Tag Archives: audio

Fixing audio sync with ffmpeg

The ffmpeg developers and their libav antipodes are engaged in a healthy battle. Ever since there was a fall-out and the ffmpeg developer community split in two (forking ffmpeg into “libav”), ffmpeg itself has seen many releases which tend to incorporate the good stuff from the other team as well as their own advancements.

Last in series is ffmpeg-0.9 for which I built Slackware packages (if you want to be able to create mp3 or aac sound, get the packages with MP3 and AAC encoding enabled instead.

The package will come in handy if you want to try what I am going to describe next.

Re-sync your movie’s audio.

You probably have seen the issue yourself too: for instance, I have a file “original.avi” which has an audio track (or “stream“) which is slightly out of sync with the video… just enough to annoy the hell out of me. I need to delay the audio by 0.2 seconds to make the movie playback in sync. Luckily, ffmpeg can fix this for you very easily.

Let’s analyze the available streams in the original video (remember, UNIX starts counting at zero):

$ ffmpeg -i original.avi

Input #0, avi, from ‘original.avi’:

Stream #0.0: Video: mpeg4, yuv420p, 672×272 [PAR 1:1 DAR 42:17], 23.98 fps, 23.98 tbr, 23.98 tbn, 23.98 tbc
Stream #0.1: Audio: mp3, 48000 Hz, stereo, s16, 128 kb/s

You see that ffmpeg reports a “stream #0.0” which is the first stream in the first input file (right now we have only one input file but that will change later on) – the video. The second stream, called “stream #0.1“, is the audio track.

What I need is to give ffmpeg the video and audio as separate inputs, instruct it to delay our audio and re-assemble the two streams into one resultant movie file. The parameters which define two inputs where the second input will be delayed for N seconds, goes like this:

$ ffmpeg -i inputfile1 -itsoffset N -i inputfile2

However, we do not have a separate audio and video tracks, we just have the single original AVI file. Luckily, the “inputfile1” and “inputfile2” can be the same file! We just need to find a way to tell ffmpeg what stream to use from which input. Look at how ffmpeg reports the content of input files if you list the same file twice:

$ ffmpeg -i original.avi -i original.avi

Input #0, avi, from ‘original.avi’:

Stream #0.0: Video: mpeg4, yuv420p, 672×272 [PAR 1:1 DAR 42:17], 23.98 fps, 23.98 tbr, 23.98 tbn, 23.98 tbc
Stream #0.1: Audio: mp3, 48000 Hz, stereo, s16, 128 kb/s

Input #1, avi, from ‘original.avi’:

Stream #1.0: Video: mpeg4, yuv420p, 672×272 [PAR 1:1 DAR 42:17], 23.98 fps, 23.98 tbr, 23.98 tbn, 23.98 tbc
Stream #1.1: Audio: mp3, 48000 Hz, stereo, s16, 128 kb/s

You see that the different streams in multiple input files are all numbered uniquely. We will need this defining quality. I colored the numbers with red & purple – these colors will show up in my example commands below.

Our remaining issue is that ffmpeg must be told that it has to use only the video stream of the first inputfile, and only the audio stream of the second inputfile. Ffmpeg will then have to do its magic and finally re-assemble the two streams into a resulting movie file. That resulting AVI file also expects video as the first stream, and audio as the second stream, just like our original AVI is laid out. Movie players will get confused otherwise.

Ffmpeg has the “map” parameter to specify this. I have looked long and hard at this parameter and its use… it is not easy for me to follow the logic. A bit like the git version control system, which does not fit into my brain conceptually, either. But perhaps I can finally explain it properly, to myself as well as to you, the reader.

Actually, we need two “map” parameters, one to map the input to the output video and another to map the input to the output audio. Map parameters are specified in the order the streams are going to be added to the output file. Remember, we want to delay the audio, so inherently the audio track must be taken from the second inputfile.

In the example below, the first “-map 0:0” parameter specifies how to create the first stream in the output. We need the first stream in the output to be video. The “0:0” value means “first_inputfile:first_stream“.

The second “-map 1:1” parameter specifies where ffmpeg should find the audio (which is going to be the second stream in the output). The value “1:1” specifies “second_inputfile:seccond_stream.

$ ffmpeg -i original.avi -itsoffset 0.2 -i original.avi -map 0:0 -map 1:1

There is one more thing (even though it looks like ffmpeg is smart enough to do this without explicitly telling so). I do not want any re-encoding of the audio or video to happen, so I instruct ffmpeg to “copy” the audio and video stream without intermediate decoding and re-encoding. The “‘-acodec copy” and “-vcodec copy” parameters take care of this.

We now have the information to write a ffmpeg commandline which takes audio and video streams from the same file and re-assembles the movie with the audio stream delayed by 0.2 seconds. The resulting synchronized movie is called “synced.avi” and the conversion takes seconds, rather than minutes:

$ ffmpeg -i original.avi -itsoffset 0.2 -i original.avi -map 0:0 -map 1:1  -acodec copy -vcodec copy synced.avi

Cheers, Eric

Upgrading the eeepc to 2.6.33

Last week I finally took the time to upgrade my Asus Eeepc 1000H to the latest Slackware-current.

I had two issues after the upgrade, which were related to the new 2.6.33 kernel.

  1. My WPA-secured wireless connections would not last longer than a few seconds. After days of despair, I finally found out that the 2.6.33 kernel has a new driver for my wireless card, the “rt2800pci”. This driver is being loaded by default now. Slackware’s kernel also ships the “rt2860sta” driver which is part of the Linux “staging area” i.e. not considered fully stable. This is the driver which would be used with Slackware kernels before 2.6.33. It is in fact a very stable driver which never failed me before.
    By coincidence I saw that both modules were mentioned as supporting the Eeepc’s wireless card in the output of “lspci -v”. After I added the line “blacklist rt2800pci” to the file “/etc/modprobe.d/blacklist.conf” and rebooted the Eeepc, I had fully functional and stable wireless connectivity again, now using the “rt2860sta” driver!
  2. My sound was gone, or at least working at a very very low volume… I could hear the KDE logout sound if I put my ear to the keyboard but that was about it. Getting normal sound output levels through my headphones was no problem at all, however.
    The ALSA troubleshooting guide for HDA Intel audio hardware pointed me in the right direction: not getting sound through the built-in speakers while the headphone output works well is quite common, and often caused by not raising the correct channel’s volume.
    It turned out that after the upgrade to the 2.6.33 kernel, I need to set the “speaker” channel’s output level to anything non-zero or else there would be no sound…

I have to mention one other piece of strangeness I experienced on my netbook:

It is an issue not related to Slackware-current but rather to my use of the new “netbook” interface of KDE 4.4’s plasma workspace manager. I toyed with the netbook interface a bit, because it lets you use the small screen more efficiently – by removing unnecessary stuff like window elements and task bars. One typical treat is that every application window in the plasma-netbook workspace runs full-screen exclusively – there is no “minimize” button but instead you have to use the application switcher in order to access other running applications’ windows. Unfortunately, when I switched back to the “normal” plasma workspace, the “minimize” buttons did not re-appear in the title bar!
I had to manually re-add this button through “system settings > appearance > windows > buttons” and drag the “minimize” button into the titlebar preview.

Just so you know.

Eric