带有 aecho 的 FFmpeg 过滤器配置无法配置所有链接和格式 - avfilter_graph_config
FFmpeg filter config with aecho fails to configure all the links and formats - avfilter_graph_config
我正在按照FFMpeg的官方教程创建过滤器链。 This 教程展示了如何通过链传递数据:
The filter chain it uses is: * (input) -> abuffer -> volume ->
aformat -> abuffersink -> (output)
这是我的代码 - 对不起锅炉代码,它只是 ffmpeg 方式:(
frame = av_frame_alloc();
filterGraph = avfilter_graph_alloc();
if (!frame) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate memory for frame");
return;
}
if (!filterGraph) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor FXProcessor! %s", av_err2str(AVERROR(ENOMEM)));
return;
}
const AVFilter *abuffer;
const AVFilter *abuffersink;
AVFilterContext *aformat_ctx;
const AVFilter *aformat;
AVFilterContext *choisen_beat_fx_ctx;
const AVFilter *choisen_beat_fx;
/* Create the abuffer filter;
* it will be used for feeding the data into the graph. */
abuffer = avfilter_get_by_name("abuffer");
if (!abuffer) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the abuffer filter!");
return;
}
abuffer_ctx = avfilter_graph_alloc_filter(filterGraph, abuffer, "src");
if (!abuffer_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the abuffer_ctx instance! %s",
av_err2str(AVERROR(ENOMEM)));
return;
}
char ch_layout[64];
/* Set the filter options through the AVOptions API. */
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, AV_CH_LAYOUT_STEREO);
av_opt_set(abuffer_ctx, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN);
av_opt_set(abuffer_ctx, "sample_fmt", av_get_sample_fmt_name(AV_SAMPLE_FMT_FLT),
AV_OPT_SEARCH_CHILDREN);
av_opt_set_q(abuffer_ctx, "time_base", (AVRational) {1, defaultSampleRate},
AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(abuffer_ctx, "sample_rate", defaultSampleRate, AV_OPT_SEARCH_CHILDREN);
/* Now initialize the filter; we pass NULL options, since we have already
* set all the options above. */
if (avfilter_init_str(abuffer_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the abuffer filter!");
return;
}
// TODO: select FX's dynamically
/* Create aecho filter. */
if (true) {
choisen_beat_fx = avfilter_get_by_name("volume");
if (!choisen_beat_fx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the aecho filter!");
return;
}
choisen_beat_fx_ctx = avfilter_graph_alloc_filter(filterGraph, choisen_beat_fx, "echo");
if (!choisen_beat_fx_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the choisen_beat_fx_ctx instance! %s",
av_err2str(AVERROR(ENOMEM)));
return;
}
av_opt_set (choisen_beat_fx_ctx, "volume", AV_STRINGIFY(0.5), AV_OPT_SEARCH_CHILDREN);
if (avfilter_init_str(choisen_beat_fx_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the choisen_beat_fx_ctx filter!");
return;
}
}
/* Create the aformat filter;
* it ensures that the output is of the format we want. */
aformat = avfilter_get_by_name("aformat");
if (!aformat) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the aformat filter!");
return;
}
aformat_ctx = avfilter_graph_alloc_filter(filterGraph, aformat, "aformat");
if (!aformat_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the aformat instance!");
return;
}
av_opt_set(aformat_ctx, "sample_fmts", av_get_sample_fmt_name(AV_SAMPLE_FMT_FLT),
AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(aformat_ctx, "sample_rates", defaultSampleRate, AV_OPT_SEARCH_CHILDREN);
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, AV_CH_LAYOUT_STEREO);
av_opt_set(aformat_ctx, "channel_layouts", ch_layout, AV_OPT_SEARCH_CHILDREN);
if (avfilter_init_str(aformat_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the aformat filter!");
return;
}
/* Finally create the abuffersink filter;
* it will be used to get the filtered data out of the graph. */
abuffersink = avfilter_get_by_name("abuffersink");
if (!abuffersink) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the abuffersink filter!");
return;
}
abuffersink_ctx = avfilter_graph_alloc_filter(filterGraph, abuffersink, "sink");
if (!abuffersink_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the abuffersink instance!");
return;
}
/* This filter takes no options. */
if (avfilter_init_str(abuffersink_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the abuffersink instance.!");
return;
}
/* Connect the filters;
* in this simple case the filters just form a linear chain. */
if (avfilter_link(abuffer_ctx, 0, choisen_beat_fx_ctx, 0) != 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error connecting filters.!");
return;
}
if (avfilter_link(choisen_beat_fx_ctx, 0, aformat_ctx, 0) != 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error connecting filters.!");
return;
}
if (avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0) != 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error connecting filters.!");
return;
}
/* Configure the graph. */
if (avfilter_graph_config(filterGraph, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error configuring the filter graph!");
return;
}
此代码在链为
时工作正常
- (input) -> abuffer -> aecho-> aformat -> abuffersink -> (output)
但是,我想使用 adelay
而不是 volume
过滤器。所以我想要:
The filter chain it uses is: * (input) -> abuffer -> volume ->
aformat -> abuffersink -> (output)
我在
更改了代码
choisen_beat_fx = avfilter_get_by_name("volume");
至
choisen_beat_fx = avfilter_get_by_name("aecho");
并删除了行
av_opt_set (choisen_beat_fx_ctx, "volume", AV_STRINGIFY(0.5), AV_OPT_SEARCH_CHILDREN);
一切顺利,直到最后一行。
avfilter_graph_config
失败并且 returns 负值。函数文档:
avfilter_graph_config: Check validity and configure all the links and
formats in the graph.
所以我猜我需要额外的链接来将 aecho 插入我的链?如何将 aecho 插入我的过滤器链?
好的问题是,我需要使用 aresample
过滤器进行编译才能正常工作。我重新编译了,神奇的是它现在可以工作了。
以下是我发现问题的方法。创建通用日志回调:
void ffmpegErrorCallback(void *ptr, int level, const char *fmt, va_list vargs) {
LOGE("ffmpegErrorCallback Error Occurred! Err: %s", fmt);
}
av_log_set_level(AV_LOG_ERROR);
av_log_set_callback(ffmpegErrorCallback);
FFmpeg 现在会将错误记录为人类可读的消息。它告诉我找不到 aresample
过滤器。我就是这样解决问题的。
我正在按照FFMpeg的官方教程创建过滤器链。 This 教程展示了如何通过链传递数据:
The filter chain it uses is: * (input) -> abuffer -> volume -> aformat -> abuffersink -> (output)
这是我的代码 - 对不起锅炉代码,它只是 ffmpeg 方式:(
frame = av_frame_alloc();
filterGraph = avfilter_graph_alloc();
if (!frame) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate memory for frame");
return;
}
if (!filterGraph) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor FXProcessor! %s", av_err2str(AVERROR(ENOMEM)));
return;
}
const AVFilter *abuffer;
const AVFilter *abuffersink;
AVFilterContext *aformat_ctx;
const AVFilter *aformat;
AVFilterContext *choisen_beat_fx_ctx;
const AVFilter *choisen_beat_fx;
/* Create the abuffer filter;
* it will be used for feeding the data into the graph. */
abuffer = avfilter_get_by_name("abuffer");
if (!abuffer) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the abuffer filter!");
return;
}
abuffer_ctx = avfilter_graph_alloc_filter(filterGraph, abuffer, "src");
if (!abuffer_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the abuffer_ctx instance! %s",
av_err2str(AVERROR(ENOMEM)));
return;
}
char ch_layout[64];
/* Set the filter options through the AVOptions API. */
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, AV_CH_LAYOUT_STEREO);
av_opt_set(abuffer_ctx, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN);
av_opt_set(abuffer_ctx, "sample_fmt", av_get_sample_fmt_name(AV_SAMPLE_FMT_FLT),
AV_OPT_SEARCH_CHILDREN);
av_opt_set_q(abuffer_ctx, "time_base", (AVRational) {1, defaultSampleRate},
AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(abuffer_ctx, "sample_rate", defaultSampleRate, AV_OPT_SEARCH_CHILDREN);
/* Now initialize the filter; we pass NULL options, since we have already
* set all the options above. */
if (avfilter_init_str(abuffer_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the abuffer filter!");
return;
}
// TODO: select FX's dynamically
/* Create aecho filter. */
if (true) {
choisen_beat_fx = avfilter_get_by_name("volume");
if (!choisen_beat_fx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the aecho filter!");
return;
}
choisen_beat_fx_ctx = avfilter_graph_alloc_filter(filterGraph, choisen_beat_fx, "echo");
if (!choisen_beat_fx_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the choisen_beat_fx_ctx instance! %s",
av_err2str(AVERROR(ENOMEM)));
return;
}
av_opt_set (choisen_beat_fx_ctx, "volume", AV_STRINGIFY(0.5), AV_OPT_SEARCH_CHILDREN);
if (avfilter_init_str(choisen_beat_fx_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the choisen_beat_fx_ctx filter!");
return;
}
}
/* Create the aformat filter;
* it ensures that the output is of the format we want. */
aformat = avfilter_get_by_name("aformat");
if (!aformat) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the aformat filter!");
return;
}
aformat_ctx = avfilter_graph_alloc_filter(filterGraph, aformat, "aformat");
if (!aformat_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the aformat instance!");
return;
}
av_opt_set(aformat_ctx, "sample_fmts", av_get_sample_fmt_name(AV_SAMPLE_FMT_FLT),
AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(aformat_ctx, "sample_rates", defaultSampleRate, AV_OPT_SEARCH_CHILDREN);
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, AV_CH_LAYOUT_STEREO);
av_opt_set(aformat_ctx, "channel_layouts", ch_layout, AV_OPT_SEARCH_CHILDREN);
if (avfilter_init_str(aformat_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the aformat filter!");
return;
}
/* Finally create the abuffersink filter;
* it will be used to get the filtered data out of the graph. */
abuffersink = avfilter_get_by_name("abuffersink");
if (!abuffersink) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not find the abuffersink filter!");
return;
}
abuffersink_ctx = avfilter_graph_alloc_filter(filterGraph, abuffersink, "sink");
if (!abuffersink_ctx) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not allocate the abuffersink instance!");
return;
}
/* This filter takes no options. */
if (avfilter_init_str(abuffersink_ctx, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Could not initialize the abuffersink instance.!");
return;
}
/* Connect the filters;
* in this simple case the filters just form a linear chain. */
if (avfilter_link(abuffer_ctx, 0, choisen_beat_fx_ctx, 0) != 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error connecting filters.!");
return;
}
if (avfilter_link(choisen_beat_fx_ctx, 0, aformat_ctx, 0) != 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error connecting filters.!");
return;
}
if (avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0) != 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error connecting filters.!");
return;
}
/* Configure the graph. */
if (avfilter_graph_config(filterGraph, nullptr) < 0) {
*mediaLoadPointer = FAILED_TO_LOAD;
LOGE("FXProcessor::FXProcessor Error configuring the filter graph!");
return;
}
此代码在链为
时工作正常
- (input) -> abuffer -> aecho-> aformat -> abuffersink -> (output)
但是,我想使用 adelay
而不是 volume
过滤器。所以我想要:
The filter chain it uses is: * (input) -> abuffer -> volume -> aformat -> abuffersink -> (output)
我在
更改了代码choisen_beat_fx = avfilter_get_by_name("volume");
至
choisen_beat_fx = avfilter_get_by_name("aecho");
并删除了行
av_opt_set (choisen_beat_fx_ctx, "volume", AV_STRINGIFY(0.5), AV_OPT_SEARCH_CHILDREN);
一切顺利,直到最后一行。
avfilter_graph_config
失败并且 returns 负值。函数文档:
avfilter_graph_config: Check validity and configure all the links and formats in the graph.
所以我猜我需要额外的链接来将 aecho 插入我的链?如何将 aecho 插入我的过滤器链?
好的问题是,我需要使用 aresample
过滤器进行编译才能正常工作。我重新编译了,神奇的是它现在可以工作了。
以下是我发现问题的方法。创建通用日志回调:
void ffmpegErrorCallback(void *ptr, int level, const char *fmt, va_list vargs) {
LOGE("ffmpegErrorCallback Error Occurred! Err: %s", fmt);
}
av_log_set_level(AV_LOG_ERROR);
av_log_set_callback(ffmpegErrorCallback);
FFmpeg 现在会将错误记录为人类可读的消息。它告诉我找不到 aresample
过滤器。我就是这样解决问题的。