FFmpeg?Principle學習new_video_stream添加視頻輸出流
new_video_stream() 函數(shù)流程
new_video_stream() 函數(shù)的流程相對來說比較簡單,主要的邏輯如下:
1, 調 new_output_stream() 函數(shù)來創(chuàng)建 OutputStream 輸出流,以及 AVCodecContext 編碼器上下文。
new_output_stream() 是一個公共函數(shù),創(chuàng)建 音頻流,數(shù)據(jù)流,字幕流都用了它。
new_output_stream() 會把命令行的一些公共參數(shù)賦值給 OutputStream 跟 AVCodecContext。
這些公共參數(shù)是指音頻,視頻,字幕都可能會有的參數(shù)。因為 new_output_stream() 是一個公共函數(shù)。
2, 調 MATCH_PER_STREAM_OPT() 宏函數(shù),把 OptionsContext 里面視頻相關的參數(shù),賦值給 給 OutputStream 跟 AVCodecContext。
流程圖

可以看到,實際上就兩步,new_video_stream() 肯定會創(chuàng)建視頻的輸出流,還有視頻的編碼器實例。
公共參數(shù),就在 new_output_stream() 函數(shù) 里面賦值了。
視頻相關的參數(shù),就在 new_video_stream() 函數(shù)再賦值。
new_video_stream() 跟 new_output_stream() 函數(shù)都調用了多次 MATCH_PER_STREAM_OPT() 宏函數(shù)來提取 OptionsContext 的內容,
MATCH_PER_STREAM_OPT() 其實是 MATCH_PER_TYPE_OPT() 的兄弟函數(shù),
#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);\
}
這兩個函數(shù),只有最后一個參數(shù),第四個參數(shù)是不一樣的。
mediatype 通常是 a 或者 v,也就是根據(jù) a 還是 v 字符來提取 OptionsContext 里面音頻或者視頻的選項。
st 是 AVStream,所以如果 AVStream 是音頻,就提取 OptionsContext 里面的音頻選項,如果是視頻就提取視頻。
這兩個函數(shù)的宏實現(xiàn)看起來有點復雜,但他們的區(qū)別就是這么一點區(qū)別。
至此,new_video_stream() 函數(shù)分析完畢。new_audio_stream() 跟 new_video_stream() 類似,里面都調了 new_output_stream() 。
new_audio_stream() 主要是提取OptionsContext 里面音頻選項,對 OutputStream 輸出流,以及 AVCodecContext 編碼器 進行賦值操作。
補充一點:雖然 new_video_stream() 里創(chuàng)建了 編碼器實例,但是還沒真正打開編碼器的。打開編碼器,需要等到解碼出第一幀 AVFrame。才會打開編碼器。
原因解析
因為 ffmpeg.exe 的邏輯,是只有在解碼出第一幀AVFrame的時候,才去用 avfilter_graph_config() 打開 FilterGragh ,這樣才能從出口濾鏡讀取到 輸出的寬高是多少。
ffmpeg.exe 比較謹慎,他可能不太相信容器層記錄的寬度,也有可能有些容器根本沒記錄寬高,所以他必須等到解碼出 AVFrame,才能確定輸入的寬高,確定了輸入的寬高,才能創(chuàng)建 buffer入口濾鏡,創(chuàng)建了入口濾鏡,才能打開 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 功能,可以看到函數(shù)的調用流程,如下:

大部分的 集成開發(fā)環(huán)境都有這個功能,你只需用 “工具名稱” + Call Hierarchy 關鍵詞,即可搜索到相關教程。
以上就是FFmpeg Principle學習new_video_stream添加視頻輸出流的詳細內容,更多關于FFmpeg Principle new_video_stream的資料請關注腳本之家其它相關文章!
相關文章
Android編程實現(xiàn)可滑動的開關效果(附demo源碼下載)
這篇文章主要介紹了Android編程實現(xiàn)可滑動的開關效果,涉及Android的布局與控件設置技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-04-04
使用RadioButton+Fragment實現(xiàn)底部導航欄效果
這篇文章主要為大家詳細介紹了使用RadioButton+Fragment實現(xiàn)底部導航欄效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
Android通過自定義Activity實現(xiàn)懸浮的Dialog詳解
這篇文章主要給大家介紹了關于Android通過自定義Activity實現(xiàn)懸浮的Dialog的相關資料,文中給出了詳細的示例代碼供大家參考學習,對大家具有一定的參考學習價值,感興趣的朋友們下面來一起看看吧。2017-05-05
Android使用IntentService進行apk更新示例代碼
這篇文章主要介紹了Android使用IntentService進行apk更新示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
Android AlertDialog多種創(chuàng)建方式案例詳解
這篇文章主要介紹了Android AlertDialog多種創(chuàng)建方式案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-08-08

