[PATCH 6/6] ffmpeg: add support for selecting a single audio channel

Anssi Hannula anssi.hannula
Fri Jul 16 22:22:46 CEST 2010


---
 doc/ffmpeg-doc.texi |    3 ++
 ffmpeg.c            |   79 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi
index 7e3abad..1d93898 100644
--- a/doc/ffmpeg-doc.texi
+++ b/doc/ffmpeg-doc.texi
@@ -511,6 +511,9 @@ Set the audio bitrate in bit/s (default = 64k).
 Set the audio quality (codec-specific, VBR).
 @item -ac @var{channels}
 Set the number of audio channels (default = 1).
+ at item -achannel @var{channel}
+Select a single input audio channel, counting from 0. Negative values select
+all channels (default behavior).
 @item -an
 Disable audio recording.
 @item -acodec @var{codec}
diff --git a/ffmpeg.c b/ffmpeg.c
index de15898..e534017 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -164,6 +164,7 @@ static int64_t channel_layout = 0;
 static float audio_qscale = QSCALE_NONE;
 static int audio_disable = 0;
 static int audio_channels = 1;
+static int audio_single_channel = -1;
 static char  *audio_codec_name = NULL;
 static unsigned int audio_codec_tag = 0;
 static char *audio_language = NULL;
@@ -232,8 +233,9 @@ static unsigned int sws_flags = SWS_BICUBIC;
 static int64_t timer_start;
 
 static uint8_t *audio_buf;
+static uint8_t *audio_buf2;
 static uint8_t *audio_out;
-unsigned int allocated_audio_out_size, allocated_audio_buf_size;
+unsigned int allocated_audio_out_size, allocated_audio_buf_size, allocated_audio_buf2_size;
 
 static short *samples;
 
@@ -627,7 +629,7 @@ static int av_exit(int ret)
     av_free(sws_opts);
     av_free(audio_buf);
     av_free(audio_out);
-    allocated_audio_buf_size= allocated_audio_out_size= 0;
+    allocated_audio_buf_size= allocated_audio_out_size= allocated_audio_buf2_size= 0;
     av_free(samples);
 
 #if CONFIG_AVFILTER
@@ -796,7 +798,7 @@ static void do_audio_out(AVFormatContext *s,
                          AVInputStream *ist,
                          unsigned char *buf, int size)
 {
-    uint8_t *buftmp;
+    uint8_t *buftmp = buf;
     int64_t audio_out_size, audio_buf_size;
     int64_t allocated_for_size= size;
 
@@ -806,9 +808,10 @@ static void do_audio_out(AVFormatContext *s,
     int osize= av_get_bits_per_sample_format(enc->sample_fmt)/8;
     int isize= av_get_bits_per_sample_format(dec->sample_fmt)/8;
     const int coded_bps = av_get_bits_per_sample(enc->codec->id);
+    int in_channels = audio_single_channel >= 0 ? 1 : dec->channels;
 
 need_realloc:
-    audio_buf_size= (allocated_for_size + isize*dec->channels - 1) / (isize*dec->channels);
+    audio_buf_size= (allocated_for_size + isize*in_channels - 1) / (isize*in_channels);
     audio_buf_size= (audio_buf_size*enc->sample_rate + dec->sample_rate) / dec->sample_rate;
     audio_buf_size= audio_buf_size*2 + 10000; //safety factors for the deprecated resampling API
     audio_buf_size= FFMAX(audio_buf_size, enc->frame_size);
@@ -826,24 +829,26 @@ need_realloc:
 
     av_fast_malloc(&audio_buf, &allocated_audio_buf_size, audio_buf_size);
     av_fast_malloc(&audio_out, &allocated_audio_out_size, audio_out_size);
-    if (!audio_buf || !audio_out){
+    if (audio_single_channel >= 0) 
+        av_fast_malloc(&audio_buf2, &allocated_audio_buf2_size, audio_buf_size);
+    if (!audio_buf || !audio_out || (audio_single_channel >= 0 && !audio_buf2)){
         fprintf(stderr, "Out of memory in do_audio_out\n");
         av_exit(1);
     }
 
-    if (enc->channels != dec->channels)
+    if (enc->channels != in_channels)
         ost->audio_resample = 1;
 
     if (ost->audio_resample && !ost->resample) {
         if (dec->sample_fmt != SAMPLE_FMT_S16)
             fprintf(stderr, "Warning, using s16 intermediate sample format for resampling\n");
-        ost->resample = av_audio_resample_init(enc->channels,    dec->channels,
+        ost->resample = av_audio_resample_init(enc->channels,    in_channels,
                                                enc->sample_rate, dec->sample_rate,
                                                enc->sample_fmt,  dec->sample_fmt,
                                                16, 10, 0, 0.8);
         if (!ost->resample) {
             fprintf(stderr, "Can not resample %d channels @ %d Hz to %d channels @ %d Hz\n",
-                    dec->channels, dec->sample_rate,
+                    in_channels, dec->sample_rate,
                     enc->channels, enc->sample_rate);
             av_exit(1);
         }
@@ -913,14 +918,27 @@ need_realloc:
         ost->sync_opts= lrintf(get_sync_ipts(ost) * enc->sample_rate)
                         - av_fifo_size(ost->fifo)/(ost->st->codec->channels * 2); //FIXME wrong
 
+    if (audio_single_channel >= 0) {
+        uint8_t *dest = audio_buf2;
+        if (audio_single_channel >= dec->channels) {
+            fprintf(stderr, "Invalid single channel selection\n");
+            av_exit(1);
+        }
+        for (uint8_t *p = (uint8_t*)buf + audio_single_channel * isize; p - buf < size; p += dec->channels * isize) {
+            memcpy(dest, p, isize);
+            dest += isize;
+        }
+        size /= dec->channels;
+        buftmp = audio_buf2;
+    }
+
     if (ost->audio_resample) {
-        buftmp = audio_buf;
         size_out = audio_resample(ost->resample,
-                                  (short *)buftmp, (short *)buf,
-                                  size / (ist->st->codec->channels * isize));
+                                  (short *)audio_buf, (short *)buftmp,
+                                  size / (in_channels * isize));
         size_out = size_out * enc->channels * osize;
+        buftmp = audio_buf;
     } else {
-        buftmp = buf;
         size_out = size;
     }
 
@@ -2138,6 +2156,32 @@ static int av_transcode(AVFormatContext **output_files,
         icodec = ist->st->codec;
 
         while ((t = av_metadata_get(ist->st->metadata, "", t, AV_METADATA_IGNORE_SUFFIX))) {
+
+            if (audio_single_channel >= 0 && audio_single_channel <= 9) {
+                char *meta_key;
+
+                if (!strncmp(t->key, "channel", 7) && strlen(t->key) > 9 && t->key[8] == '/') {
+                    if (t->key[7] != '0' + audio_single_channel)
+                        continue; /* metadata belongs to a dropped channel */
+                    meta_key = av_strdup(t->key + 9);
+                    if (!meta_key)
+                        continue;
+                    av_metadata_set2(&ost->st->metadata, meta_key, t->value,
+                                     AV_METADATA_DONT_OVERWRITE);
+                    av_freep(&meta_key);
+                    continue;
+                }
+
+                meta_key = av_malloc(strlen(t->key) + 9 + 1);
+                strcpy(meta_key, "channel0/");
+                meta_key[7] = '0' + audio_single_channel;
+                strcpy(meta_key + 9, t->key);
+                if (av_metadata_get(ist->st->metadata, meta_key, NULL, AV_METADATA_IGNORE_SUFFIX)) {
+                    av_freep(&meta_key);
+                    continue; /* ignore key, there is a channel specific one */
+                }
+                av_freep(&meta_key);
+            }
             av_metadata_set2(&ost->st->metadata, t->key, t->value, AV_METADATA_DONT_OVERWRITE);
         }
 
@@ -2932,6 +2976,12 @@ static int opt_audio_channels(const char *opt, const char *arg)
     return 0;
 }
 
+static int opt_audio_single_channel(const char *opt, const char *arg)
+{
+    audio_single_channel = parse_number_or_die(opt, arg, OPT_INT64, -1, INT_MAX);
+    return 0;
+}
+
 static void opt_video_channel(const char *arg)
 {
     video_channel = strtol(arg, NULL, 0);
@@ -3536,11 +3586,11 @@ static void new_audio_stream(AVFormatContext *oc)
             audio_enc->flags |= CODEC_FLAG_QSCALE;
             audio_enc->global_quality = st->quality = FF_QP2LAMBDA * audio_qscale;
         }
-        audio_enc->channels = audio_channels;
+        audio_enc->channels = audio_single_channel >= 0 ? 1 : audio_channels;
         audio_enc->sample_fmt = audio_sample_fmt;
         audio_enc->sample_rate = audio_sample_rate;
         audio_enc->channel_layout = channel_layout;
-        if (avcodec_channel_layout_num_channels(channel_layout) != audio_channels)
+        if (avcodec_channel_layout_num_channels(channel_layout) != audio_enc->channels)
             audio_enc->channel_layout = 0;
         choose_sample_fmt(st, codec);
         choose_sample_rate(st, codec);
@@ -4268,6 +4318,7 @@ static const OptionDef options[] = {
     { "aq", OPT_FLOAT | HAS_ARG | OPT_AUDIO, {(void*)&audio_qscale}, "set audio quality (codec-specific)", "quality", },
     { "ar", HAS_ARG | OPT_FUNC2 | OPT_AUDIO, {(void*)opt_audio_rate}, "set audio sampling rate (in Hz)", "rate" },
     { "ac", HAS_ARG | OPT_FUNC2 | OPT_AUDIO, {(void*)opt_audio_channels}, "set number of audio channels", "channels" },
+    { "achannel", HAS_ARG | OPT_FUNC2 | OPT_AUDIO, {(void*)opt_audio_single_channel}, "select single channel", "channel" },
     { "an", OPT_BOOL | OPT_AUDIO, {(void*)&audio_disable}, "disable audio" },
     { "acodec", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" },
     { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_audio_tag}, "force audio tag/fourcc", "fourcc/tag" },
-- 
1.7.1


--Boundary-00=_ZzOQMxVxT486NZ+--



More information about the ffmpeg-devel mailing list