FFmpeg Principle學習new_video_stream添加視頻輸出流
正文
new_video_stream()
函數的流程相對來說比較簡單,主要的邏輯如下:
1, 調 new_output_stream()
函數來創建 OutputStream
輸出流,以及 AVCodecContext
編碼器上下文。
new_output_stream()
是一個公共函數,創建 音頻流,數據流,字幕流都用瞭它。
new_output_stream()
會把命令行的一些公共參數賦值給 OutputStream
跟 AVCodecContext
。
這些公共參數是指音頻,視頻,字幕都可能會有的參數。因為 new_output_stream()
是一個公共函數。
2, 調 MATCH_PER_STREAM_OPT()
宏函數,把 OptionsContext
裡面視頻相關的參數,賦值給 給 OutputStream
跟 AVCodecContext
。
流程圖
可以看到,實際上就兩步,new_video_stream()
肯定會創建視頻的輸出流,還有視頻的編碼器實例。
公共參數,就在 new_output_stream()
函數 裡面賦值瞭。
視頻相關的參數,就在 new_video_stream()
函數再賦值。
new_video_stream()
跟 new_output_stream()
函數都調用瞭多次 MATCH_PER_STREAM_OPT()
宏函數來提取 OptionsContext
的內容,
MATCH_PER_STREAM_OPT()
其實是 MATCH_PER_TYPE_OPT()
的兄弟函數,
#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\ {\ int i;\ for (i = 0; i < o->nb_ ## name; i++) {\ char *spec = o->name[i].specifier;\ if (!strcmp(spec, mediatype))\ outvar = o->name[i].u.type;\ }\ }
#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ {\ int i, ret, matches = 0;\ SpecifierOpt *so;\ for (i = 0; i < o->nb_ ## name; i++) {\ char *spec = o->name[i].specifier;\ if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\ outvar = o->name[i].u.type;\ so = &o->name[i];\ matches++;\ } else if (ret < 0)\ exit_program(1);\ }\ if (matches > 1)\ WARN_MULTIPLE_OPT_USAGE(name, type, so, st);\ }
這兩個函數,隻有最後一個參數,第四個參數是不一樣的。
mediatype 通常是 a 或者 v,也就是根據 a 還是 v 字符來提取 OptionsContext
裡面音頻或者視頻的選項。
st 是 AVStream,所以如果 AVStream
是音頻,就提取 OptionsContext
裡面的音頻選項,如果是視頻就提取視頻。
這兩個函數的宏實現看起來有點復雜,但他們的區別就是這麼一點區別。
至此,new_video_stream()
函數分析完畢。new_audio_stream()
跟 new_video_stream()
類似,裡面都調瞭 new_output_stream()
。
new_audio_stream()
主要是提取OptionsContext
裡面音頻選項,對 OutputStream
輸出流,以及 AVCodecContext
編碼器 進行賦值操作。
補充一點:雖然 new_video_stream()
裡創建瞭 編碼器實例,但是還沒真正打開編碼器的。打開編碼器,需要等到解碼出第一幀 AVFrame。才會打開編碼器。
原因解析
因為 ffmpeg.exe 的邏輯,是隻有在解碼出第一幀AVFrame的時候,才去用 avfilter_graph_config()
打開 FilterGragh ,這樣才能從出口濾鏡讀取到 輸出的寬高是多少。
ffmpeg.exe
比較謹慎,他可能不太相信容器層記錄的寬度,也有可能有些容器根本沒記錄寬高,所以他必須等到解碼出 AVFrame,才能確定輸入的寬高,確定瞭輸入的寬高,才能創建 buffer入口濾鏡,創建瞭入口濾鏡,才能打開 FilterGragh
。
TODO:這個邏輯非常重要,在本章結尾的時候再重復講一次。
最後是在 init_output_stream_encode()
裡面,從濾鏡出口裡面獲取的寬高,如下:
enc_ctx->width = av_buffersink_get_w(ost->filter->filter); enc_ctx->height = av_buffersink_get_h(ost->filter->filter); enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio
最後,推薦一下 clion 的 Call Hierarchy 功能,可以看到函數的調用流程,如下:
大部分的 集成開發環境都有這個功能,你隻需用 “工具名稱” + Call Hierarchy 關鍵詞,即可搜索到相關教程。
以上就是FFmpeg Principle學習new_video_stream添加視頻輸出流的詳細內容,更多關於FFmpeg Principle new_video_stream的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- FFmpeg Principle學習open_output_file打開輸出文件
- FFmpeg Principle分析Out put File 數據結構
- php如何利用ffmpeg獲取視頻第一幀為縮略圖
- Python 如何利用ffmpeg 處理視頻素材
- ffmpeg網頁視頻流m3u8 ts實現視頻下載