ffmpeg combine audio mix code into complex concate script - bash

I got currently 2 different ffmpeg scripts which I want to combine. I do not have good ffmpeg experience and those codes are mostly googel code so please be patient with me
The first code is concating 3 videos:
ffmpeg -y -i "$vid1" -i "$fp" -i "$vid1" -filter_complex \
"[0:v]scale=$cResolution:force_original_aspect_ratio=decrease,pad=$cResolution:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30,format=yuv420p[v0]; \
[1:v]scale=$cResolution:force_original_aspect_ratio=decrease,pad=$cResolution:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30,format=yuv420p[v1]; \
[2:v]scale=$cResolution:force_original_aspect_ratio=decrease,pad=$cResolution:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30,format=yuv420p[v2]; \
[0:a]aformat=sample_rates=48000:channel_layouts=stereo[a0]; \
[1:a]aformat=sample_rates=48000:channel_layouts=stereo[a1]; \
[2:a]aformat=sample_rates=48000:channel_layouts=stereo[a2]; \
[v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[v][a]; \
[v]drawtext=text='example..':y=h-line_h-$h3:x=w/30*mod(t\,20):enable='gt(mod(t,$dr2),$Introdr_rounded)'[v]; \
[v]drawtext=text='example..':y=h-line_h-$hcentral:x=w/20*mod(t\,100):enable='gt(mod(t,$dr2),$Introdr_rounded)'[v]; \
[v]drawtext=text='example..':y=h-line_h-23:x=w/30*mod(t\,20):enable='gt(mod(t,$dr2),$Introdr_rounded)'[v]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 22 -preset veryfast -c:a aac -movflags +faststart "$fp_dest"
The second code is overlay a background mp3 in endless loop to the created video from above. Its important to know that this code does overlap the audio of the video and does not replace it. In future I will lower the volume of the mp3 files to work as background music
ffmpeg -y -i "$fp_dest" -filter_complex "amovie=$audio:loop=0,asetpts=N/SR/TB[aud];[0:a][aud]amix[a]" -map 0:v -map '[a]' -c:v copy -c:a aac -b:a 256k -shortest ./test.mp4
So currently I got 2 steps which I want to combine into 1 step. Can you please help me to include the second code into the first one without change any logic of the code?

Use amix to mix the music and the concated audio. stream_loop is applied to the music to loop it.
ffmpeg -y -i "$vid1" -i "$fp" -i "$vid1" -stream_loop -1 -i "$audio" -filter_complex \
"[0:v]scale=$cResolution:force_original_aspect_ratio=decrease,pad=$cResolution:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30,format=yuv420p[v0]; \
[1:v]scale=$cResolution:force_original_aspect_ratio=decrease,pad=$cResolution:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30,format=yuv420p[v1]; \
[2:v]scale=$cResolution:force_original_aspect_ratio=decrease,pad=$cResolution:(ow-iw)/2:(oh-ih)/2,setsar=1,fps=30,format=yuv420p[v2]; \
[0:a]aformat=sample_rates=48000:channel_layouts=stereo[a0]; \
[1:a]aformat=sample_rates=48000:channel_layouts=stereo[a1]; \
[2:a]aformat=sample_rates=48000:channel_layouts=stereo[a2]; \
[v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[v][a]; \
[a][3]amix=duration=first[a]; \
[v]drawtext=text='example..':y=h-line_h-$h3:x=w/30*mod(t\,20):enable='gt(mod(t,$dr2),$Introdr_rounded)'[v]; \
[v]drawtext=text='example..':y=h-line_h-$hcentral:x=w/20*mod(t\,100):enable='gt(mod(t,$dr2),$Introdr_rounded)'[v]; \
[v]drawtext=text='example..':y=h-line_h-23:x=w/30*mod(t\,20):enable='gt(mod(t,$dr2),$Introdr_rounded)'[v]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 22 -preset veryfast -c:a aac -b:a 256k -movflags +faststart "$fp_dest"

Related

Multiple sounds + watermark overlay not working with ffmpeg

I have a problem with an ffmpeg command.
I want to add the same sound several times in the final video and then add a watermark above.
When I do the full command, it doesn't work correctly because the sound is only played once (the first reference):
ffmpeg -i "assets/frame%05d.png" -i "assets/sound.mp3" -loop 1 -i
"assets/watermark.png" -filter_complex
"[1:a]adelay=1000|1000[s1];[1:a]adelay=3000|3000[s2];[s1][s2]amix=2[a];[0:v][2:v]overlay=shortest=1[outv]"
-map "[outv]" -map "[a]" -c:v libx264 -pix_fmt yuv420p -preset ultrafast -y "result.mp4"
When I don't add the watermark, it works correctly:
ffmpeg -i "assets/frame%05d.png" -i "assets/sound.mp3" -filter_complex
"[1:a]adelay=1000|1000[s1];[1:a]adelay=3000|3000[s2];[s1][s2]amix=2[a]"
-map 0:v -map "[a]" -c:v libx264 -pix_fmt yuv420p -preset ultrafast -y "result.mp4"
Try this:
ffmpeg -i "assets/frame%05d.png" \
-stream_loop -1 -i "assets/sound.mp3" \
-loop 1 -i "assets/watermark.png" \
-filter_complex "[1:a]adelay=1000|1000[s1];\
[1:a]adelay=3000|3000[s2];\
[s1][s2]amix=2[a];\
[0:v][2:v]overlay=shortest=1[outv]" \
-map "[outv]" -map "[a]" -shortest \
-c:v libx264 -pix_fmt yuv420p -preset ultrafast -y "result.mp4"
-stream_loop -1 input option loops the input infinitely and -shortest output option stops the audio when video is done.
p.s., I think an aecho filter can combine the 2nd adelay and amix filters.
I found the problem was that the different frames that make up the video were not all correctly encoded which caused the problem with the sounds.
ffmpeg can't read indexed PNG correctly.
You must therefore use this option (for those like me who use imagick):
$imagick->setOption('png:color-type', 6);
$imagick->writeImage('frame00000.png');

Ffmpeg - How can I create HLS multiple language streams, in multiple qualities?

Preface
I'm working on converting videos from 4k to multiple qualities with multiple languages but am having issues with the multiple languages overlaying, sometimes losing quality and sometimes being out of sync. (this is less of a problem in the German audio, as this is voice over anyhow)
We as a team are complete noobs in terms of Video / Audio + HLS -- I'm a front end developer who has no experience of this so apologies if my question is poorly phrased
Videos
I have the video in a 4k format and have removed the original sound as I have English and German audio files that need to be overlayed. I am then taking these files and throwing them together into a .ts file like this:
$ ffmpeg -i ep03-ns-4k.mp4 -i nkit-ep3-de-output.m4a -i nkit-ep3-en-output.m4a \
> -thread 0 -muxdelay 0 -y \
> -map 0:v -map 1 -map 2 -movflags +faststart -refs 1 \
> -vcodec libx264 -acodec aac -profile:v baseline -level 30 -ar 44100 -ab 64k -f mpegts out.ts
This outputs a 4k out.ts video, with both audio tracks playing.
The hard part
This is where I'm finding it tricky, I now need to convert this single file into multiple quality levels (480, 720, 1080, 1920) and I attempt this with the following command:
ffmpeg -hide_banner -y -i out.ts \
-crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -ar 48000 \
-map 0:v:0 -map 0:v:0 -map 0:v:0 -map 0:v:0 \
-c:v:0 h264 -profile:v:0 main -filter:v:0 "scale=w=848:h=480:force_original_aspect_ratio=decrease" -b:v:0 1400k -maxrate:v:0 1498k -bufsize:v:0 2100k \
-c:v:1 h264 -profile:v:1 main -filter:v:1 "scale=w=1280:h=720:force_original_aspect_ratio=decrease" -b:v:1 2800k -maxrate:v:1 2996k -bufsize:v:1 4200k \
-c:v:2 h264 -profile:v:2 main -filter:v:2 "scale=w=1920:h=1080:force_original_aspect_ratio=decrease" -b:v:2 5600k -maxrate:v:2 5992k -bufsize:v:2 8400k \
-c:v:3 h264 -profile:v:3 main -filter:v:3 "scale=w=3840:h=1920:force_original_aspect_ratio=decrease" -b:v:3 11200k -maxrate:v:3 11984k -bufsize:v:3 16800k \
-var_stream_map "v:0 v:1 v:2 v:3" \
-master_pl_name master.m3u8 \
-f hls -hls_time 4 -hls_playlist_type vod -hls_list_size 0 \
-hls_segment_filename "%v/episode-%03d.ts" "%v/episode.m3u8"
This creates the required qualities, but I'm now at a loss of how this might work with the audio
Audio
For the audio I run this command:
ffmpeg -i out.ts -threads 0 -muxdelay 0 -y -map 0:a:0 -codec copy -f segment -segment_time 4 -segment_list_size 0 -segment_list audio-de/audio-de.m3u8 -segment_format mpegts audio-de/audio-de_%d.aac
ffmpeg -i out.ts -threads 0 -muxdelay 0 -y -map 0:a:1 -codec copy -f segment -segment_time 4 -segment_list_size 0 -segment_list audio-en/audio-en.m3u8 -segment_format mpegts audio-en/audio-en_%d.aac
This creates the required audio segments.
The question
I realise this is quite an ask, but is there anything wrong with our inputs? Is there a way that this can be done a bit more streamlined?
Any answers are greatly appreciated.
Lets say you have:
VideoA
AudioB-> Language 1
AudioC-> Language 2
AudioD-> Language 3
Although it can be done all together, it is better to use different commands for each language instance.
Note that the following are schematics only- some values and parameters will need to be filled in by you. However, this provides a scheme of how to connect the entities. Also I have simply set the size, and NOT used a scale filter. You can use a scale filter instead. Filters will go in place of the size parameter (-s 1280x720 etc).
ffmpeg -i VideoA -i AudioB -map [0:v] -map [1:a] -s 1280x720 -acodec aac -b:a 128k \
-vcodec libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAB_720p.mp4 -map [0:v] -map [1:a] -s 1920x1080 -acodec aac -b:a 128k -vcodec \
libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAB_1080p.mp4
The above shows a scheme for 2 resolutions, 720p and 1080p, merging VideoA with AudioB. To do the same scheme for AudioC you would repeat:
ffmpeg -i VideoA -i AudioC -map [0:v] -map [1:a] -s 1280x720 -acodec aac -b:a 128k \
-vcodec libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAC_720p.mp4 -map [0:v] -map [1:a] -s 1920x1080 -acodec aac -b:a 128k -vcodec \
libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAC_1080p.mp4
You could put all the inputs together:
ffmpeg -i VideoA -i AudioB -i AudioC -i AudioD
and accordingly map each for every language:
-map [0:v] -map [1:a]
-map [0:v] -map [2:a]
-map [0:v] -map [3:a]
etc.
But I feel such long commands that will result make it difficult to read, maintain and correct.

How do I compose three overlapping videos w/audio in ffmpeg?

I have three videos: let's call them intro, recording and outro. My ultimate goal is to stitch them together like so:
Both intro and outro have alpha (prores 4444) and a "wipe" to transition, so when overlaying, they must be on top of the recording. The recording is h264, and ultimately I'm encoding out for youtube with these recommended settings.
I've figured out how to make the thing work correctly for intro + recording:
$ ffmpeg \
-i intro.mov \
-i recording.mp4 \
-filter_complex \
"[1:v]tpad=start_duration=10:start_mode=add:color=black[rv]; \
[1:a]adelay=delays=10s:all=1[ra]; \
[rv][0:v]overlay[v];[0:a][ra]amix[a]" \
-map "[a]" -map "[v]" \
-movflags faststart -c:v libx264 -profile:v high -bf 2 -g 30 -crf 18 -pix_fmt yuv420p \
out.mp4 -y
However I can't use the tpad trick for the outro because it would render black frames over everything.
I've tried various iterations with setpts/asetpts as well as passing -itsoffset for the input, but haven't come up with a solution that works correctly for both video and audio. This tries to start the outro at 16 seconds into the recording (10s start + 16s of recording is how I got to setpts=PTS+26/TB). del, but doesn't work correctly, I get both intro and outro audio from the first frame, and the recording audio cuts out when the outro overlay begins:
$ ffmpeg \
-i intro.mov \
-i recording.mp4 \
-i outro.mov \
-filter_complex \
"[1:v]tpad=start_duration=10:start_mode=add:color=black[rv]; \
[1:a]adelay=delays=10s:all=1[ra]; \
[2:v]setpts=PTS+26/TB[outv]; \
[2:a]asetpts=PTS+26/TB[outa]; \
[rv][0:v]overlay[v4]; \
[0:a][ra]amix[a4]; \
[v4][outv]overlay[v]; \
[a4][outa]amix[a]" \
-map "[a]" -map "[v]" \
-movflags faststart -c:v libx264 -profile:v high -bf 2 -g 30 -crf 18 -pix_fmt yuv420p \
out.mp4 -y
I think the right solution lies in the direction of using setpts correctly but I haven't been able to wrap my brain fully around it. Or, maybe I'm making life complicated and there's an easier approach?
In the nice-to-have realm, I'd love to be able to specify the start of the outro relative to the end of the recording. I will be doing this to a bunch of recordings of varying lengths. It would be nice to have one command to invoke on everything rather than figuring out a specific timestamp for each one.
Thank you!
Use adelay for all audio adjustments. Perform all mixing in a single amix.
Set the outro overlay to start only at the correct timestamps.
Use
$ ffmpeg \
-i intro.mov \
-i recording.mp4 \
-i outro.mov \
-filter_complex \
"[1:v]tpad=start_duration=10:start_mode=add:color=black[mainv]; \
[1:a]adelay=delays=10s:all=1[maina]; \
[2:v]setpts=PTS+26/TB[outv]; \
[2:a]adelay=delays=26s:all=1[outa]; \
[mainv][0:v]overlay=eof_action=pass[previd]; \
[previd][outv]overlay=enable='gte(t,26)'[v]; \
[maina][0:a][outa]amix=inputs=3[a]; \
-map "[v]" -map "[a]" \
-c:v libx264 -profile:v high -bf 2 -g 30 -crf 18 -pix_fmt yuv420p \
-movflags +faststart \
out.mp4 -y

FFmpeg add a text to last image only

I managed to create a video from set of non-sequential images and attached an audio to it. Also I added a "Copyright" text on top right hand corner so that the text appears throughout the video. However, I would like that text to appear only on the last image. How should I change my code below to address this?
ffmpeg \
-thread_queue_size 512 -f image2 -pattern_type glob -framerate 1/3 \
-i '*.jpg' \
-i 'audio.mp3' \
-c:a aac -c:v libx264 \
-vf scale=640:480, format=yuv420p, drawtext="text='Copyright':fontcolor=white:box=1:boxcolor=black#0.5:boxborderw=5:x=w-tw-5:y=5" \
-preset medium \
video.mp4
Isolate the last image from the glob and then concat it:
ffmpeg \
-pattern_type glob -framerate 1/3 -i '*.jpg' -framerate 1/3 -loop 1 -t 5 -i last/img.jpg -i audio.mp3 \
-filter_complex \
"[0:v]scale=640:480,setsar=1[v0]; \
[1:v]scale=640:480,setsar=1,drawtext=text='Copyright':fontcolor=white:box=1:boxcolor=black#0.5:boxborderw=5:x=w-tw-5:y=5[v1]; \
[v0][v1]concat=n=2:v=1:a=0,fps=25,format=yuv420p[v]" \
-map "[v]" -map 2:a -c:v libx264 -c:a aac -shortest -movflags +faststart video.mp4

FFMpeg - Combine multiple filter_complex and overlay functions

I am having trouble combining these 3 passes in ffmpeg into a single process.
Is this even possible?
Pass 1
ffmpeg -y -i C:\Users\MJ\Downloads\20151211_pmoney_pmpod.mp3 -loop 1 -i C:\Users\MJ\Documents\pm1080.png -filter_complex "[0:a]showwaves=s=1920x1080:mode=line,colorkey=0x000000:0.01:0.1,format=yuva420p[v];[1:v][v]overlay=0:270[outv]" -map "[outv]" -pix_fmt yuv420p -map 0:a -c:v libx264 -c:a copy -shortest C:\Users\MJ\Documents\20151211_pmoney_pmpod4.mp4
Pass 2
ffmpeg -i "C:\Users\MJ\Documents\20151211_pmoney_pmpod4.mp4" -vf drawtext="fontsize=50:fontcolor=white:fontfile=/Windows/Fonts/impact.ttf:text=Planet Money Podcast on NPR - A/B Split Testing:x=(w-text_w)/2:y=200" -acodec copy "C:\Users\MJ\Documents\20151211_pmoney_pmpod-overlay-text.mp4"
Pass 3
ffmpeg -i "C:\Users\MJ\Documents\20151211_pmoney_pmpod-overlay-text.mp4" -i C:\Users\MJ\Downloads\6.png -filter_complex "overlay=10:10" C:\Users\MJ\Documents\20151211_pmoney_pmpod-overlay-text1.mp4"
Thanks!
Join filters with a comma and filterchains with a semicolon:
ffmpeg -i audio.mp3 -i image1.png -i image2.png -filter_complex \
"[0:a]showwaves=s=1920x1080:mode=line[fg]; \
[1:v][fg]overlay=0:270,drawtext=fontsize=50:fontcolor=white:fontfile=/Windows/Fonts/impact.ttf:text='Planet Money Podcast on NPR - A/B Split Testing':x=(w-text_w)/2:y=200[bg]; \
[bg][2:v]overlay=10:10,format=yuv420p[outv]" \
-map "[outv]" -map 0:a -c:v libx264 -c:a copy -movflags +faststart -shortest out.mp4

Resources