]> git.sesse.net Git - ffmpeg/blobdiff - avconv.c
avcodec: refactor avcodec_encode_audio2() to merge common branches
[ffmpeg] / avconv.c
index 851d8dd7d8f73cc09a3af251d1ccd704a0982bef..73f3bc37631d80e810e58d16b6c80b42c9c3a446 100644 (file)
--- a/avconv.c
+++ b/avconv.c
@@ -31,8 +31,8 @@
 #include "libavformat/avformat.h"
 #include "libavdevice/avdevice.h"
 #include "libswscale/swscale.h"
+#include "libavresample/avresample.h"
 #include "libavutil/opt.h"
-#include "libavcodec/audioconvert.h"
 #include "libavutil/audioconvert.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/samplefmt.h"
@@ -266,12 +266,11 @@ typedef struct OutputStream {
 
     /* audio only */
     int audio_resample;
-    ReSampleContext *resample; /* for audio resampling */
+    AVAudioResampleContext *avr;
     int resample_sample_fmt;
     int resample_channels;
+    uint64_t resample_channel_layout;
     int resample_sample_rate;
-    int reformat_pair;
-    AVAudioConvert *reformat_ctx;
     AVFifoBuffer *fifo;     /* for compression: one audio fifo per codec */
     FILE *logfile;
 
@@ -599,7 +598,6 @@ static int configure_video_filters(FilterGraph *fg)
     InputStream  *ist = fg->inputs[0]->ist;
     OutputStream *ost = fg->outputs[0]->ost;
     AVFilterContext *last_filter, *filter;
-    /** filter graph containing all filters including input & output */
     AVCodecContext *codec = ost->st->codec;
     SinkContext sink_ctx = { .pix_fmts = choose_pixel_fmts(ost) };
     AVRational sample_aspect_ratio;
@@ -725,7 +723,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
         char *p;
         int file_idx = strtol(in->name, &p, 0);
 
-        if (file_idx < 0 || file_idx > nb_input_files) {
+        if (file_idx < 0 || file_idx >= nb_input_files) {
             av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtegraph description %s.\n",
                    file_idx, fg->graph_desc);
             exit_program(1);
@@ -1314,7 +1312,7 @@ static int encode_audio_frame(AVFormatContext *s, OutputStream *ost,
 }
 
 static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc,
-                                  int nb_samples)
+                                  int nb_samples, int *buf_linesize)
 {
     int64_t audio_buf_samples;
     int audio_buf_size;
@@ -1327,7 +1325,7 @@ static int alloc_audio_output_buf(AVCodecContext *dec, AVCodecContext *enc,
     if (audio_buf_samples > INT_MAX)
         return AVERROR(EINVAL);
 
-    audio_buf_size = av_samples_get_buffer_size(NULL, enc->channels,
+    audio_buf_size = av_samples_get_buffer_size(buf_linesize, enc->channels,
                                                 audio_buf_samples,
                                                 enc->sample_fmt, 0);
     if (audio_buf_size < 0)
@@ -1345,77 +1343,88 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
 {
     uint8_t *buftmp;
 
-    int size_out, frame_bytes, resample_changed;
+    int size_out, frame_bytes, resample_changed, ret;
     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 = decoded_frame->data[0];
     int size     = decoded_frame->nb_samples * dec->channels * isize;
+    int out_linesize = 0;
+    int buf_linesize = decoded_frame->linesize[0];
 
     get_default_channel_layouts(ost, ist);
 
-    if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples) < 0) {
+    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 (enc->channels != dec->channels || enc->sample_rate != dec->sample_rate)
+    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->resample) || resample_changed) {
+    if ((ost->audio_resample && !ost->avr) || resample_changed) {
         if (resample_changed) {
-            av_log(NULL, AV_LOG_INFO, "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d to rate:%d fmt:%s ch:%d\n",
+            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,
-                   dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels);
+                   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;
-            if (ost->resample)
-                audio_resample_close(ost->resample);
+            if (ost->avr)
+                avresample_close(ost->avr);
         }
         /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
         if (audio_sync_method <= 1 &&
             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->resample = NULL;
             ost->audio_resample = 0;
         } else if (ost->audio_resample) {
-            if (dec->sample_fmt != AV_SAMPLE_FMT_S16)
-                av_log(NULL, AV_LOG_WARNING, "Using s16 intermediate sample format for resampling\n");
-            ost->resample = av_audio_resample_init(enc->channels,    dec->channels,
-                                                   enc->sample_rate, dec->sample_rate,
-                                                   enc->sample_fmt,  dec->sample_fmt,
-                                                   16, 10, 0, 0.8);
-            if (!ost->resample) {
-                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);
+            if (!ost->avr) {
+                ost->avr = avresample_alloc_context();
+                if (!ost->avr) {
+                    av_log(NULL, AV_LOG_FATAL, "Error allocating context for libavresample\n");
+                    exit_program(1);
+                }
             }
-        }
-    }
 
-#define MAKE_SFMT_PAIR(a,b) ((a)+AV_SAMPLE_FMT_NB*(b))
-    if (!ost->audio_resample && dec->sample_fmt != enc->sample_fmt &&
-        MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt) != ost->reformat_pair) {
-        if (ost->reformat_ctx)
-            av_audio_convert_free(ost->reformat_ctx);
-        ost->reformat_ctx = av_audio_convert_alloc(enc->sample_fmt, 1,
-                                                   dec->sample_fmt, 1, NULL, 0);
-        if (!ost->reformat_ctx) {
-            av_log(NULL, AV_LOG_FATAL, "Cannot convert %s sample format to %s sample format\n",
-                   av_get_sample_fmt_name(dec->sample_fmt),
-                   av_get_sample_fmt_name(enc->sample_fmt));
-            exit_program(1);
+            av_opt_set_int(ost->avr, "in_channel_layout",  dec->channel_layout, 0);
+            av_opt_set_int(ost->avr, "in_sample_fmt",      dec->sample_fmt,     0);
+            av_opt_set_int(ost->avr, "in_sample_rate",     dec->sample_rate,    0);
+            av_opt_set_int(ost->avr, "out_channel_layout", enc->channel_layout, 0);
+            av_opt_set_int(ost->avr, "out_sample_fmt",     enc->sample_fmt,     0);
+            av_opt_set_int(ost->avr, "out_sample_rate",    enc->sample_rate,    0);
+            if (audio_sync_method > 1)
+                av_opt_set_int(ost->avr, "force_resampling", 1, 0);
+
+            /* if both the input and output formats are s16 or u8, use s16 as
+               the internal sample format */
+            if (av_get_bytes_per_sample(dec->sample_fmt) <= 2 &&
+                av_get_bytes_per_sample(enc->sample_fmt) <= 2) {
+                av_opt_set_int(ost->avr, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
+            }
+
+            ret = avresample_open(ost->avr);
+            if (ret < 0) {
+                av_log(NULL, AV_LOG_FATAL, "Error opening libavresample\n");
+                exit_program(1);
+            }
         }
-        ost->reformat_pair = MAKE_SFMT_PAIR(enc->sample_fmt,dec->sample_fmt);
     }
 
     if (audio_sync_method > 0) {
@@ -1444,7 +1453,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
                         exit_program(1);
                     }
 
-                    if (alloc_audio_output_buf(dec, enc, decoded_frame->nb_samples + idelta) < 0) {
+                    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);
                     }
@@ -1454,15 +1463,15 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
                     memcpy(async_buf + byte_delta, buf, size);
                     buf = async_buf;
                     size += byte_delta;
+                    buf_linesize = allocated_async_buf_size;
                     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_assert0(ost->audio_resample);
                 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));
-                av_resample_compensate(*(struct AVResampleContext**)ost->resample, comp, enc->sample_rate);
+                avresample_set_compensation(ost->avr, comp, enc->sample_rate);
             }
         }
     } else if (audio_sync_method == 0)
@@ -1471,31 +1480,16 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
 
     if (ost->audio_resample) {
         buftmp = audio_buf;
-        size_out = audio_resample(ost->resample,
-                                  (short *)buftmp, (short *)buf,
-                                  size / (dec->channels * isize));
+        size_out = avresample_convert(ost->avr, (void **)&buftmp,
+                                      allocated_audio_buf_size, out_linesize,
+                                      (void **)&buf, buf_linesize,
+                                      size / (dec->channels * isize));
         size_out = size_out * enc->channels * osize;
     } else {
         buftmp = buf;
         size_out = size;
     }
 
-    if (!ost->audio_resample && dec->sample_fmt != enc->sample_fmt) {
-        const void *ibuf[6] = { buftmp };
-        void *obuf[6]  = { audio_buf };
-        int istride[6] = { isize };
-        int ostride[6] = { osize };
-        int len = size_out / istride[0];
-        if (av_audio_convert(ost->reformat_ctx, obuf, ostride, ibuf, istride, len) < 0) {
-            printf("av_audio_convert() failed\n");
-            if (exit_on_error)
-                exit_program(1);
-            return;
-        }
-        buftmp = audio_buf;
-        size_out = len * osize;
-    }
-
     /* now encode as many frames as possible */
     if (!(enc->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
         /* output resampled raw samples */
@@ -2612,7 +2606,11 @@ static int transcode_init(void)
         }
 
         if (ost->stream_copy) {
-            uint64_t extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
+            uint64_t extra_size;
+
+            av_assert0(ist && !ost->filter);
+
+            extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
 
             if (extra_size > INT_MAX) {
                 return AVERROR(EINVAL);
@@ -2705,7 +2703,6 @@ static int transcode_init(void)
                 if (!ost->fifo) {
                     return AVERROR(ENOMEM);
                 }
-                ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE);
 
                 if (!codec->sample_rate)
                     codec->sample_rate = icodec->sample_rate;
@@ -2718,15 +2715,16 @@ static int transcode_init(void)
 
                 if (!codec->channels)
                     codec->channels = icodec->channels;
-                codec->channel_layout = icodec->channel_layout;
+                if (!codec->channel_layout)
+                    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;
                 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) {
@@ -3198,10 +3196,8 @@ static int transcode(void)
                                              initialized but set to zero */
                 av_freep(&ost->st->codec->subtitle_header);
                 av_free(ost->forced_kf_pts);
-                if (ost->resample)
-                    audio_resample_close(ost->resample);
-                if (ost->reformat_ctx)
-                    av_audio_convert_free(ost->reformat_ctx);
+                if (ost->avr)
+                    avresample_free(&ost->avr);
                 av_dict_free(&ost->opts);
             }
         }
@@ -4194,6 +4190,13 @@ static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
 
     ofilter->ost      = ost;
 
+    if (ost->stream_copy) {
+        av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
+               "which is fed from a complex filtergraph. Filtering and streamcopy "
+               "cannot be used together.\n", ost->file_index, ost->index);
+        exit_program(1);
+    }
+
     if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
         av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
         exit_program(1);
@@ -4832,61 +4835,10 @@ static int opt_deinterlace(const char *opt, const char *arg)
 
 static int opt_cpuflags(const char *opt, const char *arg)
 {
-#define CPUFLAG_MMX2     (AV_CPU_FLAG_MMX      | AV_CPU_FLAG_MMX2)
-#define CPUFLAG_3DNOW    (AV_CPU_FLAG_3DNOW    | AV_CPU_FLAG_MMX)
-#define CPUFLAG_3DNOWEXT (AV_CPU_FLAG_3DNOWEXT | CPUFLAG_3DNOW)
-#define CPUFLAG_SSE      (AV_CPU_FLAG_SSE      | CPUFLAG_MMX2)
-#define CPUFLAG_SSE2     (AV_CPU_FLAG_SSE2     | CPUFLAG_SSE)
-#define CPUFLAG_SSE2SLOW (AV_CPU_FLAG_SSE2SLOW | CPUFLAG_SSE2)
-#define CPUFLAG_SSE3     (AV_CPU_FLAG_SSE3     | CPUFLAG_SSE2)
-#define CPUFLAG_SSE3SLOW (AV_CPU_FLAG_SSE3SLOW | CPUFLAG_SSE3)
-#define CPUFLAG_SSSE3    (AV_CPU_FLAG_SSSE3    | CPUFLAG_SSE3)
-#define CPUFLAG_SSE4     (AV_CPU_FLAG_SSE4     | CPUFLAG_SSSE3)
-#define CPUFLAG_SSE42    (AV_CPU_FLAG_SSE42    | CPUFLAG_SSE4)
-#define CPUFLAG_AVX      (AV_CPU_FLAG_AVX      | CPUFLAG_SSE42)
-#define CPUFLAG_XOP      (AV_CPU_FLAG_XOP      | CPUFLAG_AVX)
-#define CPUFLAG_FMA4     (AV_CPU_FLAG_FMA4     | CPUFLAG_AVX)
-    static const AVOption cpuflags_opts[] = {
-        { "flags"   , NULL, 0, AV_OPT_TYPE_FLAGS, { 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
-        { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ALTIVEC  },    .unit = "flags" },
-        { "mmx"     , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_MMX      },    .unit = "flags" },
-        { "mmx2"    , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_MMX2         },    .unit = "flags" },
-        { "sse"     , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE          },    .unit = "flags" },
-        { "sse2"    , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE2         },    .unit = "flags" },
-        { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE2SLOW     },    .unit = "flags" },
-        { "sse3"    , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE3         },    .unit = "flags" },
-        { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE3SLOW     },    .unit = "flags" },
-        { "ssse3"   , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSSE3        },    .unit = "flags" },
-        { "atom"    , NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ATOM     },    .unit = "flags" },
-        { "sse4.1"  , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE4         },    .unit = "flags" },
-        { "sse4.2"  , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_SSE42        },    .unit = "flags" },
-        { "avx"     , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_AVX          },    .unit = "flags" },
-        { "xop"     , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_XOP          },    .unit = "flags" },
-        { "fma4"    , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_FMA4         },    .unit = "flags" },
-        { "3dnow"   , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOW        },    .unit = "flags" },
-        { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOWEXT     },    .unit = "flags" },
-
-        { "armv5te",  NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV5TE  },    .unit = "flags" },
-        { "armv6",    NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV6    },    .unit = "flags" },
-        { "armv6t2",  NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV6T2  },    .unit = "flags" },
-        { "vfp",      NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_VFP      },    .unit = "flags" },
-        { "vfpv3",    NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_VFPV3    },    .unit = "flags" },
-        { "neon",     NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_NEON     },    .unit = "flags" },
-
-        { NULL },
-    };
-    static const AVClass class = {
-        .class_name = "cpuflags",
-        .item_name  = av_default_item_name,
-        .option     = cpuflags_opts,
-        .version    = LIBAVUTIL_VERSION_INT,
-    };
-
-    int flags = 0, ret;
-    const AVClass *pclass = &class;
-
-    if ((ret = av_opt_eval_flags(&pclass, &cpuflags_opts[0], arg, &flags)) < 0)
-        return ret;
+    int flags = av_parse_cpu_flags(arg);
+
+    if (flags < 0)
+        return flags;
 
     av_set_cpu_flags_mask(flags);
     return 0;