From: Carl Hetherington Date: Sun, 21 May 2017 18:48:14 +0000 (+0100) Subject: Do resampling in AudioDecoder rather than Player. X-Git-Tag: v2.11.6~9 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=fa4d2529d63bcfa7cf7c516b7227e20a1b6dec7e Do resampling in AudioDecoder rather than Player. 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. --- diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 3e4584a3f..4b77a8afb 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -22,19 +22,24 @@ #include "audio_buffers.h" #include "audio_content.h" #include "log.h" +#include "resampler.h" #include "compose.hpp" #include #include #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 content, shared_ptr 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 data, _positions[stream] = time.frames_round (stream->frame_rate ()); } + shared_ptr resampler; + map >::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 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 p; for (map::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 >::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) { + i->second->flush (); + i->second->reset (); + } + for (map::iterator i = _positions.begin(); i != _positions.end(); ++i) { i->second = 0; } } + +void +AudioDecoder::flush () +{ + for (map >::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) { + shared_ptr ro = i->second->flush (); + if (ro->frames() > 0) { + Data (i->first, ContentAudio (ro, _positions[i->first])); + _positions[i->first] += ro->frames(); + } + } +} diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index c104d8201..fcbd8267b 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -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, ContentTime); void seek (); + void flush (); boost::signals2::signal Data; private: + boost::shared_ptr _content; /** Frame after the last one that was emitted from Data for each AudioStream */ std::map _positions; + std::map > _resamplers; }; #endif diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 1c886284b..baec57f3d 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -113,6 +113,7 @@ FFmpegDecoder::flush () if (audio) { decode_audio_packet (); + audio->flush (); } } diff --git a/src/lib/player.cc b/src/lib/player.cc index d51c94400..7f8b06458 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -47,7 +47,6 @@ #include "content_subtitle.h" #include "dcp_decoder.h" #include "image_decoder.h" -#include "resampler.h" #include "compose.hpp" #include #include @@ -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 wp, ContentVideo video) emit_video (_last_video[wp], time); } -void -Player::audio_flush (shared_ptr piece, AudioStreamPtr stream) -{ - shared_ptr content = piece->content->audio; - DCPOMATIC_ASSERT (content); - - shared_ptr r = resampler (content, stream, false); - if (!r) { - return; - } - - pair, 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 content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time) @@ -802,17 +769,6 @@ Player::audio (weak_ptr wp, AudioStreamPtr stream, ContentAudio content_a shared_ptr content = piece->content->audio; DCPOMATIC_ASSERT (content); - /* Resample */ - if (stream->frame_rate() != content->resampled_frame_rate()) { - shared_ptr r = resampler (content, stream, true); - pair, 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 -Player::resampler (shared_ptr 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 (); - } - - LOG_GENERAL ( - "Creating new resampler from %1 to %2 with %3 channels", - stream->frame_rate(), - content->resampled_frame_rate(), - stream->channels() - ); - - shared_ptr 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 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) { diff --git a/src/lib/player.h b/src/lib/player.h index 20c55e26d..20d9c9388 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -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, ContentImageSubtitle); void text_subtitle_start (boost::weak_ptr, ContentTextSubtitle); void subtitle_stop (boost::weak_ptr, ContentTime); - boost::shared_ptr resampler (boost::shared_ptr content, AudioStreamPtr stream, bool create); DCPTime one_video_frame () const; void fill_audio (DCPTimePeriod period); - void audio_flush (boost::shared_ptr, AudioStreamPtr stream); void audio_transform (boost::shared_ptr content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time); std::pair, DCPTime> discard_audio ( boost::shared_ptr audio, DCPTime time, DCPTime discard_to @@ -173,8 +170,6 @@ private: ActiveSubtitles _active_subtitles; boost::shared_ptr _audio_processor; - typedef std::map, AudioStreamPtr>, boost::shared_ptr > ResamplerMap; - ResamplerMap _resamplers; boost::signals2::scoped_connection _film_changed_connection; boost::signals2::scoped_connection _playlist_changed_connection; diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc index e991591c2..553180f08 100644 --- a/src/lib/resampler.cc +++ b/src/lib/resampler.cc @@ -67,19 +67,9 @@ Resampler::set_fast () } } -pair, Frame> -Resampler::run (shared_ptr in, Frame frame) +shared_ptr +Resampler::run (shared_ptr 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 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, Frame> +shared_ptr Resampler::flush () { shared_ptr 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 diff --git a/src/lib/resampler.h b/src/lib/resampler.h index 9e9304fb4..4b19dc511 100644 --- a/src/lib/resampler.h +++ b/src/lib/resampler.h @@ -31,8 +31,8 @@ public: Resampler (int, int, int); ~Resampler (); - std::pair, Frame> run (boost::shared_ptr, Frame); - std::pair, Frame> flush (); + boost::shared_ptr run (boost::shared_ptr); + boost::shared_ptr flush (); void reset (); void set_fast (); @@ -41,6 +41,4 @@ private: int _in_rate; int _out_rate; int _channels; - boost::optional _next_in; - boost::optional _next_out; };