FFMPEG结构体分析:AVFrame

注:写了一系列的结构体的分析的文章,在这里列一个列表:

FFMPEG结构体分析:AVFrame
FFMPEG结构体分析:AVFormatContext
FFMPEG结构体分析:AVCodecContext
FFMPEG结构体分析:AVIOContext
FFMPEG结构体分析:AVCodec
FFMPEG结构体分析:AVStream
FFMPEG结构体分析:AVPacket


FFMPEG有几个最重要的结构体,包含了解协议,解封装,解码操作,此前已经进行过分析:

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

在此不再详述,其中AVFrame是包含码流参数较多的结构体。本文将会详细分析一下该结构体里主要变量的含义和作用。

首先看一下结构体的定义(位于avcodec.h):

  1. /*
  2. *雷霄骅
  3. *[email protected]
  4. *中国传媒大学/数字电视技术
  5. */
  6. /**
  7. *AudioVideoFrame.
  8. *NewfieldscanbeaddedtotheendofAVFRAMEwithminorversion
  9. *bumps.Similarlyfieldsthataremarkedastobeonlyaccessedby
  10. *av_opt_ptr()canbereordered.Thisallows2forkstoaddfields
  11. *withoutbreakingcompatibilitywitheachother.
  12. *Removal,reorderingandchangesintheremainingcasesrequire
  13. *amajorversionbump.
  14. *sizeof(AVFrame)mustnotbeusedoutsidelibavcodec.
  15. */
  16. typedefstructAVFrame{
  17. #defineAV_NUM_DATA_POINTERS8
  18. /**图像数据
  19. *pointertothepicture/channelplanes.
  20. *Thismightbedifferentfromthefirstallocatedbyte
  21. *-encoding:Setbyuser
  22. *-decoding:setbyAVCodecContext.get_buffer()
  23. */
  24. uint8_t*data[AV_NUM_DATA_POINTERS];
  25. /**
  26. *Size,inbytes,ofthedataforeachpicture/channelplane.
  27. *
  28. *Foraudio,onlylinesize[0]maybeset.Forplanaraudio,eachchannel
  29. *planemustbethesamesize.
  30. *
  31. *-encoding:Setbyuser
  32. *-decoding:setbyAVCodecContext.get_buffer()
  33. */
  34. intlinesize[AV_NUM_DATA_POINTERS];
  35. /**
  36. *pointerstothedataplanes/channels.
  37. *
  38. *Forvideo,thisshouldsimplypointtodata[].
  39. *
  40. *Forplanaraudio,eachchannelhasaseparatedatapointer,and
  41. *linesize[0]containsthesizeofeachchannelbuffer.
  42. *Forpackedaudio,thereisjustonedatapointer,andlinesize[0]
  43. *containsthetotalsizeofthebufferforallchannels.
  44. *
  45. *Note:Bothdataandextended_datawillalwaysbesetbyget_buffer(),
  46. *butforplanaraudiowithmorechannelsthatcanfitindata,
  47. *extended_datamustbeusedbythedecoderinordertoaccessall
  48. *channels.
  49. *
  50. *encoding:unused
  51. *decoding:setbyAVCodecContext.get_buffer()
  52. */
  53. uint8_t**extended_data;
  54. /**宽高
  55. *widthandheightofthevideoframe
  56. *-encoding:unused
  57. *-decoding:Readbyuser.
  58. */
  59. intwidth,height;
  60. /**
  61. *numberofaudiosamples(perchannel)describedbythisframe
  62. *-encoding:Setbyuser
  63. *-decoding:Setbylibavcodec
  64. */
  65. intnb_samples;
  66. /**
  67. *formatoftheframe,-1ifunknownorunset
  68. *ValuescorrespondtoenumAVPixelFormatforvideoframes,
  69. *enumAVSampleFormatforaudio)
  70. *-encoding:unused
  71. *-decoding:Readbyuser.
  72. */
  73. intformat;
  74. /**是否是关键帧
  75. *1->keyframe,0->not
  76. *-encoding:Setbylibavcodec.
  77. *-decoding:Setbylibavcodec.
  78. */
  79. intkey_frame;
  80. /**帧类型(I,B,P)
  81. *Picturetypeoftheframe,see?_TYPEbelow.
  82. *-encoding:Setbylibavcodec.forcoded_picture(andsetbyuserforinput).
  83. *-decoding:Setbylibavcodec.
  84. */
  85. enumAVPictureTypepict_type;
  86. /**
  87. *pointertothefirstallocatedbyteofthepicture.Canbeusedinget_buffer/release_buffer.
  88. *Thisisn'tusedbylibavcodecunlessthedefaultget/release_buffer()isused.
  89. *-encoding:
  90. *-decoding:
  91. */
  92. uint8_t*base[AV_NUM_DATA_POINTERS];
  93. /**
  94. *sampleaspectratioforthevideoframe,0/1ifunknown/unspecified
  95. *-encoding:unused
  96. *-decoding:Readbyuser.
  97. */
  98. AVRationalsample_aspect_ratio;
  99. /**
  100. *presentationtimestampintime_baseunits(timewhenframeshouldbeshowntouser)
  101. *IfAV_NOPTS_VALUEthenframe_rate=1/time_basewillbeassumed.
  102. *-encoding:MUSTbesetbyuser.
  103. *-decoding:Setbylibavcodec.
  104. */
  105. int64_tpts;
  106. /**
  107. *reorderedptsfromthelastAVPacketthathasbeeninputintothedecoder
  108. *-encoding:unused
  109. *-decoding:Readbyuser.
  110. */
  111. int64_tpkt_pts;
  112. /**
  113. *dtsfromthelastAVPacketthathasbeeninputintothedecoder
  114. *-encoding:unused
  115. *-decoding:Readbyuser.
  116. */
  117. int64_tpkt_dts;
  118. /**
  119. *picturenumberinbitstreamorder
  120. *-encoding:setby
  121. *-decoding:Setbylibavcodec.
  122. */
  123. intcoded_picture_number;
  124. /**
  125. *picturenumberindisplayorder
  126. *-encoding:setby
  127. *-decoding:Setbylibavcodec.
  128. */
  129. intdisplay_picture_number;
  130. /**
  131. *quality(between1(good)andFF_LAMBDA_MAX(bad))
  132. *-encoding:Setbylibavcodec.forcoded_picture(andsetbyuserforinput).
  133. *-decoding:Setbylibavcodec.
  134. */
  135. intquality;
  136. /**
  137. *isthispictureusedasreference
  138. *ThevaluesforthisarethesameastheMpegEncContext.picture_structure
  139. *variable,thatis1->topfield,2->bottomfield,3->frame/bothfields.
  140. *Setto4fordelayed,non-referenceframes.
  141. *-encoding:unused
  142. *-decoding:Setbylibavcodec.(beforeget_buffer()call)).
  143. */
  144. intreference;
  145. /**QP表
  146. *QPtable
  147. *-encoding:unused
  148. *-decoding:Setbylibavcodec.
  149. */
  150. int8_t*qscale_table;
  151. /**
  152. *QPstorestride
  153. *-encoding:unused
  154. *-decoding:Setbylibavcodec.
  155. */
  156. intqstride;
  157. /**
  158. *
  159. */
  160. intqscale_type;
  161. /**跳过宏块表
  162. *mbskip_table[mb]>=1ifMBdidn'tchange
  163. *stride=mb_width=(width+15)>>4
  164. *-encoding:unused
  165. *-decoding:Setbylibavcodec.
  166. */
  167. uint8_t*mbskip_table;
  168. /**运动矢量表
  169. *motionvectortable
  170. *@code
  171. *example:
  172. *intmv_sample_log2=4-motion_subsample_log2;
  173. *intmb_width=(width+15)>>4;
  174. *intmv_stride=(mb_width<<mv_sample_log2)+1;
  175. *motion_val[direction][x+y*mv_stride][0->mv_x,1->mv_y];
  176. *@endcode
  177. *-encoding:Setbyuser.
  178. *-decoding:Setbylibavcodec.
  179. */
  180. int16_t(*motion_val[2])[2];
  181. /**宏块类型表
  182. *macroblocktypetable
  183. *mb_type_base+mb_width+2
  184. *-encoding:Setbyuser.
  185. *-decoding:Setbylibavcodec.
  186. */
  187. uint32_t*mb_type;
  188. /**DCT系数
  189. *DCTcoefficients
  190. *-encoding:unused
  191. *-decoding:Setbylibavcodec.
  192. */
  193. short*dct_coeff;
  194. /**参考帧列表
  195. *motionreferenceframeindex
  196. *theorderinwhichthesearestoredcandependonthecodec.
  197. *-encoding:Setbyuser.
  198. *-decoding:Setbylibavcodec.
  199. */
  200. int8_t*ref_index[2];
  201. /**
  202. *forsomeprivatedataoftheuser
  203. *-encoding:unused
  204. *-decoding:Setbyuser.
  205. */
  206. void*opaque;
  207. /**
  208. *error
  209. *-encoding:Setbylibavcodec.ifflags&CODEC_FLAG_PSNR.
  210. *-decoding:unused
  211. */
  212. uint64_terror[AV_NUM_DATA_POINTERS];
  213. /**
  214. *typeofthebuffer(tokeeptrackofwhohastodeallocatedata[*])
  215. *-encoding:Setbytheonewhoallocatesit.
  216. *-decoding:Setbytheonewhoallocatesit.
  217. *Note:Userallocated(directrendering)&internalbufferscannotcoexistcurrently.
  218. */
  219. inttype;
  220. /**
  221. *Whendecoding,thissignalshowmuchthepicturemustbedelayed.
  222. *extra_delay=repeat_pict/(2*fps)
  223. *-encoding:unused
  224. *-decoding:Setbylibavcodec.
  225. */
  226. intrepeat_pict;
  227. /**
  228. *Thecontentofthepictureisinterlaced.
  229. *-encoding:Setbyuser.
  230. *-decoding:Setbylibavcodec.(default0)
  231. */
  232. intinterlaced_frame;
  233. /**
  234. *Ifthecontentisinterlaced,istopfielddisplayedfirst.
  235. *-encoding:Setbyuser.
  236. *-decoding:Setbylibavcodec.
  237. */
  238. inttop_field_first;
  239. /**
  240. *Telluserapplicationthatpalettehaschangedfrompreviousframe.
  241. *-encoding:???(nopalette-enabledencoderyet)
  242. *-decoding:Setbylibavcodec.(default0).
  243. */
  244. intpalette_has_changed;
  245. /**
  246. *codecsuggestiononbuffertypeif!=0
  247. *-encoding:unused
  248. *-decoding:Setbylibavcodec.(beforeget_buffer()call)).
  249. */
  250. intbuffer_hints;
  251. /**
  252. *Panscan.
  253. *-encoding:Setbyuser.
  254. *-decoding:Setbylibavcodec.
  255. */
  256. AVPanScan*pan_scan;
  257. /**
  258. *reorderedopaque64bit(generallyanintegeroradoubleprecisionfloat
  259. *PTSbutcanbeanything).
  260. *TheusersetsAVCodecContext.reordered_opaquetorepresenttheinputat
  261. *thattime,
  262. *thedecoderreordersvaluesasneededandsetsAVFrame.reordered_opaque
  263. *toexactlyoneofthevaluesprovidedbytheuserthroughAVCodecContext.reordered_opaque
  264. *@deprecatedinfavorofpkt_pts
  265. *-encoding:unused
  266. *-decoding:Readbyuser.
  267. */
  268. int64_treordered_opaque;
  269. /**
  270. *hardwareacceleratorprivatedata(FFmpeg-allocated)
  271. *-encoding:unused
  272. *-decoding:Setbylibavcodec
  273. */
  274. void*hwaccel_picture_private;
  275. /**
  276. *theAVCodecContextwhichff_thread_get_buffer()waslastcalledon
  277. *-encoding:Setbylibavcodec.
  278. *-decoding:Setbylibavcodec.
  279. */
  280. structAVCodecContext*owner;
  281. /**
  282. *usedbymultithreadingtostoreframe-specificinfo
  283. *-encoding:Setbylibavcodec.
  284. *-decoding:Setbylibavcodec.
  285. */
  286. void*thread_opaque;
  287. /**
  288. *log2ofthesizeoftheblockwhichasinglevectorinmotion_valrepresents:
  289. *(4->16x16,3->8x8,2->4x4,1->2x2)
  290. *-encoding:unused
  291. *-decoding:Setbylibavcodec.
  292. */
  293. uint8_tmotion_subsample_log2;
  294. /**(音频)采样率
  295. *Samplerateoftheaudiodata.
  296. *
  297. *-encoding:unused
  298. *-decoding:readbyuser
  299. */
  300. intsample_rate;
  301. /**
  302. *Channellayoutoftheaudiodata.
  303. *
  304. *-encoding:unused
  305. *-decoding:readbyuser.
  306. */
  307. uint64_tchannel_layout;
  308. /**
  309. *frametimestampestimatedusingvariousheuristics,instreamtimebase
  310. *Codeoutsidelibavcodecshouldaccessthisfieldusing:
  311. *av_frame_get_best_effort_timestamp(frame)
  312. *-encoding:unused
  313. *-decoding:setbylibavcodec,readbyuser.
  314. */
  315. int64_tbest_effort_timestamp;
  316. /**
  317. *reorderedposfromthelastAVPacketthathasbeeninputintothedecoder
  318. *Codeoutsidelibavcodecshouldaccessthisfieldusing:
  319. *av_frame_get_pkt_pos(frame)
  320. *-encoding:unused
  321. *-decoding:Readbyuser.
  322. */
  323. int64_tpkt_pos;
  324. /**
  325. *durationofthecorrespondingpacket,expressedin
  326. *AVStream->time_baseunits,0ifunknown.
  327. *Codeoutsidelibavcodecshouldaccessthisfieldusing:
  328. *av_frame_get_pkt_duration(frame)
  329. *-encoding:unused
  330. *-decoding:Readbyuser.
  331. */
  332. int64_tpkt_duration;
  333. /**
  334. *metadata.
  335. *Codeoutsidelibavcodecshouldaccessthisfieldusing:
  336. *av_frame_get_metadata(frame)
  337. *-encoding:Setbyuser.
  338. *-decoding:Setbylibavcodec.
  339. */
  340. AVDictionary*metadata;
  341. /**
  342. *decodeerrorflagsoftheframe,settoacombinationof
  343. *FF_DECODE_ERROR_xxxflagsifthedecoderproducedaframe,butthere
  344. *wereerrorsduringthedecoding.
  345. *Codeoutsidelibavcodecshouldaccessthisfieldusing:
  346. *av_frame_get_decode_error_flags(frame)
  347. *-encoding:unused
  348. *-decoding:setbylibavcodec,readbyuser.
  349. */
  350. intdecode_error_flags;
  351. #defineFF_DECODE_ERROR_INVALID_BITSTREAM1
  352. #defineFF_DECODE_ERROR_MISSING_REFERENCE2
  353. /**
  354. *numberofaudiochannels,onlyusedforaudio.
  355. *Codeoutsidelibavcodecshouldaccessthisfieldusing:
  356. *av_frame_get_channels(frame)
  357. *-encoding:unused
  358. *-decoding:Readbyuser.
  359. */
  360. int64_tchannels;
  361. }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

包含以下类型:

  1. enumAVPictureType{
  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-dirpredicted
  6. AV_PICTURE_TYPE_S,///<S(GMC)-VOPMPEG4
  7. AV_PICTURE_TYPE_SI,///<SwitchingIntra
  8. AV_PICTURE_TYPE_SP,///<SwitchingPredicted
  9. AV_PICTURE_TYPE_BI,///<BItype
  10. };
3.sample_aspect_ratio

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

  1. /**
  2. *rationalnumbernumerator/denominator
  3. */
  4. typedefstructAVRational{
  5. intnum;///<numerator
  6. intden;///<denominator
  7. }AVRational;

4.qscale_table

QP表指向一块内存,里面存储的是每个宏块的QP值。宏块的标号是从左往右,一行一行的来的。每个宏块对应1个QP。

qscale_table[0]就是第1行第1列宏块的QP值;qscale_table[1]就是第1行第2列宏块的QP值;qscale_table[2]就是第1行第3列宏块的QP值。以此类推...

宏块的个数用下式计算:

注:宏块大小是16x16的。

每行宏块数:

  1. intmb_stride=pCodecCtx->width/16+1

宏块的总数:

  1. intmb_sum=((pCodecCtx->height+15)>>4)*(pCodecCtx->width/16+1)


5.motion_subsample_log2

1个运动矢量所能代表的画面大小(用宽或者高表示,单位是像素),注意,这里取了log2。

代码注释中给出以下数据:

4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2

即1个运动矢量代表16x16的画面的时候,该值取4;1个运动矢量代表8x8的画面的时候,该值取3...以此类推

6.motion_val

运动矢量表存储了一帧视频中的所有运动矢量。

该值的存储方式比较特别:

  1. int16_t(*motion_val[2])[2];
为了弄清楚该值究竟是怎么存的,花了我好一阵子功夫...

注释中给了一段代码:

  1. intmv_sample_log2=4-motion_subsample_log2;
  2. intmb_width=(width+15)>>4;
  3. intmv_stride=(mb_width<<mv_sample_log2)+1;
  4. motion_val[direction][x+y*mv_stride][0->mv_x,1->mv_y];

大概知道了该数据的结构:

1.首先分为两个列表L0和L1

2.每个列表(L0或L1)存储了一系列的MV(每个MV对应一个画面,大小由motion_subsample_log2决定)

3.每个MV分为横坐标和纵坐标(x,y)

注意,在FFMPEG中MV和MB在存储的结构上是没有什么关联的,第1个MV是屏幕上左上角画面的MV(画面的大小取决于motion_subsample_log2),第2个MV是屏幕上第1行第2列的画面的MV,以此类推。因此在一个宏块(16x16)的运动矢量很有可能如下图所示(line代表一行运动矢量的个数):

  1. //例如8x8划分的运动矢量与宏块的关系:
  2. //-------------------------
  3. //|||
  4. //|mv[x]|mv[x+1]|
  5. //-------------------------
  6. //|||
  7. //|mv[x+line]|mv[x+line+1]|
  8. //-------------------------


7.mb_type

宏块类型表存储了一帧视频中的所有宏块的类型。其存储方式和QP表差不多。只不过其是uint32类型的,而QP表是uint8类型的。每个宏块对应一个宏块类型变量。

宏块类型如下定义所示:

  1. //Thefollowingdefinesmaychange,don'texpectcompatibilityifyouusethem.
  2. #defineMB_TYPE_INTRA4x40x0001
  3. #defineMB_TYPE_INTRA16x160x0002//FIXMEH.264-specific
  4. #defineMB_TYPE_INTRA_PCM0x0004//FIXMEH.264-specific
  5. #defineMB_TYPE_16x160x0008
  6. #defineMB_TYPE_16x80x0010
  7. #defineMB_TYPE_8x160x0020
  8. #defineMB_TYPE_8x80x0040
  9. #defineMB_TYPE_INTERLACED0x0080
  10. #defineMB_TYPE_DIRECT20x0100//FIXME
  11. #defineMB_TYPE_ACPRED0x0200
  12. #defineMB_TYPE_GMC0x0400
  13. #defineMB_TYPE_SKIP0x0800
  14. #defineMB_TYPE_P0L00x1000
  15. #defineMB_TYPE_P1L00x2000
  16. #defineMB_TYPE_P0L10x4000
  17. #defineMB_TYPE_P1L10x8000
  18. #defineMB_TYPE_L0(MB_TYPE_P0L0|MB_TYPE_P1L0)
  19. #defineMB_TYPE_L1(MB_TYPE_P0L1|MB_TYPE_P1L1)
  20. #defineMB_TYPE_L0L1(MB_TYPE_L0|MB_TYPE_L1)
  21. #defineMB_TYPE_QUANT0x00010000
  22. #defineMB_TYPE_CBP0x00020000
  23. //Notebits24-31arereservedforcodecspecificuse(h264ref0,mpeg10mv,...)
一个宏块如果包含上述定义中的一种或两种类型,则其对应的宏块变量的对应位会被置1。
注:一个宏块可以包含好几种类型,但是有些类型是不能重复包含的,比如说一个宏块不可能既是16x16又是8x8。


8.ref_index

运动估计参考帧列表存储了一帧视频中所有宏块的参考帧索引。这个列表其实在比较早的压缩编码标准中是没有什么用的。只有像H.264这样的编码标准才有多参考帧的概念。但是这个字段目前我还没有研究透。只是知道每个宏块包含有4个该值,该值反映的是参考帧的索引。以后有机会再进行细研究吧。


在这里展示一下自己做的码流分析软件的运行结果。将上文介绍的几个列表图像化显示了出来(在这里是使用MFC的绘图函数画出来的)

视频帧:

FFMPEG结构体分析:AVFrame

QP参数提取的结果:

FFMPEG结构体分析:AVFrame

美化过的(加上了颜色):

FFMPEG结构体分析:AVFrame

宏块类型参数提取的结果:

FFMPEG结构体分析:AVFrame

美化过的(加上了颜色,更清晰一些,s代表skip宏块):

FFMPEG结构体分析:AVFrame

运动矢量参数提取的结果(在这里是List0):

FFMPEG结构体分析:AVFrame

运动估计参考帧参数提取的结果:

FFMPEG结构体分析:AVFrame