您现在的位置是:主页 > news > 武汉网站建设吧/怎么制作网站教程
武汉网站建设吧/怎么制作网站教程
admin2025/5/1 6:37:51【news】
简介武汉网站建设吧,怎么制作网站教程,绵阳医院网站建设,中国空间站拒绝日本一、开发前的准备工作(见文末链接) 开发工具为Qt5.8,目录结构: bin:工作和测试目录include:ffmpeg头文件配置目录lib:ffmpeg静态库配置目录...... 二、编解码基础知识 (1)封装格式 指音视频的组合格式,常见的封装格…
一、开发前的准备工作(见文末链接)
开发工具为Qt5.8,目录结构:
- bin:工作和测试目录
- include:ffmpeg头文件配置目录
- lib:ffmpeg静态库配置目录
- ......
二、编解码基础知识
(1)封装格式
指音视频的组合格式,常见的封装格式(带后缀的音视频文件)有wmv,avi,rmvb,mp4,mp3,flv,mkv等等
(2)编码格式
就像wmv这种格式而言,一般包含有视频和音频。视频的编码格式为YUV420P,音频的编码格式为PCM。所以通常我们说的编码过程就包括:画面采集、转码、编码再封装。
(3)视频解码和音频解码有什么区别
一些高速摄像机的采集速度能够达到12000帧/秒,那么在播放这类影片的时候我们是否也需要以12000帧/秒播放呢?当然不是,通常我们会按照25帧/秒或者60帧/秒设定图像的FPS值。但是由于视频中关键帧保存了完整的画面而过渡帧只是保存了与前一帧画面的变化部分,需要通过关键帧计算获得。因此我们需要对每一帧都进行解码,即获取画面的YUV数据。同时只对我们真正需要显示的画面进行转码,即将YUV数据转换成RGB数据,包括计算画面的宽高等。
而音频的播放必须和采集保持同步。提高或降低音频的播放速度都会让音质发生变化,这也是变声器的原理。因此在实际开发中为了保证播放的音视频同步,我们往往会按照音频的播放速度来控制视频的解码转码速度。
( 4 ) 框架图
三、步骤及代码
1、注册所有组件:av_register_all()
2、打开视频文件
//参数1:封装格式上下文->AVFormatContext结构体->包含了视频信息(视频格式、大小等)//参数2:要打开流的路径(文件名)AVFormatContext * formatContent = avformat_alloc_context();char * filename="Warcraft3_End.avi";/*2、打开视频文件*/int res = avformat_open_input(&formatContent,filename,nullptr,nullptr);if(res!=0){char *err = new char[32];//显示异常的信息av_strerror(res,err,1024);qDebug()<<QString("错误的信息:%1").arg(err);//qDebug()<<"打开流媒体信息";//return ;}
3、获取视频文件(视频流)信息
//参数一:封装格式文件上下文->AVFormatContext。//参数二:字典,一些配置选项。res = avformat_find_stream_info(pFormatContext,NULL);//获取视频文件信息(视频流信息)if(res<0)//进行判断的原因是有可能打开普通文件{char *err = new char[1024];//显示异常的信息av_strerror(res,err,1024);qDebug()<<QString("错误的信息:%1").arg(err);}
4、查找解码器
//第一点:获取当前解码器是属于什么类型解码器->找到视频流//音频、视频、字幕解码器等等...int videoType = -1;for (int i = 0; i < formatContent->nb_streams; ++i) {//循环遍历每一流,包括视频流、音频流、字幕流等等...//streams->AVStream->codecif (formatContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){//找到视频流(只有一个)videoType = i;//标识视频流这个类型break;}}if (videoType== -1){qDebug()<<QString("没有找到视频流相关信息");return ;}//第二点:根据视频流->查找到视频解码器上下文->视频压缩数据(宽高格式等)AVCodecContext* codec= formatContent->streams[videoType]->codec;//第三点:有视频流,则查找对应视频流的解码器AVCodec *decoder = avcodec_find_decoder(codec->codec_id);//需要解码器的idif(decoder ==nullptr){qDebug()<<"没有找到对应的视频解码器";return;}
5、打开解码器
//参数:1.初始化的上下文对象 2.打开的解码器 3.类似目录的东西(没有)res = avcodec_open2(codec,decoder,nullptr);if(res!=0){//qDebug()<<"解码器打开失败";//return;char* error_info = new char[32];av_strerror(avformat_find_stream_info_result, error_info, 1024);qDebug()<<QString("异常信息 %1").arg(error_info);return false;}
以上基本就是打开多媒体文件的主要步骤,解码和转码的所有参数都可以在这里获取。接下来我们就需要循环进行读取、解码、转码直到播放完成。
6、循环读取视频帧,进行循环解码,转码输出YUV420P视频
FILE *fp = fopen("saveH264.h264","wb+");FILE *fpYUV = fopen("saveYUV.yuv","wb+");AVPacket *pkt=nullptr;//pkt这时没有指向,要我们给他分配内存空间pkt = (AVPacket *)malloc(sizeof(AVPacket));//读取帧数据换成到哪里?->缓存到packet里面//开空间不知道一帧的码流数据是多少?其实编解码器告诉了宽高,以此可以计算出给码流数据开多大空间int bufSize = codec->width*codec->height;//计算一帧(类似一张图)数据的大小av_new_packet(pkt,bufSize);AVFrame *pictureYUV = nullptr;//保存解码及剔除后的像素数据(做准备)pictureYUV = av_frame_alloc();pictureYUV->width = codec->width;pictureYUV->height = codec->height;pictureYUV->format = codec->pix_fmt;//格式的设置//要存解码后的像素数据到pictureYUV,那这个数据有多大呢?//获取解码后的一帧像素数据有多大int numByte = avpicture_get_size(AV_PIX_FMT_YUV420P,codec->width,codec->height);//开的空间用来保存像素数据的大小uint8_t *buffer = (uint8_t *)av_malloc(numByte*sizeof(uint8_t));//像素数据填充到AVFrame的pictureYUV里avpicture_fill((AVPicture *)pictureYUV,buffer,AV_PIX_FMT_YUV420P,codec->width,codec->height);//因为解码之后要伸展,所以先进行转换规则的设置,转换完进入第七步解码SwsContext *swsContent = nullptr;swsContent = sws_getContext(codec->width,codec->height,codec->pix_fmt,codec->width,codec->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,nullptr,nullptr,nullptr);while(av_read_frame(formatContent,pkt) >= 0)//>=0:说明有数据,继续读取 <0:说明读取完毕,结束{/*判断读到的每一帧的码流数据是不是视频流*/if(pkt->stream_index == videoType){//是视频流则写到文件中(saveH264.h264)fwrite(pkt->data,pkt->size,1,fp);//每次写一个结构体//读到一帧是视频流就进行解码的动作/*avcodec_decode_video2:解码得到YUV,保存在AVFrame结构体里*///参数:1编解码器上下文对象的结构体 2存放解码后的像素数据(AVFrame类型)//3判断有没有数据可以进行解码:指针类型的变量 4对谁进行解码:一帧的码流数据//功能:把得到的一帧码流数据用编解码器上下文对象去解,存放在AVFrame结构体里int got_picture_ptr = -1;AVFrame *picture = av_frame_alloc();//保存原始yuv像素数据avcodec_decode_video2(codec,picture,&got_picture_ptr,pkt);if(got_picture_ptr != 0){//把解码得到的损坏的像素数据剔除存到pictureYUV中//data是数组,把Y U V 三份数据分开存储 sws_scale(swsContent,picture->data,picture->linesize,0,picture->height,pictureYUV->data,pictureYUV->linesize);//因为所有的像素数据都有完整的亮点数据,所有Y保存的是bufSize的大小,其他的都是1/4fwrite(pictureYUV->data[0],bufSize,1,fpYUV);//写入->Yfwrite(pictureYUV->data[1],bufSize/4,1,fpYUV);//写入->Ufwrite(pictureYUV->data[2],bufSize/4,1,fpYUV);//写入->V}}
7、关闭解码组件
av_packet_unref(pkt);//此处不是free//关闭流fclose(fp);fclose(fpYUV);av_frame_free(&picture);av_frame_free(&pictureYUV);avcodec_close(codec);avformat_free_context(formatContent);
四、实现效果
解码后用YUV Player Deluxe 软件查看存储到本地的yuv视频文件
开发前的准备工作(详见Qt与FFmpeg开发指南(一)
Qt与FFmpeg开发指南(一)--Windows下环境搭建_hml111666的博客-CSDN博客