History

ffmpeg: add -map_channel option.

Based on an initial work by Baptiste Coudurier.

Clément Bœsch committed 15 years ago

Commit f5cd1361 parent 682e0ea15 files · +228 −22Browse files

Unified · Split

15 files
  1. Changelog +1 −0
  2. doc/ffmpeg.texi +38 −0
  3. ffmpeg.c +120 −3
  4. ffplay.c +1 −1
  5. libswresample/audioconvert.c +8 −3
  6. libswresample/audioconvert.h +4 −1
  7. libswresample/swresample.c +23 −9
  8. libswresample/swresample.h +2 −2
  9. libswresample/swresample_internal.h +2 −0
  10. libswresample/swresample_test.c +5 −3
  11. tests/Makefile +8 −0
  12. tests/fate2.mak +12 −0
  13. tests/ref/fate/mapchan-6ch-extract-2 +2 −0
  14. tests/ref/fate/mapchan-6ch-extract-2-downmix-mono +1 −0
  15. tests/ref/fate/mapchan-silent-mono +1 −0
Changelog+1−0
@@ -72,6 +72,7 @@ easier to use. The changes are: · 71 unmodified lines
72- Prores encoder72- Prores encoder
73- Video Decoder Acceleration (VDA) HWAccel module.73- Video Decoder Acceleration (VDA) HWAccel module.
74- replacement Indeo 3 decoder74- replacement Indeo 3 decoder
75- new ffmpeg option: -map_channel
75 76
76version 0.8:77version 0.8:
77 78
doc/ffmpeg.texi+38−0
@@ -721,6 +721,44 @@ ffmpeg -i INPUT -map 0 -map -0:a:1 OUTPUT · 720 unmodified lines
721 721
722Note that using this option disables the default mappings for this output file.722Note that using this option disables the default mappings for this output file.
723 723
724@item -map_channel [@var{input_file_id}.@var{stream_specifier}.@var{channel_id}|-1][:@var{output_file_id}.@var{stream_specifier}]
725Map an audio channel from a given input to an output. If
726@var{output_file_id}.@var{stream_specifier} are not set, the audio channel will
727be mapped on all the audio streams.
728
729Using "-1" instead of
730@var{input_file_id}.@var{stream_specifier}.@var{channel_id} will map a muted
731channel.
732
733For example, assuming @var{INPUT} is a stereo audio file, you can switch the
734two audio channels with the following command:
735@example
736ffmpeg -i INPUT -map_channel 0.0.1 -map_channel 0.0.0 OUTPUT
737@end example
738
739If you want to mute the first channel and keep the second:
740@example
741ffmpeg -i INPUT -map_channel -1 -map_channel 0.0.1 OUTPUT
742@end example
743
744The order of the "-map_channel" option specifies the order of the channels in
745the output stream. The output channel layout is guessed from the number of
746channels mapped (mono if one "-map_channel", stereo if two, etc.). Using "-ac"
747in combination of "-map_channel" makes the channel gain levels to be updated if
748channel layouts don't match (for instance two "-map_channel" options and "-ac
7496").
750
751You can also extract each channel of an @var{INPUT} to specific outputs; the
752following command extract each channel of the audio stream (file 0, stream 0)
753to the respective @var{OUTPUT_CH0} and @var{OUTPUT_CH1}:
754@example
755ffmpeg -i INPUT -map_channel 0.0.0 OUTPUT_CH0 -map_channel 0.0.1 OUTPUT_CH1
756@end example
757
758Note that "-map_channel" is currently limited to the scope of one input for
759each output; you can't for example use it to pick multiple input audio files
760and mix them into one single output.
761
724@item -map_metadata[:@var{metadata_type}][:@var{index}] @var{infile}[:@var{metadata_type}][:@var{index}] (@emph{output,per-metadata})762@item -map_metadata[:@var{metadata_type}][:@var{index}] @var{infile}[:@var{metadata_type}][:@var{index}] (@emph{output,per-metadata})
725Set metadata information of the next output file from @var{infile}. Note that763Set metadata information of the next output file from @var{infile}. Note that
726those are file indices (zero-based), not filenames.764those are file indices (zero-based), not filenames.
ffmpeg.c+120−3
@@ -99,6 +99,11 @@ typedef struct StreamMap { · 98 unmodified lines
99 int sync_stream_index;99 int sync_stream_index;
100} StreamMap;100} StreamMap;
101 101
102typedef struct {
103 int file_idx, stream_idx, channel_idx; // input
104 int ofile_idx, ostream_idx; // output
105} AudioChannelMap;
106
102/**107/**
103 * select an input file for an output file108 * select an input file for an output file
104 */109 */
@@ -231,6 +236,8 @@ typedef struct OutputStream { · 126 unmodified lines
231 236
232 /* audio only */237 /* audio only */
233 int audio_resample;238 int audio_resample;
239 int audio_channels_map[SWR_CH_MAX]; ///< list of the channels id to pick from the source stream
240 int audio_channels_mapped; ///< number of channels in audio_channels_map
234 int resample_sample_fmt;241 int resample_sample_fmt;
235 int resample_channels;242 int resample_channels;
236 int resample_sample_rate;243 int resample_sample_rate;
@@ -313,6 +320,8 @@ typedef struct OptionsContext { · 76 unmodified lines
313 /* output options */320 /* output options */
314 StreamMap *stream_maps;321 StreamMap *stream_maps;
315 int nb_stream_maps;322 int nb_stream_maps;
323 AudioChannelMap *audio_channel_maps; ///< one info entry per -map_channel
324 int nb_audio_channel_maps; ///< number of (valid) -map_channel settings
316 /* first item specifies output metadata, second is input */325 /* first item specifies output metadata, second is input */
317 MetadataMap (*meta_data_maps)[2];326 MetadataMap (*meta_data_maps)[2];
318 int nb_meta_data_maps;327 int nb_meta_data_maps;
@@ -409,6 +418,7 @@ static void reset_options(OptionsContext *o, int is_input) · 90 unmodified lines
409 }418 }
410 419
411 av_freep(&o->stream_maps);420 av_freep(&o->stream_maps);
421 av_freep(&o->audio_channel_maps);
412 av_freep(&o->meta_data_maps);422 av_freep(&o->meta_data_maps);
413 av_freep(&o->streamid_map);423 av_freep(&o->streamid_map);
414 424
@@ -857,7 +867,7 @@ need_realloc: · 442 unmodified lines
857 ost->resample_channels != dec->channels ||867 ost->resample_channels != dec->channels ||
858 ost->resample_sample_rate != dec->sample_rate;868 ost->resample_sample_rate != dec->sample_rate;
859 869
860 if ((ost->audio_resample && !ost->swr) || resample_changed) {870 if ((ost->audio_resample && !ost->swr) || resample_changed || ost->audio_channels_mapped) {
861 if (resample_changed) {871 if (resample_changed) {
862 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",872 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",
863 ist->file_index, ist->st->index,873 ist->file_index, ist->st->index,
@@ -869,7 +879,7 @@ need_realloc: · 5 unmodified lines
869 swr_free(&ost->swr);879 swr_free(&ost->swr);
870 }880 }
871 /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */881 /* if audio_sync_method is >1 the resampler is needed for audio drift compensation */
872 if (audio_sync_method <= 1 &&882 if (audio_sync_method <= 1 && !ost->audio_channels_mapped &&
873 ost->resample_sample_fmt == enc->sample_fmt &&883 ost->resample_sample_fmt == enc->sample_fmt &&
874 ost->resample_channels == enc->channels &&884 ost->resample_channels == enc->channels &&
875 ost->resample_sample_rate == enc->sample_rate) {885 ost->resample_sample_rate == enc->sample_rate) {
@@ -879,8 +889,13 @@ need_realloc: · 3 unmodified lines
879 ost->swr = swr_alloc2(ost->swr,889 ost->swr = swr_alloc2(ost->swr,
880 enc->channel_layout, enc->sample_fmt, enc->sample_rate,890 enc->channel_layout, enc->sample_fmt, enc->sample_rate,
881 dec->channel_layout, dec->sample_fmt, dec->sample_rate,891 dec->channel_layout, dec->sample_fmt, dec->sample_rate,
892 ost->audio_channels_mapped ? ost->audio_channels_map : NULL,
882 0, NULL);893 0, NULL);
883 av_set_double(ost->swr, "rmvol", ost->rematrix_volume);894 av_set_double(ost->swr, "rmvol", ost->rematrix_volume);
895 if (ost->audio_channels_mapped) {
896 av_set_int(ost->swr, "icl", av_get_default_channel_layout(ost->audio_channels_mapped));
897 av_set_int(ost->swr, "uch", ost->audio_channels_mapped);
898 }
884 av_set_int(ost->swr, "ich", dec->channels);899 av_set_int(ost->swr, "ich", dec->channels);
885 av_set_int(ost->swr, "och", enc->channels);900 av_set_int(ost->swr, "och", enc->channels);
886 if(audio_sync_method>1) av_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE);901 if(audio_sync_method>1) av_set_int(ost->swr, "flags", SWR_FLAG_RESAMPLE);
@@ -2176,7 +2191,23 @@ static int transcode_init(OutputFile *output_files, int nb_output_files, · 1289 unmodified lines
2176 if (codec->sample_fmt == AV_SAMPLE_FMT_NONE)2191 if (codec->sample_fmt == AV_SAMPLE_FMT_NONE)
2177 codec->sample_fmt = icodec->sample_fmt;2192 codec->sample_fmt = icodec->sample_fmt;
2178 choose_sample_fmt(ost->st, ost->enc);2193 choose_sample_fmt(ost->st, ost->enc);
2179 if (!codec->channels) {2194 if (ost->audio_channels_mapped) {
2195 /* the requested output channel is set to the number of
2196 * -map_channel only if no -ac are specified */
2197 if (!codec->channels) {
2198 codec->channels = ost->audio_channels_mapped;
2199 codec->channel_layout = av_get_default_channel_layout(codec->channels);
2200 if (!codec->channel_layout) {
2201 av_log(NULL, AV_LOG_FATAL, "Unable to find an appropriate channel layout for requested number of channel\n");
2202 exit_program(1);
2203 }
2204 }
2205 /* fill unused channel mapping with -1 (which means a muted
2206 * channel in case the number of output channels is bigger
2207 * than the number of mapped channel) */
2208 for (j = ost->audio_channels_mapped; j < FF_ARRAY_ELEMS(ost->audio_channels_map); j++)
2209 ost->audio_channels_map[j] = -1;
2210 } else if (!codec->channels) {
2180 codec->channels = icodec->channels;2211 codec->channels = icodec->channels;
2181 codec->channel_layout = icodec->channel_layout;2212 codec->channel_layout = icodec->channel_layout;
2182 }2213 }
@@ -2388,6 +2419,15 @@ static int transcode_init(OutputFile *output_files, int nb_output_files, · 205 unmodified lines
2388 input_streams[ost->source_index].st->index,2419 input_streams[ost->source_index].st->index,
2389 ost->file_index,2420 ost->file_index,
2390 ost->index);2421 ost->index);
2422 if (ost->audio_channels_mapped) {
2423 av_log(NULL, AV_LOG_INFO, " [ch:");
2424 for (j = 0; j < ost->audio_channels_mapped; j++)
2425 if (ost->audio_channels_map[j] == -1)
2426 av_log(NULL, AV_LOG_INFO, " M");
2427 else
2428 av_log(NULL, AV_LOG_INFO, " %d", ost->audio_channels_map[j]);
2429 av_log(NULL, AV_LOG_INFO, "]");
2430 }
2391 if (ost->sync_ist != &input_streams[ost->source_index])2431 if (ost->sync_ist != &input_streams[ost->source_index])
2392 av_log(NULL, AV_LOG_INFO, " [sync #%d.%d]",2432 av_log(NULL, AV_LOG_INFO, " [sync #%d.%d]",
2393 ost->sync_ist->file_index,2433 ost->sync_ist->file_index,
@@ -2899,6 +2939,66 @@ static int opt_attach(OptionsContext *o, const char *opt, const char *arg) · 505 unmodified lines
2899 return 0;2939 return 0;
2900}2940}
2901 2941
2942static int opt_map_channel(OptionsContext *o, const char *opt, const char *arg)
2943{
2944 int n;
2945 AVStream *st;
2946 AudioChannelMap *m;
2947
2948 o->audio_channel_maps =
2949 grow_array(o->audio_channel_maps, sizeof(*o->audio_channel_maps),
2950 &o->nb_audio_channel_maps, o->nb_audio_channel_maps + 1);
2951 m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
2952
2953 /* muted channel syntax */
2954 n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
2955 if ((n == 1 || n == 3) && m->channel_idx == -1) {
2956 m->file_idx = m->stream_idx = -1;
2957 if (n == 1)
2958 m->ofile_idx = m->ostream_idx = -1;
2959 return 0;
2960 }
2961
2962 /* normal syntax */
2963 n = sscanf(arg, "%d.%d.%d:%d.%d",
2964 &m->file_idx, &m->stream_idx, &m->channel_idx,
2965 &m->ofile_idx, &m->ostream_idx);
2966
2967 if (n != 3 && n != 5) {
2968 av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
2969 "[file.stream.channel|-1][:syncfile:syncstream]\n");
2970 exit_program(1);
2971 }
2972
2973 if (n != 5) // only file.stream.channel specified
2974 m->ofile_idx = m->ostream_idx = -1;
2975
2976 /* check input */
2977 if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
2978 av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
2979 m->file_idx);
2980 exit_program(1);
2981 }
2982 if (m->stream_idx < 0 ||
2983 m->stream_idx >= input_files[m->file_idx].nb_streams) {
2984 av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
2985 m->file_idx, m->stream_idx);
2986 exit_program(1);
2987 }
2988 st = input_files[m->file_idx].ctx->streams[m->stream_idx];
2989 if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
2990 av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
2991 m->file_idx, m->stream_idx);
2992 exit_program(1);
2993 }
2994 if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
2995 av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
2996 m->file_idx, m->stream_idx, m->channel_idx);
2997 exit_program(1);
2998 }
2999 return 0;
3000}
3001
2902static void parse_meta_type(char *arg, char *type, int *index)3002static void parse_meta_type(char *arg, char *type, int *index)
2903{3003{
2904 if (*arg) {3004 if (*arg) {
@@ -3588,6 +3688,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) · 683 unmodified lines
3588 3688
3589static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)3689static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
3590{3690{
3691 int n;
3591 AVStream *st;3692 AVStream *st;
3592 OutputStream *ost;3693 OutputStream *ost;
3593 AVCodecContext *audio_enc;3694 AVCodecContext *audio_enc;
@@ -3616,6 +3717,21 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc) · 22 unmodified lines
3616 MATCH_PER_STREAM_OPT(rematrix_volume, f, ost->rematrix_volume, oc, st);3717 MATCH_PER_STREAM_OPT(rematrix_volume, f, ost->rematrix_volume, oc, st);
3617 }3718 }
3618 3719
3720 /* check for channel mapping for this audio stream */
3721 for (n = 0; n < o->nb_audio_channel_maps; n++) {
3722 AudioChannelMap *map = &o->audio_channel_maps[n];
3723 InputStream *ist = &input_streams[ost->source_index];
3724 if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) &&
3725 (map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
3726 (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
3727 if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map))
3728 ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
3729 else
3730 av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n",
3731 ost->file_index, ost->st->index);
3732 }
3733 }
3734
3619 return ost;3735 return ost;
3620}3736}
3621 3737
@@ -4430,6 +4546,7 @@ static const OptionDef options[] = { · 808 unmodified lines
4430 { "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },4546 { "codec", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(codec_names)}, "codec name", "codec" },
4431 { "pre", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(presets)}, "preset name", "preset" },4547 { "pre", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(presets)}, "preset name", "preset" },
4432 { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },4548 { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },
4549 { "map_channel", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_channel}, "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
4433 { "map_meta_data", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",4550 { "map_meta_data", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
4434 "outfile[,metadata]:infile[,metadata]" },4551 "outfile[,metadata]:infile[,metadata]" },
4435 { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile",4552 { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile",
ffplay.c+1−1
@@ -2077,7 +2077,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) · 2076 unmodified lines
2077 swr_free(&is->swr_ctx);2077 swr_free(&is->swr_ctx);
2078 is->swr_ctx = swr_alloc2(NULL, is->audio_tgt_channel_layout, is->audio_tgt_fmt, is->audio_tgt_freq,2078 is->swr_ctx = swr_alloc2(NULL, is->audio_tgt_channel_layout, is->audio_tgt_fmt, is->audio_tgt_freq,
2079 dec_channel_layout, dec->sample_fmt, dec->sample_rate,2079 dec_channel_layout, dec->sample_fmt, dec->sample_rate,
2080 0, NULL);2080 NULL, 0, NULL);
2081 if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {2081 if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
2082 fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",2082 fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2083 dec->sample_rate,2083 dec->sample_rate,
libswresample/audioconvert.c+8−3
@@ -35,11 +35,13 @@ · 34 unmodified lines
35struct AVAudioConvert {35struct AVAudioConvert {
36 int channels;36 int channels;
37 int fmt_pair;37 int fmt_pair;
38 const int *ch_map;
38};39};
39 40
40AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt,41AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt,
41 enum AVSampleFormat in_fmt,42 enum AVSampleFormat in_fmt,
42 int channels, int flags)43 int channels, const int *ch_map,
44 int flags)
43{45{
44 AVAudioConvert *ctx;46 AVAudioConvert *ctx;
45 ctx = av_malloc(sizeof(AVAudioConvert));47 ctx = av_malloc(sizeof(AVAudioConvert));
@@ -47,6 +49,7 @@ AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt, · 1 unmodified line
47 return NULL;49 return NULL;
48 ctx->channels = channels;50 ctx->channels = channels;
49 ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt;51 ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt;
52 ctx->ch_map = ch_map;
50 return ctx;53 return ctx;
51}54}
52 55
@@ -58,15 +61,17 @@ void swr_audio_convert_free(AVAudioConvert **ctx) · 5 unmodified lines
58int swr_audio_convert(AVAudioConvert *ctx, AudioData *out, AudioData*in, int len)61int swr_audio_convert(AVAudioConvert *ctx, AudioData *out, AudioData*in, int len)
59{62{
60 int ch;63 int ch;
64 const uint8_t null_input[8] = {0};
61 65
62 av_assert0(ctx->channels == out->ch_count);66 av_assert0(ctx->channels == out->ch_count);
63 67
64 //FIXME optimize common cases68 //FIXME optimize common cases
65 69
66 for(ch=0; ch<ctx->channels; ch++){70 for(ch=0; ch<ctx->channels; ch++){
67 const int is= (in ->planar ? 1 : in->ch_count) * in->bps;71 const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch;
72 const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps;
68 const int os= (out->planar ? 1 :out->ch_count) *out->bps;73 const int os= (out->planar ? 1 :out->ch_count) *out->bps;
69 const uint8_t *pi= in ->ch[ch];74 const uint8_t *pi= ich < 0 ? null_input : in->ch[ich];
70 uint8_t *po= out->ch[ch];75 uint8_t *po= out->ch[ch];
71 uint8_t *end= po + os*len;76 uint8_t *end= po + os*len;
72 if(!po)77 if(!po)
libswresample/audioconvert.h+4−1
@@ -42,11 +42,14 @@ typedef struct AVAudioConvert AVAudioConvert; · 41 unmodified lines
42 * @param in_fmt Input sample format42 * @param in_fmt Input sample format
43 * @param channels Number of channels43 * @param channels Number of channels
44 * @param flags See AV_CPU_FLAG_xx44 * @param flags See AV_CPU_FLAG_xx
45 * @param ch_map list of the channels id to pick from the source stream, NULL
46 * if all channels must be selected
45 * @return NULL on error47 * @return NULL on error
46 */48 */
47AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt,49AVAudioConvert *swr_audio_convert_alloc(enum AVSampleFormat out_fmt,
48 enum AVSampleFormat in_fmt,50 enum AVSampleFormat in_fmt,
49 int channels, int flags);51 int channels, const int *ch_map,
52 int flags);
50 53
51/**54/**
52 * Free audio sample format converter context.55 * Free audio sample format converter context.
libswresample/swresample.c+23−9
@@ -38,6 +38,7 @@ · 37 unmodified lines
38static const AVOption options[]={38static const AVOption options[]={
39{"ich", "input channel count", OFFSET( in.ch_count ), AV_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},39{"ich", "input channel count", OFFSET( in.ch_count ), AV_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},
40{"och", "output channel count", OFFSET(out.ch_count ), AV_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},40{"och", "output channel count", OFFSET(out.ch_count ), AV_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},
41{"uch", "used channel count", OFFSET(used_ch_count ), AV_OPT_TYPE_INT, {.dbl=2}, 1, SWR_CH_MAX, 0},
41{"isr", "input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0},42{"isr", "input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0},
42{"osr", "output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0},43{"osr", "output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT, {.dbl=48000}, 1, INT_MAX, 0},
43//{"ip" , "input planar" , OFFSET( in.planar ), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1, 0},44//{"ip" , "input planar" , OFFSET( in.planar ), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1, 0},
@@ -76,7 +77,7 @@ SwrContext *swr_alloc(void){ · 32 unmodified lines
76 77
77SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,78SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
78 int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,79 int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
79 int log_offset, void *log_ctx){80 const int *channel_map, int log_offset, void *log_ctx){
80 if(!s) s= swr_alloc();81 if(!s) s= swr_alloc();
81 if(!s) return NULL;82 if(!s) return NULL;
82 83
@@ -90,9 +91,11 @@ SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampl · 7 unmodified lines
90 av_set_int(s, "isf", in_sample_fmt);91 av_set_int(s, "isf", in_sample_fmt);
91 av_set_int(s, "isr", in_sample_rate);92 av_set_int(s, "isr", in_sample_rate);
92 93
94 s->channel_map = channel_map;
93 s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);95 s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);
94 s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);96 s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);
95 s->int_sample_fmt = AV_SAMPLE_FMT_S16;97 s->int_sample_fmt = AV_SAMPLE_FMT_S16;
98 s->used_ch_count= s-> in.ch_count;
96 99
97 return s;100 return s;
98}101}
@@ -167,13 +170,16 @@ int swr_init(SwrContext *s){ · 68 unmodified lines
167 return -1;170 return -1;
168 }171 }
169 172
170 if(s-> in.ch_count && s-> in_ch_layout && s->in.ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){173 if(!s->used_ch_count)
171 av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than there actually is, ignoring layout\n");174 s->used_ch_count= s->in.ch_count;
175
176 if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){
177 av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n");
172 s-> in_ch_layout= 0;178 s-> in_ch_layout= 0;
173 }179 }
174 180
175 if(!s-> in_ch_layout)181 if(!s-> in_ch_layout)
176 s-> in_ch_layout= av_get_default_channel_layout(s->in.ch_count);182 s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count);
177 if(!s->out_ch_layout)183 if(!s->out_ch_layout)
178 s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count);184 s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count);
179 185
@@ -182,10 +188,13 @@ int swr_init(SwrContext *s){ · 2 unmodified lines
182#define RSC 1 //FIXME finetune188#define RSC 1 //FIXME finetune
183 if(!s-> in.ch_count)189 if(!s-> in.ch_count)
184 s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);190 s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);
191 if(!s->used_ch_count)
192 s->used_ch_count= s->in.ch_count;
185 if(!s->out.ch_count)193 if(!s->out.ch_count)
186 s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);194 s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);
187 195
188av_assert0(s-> in.ch_count);196av_assert0(s-> in.ch_count);
197av_assert0(s->used_ch_count);
189av_assert0(s->out.ch_count);198av_assert0(s->out.ch_count);
190 s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0;199 s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0;
191 200
@@ -193,22 +202,27 @@ av_assert0(s->out.ch_count); · 1 unmodified line
193 s->int_bps= av_get_bits_per_sample_fmt(s->int_sample_fmt)/8;202 s->int_bps= av_get_bits_per_sample_fmt(s->int_sample_fmt)/8;
194 s->out.bps= av_get_bits_per_sample_fmt(s->out_sample_fmt)/8;203 s->out.bps= av_get_bits_per_sample_fmt(s->out_sample_fmt)/8;
195 204
196 if(!s->resample && !s->rematrix){205 if(!s->resample && !s->rematrix && !s->channel_map){
197 s->full_convert = swr_audio_convert_alloc(s->out_sample_fmt,206 s->full_convert = swr_audio_convert_alloc(s->out_sample_fmt,
198 s-> in_sample_fmt, s-> in.ch_count, 0);207 s-> in_sample_fmt, s-> in.ch_count, NULL, 0);
199 return 0;208 return 0;
200 }209 }
201 210
202 s->in_convert = swr_audio_convert_alloc(s->int_sample_fmt,211 s->in_convert = swr_audio_convert_alloc(s->int_sample_fmt,
203 s-> in_sample_fmt, s-> in.ch_count, 0);212 s-> in_sample_fmt, s->used_ch_count, s->channel_map, 0);
204 s->out_convert= swr_audio_convert_alloc(s->out_sample_fmt,213 s->out_convert= swr_audio_convert_alloc(s->out_sample_fmt,
205 s->int_sample_fmt, s->out.ch_count, 0);214 s->int_sample_fmt, s->out.ch_count, NULL, 0);
206 215
207 216
208 s->postin= s->in;217 s->postin= s->in;
209 s->preout= s->out;218 s->preout= s->out;
210 s->midbuf= s->in;219 s->midbuf= s->in;
211 s->in_buffer= s->in;220 s->in_buffer= s->in;
221 if(s->channel_map){
222 s->postin.ch_count=
223 s->midbuf.ch_count=
224 s->in_buffer.ch_count= s->used_ch_count;
225 }
212 if(!s->resample_first){226 if(!s->resample_first){
213 s->midbuf.ch_count= s->out.ch_count;227 s->midbuf.ch_count= s->out.ch_count;
214 s->in_buffer.ch_count = s->out.ch_count;228 s->in_buffer.ch_count = s->out.ch_count;
@@ -325,7 +339,7 @@ int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_coun · 110 unmodified lines
325 if((ret=realloc_audio(&s->postin, in_count))<0)339 if((ret=realloc_audio(&s->postin, in_count))<0)
326 return ret;340 return ret;
327 if(s->resample_first){341 if(s->resample_first){
328 av_assert0(s->midbuf.ch_count == s-> in.ch_count);342 av_assert0(s->midbuf.ch_count == s->used_ch_count);
329 if((ret=realloc_audio(&s->midbuf, out_count))<0)343 if((ret=realloc_audio(&s->midbuf, out_count))<0)
330 return ret;344 return ret;
331 }else{345 }else{
libswresample/swresample.h+2−2
@@ -25,7 +25,7 @@ · 24 unmodified lines
25#include "libavutil/samplefmt.h"25#include "libavutil/samplefmt.h"
26 26
27#define LIBSWRESAMPLE_VERSION_MAJOR 027#define LIBSWRESAMPLE_VERSION_MAJOR 0
28#define LIBSWRESAMPLE_VERSION_MINOR 128#define LIBSWRESAMPLE_VERSION_MINOR 2
29#define LIBSWRESAMPLE_VERSION_MICRO 029#define LIBSWRESAMPLE_VERSION_MICRO 0
30 30
31#define SWR_CH_MAX 1631#define SWR_CH_MAX 16
@@ -57,7 +57,7 @@ int swr_init(struct SwrContext *s); · 25 unmodified lines
57 */57 */
58struct SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,58struct SwrContext *swr_alloc2(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
59 int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,59 int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
60 int log_offset, void *log_ctx);60 const int *channel_map, int log_offset, void *log_ctx);
61 61
62/**62/**
63 * Free the given SwrContext.63 * Free the given SwrContext.
libswresample/swresample_internal.h+2−0
@@ -45,6 +45,8 @@ typedef struct SwrContext { //FIXME find unused fields · 44 unmodified lines
45 int out_sample_rate;45 int out_sample_rate;
46 int flags;46 int flags;
47 float slev, clev, rematrix_volume;47 float slev, clev, rematrix_volume;
48 const int *channel_map; ///< channel index (or -1 if muted channel) map
49 int used_ch_count; ///< number of used channels (mapped channel count if channel_map, otherwise in.ch_count)
48 50
49 //below are private51 //below are private
50 int int_bps;52 int int_bps;
libswresample/swresample_test.c+5−3
@@ -131,9 +131,11 @@ int main(int argc, char **argv){ · 130 unmodified lines
131 in_sample_rate, out_sample_rate,131 in_sample_rate, out_sample_rate,
132 av_get_sample_fmt_name(in_sample_fmt), av_get_sample_fmt_name(out_sample_fmt));132 av_get_sample_fmt_name(in_sample_fmt), av_get_sample_fmt_name(out_sample_fmt));
133 forw_ctx = swr_alloc2(forw_ctx, out_ch_layout, out_sample_fmt+planar_out, out_sample_rate,133 forw_ctx = swr_alloc2(forw_ctx, out_ch_layout, out_sample_fmt+planar_out, out_sample_rate,
134 in_ch_layout, in_sample_fmt+planar_in , in_sample_rate, 0, 0);134 in_ch_layout, in_sample_fmt+planar_in , in_sample_rate,
135 backw_ctx = swr_alloc2(backw_ctx,in_ch_layout, in_sample_fmt, in_sample_rate,135 NULL, 0, 0);
136 out_ch_layout, out_sample_fmt+planar_out, out_sample_rate, 0, 0);136 backw_ctx = swr_alloc2(backw_ctx,in_ch_layout, in_sample_fmt, in_sample_rate,
137 out_ch_layout, out_sample_fmt+planar_out, out_sample_rate,
138 NULL, 0, 0);
137 if(swr_init( forw_ctx) < 0)139 if(swr_init( forw_ctx) < 0)
138 fprintf(stderr, "swr_init(->) failed\n");140 fprintf(stderr, "swr_init(->) failed\n");
139 if(swr_init(backw_ctx) < 0)141 if(swr_init(backw_ctx) < 0)
tests/Makefile+8−0
@@ -30,6 +30,14 @@ tests/data/asynth-16000-1.sw: tests/audiogen$(HOSTEXESUF) · 29 unmodified lines
30 @mkdir -p tests/data30 @mkdir -p tests/data
31 $(M)./$< $@ 16000 131 $(M)./$< $@ 16000 1
32 32
33tests/data/mapchan-6ch.sw: tests/audiogen$(HOSTEXESUF)
34 @mkdir -p tests/data
35 $(M)./$< $@ 22050 6
36
37tests/data/mapchan-mono.sw: tests/audiogen$(HOSTEXESUF)
38 @mkdir -p tests/data
39 $(M)./$< $@ 22050 1
40
33tests/data/asynth%.sw tests/vsynth%/00.pgm: TAG = GEN41tests/data/asynth%.sw tests/vsynth%/00.pgm: TAG = GEN
34 42
35include $(SRC_PATH)/tests/fate.mak43include $(SRC_PATH)/tests/fate.mak
tests/fate2.mak+12−0
@@ -137,6 +137,18 @@ FATE_TESTS += fate-g722enc · 136 unmodified lines
137fate-g722enc: tests/data/asynth-16000-1.sw137fate-g722enc: tests/data/asynth-16000-1.sw
138fate-g722enc: CMD = md5 -ar 16000 -ac 1 -f s16le -i $(TARGET_PATH)/tests/data/asynth-16000-1.sw -acodec g722 -ac 1 -f g722138fate-g722enc: CMD = md5 -ar 16000 -ac 1 -f s16le -i $(TARGET_PATH)/tests/data/asynth-16000-1.sw -acodec g722 -ac 1 -f g722
139 139
140FATE_TESTS += fate-mapchan-6ch-extract-2
141fate-mapchan-6ch-extract-2: tests/data/mapchan-6ch.sw
142fate-mapchan-6ch-extract-2: CMD = avconv -ar 22050 -ac 6 -i $(TARGET_PATH)/tests/data/mapchan-6ch.sw -map_channel 0.0.0 -f wav md5: -map_channel 0.0.1 -f wav md5:
143
144FATE_TESTS += fate-mapchan-6ch-extract-2-downmix-mono
145fate-mapchan-6ch-extract-2-downmix-mono: tests/data/mapchan-6ch.sw
146fate-mapchan-6ch-extract-2-downmix-mono: CMD = md5 -ar 22050 -ac 6 -i $(TARGET_PATH)/tests/data/mapchan-6ch.sw -map_channel 0.0.1 -map_channel 0.0.0 -ac 1 -f wav
147
148FATE_TESTS += fate-mapchan-silent-mono
149fate-mapchan-silent-mono: tests/data/mapchan-mono.sw
150fate-mapchan-silent-mono: CMD = md5 -ar 22050 -ac 1 -i $(TARGET_PATH)/tests/data/mapchan-mono.sw -map_channel -1 -map_channel 0.0.0 -f wav
151
140FATE_TESTS += fate-msmpeg4v1152FATE_TESTS += fate-msmpeg4v1
141fate-msmpeg4v1: CMD = framecrc -flags +bitexact -dct fastint -idct simple -i $(SAMPLES)/msmpeg4v1/mpg4.avi -an153fate-msmpeg4v1: CMD = framecrc -flags +bitexact -dct fastint -idct simple -i $(SAMPLES)/msmpeg4v1/mpg4.avi -an
142 154
tests/ref/fate/mapchan-6ch-extract-2+2−0
@@ -0,0 +1,2 @@
16f091fe8c0be88c75921731dc9f74314
25c2d162b9024329eb367295d37b8ca0a
tests/ref/fate/mapchan-6ch-extract-2-downmix-mono+1−0
@@ -0,0 +1 @@
1959645ed73e6d08d8f1e947eac5d0b92
tests/ref/fate/mapchan-silent-mono+1−0
@@ -0,0 +1 @@
14f5148f08587a4b9794aa52aec7852ac

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t