ffmpeg, add static image to beginning and end with transitions - ffmpeg

ffmpeg noob here, trying to help my mother with some videos for real estate walkthroughs. I'd like to set up a simple pipeline that I can run videos through and have outputted as such:
5 second (silent) title card ->
xfade transition ->
property walk through ->
xfade transition ->
5 second (silent) title card
Considerations:
The intro / outro card will be the same content.
The input walkthrough videos will be of variable length so, if possible, a dynamic solution accounting for this would be ideal. If this requires me to script something using ffprobe, I can do that - just need to gain an understanding of the syntax and order of operations.
The video clip will come in with some audio already overlaid. I would like for the title cards to be silent, and have the video/audio clip fade in/out together.
I have gotten a sample working without the transitions:
ffmpeg -loop 1 -t 5 -i title_card.jpg \
-i walkthrough.MOV \
-f lavfi -t 0.1 -i anullsrc \
-filter_complex "[0][2][1:v][1:a][0][2]concat=n=3:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" \
-vcodec libx265 \
-crf 18 \
-vsync 2 \
output_without_transitions.mp4
I have been unable to get it to work with transitions. See below for the latest iteration:
ffmpeg -loop 1 -t 5 -r 60 -i title_card.jpg \
-r 60 -i walkthrough.MOV \
-f lavfi -t 0.1 -i anullsrc \
-filter_complex \
"[0][1:v]xfade=transition=fade:duration=0.5:offset=4.5[v01]; \
[v01][0]xfade=transition=fade:duration=0.5:offset=12.8[v]" \
-map "[v]" \
-vcodec libx265 \
-crf 18 \
-vsync 2 \
output_with_transitions.mp4
This half-works, resulting in the initial title card, fading into the video, but the second title card never occurs. Note, I also removed any references to audio, in an effort to get the transitions alone to work.
I have been beating my head against the wall on this, so help would be appreciated :)

Assuming walkthrough.MOV is 10 seconds long:
ffmpeg -loop 1 -t 5 -framerate 30 -i title_card.jpg -i walkthrough.MOV -filter_complex "[0]settb=AVTB,split[begin][end];[1:v]settb=AVTB[main];[begin][main]xfade=transition=fade:duration=1:offset=4[xf];[xf][end]xfade=transition=fade:duration=1:offset=13,format=yuv420p[v];[1:a]adelay=4s:all=1,afade=t=in:start_time=4:duration=1,afade=t=out:start_time=13:duration=1,apad=pad_dur=4[a]" -map "[v]" -map "[a]" -c:v libx265 -crf 18 -movflags +faststart output.mp4
You will need to upgrade your ffmpeg for this to work. The current release version (4.3 as of this answer) is too old, so get a build from the git master branch. See FFmpeg Download for links to builds for your OS, or see FFmpeg Wiki: Compile Guide.
title_card.jpg frame rate, width, and height must match walkthrough.MOV.
See Merging multiple video files with ffmpeg and xfade filter to see how to calculate xfade and afade offsets.
See FFmpeg Filter documentation for details on each filter.
See How to get video duration in seconds? which can help you automate this via scripting.
apad is supposed to automatically work with -shortest, but it doesn't with -filter_complex. So pad_dur is used to add the additional silence to the last title image, but whole_dur can be used instead if that is easier for you. Another method is to use anullsrc as in your question, then concatenate audio only with the concat filter, but I wanted to show adelay+apad as a viable alternative.

Related

Concatenating video clip with static image causes buffer errors

I'm trying to concatenate a 15 second clip of a video (MOVIE.mp4) with 5 seconds (no audio) of an image (IMAGE.jpg) using FFmpeg.
Something seems to be wrong with my filtergraph, although I'm unable to determine what. The command I've put together is the following:
ffmpeg \
-loop 1 -t 5 -I IMAGE.jpg \
-t 15 -I MOVIE.mp4 \
-filter_complex "[0:v]scale=480:640[1_v];anullsrc[1_a];[1:v][1:a][1_v][1_a]concat=n=2:v=1:a=1[out]" \
-map "[out]" \
-strict experimental tst_full.mp4
Unfortunately, this seems to be creating some strange results:
On my personal computer (FFmpeg 4.2.1) it correctly concatenates the movie with the static image; however, the static image lasts for an unbounded length of time. (After entering ctrl-C, the movie is still viewable, but is of an extremely long length--e.g., 35 min--depending on when I interrupt the process.)
On a remote machine where I need to do the ultimate video processing (FFmpeg 2.8.15-0ubuntu0.16.04.1), the command does not terminate, and instead, I get cascading errors of the following form:
Past duration 0.611458 too large
...
[output stream 0:0 # 0x21135a0] 100 buffers queued in output stream 0:0, something may be wrong.
...
[output stream 0:0 # 0x21135a0] 100000 buffers queued in output stream 0:0, something may be wrong.
I haven't been able to find much documentation that elucidates what these errors mean, so I don't know what's going wrong.
As Gyan pointed out, you only have to add atrim to your audio:
anullsrc,atrim=0:5[silent-audio]
Instead of scale you could use scale2ref and setsar to automatically make your image the same size and aspect ratio as the video.
ffmpeg \
-loop 1 -t 5 -i IMAGE.jpg \
-t 15 -i MOVIE.mp4 \
-filter_complex "[0:v][1:v]scale2ref[img][v];[img]setsar=1[img]; \
anullsrc,atrim=0:5[silent-audio];[v][1:a][img]
[silent-audio]concat=n=2:v=1:a=1[out]" \
-map "[out]" \
-strict experimental tst_full.mp4
Alternatively you could use anullsrc as a 3rd input:
ffmpeg \
-t 15 -i MOVIE.mp4 \
-loop 1 -t 5 -i IMAGE.jpg \
-f lavfi -t 5 -i anullsrc \
-filter_complex "[1:v][0:v]scale2ref[img][v];\
[img]setsar=1[img];[v][0:a][img][2:a]concat=n=2:v=1:a=1[out]" \
-map "[out]" \
-strict experimental tst_full.mp4

Adding background music that fades out with ffmpeg

I have a piece of video that is 30fps and simply want to add overlay faint background music starting at 10 seconds. Then I want it to fade out during the last 15 seconds. I can't find any good examples of this other than weird hacks.
ffmpeg -i main.mp4 -i outro.mp3 -t 10 \
-filter_complex "[a0][1:a]acrossfade=d=15[a];weight1:0.5" \
-map '[v]' -map '[a]' out.mp4
I get bad arguments in the filter_complex. Somethings off right there. in terms of the duration. Any help is greatly appreciated!!
Use
ffmpeg -i main.mp4 -i outro.mp3 \
-filter_complex "[0:a]volume=0,asplit[0a][0acf];[1:a]adelay=10s|10s[1a];\
[0a][1a]amix=inputs=2:duration=first:dropout_transition=0,volume=2,afifo[outro];\
[0acf]atrim=0:16,afifo[0acf];[outro][0acf]acrossfade=d=15[outro];\
[0:a][outro]amix=duration=first:weights='2 1'[a]" \
-map 0:v -c:v copy -map '[a]' out.mp4
The main audio is muted and then cloned to two copies. It is then mixed with the delayed music so that the music duration matches the main audio. It is then crossfaded with the other copy of the muted main audio. This result is then mixed with the original main audio.

Using hex colors with ffmpeg's showwaves

I've been trying to create a video with ffmpeg's showwaves filter and have cobbled together the below command which I sort of understand. I'm wondering if it is possible to set the color of the wav form using hex colors. (i.e. #F3ECDA instead of "blue")
Also, feel free to tell me if there's any unneeded garbage in the command as is. Thanks.
ffmpeg -i audio.mp3 -loop 1 -i picture.jpg -filter_complex \
"[0:a]showwaves=s=960x202:mode=cline:colors=blue[fg]; \
[1:v]scale=960:-1,crop=iw:540[bg]; \
[bg][fg]overlay=shortest=1:main_h-overlay_h-30,format=yuv420p[out]" \
-map "[out]" -map 0:a -c:v libx264 -preset fast -crf 18 -c:a libopus output.col.mkv
See https://ffmpeg.org/ffmpeg-utils.html#Color for syntax. In short, it is colors=0xRRGGBB or colors=#RRGGBB. Rest looks fine.

ffmpeg - Dynamic letters and random position watermark to video?

I am making an online course, and to avoid piracy distribution I thought to put watermarks on the videos (including personal user information) so it cannot upload to sharing websites. Now the hard part: I would move the watermark during the video, in 3/4 random positions, every 30 seconds.
It is possibile with ffmpeg?
Edit: this is an adaptation of the answer in LN's link, which will randomize the position every 30 seconds with no repeats:
ffmpeg -i input.mp4 \
-vf \
"drawtext=fontfile=font.ttf:fontsize=80:fontcolor=yellow#0.5:text='studentname': \
x=if(eq(mod(t\,30)\,0)\,rand(0\,(W-tw))\,x): \
y=if(eq(mod(t\,30)\,0)\,rand(0\,(H-th))\,y)" \
-c:v libx264 -crf 23 -c:a copy output.mp4
Older answer
You can use a command like the one below:
ffmpeg -i input.mp4 \
-vf \
"drawtext=fontfile=font.ttf:fontsize=80:fontcolor=yellow#0.5: \
text='studentname':x=200:y=350:enable='between(mod(t\,30*3),0,30)', \
drawtext=fontfile=font.ttf:fontsize=80:fontcolor=yellow#0.5: \
text='studentname':x=1000:y=600:enable='between(mod(t\,30*3),31,60)', \
drawtext=fontfile=font.ttf:fontsize=80:fontcolor=yellow#0.5: \
text='studentname':x=450:y=50:enable='between(mod(t\,30*3),61,90)'" \
-c:v libx264 -crf 23 -c:a copy output.mp4
Here, three positions are rotated with a change occurring every 30 seconds. Each x:y parameter is manually set. If you're calling the command from a shell script, you can use a random number generator and feed that into the command. There is a random function included in the drawtext filter, but it is evaluated each frame, so that will result in a pseudo ping pong game with the text.

How to scale and position watermark to scale?

I'm scaling a video and applying a watermark like so:
ffmpeg -ss 0:0:0.000 -i video.mp4 -y -an -t 0:0:10.000
-vf \"[in]scale=400:316[middle]\" -b:v 2000k -r 20
-vf 'movie=watermark.png,pad=400:316:0:0:0x00000000 [watermark];[middle] [watermark]overlay=0:0[out]'
out.flv
However, the applied watermark seems to be scaled to the original video size rather than the smaller scaled video size.
This command line worked on ffmpeg version 0.8.6.git and now behaves differently after an upgrade to version N-52381-g2288c77.
How do I get it to work again?
Update 2013-04-26:
I now have tried to use the overlay filter's X and Y parameters instead of padding without success.
Answered by ubitux on the FFmpeg IRC:
Use scale and overlay in a single -filter_complex chain, like so:
ffmpeg -y -ss 0 -t 0:0:30.0 -i 'video.mp4' -i '/watermark.png'
-filter_complex "[0:0] scale=400:225 [wm]; [wm][1:0] overlay=305:0 [out]"
-map "[out]" -b:v 896k -r 20 -an
'out.flv'
Also load the watermark via -i rather than the movie filter.

Resources