Browse code

ffmpeg options: Enable trailing ? for map_channel

The -map option allows for a trailing ? so that an error is not thrown if
the input stream does not exist.
This capability is extended to the map_channel option.
This allows a ffmpeg command not to break if an input channel does not
exist, which can be of use (for instance, scripts processing audio
channels with sources having unset number of audio channels).

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

pkviet authored on 2017/08/22 18:30:45
Showing 5 changed files
... ...
@@ -996,7 +996,7 @@ such streams is attempted.
996 996
 Allow input streams with unknown type to be copied instead of failing if copying
997 997
 such streams is attempted.
998 998
 
999
-@item -map_channel [@var{input_file_id}.@var{stream_specifier}.@var{channel_id}|-1][:@var{output_file_id}.@var{stream_specifier}]
999
+@item -map_channel [@var{input_file_id}.@var{stream_specifier}.@var{channel_id}|-1][?][:@var{output_file_id}.@var{stream_specifier}]
1000 1000
 Map an audio channel from a given input to an output. If
1001 1001
 @var{output_file_id}.@var{stream_specifier} is not set, the audio channel will
1002 1002
 be mapped on all the audio streams.
... ...
@@ -1005,6 +1005,10 @@ Using "-1" instead of
1005 1005
 @var{input_file_id}.@var{stream_specifier}.@var{channel_id} will map a muted
1006 1006
 channel.
1007 1007
 
1008
+A trailing @code{?} will allow the map_channel to be
1009
+optional: if the map_channel matches no channel the map_channel will be ignored instead
1010
+of failing.
1011
+
1008 1012
 For example, assuming @var{INPUT} is a stereo audio file, you can switch the
1009 1013
 two audio channels with the following command:
1010 1014
 @example
... ...
@@ -1052,6 +1056,13 @@ video stream), you can use the following command:
1052 1052
 ffmpeg -i input.mkv -filter_complex "[0:1] [0:2] amerge" -c:a pcm_s16le -c:v copy output.mkv
1053 1053
 @end example
1054 1054
 
1055
+To map the first two audio channels from the first input, and using the
1056
+trailing @code{?}, ignore the audio channel mapping if the first input is
1057
+mono instead of stereo:
1058
+@example
1059
+ffmpeg -i INPUT -map_channel 0.0.0 -map_channel 0.0.1? OUTPUT
1060
+@end example
1061
+
1055 1062
 @item -map_metadata[:@var{metadata_spec_out}] @var{infile}[:@var{metadata_spec_in}] (@emph{output,per-metadata})
1056 1063
 Set metadata information of the next output file from @var{infile}. Note that
1057 1064
 those are file indices (zero-based), not filenames.
... ...
@@ -405,6 +405,11 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg)
405 405
     int n;
406 406
     AVStream *st;
407 407
     AudioChannelMap *m;
408
+    char *allow_unused;
409
+    char *mapchan;
410
+    mapchan = av_strdup(arg);
411
+    if (!mapchan)
412
+        return AVERROR(ENOMEM);
408 413
 
409 414
     GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);
410 415
     m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
... ...
@@ -415,6 +420,7 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg)
415 415
         m->file_idx = m->stream_idx = -1;
416 416
         if (n == 1)
417 417
             m->ofile_idx = m->ostream_idx = -1;
418
+        av_free(mapchan);
418 419
         return 0;
419 420
     }
420 421
 
... ...
@@ -450,11 +456,22 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg)
450 450
                m->file_idx, m->stream_idx);
451 451
         exit_program(1);
452 452
     }
453
+    /* allow trailing ? to map_channel */
454
+    if (allow_unused = strchr(mapchan, '?'))
455
+        *allow_unused = 0;
453 456
     if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->channels) {
454
-        av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
455
-               m->file_idx, m->stream_idx, m->channel_idx);
456
-        exit_program(1);
457
+        if (allow_unused) {
458
+            av_log(NULL, AV_LOG_VERBOSE, "mapchan: invalid audio channel #%d.%d.%d\n",
459
+                    m->file_idx, m->stream_idx, m->channel_idx);
460
+        } else {
461
+            av_log(NULL, AV_LOG_FATAL,  "mapchan: invalid audio channel #%d.%d.%d\n"
462
+                    "To ignore this, add a trailing '?' to the map_channel.\n",
463
+                    m->file_idx, m->stream_idx, m->channel_idx);
464
+            exit_program(1);
465
+        }
466
+
457 467
     }
468
+    av_free(mapchan);
458 469
     return 0;
459 470
 }
460 471
 
... ...
@@ -10,6 +10,14 @@ FATE_MAPCHAN-$(CONFIG_CHANNELMAP_FILTER) += fate-mapchan-silent-mono
10 10
 fate-mapchan-silent-mono: tests/data/asynth-22050-1.wav
11 11
 fate-mapchan-silent-mono: CMD = md5 -i $(TARGET_PATH)/tests/data/asynth-22050-1.wav -map_channel -1 -map_channel 0.0.0 -fflags +bitexact -f wav
12 12
 
13
+FATE_MAPCHAN-$(CONFIG_CHANNELMAP_FILTER) += fate-mapchan-2ch-extract-ch0-ch2-trailing
14
+fate-mapchan-2ch-extract-ch0-ch2-trailing: tests/data/asynth-44100-2.wav
15
+fate-mapchan-2ch-extract-ch0-ch2-trailing: CMD = md5 -i $(TARGET_PATH)/tests/data/asynth-44100-2.wav -map_channel 0.0.0 -map_channel 0.0.2? -fflags +bitexact -f wav
16
+
17
+FATE_MAPCHAN-$(CONFIG_CHANNELMAP_FILTER) += fate-mapchan-3ch-extract-ch0-ch2-trailing
18
+fate-mapchan-3ch-extract-ch0-ch2-trailing: tests/data/asynth-44100-3.wav
19
+fate-mapchan-3ch-extract-ch0-ch2-trailing: CMD = md5 -i $(TARGET_PATH)/tests/data/asynth-44100-3.wav -map_channel 0.0.0 -map_channel 0.0.2? -fflags +bitexact -f wav
20
+
13 21
 FATE_MAPCHAN = $(FATE_MAPCHAN-yes)
14 22
 
15 23
 FATE_FFMPEG += $(FATE_MAPCHAN)
16 24
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+b6e1d142b4e484221562e7b66b9bbbdc
0 1
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+ae533985186cab287309c04f6b3e866c