一.ffmpeg主要结构体
1.结构体
1.AVFormatContext
封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
通过avformat_alloc_context()函数分配空间,并初始化默认参数
参数:
nb_streams代表封装格式里流有几个
streams[]代表第几个流,其中codec参数代表编解码器对应的上下文对象结构体,codec中codec_type代表类型:AVMEDIA_TYPE_VIDEO为视频类型,AVMEDIA_TYPE_AUDIO为音频类型
2.AVInputFormat/AVOutpufFormat
封装格式,保存了视频文件封装格式相关信息
3.AVStream
视频文件中流
4.AVCodecContext
编码器上下文,保存了编解码相关信息
5.AVCodec
每种编解码器
6.AVPacket
存储一帧压缩编码数据
7.AVFrame
存储一帧解码后像素数据
2.函数
二.ffmpeg解码提取帧RGB格式信息
1.打开视频文件 avformat_open_input()
AVFormatContext*封装格式上下文结构体;//用来保存视频相关信息的结构体,指针别忘记封装格式上下文结构体=avformat_alloc_context();//分配空间intres=avformat_open_input(&forContent, 文件路径+文件名称,nullptr,nullptr); if(res!=0)//判断是否打开视频文件return;
2.获取视频信息 如视频码流、音频码流等
//打开视频文件成功,获取文件信息res=avformat_find_stream_info(封装格式上下文结构体,nullptr); //查看有没有相关视频流信息if(res<0) return;
3.查找流信息 avformat_find_stream_info()
//一个视频流有多股码流,存在封装格式上下文结构体中streams数组中int第几路流(为视频流的那路流)=-1; //nb_streams代表封装格式里面的结构体信息有几个,正常两个:音频信息、视频信息for(inti=0;i<封装格式上下文结构体->nb_streams;i++) //i小于流的个数{ if(封装格式上下文结构体->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)//视频流 { 第几路流(为视频流的那路流)=i;//标识类型break; } } //判断是否有视频流信息if(第几路流(为视频流的那路流)==-1) return;
4.找到解码器 avcodec_find_decoder()
//编解码器对应的上下文对象结构体:保存解码器信息以及图形的宽高、像素信息AVCodecContext*编解码器对应的上下文对象=封装格式上下文结构体->streams[videoType]->codec; //查找对应的视频流解码器AVCodec*具体编解码器=avcodec_find_decoder(编解码器对应的上下文对象->codec_id); if(decoder==nullptr)//判断是否找到解码器return;
5.打开解码器 avcodec_open2()
//找到了解码器,打开解码器res=avcodec_open2(编解码器对应的上下文对象,具体编解码器,nullptr); if(res!=0) return;
6.读取码流中的一帧码流数据 av_read_frame()
//AVPacket 用来存储一帧一帧的压缩数据AVPacket*pkt=nullptr; //设置缓冲区,开空间pkt=(AVPacket*) malloc(sizeof(AVPacket)); intsize=codec->width*codec->height;//计算一张图片数据大小av_new_packet(pkt,size); /* pictureRGB 保存解码后的RGB像素数据* picture 保存未处理的像素数据*/AVFrame*RGB,*picture=nullptr; //内存分配RGB=av_frame_alloc(); picture=av_frame_alloc(); //大小以及格式设置RGBRGB->width=codec->width;//宽度RGB->height=codec->height;//高度RGB->format=codec->pix_fmt;//格式设置//一帧码流数据解码后得到RGB像素数据有多大intnumByte_RGB=avpicture_get_size(AV_PIX_FMT_RGB32,编解码器对应的上下文对象->width,编解码器对应的上下文对象->height); //开的空间用来保存RGB像素数据大小uint8_t*buffer_RGB=(uint8_t*)av_malloc(numByte_RGB*sizeof(uint8_t)); //像素数据的填充avpicture_fill((AVPicture*)RGB,buffer_RGB,AV_PIX_FMT_RGB32,编解码器对应的上下文对象->width, 编解码器对应的上下文对象->height); //转换规则SwsContext*sws_RGB=nullptr;//保存转换规则的结构体//转换规则的设置AV_PIX_FMT_RGB32sws_RGB=sws_getContext(编解码器对应的上下文对象->width,编解码器对应的上下文对象->height,编解码器对应的上下文对象->pix_fmt, 编解码器对应的上下文对象->width,编解码器对应的上下文对象->height,AV_PIX_FMT_RGB32, //目标格式SWS_BICUBIC,nullptr,nullptr,nullptr); //转换规则
7.解码读到一帧码流数据 得到一帧的像素数据
8.重复6,7两个步骤直到视频所有的帧都处理完
//一帧一帧的读取压缩数据while(av_read_frame(封装格式上下文结构体,pkt)==0)//读到数据{ if(pkt->stream_index==第几路流(为视频流的那路流))//判断一帧码流数据是不是需要得到的视频流 { intptr=-1; //解码res=avcodec_decode_video2(封装格式上下文结构体,picture,&ptr,pkt); if(res<0) return; //压缩码流数据,解码后的像素数据,判断有没有数据可以解码,对谁进行解码if(ptr!=0)//解码操作 { //把解码得到的坏数据剔除sws_scale(sws_RGB,picture->data,picture->linesize,0/*像素内存的偏移位*/,picture->height, RGB->data,RGB->linesize);//RGBQImageimage((uchar*)RGB->data[0],RGB->width,RGB->height,QImage::Format_RGB32);//像素数据 } } //释放包以及AVFrame资源av_packet_unref(pkt); }
9.关闭解码器
10.关闭视频文件
//释放AVFrameav_frame_free(&picture); //关闭解码器avcodec_close(编解码器对应的上下文对象); //释放视频信息结构体avformat_free_context(forContent) sws_freeContext(sws_RGB); // 释放一个SwsContextav_frame_free(&RGB);