110

In my .mp4 file the audio delay is -3840 ms. I synced it in KMplayer, and I don't want to use MKVGUI to make a .mkv file. I just need to delay the audio by 3840 ms, everything else should be left intact.
What would be the right command to accomplish this using ffmpeg?
I would appreciate your help.

Weaver
  • 2,005
  • 1
  • 10
  • 8
Alireza
  • 1,101
  • 2
  • 8
  • 3
  • 1
    How did you find the audio delay? – Zimba Feb 13 '20 at 16:19
  • 1
    `In my .mp4 file the audio delay is -3840 ms. ... I just need to delay the audio by -3840 ms,` it's a bit contradictory: between the number of the **present** delay and the number of the **needed** delay, **one and only one** of them **has to** be negative. – cipricus Mar 21 '20 at 11:35
  • 1
    You are right @cipricus, I removed the minus sign in front of the second delay amount. – Weaver Mar 22 '20 at 16:19

7 Answers7

179

If you need to delay video by 3.84 seconds, use a command like this:

ffmpeg -i "movie.mp4" -itsoffset 3.84 -i "movie.mp4" -map 1:v -map 0:a -c copy "movie-video-delayed.mp4"

If you need to delay audio by 3.84 seconds, use a command like this:

ffmpeg -i "movie.mp4" -itsoffset 3.84 -i "movie.mp4" -map 0:v -map 1:a -c copy "movie-audio-delayed.mp4"

Make sure, that your ffmpeg build is not too old, newer than 2012 will suffice.


Explanation

-itsoffset 3.84 -i "movie.mp4"

Offsets timestamps of all streams by 3.84 seconds in the input file that follows the option (movie.mp4). itsoffset is documented in the Main options section

-map 1:v -map 0:a

Takes video stream from the second (delayed) input and audio stream from the first input - both inputs may of course be the same file. map is documented in the Advanced options section

A more verbose explanation can be found here:
http://alien.slackbook.org/blog/fixing-audio-sync-with-ffmpeg/

Weaver
  • 2,005
  • 1
  • 10
  • 8
  • 3
    How do you choose one specific audio track instead of delaying all audio tracks? – Freedo Oct 20 '17 at 06:41
  • 1
    Using the capabilities of [map option](https://trac.ffmpeg.org/wiki/Map). You first need to find the index of the desired audio stream in the input file using any of these commands: `ffprobe.exe "input_file.mp4"` or `ffmpeg.exe -i "input_file.mp4"` Let's suppose that the index of the audio stream to be delayed is 2 (i.e. the third stream) and that the delayed input is the second one (as in my example). To delay only the third stream, take all other streams from the first input and only the one audio stream from the second (delayed) input: `-map 0:0 -map 0:1 -map 1:2` – Weaver Oct 22 '17 at 15:03
  • that's kind not what I meant. In this case i still have to call ffmpeg and parse the results to do find the indexes. Is there a equivalent to say -map eng – Freedo Nov 11 '17 at 06:53
  • Well, @Freedo , as you have been already advised in https://superuser.com/questions/639402/convert-specific-video-and-audio-track-only-with-ffmpeg#comment1855076_639430 , what you suggest is in fact possible by [specifying streams](http://ffmpeg.org/ffmpeg.html#Stream-specifiers) using metadata values, e.g.: `-map 1:m:language:eng` However, bear in mind, that it will select all streams satisfying the criterium, possibly including multiple audio and/or subtitle streams. You can find more information in https://stackoverflow.com/questions/46769419/ffmpeg-choosing-audio-streams-by-language – Weaver Nov 11 '17 at 14:42
  • 2
    AFAIK `-c copy` can be used instead of `-vcodec copy -acodec copy`, and `itsoffset` only affects video, so maybe this would work the same?: `ffmpeg -i "movie.mp4" -itsoffset 3.84 -c copy "movie-video-delayed.mp4"` and to delay the audio instead simply add a negative sign to the duration: `-3.84`. – miyalys Mar 16 '18 at 14:35
  • 1
    @miyalys, you are right, I have shortened the codec options in the answer. However I am not sure whether the `-itsoffset` option affecting only video is a bug or a feature. If it is a bug, it might get fixed in a future version. – Weaver Mar 18 '18 at 13:33
  • Why does -i have to be specified two times, in the "delay audio" example? – shevy Mar 29 '18 at 10:32
  • 1
    Because we need a non-delayed input video stream and another delayed input audio stream, @shevy – Weaver Apr 07 '18 at 19:12
  • delay video command is not working.. delay audio command is working. – MathankumarK Mar 05 '19 at 12:55
  • shouldn't there be a minus (`-`) sign in front of those numbers in order to achieve the declared purpose of delaying the audio? as it is, the second command makes the audio come even sooner than before. – cipricus Mar 21 '20 at 11:58
  • 1
    Definitely not @cipricus. Both commands work according to their respective descriptions, I tested them on ffmpeg ver. 4.0.2. – Weaver Mar 22 '20 at 16:11
  • 1
    Perfect answer, should be checked as such. – Nicholi Apr 08 '20 at 19:42
  • 2
    @miyalys Doing that doesn't work for me: "Option itsoffset (set the input ts offset) cannot be applied to output url delayed.mp4 -- you are trying to apply an input option to an output file or vice versa. Move this option before the file it belongs to. Error parsing options for output file delayed.mp4. Error opening output files: Invalid argument" – Geremia Dec 01 '20 at 22:52
  • 1
    @Geremia So try `ffmpeg -itsoffset 3.84 -i "movie.mp4" -c copy "movie-video-delayed.mp4"`? (Ie. placing the `itsoffset` argument *before* the input file argument.) – miyalys Dec 02 '20 at 01:52
  • @miyalys That produces a video with no audio delay. – Geremia Dec 02 '20 at 03:31
  • @Geremia I'm not sure, but I'm curious if you have multiple input files? If so it should be before the one with the audio that's supposed to be delayed. – miyalys Dec 07 '20 at 04:37
  • @miyalys No, I have one input file. – Geremia Dec 07 '20 at 18:33
  • @Geremia Okay, looking at the manpage now I'm not so sure it only affects video anymore (seemingly it used to?), so maybe doing what Weaver is doing, by specifying the input file twice and then using `map`, might be needed at this point. – miyalys Dec 09 '20 at 03:20
  • @miyalys Yes, I think so. – Geremia Dec 09 '20 at 17:05
  • hi , how could we delay audio track from a specific time point, e.g. I would like to delay 2 seconds from time 00:51:21 onward? – Franva Jan 03 '21 at 00:47
  • Is there a reason the input is included twice? – Hashim Aziz Jun 27 '21 at 17:49
  • 1
    Yes, as the second input is delayed; see the explanation above, @HashimAziz – Weaver Jun 29 '21 at 18:29
  • @Weaver did you confirm if `itsoffset` only effects on video or audio too? – Muhammad Mar 21 '22 at 19:35
  • Is it important for `itsoffset` to transcode video? – Muhammad Apr 23 '22 at 12:47
  • When I try this command, the delay gotten is different from the delay I set. For example, if I set 4, I get a delay of 0.191 s; if I set 8, I get a delay of 0.383 s; if I set -0.5, I get 0; if I set -1, I get -0.022. – Raphael Sep 24 '22 at 17:24
  • @Muhammad according to ffmpeg wiki, itsoffset should effect all streams in the input file: https://trac.ffmpeg.org/wiki/UnderstandingItsoffset – Weaver Oct 02 '22 at 18:58
3

Make first silence audio:

ffmpeg -f lavfi -i anullsrc=channel_layout=5.1:sample_rate=48000 -t 3 silence_3_sec.mp3

Then concat files:

ffmpeg -i "concat:silence_3_sec.mp3|input.mp3" -acodec copy out.mp3
Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
Ivan Malyshev
  • 374
  • 3
  • 8
3

As stated in the currently top voted answer, you can use ffmpeg's -itsoffset. According to the ffmpeg wiki, if you do not want to offset all streams, all you have to do is to specify the input file twice. Once for the streams you want to keep as they are and once again for the streams you want to offset. Then you simply map the streams you want to the final output file. This way there is no need to extract streams and them remux them together later.

For instance (copied from the wiki), if you want all audio streams to be offset by 5 seconds

ffmpeg -i video.mp4 -itsoffset 5 -i video.mp4 -map 0:v -map 1:a out.mp4
  • -map 0:v will copy the video from the first input file (video.mp4)
  • -map 0:a will copy the audio from the second input file. Which happens to be video.mp4 too, but delayed 5 seconds by the use of -itsoffset right before the corresponding -i option
Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
user1593842
  • 131
  • 2
  • 1
    I think the second bullet should say "`-map 1:a` will copy the audio ..." but I'm not confident enough of that to make the edit. – Amanda Mar 20 '23 at 01:04
1

I extracted audio with Audacity, then cut some silence (equal to delay) from end of video, and added to beginning of audio.

After doing any other adjustments to audio eg. normalization, I exported audio, and replaced audio in original via ffmpeg:

ffmpeg-i "in.mp4" -i "synced.m4a" -vcodec copy -acodec copy -map 0:0 -map 1:0 out.mp4
Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
Zimba
  • 1,051
  • 11
  • 15
  • 1
    For future reference, Audacity has a Generate > Silence menu item that will allow you to insert silence at the cursor down to the millisecond. – Eric Apr 16 '21 at 20:51
1

A method that works without ffmpeg having to read and process the file twice is to use a so-called complex filter that manipulates the presentation timestamps of either the video or audio tracks.

The benefit of this method is that it works for streams (which can be read from only once), and not just for files.

For example -filter_complex "asetpts=PTS-0.3/TB" subtracts 300ms from the presentation time stamps of audio packets.

Peregrino69
  • 4,526
  • 2
  • 22
  • 30
  • Welcome to SuperUser, and thanks for your contribution. It looks technically simpler, more versatile and is something not previously proposed, so very good addition :-) What'd make it better is firstly putting in the entire `ffmpeg` command as you'd recommend, and maybe a link to `ffmpeg` documentation that explains the option. – Peregrino69 Mar 01 '23 at 20:13
0

Newer versions of ffmpeg require the -map options to be located just before the output options. For example:

ffmpeg.exe %InputOpts% -i %1 -itsoffset 1.00 -i %1  %CodecsOpts% %MapOpts% %OutputOpts%
Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
0

Having had no luck with the earlier suggestions, I finally got it to work. My input was mp4 made of mpeg-4 avc with mp3 audio. The critical information points that were missing for me, is that -itsoffset with codec copy doesn't update the streams. It only applies timestamp offset information to the output stream. And this: "For MP4s, ffmpeg's muxer writes an edit list for delaying a stream. Players which honor it, will play as expected e.g. Potplayer does, WMP does not.". That came from https://trac.ffmpeg.org/ticket/1349

So I output to mkv instead.

I'd seen comments that -itsofset works only on video not audio, and that it doesn't work on avi, but also saw both those positions contradicted. YMMV.

To simplify I split the input into separate video and audio files to avoid the -map complexity. I expect this method will also work with map. My audio was late and needed to be brought forward.

ffmpeg -itsoffset 0.4 -i inputVid.mp4 -itsoffset 0 -i inputAudio.mp3 -vcodec copy -acodec copy fixed.mkv