FFmpeg filter complex audio - ffmpeg

How do I add the aac to the filter_complex/split so the audio only is encoded once as the yadif?
ffmpeg -y -hwaccel cuvid -i test.mxf -filter_complex "[0:v]yadif=1,split=2[out1][out2]" -map "[out1]" -s 1920:1080 -c:v h264_nvenc -force_key_frames "expr:gte(t,n_forced*10)" -pix_fmt yuv420p -preset slow -rc vbr_hq -b:v 4.5M -map 0:1 -c:a aac -b:a 192k test2.mp4 -map "[out2]" -s 768:432 -c:v h264_nvenc -force_key_frames "expr:gte(t,n_forced*10)" -pix_fmt yuv420p -preset slow -rc vbr_hq -b:v 1.5M -map 0:1 -c:a aac -b:a 192k test3.mp4

Your video is being encoded twice which is unavoidable because you are outputting two different width x height. Your audio is the same for each output, so you can use the tee muxer to only encode audio once and put it in both outputs:
ffmpeg -hwaccel cuvid -i test.mxf -filter_complex "[0:v]yadif=1,format=yuv420p,split=2[vid1][vid2];[vid1]scale=-2:1080[1080];[vid2]scale=-2:432[432]" -map "[1080]" -map "[432]" -map 0:a:0 -c:v h264_nvenc -force_key_frames "expr:gte(t,n_forced*10)" -preset slow -rc vbr_hq -b:v:0 4.5M -b:v:1 1.5M -c:a aac -b:a 192k -f tee "[select=\'v:0,a\']1080.mp4|[select=\'v:1,a\']432.mp4"

Related

FFMPEG stream to multiples servers using the same -filter_complex options

I want to stream a video to two rtmp servers, I have some options like scaling the resolution from 1080p to 576p or adding a logo. These options are serving in the first rtmp server which the signal was sent, but in the second rtmp it is sending 1080p without any of these options, what am I doing wrong?
ffmpeg -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect 1 -reconnect_delay_max 4 -i video.mp4 -i hello.jpg -filter_complex "overlay=1650:950,scale=1024:576" -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k -f flv rtmp://test -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k -f flv rtmp://test2
Unlike input streams, you can only consume a filtergraph output stream only once, and the first rtmp output is snatching it up. If you want to use it on both outputs, split the output of the filter:
ffmpeg -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect 1 -reconnect_delay_max 4 \
-i video.mp4 -i hello.jpg \
-filter_complex "overlay=1650:950,scale=1024:576,split=2[v1][v2]" \
-map [v1] -map 0:a -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k \
-f flv rtmp://test \
-map [v2] -map 0:a -vcodec libx264 -preset veryfast -b:v 1300k \
-acodec aac -b:a 128k -f flv rtmp://test2
Another, likely preferred, option if you are outputting identical streams is to use tee muxer. It should look something like this:
ffmpeg -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect 1 -reconnect_delay_max 4 \
-i video.mp4 -i hello.jpg \
-filter_complex "overlay=1650:950,scale=1024:576[vout]" \
-map [vout] -map 0:a -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k \
-f tee "[f=flv]rtmp://test|[f=flv] rtmp://test2"

Ffmpeg silent audio

I have a string that outputs 4x mp4.
I would like to add quiet audio to the outputs.
I have tried to insert anullsrc=cl=mono:sample_rate=48000 but don't really know where to insert it. It gives me an error.
ffmpeg -hwaccel_output_format cuda -i test.mxf -filter_complex "[0:v]yadif=1,format=yuv420p,split=4[vid1][vid2][vid3][vid4];[vid1]scale=-2:1080[1080];[vid2]scale=-2:432[432];[vid3]scale=-2:288[288];[vid4]scale=-2:216[216]" -map "[1080]" -map "[432]" -map "[288]" -map "[216]" -map 0:a:0 -c:v h264_nvenc -force_key_frames "expr:gte(t,n_forced*10)" -preset slow -rc vbr_hq -b:v:0 4.5M -b:v:1 1.5M -b:v:2 1.0M -b:v:3 0.5M -c:a aac -b:a 192k -f tee "[select=\'v:0,a\']1080.mp4|[select=\'v:1,a\']432.mp4|[select=\'v:2,a\']288.mp4|[select=\'v:3,a\']216.mp4"
You would add the anullsrc as a lavfi input and then map it.
You then either have to add -shortest or add -t X where X is the duration of the video.
ffmpeg -hwaccel_output_format cuda -i test.mxf -f lavfi -i "anullsrc=cl=mono:sample_rate=48000" -filter_complex "[0:v]yadif=1,format=yuv420p,split=4[vid1][vid2][vid3][vid4];[vid1]scale=-2:1080[1080];[vid2]scale=-2:432[432];[vid3]scale=-2:288[288];[vid4]scale=-2:216[216]" -map "[1080]" -map "[432]" -map "[288]" -map "[216]" -map 0:a:0? -map 1:a -c:v h264_nvenc -force_key_frames "expr:gte(t,n_forced*10)" -preset slow -rc vbr_hq -b:v:0 4.5M -b:v:1 1.5M -b:v:2 1.0M -b:v:3 0.5M -c:a aac -b:a 192k -shortest -f tee "[select=\'v:0,a\']1080.mp4|[select=\'v:1,a\']432.mp4|[select=\'v:2,a\']288.mp4|[select=\'v:3,a\']216.mp4"

How to concatenate and output various video bitrates and a standalone audio file?

How to concatenate and output various video bitrates and a standalone audio file in ffmpeg?
My requirement is:
I have 4 input files.
Need to stitch all 4 files into single segment.
Need output with four different video bit rates: 500k, 800k 1000k 1500k
Along with that I need to extract only audio from stitched file.
So my output will be 4 different video bitrate + 1 audio only file.
tee muxer
Most efficient method is to use the tee muxer (more examples) to avoid unnecessarily encoding the audio for each output, but it is complicated to use:
ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][aud];[v]split=4[v0][v1][v2][v3]" -map "[v0]" -b:v:0 500k -map "[v1]" -b:v:1 800k -map "[v2]" -b:v:2 1000k -map "[v3]" -b:v:3 1500k -map "[aud]" -c:v libx264 -c:a aac -f tee "[select=\'v:0,aud\':movflags=faststart]500.mp4|[select=\'v:1,aud\':movflags=faststart]800.mp4|[select=\'v:2,aud\':movflags=faststart]1000.mp4|[select=\'v:3,aud\':movflags=faststart]1500.mp4|[select=aud:movflags=faststart]audio.m4a"
This example method doesn't perform two-passes which you should do when using your old school method of manually choosing the bitrate for non-streaming outputs. See FFmpeg Wiki: H.264.
simpler but less efficient method
You can do a much less complicated command but it will be less efficient because it will separately encode the audio for each output. Possibly worth the tradeoff of less complexity.
ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a];[v]split=4[v0][v1][v2][v3];[a]asplit=4[a0][a1][a2][a3]" -map "[v0]" -map "[a0]" -b:v 500k -movflags +faststart 500.mp4 -map "[v1]" -map "[a1]" -c:v libx264 -c:a aac -b:v 800k -movflags +faststart 800.mp4 -map "[v2]" -map "[a2]" -b:v 1000k -movflags +faststart 1000.mp4 -map "[v3]" -map "[a3]" -b:v 1500k -movflags +faststart 1500.mp4
But since you're wanting to target a specific bitrate you should perform two passes:
ffmpeg -y -i 1.mp4 -i 2.mp4 -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0[v];[v]split=4[v0][v1][v2][v3]" -map "[v0]" -b:v 500k -pass 1 -passlogfile 500 -f mp4 /dev/null -map "[v1]" -c:v libx264 -c:a aac -b:v 800k -pass 1 -passlogfile 800 -f mp4 /dev/null -map "[v2]" -c:v libx264 -c:a aac -b:v 1000k -pass 1 -passlogfile 1000 -f mp4 /dev/null -map "[v3]" -c:v libx264 -c:a aac -b:v 1500k -pass 1 -passlogfile 1500 -f mp4 /dev/null
ffmpeg -y -i 1.mp4 -i 2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a];[v]split=4[v0][v1][v2][v3];[a]asplit=5[a0][a1][a2][a3][a4]" -map "[v0]" -map "[a0]" -c:v libx264 -c:a aac -b:v 500k -pass 2 -passlogfile 500 -movflags +faststart 500.mp4 -map "[v1]" -map "[a1]" -c:v libx264 -c:a aac -b:v 800k -pass 2 -passlogfile 800 -movflags +faststart 800.mp4 -map "[v2]" -map "[a2]" -c:v libx264 -c:a aac -b:v 1000k -pass 2 -passlogfile 1000 -movflags +faststart 1000.mp4 -map "[v3]" -map "[a3]" -c:v libx264 -c:a aac -b:v 1500k -pass 2 -passlogfile 1500 -movflags +faststart 1500.mp4 -map "[a4]" -movflags +faststart audio.m4a
If you're using Windows replace /dev/null with NUL in the examples above.

Burning subtitles different resolutions

I'm trying to create a live stream with three quality profiles with different resolutions (SD, HD and FullHD). The live stream has subtitles, and I have to burn them for compatibility reasons.
I know how to do it with one profile, but with many no idea.
ffmpeg -nostdin -loglevel error -hwaccel cuvid -deint 2 -drop_second_field 1 -surfaces 15 -c:v h264_cuvid -resize 1280x720 -y -i udp://xxx.xxx.xxx.xxx:xxxxx?pkt_size=1316\&buffer_size=409600\&fifo_size=1000000\&overrun_nonfatal=1 -filter_complex [i:0x2c6]hwdownload,format=nv12[base];[i:0x993]setpts=(2.5)/TB+PTS[subs];[subs]scale=1280:720[subtitle];[base][subtitle]overlay[v];[v]hwupload_cuda[v] -map [v] -c:v hevc_nvenc -preset llhq -rc vbr_hq -cq 23 -qp 23 -tier high -profile:v main10 -level 4.0 -b:v 2000k -maxrate 2400k -bufsize 1000k -map i:0x2bd -c:a libfdk_aac -ac 2 -b:a 64k -map i:0x2be -c:a libfdk_aac -ac 2 -b:a 64k -metadata:s:a:0 language=eng -metadata:s:a:1 language=spa -f mpegts -mpegts_flags resend_headers+pat_pmt_at_frames -mpegts_copyts 1 -pcr_period 40 udp://yyy.yyy.yyy.yyy:yyyy?ttl=31\?pkt_size=1316\&buffer_size=409600\&fifo_size=1000000\&overrun_nonfatal=1
Apparenlty, Iffmpeg doen't allow to use -vf filter with filter_complex.
I'm using ffmpeg 3.4, cuda 8.
Use
ffmpeg -nostdin -loglevel error -hwaccel cuvid -deint 2 -drop_second_field 1 -surfaces 15
-c:v h264_cuvid -y -i udp://xxx.xxx.xxx.xxx:xxxxx?pkt_size=1316\&buffer_size=409600\&fifo_size=1000000\&overrun_nonfatal=1
-filter_complex "[i:0x2c6]hwdownload,format=nv12,split=3[fhd][hd][sd];
[i:0x993]setpts=(2.5)/TB+PTS,split=3[subfhd][subhd][subsd];
[fhd]scale=1920:1080[fhd];
[hd]scale=1280:720[hd];
[sd]scale=960:540[sd];
[subfhd]scale=1920:1080[subfhd];
[subhd]scale=1280:720[subhd];
[subsd]scale=960:540[subsd];
[fhd][subfhd]overlay,hwupload_cuda[v-fhd];
[hd][subhd]overlay,hwupload_cuda[v-hd];
[sd][subsd]overlay,hwupload_cuda[v-sd]"
-map [v-fhd] -map [v-hd] -map [v-sd] -c:v hevc_nvenc -preset llhq -rc vbr_hq -cq 23 -qp 23 -tier high
-profile:v main10 -level 4.0 -b:v 2000k -maxrate 2400k -bufsize 1000k
-map i:0x2bd -map i:0x2be -c:a libfdk_aac -ac 2 -b:a 64k
-metadata:s:a:0 language=eng -metadata:s:a:1 language=spa
-f mpegts -mpegts_flags resend_headers+pat_pmt_at_frames -mpegts_copyts 1
-pcr_period 40 udp://yyy.yyy.yyy.yyy:yyyy?ttl=31\?pkt_size=1316\&buffer_size=409600\&fifo_size=1000000\&overrun_nonfatal=1
You'll have to adjust the video bitrates and buffer sizes as required, but this is the basic command template.

FFMpeg combine two separate commands

I am running 2 seperate ffmpeg commands..
ffmpeg -i video.mp4 -vf scale=1024:768 -crf 0 output_video.mp4
ffmpeg -i output_video.mp4 -s 640x360 -c:v libx264 -preset slow -b:v 650k -r 24 -x264opts keyint=48:min-keyint=48:no-scenecut -profile:v main -preset fast -movflags +faststart -c:a libfdk_aac -b:a 128k -ac 2 out-low.mp4
Is there a way I can do both of these commands in once go? Trying to avoid 2 encoding sessions reducing the quality
Label filter outputs and refer to them in the -map option:
ffmpeg -i video.mp4 -filter_complex "[0:v]scale=1024:768[v768];[0:v]scale=640:360[v360]"
-map "[v768]" -map 0:a -c:v libx264 -c:a copy -crf 0 output_video.mp4
-map "[v360]" -map 0:a -c:v libx264 -preset slow -b:v 650k -r 24 -x264opts keyint=48:min-keyint=48:no-scenecut -profile:v main -preset fast -movflags +faststart -c:a libfdk_aac -b:a 128k -ac 2 out-low.mp4

Resources