目錄
- ffplay的斷點調(diào)試
- (解封裝部分)常用結(jié)構(gòu)體以及之間的關(guān)系分析
- 資料
- 收獲
工欲善其事笔呀,必先利其器埠帕,斷點調(diào)試媳瞪,對我們梳理流程排查問題十分重要抑片,可以ffmpeg的調(diào)試可以在XCode、VS code以及QT等ide上進行方便的調(diào)試分析硫惕。本篇我們以XCode為例來先介紹下ffplay的斷點調(diào)試茧痕,以ffmpeg4.4版本來進行分析。
一恼除、ffplay的斷點調(diào)試
首先下載和編譯ffmpeg踪旷,具體可以參考音視頻開發(fā)之旅(33) -交叉編譯android使用的FFmpeg(3.x和4.x)
區(qū)別在于,我們這次不是交叉編譯豁辉,而是在Mac上編譯安裝調(diào)試令野。
./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
編譯成功之后我們會看到幾個重要的可執(zhí)行文件ffmpeg_g、ffprobe_g以及ffplay_g
,而接下來的運行和調(diào)試就會用到他們徽级。
如何在Xcode下配置調(diào)試ffmpeg源碼請參考:http://www.reibang.com/p/27a90b113413
我們在ffplay.c的main函數(shù)打斷點進行進行分析ffplay解封裝(read_thread)流程中用的的結(jié)構(gòu)體气破。
打開媒體流
VideoState *stream_open(const char *filename,const AVInputFormat *iformat)
涉及到結(jié)構(gòu)體:AVInputFormat
啟動readthread開始讀取
is->read_tid = SDL_CreateThread(read_thread, "read_thread", is);
分配AVFormatContext內(nèi)存
AVFormatContext ic = avformat_alloc_context();
打開流媒體文件
int avformat_open_input(AVFormatContext **ps, const char *filename,
const AVInputFormat *fmt, AVDictionary **options)
涉及到結(jié)構(gòu)體:AVFormatContext、AVInputFormat灰追、AVDictionary
獲取流信息
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
涉及到結(jié)構(gòu)體:AVStream AVCodecParameters AVRational
循環(huán)讀取frame數(shù)據(jù)
for (;;) {
...
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
...
}
涉及到結(jié)構(gòu)體:AVFormatContext堵幽、AVPacket等
解封裝的流程先到這里,可見如果想學(xué)習(xí)ffplay的源碼弹澎,首先要搞清楚主要流程以及過程中涉及的關(guān)鍵結(jié)構(gòu)體。
下一節(jié)我們來具體分析這些結(jié)構(gòu)體努咐。
三苦蒿、(解封裝部分)常用結(jié)構(gòu)體以及之間的關(guān)系分析常用結(jié)構(gòu)體以及之間的關(guān)系分析
3.1 常用結(jié)構(gòu)體以及之間的關(guān)系
FFMPEG中結(jié)構(gòu)體很多。最關(guān)鍵的結(jié)構(gòu)體可以分成以下幾類:
a) 解協(xié)議(http,rtsp,rtmp,mms)
AVIOContext渗稍,URLProtocol佩迟,URLContext主要存儲視音頻使用的協(xié)議的類型以及狀態(tài)。URLProtocol存儲輸入視音頻使用的封裝格式竿屹。每種協(xié)議都對應(yīng)一個URLProtocol結(jié)構(gòu)报强。(注意:FFMPEG中文件也被當做一種協(xié)議“file”)
b) 解封裝(flv,avi,rmvb,mp4)
AVFormatContext主要存儲視音頻封裝格式中包含的信息;AVInputFormat存儲輸入視音頻使用的封裝格式拱燃。每種視音頻封裝格式都對應(yīng)一個AVInputFormat 結(jié)構(gòu)秉溉。
c) 解碼(h264,mpeg2,aac,mp3)
每個AVStream存儲一個視頻/音頻流的相關(guān)數(shù)據(jù);每個AVStream對應(yīng)一個AVCodecContext,存儲該視頻/音頻流使用解碼方式的相關(guān)數(shù)據(jù)召嘶;每個AVCodecContext中對應(yīng)一個AVCodec父晶,包含該視頻/音頻對應(yīng)的解碼器。每種解碼器都對應(yīng)一個AVCodec結(jié)構(gòu)弄跌。
d) 存數(shù)據(jù)
視頻的話甲喝,每個結(jié)構(gòu)一般是存一幀;音頻可能有好幾幀
解碼前數(shù)據(jù):AVPacket
解碼后數(shù)據(jù):AVFrame
引用自: https://blog.csdn.net/leixiaohua1020/article/details/11693997
他們之間的關(guān)系如下:
圖片來自:FFMPEG中最關(guān)鍵的結(jié)構(gòu)體之間的關(guān)系
3.2铛只。AVFormatContext
該結(jié)構(gòu)體定義在libavformat/Avformat.h中埠胖,它是一個貫穿始終的數(shù)據(jù)結(jié)構(gòu),很多函數(shù)都要用到它作為參數(shù)淳玩。幾個主要變量的作用如下:
struct AVInputFormat *iformat:輸入數(shù)據(jù)的封裝格式
struct AVOutputFormat *oformat:輸出數(shù)據(jù)的封裝格式
AVIOContext *pb:輸入數(shù)據(jù)的緩存
unsigned int nb_streams:視音頻流的個數(shù)
AVStream **streams:視音頻流
char filename[1024]:文件名
int64_t duration:時長(單位:微秒us押袍,轉(zhuǎn)換為秒需要除以1000000)
int bit_rate:比特率(單位bps,轉(zhuǎn)換為kbps需要除以1000)
AVDictionary *metadata:元數(shù)據(jù)
3.3 AVInputFormat
該結(jié)構(gòu)體定義也在libavformat/Avformat.h中凯肋,是解封裝器對象主要的變量的作用如下
const char *name: 格式的名稱
const char *mime_type: mime類型如 video/avc video/hevc audio/aac等
以及一系列函數(shù)指針
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存儲一個視頻/音頻流的相關(guān)數(shù)據(jù)谊惭;是解封裝器分離出來的流對象,即解封裝的產(chǎn)物侮东,它保存在AVFormatcontext中圈盔。
該結(jié)構(gòu)體定義也在libavformat/Avformat.h中, 主要變量如下:
int index; 流索引
int id; 流id
void *priv_data; 流數(shù)據(jù)
AVRational time_base; 時間基,通過該值可以把PTS悄雅,DTS轉(zhuǎn)化為真正的時間驱敲;PTS*time_base=真正的時間
int64_t duration:流長度
AVRational sample_aspect_ratio; 采樣率
AVRational avg_frame_rate:幀率
AVCodecContext *codec:指向該視頻/音頻流的AVCodecContext(它們是一一對應(yīng)的關(guān)系)
AVStream是解封裝環(huán)節(jié)的輸出宽闲,同時也是解碼環(huán)節(jié)的輸入众眨,每個AVStream對應(yīng)一個AVCodecContext,存儲該視頻/音頻流使用解碼方式的相關(guān)數(shù)據(jù)容诬;每個AVCodecContext中對應(yīng)一個AVCodec娩梨,包含該視頻/音頻對應(yīng)的解碼器。每種解碼器都對應(yīng)一個AVCodec結(jié)構(gòu)览徒。
解碼部分的數(shù)據(jù)結(jié)構(gòu)分析我們下一篇再來分析學(xué)習(xí)狈定。
3.5 AVPacket
存儲壓縮編碼數(shù)據(jù)相關(guān)信息的結(jié)構(gòu)體,保存了解封裝之后习蓬,解碼之前的數(shù)據(jù)以及PTS纽什、DTS、Duration以及streamId等信息
該結(jié)構(gòu)體定義位于libavcodec/Packet.h中躲叼,主要變量如下:
uint8_t *data; 對于H.264來說芦缰。1個AVPacket的data通常對應(yīng)一個NAL。
int size:data的大小
int64_t pts:顯示時間戳
int64_t dts:解碼時間戳
AVPacketSideData *side_data;附加信息
三枫慷、資料
《Android音視頻開發(fā)》-第八章
Xcode調(diào)試ffmpeg源碼(十五)
FFMPEG中最關(guān)鍵的結(jié)構(gòu)體之間的關(guān)系
FFMPEG結(jié)構(gòu)體分析:AVFormatContext
FFMPEG結(jié)構(gòu)體分析:AVStream
FFMPEG結(jié)構(gòu)體分析:AVPacket
四让蕾、收獲
通過本篇的學(xué)習(xí)實踐浪规,我們學(xué)習(xí)到了
- 如何在Xcode下斷點調(diào)試ffmpeg并進行ffplay解封裝流程的分析
- 了解常用結(jié)構(gòu)體之間的關(guān)系:解協(xié)議、解封裝涕俗、解碼對應(yīng)的結(jié)構(gòu)體以及之間的關(guān)系
- 了解解封裝相關(guān)的幾個關(guān)鍵結(jié)構(gòu)的的主要變量和函數(shù)罗丰。AVFormatContext、AVInputFormat再姑、AVStream
感謝你的閱讀
下一篇我們分析ffmpeg解碼部分的常用結(jié)構(gòu)體萌抵,歡迎關(guān)注公眾號“音視頻開發(fā)之旅”,一起學(xué)習(xí)成長元镀。
歡迎交流