diff options
author | Anton Khirnov <anton@khirnov.net> | 2012-05-05 18:22:46 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-05-17 03:29:21 +0200 |
commit | fc49f22c3b735db5aaac5f98e40b7124a2be13b8 (patch) | |
tree | 1803664a062717d85542229ed6de829f0ede862a /ffmpeg.c | |
parent | dfa988ee5ea704ba761d004f0c27e7acc1fb4251 (diff) | |
download | ffmpeg-fc49f22c3b735db5aaac5f98e40b7124a2be13b8.tar.gz |
ffmpeg: add support for audio filters.
Some of the FATE changes are due to off-by-one different rounding being used
(lrintf vs av_rescale_q).
Some fate changes are due to 1 audio frame less being encoded (the new variant seems
matching what qatar does and according to ffprobe its closer to the requested duration)
the mapchan feature sadly is lost in this commit because it depends on resampling
being done in ffmpeg.c which is now moved completely into the av filter layer
-async is broken after this commit, this will be fixed in subsequent commits
the new filter reconfiguration system is flawed and will drop a frame on each
parameter change which is why the nelly moser checksums need updating.
Conflicts:
ffmpeg.c
tests/ref/fate/smjpeg
Diffstat (limited to 'ffmpeg.c')
-rw-r--r-- | ffmpeg.c | 925 |
1 files changed, 386 insertions, 539 deletions
@@ -96,6 +96,9 @@ #define VSYNC_VFR 2 #define VSYNC_DROP 0xff +// #define SRCA +#define SINKA + const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; @@ -167,11 +170,6 @@ static int print_stats = 1; static int debug_ts = 0; static int current_time; -static uint8_t *audio_buf; -static unsigned int allocated_audio_buf_size; -static uint8_t *async_buf; -static unsigned int allocated_async_buf_size; - #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" typedef struct InputFilter { @@ -241,6 +239,11 @@ typedef struct InputStream { int resample_width; int resample_pix_fmt; + int resample_sample_fmt; + int resample_sample_rate; + int resample_channels; + uint64_t resample_channel_layout; + /* a pool of free buffers for decoded data */ FrameBuffer *buffer_pool; int dr1; @@ -276,7 +279,6 @@ typedef struct OutputStream { AVBitStreamFilterContext *bitstream_filters; AVCodec *enc; int64_t max_frames; - AVFrame *output_frame; AVFrame *filtered_frame; /* video only */ @@ -292,20 +294,8 @@ typedef struct OutputStream { int forced_kf_count; int forced_kf_index; - /* audio only */ - int audio_resample; - int audio_channels_map[SWR_CH_MAX]; ///< list of the channels id to pick from the source stream - int audio_channels_mapped; ///< number of channels in audio_channels_map - int resample_sample_fmt; - int resample_channels; - uint64_t resample_channel_layout; - int resample_sample_rate; - float rematrix_volume; - AVFifoBuffer *fifo; /* for compression: one audio fifo per codec */ FILE *logfile; - SwrContext *swr; - OutputFilter *filter; char *avfilter; @@ -363,8 +353,6 @@ typedef struct OptionsContext { int nb_audio_channels; SpecifierOpt *audio_sample_rate; int nb_audio_sample_rate; - SpecifierOpt *rematrix_volume; - int nb_rematrix_volume; SpecifierOpt *frame_rates; int nb_frame_rates; SpecifierOpt *frame_sizes; @@ -705,9 +693,9 @@ static enum PixelFormat choose_pixel_fmt(AVStream *st, AVCodec *codec, enum Pixe return target; } -static char *choose_pixel_fmts(OutputStream *ost) +static char *choose_pix_fmts(OutputStream *ost) { - if (ost->keep_pix_fmt) { + if (ost->keep_pix_fmt) { if (ost->filter) avfilter_graph_set_auto_convert(ost->filter->graph->graph, AVFILTER_AUTO_CONVERT_NONE); @@ -737,8 +725,10 @@ static char *choose_pixel_fmts(OutputStream *ost) } } - for (; *p != PIX_FMT_NONE; p++) - avio_printf(s, "%s:", av_get_pix_fmt_name(*p)); + for (; *p != PIX_FMT_NONE; p++) { + const char *name = av_get_pix_fmt_name(*p); + avio_printf(s, "%s:", name); + } len = avio_close_dyn_buf(s, &ret); ret[len - 1] = 0; return ret; @@ -746,11 +736,149 @@ static char *choose_pixel_fmts(OutputStream *ost) return NULL; } -static int configure_video_filters(FilterGraph *fg) +/** + * Define a function for building a string containing a list of + * allowed formats, + */ +#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name, separator) \ +static char *choose_ ## var ## s(OutputStream *ost) \ +{ \ + if (ost->st->codec->var != none) { \ + get_name(ost->st->codec->var); \ + return av_strdup(name); \ + } else if (ost->enc->supported_list) { \ + const type *p; \ + AVIOContext *s = NULL; \ + uint8_t *ret; \ + int len; \ + \ + if (avio_open_dyn_buf(&s) < 0) \ + exit_program(1); \ + \ + for (p = ost->enc->supported_list; *p != none; p++) { \ + get_name(*p); \ + avio_printf(s, "%s" separator, name); \ + } \ + len = avio_close_dyn_buf(s, &ret); \ + ret[len - 1] = 0; \ + return ret; \ + } else \ + return NULL; \ +} + +#define GET_PIX_FMT_NAME(pix_fmt)\ + const char *name = av_get_pix_fmt_name(pix_fmt); + +// DEF_CHOOSE_FORMAT(enum PixelFormat, pix_fmt, pix_fmts, PIX_FMT_NONE, +// GET_PIX_FMT_NAME, ":") + +#define GET_SAMPLE_FMT_NAME(sample_fmt)\ + const char *name = av_get_sample_fmt_name(sample_fmt) + +DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts, + AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME, ",") + +#define GET_SAMPLE_RATE_NAME(rate)\ + char name[16];\ + snprintf(name, sizeof(name), "%d", rate); + +DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0, + GET_SAMPLE_RATE_NAME, ",") + +#define GET_CH_LAYOUT_NAME(ch_layout)\ + char name[16];\ + snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout); + +DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0, + GET_CH_LAYOUT_NAME, ",") + +static int configure_audio_filters(FilterGraph *fg, AVFilterContext **in_filter, + AVFilterContext **out_filter) +{ + InputStream *ist = fg->inputs[0]->ist; + OutputStream *ost = fg->outputs[0]->ost; + AVCodecContext *codec = ost->st->codec; + AVCodecContext *icodec = ist->st->codec; + char *sample_fmts, *sample_rates, *channel_layouts; + char args[256]; + int ret; + + avfilter_graph_free(&fg->graph); + if (!(fg->graph = avfilter_graph_alloc())) + return AVERROR(ENOMEM); + +#ifdef SRCA + snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:" + "channel_layout=0x%"PRIx64, ist->st->time_base.num, +#else + snprintf(args, sizeof(args), "%d/%d:%d:%s:" + "0x%"PRIx64, ist->st->time_base.num, +#endif + ist->st->time_base.den, icodec->sample_rate, + av_get_sample_fmt_name(icodec->sample_fmt), icodec->channel_layout); + ret = avfilter_graph_create_filter(&fg->inputs[0]->filter, + avfilter_get_by_name("abuffer"), + "src", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, + avfilter_get_by_name("abuffersink_old"), + "out", NULL, NULL, fg->graph); + if (ret < 0) + return ret; + + *in_filter = fg->inputs[0]->filter; + *out_filter = fg->outputs[0]->filter; + + if (codec->channels && !codec->channel_layout) + codec->channel_layout = av_get_default_channel_layout(codec->channels); + + sample_fmts = choose_sample_fmts(ost); + sample_rates = choose_sample_rates(ost); + channel_layouts = choose_channel_layouts(ost); + if (sample_fmts || sample_rates || channel_layouts) { + AVFilterContext *format; + char args[256]; + int len = 0; + + if (sample_fmts) + len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:", + sample_fmts); + if (sample_rates) + len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:", + sample_rates); + if (channel_layouts) + len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:", + channel_layouts); + args[len - 1] = 0; + + av_freep(&sample_fmts); + av_freep(&sample_rates); + av_freep(&channel_layouts); + + ret = avfilter_graph_create_filter(&format, + avfilter_get_by_name("aformat"), + "aformat", args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(format, 0, fg->outputs[0]->filter, 0); + if (ret < 0) + return ret; + + *out_filter = format; + } + + return 0; +} + +static int configure_video_filters(FilterGraph *fg, AVFilterContext **in_filter, + AVFilterContext **out_filter) { InputStream *ist = fg->inputs[0]->ist; OutputStream *ost = fg->outputs[0]->ost; - AVFilterContext *in_filter, *out_filter, *filter; + AVFilterContext *filter; AVCodecContext *codec = ost->st->codec; AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); char *pix_fmts; @@ -758,11 +886,6 @@ static int configure_video_filters(FilterGraph *fg) char args[255]; int ret; - avfilter_graph_free(&fg->graph); - fg->graph = avfilter_graph_alloc(); - if (!fg->graph) - return AVERROR(ENOMEM); - if (ist->st->sample_aspect_ratio.num) { sample_aspect_ratio = ist->st->sample_aspect_ratio; } else @@ -791,8 +914,8 @@ static int configure_video_filters(FilterGraph *fg) if (ret < 0) return ret; - in_filter = fg->inputs[0]->filter; - out_filter = fg->outputs[0]->filter; + *in_filter = fg->inputs[0]->filter; + *out_filter = fg->outputs[0]->filter; if (codec->width || codec->height) { snprintf(args, 255, "%d:%d:flags=0x%X", @@ -802,27 +925,53 @@ static int configure_video_filters(FilterGraph *fg) if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), NULL, args, NULL, fg->graph)) < 0) return ret; - if ((ret = avfilter_link(in_filter, 0, filter, 0)) < 0) + if ((ret = avfilter_link(*in_filter, 0, filter, 0)) < 0) return ret; - in_filter = filter; + *in_filter = filter; } - if ((pix_fmts = choose_pixel_fmts(ost))) { + if ((pix_fmts = choose_pix_fmts(ost))) { if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("format"), "format", pix_fmts, NULL, fg->graph)) < 0) return ret; - if ((ret = avfilter_link(filter, 0, out_filter, 0)) < 0) + if ((ret = avfilter_link(filter, 0, *out_filter, 0)) < 0) return ret; - out_filter = filter; + *out_filter = filter; av_freep(&pix_fmts); } snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); fg->graph->scale_sws_opts = av_strdup(args); + return 0; +} + +static int configure_simple_filtergraph(FilterGraph *fg) +{ + OutputStream *ost = fg->outputs[0]->ost; + AVFilterContext *in_filter, *out_filter; + int ret; + + avfilter_graph_free(&fg->graph); + fg->graph = avfilter_graph_alloc(); + if (!fg->graph) + return AVERROR(ENOMEM); + + switch (ost->st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + ret = configure_video_filters(fg, &in_filter, &out_filter); + break; + case AVMEDIA_TYPE_AUDIO: + ret = configure_audio_filters(fg, &in_filter, &out_filter); + break; + default: av_assert0(0); + } + if (ret < 0) + return ret; + if (ost->avfilter) { AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); @@ -1000,7 +1149,7 @@ static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFil pad_idx = 0; } - if ((pix_fmts = choose_pixel_fmts(ofilter->ost))) { + if ((pix_fmts = choose_pix_fmts(ofilter->ost))) { AVFilterContext *filter; if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("format"), @@ -1097,7 +1246,8 @@ static int configure_complex_filters(void) static int configure_filtergraph(FilterGraph *fg) { - return fg->graph_desc ? configure_complex_filter(fg) : configure_video_filters(fg); + return fg->graph_desc ? configure_complex_filter(fg) : + configure_simple_filtergraph(fg); } static int ist_in_filtergraph(FilterGraph *fg, InputStream *ist) @@ -1258,12 +1408,6 @@ void av_noreturn exit_program(int ret) } output_streams[i]->bitstream_filters = NULL; - if (output_streams[i]->output_frame) { - AVFrame *frame = output_streams[i]->output_frame; - if (frame->extended_data != frame->data) - av_freep(&frame->extended_data); - av_freep(&frame); - } av_freep(&output_streams[i]->filtered_frame); av_freep(&output_streams[i]); } @@ -1289,10 +1433,6 @@ void av_noreturn exit_program(int ret) av_freep(&output_files); uninit_opts(); - av_freep(&audio_buf); - allocated_audio_buf_size = 0; - av_freep(&async_buf); - allocated_async_buf_size = 0; avfilter_uninit(); avformat_network_deinit(); @@ -1354,37 +1494,6 @@ static void choose_sample_fmt(AVStream *st, AVCodec *codec) } } -static void choose_sample_rate(AVStream *st, AVCodec *codec) -{ - if (codec && codec->supported_samplerates) { - const int *p = codec->supported_samplerates; - int best = 0; - int best_dist = INT_MAX; - for (; *p; p++) { - int dist = abs(st->codec->sample_rate - *p); - if (dist < best_dist) { - best_dist = dist; - best = *p; - } - } - if (best_dist) { - int i; - const int *sample_rates = codec->supported_samplerates; - av_log(st->codec, AV_LOG_WARNING, - "Requested sampling rate (%dHz) unsupported, using %dHz instead\n" - "Available sampling rates for %s:", - st->codec->sample_rate, best, codec->name); - for (i = 0; sample_rates[i]; i++) { - if (!sample_rates[i + 1]) av_log(st->codec, AV_LOG_WARNING, " and"); - else if (i) av_log(st->codec, AV_LOG_WARNING, ","); - av_log(st->codec, AV_LOG_WARNING, " %d", sample_rates[i]); - } - av_log(st->codec, AV_LOG_WARNING, ".\n"); - } - st->codec->sample_rate = best; - } -} - static double get_sync_ipts(const OutputStream *ost, int64_t pts) { @@ -1447,104 +1556,38 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost) } } -static void get_default_channel_layouts(OutputStream *ost, InputStream *ist) -{ - char layout_name[256]; - AVCodecContext *enc = ost->st->codec; - AVCodecContext *dec = ist->st->codec; - - if (dec->channel_layout && - av_get_channel_layout_nb_channels(dec->channel_layout) != dec->channels) { - av_get_channel_layout_string(layout_name, sizeof(layout_name), - dec->channels, dec->channel_layout); - av_log(NULL, AV_LOG_ERROR, "New channel layout (%s) is invalid\n", - layout_name); - dec->channel_layout = 0; - } - if (!dec->channel_layout) { - if (enc->channel_layout && dec->channels == enc->channels) { - dec->channel_layout = enc->channel_layout; - } else { - dec->channel_layout = av_get_default_channel_layout(dec->channels); - - if (!dec->channel_layout) { - av_log(NULL, AV_LOG_FATAL, "Unable to find default channel " - "layout for Input Stream #%d.%d\n", ist->file_index, - ist->st->index); - exit_program(1); - } - } - av_get_channel_layout_string(layout_name, sizeof(layout_name), - dec->channels, dec->channel_layout); - av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream " - "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name); - } - if (!enc->channel_layout) { - if (dec->channels == enc->channels) { - enc->channel_layout = dec->channel_layout; - return; - } else { - enc->channel_layout = av_get_default_channel_layout(enc->channels); - } - if (!enc->channel_layout) { - av_log(NULL, AV_LOG_FATAL, "Unable to find default channel layout " - "for Output Stream #%d.%d\n", ost->file_index, - ost->st->index); - exit_program(1); - } - av_get_channel_layout_string(layout_name, sizeof(layout_name), - enc->channels, enc->channel_layout); - av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Output Stream " - "#%d.%d : %s\n", ost->file_index, ost->st->index, layout_name); - } -} - -static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_t size) -{ - int fill_char = 0x00; - if (sample_fmt == AV_SAMPLE_FMT_U8) - fill_char = 0x80; - memset(buf, fill_char, size); -} +// static int check_recording_time(OutputStream *ost) +// { +// OutputFile *of = output_files[ost->file_index]; +// +// if (of->recording_time != INT64_MAX && +// av_compare_ts(ost->sync_opts - ost->first_pts, ost->st->codec->time_base, of->recording_time, +// AV_TIME_BASE_Q) >= 0) { +// ost->is_past_recording_time = 1; +// return 0; +// } +// return 1; +// } -static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, - const uint8_t *buf, int buf_size) +static void do_audio_out(AVFormatContext *s, OutputStream *ost, + AVFrame *frame) { AVCodecContext *enc = ost->st->codec; - AVFrame *frame = NULL; AVPacket pkt; - int ret, got_packet; + int got_packet = 0; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; - - if (buf && buf_size) { - if (!ost->output_frame) { - ost->output_frame = avcodec_alloc_frame(); - if (!ost->output_frame) { - av_log(NULL, AV_LOG_FATAL, "out-of-memory in encode_audio_frame()\n"); - exit_program(1); - } - } - frame = ost->output_frame; - if (frame->extended_data != frame->data) - av_freep(&frame->extended_data); - avcodec_get_frame_defaults(frame); - - frame->nb_samples = buf_size / - (enc->channels * av_get_bytes_per_sample(enc->sample_fmt)); - if ((ret = avcodec_fill_audio_frame(frame, enc->channels, enc->sample_fmt, - buf, buf_size, 1)) < 0) { - av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_fill_audio_frame)\n"); - exit_program(1); - } - +#if 0 + if (!check_recording_time(ost)) + return; +#endif + if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0) frame->pts = ost->sync_opts; - ost->sync_opts += frame->nb_samples; - } + ost->sync_opts = frame->pts + frame->nb_samples; - got_packet = 0; + av_assert0(pkt.size || !pkt.data); update_benchmark(NULL); if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) { av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n"); @@ -1552,8 +1595,6 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, } update_benchmark("encode_audio %d.%d", ost->file_index, ost->index); - ret = pkt.size; - if (got_packet) { if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base); @@ -1568,244 +1609,18 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost, if (pkt.duration > 0) pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base); + if (debug_ts) { + av_log(NULL, AV_LOG_INFO, "encoder -> type:audio " + "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", + av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base), + av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base)); + } + write_frame(s, &pkt, ost); audio_size += pkt.size; - av_free_packet(&pkt); } - - if (debug_ts) { - av_log(NULL, AV_LOG_INFO, "encoder -> type:audio " - "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n", - av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base), - av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base)); - } - - return ret; -} - -static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc, - int nb_samples, int *buf_linesize) -{ - int64_t audio_buf_samples; - int audio_buf_size; - - /* calculate required number of samples to allocate */ - audio_buf_samples = ((int64_t)nb_samples * enc->sample_rate + dec->sample_rate) / - dec->sample_rate; - audio_buf_samples = 4 * audio_buf_samples + 10000; // safety factors for resampling - audio_buf_samples = FFMAX(audio_buf_samples, enc->frame_size); - if (audio_buf_samples > INT_MAX) - return AVERROR(EINVAL); - - audio_buf_size = av_samples_get_buffer_size(buf_linesize, enc->channels, - audio_buf_samples, - enc->sample_fmt, 0); - if (audio_buf_size < 0) - return audio_buf_size; - - av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size); - if (!audio_buf) - return AVERROR(ENOMEM); - - return 0; -} - -static void do_audio_out(AVFormatContext *s, OutputStream *ost, - InputStream *ist, AVFrame *decoded_frame) -{ - uint8_t *buftmp; - int64_t size_out; - - int frame_bytes, resample_changed; - AVCodecContext *enc = ost->st->codec; - AVCodecContext *dec = ist->st->codec; - int osize = av_get_bytes_per_sample(enc->sample_fmt); - int isize = av_get_bytes_per_sample(dec->sample_fmt); - uint8_t *buf[AV_NUM_DATA_POINTERS]; - int size = decoded_frame->nb_samples * dec->channels * isize; - int planes = av_sample_fmt_is_planar(dec->sample_fmt) ? dec->channels : 1; - int i; - int out_linesize = 0; - - av_assert0(planes <= AV_NUM_DATA_POINTERS); - - for(i=0; i<planes; i++) - buf[i]= decoded_frame->data[i]; - - - get_default_channel_layouts(ost, ist); - - if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples, &out_linesize) < 0) { - av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); - exit_program(1); - } - - if (audio_sync_method > 1 || - enc->channels != dec->channels || - enc->channel_layout != dec->channel_layout || - enc->sample_rate != dec->sample_rate || - dec->sample_fmt != enc->sample_fmt) - ost->audio_resample = 1; - - resample_changed = ost->resample_sample_fmt != dec->sample_fmt || - ost->resample_channels != dec->channels || - ost->resample_channel_layout != dec->channel_layout || - ost->resample_sample_rate != dec->sample_rate; - - if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) { - - if (resample_changed) { - av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:0x%"PRIx64" to rate:%d fmt:%s ch:%d chl:0x%"PRIx64"\n", - ist->file_index, ist->st->index, - ost->resample_sample_rate, av_get_sample_fmt_name(ost->resample_sample_fmt), - ost->resample_channels, ost->resample_channel_layout, - dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), - dec->channels, dec->channel_layout); - ost->resample_sample_fmt = dec->sample_fmt; - ost->resample_channels = dec->channels; - ost->resample_channel_layout = dec->channel_layout; - ost->resample_sample_rate = dec->sample_rate; - swr_free(&ost->swr); - } - /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */ - if (audio_sync_method <= 1 && !ost->audio_channels_mapped && - ost->resample_sample_fmt == enc->sample_fmt && - ost->resample_channels == enc->channels && - ost->resample_channel_layout == enc->channel_layout && - ost->resample_sample_rate == enc->sample_rate) { - //ost->swr = NULL; - ost->audio_resample = 0; - } else { - ost->swr = swr_alloc_set_opts(ost->swr, - enc->channel_layout, enc->sample_fmt, enc->sample_rate, - dec->channel_layout, dec->sample_fmt, dec->sample_rate, - 0, NULL); - av_opt_set_int(ost->swr, "dither_method", ost->swr_dither_method,0); - av_opt_set_double(ost->swr, "dither_scale", ost->swr_dither_scale,0); - if (ost->audio_channels_mapped) - swr_set_channel_mapping(ost->swr, ost->audio_channels_map); - av_opt_set_double(ost->swr, "rmvol", ost->rematrix_volume, 0); - if (ost->audio_channels_mapped) { - av_opt_set_int(ost->swr, "icl", av_get_default_channel_layout(ost->audio_channels_mapped), 0); - av_opt_set_int(ost->swr, "uch", ost->audio_channels_mapped, 0); - } - if (av_opt_set_int(ost->swr, "ich", dec->channels, 0) < 0) { - av_log(NULL, AV_LOG_FATAL, "Unsupported number of input channels\n"); - exit_program(1); - } - if (av_opt_set_int(ost->swr, "och", enc->channels, 0) < 0) { - av_log(NULL, AV_LOG_FATAL, "Unsupported number of output channels\n"); - exit_program(1); - } - if(audio_sync_method>1) av_opt_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE, 0); - if(ost->swr && swr_init(ost->swr) < 0){ - av_log(NULL, AV_LOG_FATAL, "swr_init() failed\n"); - swr_free(&ost->swr); - } - - if (!ost->swr) { - av_log(NULL, AV_LOG_FATAL, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n", - dec->channels, dec->sample_rate, - enc->channels, enc->sample_rate); - exit_program(1); - } - } - } - - av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt); - - if (audio_sync_method > 0) { - double delta = get_sync_ipts(ost, ist->pts) * enc->sample_rate - ost->sync_opts - - av_fifo_size(ost->fifo) / (enc->channels * osize); - int idelta = delta * dec->sample_rate / enc->sample_rate; - int byte_delta = idelta * isize * dec->channels; - - // FIXME resample delay - if (fabs(delta) > 50) { - if (ist->is_start || fabs(delta) > audio_drift_threshold*enc->sample_rate) { - if (byte_delta < 0) { - byte_delta = FFMAX(byte_delta, -size); - size += byte_delta; - for (i=0; i<planes; i++) - buf[i] -= byte_delta/planes; - av_log(NULL, AV_LOG_VERBOSE, "discarding %d audio samples\n", - -byte_delta / (isize * dec->channels)); - if (!size) - return; - ist->is_start = 0; - } else { - av_fast_malloc(&async_buf, &allocated_async_buf_size, - byte_delta + size); - if (!async_buf) { - av_log(NULL, AV_LOG_FATAL, "Out of memory in do_audio_out\n"); - exit_program(1); - } - - if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta, &out_linesize) < 0) { - av_log(NULL, AV_LOG_FATAL, "Error allocating audio buffer\n"); - exit_program(1); - } - ist->is_start = 0; - - for (i=0; i<planes; i++) { - uint8_t *t = async_buf + i*((byte_delta + size)/planes); - generate_silence(t, dec->sample_fmt, byte_delta/planes); - memcpy(t + byte_delta/planes, buf[i], size/planes); - buf[i] = t; - } - size += byte_delta; - av_log(NULL, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", idelta); - } - } else if (audio_sync_method > 1) { - int comp = av_clip(delta, -audio_sync_method, audio_sync_method); - av_log(NULL, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", - delta, comp, enc->sample_rate); -// fprintf(stderr, "drift:%f len:%d opts:%"PRId64" ipts:%"PRId64" fifo:%d\n", delta, -1, ost->sync_opts, (int64_t)(get_sync_ipts(ost) * enc->sample_rate), av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2)); - swr_set_compensation(ost->swr, comp, enc->sample_rate); - } - } - } else if (audio_sync_method == 0) - ost->sync_opts = lrintf(get_sync_ipts(ost, ist->pts) * enc->sample_rate) - - av_fifo_size(ost->fifo) / (enc->channels * osize); // FIXME wrong - - if (ost->audio_resample || ost->audio_channels_mapped) { - buftmp = audio_buf; - size_out = swr_convert(ost->swr, ( uint8_t*[]){buftmp}, - allocated_audio_buf_size / (enc->channels * osize), - (const uint8_t **)buf, - size / (dec->channels * isize)); - if (size_out < 0) { - av_log(NULL, AV_LOG_FATAL, "swr_convert failed\n"); - exit_program(1); - } - size_out = size_out * enc->channels * osize; - } else { - buftmp = buf[0]; - size_out = size; - } - - av_assert0(ost->audio_resample || dec->sample_fmt==enc->sample_fmt); - - /* now encode as many frames as possible */ - if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) { - /* output resampled raw samples */ - if (av_fifo_realloc2(ost->fifo, av_fifo_size(ost->fifo) + size_out) < 0) { - av_log(NULL, AV_LOG_FATAL, "av_fifo_realloc2() failed\n"); - exit_program(1); - } - av_fifo_generic_write(ost->fifo, buftmp, size_out, NULL); - - frame_bytes = enc->frame_size * osize * enc->channels; - - while (av_fifo_size(ost->fifo) >= frame_bytes) { - av_fifo_generic_read(ost->fifo, audio_buf, frame_bytes, NULL); - encode_audio_frame(s, ost, audio_buf, frame_bytes); - } - } else { - encode_audio_frame(s, ost, buftmp, size_out); - } } static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void **bufp) @@ -2121,6 +1936,7 @@ static int poll_filters(void) for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; OutputFile *of = output_files[ost->file_index]; + int ret = 0; if (!ost->filter || ost->is_past_recording_time) continue; @@ -2133,8 +1949,17 @@ static int poll_filters(void) while (1) { AVRational ist_pts_tb = ost->filter->filter->inputs[0]->time_base; - ret = av_buffersink_get_buffer_ref(ost->filter->filter, &picref, - AV_BUFFERSINK_FLAG_NO_REQUEST); + if (ost->enc->type == AVMEDIA_TYPE_AUDIO && + !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) + ret = av_buffersink_read_samples(ost->filter->filter, &picref, + ost->st->codec->frame_size); + else +#ifdef SINKA + ret = av_buffersink_read(ost->filter->filter, &picref); +#else + ret = av_buffersink_get_buffer_ref(ost->filter->filter, &picref, + AV_BUFFERSINK_FLAG_NO_REQUEST); +#endif if (ret < 0) { if (ret != AVERROR(EAGAIN)) { char buf[256]; @@ -2144,7 +1969,15 @@ static int poll_filters(void) } break; } - filtered_frame->pts = frame_pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q); + if (ost->enc->type == AVMEDIA_TYPE_VIDEO) + filtered_frame->pts = frame_pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q); + else if (picref->pts != AV_NOPTS_VALUE) + filtered_frame->pts = frame_pts = av_rescale_q(picref->pts, + ost->filter->filter->inputs[0]->time_base, + ost->st->codec->time_base) - + av_rescale_q(of->start_time, + AV_TIME_BASE_Q, + ost->st->codec->time_base); //if (ost->source_index >= 0) // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold @@ -2162,8 +1995,13 @@ static int poll_filters(void) same_quant ? ost->last_quality : ost->st->codec->global_quality); break; + case AVMEDIA_TYPE_AUDIO: + avfilter_copy_buf_props(filtered_frame, picref); + filtered_frame->pts = frame_pts; + do_audio_out(of->ctx, ost, filtered_frame); + break; default: - // TODO support audio/subtitle filters + // TODO support subtitle filters av_assert0(0); } @@ -2346,40 +2184,40 @@ static void flush_encoders(void) continue; for (;;) { - AVPacket pkt; - int fifo_bytes, got_packet; - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; + int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL; + const char *desc; + int64_t *size; switch (ost->st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: - fifo_bytes = av_fifo_size(ost->fifo); - if (fifo_bytes > 0) { - /* encode any samples remaining in fifo */ - int frame_bytes = fifo_bytes; - - av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL); - - encode_audio_frame(os, ost, audio_buf, frame_bytes); - } else { - /* flush encoder with NULL frames until it is done - returning packets */ - if (encode_audio_frame(os, ost, NULL, 0) == 0) { - stop_encoding = 1; - break; - } - } + encode = avcodec_encode_audio2; + desc = "Audio"; + size = &audio_size; break; case AVMEDIA_TYPE_VIDEO: + encode = avcodec_encode_video2; + desc = "Video"; + size = &video_size; + break; + default: + stop_encoding = 1; + } + + if (encode) { + AVPacket pkt; + int got_packet; + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; + update_benchmark(NULL); - ret = avcodec_encode_video2(enc, &pkt, NULL, &got_packet); - update_benchmark("encode_video %d.%d", ost->file_index, ost->index); + ret = encode(enc, &pkt, NULL, &got_packet); + update_benchmark("flush %s %d.%d", desc, ost->file_index, ost->index); if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n"); + av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc); exit_program(1); } - video_size += pkt.size; + *size += pkt.size; if (ost->logfile && enc->stats_out) { fprintf(ost->logfile, "%s", enc->stats_out); } @@ -2392,10 +2230,8 @@ static void flush_encoders(void) if (pkt.dts != AV_NOPTS_VALUE) pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base); write_frame(os, &pkt, ost); - break; - default: - stop_encoding = 1; } + if (stop_encoding) break; } @@ -2496,12 +2332,30 @@ static void rate_emu_sleep(InputStream *ist) } } +static int guess_input_channel_layout(InputStream *ist) +{ + AVCodecContext *dec = ist->st->codec; + + if (!dec->channel_layout) { + char layout_name[256]; + + dec->channel_layout = av_get_default_channel_layout(dec->channels); + if (!dec->channel_layout) + return 0; + av_get_channel_layout_string(layout_name, sizeof(layout_name), + dec->channels, dec->channel_layout); + av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream " + "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name); + } + return 1; +} + static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) { AVFrame *decoded_frame; AVCodecContext *avctx = ist->st->codec; int bps = av_get_bytes_per_sample(ist->st->codec->sample_fmt); - int i, ret; + int i, ret, resample_changed; if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame())) return AVERROR(ENOMEM); @@ -2522,6 +2376,13 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) if (!*got_output) { /* no audio frame */ + if (!pkt->size) + for (i = 0; i < ist->nb_filters; i++) +#ifdef SRCA + av_buffersrc_buffer(ist->filters[i]->filter, NULL); +#else + av_buffersrc_add_ref(ist->filters[i]->filter, NULL, 0); +#endif return ret; } @@ -2529,14 +2390,21 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) the decoder could be delaying output by a packet or more. */ if (decoded_frame->pts != AV_NOPTS_VALUE) ist->dts = ist->next_dts = ist->pts = ist->next_pts = decoded_frame->pts; + else if (pkt->pts != AV_NOPTS_VALUE) { + decoded_frame->pts = pkt->pts; + pkt->pts = AV_NOPTS_VALUE; + }else + decoded_frame->pts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base); + +#if 1 /* increment next_dts to use for the case where the input stream does not have timestamps or there are multiple frames in the packet */ ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / avctx->sample_rate; ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / avctx->sample_rate; - +#endif // preprocess audio (volume) if (audio_volume != 256) { @@ -2598,12 +2466,54 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output) rate_emu_sleep(ist); - for (i = 0; i < nb_output_streams; i++) { - OutputStream *ost = output_streams[i]; + resample_changed = ist->resample_sample_fmt != decoded_frame->format || + ist->resample_channels != avctx->channels || + ist->resample_channel_layout != decoded_frame->channel_layout || + ist->resample_sample_rate != decoded_frame->sample_rate; + if (resample_changed) { + char layout1[64], layout2[64]; - if (!check_output_constraints(ist, ost) || !ost->encoding_needed) - continue; - do_audio_out(output_files[ost->file_index]->ctx, ost, ist, decoded_frame); + if (!guess_input_channel_layout(ist)) { + av_log(NULL, AV_LOG_FATAL, "Unable to find default channel " + "layout for Input Stream #%d.%d\n", ist->file_index, + ist->st->index); + exit_program(1); + } + decoded_frame->channel_layout = avctx->channel_layout; + + av_get_channel_layout_string(layout1, sizeof(layout1), ist->resample_channels, + ist->resample_channel_layout); + av_get_channel_layout_string(layout2, sizeof(layout2), avctx->channels, + decoded_frame->channel_layout); + + av_log(NULL, AV_LOG_INFO, + "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s\n", + ist->file_index, ist->st->index, + ist->resample_sample_rate, av_get_sample_fmt_name(ist->resample_sample_fmt), + ist->resample_channels, layout1, + decoded_frame->sample_rate, av_get_sample_fmt_name(decoded_frame->format), + avctx->channels, layout2); + + ist->resample_sample_fmt = decoded_frame->format; + ist->resample_sample_rate = decoded_frame->sample_rate; + ist->resample_channel_layout = decoded_frame->channel_layout; + ist->resample_channels = avctx->channels; + + for (i = 0; i < nb_filtergraphs; i++) + if (ist_in_filtergraph(filtergraphs[i], ist) && + configure_filtergraph(filtergraphs[i]) < 0) { + av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n"); + exit_program(1); + } + } + + for (i = 0; i < ist->nb_filters; i++) { +#ifdef SRCA + av_buffersrc_write_frame(ist->filters[i]->filter, decoded_frame); +#else + AVFilterBufferRef *fb= avfilter_get_audio_buffer_ref_from_frame(decoded_frame, AV_PERM_WRITE); + av_buffersrc_add_ref(ist->filters[i]->filter, fb, 0*AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT); +#endif } return ret; @@ -2938,17 +2848,6 @@ static int init_input_stream(int ist_index, char *error, int error_len) } assert_codec_experimental(ist->st->codec, 0); assert_avoptions(ist->opts); - - if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - for (i = 0; i < nb_output_streams; i++) { - OutputStream *ost = output_streams[i]; - if (ost->source_index == ist_index) { - if (!ist->st->codec->channel_layout || !ost->st->codec->channel_layout) - get_default_channel_layouts(ost, ist); - break; - } - } - } } ist->next_pts = AV_NOPTS_VALUE; @@ -3146,67 +3045,28 @@ static int transcode_init(void) ist->decoding_needed = 1; ost->encoding_needed = 1; - switch (codec->codec_type) { - case AVMEDIA_TYPE_AUDIO: - ost->fifo = av_fifo_alloc(1024); - if (!ost->fifo) { - return AVERROR(ENOMEM); - } - - if (!codec->sample_rate) - codec->sample_rate = icodec->sample_rate; - choose_sample_rate(ost->st, ost->enc); - codec->time_base = (AVRational){ 1, codec->sample_rate }; - - if (codec->sample_fmt == AV_SAMPLE_FMT_NONE) - codec->sample_fmt = icodec->sample_fmt; - choose_sample_fmt(ost->st, ost->enc); - - if (ost->audio_channels_mapped) { - /* the requested output channel is set to the number of - * -map_channel only if no -ac are specified */ - if (!codec->channels) { - codec->channels = ost->audio_channels_mapped; - codec->channel_layout = av_get_default_channel_layout(codec->channels); - if (!codec->channel_layout) { - av_log(NULL, AV_LOG_FATAL, "Unable to find an appropriate channel layout for requested number of channel\n"); - exit_program(1); - } - } - /* fill unused channel mapping with -1 (which means a muted - * channel in case the number of output channels is bigger - * than the number of mapped channel) */ - for (j = ost->audio_channels_mapped; j < FF_ARRAY_ELEMS(ost->audio_channels_map); j++) - ost->audio_channels_map[j] = -1; - } else if (!codec->channels) { - codec->channels = icodec->channels; - codec->channel_layout = icodec->channel_layout; - } - if (av_get_channel_layout_nb_channels(codec->channel_layout) != codec->channels) - codec->channel_layout = 0; - - -// ost->audio_resample = codec->sample_rate != icodec->sample_rate || audio_sync_method > 1; -// ost->audio_resample |= codec->sample_fmt != icodec->sample_fmt -// || codec->channel_layout != icodec->channel_layout; - icodec->request_channels = codec-> channels; - ost->resample_sample_fmt = icodec->sample_fmt; - ost->resample_sample_rate = icodec->sample_rate; - ost->resample_channels = icodec->channels; - ost->resample_channel_layout = icodec->channel_layout; - break; - case AVMEDIA_TYPE_VIDEO: - if (!ost->filter) { + if (!ost->filter && + (codec->codec_type == AVMEDIA_TYPE_VIDEO || + codec->codec_type == AVMEDIA_TYPE_AUDIO)) { FilterGraph *fg; fg = init_simple_filtergraph(ist, ost); - if (configure_video_filters(fg)) { + if (configure_simple_filtergraph(fg)) { av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n"); exit(1); } - } + } + switch (codec->codec_type) { + case AVMEDIA_TYPE_AUDIO: + codec->sample_fmt = ost->filter->filter->inputs[0]->format; + codec->sample_rate = ost->filter->filter->inputs[0]->sample_rate; + codec->channel_layout = ost->filter->filter->inputs[0]->channel_layout; + codec->channels = av_get_channel_layout_nb_channels(codec->channel_layout); + codec->time_base = (AVRational){ 1, codec->sample_rate }; + break; + case AVMEDIA_TYPE_VIDEO: if (ist && !ost->frame_rate.num) - ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational) { 25, 1 }; + ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25, 1}; if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) { int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates); ost->frame_rate = ost->enc->supported_framerates[idx]; @@ -3409,15 +3269,6 @@ static int transcode_init(void) input_streams[ost->source_index]->st->index, ost->file_index, ost->index); - if (ost->audio_channels_mapped) { - av_log(NULL, AV_LOG_INFO, " [ch:"); - for (j = 0; j < ost->audio_channels_mapped; j++) - if (ost->audio_channels_map[j] == -1) - av_log(NULL, AV_LOG_INFO, " M"); - else - av_log(NULL, AV_LOG_INFO, " %d", ost->audio_channels_map[j]); - av_log(NULL, AV_LOG_INFO, "]"); - } if (ost->sync_ist != input_streams[ost->source_index]) av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]", ost->sync_ist->file_index, @@ -3783,11 +3634,8 @@ static int transcode(void) fclose(ost->logfile); ost->logfile = NULL; } - av_fifo_free(ost->fifo); /* works even if fifo is not - initialized but set to zero */ av_freep(&ost->st->codec->subtitle_header); av_free(ost->forced_kf_pts); - swr_free(&ost->swr); av_dict_free(&ost->opts); } } @@ -4220,6 +4068,14 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) break; case AVMEDIA_TYPE_AUDIO: + guess_input_channel_layout(ist); + + ist->resample_sample_fmt = dec->sample_fmt; + ist->resample_sample_rate = dec->sample_rate; + ist->resample_channels = dec->channels; + ist->resample_channel_layout = dec->channel_layout; + + break; case AVMEDIA_TYPE_DATA: case AVMEDIA_TYPE_SUBTITLE: if(!ist->dec) @@ -4793,7 +4649,7 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in audio_enc->codec_type = AVMEDIA_TYPE_AUDIO; if (!ost->stream_copy) { - char *sample_fmt = NULL; + char *sample_fmt = NULL, *filters = NULL;; MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st); @@ -4806,23 +4662,9 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st); - ost->rematrix_volume=1.0; - MATCH_PER_STREAM_OPT(rematrix_volume, f, ost->rematrix_volume, oc, st); - } - - /* check for channel mapping for this audio stream */ - for (n = 0; n < o->nb_audio_channel_maps; n++) { - AudioChannelMap *map = &o->audio_channel_maps[n]; - InputStream *ist = input_streams[ost->source_index]; - if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) && - (map->ofile_idx == -1 || ost->file_index == map->ofile_idx) && - (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) { - if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map)) - ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx; - else - av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n", - ost->file_index, ost->st->index); - } + MATCH_PER_STREAM_OPT(filters, str, filters, oc, st); + if (filters) + ost->avfilter = av_strdup(filters); } return ost; @@ -5697,6 +5539,11 @@ static int opt_video_filters(OptionsContext *o, const char *opt, const char *arg return parse_option(o, "filter:v", arg, options); } +static int opt_audio_filters(OptionsContext *o, const char *opt, const char *arg) +{ + return parse_option(o, "filter:a", arg, options); +} + static int opt_vsync(const char *opt, const char *arg) { if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR; @@ -5879,8 +5726,8 @@ static const OptionDef options[] = { { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_old2new}, "force audio tag/fourcc", "fourcc/tag" }, { "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, // { "sample_fmt", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_SPEC | OPT_STRING, {.off = OFFSET(sample_fmts)}, "set sample format", "format" }, - { "rmvol", HAS_ARG | OPT_AUDIO | OPT_FLOAT | OPT_SPEC, {.off = OFFSET(rematrix_volume)}, "rematrix volume (as factor)", "volume" }, { "channel_layout", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_channel_layout}, "set channel layout", "layout" }, + { "af", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_filters}, "audio filters", "filter list" }, /* subtitle options */ { "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" }, |