Various attempted fixes to audio sync.
authorCarl Hetherington <cth@carlh.net>
Fri, 3 Jan 2014 23:18:47 +0000 (23:18 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 3 Jan 2014 23:18:47 +0000 (23:18 +0000)
src/lib/audio_decoder.cc
src/lib/audio_decoder.h
src/lib/decoder.cc
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/player.cc
src/lib/sndfile_decoder.cc
src/lib/sndfile_decoder.h

index adabd5d9941afaad9d3b15d804d4a108876d0dab..8d3b0e1288ea5b53627a9cfb82619b0ccc125c7e 100644 (file)
@@ -37,7 +37,6 @@ using boost::shared_ptr;
 AudioDecoder::AudioDecoder (shared_ptr<const Film> film, shared_ptr<const AudioContent> content)
        : Decoder (film)
        , _audio_content (content)
-       , _audio_position (0)
 {
        if (content->output_audio_frame_rate() != content->content_audio_frame_rate() && content->audio_channels ()) {
                _resampler.reset (new Resampler (content->content_audio_frame_rate(), content->output_audio_frame_rate(), content->audio_channels ()));
@@ -47,16 +46,26 @@ AudioDecoder::AudioDecoder (shared_ptr<const Film> film, shared_ptr<const AudioC
 /** Audio timestamping is made hard by many factors, but the final nail in the coffin is resampling.
  *  We have to assume that we are feeding continuous data into the resampler, and so we get continuous
  *  data out.  Hence we do the timestamping here, post-resampler, just by counting samples.
+ *
+ *  The time is passed in here so that after a seek we can set up our _audio_position.  The
+ *  time is ignored once this has been done.
  */
 void
-AudioDecoder::audio (shared_ptr<const AudioBuffers> data)
+AudioDecoder::audio (shared_ptr<const AudioBuffers> data, ContentTime time)
 {
        if (_resampler) {
                data = _resampler->run (data);
        }
 
-       _pending.push_back (shared_ptr<DecodedAudio> (new DecodedAudio (data, _audio_position)));
-       _audio_position += data->frames ();
+       if (!_audio_position) {
+               shared_ptr<const Film> film = _film.lock ();
+               assert (film);
+               FrameRateChange frc = film->active_frame_rate_change (_audio_content->position ());
+               _audio_position = (double (time) / frc.speed_up) * film->audio_frame_rate() / TIME_HZ;
+       }
+
+       _pending.push_back (shared_ptr<DecodedAudio> (new DecodedAudio (data, _audio_position.get ())));
+       _audio_position = _audio_position.get() + data->frames ();
 }
 
 void
@@ -68,17 +77,13 @@ AudioDecoder::flush ()
 
        shared_ptr<const AudioBuffers> b = _resampler->flush ();
        if (b) {
-               _pending.push_back (shared_ptr<DecodedAudio> (new DecodedAudio (b, _audio_position)));
-               _audio_position += b->frames ();
+               _pending.push_back (shared_ptr<DecodedAudio> (new DecodedAudio (b, _audio_position.get ())));
+               _audio_position = _audio_position.get() + b->frames ();
        }
 }
 
 void
-AudioDecoder::seek (ContentTime t, bool)
+AudioDecoder::seek (ContentTime, bool)
 {
-       shared_ptr<const Film> film = _film.lock ();
-       assert (film);
-       
-       FrameRateChange frc = film->active_frame_rate_change (_audio_content->position ());
-       _audio_position = ((t + first_audio()) / frc.speed_up) * film->audio_frame_rate() / TIME_HZ;
+       _audio_position.reset ();
 }
index 12f8505f64814244f4a5d1a0cba530df3e648f22..bb3aafccd6a8982824f890fa05907ea8def66b96 100644 (file)
@@ -48,13 +48,12 @@ public:
        
 protected:
 
-       virtual ContentTime first_audio () const = 0;
-       void audio (boost::shared_ptr<const AudioBuffers>);
+       void audio (boost::shared_ptr<const AudioBuffers>, ContentTime);
        void flush ();
 
        boost::shared_ptr<const AudioContent> _audio_content;
        boost::shared_ptr<Resampler> _resampler;
-       AudioFrame _audio_position;
+       boost::optional<AudioFrame> _audio_position;
 };
 
 #endif
index 30244b40b5eae2591bbde3301e4ddb5e3f033f20..53a0c31e140d6ceab0a3d2f222fe419bda88237b 100644 (file)
@@ -40,6 +40,14 @@ Decoder::Decoder (shared_ptr<const Film> f)
 
 }
 
+struct DecodedSorter
+{
+       bool operator() (shared_ptr<Decoded> a, shared_ptr<Decoded> b)
+       {
+               return a->dcp_time < b->dcp_time;
+       }
+};
+
 shared_ptr<Decoded>
 Decoder::peek ()
 {
@@ -51,6 +59,7 @@ Decoder::peek ()
                return shared_ptr<Decoded> ();
        }
 
+       _pending.sort (DecodedSorter ());
        return _pending.front ();
 }
 
index 25fe655be10c6b99f1b7b31c55b3b1867a5d5f3b..dae0ddbe8924b2b65fa8657a455a01128555b50f 100644 (file)
@@ -445,11 +445,17 @@ FFmpegDecoder::decode_audio_packet ()
                }
 
                if (frame_finished) {
+                       ContentTime const ct = (
+                               av_frame_get_best_effort_timestamp (_frame) *
+                               av_q2d (_ffmpeg_content->audio_stream()->stream (_format_context)->time_base)
+                               + _pts_offset
+                               ) * TIME_HZ;
+                       
                        int const data_size = av_samples_get_buffer_size (
                                0, audio_codec_context()->channels, _frame->nb_samples, audio_sample_format (), 1
                                );
-                       
-                       audio (deinterleave_audio (_frame->data, data_size));
+
+                       audio (deinterleave_audio (_frame->data, data_size), ct);
                }
                        
                copy_packet.data += decode_result;
@@ -603,13 +609,3 @@ FFmpegDecoder::decode_subtitle_packet ()
        
        avsubtitle_free (&sub);
 }
-
-ContentTime
-FFmpegDecoder::first_audio () const
-{
-       if (!_ffmpeg_content->audio_stream ()) {
-               return 0;
-       }
-
-       return _ffmpeg_content->audio_stream()->first_audio.get_value_or(0) + _pts_offset;
-}
index 680e39c393a9dad5aca9e71cae4337e9108e1472..ee725b20c9c46cb066d9e98bbfd6d7331bee45c9 100644 (file)
@@ -58,7 +58,6 @@ private:
 
        bool pass ();
        void flush ();
-       ContentTime first_audio () const;
 
        void setup_subtitle ();
 
index eb7b177ecd21aacc86bc5c96d89e404a8333f7e1..3db2fe6c9eb19074be6f265f7fd4ffe6918ca61d 100644 (file)
@@ -172,11 +172,6 @@ Player::pass ()
        /* Will be set to false if we shouldn't consume the peeked DecodedThing */
        bool consume = true;
 
-       /* This is the margin either side of _{video,audio}_position that we will accept
-          as a starting point for a frame consecutive to the previous.
-       */
-       DCPTime const margin = TIME_HZ / (2 * _film->video_frame_rate ());
-       
        if (dv && _video) {
 
                if (_just_did_inaccurate_seek) {
@@ -185,7 +180,7 @@ Player::pass ()
                        emit_video (earliest_piece, dv);
                        step_video_position (dv);
                        
-               } else if (dv->dcp_time - _video_position > margin) {
+               } else if (dv->dcp_time > _video_position) {
 
                        /* Too far ahead */
 
@@ -208,7 +203,7 @@ Player::pass ()
 
                        consume = false;
 
-               } else if (abs (dv->dcp_time - _video_position) < margin) {
+               } else if (dv->dcp_time == _video_position) {
                        /* We're ok */
                        emit_video (earliest_piece, dv);
                        step_video_position (dv);
@@ -222,12 +217,12 @@ Player::pass ()
 
        } else if (da && _audio) {
 
-               if (da->dcp_time - _audio_position > margin) {
+               if (da->dcp_time > _audio_position) {
                        /* Too far ahead */
                        emit_silence (da->dcp_time - _audio_position);
                        consume = false;
                        _statistics.audio.silence += (da->dcp_time - _audio_position);
-               } else if (abs (da->dcp_time - _audio_position) < margin) {
+               } else if (da->dcp_time == _audio_position) {
                        /* We're ok */
                        emit_audio (earliest_piece, da);
                        _statistics.audio.good += da->data->frames();
index 1c651e6142abb1cc583011adee35723dad6d505f..d6537843e8970ebde3ae6872bb99f04fd66e5de3 100644 (file)
@@ -45,6 +45,7 @@ SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<const Sndfi
                throw DecodeError (_("could not open audio file for reading"));
        }
 
+       _done = 0;
        _remaining = _info.frames;
 }
 
@@ -93,7 +94,8 @@ SndfileDecoder::pass ()
        }
                
        data->set_frames (this_time);
-       audio (data);
+       audio (data, _done * TIME_HZ / audio_frame_rate ());
+       _done += this_time;
        _remaining -= this_time;
 
        return _remaining == 0;
@@ -123,5 +125,6 @@ SndfileDecoder::seek (ContentTime t, bool accurate)
        Decoder::seek (t, accurate);
        AudioDecoder::seek (t, accurate);
 
+       _done = t * audio_frame_rate() / TIME_HZ;
        _remaining = _info.frames - _done;
 }
index 4ecea0846ef030ea22324c53e93d9be785958db6..46d9c5e5cf24762b5c2733e4f8c0be6c035a4d97 100644 (file)
@@ -36,15 +36,12 @@ public:
        int audio_frame_rate () const;
 
 private:
-       ContentTime first_audio () const {
-               return 0;
-       }
-
        bool pass ();
        
        boost::shared_ptr<const SndfileContent> _sndfile_content;
        SNDFILE* _sndfile;
        SF_INFO _info;
+       AudioFrame _done;
        AudioFrame _remaining;
        float* _deinterleave_buffer;
 };