FFmpeg 常用結構體


0、FFmpeg 中最關鍵的結構體之間的關系

FFmpeg 中結構體很多。最關鍵的結構體可以分成以下幾類:

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

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

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

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

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

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

4)存數據

視頻的話,每個結構一般是存一幀;音頻可能有好幾幀。解碼前數據:AVPacket;解碼后數據:AVFrame。


它們之間的對應關系如下所示:


一、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的

如果想了解這些變量具體的含義,請看:FFMPEG結構體分析:AVFrame


二、AVFormatContext

AVFormatContext 是存儲音視頻封裝格式中包含的信息的結構體。下面看幾個主要變量的作用(在這里考慮解碼的情況):

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; // 元數據

三、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 中很多的參數是編碼的時候使用的,而不是解碼的時候使用的。如果想了解這些變量具體的含義,請看:FFMPEG結構體分析:AVCodecContext


四、AVIOContext

AVIOContext 是 FFmpeg 管理輸入輸出數據的結構體。其重要的變量如下所示:

unsigned char *buffer; // 緩存開始位置

int buffer_size; // 緩存大小(默認32768)

unsigned char *buf_ptr; // 當前指針讀取到的位置

unsigned char *buf_end; // 緩存結束的位置

void *opaque; // URLContext結構體

在解碼的情況下,buffer 用於存儲 FFmpeg 讀入的數據。例如打開一個視頻文件的時候,先把數據從硬盤讀入 buffer,然后在送給解碼器用於解碼。


五、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; // 支持的像素格式(僅視頻),如RGB24、YUV420P等。

const int *supported_samplerates; // 支持的采樣率(僅音頻)

const enum AVSampleFormat *sample_fmts; // 支持的采樣格式(僅音頻)

const uint64_t *channel_layouts; // 支持的聲道數(僅音頻)

int priv_data_size; // 私有數據的大小

如果想了解這些變量具體的含義,請看:FFMPEG結構體分析:AVCodec


每一個編解碼器對應一個該結構體,查看一下 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,
};

六、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音頻文件附帶的專輯封面。

七、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 結構體的文章:

FFMPEG中最關鍵的結構體之間的關系

FFMPEG結構體分析:AVFrame

FFMPEG結構體分析:AVFormatContext

FFMPEG結構體分析:AVCodecContext

FFMPEG結構體分析:AVIOContext

FFMPEG結構體分析:AVCodec

FFMPEG結構體分析:AVStream

FFMPEG結構體分析:AVPacket



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM