FFMPEG的重要的结构体

1. FFMPEG中最关键的结构体之间的关系

FFMPEG中结构体很多。最关键的结构体可以分成以下几类:

a)        解协议(http,rtsp,rtmp,mms)

AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)

b)        解封装(flv,avi,rmvb,mp4)

AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。

c)        解码(h264,mpeg2,aac,mp3)

每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。

d) 存数据

视频的话,每个结构一般是存一帧;音频可能有好几帧

解码前数据:AVPacket

解码后数据:AVFrame

他们之间的对应关系如下所示:

FFMPEG的重要的结构体_第1张图片

1)AVPacket结构体

AVPacket是存储压缩编码数据相关信息的结构体。

在AVPacket结构体中,重要的变量有以下几个:

uint8_t *data:压缩编码的数据。

例如对于H.264来说。1个AVPacket的data通常对应一个NAL。

注意:在这里只是对应,而不是一模一样。他们之间有微小的差别:使用FFMPEG类库分离出多媒体文件中的H.264码流

因此在使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件。

int   size:data的大小

int64_t pts:显示时间戳

int64_t dts:解码时间戳

int   stream_index:标识该AVPacket所属的视频/音频流。

说明:FFMPEG使用AVPacket来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)。其中:

  • dts表示解码时间戳,pts表示显示时间戳,它们的单位是所属媒体流的时间基准。
  • stream_index给出所属媒体流的索引;
  • data为数据缓冲区指针,size为长度;
  • duration为数据的时长,也是以所属媒体流的时间基准为单位;
  • pos表示该数据在媒体流中的字节偏移量;
  • destruct为用于释放数据缓冲区的函数指针;
  • flags为标志域,其中,最低为置1表示该数据是一个关键帧。

AVPacket结构本身只是个容器,它使用data成员引用实际的数据缓冲区。这个缓冲区通常是由av_new_packet创建的,但也可能由 FFMPEG的API创建(如av_read_frame)。当某个AVPacket结构的数据缓冲区不再被使用时,要需要通过调用 av_free_packet释放。av_free_packet调用的是结构体本身的destruct函数,它的值有两种情 况:1)av_destruct_packet_nofree或0;2)av_destruct_packet,其中,情况1)仅仅是将data和 size的值清0而已,情况2)才会真正地释放缓冲区。

FFMPEG内部使用AVPacket结构建立缓冲区装载数据,同时提供destruct函数,如果FFMPEG打算自己维护缓冲区,则将 destruct设为av_destruct_packet_nofree,用户调用av_free_packet清理缓冲区时并不能够将其释放;如果 FFMPEG打算将该缓冲区彻底交给调用者,则将destruct设为av_destruct_packet,表示它能够被释放。安全起见,如果用户希望 自由地使用一个FFMPEG内部创建的AVPacket结构,最好调用av_dup_packet进行缓冲区的克隆,将其转化为缓冲区能够被释放的 AVPacket,以免对缓冲区的不当占用造成异常错误。av_dup_packet会为destruct指针为 av_destruct_packet_nofree的AVPacket新建一个缓冲区,然后将原缓冲区的数据拷贝至新缓冲区,置data的值为新缓冲区 的地址,同时设destruct指针为av_destruct_packet。


2)  AVFormatContext

在使用FFMPEG进行开发的时候,AVFormatContext是一个贯穿始终的数据结构,很多函数都要用到它作为参数。它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。下面看几个主要变量的作用(在这里考虑解码的情况):

struct AVInputFormat *iformat:输入数据的封装格式

AVIOContext *pb:输入数据的缓存

unsigned int nb_streams:视音频流的个数

AVStream **streams:视音频流

char filename[1024]:文件名

int64_t duration:时长(单位:微秒us,转换为秒需要除以1000000)

int bit_rate:比特率(单位bps,转换为kbps需要除以1000)

AVDictionary *metadata:元数据

  
3)AVIOContext结构体,URLContext结构体,URLProtocol结构体
AVIOContext结构体有以下几个变量比较重要:

unsigned char *buffer:缓存开始位置

int buffer_size:缓存大小(默认32768)

unsigned char *buf_ptr:当前指针读取到的位置

unsigned char *buf_end:缓存结束的位置

void *opaque:URLContext结构体

在解码的情况下,buffer用于存储ffmpeg读入的数据。例如打开一个视频文件的时候,先把数据从硬盘读入buffer,然后在送给解码器用于解码。

其中opaque指向了URLContext。注意,这个结构体并不在FFMPEG提供的头文件中,而是在FFMPEG的源代码中。从FFMPEG源代码中翻出的定义如下所示:

[cpp]  view plain  copy
  1. typedef struct URLContext {  
  2.     const AVClass *av_class; ///< information for av_log(). Set by url_open().  
  3.     struct URLProtocol *prot;  
  4.     int flags;  
  5.     int is_streamed;  /**< true if streamed (no seek possible), default = false */  
  6.     int max_packet_size;  /**< if non zero, the stream is packetized with this max packet size */  
  7.     void *priv_data;  
  8.     char *filename; /**< specified URL */  
  9.     int is_connected;  
  10.     AVIOInterruptCB interrupt_callback;  
  11. } URLContext;  

URLContext结构体中还有一个结构体URLProtocol。注:每种协议(rtp,rtmp,file等)对应一个URLProtocol。这个结构体也不在FFMPEG提供的头文件中。从FFMPEG源代码中翻出其的定义:

[cpp]  view plain  copy
  1. typedef struct URLProtocol {  
  2.     const char *name;  
  3.     int (*url_open)(URLContext *h, const char *url, int flags);  
  4.     int (*url_read)(URLContext *h, unsigned char *buf, int size);  
  5.     int (*url_write)(URLContext *h, const unsigned char *buf, int size);  
  6.     int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);  
  7.     int (*url_close)(URLContext *h);  
  8.     struct URLProtocol *next;  
  9.     int (*url_read_pause)(URLContext *h, int pause);  
  10.     int64_t (*url_read_seek)(URLContext *h, int stream_index,  
  11.         int64_t timestamp, int flags);  
  12.     int (*url_get_file_handle)(URLContext *h);  
  13.     int priv_data_size;  
  14.     const AVClass *priv_data_class;  
  15.     int flags;  
  16.     int (*url_check)(URLContext *h, int mask);  
  17. } URLProtocol;  

在这个结构体中,除了一些回调函数接口之外,有一个变量const char *name,该变量存储了协议的名称。每一种输入协议都对应这样一个结构体。
比如说,文件协议中代码如下(file.c):

[cpp]  view plain  copy
  1. URLProtocol ff_file_protocol = {  
  2.     .name                = "file",  
  3.     .url_open            = file_open,  
  4.     .url_read            = file_read,  
  5.     .url_write           = file_write,  
  6.     .url_seek            = file_seek,  
  7.     .url_close           = file_close,  
  8.     .url_get_file_handle = file_get_handle,  
  9.     .url_check           = file_check,  
  10. };  


 4)AVStream结构体

AVStream是存储每一个视频/音频流信息的结构体

AVStream重要的变量如下所示:

int index:标识该视频/音频流

AVCodecContext *codec:指向该视频/音频流的AVCodecContext(它们是一一对应的关系)

AVRational time_base:时基。通过该值可以把PTS,DTS转化为真正的时间。FFMPEG其他结构体中也有这个字段,但是根据我的经验,只有AVStream中的time_base是可用的。PTS*time_base=真正的时间

int64_t duration:该视频/音频流长度

AVDictionary *metadata:元数据信息

AVRational avg_frame_rate:帧率(注:对视频来说,这个挺重要的)

AVPacket attached_pic:附带的图片。比如说一些MP3,AAC音频文件附带的专辑封面。


5)AVCodecContext结构体
AVCodecContext是包含变量较多的结构体(感觉差不多是变量最多的结构体),下面挑一些关键的变量来看看(这里只考虑解码)

enum AVMediaType codec_type:编解码器的类型(视频,音频...)

struct AVCodec  *codec:采用的解码器AVCodec(H.264,MPEG2...)

int bit_rate:平均比特率

uint8_t *extradata; int extradata_size:针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)

AVRational time_base:根据该参数,可以把PTS转化为实际的时间(单位为秒s)

int width, height:如果是视频的话,代表宽和高

int refs:运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)

int sample_rate:采样率(音频)

int channels:声道数(音频)

enum AVSampleFormat sample_fmt:采样格式

int profile:型(H.264里面就有,其他编码标准应该也有)

int level:级(和profile差不太多)

在这里需要注意:AVCodecContext中很多的参数是编码的时候使用的,而不是解码的时候使用的。


6)AVCodec结构体

AVCodec是存储编解码器信息的结构体

下面说一下最主要的几个变量:

const char *name:编解码器的名字,比较短

const char *long_name:编解码器的名字,全称,比较长

enum AVMediaType type:指明了类型,是视频,音频,还是字幕

enum AVCodecID id:ID,不重复

const AVRational *supported_framerates:支持的帧率(仅视频)

const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频)

const int *supported_samplerates:支持的采样率(仅音频)

const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)

const uint64_t *channel_layouts:支持的声道数(仅音频)

int priv_data_size:私有数据的大小

详细介绍几个变量:

1.enum AVMediaType type

AVMediaType定义如下:

[cpp]  view plain  copy
  1. enum AVMediaType {  
  2.     AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATA  
  3.     AVMEDIA_TYPE_VIDEO,  
  4.     AVMEDIA_TYPE_AUDIO,  
  5.     AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuous  
  6.     AVMEDIA_TYPE_SUBTITLE,  
  7.     AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparse  
  8.     AVMEDIA_TYPE_NB  
  9. };  

2.enum AVCodecID id

AVCodecID定义如下:

[cpp]  view plain  copy
  1. enum AVCodecID {  
  2.     AV_CODEC_ID_NONE,  
  3.   
  4.     /* video codecs */  
  5.     AV_CODEC_ID_MPEG1VIDEO,  
  6.     AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding  
  7.     AV_CODEC_ID_MPEG2VIDEO_XVMC,  
  8.     AV_CODEC_ID_H261,  
  9.     AV_CODEC_ID_H263,  
  10.     AV_CODEC_ID_RV10,  
  11.     AV_CODEC_ID_RV20,  
  12.     AV_CODEC_ID_MJPEG,  
  13.     AV_CODEC_ID_MJPEGB,  
  14.     AV_CODEC_ID_LJPEG,  
  15.     AV_CODEC_ID_SP5X,  
  16.     AV_CODEC_ID_JPEGLS,  
  17.     AV_CODEC_ID_MPEG4,  
  18.     AV_CODEC_ID_RAWVIDEO,  
  19.     AV_CODEC_ID_MSMPEG4V1,  
  20.     AV_CODEC_ID_MSMPEG4V2,  
  21.     AV_CODEC_ID_MSMPEG4V3,  
  22.     AV_CODEC_ID_WMV1,  
  23.     AV_CODEC_ID_WMV2,  
  24.     AV_CODEC_ID_H263P,  
  25.     AV_CODEC_ID_H263I,  
  26.     AV_CODEC_ID_FLV1,  
  27.     AV_CODEC_ID_SVQ1,  
  28.     AV_CODEC_ID_SVQ3,  
  29.     AV_CODEC_ID_DVVIDEO,  
  30.     AV_CODEC_ID_HUFFYUV,  
  31.     AV_CODEC_ID_CYUV,  
  32.     AV_CODEC_ID_H264,  
  33.     ...(代码太长,略)  
  34. }  


3.const enum AVPixelFormat *pix_fmts

AVPixelFormat定义如下:

[cpp]  view plain  copy
  1. enum AVPixelFormat {  
  2.     AV_PIX_FMT_NONE = -1,  
  3.     AV_PIX_FMT_YUV420P,   ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)  
  4.     AV_PIX_FMT_YUYV422,   ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr  
  5.     AV_PIX_FMT_RGB24,     ///< packed RGB 8:8:8, 24bpp, RGBRGB...  
  6.     AV_PIX_FMT_BGR24,     ///< packed RGB 8:8:8, 24bpp, BGRBGR...  
  7.     AV_PIX_FMT_YUV422P,   ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)  
  8.     AV_PIX_FMT_YUV444P,   ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)  
  9.     AV_PIX_FMT_YUV410P,   ///< planar YUV 4:1:0,  9bpp, (1 Cr & Cb sample per 4x4 Y samples)  
  10.     AV_PIX_FMT_YUV411P,   ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)  
  11.     AV_PIX_FMT_GRAY8,     ///<        Y        ,  8bpp  
  12.     AV_PIX_FMT_MONOWHITE, ///<        Y        ,  1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb  
  13.     AV_PIX_FMT_MONOBLACK, ///<        Y        ,  1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb  
  14.     AV_PIX_FMT_PAL8,      ///< 8 bit with PIX_FMT_RGB32 palette  
  15.     AV_PIX_FMT_YUVJ420P,  ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range  
  16.     AV_PIX_FMT_YUVJ422P,  ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range  
  17.     AV_PIX_FMT_YUVJ444P,  ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range  
  18.     AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing  
  19.     AV_PIX_FMT_XVMC_MPEG2_IDCT,  
  20.     ...(代码太长,略)  
  21. }  

4.const enum AVSampleFormat *sample_fmts
[cpp]  view plain  copy
  1. enum AVSampleFormat {  
  2.     AV_SAMPLE_FMT_NONE = -1,  
  3.     AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits  
  4.     AV_SAMPLE_FMT_S16,         ///< signed 16 bits  
  5.     AV_SAMPLE_FMT_S32,         ///< signed 32 bits  
  6.     AV_SAMPLE_FMT_FLT,         ///< float  
  7.     AV_SAMPLE_FMT_DBL,         ///< double  
  8.   
  9.     AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar  
  10.     AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar  
  11.     AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar  
  12.     AV_SAMPLE_FMT_FLTP,        ///< float, planar  
  13.     AV_SAMPLE_FMT_DBLP,        ///< double, planar  
  14.   
  15.     AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically  
  16. };  


每一个编解码器对应一个该结构体,查看一下ffmpeg的源代码,我们可以看一下H.264解码器的结构体如下所示(h264.c):

[cpp]  view plain  copy
  1. AVCodec ff_h264_decoder = {  
  2.     .name           = "h264",  
  3.     .type           = AVMEDIA_TYPE_VIDEO,  
  4.     .id             = CODEC_ID_H264,  
  5.     .priv_data_size = sizeof(H264Context),  
  6.     .init           = ff_h264_decode_init,  
  7.     .close          = ff_h264_decode_end,  
  8.     .decode         = decode_frame,  
  9.     .capabilities   = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY |  
  10.                       CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,  
  11.     .flush= flush_dpb,  
  12.     .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),  
  13.     .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),  
  14.     .update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),  
  15.     .profiles = NULL_IF_CONFIG_SMALL(profiles),  
  16.     .priv_class     = &h264_class,  
  17. };  

JPEG2000解码器结构体(j2kdec.c)

[cpp]  view plain  copy
  1. AVCodec ff_jpeg2000_decoder = {  
  2.     .name           = "j2k",  
  3.     .type           = AVMEDIA_TYPE_VIDEO,  
  4.     .id             = CODEC_ID_JPEG2000,  
  5.     .priv_data_size = sizeof(J2kDecoderContext),  
  6.     .init           = j2kdec_init,  
  7.     .close          = decode_end,  
  8.     .decode         = decode_frame,  
  9.     .capabilities = CODEC_CAP_EXPERIMENTAL,  
  10.     .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),  
  11.     .pix_fmts =  
  12.         (const enum PixelFormat[]) {PIX_FMT_GRAY8, PIX_FMT_RGB24, PIX_FMT_NONE}  
  13. };  

下面简单介绍一下遍历ffmpeg中的解码器信息的方法(这些解码器以一个链表的形式存储):

1.注册所有编解码器:av_register_all();

2.声明一个AVCodec类型的指针,比如说AVCodec* first_c;

3.调用av_codec_next()函数,即可获得指向链表下一个解码器的指针,循环往复可以获得所有解码器的信息。注意,如果想要获得指向第一个解码器的指针,则需要将该函数的参数设置为NULL。


7)AVFrame结构体

AVFrame结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM),此外还包含了一些相关的信息。比如说,解码的时候存储了宏块类型表,QP表,运动矢量表等数据。编码的时候也存储了相关的数据。因此在使用FFMPEG进行码流分析的时候,AVFrame是一个很重要的结构体。

下面看几个主要变量的作用(在这里考虑解码的情况):

uint8_t *data[AV_NUM_DATA_POINTERS]:解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)

int linesize[AV_NUM_DATA_POINTERS]:data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。

int width, height:视频帧宽和高(1920x1080,1280x720...)

int nb_samples:音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个

int format:解码后原始数据类型(YUV420,YUV422,RGB24...)

int key_frame:是否是关键帧

enum AVPictureType pict_type:帧类型(I,B,P...)

AVRational sample_aspect_ratio:宽高比(16:9,4:3...)

int64_t pts:显示时间戳

int coded_picture_number:编码帧序号

int display_picture_number:显示帧序号

int8_t *qscale_table:QP表

uint8_t *mbskip_table:跳过宏块表

int16_t (*motion_val[2])[2]:运动矢量表

uint32_t *mb_type:宏块类型表

short *dct_coeff:DCT系数,这个没有提取过

int8_t *ref_index[2]:运动估计参考帧列表(貌似H.264这种比较新的标准才会涉及到多参考帧)

int interlaced_frame:是否是隔行扫描

uint8_t motion_subsample_log2:一个宏块中的运动矢量采样个数,取log的

其他的变量不再一一列举,源代码中都有详细的说明。在这里重点分析一下几个需要一定的理解的变量:

1.data[]

对于packed格式的数据(例如RGB24),会存到data[0]里面。

对于planar格式的数据(例如YUV420P),则会分开成data[0],data[1],data[2]...(YUV420P中data[0]存Y,data[1]存U,data[2]存V)

具体参见:FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)

2.pict_type

包含以下类型:

[cpp]  view plain  copy
  1. enum AVPictureType {  
  2.     AV_PICTURE_TYPE_NONE = 0, ///< Undefined  
  3.     AV_PICTURE_TYPE_I,     ///< Intra  
  4.     AV_PICTURE_TYPE_P,     ///< Predicted  
  5.     AV_PICTURE_TYPE_B,     ///< Bi-dir predicted  
  6.     AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG4  
  7.     AV_PICTURE_TYPE_SI,    ///< Switching Intra  
  8.     AV_PICTURE_TYPE_SP,    ///< Switching Predicted  
  9.     AV_PICTURE_TYPE_BI,    ///< BI type  
  10. };  
3.sample_aspect_ratio

宽高比是一个分数,FFMPEG中用AVRational表达分数:

[cpp]  view plain  copy
  1. /** 
  2.  * rational number numerator/denominator 
  3.  */  
  4. typedef struct AVRational{  
  5.     int num; ///< numerator  
  6.     int den; ///< denominator  
  7. } AVRational;  























你可能感兴趣的:(FFmpeg)