Opened 10 years ago

Closed 10 years ago

#1035 closed defect (fixed)

ffplay: after changing audio stream, audio video become out of sync

Reported by: REN Lifeng Owned by: Marton Balint
Priority: minor Component: ffplay
Version: git-master Keywords:
Cc: Blocked By:
Blocking: Reproduced by developer: yes
Analyzed by developer: no


steps to reproduce:

  1. play a video containing 2 audio stream with ffplay
  2. while playing it, press a to toggle audio stream
  3. now audio and video become out of sync

Change History (12)

comment:1 by REN Lifeng, 10 years ago

the reported symptom will not show after patching ffplay.c as such.

diff --git a/ffplay.c b/ffplay.c
index 93097e1..ac31ce6 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -2725,6 +2725,7 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
     AVFormatContext *ic = is->ic;
     int start_index, stream_index;
     AVStream *st;
+    double pos;
     if (codec_type == AVMEDIA_TYPE_VIDEO)
         start_index = is->video_stream;
@@ -2765,8 +2766,10 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
+    pos = get_master_clock(is);
     stream_component_close(is, start_index);
     stream_component_open(is, stream_index);
+    stream_seek(is, (int64_t)(pos * AV_TIME_BASE), 0, 0);

comment:2 by Carl Eugen Hoyos, 10 years ago

Please post patches on ffmpeg-devel, they get more attention there.

comment:3 by REN Lifeng, 10 years ago

Let's forget the patch, it is does not work now.

But the symptom remains. After changing audio stream, video becomes out of sync. The user have to seek backward then forward by pressing arrow key in order to sync the audio and video streams.

comment:4 by Marton Balint, 10 years ago

FFplay should handle this unless the A-V difference becomes greater than 10 seconds, which may happen for some files.

Can you reproduce the problem if you change AV_NOSYNC_THRESHOLD to 60 seconds? If you can, then please provide a sample file.

comment:5 by REN Lifeng, 10 years ago

I confirm that after setting AV_NOSYNC_THRESHOLD 60.0, the problem goes away.

But I don't understand why 10 seconds is not big enough. In my case, the sample is a Karaoke MTV. All audio streams in it is strictly sync-ed to the video stream. A-V will be sync-ed no matter which audio stream is selected by command line such as:

$ ffplay -ast 1 sample.mpg
$ ffpaly -ast 2 sample.mpg

but A-V will not be sync-ed anymore after pressing 'a' during the playback process.

I put the sample here.

Last edited 10 years ago by REN Lifeng (previous) (diff)

comment:6 by Carl Eugen Hoyos, 10 years ago

Reproduced by developer: set
Status: newopen

For the specific sample it is sufficient to set AV_NOSYNC_THRESHOLD to 11, we should probably commit this as a work-around.

The bigger problem that I see with the sample is that shen changing audio, ffplay automatically skips 10 seconds instead of continuing to play from the current position.

comment:7 by REN Lifeng, 10 years ago


As a user, I do not expect ffplay make the decision on my behalf to skip 10s. What I tell it is just to change to another audio stream. But the work-around is acceptable if fixing the problem requires big change of the code.

comment:8 by reimar, 10 years ago

I don't think it skips it by intention, it is just that there is probably a lot of audio data already demuxed and buffered for the enabled and in-use stream.
When switching to a different audio stream, demuxing of that will only be enabled at that point.
ffplay has now the two options of either continuing to play the old stream until it gets data from the new one (annoying and complex to implement) or just to drop the audio for the old one and start playing the new one even though the first data for that is several seconds in the future.

comment:9 by Marton Balint, 10 years ago

Yes, exactly like reimar described. Probably the best way is to reduce the amount of queued audio frames, and use a similar logic to what is already used for the video queue:

diff --git a/ffplay.c b/ffplay.c
index dc29394..ad4892c 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -2605,7 +2604,7 @@ static int read_thread(void *arg)
         /* if the queue are full, no need to read more */
         if (   is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
-            || (   (is->audioq   .size  > MIN_AUDIOQ_SIZE || is->audio_stream < 0)
+            || (   (is->audioq   .nb_packets > MIN_FRAMES || is->audio_stream < 0)
                 && (is->videoq   .nb_packets > MIN_FRAMES || is->video_stream < 0)
                 && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0))) {
             /* wait 10 ms */

comment:10 by Marton Balint, 10 years ago

Owner: set to Marton Balint

comment:11 by REN Lifeng, 10 years ago

Cus's patch works for me. Thanks!

comment:12 by Carl Eugen Hoyos, 10 years ago

Resolution: fixed
Status: openclosed

Fixed by Marton.

Note: See TracTickets for help on using tickets.