Repository: just-work/fffw

Issue:
Multiple options specified for stream
```
Multiple -c, -codec, -acodec, -vcodec, -scodec or -dcodec options specified for stream 0, only the last option '-c:v libx264' will be used.
```

since ffmpeg-4.4 (or even earlier) to set different options for different streams in same file, output stream index suffix should be used (like '-c:v:0 libx264')

Discussion:

Patch:
diff --git a/fffw/encoding/outputs.py b/fffw/encoding/outputs.py
index 968db2f..92e0ba0 100644
--- a/fffw/encoding/outputs.py
+++ b/fffw/encoding/outputs.py
@@ -1,11 +1,12 @@
+from collections import defaultdict
 from dataclasses import dataclass
-from itertools import chain
-from typing import List, cast, Optional, Iterable, Any
+from typing import List, cast, Optional, Iterable, Any, Tuple, Dict
 
-from fffw.graph.meta import AUDIO, VIDEO, StreamType
+from fffw.encoding import mixins
 from fffw.graph import base
+from fffw.graph.meta import AUDIO, VIDEO, StreamType
 from fffw.wrapper import BaseWrapper, ensure_binary, param
-from fffw.encoding import mixins
+
 __all__ = [
     'Codec',
     'Output',
@@ -57,9 +58,22 @@ class Codec(mixins.StreamValidationMixin, base.Dest, BaseWrapper):
         return bool(self.edge)
 
     def get_args(self) -> List[bytes]:
+        """
+        Insert map argument before all rest codec params.
+        """
         args = ['-map', self.map]
         return ensure_binary(args) + super().get_args()
 
+    def as_pairs(self) -> List[Tuple[Optional[str], Optional[str]]]:
+        """
+        Add stream index suffix to all named params
+        """
+        pairs = super().as_pairs()
+        result = []
+        for p, v in pairs:
+            result.append((p and f'{p}:{self.index}', v))
+        return result
+
     def clone(self, count: int = 1) -> List["Codec"]:
         """
         Creates multiple copies of self to reuse it as output node for multiple
@@ -202,8 +216,6 @@ class OutputList(list):
         :param outputs: list of output files
         """
         super().__init__()
-        self.__video_index = 0
-        self.__audio_index = 0
         self.extend(outputs)
 
     @property
@@ -219,8 +231,7 @@ class OutputList(list):
 
         :param output: output file
         """
-        for codec in output.codecs:
-            self.__set_index(codec)
+        self.__set_index(output)
         super().append(output)
 
     def extend(self, outputs: Iterable[Output]) -> None:
@@ -229,20 +240,25 @@ class OutputList(list):
 
         :param outputs: list of output files
         """
-        for codec in chain(*map(lambda output: output.codecs, outputs)):
-            self.__set_index(codec)
+        for output in outputs:
+            self.__set_index(output)
         super().extend(outputs)
 
     def get_args(self) -> List[bytes]:
+        """
+        Combine all output params together
+        """
         result: List[bytes] = []
-        for source in self:
-            result.extend(source.get_args())
+        for output in self:
+            result.extend(output.get_args())
         return result
 
-    def __set_index(self, codec: Codec) -> None:
-        if codec.kind == VIDEO:
-            codec.index = self.__video_index
-            self.__video_index += 1
-        else:
-            codec.index = self.__audio_index
-            self.__audio_index += 1
+    @staticmethod
+    def __set_index(output: Output) -> None:
+        """
+        Enumerate codecs in output with a stream index in this output
+        """
+        indices: Dict[StreamType, int] = defaultdict(lambda: 0)
+        for codec in output.codecs:
+            codec.index = indices[codec.kind]
+            indices[codec.kind] += 1


Test patch:
diff --git a/tests/test_ffmpeg.py b/tests/test_ffmpeg.py
index 9408ae8..36ce86b 100644
--- a/tests/test_ffmpeg.py
+++ b/tests/test_ffmpeg.py
@@ -109,12 +109,12 @@ class FFMPEGTestCase(BaseTestCase):
             '-filter_complex',
             '[0:v:0]scale=w=640:h=360[vout0];[0:a:0]asplit[aout0][aout1]',
 
-            '-map', '[vout0]', '-c:v', 'libx264', '-b:v', '3600000',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '192000',
+            '-map', '[vout0]', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '192000',
 
             'output.mp4',
 
-            '-map', '[aout1]', '-c:a', 'libmp3lame', '-b:a', '394000',
+            '-map', '[aout1]', '-c:a:0', 'libmp3lame', '-b:a:0', '394000',
             '-vn',
             '/tmp/out.mp3'
         )
@@ -164,11 +164,47 @@ class FFMPEGTestCase(BaseTestCase):
             '-i', 'source.mp4',
             '-filter_complex',
             '[0:v:0]scale=w=640:h=360[vout0]',
-            '-map', '[vout0]', '-c:v', 'libx264', '-b:v', '3600000',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '192000',
+            '-map', '[vout0]', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '192000',
             'output.mp4'
         )
 
+    def test_set_stream_index_for_codec_params(self):
+        """ Codec params in same file should be properly indexed."""
+        ff = self.ffmpeg
+        ff < self.source
+
+        split = ff.video | filters.Scale(640, 360) | filters.Split(VIDEO, 4)
+        split > self.video_codec
+        vc1 = X264(bitrate=1800000)
+        vc2 = X264(bitrate=900000)
+        vc3 = X264(bitrate=450000)
+
+        split > vc1
+        split > vc2
+        split > vc3
+
+        output1 = outputs.output_file('first.mp4', self.video_codec, vc1)
+        output2 = outputs.output_file('second.mp4', vc2, vc3)
+
+        ff > output1
+        ff > output2
+
+        self.assert_ffmpeg_args(
+            '-i', 'source.mp4',
+            '-filter_complex',
+            '[0:v:0]scale=w=640:h=360[v:scale0];'
+            '[v:scale0]split=4[vout0][vout1][vout2][vout3]',
+            '-map', '[vout0]', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '[vout1]', '-c:v:1', 'libx264', '-b:v:1', '1800000',
+            '-an',
+            'first.mp4',
+            '-map', '[vout2]', '-c:v:0', 'libx264', '-b:v:0', '900000',
+            '-map', '[vout3]', '-c:v:1', 'libx264', '-b:v:1', '450000',
+            '-an',
+            'second.mp4'
+        )
+
     def test_bypass_disabled_filter(self):
         """ Audio stream bypass mode."""
         ff = self.ffmpeg
@@ -182,8 +218,8 @@ class FFMPEGTestCase(BaseTestCase):
 
         self.assert_ffmpeg_args(
             '-i', 'source.mp4',
-            '-map', '0:v:0', '-c:v', 'libx264', '-b:v', '3600000',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '192000',
+            '-map', '0:v:0', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '192000',
             'output.mp4'
         )
 
@@ -200,7 +236,7 @@ class FFMPEGTestCase(BaseTestCase):
             '-i', 'source.mp4',
             '-filter_complex',
             '[0:v:0]scale=w=640:h=360[vout0]',
-            '-map', '[vout0]', '-c:v', 'libx264',
+            '-map', '[vout0]', '-c:v:0', 'libx264',
             '-an',
             'out.mp4'
         )
@@ -213,8 +249,8 @@ class FFMPEGTestCase(BaseTestCase):
 
         self.assert_ffmpeg_args(
             '-i', 'source.mp4',
-            '-map', '0:v:0', '-c:v', 'libx264', '-b:v', '3600000',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '192000',
+            '-map', '0:v:0', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '192000',
             'output.mp4'
         )
 
@@ -244,8 +280,8 @@ class FFMPEGTestCase(BaseTestCase):
             '[v:scale0][v:scale1]overlay[vout0];'
             '[1:v:0]scale=w=1280:h=720[v:scale1];'
             '[1:a:0]volume=-20.00[aout0]',
-            '-map', '[vout0]', '-c:v', 'libx264', '-b:v', '3600000',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '192000',
+            '-map', '[vout0]', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '192000',
             'output.mp4'
         )
 
@@ -265,9 +301,9 @@ class FFMPEGTestCase(BaseTestCase):
             '-filter_complex',
             '[0:a:0]volume=20.00[aout0]',
             '-map', '0:v:0',
-            '-c:v', 'copy',
+            '-c:v:0', 'copy',
             '-map', '[aout0]',
-            '-c:a', 'aac', '-b:a', '128000',
+            '-c:a:0', 'aac', '-b:a:0', '128000',
             '/tmp/out.flv'
         )
 
@@ -289,14 +325,14 @@ class FFMPEGTestCase(BaseTestCase):
         self.assert_ffmpeg_args(
             '-i', 'source.mp4',
             '-map', '0:v:0',
-            '-c:v', 'libx264', '-b:v', '3600000',
+            '-c:v:0', 'libx264', '-b:v:0', '3600000',
             '-map', '0:a:0',
-            '-c:a', 'aac', '-b:a', '192000',
+            '-c:a:0', 'aac', '-b:a:0', '192000',
             'output.mp4',
             '-map', '0:v:0',
-            '-c:v', 'copy',
+            '-c:v:0', 'copy',
             '-map', '0:a:0',
-            '-c:a', 'copy',
+            '-c:a:0', 'copy',
             '/tmp/out1.flv',
         )
 
@@ -321,14 +357,14 @@ class FFMPEGTestCase(BaseTestCase):
             '-filter_complex',
             '[0:v:0]scale=w=640:h=360[vout0]',
             '-map', '0:v:0',
-            '-c:v', 'copy',
+            '-c:v:0', 'copy',
             '-map', '0:a:0',
-            '-c:a', 'copy',
+            '-c:a:0', 'copy',
             '/tmp/copy.flv',
             '-map', '[vout0]',
-            '-c:v', 'libx264',
+            '-c:v:0', 'libx264',
             '-map', '0:a:0',
-            '-c:a', 'aac',
+            '-c:a:0', 'aac',
             '/tmp/out.flv')
 
     def test_transcoding_without_graph(self):
@@ -361,9 +397,9 @@ class FFMPEGTestCase(BaseTestCase):
             'ffmpeg',
             '-i', '/tmp/input.mp4',
             '-map', '0:v:0',
-            '-c:v', 'libx264',
+            '-c:v:0', 'libx264',
             '-map', '0:a:0',
-            '-c:a', 'aac',
+            '-c:a:0', 'aac',
             '-f', 'tee',
             '[f=hls:hls_time=2]http://ya.ru/1.m3u8|'
             '[f=hls:hls_list_size=5]http://ya.ru/2.m3u8'
@@ -398,8 +434,8 @@ class FFMPEGTestCase(BaseTestCase):
             "[v:scale0]setsar=1[v:setsar0];"
             "[v:setsar0][1:v:0]concat[vout0];"
             "[0:a:0][1:a:0]concat=v=0:a=1:n=2[aout0]",
-            '-map', '[vout0]', '-c:v', 'libx264', '-b:v', '3600000',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '192000',
+            '-map', '[vout0]', '-c:v:0', 'libx264', '-b:v:0', '3600000',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '192000',
             'output.mp4'
         )
 
diff --git a/tests/test_vector.py b/tests/test_vector.py
index 57047bf..b950d50 100644
--- a/tests/test_vector.py
+++ b/tests/test_vector.py
@@ -125,11 +125,11 @@ class VectorTestCase(BaseTestCase):
         """ Checks that vector works correctly without filter graph."""
         self.assert_simd_args(
             '-i', 'input.mp4',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_filter_graph_pass_through(self):
@@ -139,11 +139,11 @@ class VectorTestCase(BaseTestCase):
 
         self.assert_simd_args(
             '-i', 'input.mp4',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_single_quality_copy_pass_through(self):
@@ -161,11 +161,11 @@ class VectorTestCase(BaseTestCase):
             '-i', 'input.mp4',
             '-filter_complex',
             '[0:v:0]scale=w=1920:h=1080[vout0]',
-            '-map', '[vout0]', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '[vout0]', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'copy',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'copy',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_same_filter_for_all_streams(self):
@@ -178,11 +178,11 @@ class VectorTestCase(BaseTestCase):
             '-filter_complex',
             '[0:a:0]volume=30.00[a:volume0];'
             '[a:volume0]asplit[aout0][aout1]',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '[aout1]', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '[aout1]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_same_filter_with_mask(self):
@@ -195,11 +195,11 @@ class VectorTestCase(BaseTestCase):
             '-filter_complex',
             '[0:a:0]asplit[a:asplit0][aout0];'
             '[a:asplit0]volume=30.00[aout1]',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '[aout1]', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '[aout1]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_multiple_disabled_filters(self):
@@ -210,11 +210,11 @@ class VectorTestCase(BaseTestCase):
             'input.mp4',
             '-filter_complex',
             '[0:a:0]asplit[aout0][aout1]',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '[aout1]', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '[aout1]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_apply_filter_with_params_vector(self):
@@ -227,11 +227,11 @@ class VectorTestCase(BaseTestCase):
             '[0:a:0]asplit[a:asplit0][a:asplit1];'
             '[a:asplit0]volume=20.00[aout0];'
             '[a:asplit1]volume=30.00[aout1]',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '[aout1]', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '[aout1]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_apply_filter_with_equal_params(self):
@@ -243,11 +243,11 @@ class VectorTestCase(BaseTestCase):
             '-filter_complex',
             '[0:a:0]volume=30.00[a:volume0];'
             '[a:volume0]asplit[aout0][aout1]',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '[aout1]', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '[aout1]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_split_filter_if_vector_differs(self):
@@ -266,11 +266,11 @@ class VectorTestCase(BaseTestCase):
             '[a:volume0]stub[aout0];'
             '[a:asplit1]volume=30.00[a:volume1];'
             '[a:volume1]stub[aout1]',
-            '-map', '0:v:0', '-c:v', 'libx264',
-            '-map', '[aout0]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '0:v:0', '-c:v:0', 'libx264',
+            '-map', '[aout0]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '0:v:0', '-c:v', 'libx265',
-            '-map', '[aout1]', '-c:a', 'libfdk_aac',
+            '-map', '0:v:0', '-c:v:0', 'libx265',
+            '-map', '[aout1]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_clone_inputs_for_destination_filter(self):
@@ -300,11 +300,11 @@ class VectorTestCase(BaseTestCase):
             '[v:another0]split[v:split4][v:split5];'
             '[v:split4][v:scale0]overlay[vout0];'
             '[v:split5][v:scale1]overlay[vout1]',
-            '-map', '[vout0]', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '[vout0]', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '[vout1]', '-c:v', 'libx265',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '[vout1]', '-c:v:0', 'libx265',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_clone_streams(self):
@@ -328,11 +328,11 @@ class VectorTestCase(BaseTestCase):
             '[v:split1]scale=w=640:h=360[v:scale1];'
             '[v:split2][v:scale0]overlay[vout0];'
             '[v:split3][v:scale1]overlay[vout1]',
-            '-map', '[vout0]', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '[vout0]', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '[vout1]', '-c:v', 'libx265',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '[vout1]', '-c:v:0', 'libx265',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5'
         )
 
@@ -352,11 +352,11 @@ class VectorTestCase(BaseTestCase):
             '-filter_complex',
             '[0:v:0]split[v:split0][vout0];'
             '[1:v:0][v:split0]overlay[vout1]',
-            '-map', '[vout1]', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '[vout1]', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '[vout0]', '-c:v', 'libx265',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '[vout0]', '-c:v:0', 'libx265',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5'
         )
 
@@ -383,11 +383,11 @@ class VectorTestCase(BaseTestCase):
             '[0:a:0]asplit[a:asplit0][aout0];'
             '[1:v:0][v:split0]concat[vout1];'
             '[1:a:0][a:asplit0]concat=v=0:a=1:n=2[aout1]',
-            '-map', '[vout1]', '-c:v', 'libx264',
-            '-map', '[aout1]', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '[vout1]', '-c:v:0', 'libx264',
+            '-map', '[aout1]', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '[vout0]', '-c:v', 'libx265',
-            '-map', '[aout0]', '-c:a', 'libfdk_aac',
+            '-map', '[vout0]', '-c:v:0', 'libx265',
+            '-map', '[aout0]', '-c:a:0', 'libfdk_aac',
             'output2.mp5')
 
     def test_connect_filter_to_a_vector(self):
@@ -406,11 +406,11 @@ class VectorTestCase(BaseTestCase):
             '[v:overlay0]split[vout0][vout1];'
             '[1:v:0]scale=w=120:h=120[v:scale0];'
             '[0:v:0][v:scale0]overlay[v:overlay0]',
-            '-map', '[vout0]', '-c:v', 'libx264',
-            '-map', '0:a:0', '-c:a', 'aac', '-b:a', '64000',
+            '-map', '[vout0]', '-c:v:0', 'libx264',
+            '-map', '0:a:0', '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
-            '-map', '[vout1]', '-c:v', 'libx265',
-            '-map', '0:a:0', '-c:a', 'libfdk_aac',
+            '-map', '[vout1]', '-c:v:0', 'libx265',
+            '-map', '0:a:0', '-c:a:0', 'libfdk_aac',
             'output2.mp5'
         )
 
@@ -437,14 +437,14 @@ class VectorTestCase(BaseTestCase):
             '[v:concat0]scale=w=1820:h=720[v:scale0];'
             '[1:v:0][1:v:0]concat[v:concat0]',
             '-map', '[vout0]',
-            '-c:v', 'libx264',
+            '-c:v:0', 'libx264',
             '-map', '[aout0]',
-            '-c:a', 'aac', '-b:a', '64000',
+            '-c:a:0', 'aac', '-b:a:0', '64000',
             'output1.mp4',
             '-map', '[vout1]',
-            '-c:v', 'libx265',
+            '-c:v:0', 'libx265',
             '-map', '[aout1]',
-            '-c:a', 'libfdk_aac',
+            '-c:a:0', 'libfdk_aac',
             'output2.mp5'
         )