目錄
- ffplay的斷點調試
- (解封裝部分)常用結構體以及之間的關系分析
- 資料
- 收獲
工欲善其事,必先利其器,斷點調試,對我們梳理流程排查問題十分重要,可以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源碼請參考:http://www.lxweimin.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
四、收獲
通過本篇的學習實踐,我們學習到了
- 如何在Xcode下斷點調試ffmpeg并進行ffplay解封裝流程的分析
- 了解常用結構體之間的關系:解協議、解封裝、解碼對應的結構體以及之間的關系
- 了解解封裝相關的幾個關鍵結構的的主要變量和函數。AVFormatContext、AVInputFormat、AVStream
感謝你的閱讀
下一篇我們分析ffmpeg解碼部分的常用結構體,歡迎關注公眾號“音視頻開發之旅”,一起學習成長。
歡迎交流