I'm trying to copy video/audio from an mkv container to mp4. When I run ffmpeg -i input.mkv -c:v copy -c:a copy output.mp4 I'm given no video with polish audio. There's only one video stream, stream #0:0. Stream #0:1 is polish audio, #0:2 english, and #0:3 - #0:5 are subtitles.
I read FFmpeg Wiki: Map but don't understand it really. Why is -map 0:1 written twice in example 1? What does -c:s do? What would a command to copy #0:0 to video and #0:2 to audio look like?
5 Answers
-map <inputNo>:<streamNo> tells ffmpeg to take stream streamNo from the input inputNo and to add it to the output, where <inputNo> starts with 0.
Sometimes, you may want to take the same input stream twice (such as -map 0:1 -map 0:1 in the example) because you can encode each with different codecs/parameters. In the example, the output contains the same audio stream twice, one in MP3 and the other in AAC.
By default (i.e. with no -map command at all), one video, one audio, and one subtitle stream from the inputs are taken. If you want to map all the streams from one input, use -map <inputNo>.
That you don't get video with your command can only mean one thing : your video track is encoded with a codec that can be muxed in MKV, but not in MP4. So it is discarded automatically. Can you post a log of ffmpeg -i input.mkv so that we can check which codecs the tracks are encoded with ?
Finally, -c:s is used for subtitle codec (while -c:a is for audio and -c:v for video)
This was the example that allowed me to understand. Imagine the following command:
ffmpeg -i tears_of_steel.mkv -map 0:0 -map 0:2 -map 0:1 -map 0:4 -map 0:3 -c copy tears_of_steel-v2.mkv And here is how ffmpeg does the mapping:
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:2 -> #0:1 (copy)
Stream #0:1 -> #0:2 (copy)
Stream #0:4 -> #0:3 (copy)
Stream #0:3 -> #0:4 (copy)What happened?
In the command, we have only one input: tears_of_steel.mkv. That's why all our maps start with #0:...
Then we write a first map option: -map 0:0, which refers to the first stream of our input (tears_of_steel.mkv), which might be a video stream, but that doesn't matter.
Because it's the first map option, it will be mapped to the first stream in our output file (tears_of_steel-v2.mkv).
Then we write a second map option: -map 0:2, which refers to the third stream of our input. Because it's the second map option, it is mapped to the second stream in our output.
And so on...
I wrote that on my github:
This should work, can't test on this machine:
ffmpeg -i input.mkv
-map 0:0 -map 0:2 \
-c:v copy \
-c:a aac \
-b:a 128k \
output.mp4or
ffmpeg -i input.mkv -map 0:0 -map 0:2 -c:v copy -c:a aac -b:a 128k output.mp4Explanations
c:s is an alias for -scodec codec, which specifies the subtitle codec.
-map 0:1 is there twice because the example has an aac and an mp3 output.
1This is a simple answer for people like me, who like simple working explanations. This is a solution when you copy mkv to mp4 and want to choose audio streams:
You have to write -map 0:numberofstreamminusone in front of -c:a copy
Let's say the video has 3 streams (you can see that in mediainfo). The first stream is video, the second is default audio, and the third is non-default audio in the language you want. So you have to write -map 0:2 NOT -map 0:3
Also, you have to write -map 0:0 in front of -c:v copy because if you don't, ffmpeg will not copy the video stream and you get only the audio stream (If the video has two video streams and you want to copy the second one, you have to write -map 0:1)
So the final command line looks like this:
ffmpeg -i "inputpath\input.mkv" -map 0:0 -c:v copy -map 0:2 -c:a copy "outputpath\output.mp4"In this case, you wil get the first video stream and the third audio stream
Another example:
ffmpeg -i "inputpath\input.mkv" -map 0:1 -c:v copy -map 0:6 -c:a copy "outputpath\output.mp4"In this case you should get the second video stream and the seventh audio stream
I hope this helps
2Here's how -c (select codecs) & -map (select streams) options work:
-c:a -> select first or best supported audio (transcoded)
-c:a copy -> best supported audio (copied)
-map 0:a -> all audio from 1st input file (transcoded)
-map 1:a:0 -> 1st audio stream from 2nd input file (transcoded)
-map 1:a:1 -c:a copy -> 2nd audio stream from 2nd input file (copied)To copy all subtitle streams from 1st input file without transcoding:
-map 0:s -c:s copy Your outfile is mp4 and input file is mkv and you've elected to have video output without transcoding (-c:v copy) to a compatible format for mp4, so you end up with an mp4 file without (a playable) video.
Either specify video encoder compatible with mp4 eg. -c:v libx264 instead of -c:v copy or leave that blank (ie. don't mention an encoder & ffmpeg encoders chosen will be the default ones registered by each output format)
If you don't want to transcode video (because it can take a considerable time) , then copy the video stream to same container but select the audio you want eg. mkv. To get an mp4 file with transcoded video & selected audio:
ffmpeg -i input.mkv -map 0:0 -c:v libx264 -map 0:2 -c:a copy output.mp4