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

目錄

  1. ffplay的斷點調試
  2. (解封裝部分)常用結構體以及之間的關係分析
  3. 資料
  4. 收穫

工欲善其事,必先利其器,斷點調試,對我們梳理流程排查問題十分重要,可以ffmpeg的調試可以在XCode、VS code以及QT等ide上進行方便的調試分析。本篇我們以XCode爲例來先介紹下ffplay的斷點調試,以ffmpeg4.4版本來進行分析。

一、ffplay的斷點調試

首先下載和編譯ffmpeg,具體可以參考音視頻開發之旅(33) -交叉編譯android使用的FFmpeg(3.x和4.x)
區別在於,我們這次不是交叉編譯,而是在Mac上編譯安裝調試。

./configure --enable-static --disable-shared --enable-debug --disable-doc --disable-x86asm --enable-nonfree  --enable-libvpx --enable-gpl  --enable-opengl --enable-libx264  --enable-libx265 --enable-libvmaf
make -j8
sudo make install

編譯成功之後我們會看到幾個重要的可執行文件ffmpeg_g、ffprobe_g以及ffplay_g,而接下來的運行和調試就會用到他們。
如何在Xcode下配置調試ffmpeg源碼請參考:https://www.jianshu.com/p/27a90b113413

我們在ffplay.c的main函數打斷點進行進行分析ffplay解封裝(read_thread)流程中用的的結構體。

打開媒體流

VideoState *stream_open(const char *filename,const AVInputFormat *iformat)

涉及到結構體:AVInputFormat

啓動readthread開始讀取

    is->read_tid     = SDL_CreateThread(read_thread, "read_thread", is);

分配AVFormatContext內存

 AVFormatContext   ic = avformat_alloc_context();

打開流媒體文件

int avformat_open_input(AVFormatContext **ps, const char *filename,
                        const AVInputFormat *fmt, AVDictionary **options)

涉及到結構體:AVFormatContext、AVInputFormat、AVDictionary

獲取流信息

int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)

涉及到結構體:AVStream AVCodecParameters AVRational

循環讀取frame數據

 for (;;) {
     ...
     int av_read_frame(AVFormatContext *s, AVPacket *pkt)
     ...
}

涉及到結構體:AVFormatContext、AVPacket等

解封裝的流程先到這裏,可見如果想學習ffplay的源碼,首先要搞清楚主要流程以及過程中涉及的關鍵結構體。
下一節我們來具體分析這些結構體。

三、(解封裝部分)常用結構體以及之間的關係分析常用結構體以及之間的關係分析

3.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中最關鍵的結構體之間的關係

3.2。AVFormatContext
該結構體定義在libavformat/Avformat.h中,它是一個貫穿始終的數據結構,很多函數都要用到它作爲參數。幾個主要變量的作用如下:

struct AVInputFormat *iformat:輸入數據的封裝格式
struct AVOutputFormat *oformat:輸出數據的封裝格式

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.3 AVInputFormat
該結構體定義也在libavformat/Avformat.h中,是解封裝器對象主要的變量的作用如下

const char *name: 格式的名稱
const char *mime_type: mime類型如 video/avc video/hevc audio/aac等

以及一系列函數指針
int (*read_probe)(const AVProbeData *);
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
int (*read_close)(struct AVFormatContext *);
int (*read_seek)(struct AVFormatContext *,
                     int stream_index, int64_t timestamp, int flags);
int (*read_play)(struct AVFormatContext *);

int (*read_pause)(struct AVFormatContext *);
int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);

3.4 AVStream
每個AVStream存儲一個視頻/音頻流的相關數據;是解封裝器分離出來的流對象,即解封裝的產物,它保存在AVFormatcontext中。

該結構體定義也在libavformat/Avformat.h中, 主要變量如下:

int index;  流索引
int id; 流id
void *priv_data; 流數據
AVRational time_base; 時間基,通過該值可以把PTS,DTS轉化爲真正的時間;PTS*time_base=真正的時間
int64_t duration:流長度
AVRational sample_aspect_ratio; 採樣率
AVRational avg_frame_rate:幀率
AVCodecContext *codec:指向該視頻/音頻流的AVCodecContext(它們是一一對應的關係)

AVStream是解封裝環節的輸出,同時也是解碼環節的輸入,每個AVStream對應一個AVCodecContext,存儲該視頻/音頻流使用解碼方式的相關數據;每個AVCodecContext中對應一個AVCodec,包含該視頻/音頻對應的解碼器。每種解碼器都對應一個AVCodec結構。
解碼部分的數據結構分析我們下一篇再來分析學習。

3.5 AVPacket
存儲壓縮編碼數據相關信息的結構體,保存瞭解封裝之後,解碼之前的數據以及PTS、DTS、Duration以及streamId等信息
該結構體定義位於libavcodec/Packet.h中,主要變量如下:

  uint8_t *data; 對於H.264來說。1個AVPacket的data通常對應一個NAL。
int   size:data的大小
int64_t pts:顯示時間戳
int64_t dts:解碼時間戳
AVPacketSideData *side_data;附加信息

三、資料

《Android音視頻開發》-第八章
Xcode調試ffmpeg源碼(十五)
FFMPEG中最關鍵的結構體之間的關係
FFMPEG結構體分析:AVFormatContext
FFMPEG結構體分析:AVStream
FFMPEG結構體分析:AVPacket

四、收穫

通過本篇的學習實踐,我們學習到了

  1. 如何在Xcode下斷點調試ffmpeg並進行ffplay解封裝流程的分析
  2. 瞭解常用結構體之間的關係:解協議、解封裝、解碼對應的結構體以及之間的關係
  3. 瞭解解封裝相關的幾個關鍵結構的的主要變量和函數。AVFormatContext、AVInputFormat、AVStream

感謝你的閱讀
下一篇我們分析ffmpeg解碼部分的常用結構體,歡迎關注公衆號“音視頻開發之旅”,一起學習成長。
歡迎交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章