[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