summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2020-06-21 21:10:10 +0200
committerCarl Hetherington <cth@carlh.net>2021-04-25 00:12:02 +0200
commitdd3862c76cc158fe7cda50cfb4ef11d07a2483e2 (patch)
treee75a99e6f821834dca2d70a82922fdef91d8c516 /src
parent151f5c81fade29e9bebea9904fd85975351b7b78 (diff)
Had a go, gave up.
Diffstat (limited to 'src')
-rw-r--r--src/lib/audio_decoder.cc13
-rw-r--r--src/lib/audio_decoder.h18
-rw-r--r--src/lib/audio_mapping.cc30
-rw-r--r--src/lib/audio_mapping.h2
-rw-r--r--src/lib/player.cc10
-rw-r--r--src/lib/player.h6
-rw-r--r--src/lib/resampler_manager.cc144
-rw-r--r--src/lib/resampler_manager.h54
-rw-r--r--src/lib/wscript1
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