[prev in list] [next in list] [prev in thread] [next in thread] 

List:       mplayer-dev-eng
Subject:    Re: [MPlayer-dev-eng] Strange behavior with audio delayed video files
From:       Dan Oscarsson <Dan.Oscarsson () tieto ! com>
Date:       2014-03-02 17:01:58
Message-ID: 1393779718.2360.3.camel () luna ! malmo ! kicore ! net
[Download RAW message or body]

fre 2014-02-21 klockan 11:48 +0100 skrev Ingo Brückl:

> 
> > In my patched mplayer I have used this for many years without problem.
> 
> Well then, please share your patch with me.

It is attached. Though it is the 6th in order of my set of 12 patches
and about 9 months old as I had no need to update it as mplayer changes
so slowly. In also includes my code to sync audio and video after a
seek. It depends on some parts in my other patches but you should see
how it works.

   Dan

["seek-sync.diff" (seek-sync.diff)]

--- mplayer.c.org	2013-05-05 15:50:08.751104736 +0200
+++ mplayer.c	2013-05-05 15:50:24.656103355 +0200
@@ -1171,6 +1171,116 @@
 }
 
 
+static double written_audio_pts(sh_audio_t *sh_audio, demux_stream_t *d_audio);
+static int fill_audio_out_buffers(int fill_only);
+static double update_video(int *blit_frame);
+
+static void sync_audio_video(int *blit_frame,double *frame_time)
+{
+    // after a seek the audio and video are normally not fully in sync
+    // resulting in a visible/audiable resync
+    // this code does the resync so that its starts with audio and video in sync
+    double apts;
+    int    sample_size = af_fmt2bits(ao_data.format)/8*ao_data.channels;
+    int    delete_bytes;
+    int    got_audio;
+    int    audio_increased;  // some audio decoders failes and return no decoded \
data +    int    tried_once = 0;
+    int    tries;
+
+
+    // decode some audio but do not play it, to get starting audio pts
+    // try several times, after seek some streams fail first decode try, but not \
next +    for (got_audio = 1, audio_increased = 0, tries = 0; tries < 3 && got_audio \
&& !audio_increased; tries++) { +        audio_increased = \
mpctx->sh_audio->a_out_buffer_len; +        got_audio       = \
fill_audio_out_buffers(1); +        audio_increased = \
mpctx->sh_audio->a_out_buffer_len-audio_increased; +    }
+    apts = written_audio_pts(mpctx->sh_audio, mpctx->d_audio)-audio_delay;
+    apts -= mpctx->audio_out->get_delay(); // compensating for latency in audio out \
(needed for pulse) +    mpctx->sh_audio->resyncing = 1; // restart resyncing as it is \
reset by written_audio_pts +    if (got_audio && audio_increased && \
mpctx->sh_video->pts == MP_NOPTS_VALUE) { +        // no valid pts from video - move \
forward till we get valid pts +        while (mpctx->sh_video->pts == MP_NOPTS_VALUE) \
{ +            double delay = mpctx->delay;
+            *frame_time  = update_video(blit_frame);
+            mpctx->delay = delay;
+            if (*frame_time < 0) break;
+        }
+    }
+    if (start_audio_pts == MP_NOPTS_VALUE) {
+        start_audio_pts = apts;  // this includes audio_delay correction which could \
be manipulated by user at start +    } else if (mpctx->sh_video->pts >= \
start_audio_pts) { +        if (got_audio && audio_increased && mpctx->sh_video->pts \
< apts) { +            // video is behind and audio is working, move it forward
+            while (mpctx->sh_video->pts < apts) {
+                double delay = mpctx->delay;
+                *frame_time  = update_video(blit_frame);
+                mpctx->delay = delay;
+                if (*frame_time < 0) break;
+            }
+        }
+        delete_bytes = (mpctx->sh_video->pts-apts)*ao_data.samplerate*sample_size /
+                       (synced_playback_speed*playback_speed);
+        delete_bytes /= sample_size;  // align to sample_size
+        delete_bytes *= sample_size;  // align to sample_size
+
+        // move audio forward until it is in sync with video
+        while (got_audio && audio_increased && *frame_time >= 0 && delete_bytes > 0) \
{ +            if (delete_bytes > mpctx->sh_audio->a_out_buffer_len) {
+                int ck = mpctx->sh_audio->a_out_buffer_len/sample_size;
+                if (ck*sample_size != mpctx->sh_audio->a_out_buffer_len) {
+                    // check so audio is aligned on samples
+                    mp_msg(MSGT_CPLAYER, MSGL_WARN, "Failed to align audio data on \
sample border\n"); +                    break;
+                } else {
+                    audio_speed_o * sd;
+
+                    // empty decoded audio buffer and data for it
+                    mpctx->sh_audio->a_out_buffer_len = 0;
+                    while (a_out_sdata) {
+                        sd = a_out_sdata->next;
+                        free(a_out_sdata);
+                        a_out_sdata = sd;
+                    }
+                    // decode some more audio
+                    // have to try sevel times, some demuxers fail later on in the \
stream too +                    // for example, lavf sometimes failes when demuxing \
latm in mpeg-ts from DVB-t +                    for (got_audio = 1, audio_increased = \
0, tries = 0; tries < 3 && got_audio && !audio_increased; tries++) { +                \
audio_increased = mpctx->sh_audio->a_out_buffer_len; +                        \
got_audio       = fill_audio_out_buffers(1); +                        audio_increased \
= mpctx->sh_audio->a_out_buffer_len-audio_increased; +                    }
+                    apts = written_audio_pts(mpctx->sh_audio, \
mpctx->d_audio)-audio_delay; +                    apts -= \
mpctx->audio_out->get_delay(); // compensating for latency in audio out (needed for \
pulse) +                    mpctx->sh_audio->resyncing = 1; // restart resyncing as \
it is reset by written_audio_pts +                    if (!tried_once && \
mpctx->sh_video->pts < apts) { +                        // audio pts jumped, may \
happen after seek for some demuxers/decoders +                        // move video \
forward +                        while (mpctx->sh_video->pts < apts) {
+                            double delay = mpctx->delay;
+                            *frame_time  = update_video(blit_frame);
+                            mpctx->delay = delay;
+                            if (*frame_time < 0) break;
+                        }
+                        tried_once = 1;
+                    }
+                    delete_bytes = \
(mpctx->sh_video->pts-apts)*ao_data.samplerate*sample_size / +                        \
(synced_playback_speed*playback_speed); +                    delete_bytes /= \
sample_size;   // align to sample_size +                    delete_bytes *= \
sample_size;   // align to sample_size +                }
+            } else {
+                mpctx->sh_audio->a_out_buffer_len -= delete_bytes;
+                memmove(mpctx->sh_audio->a_out_buffer, \
&mpctx->sh_audio->a_out_buffer[delete_bytes], +                        \
mpctx->sh_audio->a_out_buffer_len); +                a_out_sdata->len -= \
delete_bytes; +                delete_bytes = 0;
+            }
+        }
+    }
+}
+
 /*  The next generation A-V-sync handling  (end) */
 
 /* This header requires all the global variable declarations. */
@@ -3027,7 +3137,7 @@
     }
 }
 
-static int fill_audio_out_buffers(void)
+static int fill_audio_out_buffers(int fill_only)
 {
     unsigned int t;
     double tt;
@@ -3055,6 +3165,10 @@
         // in get_space()
         ao_data.pts    = ((mpctx->sh_video ? mpctx->sh_video->timer : 0) + \
mpctx->delay) * 90000.0;  bytes_to_write = mpctx->audio_out->get_space();
+        if (fill_only) {
+            if (bytes_to_write < ao_data.outburst) bytes_to_write = \
ao_data.outburst; +            break;
+        }
         if (mpctx->sh_video || bytes_to_write >= ao_data.outburst)
             break;
         if (timeout++ > 10) {
@@ -3112,6 +3226,8 @@
         }
         a_out_sdata->len += sh_audio->a_out_buffer_len-old_a_out_len;
 
+        if (fill_only) break;
+
         // play audio:
         current_module = "play_audio";
 
@@ -3679,6 +3795,7 @@
         return -1;
 
     mpctx->startup_decode_retry = DEFAULT_STARTUP_DECODE_RETRY;
+    if (start_audio_pts == MP_NOPTS_VALUE) start_audio_pts = 0; // seeking before \
starting play turns this off  if (mpctx->sh_video) {
         current_module = "seek_video_reset";
         if (vo_config_count)
@@ -4690,6 +4807,7 @@
         // display vsync rate matching
         init_vsync_handling();
         displaysynced_speed   = 0;
+        start_audio_pts       = MP_NOPTS_VALUE;
         synced_playback_speed = 1.0;
 
         if (play_n_frames == 0) {
@@ -4730,7 +4848,7 @@
             if (!mpctx->sh_video && mpctx->sh_audio) {
                 // handle audio-only case:
                 double a_pos = 0;
-                if (!fill_audio_out_buffers())
+                if (!fill_audio_out_buffers(0))
                     // at eof, all audio at least written to ao
                     if (!mpctx->sh_video)
                         mpctx->eof = PT_NEXT_ENTRY;
@@ -4758,6 +4876,7 @@
                 unsigned int work_start,work_end;
                 unsigned int last_decode_time     = 0;
                 unsigned int previous_decode_time = 0;
+                int sync_av = mpctx->startup_decode_retry > 0 && mpctx->sh_audio;
 
                 work_start = GetTimer();
                 vo_pts = mpctx->sh_video->timer * 90000.0;
@@ -4774,6 +4893,9 @@
                         mpctx->startup_decode_retry--;
                     }
                     mpctx->startup_decode_retry = 0;
+                    if (tng && sync_av) {
+                        sync_audio_video(&blit_frame,&frame_time);
+                    }
                     mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", \
frame_time);  if (mpctx->sh_video->vf_initialized < 0) {
                         mp_msg(MSGT_CPLAYER, MSGL_FATAL, \
MSGTR_NotInitializeVOPorVO); @@ -4804,8 +4926,8 @@
 
 /*========================== PLAY AUDIO ============================*/
 
-                if (mpctx->sh_audio)
-                    if (!fill_audio_out_buffers())
+                if (mpctx->sh_audio && (!tng || start_audio_pts < \
mpctx->sh_video->pts)) +                    if (!fill_audio_out_buffers(0))
                         // at eof, all audio at least written to ao
                         if (!mpctx->sh_video)
                             mpctx->eof = PT_NEXT_ENTRY;



_______________________________________________
MPlayer-dev-eng mailing list
MPlayer-dev-eng@mplayerhq.hu
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic