Do resampling in AudioDecoder rather than Player.
authorCarl Hetherington <cth@carlh.net>
Sun, 21 May 2017 18:48:14 +0000 (19:48 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 21 May 2017 18:48:14 +0000 (19:48 +0100)
This fixes the problem where the decoder's position would not take
into account that all samples pushed into the resampler do not
always immediately come out.  This would result in Player thinking
that there would be gaps when there are not.

src/lib/audio_decoder.cc
src/lib/audio_decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/player.cc
src/lib/player.h
src/lib/resampler.cc
src/lib/resampler.h

index 3e4584a3f5a04552523344fa54ba8f1c3b0593cc..4b77a8afbe0a1f56787f110c60c227cdd849b262 100644 (file)
 #include "audio_buffers.h"
 #include "audio_content.h"
 #include "log.h"
+#include "resampler.h"
 #include "compose.hpp"
 #include <boost/foreach.hpp>
 #include <iostream>
 
 #include "i18n.h"
 
+#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
+
 using std::cout;
 using std::map;
+using std::pair;
 using boost::shared_ptr;
 using boost::optional;
 
 AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<const AudioContent> content, shared_ptr<Log> log)
        : DecoderPart (parent, log)
+       , _content (content)
 {
        /* Set up _positions so that we have one for each stream */
        BOOST_FOREACH (AudioStreamPtr i, content->streams ()) {
@@ -58,6 +63,32 @@ AudioDecoder::emit (AudioStreamPtr stream, shared_ptr<const AudioBuffers> data,
                _positions[stream] = time.frames_round (stream->frame_rate ());
        }
 
+       shared_ptr<Resampler> resampler;
+       map<AudioStreamPtr, shared_ptr<Resampler> >::iterator i = _resamplers.find(stream);
+       if (i != _resamplers.end ()) {
+               resampler = i->second;
+       } else {
+               if (stream->frame_rate() != _content->resampled_frame_rate()) {
+                       LOG_GENERAL (
+                               "Creating new resampler from %1 to %2 with %3 channels",
+                               stream->frame_rate(),
+                               _content->resampled_frame_rate(),
+                               stream->channels()
+                               );
+
+                       resampler.reset (new Resampler (stream->frame_rate(), _content->resampled_frame_rate(), stream->channels()));
+                       _resamplers[stream] = resampler;
+               }
+       }
+
+       if (resampler) {
+               shared_ptr<const AudioBuffers> ro = resampler->run (data);
+               if (ro->frames() == 0) {
+                       return;
+               }
+               data = ro;
+       }
+
        Data (stream, ContentAudio (data, _positions[stream]));
        _positions[stream] += data->frames();
 }
@@ -67,7 +98,7 @@ AudioDecoder::position () const
 {
        optional<ContentTime> p;
        for (map<AudioStreamPtr, Frame>::const_iterator i = _positions.begin(); i != _positions.end(); ++i) {
-               ContentTime const ct = ContentTime::from_frames (i->second, i->first->frame_rate ());
+               ContentTime const ct = ContentTime::from_frames (i->second, _content->resampled_frame_rate());
                if (!p || ct < *p) {
                        p = ct;
                }
@@ -79,7 +110,24 @@ AudioDecoder::position () const
 void
 AudioDecoder::seek ()
 {
+       for (map<AudioStreamPtr, shared_ptr<Resampler> >::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) {
+               i->second->flush ();
+               i->second->reset ();
+       }
+
        for (map<AudioStreamPtr, Frame>::iterator i = _positions.begin(); i != _positions.end(); ++i) {
                i->second = 0;
        }
 }
+
+void
+AudioDecoder::flush ()
+{
+       for (map<AudioStreamPtr, shared_ptr<Resampler> >::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) {
+               shared_ptr<const AudioBuffers> ro = i->second->flush ();
+               if (ro->frames() > 0) {
+                       Data (i->first, ContentAudio (ro, _positions[i->first]));
+                       _positions[i->first] += ro->frames();
+               }
+       }
+}
index c104d8201971a3b1ee98bf72dfed3f58f619945c..fcbd8267b6f6a7380dc5356551c68a5d8520d79d 100644 (file)
@@ -36,6 +36,7 @@ class AudioBuffers;
 class AudioContent;
 class AudioDecoderStream;
 class Log;
+class Resampler;
 
 /** @class AudioDecoder.
  *  @brief Parent class for audio decoders.
@@ -48,12 +49,15 @@ public:
        ContentTime position () const;
        void emit (AudioStreamPtr stream, boost::shared_ptr<const AudioBuffers>, ContentTime);
        void seek ();
+       void flush ();
 
        boost::signals2::signal<void (AudioStreamPtr, ContentAudio)> Data;
 
 private:
+       boost::shared_ptr<const AudioContent> _content;
        /** Frame after the last one that was emitted from Data for each AudioStream */
        std::map<AudioStreamPtr, Frame> _positions;
+       std::map<AudioStreamPtr, boost::shared_ptr<Resampler> > _resamplers;
 };
 
 #endif
index 1c886284b69cfad5fcc3f4779f7feb0f05d3dc70..baec57f3d24e19473df2dd74788caa7a411e1841 100644 (file)
@@ -113,6 +113,7 @@ FFmpegDecoder::flush ()
 
        if (audio) {
                decode_audio_packet ();
+               audio->flush ();
        }
 }
 
index d51c944009c900a1b354730814e5b6787bae9b89..7f8b06458bd06876101e3dd6f9b51d26f4fc7bd6 100644 (file)
@@ -47,7 +47,6 @@
 #include "content_subtitle.h"
 #include "dcp_decoder.h"
 #include "image_decoder.h"
-#include "resampler.h"
 #include "compose.hpp"
 #include <dcp/reel.h>
 #include <dcp/reel_sound_asset.h>
@@ -580,12 +579,6 @@ Player::pass ()
 
        if (earliest) {
                earliest->done = earliest->decoder->pass ();
-               if (earliest->done && earliest->content->audio) {
-                       /* Flush the Player audio system for this piece */
-                       BOOST_FOREACH (AudioStreamPtr i, earliest->content->audio->streams()) {
-                               audio_flush (earliest, i);
-                       }
-               }
        }
 
        /* Emit any audio that is ready */
@@ -709,32 +702,6 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
        emit_video (_last_video[wp], time);
 }
 
-void
-Player::audio_flush (shared_ptr<Piece> piece, AudioStreamPtr stream)
-{
-       shared_ptr<AudioContent> content = piece->content->audio;
-       DCPOMATIC_ASSERT (content);
-
-       shared_ptr<Resampler> r = resampler (content, stream, false);
-       if (!r) {
-               return;
-       }
-
-       pair<shared_ptr<const AudioBuffers>, Frame> ro = r->flush ();
-       if (ro.first->frames() == 0) {
-               return;
-       }
-
-       ContentAudio content_audio;
-       content_audio.audio = ro.first;
-       content_audio.frame = ro.second;
-
-       /* Compute time in the DCP */
-       DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
-
-       audio_transform (content, stream, content_audio, time);
-}
-
 /** Do our common processing on some audio */
 void
 Player::audio_transform (shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time)
@@ -802,17 +769,6 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
        shared_ptr<AudioContent> content = piece->content->audio;
        DCPOMATIC_ASSERT (content);
 
-       /* Resample */
-       if (stream->frame_rate() != content->resampled_frame_rate()) {
-               shared_ptr<Resampler> r = resampler (content, stream, true);
-               pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
-               if (ro.first->frames() == 0) {
-                       return;
-               }
-               content_audio.audio = ro.first;
-               content_audio.frame = ro.second;
-       }
-
        /* Compute time in the DCP */
        DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
        /* And the end of this block in the DCP */
@@ -937,11 +893,6 @@ Player::seek (DCPTime time, bool accurate)
                _audio_processor->flush ();
        }
 
-       for (ResamplerMap::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) {
-               i->second->flush ();
-               i->second->reset ();
-       }
-
        _audio_merger.clear ();
        _active_subtitles.clear ();
 
@@ -969,33 +920,6 @@ Player::seek (DCPTime time, bool accurate)
        }
 }
 
-shared_ptr<Resampler>
-Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create)
-{
-       ResamplerMap::const_iterator i = _resamplers.find (make_pair (content, stream));
-       if (i != _resamplers.end ()) {
-               return i->second;
-       }
-
-       if (!create) {
-               return shared_ptr<Resampler> ();
-       }
-
-       LOG_GENERAL (
-               "Creating new resampler from %1 to %2 with %3 channels",
-               stream->frame_rate(),
-               content->resampled_frame_rate(),
-               stream->channels()
-               );
-
-       shared_ptr<Resampler> r (
-               new Resampler (stream->frame_rate(), content->resampled_frame_rate(), stream->channels())
-               );
-
-       _resamplers[make_pair(content, stream)] = r;
-       return r;
-}
-
 void
 Player::emit_video (shared_ptr<PlayerVideo> pv, DCPTime time)
 {
@@ -1026,6 +950,7 @@ Player::fill_audio (DCPTimePeriod period)
                return;
        }
 
+       cout << "fillin " << to_string(period.from) << " to " << to_string(period.to) << "\n";
        BOOST_FOREACH (DCPTimePeriod i, subtract(period, _no_audio)) {
                DCPTime t = i.from;
                while (t < i.to) {
index 20c55e26d1b55dd979958d1587c14c8822cae2a3..20d9c9388b33fa00464aa06609a836514220571e 100644 (file)
@@ -45,7 +45,6 @@ class Playlist;
 class Font;
 class AudioBuffers;
 class ReferencedReelAsset;
-class Resampler;
 
 /** @class Player
  *  @brief A class which can `play' a Playlist.
@@ -107,10 +106,8 @@ private:
        void image_subtitle_start (boost::weak_ptr<Piece>, ContentImageSubtitle);
        void text_subtitle_start (boost::weak_ptr<Piece>, ContentTextSubtitle);
        void subtitle_stop (boost::weak_ptr<Piece>, ContentTime);
-       boost::shared_ptr<Resampler> resampler (boost::shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create);
        DCPTime one_video_frame () const;
        void fill_audio (DCPTimePeriod period);
-       void audio_flush (boost::shared_ptr<Piece>, AudioStreamPtr stream);
        void audio_transform (boost::shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time);
        std::pair<boost::shared_ptr<AudioBuffers>, DCPTime> discard_audio (
                boost::shared_ptr<const AudioBuffers> audio, DCPTime time, DCPTime discard_to
@@ -173,8 +170,6 @@ private:
 
        ActiveSubtitles _active_subtitles;
        boost::shared_ptr<AudioProcessor> _audio_processor;
-       typedef std::map<std::pair<boost::shared_ptr<const AudioContent>, AudioStreamPtr>, boost::shared_ptr<Resampler> > ResamplerMap;
-       ResamplerMap _resamplers;
 
        boost::signals2::scoped_connection _film_changed_connection;
        boost::signals2::scoped_connection _playlist_changed_connection;
index e991591c24544b5bf77849eb7eacd5d564849ded..553180f0832c7a26852b2354bec045b1263faa01 100644 (file)
@@ -67,19 +67,9 @@ Resampler::set_fast ()
        }
 }
 
-pair<shared_ptr<const AudioBuffers>, Frame>
-Resampler::run (shared_ptr<const AudioBuffers> in, Frame frame)
+shared_ptr<const AudioBuffers>
+Resampler::run (shared_ptr<const AudioBuffers> in)
 {
-       if (!_next_in || !_next_out || _next_in.get() != frame) {
-               /* Either there was a discontinuity in the input or this is the first input;
-                  reset _next_out.
-               */
-               _next_out = lrintf (frame * _out_rate / _in_rate);
-       }
-
-       /* Expected next input frame */
-       _next_in = frame + in->frames ();
-
        int in_frames = in->frames ();
        int in_offset = 0;
        int out_offset = 0;
@@ -154,15 +144,10 @@ Resampler::run (shared_ptr<const AudioBuffers> in, Frame frame)
                delete[] data.data_out;
        }
 
-       Frame out_frame = _next_out.get ();
-
-       /* Expected next output frame */
-       _next_out = _next_out.get() + resampled->frames();
-
-       return make_pair (resampled, out_frame);
+       return resampled;
 }
 
-pair<shared_ptr<const AudioBuffers>, Frame>
+shared_ptr<const AudioBuffers>
 Resampler::flush ()
 {
        shared_ptr<AudioBuffers> out (new AudioBuffers (_channels, 0));
@@ -200,7 +185,7 @@ Resampler::flush ()
        out->set_frames (out_offset);
 
        delete[] buffer;
-       return make_pair (out, _next_out.get ());
+       return out;
 }
 
 void
index 9e9304fb421c7d46ca529702c635a09c67133ed1..4b19dc511b891e988c33b4a89b22af8c78da4eb9 100644 (file)
@@ -31,8 +31,8 @@ public:
        Resampler (int, int, int);
        ~Resampler ();
 
-       std::pair<boost::shared_ptr<const AudioBuffers>, Frame> run (boost::shared_ptr<const AudioBuffers>, Frame);
-       std::pair<boost::shared_ptr<const AudioBuffers>, Frame> flush ();
+       boost::shared_ptr<const AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+       boost::shared_ptr<const AudioBuffers> flush ();
        void reset ();
        void set_fast ();
 
@@ -41,6 +41,4 @@ private:
        int _in_rate;
        int _out_rate;
        int _channels;
-       boost::optional<Frame> _next_in;
-       boost::optional<Frame> _next_out;
 };