音視頻開發之旅(61)- 調試分析FFmpeg (解碼部分的)常用結構體

上一篇我們分析了解封裝部分的常用結構體,這篇我們來學習分析解碼部分的常用結構體。

目錄

  1. 斷點分析ffplay解碼流程及關鍵結構體
  2. (解碼部分)常用結構體以及之間的關系分析
  3. 資料
  4. 收獲

一、斷點分析ffplay解碼流程及關鍵結構體

還是從read_thread進行分析

        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);

stream_component_open 打開指定的流

static int stream_component_open(VideoState *is, int stream_index)

AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
const AVCodec *codec;

其中的關鍵函數如下 
avctx = avcodec_alloc_context3(NULL);
int avcodec_parameters_to_context(AVCodecContext *codec,
                                  const AVCodecParameters *par)
codec = avcodec_find_decoder(avctx->codec_id);
codec = avcodec_find_decoder_by_name(forced_codec_name);
//打開codec
avcodec_open2(avctx, codec, &opts)

//音頻解碼
decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread)
decoder_start(&is->auddec, audio_thread, "audio_decoder", is)

//視頻解碼
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread)
decoder_start(&is->viddec, video_thread, "video_decoder", is)

avcodec_free_context(&avctx);

涉及到結構體:AVFormatContext、AVCodecContext、AVCodec

avcodec_parameters_to_context

int avcodec_parameters_to_context(AVCodecContext *codec,
                                  const AVCodecParameters *par)

涉及到結構體:AVCodecContext、AVCodecParameters

avcodec_find_decoder通過codecid查找解碼器

const AVCodec *avcodec_find_decoder(enum AVCodecID id)

涉及到結構體:AVCodec

avcodec_open2

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)

涉及到結構體:AVCodecContext、AVCodec

解碼線程

static int audio_thread(void *arg)
static int video_thread(void *arg)

解碼線程中以AVFrame作為解壓縮后的結構體

涉及到結構體:AVFrame

然后分別開啟音頻和視頻的解碼線程開始解碼。我們可以看到涉及的主要結構體有AVCodecContext 、AVCodecParameters 、AVCodec 、AVFrame

作為解碼的輸入AVPacket(存儲壓縮編碼數據相關信息的結構體)以及AVStream(每個AVStream存儲一個視頻/音頻流的相關數據;是解封裝器分離出來的流對象)我們上一篇已經介紹過,下面我們來主要分析解碼相關的幾個結構體AVCodecContext 、AVCodec 、AVFrame

二、(解碼部分)常用結構體以及之間的關系分析

2.1 常用結構體以及之間的關系(再引用一次,雷神總結梳理的太好了)

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


引用自: https://blog.csdn.net/leixiaohua1020/article/details/11693997

他們之間的關系如下:


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

2.2 AVCodecContext
AVCodecContext是一個描述解碼器上下文的數據結構,包含了很多編碼器需要的參數信息。
該結構體定義位于libavcodec/AVcodec.h中,主要變量如下:

enum AVMediaType codec_type; // 該枚舉定義在libavutil/Avutil.h中,編碼的類型,音頻、視頻、字母等 
const struct AVCodec  *codec;//采用的解碼器AVCodec,下面單獨分析
enum AVCodecID     codec_id; // 該枚舉定義在libavcodec/Codec_id.h中,定了一了所有的編解碼器id 
void *priv_data;
struct AVCodecInternal *internal;//內部使用的上下文環境
void *opaque;
int64_t bit_rate;//平均碼率
uint8_t *extradata; int extradata_size:針對特定編碼器包含的附加信息(例如對于H.264解碼器來說,存儲SPS,PPS等)

AVRational time_base;//時間基,根據該參數,可以把PTS轉化為實際的時間(單位為秒s)
int width, height;//僅視頻類型用
int gop_size;//關鍵幀間隔
int max_b_frames;//最大b幀數量
int has_b_frames;//是否有b幀,關系到視頻的壓縮比率,一般b幀越多壓縮比越大
int slice_count;//片的總和,關于slice相關,可以[音視頻開發之旅(56) -H264/AVC基本結構](https://mp.weixin.qq.com/s?__biz=MzU5NjkxMjE5Mg==&mid=2247484355&idx=1&sn=538378561c16b640a4ea42bc1f354044&chksm=fe5a32ecc92dbbfa1d6a2e83f22aece727badb99966b6e621322ed8bf6b0cd8f0b2d1c262013&token=778944351&lang=zh_CN#rd)
AVRational sample_aspect_ratio;//采樣率


  /* audio only */
int sample_rate; ///< samples per second 音頻采樣率
int channels;    ///< number of audio channels 通道數
enum AVSampleFormat sample_fmt;  ///< sample format 采樣格式,定義在libavutil/Samplefmt.h中

enum AVColorSpace colorspace;//顏色空間,定義在libavutil/Pixfmt.h 
AVRational framerate;//幀率
enum AVPixelFormat sw_pix_fmt;//像素格式,如yuv420pdeng ,定義在libavutil/Pixfmt.h 如果設置不對導致解碼器無法正常解碼會出現花屏的情況。

這個結構體涉及的變量很多,并且很多是和編碼相關,解碼用的的其實并不算太多。

2.3 AVCodec
AVCodec是存儲編碼器信息的結構體。
該結構體定義位于libavcodec/Codec.h中,主要變量如下:

const char *name;//codec的名稱
enum AVMediaType type;//codec的類型,AVCodecContext中已經介紹
enum AVCodecID id;//codec的id,AVCodecContext中已經介紹
int capabilities;//編解碼的能力,見 AV_CODEC_CAP_
const AVRational *supported_framerates;//支持的幀率
const enum AVPixelFormat *pix_fmts;//支持的像素格式
const int *supported_samplerates; //支持的音頻采樣率
const enum AVSampleFormat *sample_fmts;//支持的采樣格式

下面是一些函數指針
int (*init)(struct AVCodecContext *);//初始化
int (*encode2)(struct AVCodecContext *avctx, struct AVPacket *avpkt,const struct AVFrame *frame, int *got_packet_ptr);//編碼
int (*decode)(struct AVCodecContext *avctx, void *outdata,
                  int *got_frame_ptr, struct AVPacket *avpkt);
int (*close)(struct AVCodecContext *);//解碼
int (*receive_packet)(struct AVCodecContext *avctx, struct AVPacket *avpkt);//接收packet數據
int (*receive_frame)(struct AVCodecContext *avctx, struct AVFrame *frame);//接收frame數據
void (*flush)(struct AVCodecContext *);//刷新緩沖區

2.4 AVFrame
AVFrame一般用于存儲原始數據(即非壓縮數據,例如對于視頻而言YUV、RGB,對于音頻而言 PCM),此外還包含了一些相關的信息。比如說,解碼的時候存儲了宏塊類型表,QP表,運動矢量表等數據。編碼的時候也存儲了相關的數據。
該結構體定義位于libavutil/Frame.h中,主要變量如下:

#define AV_NUM_DATA_POINTERS 8
uint8_t *data[AV_NUM_DATA_POINTERS];//對于planar格式的數據(例如YUV420P),則會分開成data[0],data[1],data[2]...(YUV420P中data[0]存Y,data[1]存U,data[2]存V)
int width, height;//視頻寬高
int nb_samples;//每個信道音頻采樣點的個數
int format;//幀的像素格式
int key_frame;//1 -> keyframe, 0-> not
enum AVPictureType pict_type;//定義在libavutil/AVutil.h中,該幀的類型,I、P、B等
AVRational sample_aspect_ratio;//寬高比(16:9,4:3...)FFMPEG中用AVRational表達分數:
int64_t pts;//顯示時間戳
int64_t pkt_dts;//從packet復制的PTS
int quality;
void *opaque;
int coded_picture_number;//編碼幀序號
int display_picture_number;//顯示幀序號
int8_t *qscale_table;//QP表 QP表指向一塊內存,里面存儲的是每個宏塊的QP值。宏塊的標號是從左往右,一行一行的來的。每個宏塊對應1個QP。
uint8_t *mbskip_table;//跳過宏塊表
int16_t (*motion_val[2])[2];//運動矢量表
int8_t *ref_index[2];//運動估計參考幀列表
int interlaced_frame;//交錯幀,表示圖像內容是交錯的,即是否是隔行掃描
int sample_rate;//音頻采樣率
uint8_t motion_subsample_log2;//一個宏塊中的運動矢量采樣個數,取log2的.1個運動矢量所能代表的畫面大小(用寬或者高表示,單位是像素),注意,這里取了log2。

三、資料

  1. 《Android音視頻開發》-第八章
  2. FFMPEG中最關鍵的結構體之間的關系
  3. FFMPEG結構體分析:AVCodecContext
  4. FFMPEG結構體分析:AVCodec
  5. FFMPEG結構體分析:AVFrame
  6. FFMPEG 實現 YUV,RGB各種圖像原始數據之間的轉換(swscale)

四、收獲

通過本篇的學習實踐,收獲如下:

  1. 斷點分析解碼的流程加深理解
  2. 重溫ffmpeg重要結構體之間的關系
  3. 了解了解碼相關的結構體 AVCodecContext、AVCodec、AVFrame. 其中設置到很多編碼協議相關知識,需要系統性的在進行學習(X265)

感謝你的閱讀
下一篇我們學習知識fflay關鍵結構體的最后一篇,解協議相關結構體,歡迎關注公眾號“音視頻開發之旅”,一起學習成長。
歡迎交流

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容