Fix excessive seeking with negative audio delay.
authorCarl Hetherington <cth@carlh.net>
Tue, 5 Jul 2016 08:49:00 +0000 (09:49 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 8 Jul 2016 00:50:29 +0000 (01:50 +0100)
Before this commit, an audio delay of -110ms on a test project
would result in a seek on every video and audio fetch.

This commit does two things to fix that:

1.  Don't discard audio data that arrives with a timestamp
before the last seek time.  In the case that we are fixing
we had the following sequence:

- video seeks to some frame F
- this causes audio data to arrive a little before F
- this audio data is discarded
- and audio get happens just after F
- the audio code thinks it must seek rather than just pass()ing
since it has no data

If we keep the audio data from before the seek our _decoded
will be much closer to the audio request, so a pass() is more
likely to happen.

2.  Extend the length of time that we will happily pass() for
rather than seeking when looking for audio data.  Seeking is
really bad so we can tolerate quite long times here.  The sensible
length of this value should probably be investigated as the
one in this commit is a finger-in-the-air guess.

src/lib/audio_decoder_stream.cc

index a254356ef0b790ead98aea5d7b67105bad940bf1..bdcef598d8f68c551597175c0bcd5418d01c9432 100644 (file)
@@ -68,8 +68,14 @@ AudioDecoderStream::get (Frame frame, Frame length, bool accurate)
 
        Frame const end = frame + length - 1;
 
-       if (frame < _decoded.frame || end > (_decoded.frame + length * 4)) {
-               /* Either we have no decoded data, or what we do have is a long way from what we want: seek */
+       /* If we are less than (about) 5 seconds behind the data that we want we'll
+          run through it rather than seeking.
+       */
+       Frame const slack = 5 * 48000;
+
+       if (frame < _decoded.frame || end > (_decoded.frame + _decoded.audio->frames() + slack)) {
+               /* Either we have no decoded data, all our data is after the time that we
+                  want, or what we do have is a long way from what we want: seek */
                _decoder->seek (ContentTime::from_frames (frame, _content->resampled_frame_rate()), accurate);
        }
 
@@ -162,20 +168,6 @@ AudioDecoderStream::audio (shared_ptr<const AudioBuffers> data, ContentTime time
                        padded->copy_from (data.get(), data->frames(), 0, delta_frames);
                        data = padded;
                        time -= delta;
-               } else if (delta_frames < 0) {
-                       /* This data comes before the seek time.  Throw some data away */
-                       Frame const to_discard = min (-delta_frames, static_cast<Frame> (data->frames()));
-                       Frame const to_keep = data->frames() - to_discard;
-                       if (to_keep == 0) {
-                               /* We have to throw all this data away, so keep _seek_reference and
-                                  try again next time some data arrives.
-                               */
-                               return;
-                       }
-                       shared_ptr<AudioBuffers> trimmed (new AudioBuffers (data->channels(), to_keep));
-                       trimmed->copy_from (data.get(), to_keep, to_discard, 0);
-                       data = trimmed;
-                       time += ContentTime::from_frames (to_discard, frame_rate);
                }
                _seek_reference = optional<ContentTime> ();
        }