ffmpeg option的解析
aresample_swr_opts
是AVFilterGraph中的option。
static const AVOption filtergraph_options[] = {
{ "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,
{ .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, F|V|A, "thread_type" },
{ "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = F|V|A, .unit = "thread_type" },
{ "threads", "Maximum number of threads", OFFSET(nb_threads), AV_OPT_TYPE_INT,
{ .i64 = 0 }, 0, INT_MAX, F|V|A, "threads"},
{"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = F|V|A, .unit = "threads"},
{"scale_sws_opts" , "default scale filter options" , OFFSET(scale_sws_opts) ,
AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|V },
{"aresample_swr_opts" , "default aresample filter options" , OFFSET(aresample_swr_opts) ,
AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|A },
{ NULL },
};
因?yàn)槭莖ption,所以就想能不能將這個(gè)option配置到graph里面,分析代碼發(fā)現(xiàn),AVFilterGraph::aresample_swr_opts
在graph解析的時(shí)候不能當(dāng)做filter的option解析。
因?yàn)間raph load的在解析graph
文本的過(guò)程,option來(lái)自filter的option,aresample_swr_opts
是AVFilterGraph的option,而AVFilterGraph不在filter的list中,所以graph解析并不能識(shí)別aresample_swr_opts
。
但是aresample_swr_opts
從名字來(lái)看,就是為了給swresample用的,所以,先看下命令行是怎么用的。
命令行支持,并不是直接用aresample_swr_opts
指定swresample的option,而是不用寫(xiě)成這樣aresample=resampler=swr:filter_size=16
,即用filter帶option的寫(xiě)法,直接寫(xiě)option也能解析。
如下:
ffmpeg -y -i test.wav -filter_size 16 -phase_shift 6 -ar 48000 out.wav
其中filter_size
和phase_shift
會(huì)在解析的時(shí)候讀取swr class的option,匹配成功后,拼接成swr_opts字符串,最后將swr_opts設(shè)置到graph->aresample_swr_opts上。avfiltergraph中協(xié)商如果convert_needed
大于0,就會(huì)創(chuàng)建對(duì)應(yīng)的swresample
,將aresample_swr_opts
中的option作為swresample
的option參數(shù)傳入。
其中-filter_size 16
,-phase_shift 6
是被當(dāng)做option解析的,會(huì)進(jìn)入opt_default
函數(shù),因?yàn)檫@兩個(gè)參數(shù)是swresample的,所以對(duì)應(yīng)代碼是:
#if CONFIG_SWRESAMPLE
if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
av_dict_set(&swr_opts, opt, arg, FLAGS);
consumed = 1;
}
#endif
解析后會(huì)把這兩個(gè)option設(shè)置到swr_opts上。
然后進(jìn)入configure_filtergraph
函數(shù),會(huì)將這個(gè)option設(shè)置到aresample_swr_opts
:
while ((e = av_dict_get(ost->swr_opts, "", e,
AV_DICT_IGNORE_SUFFIX))) {
av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
}
if (strlen(args))
args[strlen(args)-1] = 0;
av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
然后在avfiltergraph的query_formats
函數(shù)中,創(chuàng)建convert filter的時(shí)候?qū)ption傳進(jìn)去:
snprintf(inst_name, sizeof(inst_name), "auto_%s_%d",
neg->conversion_filter, converter_count++);
opts = FF_FIELD_AT(char *, neg->conversion_opts_offset, *graph);
ret = avfilter_graph_create_filter(&convert, filter, inst_name, opts, NULL, graph);
其中,graph參數(shù)中,可以看到aresample_swr_opts
就是"filter_size=16:phase_shift=6"。
graph中解析swr option
跟蹤程序運(yùn)行過(guò)程,在不走ffmpeg命令行程序的時(shí)候,像前面,直接設(shè)置在avfilter里面類(lèi)似cmdutils.c里面的邏輯,添加對(duì)swr的處理,就可以在自定義程序中l(wèi)oad graph的時(shí)候如同命令行程序一樣,解析swr的option。
最終實(shí)現(xiàn)如下:
+#include "libswresample/swresample.h"
#define FF_INTERNAL_FIELDS 1
#include "framequeue.h"
@@ -951,6 +952,10 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options,
char *av_uninit(parsed_key), *av_uninit(value);
const char *key;
int offset= -1;
+#if CONFIG_SWRESAMPLE
+ char swr_opts[256] = { 0 };
+ const AVClass *swr_class = swr_get_class();
+#endif
if (!args)
return 0;
@@ -995,24 +1000,31 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options,
av_free(parsed_key);
return ret;
}
- } else {
- o = av_opt_find(ctx->priv, key, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (!o) {
- av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
- av_free(value);
- av_free(parsed_key);
- return AVERROR_OPTION_NOT_FOUND;
- }
+ } else if (o = av_opt_find(ctx->priv, key, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) {
av_dict_set(options, key, value,
(o->type == AV_OPT_TYPE_FLAGS &&
(value[0] == '-' || value[0] == '+')) ? AV_DICT_APPEND : 0);
+#if CONFIG_SWRESAMPLE
+ } else if (o = av_opt_find(&swr_class, key, NULL, 0, 0)) {
+ av_strlcatf(swr_opts, sizeof(swr_opts), "%s=%s:", key, value);
+#endif
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
+ av_free(value);
+ av_free(parsed_key);
+ return AVERROR_OPTION_NOT_FOUND;
}
av_free(value);
av_free(parsed_key);
}
+ if (strlen(swr_opts)) {
+ swr_opts[strlen(swr_opts) - 1] = 0;
+ av_opt_set(ctx->graph, "aresample_swr_opts", swr_opts, 0);
+ }
+
這樣,在graph中配置上filter_size=16:phase_shift=6
,然后,load graph的時(shí)候并不會(huì)在avfiltergraph里面進(jìn)行解析,播放的時(shí)候,調(diào)用avfilter_graph_reconfig
,調(diào)用棧如下:
query_formats(AVFilterGraph * graph, void * log_ctx) (ffmpeg/libavfilter/avfiltergraph.c:747)
graph_config_formats(AVFilterGraph * graph, void * log_ctx) (ffmpeg/libavfilter/avfiltergraph.c:1373)
avfilter_graph_reconfig(AVFilterGraph * graphctx, void * log_ctx) (ffmpeg/libavfilter/avfiltergraph.c:1519)
movie_async_activate(AVFilterContext * ctx) (ffmpeg/libavfilter/src_movie_async.c:1254)
ff_filter_activate(AVFilterContext * filter) (ffmpeg/libavfilter/avfilter.c:1565)
ff_filter_graph_run_all(AVFilterGraph * graph) (ffmpeg/libavfilter/avfiltergraph.c:1718)
進(jìn)入query_formats之后,獲取opts,就是前面在graph中配置的opts:
opts = FF_FIELD_AT(char *, neg->conversion_opts_offset, *graph);
if (link->type == AVMEDIA_TYPE_AUDIO) {
snprintf(inst_opts, sizeof(inst_opts), "converter=%d:%s", convert_needed, opts ? opts : "");
opts = inst_opts;
}
snprintf(inst_name, sizeof(inst_name), "auto_%s", neg->conversion_filter);
ret = avfilter_graph_create_filter(&convert, filter, inst_name, opts, NULL, graph);
if (ret < 0)
return ret;
if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0)
return ret;
最后創(chuàng)建filter的時(shí)候,就會(huì)將這些options設(shè)置到fitler上。
附:ffmpeg help命令的解析
當(dāng)用戶在命令行中輸入ffmpeg -h
或ffmpeg -help
時(shí),show_help_default
函數(shù)會(huì)被調(diào)用,輸出幫助信息。該函數(shù)還可以在其他情況下被調(diào)用,例如當(dāng)用戶輸入無(wú)效的命令行選項(xiàng)時(shí),或者當(dāng)用戶輸入ffmpeg -h <選項(xiàng)>
時(shí),顯示特定選項(xiàng)的幫助信息。
ffmpeg --help full
如果是help full
,會(huì)有這樣的調(diào)用層次,并且show_avoptions和show_advanced都被賦值為1:
show_help
- show_help_default
- show_help_options
在show_help_options中:
if (opt && *opt) {
if (!strcmp(opt, "long"))
show_advanced = 1;
else if (!strcmp(opt, "full"))
show_advanced = show_avoptions = 1;
else
av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
}
show_avoptions的分支中:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-615690.html
if (show_avoptions) {
int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
show_help_children(avcodec_get_class(), flags);
show_help_children(avformat_get_class(), flags);
#if CONFIG_SWSCALE
show_help_children(sws_get_class(), flags);
#endif
#if CONFIG_SWRESAMPLE
show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
#endif
show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM);
show_help_children(av_bsf_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM);
}
這里,會(huì)遍歷avcodec
,avformat
,sws
,swr
,avfilter
,av_bsf
的class,將其children class
對(duì)應(yīng)的option全部顯示出來(lái)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-615690.html
到了這里,關(guān)于FFmpeg aresample_swr_opts的解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!