How to delay audio after a specific position with ffmpeg? - audio

I have a 10 seconds a.mp4 with two streams: Stream #0 is a video stream and Stream #1 is a audio stream.
Now, I want to delay the audio stream by 4 seconds after the time position 00:03. It is to say, in the output file, I want that: 00:00-00:03 is the original audio, 00:03-00:07 has no sound, 00:07-00:14 is the original 00:03-00:10 audio.
I've tried this:
ffmpeg -i a.mp4 -t 00:00:03 -i a.map4 -itsoffset 4 -ss 00:00:03 -i a.mp4 -map 0:v -map 1:a -map 2:a -codec copy output.mp4
But it seems that there are two audio streams in the output.mp4 and only one of them can be played once. Then I tried amix filter:
ffmpeg -i a.mp4 -t 00:00:03 -i a.mp4 -itsoffset 4 -ss 00:00:03 -i a.mp4 -filter_complex "[1:a][2:a] amix=inputs=2" -map 0:v output.mp4
But it also doesn't work. I'm new to ffmpeg so I have no idea what should I do now? Any idea for me? Very much thanks!

Use the asetpts filter to change timestamps, and aresample to (optionally) insert silence in that gap.
ffmpeg -i a.mp4 -af "asetpts='if(lt(T\,3),PTS,PTS+4/TB)',aresample=async=1" -c:v copy output.mp4
Test without aresample to see if your player is tolerant of large gaps in the audio stream.

Related

Why is adding background music to video using `ffmpeg -i input.mp4 -i music.mp3 output.mp4` not working?

I explored google and StackOverflow for how to add background music to the video and many of them suggested to use
ffmpeg -i input.mp4 -i audio.mp3 -shortest output.mp4
I have been trying to achieve this but it just does not work. When I try to add map like
ffmpeg -i "input.mp4" -i bg.mp3 -map 0:v:0 -map 1:a:0 oo.mp4
The video sound is replaced by the bg.mp3
And if I try -map 0 -map 1:a:0 or not provide map, the audio is not added at all.
How do I add the background music? I don't also get any error.
-map is a selector; select a type of stream from an input "file". To merge two audio streams, you need an audio filter:
ffmpeg -i input.mp4 -i audio.mp3 -lavfi "[0:a][1:a]amerge[out]" -map 0:v -map [out]:a -shortest output.mp4
-lavfi: Same as -filter_complex, because you have two inputs
[0:a][1:a] take audio stream from the first and second inputs
-map 0:v select the video stream from the first input without processing
-map [out]:a select the audio stream from the filtergraph (processed)
The shortest option in the amerge filter is set by default.
If you have problems, you might want to check also the amix filter, the audio codecs of your files, and the volume filter to adjust the volume of the inputs in the filtergraph.
Additional references:
https://ffmpeg.org/ffmpeg-filters.html#amerge
https://ffmpeg.org/ffmpeg-filters.html#amix
https://ffmpeg.org/ffmpeg-filters.html#volume
If the video length is longer than music you can add "-stream_loop -1" to repeat music until end of video
ffmpeg -i video_with_audio.mkv -stream_loop -1 -i background_music.mp3 -lavfi "[0:a][1:a]amerge[out]" -map 0:v -map [out]:a -shortest video_with_audio_and_background_music.mkv
If you want increase or decrease the volume, follow this command:
ffmpeg -i video_with_audio.mkv -stream_loop -1 -i background_music.mp3 -lavfi "[1:a]volume=0.2,apad[A];[0:a][A]amerge[out]" -map 0:v -map [out]:a -shortest video_with_audio_and_background_music.mkv

Concat mp4 videos and merge their audios to the final output

I have several videos and photos and need to merge them with the cross-dissolve effect. The algorithm is next:
Create videos from images and add silent audio to them (so they will also have a sound stream):
ffmpeg -y -f lavfi -i anullsrc -loop 1 -i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/ea5c93fd-d946-4742-b8f7-ea9ae4d43441.jpg -c:v libx264 -t 10 -pix_fmt yuv420p -vf scale=750:1280 /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/ea5c93fd-d946-4742-b8f7-ea9ae4d43441.mp4
Combine all the videos and audios into one using this command:
ffmpeg
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_68d437c0-f5e2-4651-b07e-91533480b6ef.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_48f3c111-610d-40c7-ac71-6ce2fbb16184.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_1593b5d8-7e16-417d-9372-2267581cd504.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_1ac7f6be-1b12-4e31-b904-1491cc9b9494.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_ea5c93fd-d946-4742-b8f7-ea9ae4d43441.mp4
-filter_complex
"[0:v]trim=start=0:end=8.032,setpts=PTS-STARTPTS[clip0];
[1:v]trim=start=2:end=13.047,setpts=PTS-STARTPTS[clip1];
[2:v]trim=start=2:end=13.558,setpts=PTS-STARTPTS[clip2];
[3:v]trim=start=2:end=13.186,setpts=PTS-STARTPTS[clip3];
[4:v]trim=start=2,setpts=PTS-STARTPTS[clip4];
[0:v]trim=start=9.032:end=10.032,setpts=PTS-STARTPTS[out0];
[1:v]trim=start=14.047:end=15.047,setpts=PTS-STARTPTS[out1];
[2:v]trim=start=14.558:end=15.558,setpts=PTS-STARTPTS[out2];
[3:v]trim=start=14.186:end=15.186,setpts=PTS-STARTPTS[out3];
[1:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in1];
[2:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in2];
[3:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in3];
[4:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in4];
[in1]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein1];
[in2]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein2];
[in3]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein3];
[in4]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein4];
[out0]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout0];
[out1]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout1];
[out2]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout2];
[out3]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout3];
[fadein1]fifo[fadein1fifo];
[fadein2]fifo[fadein2fifo];
[fadein3]fifo[fadein3fifo];
[fadein4]fifo[fadein4fifo];
[fadeout0]fifo[fadeout0fifo];
[fadeout1]fifo[fadeout1fifo];
[fadeout2]fifo[fadeout2fifo];
[fadeout3]fifo[fadeout3fifo];
[fadeout0fifo][fadein1fifo]overlay[crossfade0];
[fadeout1fifo][fadein2fifo]overlay[crossfade1];
[fadeout2fifo][fadein3fifo]overlay[crossfade2];
[fadeout3fifo][fadein4fifo]overlay[crossfade3];
[clip0][crossfade0][clip1][crossfade1][clip2][crossfade2][clip3][crossfade3][clip4]concat=n=9[output];
[0:a][1:a]acrossfade=d=10:c1=tri:c2=tri[A1];
[A1][2:a]acrossfade=d=10:c1=tri:c2=tri[A2];
[A2][3:a]acrossfade=d=10:c1=tri:c2=tri[A3];
[A3][4:a]acrossfade=d=10:c1=tri:c2=tri[audio] "
-vsync 0 -map "[output]" -map "[audio]" /tmp/media/final/some_filename_d0d2aab0-792a-4540-b2d3-e64abe98bf5c.mp4
And all works pretty well, but if I have, for example:
picture
video
video
picture
Then the sound from the second video is mapping to the first picture and sound from the third video to second video. And the third video actually goes without sound.
It seems like it's happening because the silent sound of the first picture is pretty short. An I right?
If so, how can I increase its duration?
I would much appreciate any help with this!
Assuming 5 inputs of 10 seconds each, all with audio streams*, with ffmpeg 4.3 or newer, use the xfade and acrossfade filters.
ffmpeg
-i in1.mp4
-i in2.mp4
-i in3.mp4
-i in4.mp4
-i in5.mp4
-filter_complex
" [0][1]xfade=transition=fade:duration=2:offset=8[V01];
[V01][2]xfade=transition=fade:duration=2:offset=16[V02];
[V02][3]xfade=transition=fade:duration=2:offset=24[V03];
[V03][4]xfade=transition=fade:duration=2:offset=32[video];
[0:a][1:a]acrossfade=d=2:c1=tri:c2=tri[A01];
[A01][2:a]acrossfade=d=2:c1=tri:c2=tri[A02];
[A02][3:a]acrossfade=d=2:c1=tri:c2=tri[A03];
[A03][4:a]acrossfade=d=2:c1=tri:c2=tri[audio]"
-vsync 0 -map "[video]" -map "[audio]" out.mp4
*if there's no existing audio stream, add one using the command in step 1.
If the existing audio stream of a file isn't 10 seconds long, use these filters on it before acrossfade.
[input]aresample=async=1:first_pts=0,apad,atrim=0:10[filtered]
and then use this filtered stream as input.

How to append 2 seconds of silence to an existing movie MP4 with ffmpeg?

I would like to append 2 seconds of silence to an existing video using ffmpeg.
I would like to keep the last frame displayed while the 2 seconds of video playsback not a black screen.
Thank you.
Use the tpad and apad filters:
ffmpeg -i input.mp4 -filter_complex "[0:v]tpad=stop_mode=clone:stop_duration=2[v];[0:a]apad=pad_dur=2[a]" -map "[v]" -map "[a]" output.mp4
A faster, but less compatible method is to stream copy the video and use the apad filter if your player and output container format supports dissimilar stream durations:
ffmpeg -i input.mp4 -filter_complex "[0:a]apad=pad_dur=2[a]" -map 0:v -map "[a]" -c:v copy output.mp4
If in doubt use the first command.

Singler line FFMPEG cmd to Merge Video /Audio and retain both audios

I have a project that requires merging of a video file with another audio file. The expected out put is an video file that will have both the audio from actual video and the merged audio file. The length of the output video file will be same to the size of the actual video file.
Is there a single line FFMPEG command to achieve this using copy and -map parameters ?
The video form I will be using is either flv or mp4
And the audio file format will be mp3
There can be achieved without using map also.
ffmpeg -i video.mp4 -i audio.mp3 output.mp4
In case you want the output.mp4 to stop as soon as one of the input stops (audio/video)
then use
-shortest
For example: ffmpeg -i video.mp4 -i audio.mp3 -shortest output.mp4
This will make sure that the output stops as and when any one of the inputs is completed.
Since you have asked that you want to do it with map. this is how you do it:
ffmpeg -i video.mp4 -i audio.mp3 -map 0:0 -map 1:0 -shortest output.mp4
Now, since you want to retain the audio of the video file, consider you want to merge audio.mp3 and video.mp4. These are the steps:
Extract audio from the video.mp4
ffmpeg -i video.mp4 1.mp3
Merge both audio.mp3 and 1.mp3
ffmpeg -i audio.mp3 -i 1.mp3 -filter_complex amerge -c:a libmp3lame -q:a 4 audiofinal.mp3
Remove the audio from video.mp4 (this step is not required. but just to do it properly)
ffmpeg -i video.mp4 -an videofinal.mp4
Now merge audiofinal.mp3 and videofinal.mp4
ffmpeg -i videofinal.mp4 -i audiofinal.mp3 -shortest final.mp4
note: in the latest version of ffmpeg it will only prompt you to use '-strict -2' in case it does then use this:
ffmpeg -i videofinal.mp4 -i audiofinal.mp3 -shortest -strict -2 final.mp4
hope this helps.
You can not do that using one cmd.
1. Get the audio from video file, the audio file name is a.mp3
ffmpeg.exe -i video.mp4 a.mp3
2. Merge two audio files(audio.mp3+a.mp3=audiofinal.mp3)
ffmpeg.exe -i audio.mp3 -i a.mp3 -filter_complex amerge -c:a libmp3lame -q:a 4 audiofinal.mp3
3. Merge video file and audio file(video.mp4+audiofinal.mp3=output.mp4)
ffmpeg.exe -i video.mp4 -i audiofinal.mp3 -map 0:v -map 1:a -c copy -y output.mp4
I don't think extracting the audio from the video is necessary. We can just use -filter_complex amix to merge both audios:
ffmpeg -i videowithaudio.mp4 -i audiotooverlay.mp3 -filter_complex amix -map 0:v -map 0:a -map 1:a -shortest videowithbothaudios.mp4
-filter_complex amix overlays the audio from the first input file on top of audio in the second input file.
-map 0:v video stream of the first input file.
-map 0:a audio stream of the first input file.
-map 1:a audio stream of the second input file.
-shortest the length of the output is the length of the shortest input
Use case:
add music to your background
you rendered a video, but muted some part of it, so you don't want to render it again(coz it's too long), instead you render only audio track(fast) and wanna merge it with original video.
Assuming
you have your video with you speech (or just audio track, whatever)
your music_file is not loud. Otherwise, you will not hear yourself D:
Steps:
1) Extract audio from the video
ffmpeg -i test.mp4 1.mp3
test.mp4 - your file
2) Merge both audio.mp3 and 1.mp3
ffmpeg -i audio.mp3 -i 1.mp3 -filter_complex amerge -c:a libmp3lame -q:a 4 audiofinal.mp3
audiofinal.mp3 - audio with music
3) Delete audio from original
ffmpeg -i example.mkv -c copy -an example-nosound.mkv
example-nosound.mkv - your video without audio
4) Merge with proper audio
ffmpeg -i audiofinal.mp3 -i example-nosound.wmv -c:v copy -vcodec copy final.wmv
final.wmv - your perfect video.
This is very easy with FFmpeg:
ffmpeg -i vid.mp4 -i audio.mp3 -codec:a libmp3lame -ar 44100 -ab 64k -ac 1 -q:v 1 -pix_fmt yuv420p -map 0:0 -map 1:0
First remove the sound from video if you are not able to merge video and audio by using this command:
ffmpeg -i video.mp4 -an videofinal.mp4

ffmpeg stream offset command (-itsoffset) not working

I would really appreciate if someone could give some pointers regarding the use of itsoffset with ffmpeg. I have read a number of posts on this subject, some of them explain very clearly how to re-synchronize audio and video with -itsoffset, but I haven't been able to make it work.
My avi file is encoded with ffmpeg, in two passes, using the following command for the second pass:
ffmpeg -i whole-vts_01.avs -pass 2 -y -vcodec libxvid -vtag XVID -b:v 1300K -g 240 -trellis 2 -mbd rd -flags +mv4+aic -acodec ac3 -ac 2 -ar 48000 -b:a 128k output.avi
For whatever reason, I end up with a 1 sec delay in the video (or the audio is 1 sec early). It doesn't happen too often but I see it from time to time.
Among other attempts, I have tried the following:
(1) ffmpeg -i output.avi -itsoffset 00:00:01.0 -i output.avi -vcodec copy -acodec copy -map 0:0 -map 1:1 output-resynched.avi
(2) ffmpeg -i output.avi -itsoffset 00:00:01.0 -i output.ac3 -vcodec copy -acodec copy -map 0:0 -map 1:0 output-resynched2.avi
(3) ffmpeg -itsoffset -00:00:01.00 -i output.avi output-resynched8.avi
(4) ffmpeg -i output.avi -itsoffset -1.0 -i output.avi -vcodec copy -acodec copy -map 0:1 -map 1:0 output-resynched13.avi
Here are the results:
Audio garbled and only 5m 35 s long vs. 1h 41m.
(Output.ac3 is audio component of output.avi) Video and audio
identical to original, offset didn't work
Audio did get shifted, but original encoding parameters replaced with default ones (as expected).
Audio garbled and only 9m 56s long vs. 1h 41m.
I see that many people explain, and apparently use the process described above, but it doesn't seem to be working for me. Am I missing something obvious? I would very much like to be able to use -itsoffset as it is cleaner than my workaround solution.
FWIW, here is a different, and longer way of obtaining the desired result:
First create a shifted video only file using -ss:
ffmpeg -i output.avi -ss 1.0 -vcodec copy -an oupput_videoshifted.avi
Then extract the audio:
ffmpeg -i output.avi -vn -acodec copy outputaudioonly.ac3
And finally remux both components:
ffmpeg -i output_videoshifted.avi -i output_audioonly.ac3 -vcodec copy -acodec copy -map 0:0 -map 1:0 output-resynched14.avi
The process works, is fast enough, but I would really prefer to use the one pass -itsoffset solution.
Here is what I did and it work for me
The first input setting -i and the second input is come from the same one video file.
Delay 1 second in first input video and the second input audio just make a copy
ffmpeg -y -itsoffset 00:00:01.000 -i "d:\Video1.mp4" -i "d:\Video1.mp4"
-map 0:v -map 1:a -vcodec copy -acodec copy
-f mp4 -threads 2 -v warning "Video2.mp4"
Delay 1 second in second input audio and the first input video just make a copy
ffmpeg -y -i "d:\Video1.mp4" -itsoffset 00:00:01.000 -i "d:\Video1.mp4"
-map 0:v -map 1:a -vcodec copy -acodec copy
-f mp4 -threads 2 -v warning "Video2.mp4"
The problem is located on -vcodec copy -acodec copy because the shifting will only work on keyframes. I have had the same problem.
Just don't copy (audio/)video, try the thing with -itsoffset, but use
-vcodec libxvid -vtag XVID -b:v 1300K -g 240 -trellis 2 -mbd rd -flags +mv4+aic -acodec ac3 -ac 2 -ar 48000 -b:a 128k
for re-encoding. It should work.

Resources