diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-06-21 21:10:10 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2021-04-25 00:12:02 +0200 |
| commit | dd3862c76cc158fe7cda50cfb4ef11d07a2483e2 (patch) | |
| tree | e75a99e6f821834dca2d70a82922fdef91d8c516 /src | |
| parent | 151f5c81fade29e9bebea9904fd85975351b7b78 (diff) | |
Had a go, gave up.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/audio_decoder.cc | 13 | ||||
| -rw-r--r-- | src/lib/audio_decoder.h | 18 | ||||
| -rw-r--r-- | src/lib/audio_mapping.cc | 30 | ||||
| -rw-r--r-- | src/lib/audio_mapping.h | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 10 | ||||
| -rw-r--r-- | src/lib/player.h | 6 | ||||
| -rw-r--r-- | src/lib/resampler_manager.cc | 144 | ||||
| -rw-r--r-- | src/lib/resampler_manager.h | 54 | ||||
| -rw-r--r-- | src/lib/wscript | 1 |
9 files changed, 262 insertions, 16 deletions
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 77c9b0695..5f7ec3730 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -25,6 +25,7 @@ #include "dcpomatic_log.h" #include "log.h" #include "resampler.h" +#include "resampler_manager.h" #include "compose.hpp" #include <iostream> @@ -99,9 +100,9 @@ AudioDecoder::emit (shared_ptr<const Film> film, AudioStreamPtr stream, shared_p _positions[stream] = time.frames_round (resampled_rate); } - shared_ptr<Resampler> resampler; + auto resampler = _resampler_manager->get (this, stream, _fast); auto i = _resamplers.find(stream); - if (i != _resamplers.end()) { + if (i != _resamplers.end ()) { resampler = i->second; } else { if (stream->frame_rate() != resampled_rate) { @@ -175,13 +176,7 @@ AudioDecoder::seek () void AudioDecoder::flush () { - for (auto const& i: _resamplers) { - auto ro = i.second->flush (); - if (ro->frames() > 0) { - Data (i.first, ContentAudio (ro, _positions[i.first])); - _positions[i.first] += ro->frames(); - } - } + _resampler_manager->maybe_flush (this); if (_content->delay() < 0) { /* Finish off with the gap caused by the delay */ diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 754321880..3197ace34 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -41,6 +41,8 @@ class AudioDecoderStream; class Log; class Film; class Resampler; +class ResamplerManager; +struct resampler_manager_setup_test; /** @class AudioDecoder. @@ -58,9 +60,21 @@ public: dcpomatic::ContentTime stream_position (std::shared_ptr<const Film> film, AudioStreamPtr stream) const; + void set_resampler_manager (std::shared_ptr<ResamplerManager> r) { + _resampler_manager = r; + } + + /** @return Number of frames of data that were accepted */ boost::signals2::signal<void (AudioStreamPtr, ContentAudio)> Data; private: + friend struct ::resampler_manager_setup_test; + + /* Only for test use */ + AudioDecoder () + : DecoderPart(0) + {} + void silence (int milliseconds); std::shared_ptr<const AudioContent> _content; @@ -72,6 +86,8 @@ private: typedef std::map<AudioStreamPtr, std::shared_ptr<Resampler>> ResamplerMap; ResamplerMap _resamplers; + boost::shared_ptr<ResamplerManager> _resampler_manager; + bool _fast; }; diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc index 8b9f102a5..2a9366cb6 100644 --- a/src/lib/audio_mapping.cc +++ b/src/lib/audio_mapping.cc @@ -254,28 +254,46 @@ AudioMapping::digest () const } -list<int> -AudioMapping::mapped_output_channels () const +pair<list<int>, list<int>> +AudioMapping::mapped_channels () const { static float const minus_96_db = 0.000015849; - list<int> mapped; + pair<list<int>, list<int>> mapped; for (auto const& i: _gain) { for (auto j: dcp::used_audio_channels()) { if (abs(i[static_cast<int>(j)]) > minus_96_db) { - mapped.push_back (static_cast<int>(j)); + mapped.first.push_back (static_cast<int>(i)); + mapped.second.push_back (static_cast<int>(j)); } } } - mapped.sort (); - mapped.unique (); + mapped.first.sort (); + mapped.first.unique (); + + mapped.second.sort (); + mapped.second.unique (); return mapped; } +list<int> +AudioMapping::mapped_input_channels () const +{ + return mapped_channels().first; +} + + +list<int> +AudioMapping::mapped_output_channels () const +{ + return mapped_channels().second; +} + + void AudioMapping::unmap_all () { diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h index 4ef5aedb1..7f4b3f8bb 100644 --- a/src/lib/audio_mapping.h +++ b/src/lib/audio_mapping.h @@ -73,6 +73,8 @@ public: std::string digest () const; + std::pair<std::list<int>, std::list<int> > mapped_channels () const; + std::list<int> mapped_input_channels () const; std::list<int> mapped_output_channels () const; void unmap_all (); diff --git a/src/lib/player.cc b/src/lib/player.cc index 0bdf46f4a..96ca80973 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -20,6 +20,7 @@ #include "atmos_decoder.h" +#include "resampler_manager.h" #include "player.h" #include "film.h" #include "audio_buffers.h" @@ -285,6 +286,15 @@ Player::setup_pieces_unlocked () _black = Empty (_film, playlist(), bind(&have_video, _1), _playback_length); _silent = Empty (_film, playlist(), bind(&have_audio, _1), _playback_length); + _resampler_manager = make_shared<ResamplerManager>(_film); + + for (auto i: _pieces) { + if (i->content->audio) { + _resampler_manager->add (i->content->position(), i->content->end(_film), i->content->audio, i->decoder->audio); + i->decoder->audio->set_resampler_manager (_resampler_manager); + } + } + _last_video_time = boost::optional<dcpomatic::DCPTime>(); _last_video_eyes = Eyes::BOTH; _last_audio_time = boost::optional<dcpomatic::DCPTime>(); diff --git a/src/lib/player.h b/src/lib/player.h index 8fc02d9c6..f1316d128 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -52,6 +52,9 @@ class Playlist; class AudioBuffers; class ReferencedReelAsset; class Shuffler; +class ResamplerManager; +struct resampler_manager_setup_test; + class PlayerProperty { @@ -123,6 +126,7 @@ private: friend struct empty_test2; friend struct check_reuse_old_data_test; friend struct overlap_video_test1; + friend struct resampler_manager_setup_test; void construct (); void setup_pieces (); @@ -228,6 +232,8 @@ private: dcpomatic::DCPTime _playback_length; + boost::shared_ptr<ResamplerManager> _resampler_manager; + boost::signals2::scoped_connection _film_changed_connection; boost::signals2::scoped_connection _playlist_change_connection; boost::signals2::scoped_connection _playlist_content_change_connection; diff --git a/src/lib/resampler_manager.cc b/src/lib/resampler_manager.cc new file mode 100644 index 000000000..aa98d0baa --- /dev/null +++ b/src/lib/resampler_manager.cc @@ -0,0 +1,144 @@ +#include "audio_content.h" +#include "audio_decoder.h" +#include "dcpomatic_log.h" +#include "resampler.h" +#include "resampler_manager.h" +#include <boost/foreach.hpp> +#include <vector> + + +using std::vector; +using boost::shared_ptr; +using namespace dcpomatic; + + +void +ResamplerManager::add (DCPTime start, DCPTime end, shared_ptr<AudioContent> content, shared_ptr<AudioDecoder> decoder) +{ + _groups.push_back (Group(start, end, content, decoder)); + coalesce (); +} + + +void +ResamplerManager::coalesce () +{ + if (_groups.size() < 2) { + return; + } + + while (coalesce_pass()) {} +} + + +bool +ResamplerManager::can_share (Group const& a, Group const& b) const +{ + vector<AudioStreamPtr> as = a.contents[0]->streams(); + vector<AudioStreamPtr> bs = b.contents[0]->streams(); + + if (a.contents[0]->streams().size() != b.contents[0]->streams().size()) { + return false; + } + + shared_ptr<const Film> film = _film.lock (); + DCPOMATIC_ASSERT (film); + if (a.contents[0]->resampled_frame_rate(film) != b.contents[0]->resampled_frame_rate(film)) { + return false; + } + + /* The first, second, etc. streams in a and b must be the same */ + + vector<AudioStreamPtr>::const_iterator i = as.begin(); + vector<AudioStreamPtr>::const_iterator j = bs.begin(); + + while (i != as.end()) { + if ( + (*i)->channels() != (*j)->channels() || + (*i)->mapping().mapped_channels() != (*j)->mapping().mapped_channels() || + (*i)->frame_rate() != (*j)->frame_rate()) { + return false; + } + ++i; + ++j; + } + + return true; +} + + +bool +ResamplerManager::coalesce_pass () +{ + for (size_t i = 0; i < _groups.size(); ++i) { + for (size_t j = 0; j < _groups.size(); ++j) { + if (i == j) { + continue; + } + + if (_groups[i].start == _groups[j].end && can_share(_groups[i], _groups[j])) { + copy (_groups[i].decoders.begin(), _groups[i].decoders.end(), back_inserter(_groups[j].decoders)); + copy (_groups[i].contents.begin(), _groups[i].contents.end(), back_inserter(_groups[j].contents)); + _groups[j].end = _groups[i].end; + _groups.erase (_groups.begin() + i); + return true; + } + } + } + + return false; +} + + +shared_ptr<Resampler> +ResamplerManager::get (AudioDecoder* decoder, AudioStreamPtr stream, bool fast) +{ + shared_ptr<const Film> film = _film.lock(); + DCPOMATIC_ASSERT (film); + + BOOST_FOREACH (Group& g, _groups) { + for (size_t i = 0; i < g.decoders.size(); ++i) { + if (g.decoders[i].get() == decoder) { + vector<AudioStreamPtr> content_streams = g.contents[i]->streams(); + ptrdiff_t index = find(content_streams.begin(), content_streams.end(), stream) - content_streams.begin(); + DCPOMATIC_ASSERT (index < static_cast<ptrdiff_t>(content_streams.size())); + if (!g.resamplers[index] && stream->frame_rate() != g.contents[i]->resampled_frame_rate(film)) { + LOG_GENERAL ( + "Creating new resampler from %1 to %2 with %3 channels", + stream->frame_rate(), + g.contents[i]->resampled_frame_rate(film), + stream->channels() + ); + + g.resamplers[index].reset (new Resampler(stream->frame_rate(), g.contents[i]->resampled_frame_rate(film), stream->channels())); + if (fast) { + g.resamplers[index]->set_fast (); + } + } + return g.resamplers[index]; + } + } + } + + DCPOMATIC_ASSERT (false); + return shared_ptr<Resampler>(); +} + + +void +ResamplerManager::maybe_flush (AudioDecoder* decoder) +{ + BOOST_FOREACH (Group& g, _groups) { + BOOST_FOREACH (shared_ptr<AudioDecoder> d, g.decoders) { + if (d.get() == decoder) { + BOOST_FOREACH (shared_ptr<Resampler> r, g.resamplers) { + shared_ptr<const AudioBuffers> ro = r->flush (); + /* XXX: err... which content do these samples belong to? Won't + * the player throw the samples away if they appear to come from the + * wrong place? + */ + } + } + } +} + diff --git a/src/lib/resampler_manager.h b/src/lib/resampler_manager.h new file mode 100644 index 000000000..25c0a5e9e --- /dev/null +++ b/src/lib/resampler_manager.h @@ -0,0 +1,54 @@ +#include "audio_content.h" +#include "dcpomatic_time.h" +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> +#include <vector> + + +class AudioContent; +class AudioDecoder; +class AudioStream; +class Resampler; + + +class ResamplerManager : public boost::noncopyable +{ +public: + ResamplerManager (boost::weak_ptr<const Film> film) + : _film (film) + {} + + void add (dcpomatic::DCPTime start, dcpomatic::DCPTime end, boost::shared_ptr<AudioContent> content, boost::shared_ptr<AudioDecoder> decoder); + boost::shared_ptr<Resampler> get (AudioDecoder* decoder, AudioStreamPtr stream, bool fast); + +private: + friend struct resampler_manager_setup_test; + + class Group + { + public: + Group (dcpomatic::DCPTime start_, dcpomatic::DCPTime end_, boost::shared_ptr<AudioContent> content, boost::shared_ptr<AudioDecoder> decoder) + : start(start_) + , end(end_) + { + contents.push_back (content); + decoders.push_back (decoder); + resamplers.resize (content->streams().size()); + } + + dcpomatic::DCPTime start; + dcpomatic::DCPTime end; + std::vector<boost::shared_ptr<AudioContent> > contents; + std::vector<boost::shared_ptr<AudioDecoder> > decoders; + std::vector<boost::shared_ptr<Resampler> > resamplers; + }; + + bool can_share (Group const& a, Group const& b) const; + void coalesce (); + bool coalesce_pass (); + + boost::weak_ptr<const Film> _film; + std::vector<Group> _groups; +}; + diff --git a/src/lib/wscript b/src/lib/wscript index 2965111ad..d040a26d7 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -143,6 +143,7 @@ sources = """ reel_writer.cc render_text.cc resampler.cc + resampler_manager.cc rgba.cc rng.cc scoped_temporary.cc |
