FFMPEG Pick First Audio Stream of Specific Language - ffmpeg

I am trying to extract a single audio stream of a specific language from a video file (which has around 10 different audio streams).
So I tried to use this command:
ffmpeg -i file.mkv -map 0:a:m:language:eng output.mp3
The problem is that the video contains multiple english language audio streams. So I get the error:
Invalid audio stream. Exactly one MP3 audio stream is required.
Here is the stream mapping:
Stream #0:1 -> #0:0
Stream #0:4 -> #0:1
From those two streams I only want the first one. I tried to with -map 0:a:m:language:eng -map 0:0, but this doesn't help in narrowing it down.
Note: I need the language filter as the stream numbers aren't consistent across multiple files. But the English language stream with the lower number is always the correct one I want to map.

Thanks to #kesh's post I found a solution.
By splitting the command into 2 and piping it in the next it is possible to get the expected behaviour.
Here is the code that worked for me:
ffmpeg -i input.mkv -map 0:a:m:language:eng -acodec copy -f matroska pipe: | ffmpeg -i pipe: -map 0:0 -c:a libmp3lame output.mp3

Related

Remove all non key frames from video without re-encoding

I have a HEVC mkv video from which I need to remove all but key frames without re-encoding whole thing.
I found out that I can extra key frames using this
ffmpeg -i full.mkv -c:v copy -vf "select=eq(pict_type\,PICT_TYPE_I)" key.mkv
but I get:
Filtergraph 'select=eq(pict_type\,PICT_TYPE_I)' was defined for video output stream 0:0 but codec copy was selected.
Filtering and streamcopy cannot be used together.
What do I do?
You'll have to use the bitstream filter filter_units for this:
ffmpeg -i test.mkv -c copy -map v -bsf:v "filter_units=pass_types=16-23|32-34" key.mkv
This will only pass through random access pictures from the HEVC stream. This should cover most of them but HEVC has more keyframes types than H.264 so I'll update the types above if there are some I've missed.

ffmpeg filter_complex trim out-sync

command line:
ffmpeg -i <INPUT> -filter-complex "<FILTER_COMPLEX>" -map "[ofa]" -map "[ofv]" -acodec aac -vcodec libx264 test.mp4
FILTER_COMPLEX content:
[0:v]split=3[sv1][sv2][sv3];
[0:a]asplit=3[sa1][sa2][sa3];
[sv1]trim=start=200:duration=5,setpts=PTS-STARTPTS[ov1];[sa1]atrim=start=200:duration=5[oa1];
[sv2]trim=start=300:duration=5,setpts=PTS-STARTPTS[ov2];[sa2]atrim=start=300:duration=5[oa2];
[sv3]trim=start=400:duration=5,setpts=PTS-STARTPTS[ov3];[sa3]atrim=start=400:duration=5[oa3];
[ov1][ov2][ov3]concat=n=3:v=1:a=0[ofv];
[oa1][oa2][oa3]concat=n=3:v=0:a=1[ofa]
As a result, the output video sounds are out of sync, and the video is redirected to 00:00:00, but the sound remains at the original time position.
Therefore, how to use ffmpeg to intercept several clips from a video, recombine them into a new video file, and keep the sound and picture synchronized.
I tried with [sa1]atrim=start=200:duration=5,setpts=PTS-STARTPTS[oa1] but an error:
Media type mismatch between the 'Parsed_atrim_4' filter output pad 0 (audio) and the 'Parsed_setpts_5' filter input pad 0 (video)
Cannot create the link atrim:0 -> setpts:0
Error initializing complex filters.
Invalid argument

Converting MKV to MP4

So I am trying to convert a really long video from MKV to MP4.
I tried this command first which is supposed to be the fastest way to convert mkv to mp4
ffmpeg -i "vid.mkv" -codec copy -map 0 "MP4/vid.mp4"
however I am getting this error everytime I run it
[mp4 # 0x7fffe98ae500] track 1: codec frame size is not set
[mp4 # 0x7fffe98ae500] opus in MP4 support is experimental, add '-strict -2' if you want to use it.
Could not write header for output file #0 (incorrect codec parameters ?): Experimental feature
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:1 -> #0:1 (copy)
Last message repeated 1 times
What am I doing wrong?
The issue and solution is mentioned in the 2nd line of the excerpt you pasted.
You're using an older version of ffmpeg. Since recently, Opus audio in MP4 is no longer treated as experimental. Upgrade to ffmpeg 4.3 or add -strict -2 as mentioned in log.
For compatibility sake, you'll usually want to transcode audio to AAC.
ffmpeg -i "vid.mkv" -map 0 -c copy -c:a aac "MP4/vid.mp4"

ffmpeg Copy and convert specific stream and mux into file with single command

If I have a video file with 1 video streams, 2 DTS audio streams, and 2 subtitle streams, can I convert a DTS stream to ac3 and mux it into a file with a single command?
Currently I used a command like this (stream 0:1 is DTS-HD) to extract the audio and convert it to AC3, then I have to manually mux it back in using -map. Is there a way to cut out that 2nd command and just convert and mux in the new stream to a new file?
ffmpeg -y -i "media.mkv" -map 0:1 -c:a ac3 -b:a 640k newmedia.mkv
ALSO: The DTS streams are 5.1 surround sound. Do I have to do anything special to preserve those channels, or will they automatically convert over?
Use
ffmpeg -y -i "media.mkv" -map 0 -c copy -c:a:0 ac3 -b:a:0 640k newmedia.mkv.
In the command above, the first output audio stream is encoded to AC3, with a bitrate set for it. All other streams are copied.
If the encoder supports the channel count and layout then they will be preserved. AC3 does, IIRC.

Adding an audio track to a video using it's own audio as a source?

I have a video file with the following layout:
Video
DTS audio
What I would like to do is:
Video
AAC audio (converted from the DTS source)
DTS audio
I can't wrap my head around the FFMPEG command I would need to do this, though, since I would need to convert the DTS audio to AAC and then place it ahead of the DTS track. The reason for this is the PS4 media player currently doesn't let you select audio tracks and it only plays the first one it sees. It doesn't support DTS audio but I'd like to keep it around.
Alright, figured it out after looking FFMPEG's map documentation: https://trac.ffmpeg.org/wiki/Map
The solution was this command:
ffmpeg -i in.mkv -map 0:0 -map 0:1 -map 0:1 -c:v copy -c:a:0 libfdk_aac -c:a:1 copy out.mkv
The trick was mapping the audio stream twice and using the -c:a:x syntax to encode the DTS stream to AAC first and then copy the DTS stream second in the output file.

Resources