Я пытаюсь использовать неадекватный фильтр FFmpeg, и он не работает должным образом. Я не могу передать параметры запуска и длительности в секундах. С этой строкой:
afilter=afade=t=out:st=1:d=0:curve=par
мой фильтр исчезает с самого первого кадра. Поэтому у меня нет звука ни в первом, ни в любом другом кадре. Но если я установлю магическое число 208 в качестве времени начала затухания:
afilter=afade=t=out:st=208:d=0:curve=par
, оно начнет работать через 1 секунду (RMS превращается в бесконечность при затухании):
...
Frame=0.501 Samples=23543 RMS=-35.186275
Frame=0.535 Samples=25014 RMS=-37.393734
Frame=0.568 Samples=26486 RMS=-40.655666
Frame=0.602 Samples=27957 RMS=-38.321899
Frame=0.635 Samples=29429 RMS=-41.370567
Frame=0.669 Samples=30900 RMS=-39.316444
Frame=0.702 Samples=32372 RMS=-27.994545
Frame=0.735 Samples=33843 RMS=-23.577181
Frame=0.769 Samples=35315 RMS=-22.933538
Frame=0.802 Samples=36786 RMS=-25.900106
Frame=0.836 Samples=38258 RMS=-26.836918
Frame=0.869 Samples=39729 RMS=-29.685308
Frame=0.902 Samples=41201 RMS=-32.493404
Frame=0.936 Samples=42672 RMS=-32.552109
Frame=0.969 Samples=44144 RMS=-42.384045
Frame=1.003 Samples=45615 RMS=-inf
Frame=1.036 Samples=47087 RMS=-inf
Frame=1.070 Samples=48558 RMS=-inf
Frame=1.103 Samples=50029 RMS=-inf
Frame=1.136 Samples=51501 RMS=-inf
Frame=1.170 Samples=52972 RMS=-inf
Frame=1.203 Samples=54444 RMS=-inf
Frame=1.237 Samples=55915 RMS=-inf
Frame=1.270 Samples=57387 RMS=-inf
Frame=1.304 Samples=58858 RMS=-inf
Frame=1.337 Samples=60330 RMS=-inf
Frame=1.370 Samples=61801 RMS=-inf
Frame=1.404 Samples=63273 RMS=-inf
Frame=1.437 Samples=64744 RMS=-inf
Frame=1.471 Samples=66216 RMS=-inf
Frame=1.504 Samples=67687 RMS=-inf
Похоже, мне нужно умножить время запуска в секундах на этот странный коэффициент 208 (я нашел это значение экспериментально для частоты дискретизации 44100 Гц). То же самое с параметром длительности. Чтобы установить длительность N секунд, я должен передать N * 208 в качестве параметра. Для других частот выборки этот коэффициент изменяется.
Так что, возможно, что-то не так с моей инициализацией графа фильтра?
Это мой код для инициализации графа фильтра (почти скопированный из некоторого примера):
int _InitFilterGraph(const char *_pszFilterDesc, AVFrame* _pFrame, AVRational* _pTimeBase)
{
const AVFilter *pBufferSrc = avfilter_get_by_name( "abuffer" );
const AVFilter *pBufferSink = avfilter_get_by_name( "abuffersink" );
AVFilterInOut *pOutputs = avfilter_inout_alloc();
AVFilterInOut *pInputs = avfilter_inout_alloc();
AVSampleFormat out_sample_fmts[] = { (AVSampleFormat)_pFrame->format, (AVSampleFormat)-1 };
int64_t out_channel_layouts[] = { (int64_t)_pFrame->channel_layout, -1 };
int out_sample_rates[] = { _pFrame->sample_rate, -1 };
m_pFilterGraph = avfilter_graph_alloc();
// Buffer audio source: the decoded frames from the decoder will be inserted here.
char args[512] = {};
snprintf( args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%llx",
_pTimeBase->num, _pTimeBase->den,
_pFrame->sample_rate, av_get_sample_fmt_name( (AVSampleFormat)_pFrame->format ),
_pFrame->channel_layout );
int nRet = avfilter_graph_create_filter( &m_pBufferSrcCtx, pBufferSrc, "in",
args, NULL, m_pFilterGraph );
if( nRet < 0 ) goto final;
// Buffer audio sink: to terminate the filter chain.
AVABufferSinkParams *pBufferSinkParams = av_abuffersink_params_alloc();
pBufferSinkParams->all_channel_counts = _pFrame->channels;
nRet = avfilter_graph_create_filter( &m_pBufferSinkCtx, pBufferSink, "out",
NULL, pBufferSinkParams, m_pFilterGraph );
av_free( pBufferSinkParams );
if( nRet < 0 ) goto final;
nRet = av_opt_set_int_list( m_pBufferSinkCtx, "sample_fmts", out_sample_fmts, -1,
AV_OPT_SEARCH_CHILDREN );
if( nRet < 0 ) goto final;
nRet = av_opt_set_int_list( m_pBufferSinkCtx, "channel_layouts", out_channel_layouts, -1,
AV_OPT_SEARCH_CHILDREN );
if( nRet < 0 ) goto final;
nRet = av_opt_set_int_list( m_pBufferSinkCtx, "sample_rates", out_sample_rates, -1,
AV_OPT_SEARCH_CHILDREN );
if( nRet < 0 ) goto final;
// Endpoints for the filter graph.
pOutputs->name = av_strdup( "in" );
pOutputs->filter_ctx = m_pBufferSrcCtx;
pOutputs->pad_idx = 0;
pOutputs->next = NULL;
pInputs->name = av_strdup( "out" );
pInputs->filter_ctx = m_pBufferSinkCtx;
pInputs->pad_idx = 0;
pInputs->next = NULL;
nRet = avfilter_graph_parse_ptr( m_pFilterGraph, _pszFilterDesc, &pInputs, &pOutputs, NULL );
if( nRet < 0 ) goto final;
nRet = avfilter_graph_config( m_pFilterGraph, NULL );
final:
avfilter_inout_free( &pInputs );
avfilter_inout_free( &pOutputs );
return nRet;
}