1. 程式人生 > >FFMpeg中的關鍵結構體, AVFormatContext, AVIOContext, AVStream, AVCodecContext, AVCodec, AVPacket, AVFrame

FFMpeg中的關鍵結構體, AVFormatContext, AVIOContext, AVStream, AVCodecContext, AVCodec, AVPacket, AVFrame

最近看雷神部落格, 便於以後查詢, 整理出了以下文件.

1. 整體關係

FFMPEG關鍵結構體關係 FFMPEG中結構體很多, 最關鍵的結構體可以分成以下幾類:

1.1解協議(http,rtsp,rtmp,mms)

AVIOContext,URLProtocol,URLContext主要儲存視音訊使用的協議的型別以及狀態。URLProtocol儲存輸入視音訊使用的封裝格式。每種協議都對應一個URLProtocol結構。(注意:FFMPEG中檔案也被當做一種協議“file”)

1.2解封裝(flv,avi,rmvb,mp4)

AVFormatContext主要儲存視音訊封裝格式中包含的資訊;AVInputFormat儲存輸入視音訊使用的封裝格式。每種視音訊封裝格式都對應一個AVInputFormat 結構。

1.3解碼(h264,mpeg2,aac,mp3)

每個AVStream儲存一個視訊/音訊流的相關資料;每個AVStream對應一個AVCodecContext,儲存該視訊/音訊流使用解碼方式的相關資料;每個AVCodecContext中對應一個AVCodec,包含該視訊/音訊對應的解碼器。每種解碼器都對應一個AVCodec結構。

1.4存資料

資料視訊的話,每個結構一般是存一幀;音訊可能有好幾幀解碼前資料:AVPacket解碼後資料:AVFrame

2. AVFormatContext

AVFormatContext是包含碼流引數較多的結構體, 結構體的定義位於avformat.h.

在使用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

AVIOContext是FFMPEG管理輸入輸出資料的結構體, 結構體的定義位於avio.h

. 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原始碼中翻出的定義如下所示:

typedef struct URLContext {
	const AVClass *av_class; ///< information for av_log(). Set by url_open().
	struct URLProtocol *prot;
	int flags;
	int is_streamed;  /**< true if streamed (no seek possible), default = false */
	int max_packet_size;  /**< if non zero, the stream is packetized with this max packet size */
	void *priv_data;
	char *filename; /**< specified URL */
	int is_connected;
	AVIOInterruptCB interrupt_callback;
} URLContext;

URLContext結構體中還有一個結構體URLProtocol。注:每種協議(rtp,rtmp,file等)對應一個URLProtocol。這個結構體也不在FFMPEG提供的標頭檔案中。從FFMPEG原始碼中翻出其的定義:

typedef struct URLProtocol {
	const char *name;
	int (*url_open)(URLContext *h, const char *url, int flags);
	int (*url_read)(URLContext *h, unsigned char *buf, int size);
	int (*url_write)(URLContext *h, const unsigned char *buf, int size);
	int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
	int (*url_close)(URLContext *h);
	struct URLProtocol *next;
	int (*url_read_pause)(URLContext *h, int pause);
	int64_t (*url_read_seek)(URLContext *h, int stream_index,
		int64_t timestamp, int flags);
	int (*url_get_file_handle)(URLContext *h);
	int priv_data_size;
	const AVClass *priv_data_class;
	int flags;
	int (*url_check)(URLContext *h, int mask);
} URLProtocol;

在這個結構體中,除了一些回撥函式介面之外,有一個變數const char *name,該變數儲存了協議的名稱。每一種輸入協議都對應這樣一個結構體。 比如說,檔案協議中程式碼如下(file.c):

URLProtocol ff_file_protocol = {
    .name                = "file",
    .url_open            = file_open,
    .url_read            = file_read,
    .url_write           = file_write,
    .url_seek            = file_seek,
    .url_close           = file_close,
    .url_get_file_handle = file_get_handle,
    .url_check           = file_check,
};

3. AVStream

AVStream是儲存每一個視訊/音訊流資訊的結構體, 結構體定義位於avformat.h檔案中.

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音訊檔案附帶的專輯封面。

4. AVCodecContext

AVCodecContext是包含變數較多的結構體(感覺差不多是變數最多的結構體), 結構體的定義位於avcodec.h中. 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中很多的引數是編碼的時候使用的,而不是解碼的時候使用的。

4.1.codec_type

編解碼器型別有以下幾種:

enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATA
    AVMEDIA_TYPE_VIDEO,
    AVMEDIA_TYPE_AUDIO,
    AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuous
    AVMEDIA_TYPE_SUBTITLE,
    AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparse
    AVMEDIA_TYPE_NB
};

4.2.sample_fmt

在FFMPEG中音訊取樣格式有以下幾種:

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double
 
    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar
 
    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

4.3.profile

在FFMPEG中型有以下幾種,可以看出AAC,MPEG2,H.264,VC-1,MPEG4都有profile的概念。

#define FF_PROFILE_UNKNOWN -99
#define FF_PROFILE_RESERVED -100
 
#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW  1
#define FF_PROFILE_AAC_SSR  2
#define FF_PROFILE_AAC_LTP  3
#define FF_PROFILE_AAC_HE   4
#define FF_PROFILE_AAC_HE_V2 28
#define FF_PROFILE_AAC_LD   22
#define FF_PROFILE_AAC_ELD  38
 
#define FF_PROFILE_H264_CONSTRAINED  (1<<9)  // 8+1; constraint_set1_flag
#define FF_PROFILE_H264_INTRA        (1<<11) // 8+3; constraint_set3_flag
 
#define FF_PROFILE_H264_BASELINE             66
#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED)
#define FF_PROFILE_H264_MAIN                 77
#define FF_PROFILE_H264_EXTENDED             88
#define FF_PROFILE_H264_HIGH                 100
#define FF_PROFILE_H264_HIGH_10              110
#define FF_PROFILE_H264_HIGH_10_INTRA        (110|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_422             122
#define FF_PROFILE_H264_HIGH_422_INTRA       (122|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_HIGH_444             144
#define FF_PROFILE_H264_HIGH_444_PREDICTIVE  244
#define FF_PROFILE_H264_HIGH_444_INTRA       (244|FF_PROFILE_H264_INTRA)
#define FF_PROFILE_H264_CAVLC_444            44

5. AVCodec

AVCodec是儲存編解碼器資訊的結構體, 結構體的定義位於avcodec.h檔案中.

最主要的幾個變數:

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:私有資料的大小

5.1.enum AVMediaType type

AVMediaType定義如下:

enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATA
    AVMEDIA_TYPE_VIDEO,
    AVMEDIA_TYPE_AUDIO,
    AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuous
    AVMEDIA_TYPE_SUBTITLE,
    AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparse
    AVMEDIA_TYPE_NB
};

5.2.enum AVCodecID id

AVCodecID定義如下:

enum AVCodecID {
    AV_CODEC_ID_NONE,
 
    /* video codecs */
    AV_CODEC_ID_MPEG1VIDEO,
    AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
    AV_CODEC_ID_MPEG2VIDEO_XVMC,
    AV_CODEC_ID_H261,
    AV_CODEC_ID_H263,
    AV_CODEC_ID_RV10,
    AV_CODEC_ID_RV20,
    AV_CODEC_ID_MJPEG,
    AV_CODEC_ID_MJPEGB,
    AV_CODEC_ID_LJPEG,
    AV_CODEC_ID_SP5X,
    AV_CODEC_ID_JPEGLS,
    AV_CODEC_ID_MPEG4,
    AV_CODEC_ID_RAWVIDEO,
    AV_CODEC_ID_MSMPEG4V1,
    AV_CODEC_ID_MSMPEG4V2,
    AV_CODEC_ID_MSMPEG4V3,
    AV_CODEC_ID_WMV1,
    AV_CODEC_ID_WMV2,
    AV_CODEC_ID_H263P,
    AV_CODEC_ID_H263I,
    AV_CODEC_ID_FLV1,
    AV_CODEC_ID_SVQ1,
    AV_CODEC_ID_SVQ3,
    AV_CODEC_ID_DVVIDEO,
    AV_CODEC_ID_HUFFYUV,
    AV_CODEC_ID_CYUV,
    AV_CODEC_ID_H264,
    ...(程式碼太長,略)
}

5.3.const enum AVPixelFormat *pix_fmts

AVPixelFormat定義如下:

enum AVPixelFormat {
    AV_PIX_FMT_NONE = -1,
    AV_PIX_FMT_YUV420P,   ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
    AV_PIX_FMT_YUYV422,   ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
    AV_PIX_FMT_RGB24,     ///< packed RGB 8:8:8, 24bpp, RGBRGB...
    AV_PIX_FMT_BGR24,     ///< packed RGB 8:8:8, 24bpp, BGRBGR...
    AV_PIX_FMT_YUV422P,   ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
    AV_PIX_FMT_YUV444P,   ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
    AV_PIX_FMT_YUV410P,   ///< planar YUV 4:1:0,  9bpp, (1 Cr & Cb sample per 4x4 Y samples)
    AV_PIX_FMT_YUV411P,   ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
    AV_PIX_FMT_GRAY8,     ///<        Y        ,  8bpp
    AV_PIX_FMT_MONOWHITE, ///<        Y        ,  1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb
    AV_PIX_FMT_MONOBLACK, ///<        Y        ,  1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb
    AV_PIX_FMT_PAL8,      ///< 8 bit with PIX_FMT_RGB32 palette
    AV_PIX_FMT_YUVJ420P,  ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range
    AV_PIX_FMT_YUVJ422P,  ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range
    AV_PIX_FMT_YUVJ444P,  ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range
    AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing
    AV_PIX_FMT_XVMC_MPEG2_IDCT,
    ...(程式碼太長,略)
}

5.4.const enum AVSampleFormat *sample_fmts

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double
 
    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar
 
    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};

每一個編解碼器對應一個該結構體,檢視一下ffmpeg的原始碼,我們可以看一下H.264解碼器的結構體如下所示(h264.c):

AVCodec ff_h264_decoder = {
    .name           = "h264",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = CODEC_ID_H264,
    .priv_data_size = sizeof(H264Context),
    .init           = ff_h264_decode_init,
    .close          = ff_h264_decode_end,
    .decode         = decode_frame,
    .capabilities   = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY |
                      CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,
    .flush= flush_dpb,
    .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
    .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
    .update_thread_context = ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
    .profiles = NULL_IF_CONFIG_SMALL(profiles),
    .priv_class     = &h264_class,
};

下面簡單介紹一下遍歷ffmpeg中的解碼器資訊的方法(這些解碼器以一個連結串列的形式儲存):

1.註冊所有編解碼器:av_register_all(); 2.宣告一個AVCodec型別的指標,比如說AVCodec* first_c; 3.呼叫av_codec_next()函式,即可獲得指向連結串列下一個解碼器的指標,迴圈往復可以獲得所有解碼器的資訊。注意,如果想要獲得指向第一個解碼器的指標,則需要將該函式的引數設定為NULL。

6. AVPacket

AVPacket是儲存壓縮編碼資料相關資訊的結構體, 結構體的定義位於avcodec.h檔案中. 在AVPacket結構體中,重要的變數有以下幾個:

uint8_t *data:壓縮編碼的資料。
例如對於H.264來說。1個AVPacket的data通常對應一個NAL。
注意:在這裡只是對應,而不是一模一樣。他們之間有微小的差別:[使用FFMPEG類庫分離出多媒體檔案中的H.264碼流](https://blog.csdn.net/leixiaohua1020/article/details/11800877)
因此在使用FFMPEG進行視音訊處理的時候,常常可以將得到的AVPacket的data資料直接寫成檔案,從而得到視音訊的碼流檔案。

int   size:data的大小
int64_t pts:顯示時間戳
int64_t dts:解碼時間戳
int   stream_index:標識該AVPacket所屬的視訊/音訊流。

7. AVFrame

AVFrame是包含碼流引數較多的結構體, 結構體的定義位於avcodec.h中. 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的

7.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)

7.2.pict_type

包含以下型別:

enum AVPictureType {
    AV_PICTURE_TYPE_NONE = 0, ///< Undefined
    AV_PICTURE_TYPE_I,     ///< Intra
    AV_PICTURE_TYPE_P,     ///< Predicted
    AV_PICTURE_TYPE_B,     ///< Bi-dir predicted
    AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG4
    AV_PICTURE_TYPE_SI,    ///< Switching Intra
    AV_PICTURE_TYPE_SP,    ///< Switching Predicted
    AV_PICTURE_TYPE_BI,    ///< BI type
};

7.3.sample_aspect_ratio

寬高比是一個分數,FFMPEG中用AVRational表達分數:

/**
 * rational number numerator/denominator
 */
typedef struct AVRational{
    int num; ///< numerator
    int den; ///< denominator
} AVRational;

7.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的。 每行巨集塊數: int mb_stride = pCodecCtx->width/16+1 巨集塊的總數: int mb_sum = ((pCodecCtx->height+15)>>4)*(pCodecCtx->width/16+1)

7.5.motion_subsample_log2

1個運動向量所能代表的畫面大小(用寬或者高表示,單位是畫素),注意,這裡取了log2。 程式碼註釋中給出以下資料:4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2 即1個運動向量代表16x16的畫面的時候,該值取4;1個運動向量代表8x8的畫面的時候,該值取3…以此類推

7.6.motion_val

運動矢量表儲存了一幀視訊中的所有運動向量。該值的儲存方式比較特別: int16_t (*motion_val[2])[2];

註釋中給了一段程式碼:

int mv_sample_log2= 4 - motion_subsample_log2;
int mb_width= (width+15)>>4;
int mv_stride= (mb_width << mv_sample_log2) + 1;
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代表一行運動向量的個數):

                //例如8x8劃分的運動向量與巨集塊的關係:
				//-------------------------
				//|          |            |
				//|mv[x]     |mv[x+1]     |
				//-------------------------
				//|          |	          |
				//|mv[x+line]|mv[x+line+1]|
				//-------------------------

7.7.mb_type

巨集塊型別表儲存了一幀視訊中的所有巨集塊的型別。其儲存方式和QP表差不多。只不過其是uint32型別的,而QP表是uint8型別的。每個巨集塊對應一個巨集塊型別變數。

巨集塊型別如下定義所示:

//The following defines may change, don't expect compatibility if you use them.
#define MB_TYPE_INTRA4x4   0x0001
#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific
#define MB_TYPE_INTRA_PCM  0x0004 //FIXME H.264-specific
#define MB_TYPE_16x16      0x0008
#define MB_TYPE_16x8       0x0010
#define MB_TYPE_8x16       0x0020
#define MB_TYPE_8x8        0x0040
#define MB_TYPE_INTERLACED 0x0080
#define MB_TYPE_DIRECT2    0x0100 //FIXME
#define MB_TYPE_ACPRED     0x0200
#define MB_TYPE_GMC        0x0400
#define MB_TYPE_SKIP       0x0800
#define MB_TYPE_P0L0       0x1000
#define MB_TYPE_P1L0       0x2000
#define MB_TYPE_P0L1       0x4000
#define MB_TYPE_P1L1       0x8000
#define MB_TYPE_L0         (MB_TYPE_P0L0 | MB_TYPE_P1L0)
#define MB_TYPE_L1         (MB_TYPE_P0L1 | MB_TYPE_P1L1)
#define MB_TYPE_L0L1       (MB_TYPE_L0   | MB_TYPE_L1)
#define MB_TYPE_QUANT      0x00010000
#define MB_TYPE_CBP        0x00020000
//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...)

一個巨集塊如果包含上述定義中的一種或兩種型別,則其對應的巨集塊變數的對應位會被置1。 注:一個巨集塊可以包含好幾種類型,但是有些型別是不能重複包含的,比如說一個巨集塊不可能既是16x16又是8x8。

7.8.ref_index

運動估計參考幀列表儲存了一幀視訊中所有巨集塊的參考幀索引。這個列表其實在比較早的壓縮編碼標準中是沒有什麼用的。只有像H.264這樣的編碼標準才有多參考幀的概念。但是這個欄位目前我還沒有研究透。只是知道每個巨集塊包含有4個該值,該值反映的是參考幀的索引。