Merge commit '755cd4197d53946208e042f095b930dca18d9430'
[ffmpeg.git] / ffmpeg.c
index b197fa1..a05d3c4 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -35,6 +35,7 @@
 #include "libavformat/avformat.h"
 #include "libavdevice/avdevice.h"
 #include "libswscale/swscale.h"
+#include "libswresample/swresample.h"
 #include "libavutil/opt.h"
 #include "libavutil/audioconvert.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/libm.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/timestamp.h"
+#include "libavutil/bprint.h"
 #include "libavformat/os_support.h"
-#include "libswresample/swresample.h"
 
 #include "libavformat/ffm.h" // not public API
 
 # include "libavfilter/avcodec.h"
 # include "libavfilter/avfilter.h"
 # include "libavfilter/avfiltergraph.h"
-# include "libavfilter/buffersink.h"
 # include "libavfilter/buffersrc.h"
+# include "libavfilter/buffersink.h"
 
 #if HAVE_SYS_RESOURCE_H
 #include <sys/types.h>
@@ -96,7 +97,6 @@
 #define VSYNC_VFR         2
 #define VSYNC_DROP        0xff
 
-// #define SRCA
 #define SINKA
 
 const char program_name[] = "ffmpeg";
@@ -227,8 +227,8 @@ typedef struct InputStream {
     /* dts of the last packet read for this stream */
     int64_t       dts;
 
-    int64_t       next_pts;  ///< synthetic pts for the next decode frame
-    int64_t       pts;       ///< current pts of the decoded frame
+    int64_t       next_pts;  /* synthetic pts for the next decode frame */
+    int64_t       pts;       /* current pts of the decoded frame */
     double ts_scale;
     int is_start;            /* is 1 at the start and after a discontinuity */
     int saw_first_ts;
@@ -249,7 +249,7 @@ typedef struct InputStream {
     int dr1;
 
     /* decoded data from this stream goes into all those filters
-     * currently video only */
+     * currently video and audio only */
     InputFilter **filters;
     int        nb_filters;
 } InputStream;
@@ -294,6 +294,10 @@ typedef struct OutputStream {
     int forced_kf_count;
     int forced_kf_index;
 
+    /* audio only */
+    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 */
+
     FILE *logfile;
 
     OutputFilter *filter;
@@ -308,7 +312,6 @@ typedef struct OutputStream {
     const char *attachment_filename;
     int copy_initial_nonkeyframes;
 
-    enum PixelFormat pix_fmts[2];
     int keep_pix_fmt;
 } OutputStream;
 
@@ -372,8 +375,8 @@ typedef struct OptionsContext {
     /* output options */
     StreamMap *stream_maps;
     int     nb_stream_maps;
-    AudioChannelMap *audio_channel_maps; ///< one info entry per -map_channel
-    int           nb_audio_channel_maps; ///< number of (valid) -map_channel settings
+    AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
+    int           nb_audio_channel_maps; /* number of (valid) -map_channel settings */
     int metadata_global_manual;
     int metadata_streams_manual;
     int metadata_chapters_manual;
@@ -701,8 +704,7 @@ static char *choose_pix_fmts(OutputStream *ost)
                                             AVFILTER_AUTO_CONVERT_NONE);
         if (ost->st->codec->pix_fmt == PIX_FMT_NONE)
             return NULL;
-        ost->pix_fmts[0] = ost->st->codec->pix_fmt;
-        return ost->pix_fmts;
+        return av_strdup(av_get_pix_fmt_name(ost->st->codec->pix_fmt));
     }
     if (ost->st->codec->pix_fmt != PIX_FMT_NONE) {
         return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->pix_fmt)));
@@ -807,13 +809,8 @@ static int configure_audio_filters(FilterGraph *fg, AVFilterContext **in_filter,
     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,
@@ -870,6 +867,70 @@ static int configure_audio_filters(FilterGraph *fg, AVFilterContext **in_filter,
         *out_filter = format;
     }
 
+    if (audio_sync_method > 0) {
+        AVFilterContext *aswr;
+        char args[256] = {0};
+
+        av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold);
+
+        if (audio_sync_method > 1)
+            av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)icodec->sample_rate);
+
+        av_log(NULL, AV_LOG_INFO, "-async %d is forwarded to lavfi similarly to -af aresample=%s\n", audio_sync_method, args);
+
+        ret = avfilter_graph_create_filter(&aswr, avfilter_get_by_name("aresample"),
+                                           "aresample", args, NULL, fg->graph);
+        if (ret < 0)
+            return ret;
+
+        ret = avfilter_link(*in_filter, 0, aswr, 0);
+        if (ret < 0)
+            return ret;
+
+        *in_filter = aswr;
+    }
+
+#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do {                 \
+    AVFilterContext *filt_ctx;                                              \
+                                                                            \
+    av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi "            \
+           "similarly to -af " filter_name "=%s.\n", arg);                  \
+                                                                            \
+    ret = avfilter_graph_create_filter(&filt_ctx,                           \
+                                       avfilter_get_by_name(filter_name),   \
+                                       filter_name, arg, NULL, fg->graph);  \
+    if (ret < 0)                                                            \
+        return ret;                                                         \
+                                                                            \
+    ret = avfilter_link(*in_filter, 0, filt_ctx, 0);                        \
+    if (ret < 0)                                                            \
+        return ret;                                                         \
+                                                                            \
+    *in_filter = filt_ctx;                                                  \
+} while (0)
+
+    if (ost->audio_channels_mapped) {
+        int i;
+        AVBPrint pan_buf;
+
+        av_bprint_init(&pan_buf, 256, 8192);
+        av_bprintf(&pan_buf, "0x%"PRIx64,
+                   av_get_default_channel_layout(ost->audio_channels_mapped));
+        for (i = 0; i < ost->audio_channels_mapped; i++)
+            if (ost->audio_channels_map[i] != -1)
+                av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+
+        AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
+        av_bprint_finalize(&pan_buf, NULL);
+    }
+
+    if (audio_volume != 256) {
+        char args[256];
+
+        snprintf(args, sizeof(args), "%lf", audio_volume / 256.);
+        AUTO_INSERT_FILTER("-vol", "volume", args);
+    }
+
     return 0;
 }
 
@@ -892,8 +953,10 @@ static int configure_video_filters(FilterGraph *fg, AVFilterContext **in_filter,
         sample_aspect_ratio = ist->st->codec->sample_aspect_ratio;
 
     snprintf(args, 255, "%d:%d:%d:%d:%d:%d:%d:flags=%d", ist->st->codec->width,
-             ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
-             sample_aspect_ratio.num, sample_aspect_ratio.den, SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
+             ist->st->codec->height, ist->st->codec->pix_fmt,
+             1, AV_TIME_BASE,
+             sample_aspect_ratio.num, sample_aspect_ratio.den,
+             SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
 
     ret = avfilter_graph_create_filter(&fg->inputs[0]->filter,
                                        avfilter_get_by_name("buffer"),
@@ -1046,8 +1109,9 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
     int i;
 
     // TODO: support other filter types
-    if (type != AVMEDIA_TYPE_VIDEO) {
-        av_log(NULL, AV_LOG_FATAL, "Only video filters supported currently.\n");
+    if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
+        av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
+               "currently.\n");
         exit_program(1);
     }
 
@@ -1108,7 +1172,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
     ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
 }
 
-static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
 {
     char *pix_fmts;
     AVCodecContext *codec = ofilter->ost->st->codec;
@@ -1170,6 +1234,104 @@ static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFil
     return 0;
 }
 
+static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+    OutputStream *ost = ofilter->ost;
+    AVCodecContext *codec  = ost->st->codec;
+    AVFilterContext *last_filter = out->filter_ctx;
+    int pad_idx = out->pad_idx;
+    char *sample_fmts, *sample_rates, *channel_layouts;
+    int ret;
+
+    ret = avfilter_graph_create_filter(&ofilter->filter,
+                                       avfilter_get_by_name("abuffersink"),
+                                       "out", NULL, NULL, fg->graph);
+    if (ret < 0)
+        return ret;
+
+    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(last_filter, pad_idx, format, 0);
+        if (ret < 0)
+            return ret;
+
+        last_filter = format;
+        pad_idx = 0;
+    }
+
+    if (audio_sync_method > 0) {
+        AVFilterContext *async;
+        char args[256];
+        int  len = 0;
+
+        av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the "
+               "asyncts audio filter instead.\n");
+
+        if (audio_sync_method > 1)
+            len += snprintf(args + len, sizeof(args) - len, "compensate=1:"
+                            "max_comp=%d:", audio_sync_method);
+        snprintf(args + len, sizeof(args) - len, "min_delta=%f",
+                 audio_drift_threshold);
+
+        ret = avfilter_graph_create_filter(&async,
+                                           avfilter_get_by_name("asyncts"),
+                                           "async", args, NULL, fg->graph);
+        if (ret < 0)
+            return ret;
+
+        ret = avfilter_link(last_filter, pad_idx, async, 0);
+        if (ret < 0)
+            return ret;
+
+        last_filter = async;
+        pad_idx = 0;
+    }
+
+    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+        return ret;
+
+    return 0;
+}
+
+static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+    switch (out->filter_ctx->output_pads[out->pad_idx].type) {
+    case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
+    case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
+    default: av_assert0(0);
+    }
+}
+
 static int configure_complex_filter(FilterGraph *fg)
 {
     AVFilterInOut *inputs, *outputs, *cur;
@@ -1189,16 +1351,34 @@ static int configure_complex_filter(FilterGraph *fg)
         InputFilter *ifilter = fg->inputs[i];
         InputStream     *ist = ifilter->ist;
         AVRational       sar;
+        AVFilter     *filter;
         char            args[255];
 
-        sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio :
-                                                 ist->st->codec->sample_aspect_ratio;
-        snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
-                 ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
-                 sar.num, sar.den);
+        switch (cur->filter_ctx->input_pads[cur->pad_idx].type) {
+        case AVMEDIA_TYPE_VIDEO:
+            sar = ist->st->sample_aspect_ratio.num ?
+                  ist->st->sample_aspect_ratio :
+                  ist->st->codec->sample_aspect_ratio;
+            snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
+                     ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
+                     sar.num, sar.den);
+            filter = avfilter_get_by_name("buffer");
+            break;
+        case AVMEDIA_TYPE_AUDIO:
+            snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:"
+                     "sample_fmt=%s:channel_layout=0x%"PRIx64,
+                     ist->st->time_base.num, ist->st->time_base.den,
+                     ist->st->codec->sample_rate,
+                     av_get_sample_fmt_name(ist->st->codec->sample_fmt),
+                     ist->st->codec->channel_layout);
+            filter = avfilter_get_by_name("abuffer");
+            break;
+        default:
+            av_assert0(0);
+        }
 
         if ((ret = avfilter_graph_create_filter(&ifilter->filter,
-                                                avfilter_get_by_name("buffer"), cur->name,
+                                                filter, cur->name,
                                                 args, NULL, fg->graph)) < 0)
             return ret;
         if ((ret = avfilter_link(ifilter->filter, 0,
@@ -1443,7 +1623,7 @@ void av_noreturn exit_program(int ret)
         exit (255);
     }
 
-    exit(ret); /* not all OS-es handle main() return value */
+    exit(ret);
 }
 
 static void assert_avoptions(AVDictionary *m)
@@ -1606,9 +1786,8 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
     if (got_packet) {
         if (pkt.pts != AV_NOPTS_VALUE)
             pkt.pts      = av_rescale_q(pkt.pts,      enc->time_base, ost->st->time_base);
-        if (pkt.dts != AV_NOPTS_VALUE) {
+        if (pkt.dts != AV_NOPTS_VALUE)
             pkt.dts      = av_rescale_q(pkt.dts,      enc->time_base, ost->st->time_base);
-        }
         if (pkt.duration > 0)
             pkt.duration = av_rescale_q(pkt.duration, enc->time_base, ost->st->time_base);
 
@@ -1984,8 +2163,10 @@ static int poll_filters(void)
                 //if (ost->source_index >= 0)
                 //    *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
 
-                if (of->start_time && filtered_frame->pts < of->start_time)
-                    return 0;
+                if (of->start_time && filtered_frame->pts < of->start_time) {
+                    avfilter_unref_buffer(picref);
+                    continue;
+                }
 
                 switch (ost->filter->filter->inputs[0]->type) {
                 case AVMEDIA_TYPE_VIDEO:
@@ -2357,7 +2538,6 @@ 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, resample_changed;
 
     if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
@@ -2381,11 +2561,8 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *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
+                av_buffersrc_add_ref(ist->filters[i]->filter, NULL,
+                                     AV_BUFFERSRC_FLAG_NO_COPY);
         return ret;
     }
 
@@ -2409,64 +2586,6 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
                      avctx->sample_rate;
 #endif
 
-    // preprocess audio (volume)
-    if (audio_volume != 256) {
-        int decoded_data_size = decoded_frame->nb_samples * avctx->channels * bps;
-        void *samples = decoded_frame->data[0];
-        switch (avctx->sample_fmt) {
-        case AV_SAMPLE_FMT_U8:
-        {
-            uint8_t *volp = samples;
-            for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
-                int v = (((*volp - 128) * audio_volume + 128) >> 8) + 128;
-                *volp++ = av_clip_uint8(v);
-            }
-            break;
-        }
-        case AV_SAMPLE_FMT_S16:
-        {
-            int16_t *volp = samples;
-            for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
-                int v = ((*volp) * audio_volume + 128) >> 8;
-                *volp++ = av_clip_int16(v);
-            }
-            break;
-        }
-        case AV_SAMPLE_FMT_S32:
-        {
-            int32_t *volp = samples;
-            for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
-                int64_t v = (((int64_t)*volp * audio_volume + 128) >> 8);
-                *volp++ = av_clipl_int32(v);
-            }
-            break;
-        }
-        case AV_SAMPLE_FMT_FLT:
-        {
-            float *volp = samples;
-            float scale = audio_volume / 256.f;
-            for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
-                *volp++ *= scale;
-            }
-            break;
-        }
-        case AV_SAMPLE_FMT_DBL:
-        {
-            double *volp = samples;
-            double scale = audio_volume / 256.;
-            for (i = 0; i < (decoded_data_size / sizeof(*volp)); i++) {
-                *volp++ *= scale;
-            }
-            break;
-        }
-        default:
-            av_log(NULL, AV_LOG_FATAL,
-                   "Audio volume adjustment on sample format %s is not supported.\n",
-                   av_get_sample_fmt_name(ist->st->codec->sample_fmt));
-            exit_program(1);
-        }
-    }
-
     rate_emu_sleep(ist);
 
     resample_changed = ist->resample_sample_fmt     != decoded_frame->format         ||
@@ -2510,14 +2629,8 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
             }
     }
 
-    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
-    }
+    for (i = 0; i < ist->nb_filters; i++)
+        av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, 0);
 
     return ret;
 }
@@ -2552,11 +2665,7 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
         /* no picture yet */
         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
+                av_buffersrc_add_ref(ist->filters[i]->filter, NULL, AV_BUFFERSRC_FLAG_NO_COPY);
         return ret;
     }
 
@@ -2565,7 +2674,6 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
         ist->next_pts = ist->pts = decoded_frame->pts = best_effort_timestamp;
 
     pkt->size = 0;
-
     pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free);
 
     rate_emu_sleep(ist);
@@ -2620,17 +2728,11 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
 
             av_assert0(buf->refcount>0);
             buf->refcount++;
-#ifdef SRCA
-            av_buffersrc_buffer(ist->filters[i]->filter, fb);
-        } else
-        if(av_buffersrc_write_frame(ist->filters[i]->filter, decoded_frame)<0) {
-#else
             av_buffersrc_add_ref(ist->filters[i]->filter, fb,
                                  AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT |
                                  AV_BUFFERSRC_FLAG_NO_COPY);
         } else
         if(av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, 0)<0) {
-#endif
             av_log(NULL, AV_LOG_FATAL, "Failed to inject frame into filter network\n");
             exit_program(1);
         }
@@ -2824,7 +2926,6 @@ static void print_sdp(void)
 
 static int init_input_stream(int ist_index, char *error, int error_len)
 {
-    int i;
     InputStream *ist = input_streams[ist_index];
 
     if (ist->decoding_needed) {
@@ -3123,7 +3224,7 @@ static int transcode_init(void)
                         size_t logbuffer_size;
                         if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
                             av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
-                                logfilename);
+                                   logfilename);
                             exit_program(1);
                         }
                         codec->stats_in = logbuffer;
@@ -4482,8 +4583,6 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
         input_streams[source_index]->st->discard = AVDISCARD_NONE;
     }
 
-    ost->pix_fmts[0] = ost->pix_fmts[1] = PIX_FMT_NONE;
-
     return ost;
 }
 
@@ -4668,6 +4767,21 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in
         MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
         if (filters)
             ost->avfilter = av_strdup(filters);
+
+        /* 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);
+            }
+        }
     }
 
     return ost;
@@ -4817,12 +4931,15 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
 {
     OutputStream *ost;
 
-    if (ofilter->out_tmp->filter_ctx->output_pads[ofilter->out_tmp->pad_idx].type != AVMEDIA_TYPE_VIDEO) {
-        av_log(NULL, AV_LOG_FATAL, "Only video filters are supported currently.\n");
+    switch (ofilter->out_tmp->filter_ctx->output_pads[ofilter->out_tmp->pad_idx].type) {
+    case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
+    case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
+    default:
+        av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
+               "currently.\n");
         exit_program(1);
     }
 
-    ost               = new_video_stream(o, oc, -1);
     ost->source_index = -1;
     ost->filter       = ofilter;
 
@@ -5003,7 +5120,7 @@ loop_end:
                 case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
                 default:
                     av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
-                        map->file_index, map->stream_index);
+                           map->file_index, map->stream_index);
                     exit_program(1);
                 }
             }