diff options
| author | Carl Hetherington <cth@carlh.net> | 2016-04-14 01:01:28 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2016-05-18 11:50:29 +0100 |
| commit | 65b331d32c383f3a9049f29bf03ab3fe3193b31a (patch) | |
| tree | 3b27e0ca60742021094cee889a1c8d1ef4d75f8c /src/lib | |
| parent | 6dd3777a0074f6f97c7f7286621006a1c14376e8 (diff) | |
Split audio; builds.
Diffstat (limited to 'src/lib')
33 files changed, 296 insertions, 342 deletions
diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 7a1a993e7..9a24a9188 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -106,7 +106,7 @@ AnalyseAudioJob::run () bool has_any_audio = false; BOOST_FOREACH (shared_ptr<Content> c, _playlist->content ()) { - if (dynamic_pointer_cast<AudioContent> (c)) { + if (c->audio) { has_any_audio = true; } } @@ -145,7 +145,7 @@ AnalyseAudioJob::run () /* If there was only one piece of content in this analysis we may later need to know what its gain was when we analysed it. */ - shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (_playlist->content().front ()); + shared_ptr<const AudioContent> ac = _playlist->content().front()->audio; DCPOMATIC_ASSERT (ac); _analysis->set_analysis_gain (ac->audio_gain ()); } diff --git a/src/lib/audio_analysis.cc b/src/lib/audio_analysis.cc index 03f35d84e..d99b01ce6 100644 --- a/src/lib/audio_analysis.cc +++ b/src/lib/audio_analysis.cc @@ -153,9 +153,8 @@ AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist) we know that content's gain when the analysis was run. Hence we can work out what correction is now needed to make it look `right'. */ - shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (playlist->content().front ()); - DCPOMATIC_ASSERT (ac); - return ac->audio_gain() - analysis_gain().get (); + DCPOMATIC_ASSERT (playlist->content().front()->audio); + return playlist->content().front()->audio->audio_gain() - analysis_gain().get (); } return 0.0f; diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index bd4bb565f..2832e2575 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -49,52 +49,34 @@ int const AudioContentProperty::AUDIO_GAIN = 201; int const AudioContentProperty::AUDIO_DELAY = 202; int const AudioContentProperty::AUDIO_VIDEO_FRAME_RATE = 203; -AudioContent::AudioContent (shared_ptr<const Film> film) - : Content (film) +AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film) + : ContentPart (parent, film) , _audio_gain (0) , _audio_delay (Config::instance()->default_audio_delay ()) { } -AudioContent::AudioContent (shared_ptr<const Film> film, DCPTime s) - : Content (film, s) - , _audio_gain (0) - , _audio_delay (Config::instance()->default_audio_delay ()) -{ - -} - -AudioContent::AudioContent (shared_ptr<const Film> film, boost::filesystem::path p) - : Content (film, p) - , _audio_gain (0) - , _audio_delay (Config::instance()->default_audio_delay ()) -{ - -} - -AudioContent::AudioContent (shared_ptr<const Film> film, cxml::ConstNodePtr node) - : Content (film, node) +AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film, cxml::ConstNodePtr node) + : ContentPart (parent, film) { _audio_gain = node->number_child<double> ("AudioGain"); _audio_delay = node->number_child<int> ("AudioDelay"); _audio_video_frame_rate = node->optional_number_child<double> ("AudioVideoFrameRate"); } -AudioContent::AudioContent (shared_ptr<const Film> film, vector<shared_ptr<Content> > c) - : Content (film, c) +AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film, vector<shared_ptr<Content> > c) + : ContentPart (parent, film) { - shared_ptr<AudioContent> ref = dynamic_pointer_cast<AudioContent> (c[0]); + shared_ptr<AudioContent> ref = c[0]->audio; DCPOMATIC_ASSERT (ref); - for (size_t i = 0; i < c.size(); ++i) { - shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (c[i]); - - if (ac->audio_gain() != ref->audio_gain()) { + for (size_t i = 1; i < c.size(); ++i) { + if (c[i]->audio->audio_gain() != ref->audio_gain()) { throw JoinError (_("Content to be joined must have the same audio gain.")); } - if (ac->audio_delay() != ref->audio_delay()) { + if (c[i]->audio->audio_delay() != ref->audio_delay()) { throw JoinError (_("Content to be joined must have the same audio delay.")); } @@ -107,6 +89,7 @@ AudioContent::AudioContent (shared_ptr<const Film> film, vector<shared_ptr<Conte _audio_delay = ref->audio_delay (); /* Preserve the optional<> part of this */ _audio_video_frame_rate = ref->_audio_video_frame_rate; + _streams = ref->streams (); } void @@ -120,34 +103,23 @@ AudioContent::as_xml (xmlpp::Node* node) const } } - void AudioContent::set_audio_gain (double g) { - { - boost::mutex::scoped_lock lm (_mutex); - _audio_gain = g; - } - - signal_changed (AudioContentProperty::AUDIO_GAIN); + maybe_set (_audio_gain, g, AudioContentProperty::AUDIO_GAIN); } void AudioContent::set_audio_delay (int d) { - { - boost::mutex::scoped_lock lm (_mutex); - _audio_delay = d; - } - - signal_changed (AudioContentProperty::AUDIO_DELAY); + maybe_set (_audio_delay, d, AudioContentProperty::AUDIO_DELAY); } string AudioContent::technical_summary () const { string s = "audio :"; - BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr i, streams ()) { s += String::compose ("stream channels %1 rate %2", i->channels(), i->frame_rate()); } @@ -158,7 +130,7 @@ void AudioContent::set_audio_mapping (AudioMapping mapping) { int c = 0; - BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr i, streams ()) { AudioMapping stream_mapping (i->channels (), MAX_DCP_AUDIO_CHANNELS); for (int j = 0; j < i->channels(); ++j) { for (int k = 0; k < MAX_DCP_AUDIO_CHANNELS; ++k) { @@ -169,14 +141,14 @@ AudioContent::set_audio_mapping (AudioMapping mapping) i->set_mapping (stream_mapping); } - signal_changed (AudioContentProperty::AUDIO_STREAMS); + _parent->signal_changed (AudioContentProperty::AUDIO_STREAMS); } AudioMapping AudioContent::audio_mapping () const { int channels = 0; - BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr i, streams ()) { channels += i->channels (); } @@ -185,7 +157,7 @@ AudioContent::audio_mapping () const int c = 0; int s = 0; - BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr i, streams ()) { AudioMapping mapping = i->mapping (); for (int j = 0; j < mapping.input_channels(); ++j) { for (int k = 0; k < MAX_DCP_AUDIO_CHANNELS; ++k) { @@ -210,7 +182,9 @@ AudioContent::resampled_audio_frame_rate () const /* Resample to a DCI-approved sample rate */ double t = has_rate_above_48k() ? 96000 : 48000; - FrameRateChange frc (audio_video_frame_rate(), film()->video_frame_rate()); + shared_ptr<const Film> film = _film.lock (); + DCPOMATIC_ASSERT (film); + FrameRateChange frc (audio_video_frame_rate(), film->video_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -227,8 +201,7 @@ AudioContent::resampled_audio_frame_rate () const string AudioContent::processing_description () const { - vector<AudioStreamPtr> streams = audio_streams (); - if (streams.empty ()) { + if (streams().empty ()) { return ""; } @@ -244,7 +217,7 @@ AudioContent::processing_description () const bool same = true; optional<int> common_frame_rate; - BOOST_FOREACH (AudioStreamPtr i, streams) { + BOOST_FOREACH (AudioStreamPtr i, streams()) { if (i->frame_rate() != resampled_audio_frame_rate()) { resampled = true; } else { @@ -280,7 +253,7 @@ AudioContent::processing_description () const bool AudioContent::has_rate_above_48k () const { - BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr i, streams ()) { if (i->frame_rate() > 48000) { return true; } @@ -296,7 +269,7 @@ AudioContent::audio_channel_names () const vector<string> n; int t = 1; - BOOST_FOREACH (AudioStreamPtr i, audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr i, streams ()) { for (int j = 0; j < i->channels(); ++j) { n.push_back (String::compose ("%1:%2", t, j + 1)); } @@ -310,8 +283,8 @@ void AudioContent::add_properties (list<UserProperty>& p) const { shared_ptr<const AudioStream> stream; - if (audio_streams().size() == 1) { - stream = audio_streams().front (); + if (streams().size() == 1) { + stream = streams().front (); } if (stream) { @@ -319,8 +292,11 @@ AudioContent::add_properties (list<UserProperty>& p) const p.push_back (UserProperty (_("Audio"), _("Content audio frame rate"), stream->frame_rate(), _("Hz"))); } - FrameRateChange const frc (audio_video_frame_rate(), film()->video_frame_rate()); - ContentTime const c (full_length(), frc); + shared_ptr<const Film> film = _film.lock (); + DCPOMATIC_ASSERT (film); + + FrameRateChange const frc (audio_video_frame_rate(), film->video_frame_rate()); + ContentTime const c (_parent->full_length(), frc); p.push_back ( UserProperty (_("Length"), _("Full length in video frames at content rate"), c.frames_round(frc.source)) @@ -376,3 +352,44 @@ AudioContent::audio_video_frame_rate () const */ return film()->active_frame_rate_change(position()).source; } + +AudioContent::set_streams (vector<AudioStreamPtr> streams) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _streams = streams; + } + + _parent->signal_changed (AudioContentProperty::AUDIO_STREAMS); +} + +AudioStreamPtr +AudioContent::stream () const +{ + boost::mutex::scoped_lock lm (_mutex); + DCPOMATIC_ASSERT (_streams.size() == 1); + return _streams.front (); +} + +void +AudioContent::add_stream (AudioStreamPtr stream) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _streams.push_back (stream); + } + + _parent->signal_changed (AudioContentProperty::AUDIO_STREAMS); +} + +void +AudioContent::set_stream (AudioStreamPtr stream) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _streams.clear (); + _streams.push_back (stream); + } + + _parent->signal_changed (AudioContentProperty::AUDIO_STREAMS); +} diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index ac91da595..3aa9678b0 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -24,7 +24,7 @@ #ifndef DCPOMATIC_AUDIO_CONTENT_H #define DCPOMATIC_AUDIO_CONTENT_H -#include "content.h" +#include "content_part.h" #include "audio_stream.h" #include "audio_mapping.h" @@ -40,23 +40,16 @@ public: static int const AUDIO_VIDEO_FRAME_RATE; }; -/** @class AudioContent - * @brief Parent class for content which may contain audio data. - */ -class AudioContent : public virtual Content +class AudioContent : public ContentPart { public: - AudioContent (boost::shared_ptr<const Film>); - AudioContent (boost::shared_ptr<const Film>, DCPTime); - AudioContent (boost::shared_ptr<const Film>, boost::filesystem::path); - AudioContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr); - AudioContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >); + AudioContent (Content* parent, boost::shared_ptr<const Film>); + AudioContent (Content* parent, boost::shared_ptr<const Film>, cxml::ConstNodePtr); + AudioContent (Content* parent, boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >); void as_xml (xmlpp::Node *) const; std::string technical_summary () const; - virtual std::vector<AudioStreamPtr> audio_streams () const = 0; - AudioMapping audio_mapping () const; void set_audio_mapping (AudioMapping); int resampled_audio_frame_rate () const; @@ -81,16 +74,26 @@ public: std::string processing_description () const; -protected: + std::vector<AudioStreamPtr> streams () const { + boost::mutex::scoped_lock lm (_mutex); + return _streams; + } + + void add_stream (AudioStreamPtr stream); + void set_stream (AudioStreamPtr stream); + void set_streams (std::vector<AudioStreamPtr> streams); + AudioStreamPtr stream () const; void add_properties (std::list<UserProperty> &) const; private: + /** Gain to apply to audio in dB */ double _audio_gain; /** Delay to apply to audio (positive moves audio later) in milliseconds */ int _audio_delay; boost::optional<double> _audio_video_frame_rate; + std::vector<AudioStreamPtr> _streams; }; #endif diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 2944357ba..705fdbef1 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,13 +30,13 @@ using std::cout; using std::map; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content, bool fast) +AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content, bool fast, shared_ptr<Log> log) : _audio_content (content) , _ignore_audio (false) , _fast (fast) { - BOOST_FOREACH (AudioStreamPtr i, content->audio_streams ()) { - _streams[i] = shared_ptr<AudioDecoderStream> (new AudioDecoderStream (_audio_content, i, this)); + BOOST_FOREACH (AudioStreamPtr i, content->streams ()) { + _streams[i] = shared_ptr<AudioDecoderStream> (new AudioDecoderStream (_audio_content, i, this, log)); } } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 716b37969..679cdd5c5 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ class AudioBuffers; class AudioContent; class AudioDecoderStream; +class Log; /** @class AudioDecoder. * @brief Parent class for audio decoders. @@ -39,7 +40,7 @@ class AudioDecoderStream; class AudioDecoder : public virtual Decoder, public boost::enable_shared_from_this<AudioDecoder> { public: - AudioDecoder (boost::shared_ptr<const AudioContent>, bool fast); + AudioDecoder (boost::shared_ptr<const AudioContent>, bool fast, boost::shared_ptr<Log> log); boost::shared_ptr<const AudioContent> audio_content () const { return _audio_content; diff --git a/src/lib/audio_decoder_stream.cc b/src/lib/audio_decoder_stream.cc index cb0372231..7037d9f47 100644 --- a/src/lib/audio_decoder_stream.cc +++ b/src/lib/audio_decoder_stream.cc @@ -39,10 +39,11 @@ using std::max; using boost::optional; using boost::shared_ptr; -AudioDecoderStream::AudioDecoderStream (shared_ptr<const AudioContent> content, AudioStreamPtr stream, AudioDecoder* decoder) +AudioDecoderStream::AudioDecoderStream (shared_ptr<const AudioContent> content, AudioStreamPtr stream, AudioDecoder* decoder, shared_ptr<Log> log) : _content (content) , _stream (stream) , _decoder (decoder) + , _log (log) { if (content->resampled_audio_frame_rate() != _stream->frame_rate() && _stream->channels() > 0) { _resampler.reset (new Resampler (_stream->frame_rate(), content->resampled_audio_frame_rate(), _stream->channels (), decoder->fast ())); @@ -62,7 +63,7 @@ AudioDecoderStream::get (Frame frame, Frame length, bool accurate) { shared_ptr<ContentAudio> dec; - _content->film()->log()->log (String::compose ("-> ADS has request for %1 %2", frame, length), LogEntry::TYPE_DEBUG_DECODE); + _log->log (String::compose ("-> ADS has request for %1 %2", frame, length), LogEntry::TYPE_DEBUG_DECODE); Frame const end = frame + length - 1; @@ -93,7 +94,7 @@ AudioDecoderStream::get (Frame frame, Frame length, bool accurate) decoded_offset = frame - _decoded.frame; - _content->film()->log()->log ( + _log->log ( String::compose ("Accurate ADS::get has offset %1 from request %2 and available %3", decoded_offset, frame, _decoded.frame), LogEntry::TYPE_DEBUG_DECODE ); @@ -141,7 +142,7 @@ AudioDecoderStream::get (Frame frame, Frame length, bool accurate) void AudioDecoderStream::audio (shared_ptr<const AudioBuffers> data, ContentTime time) { - _content->film()->log()->log (String::compose ("ADS receives %1 %2", time, data->frames ()), LogEntry::TYPE_DEBUG_DECODE); + _log->log (String::compose ("ADS receives %1 %2", time, data->frames ()), LogEntry::TYPE_DEBUG_DECODE); if (_resampler) { data = _resampler->run (data); diff --git a/src/lib/audio_decoder_stream.h b/src/lib/audio_decoder_stream.h index 3503a46d1..90269a0f4 100644 --- a/src/lib/audio_decoder_stream.h +++ b/src/lib/audio_decoder_stream.h @@ -28,11 +28,12 @@ class AudioContent; class AudioDecoder; class Resampler; +class Log; class AudioDecoderStream { public: - AudioDecoderStream (boost::shared_ptr<const AudioContent>, AudioStreamPtr, AudioDecoder* decoder); + AudioDecoderStream (boost::shared_ptr<const AudioContent>, AudioStreamPtr, AudioDecoder* decoder, boost::shared_ptr<Log> log); ContentAudio get (Frame time, Frame length, bool accurate); void audio (boost::shared_ptr<const AudioBuffers>, ContentTime); @@ -47,6 +48,7 @@ private: boost::shared_ptr<const AudioContent> _content; AudioStreamPtr _stream; AudioDecoder* _decoder; + boost::shared_ptr<Log> _log; boost::shared_ptr<Resampler> _resampler; boost::optional<Frame> _position; /** Currently-available decoded audio data */ diff --git a/src/lib/audio_stream.h b/src/lib/audio_stream.h index 506a3c02d..8d05df268 100644 --- a/src/lib/audio_stream.h +++ b/src/lib/audio_stream.h @@ -30,6 +30,7 @@ class AudioStream public: AudioStream (int frame_rate, int channels); AudioStream (int frame_rate, AudioMapping mapping); + virtual ~AudioStream () {} void set_mapping (AudioMapping mapping); diff --git a/src/lib/content.cc b/src/lib/content.cc index 28103e9c0..499f90dd1 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -155,6 +155,7 @@ Content::examine (shared_ptr<Job> job) void Content::signal_changed (int p) { + changed (p); emit (boost::bind (boost::ref (Changed), shared_from_this (), p, _change_signals_frequent)); } diff --git a/src/lib/content.h b/src/lib/content.h index f488962b3..60dd89b97 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -93,6 +93,8 @@ public: */ virtual std::list<DCPTime> reel_split_points () const; + virtual void changed (int) {} + boost::shared_ptr<Content> clone () const; void set_path (boost::filesystem::path); @@ -167,6 +169,7 @@ public: boost::signals2::signal<void (boost::weak_ptr<Content>, int, bool)> Changed; boost::shared_ptr<VideoContent> video; + boost::shared_ptr<AudioContent> audio; boost::shared_ptr<SubtitleContent> subtitle; void signal_changed (int); diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index a81a152c1..cfd19fe31 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -19,6 +19,7 @@ #include "dcp_content.h" #include "video_content.h" +#include "audio_content.h" #include "dcp_examiner.h" #include "job.h" #include "film.h" @@ -55,7 +56,6 @@ int const DCPContentProperty::REFERENCE_SUBTITLE = 603; DCPContent::DCPContent (shared_ptr<const Film> film, boost::filesystem::path p) : Content (film) - , AudioContent (film) , _has_subtitles (false) , _encrypted (false) , _kdm_valid (false) @@ -64,6 +64,7 @@ DCPContent::DCPContent (shared_ptr<const Film> film, boost::filesystem::path p) , _reference_subtitle (false) { video.reset (new VideoContent (this, film)); + audio.reset (new AudioContent (this, film)); subtitle.reset (new SubtitleContent (this, film)); read_directory (p); @@ -72,10 +73,14 @@ DCPContent::DCPContent (shared_ptr<const Film> film, boost::filesystem::path p) DCPContent::DCPContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version) : Content (film, node) - , AudioContent (film, node) - , _audio_stream (new AudioStream (node->number_child<int> ("AudioFrameRate"), AudioMapping (node->node_child ("AudioMapping"), version))) { video.reset (new VideoContent (this, film, node, version)); + audio.reset (new AudioContent (this, film, node)); + audio->set_stream ( + AudioStreamPtr ( + new AudioStream (node->number_child<int> ("AudioFrameRate"), AudioMapping (node->node_child ("AudioMapping"), version)) + ) + ); subtitle.reset (new SubtitleContent (this, film, node, version)); _name = node->string_child ("Name"); @@ -116,10 +121,12 @@ DCPContent::examine (shared_ptr<Job> job) { boost::mutex::scoped_lock lm (_mutex); - _audio_stream.reset (new AudioStream (examiner->audio_frame_rate(), examiner->audio_channels ())); - AudioMapping m = _audio_stream->mapping (); + + AudioStreamPtr as (new AudioStream (examiner->audio_frame_rate(), examiner->audio_channels ())); + audio->set_stream (as); + AudioMapping m = as->mapping (); film()->make_audio_mapping_default (m); - _audio_stream->set_mapping (m); + as->set_mapping (m); } signal_changed (AudioContentProperty::AUDIO_STREAMS); @@ -149,7 +156,7 @@ DCPContent::technical_summary () const { return Content::technical_summary() + " - " + video->technical_summary() + " - " - + AudioContent::technical_summary() + " - "; + + audio->technical_summary() + " - "; } void @@ -159,9 +166,9 @@ DCPContent::as_xml (xmlpp::Node* node) const Content::as_xml (node); video->as_xml (node); - AudioContent::as_xml (node); - node->add_child("AudioFrameRate")->add_child_text (raw_convert<string> (audio_stream()->frame_rate ())); - audio_stream()->mapping().as_xml (node->add_child("AudioMapping")); + audio->as_xml (node); + node->add_child("AudioFrameRate")->add_child_text (raw_convert<string> (audio->stream()->frame_rate())); + audio->stream()->mapping().as_xml (node->add_child("AudioMapping")); subtitle->as_xml (node); boost::mutex::scoped_lock lm (_mutex); @@ -226,7 +233,7 @@ DCPContent::directory () const void DCPContent::add_properties (list<UserProperty>& p) const { - AudioContent::add_properties (p); + audio->add_properties (p); } void @@ -337,15 +344,8 @@ DCPContent::can_reference_video (list<string>& why_not) const bool DCPContent::can_reference_audio (list<string>& why_not) const { - DCPDecoder decoder (shared_from_this(), film()->log(), false); - BOOST_FOREACH (shared_ptr<dcp::Reel> i, decoder.reels()) { - if (!i->main_sound()) { - why_not.push_back (_("The DCP does not have sound in all reels.")); - return false; - } - } - - return can_reference<AudioContent> (_("There is other audio content overlapping this DCP; remove it."), why_not); + /* XXX: this needs to be fixed */ + return true; } bool @@ -355,16 +355,10 @@ DCPContent::can_reference_subtitle (list<string>& why_not) const return true; } -double -DCPContent::subtitle_video_frame_rate () const -{ - return video->video_frame_rate (); -} - -vector<AudioStreamPtr> -DCPContent::audio_streams () const +void +DCPContent::changed (int property) { - vector<AudioStreamPtr> s; - s.push_back (_audio_stream); - return s; + if (property == VideoContentProperty::VIDEO_FRAME_RATE && subtitle) { + subtitle->set_subtitle_video_frame_rate (video->video_frame_rate ()); + } } diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h index f3cd6bf65..b2bc90ebd 100644 --- a/src/lib/dcp_content.h +++ b/src/lib/dcp_content.h @@ -24,7 +24,7 @@ * @brief DCPContent class. */ -#include "audio_content.h" +#include "content.h" #include <libcxml/cxml.h> #include <dcp/encrypted_kdm.h> @@ -40,7 +40,7 @@ public: /** @class DCPContent * @brief An existing DCP used as input. */ -class DCPContent : public AudioContent +class DCPContent : public Content { public: DCPContent (boost::shared_ptr<const Film>, boost::filesystem::path p); @@ -65,8 +65,6 @@ public: void set_default_colour_conversion (); std::list<DCPTime> reel_split_points () const; - /* SubtitleContent */ - bool has_text_subtitles () const { boost::mutex::scoped_lock lm (_mutex); return _has_subtitles; @@ -76,7 +74,7 @@ public: return false; } - double subtitle_video_frame_rate () const; + void changed (int property); boost::filesystem::path directory () const; @@ -120,16 +118,9 @@ public: bool can_reference_subtitle (std::list<std::string> &) const; - std::vector<AudioStreamPtr> audio_streams () const; - - AudioStreamPtr audio_stream () const { - return _audio_stream; - } - -protected: +private: void add_properties (std::list<UserProperty>& p) const; -private: void read_directory (boost::filesystem::path); std::list<DCPTimePeriod> reels () const; template <class T> bool can_reference (std::string overlapping, std::list<std::string>& why_not) const; @@ -153,8 +144,6 @@ private: * rather than by rewrapping. */ bool _reference_subtitle; - - boost::shared_ptr<AudioStream> _audio_stream; }; #endif diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index f032ee661..4e28dc758 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "dcp_decoder.h" #include "dcp_content.h" +#include "audio_content.h" #include "j2k_image_proxy.h" #include "image.h" #include "config.h" @@ -44,7 +45,7 @@ using boost::dynamic_pointer_cast; DCPDecoder::DCPDecoder (shared_ptr<const DCPContent> c, shared_ptr<Log> log, bool fast) : VideoDecoder (c->video, log) - , AudioDecoder (c, fast) + , AudioDecoder (c->audio, fast, log) , SubtitleDecoder (c->subtitle) , _dcp_content (c) { @@ -103,7 +104,7 @@ DCPDecoder::pass (PassReason reason, bool) shared_ptr<const dcp::SoundFrame> sf = (*_reel)->main_sound()->asset()->get_frame (entry_point + frame); uint8_t const * from = sf->data (); - int const channels = _dcp_content->audio_stream()->channels (); + int const channels = _dcp_content->audio->stream()->channels (); int const frames = sf->size() / (3 * channels); shared_ptr<AudioBuffers> data (new AudioBuffers (channels, frames)); for (int i = 0; i < frames; ++i) { @@ -113,7 +114,7 @@ DCPDecoder::pass (PassReason reason, bool) } } - audio (_dcp_content->audio_stream(), data, ContentTime::from_frames (offset, vfr) + _next); + audio (_dcp_content->audio->stream(), data, ContentTime::from_frames (offset, vfr) + _next); } if ((*_reel)->main_subtitle ()) { diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc index b38c0c6a7..3feb8947a 100644 --- a/src/lib/dcp_subtitle_content.cc +++ b/src/lib/dcp_subtitle_content.cc @@ -44,7 +44,6 @@ DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, boost::file DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version) : Content (film, node) , _length (node->number_child<ContentTime::Type> ("Length")) - , _frame_rate (node->optional_number_child<int>("SubtitleFrameRate")) { subtitle.reset (new SubtitleContent (this, film, node, version)); } @@ -68,7 +67,7 @@ DCPSubtitleContent::examine (shared_ptr<Job> job) shared_ptr<dcp::SMPTESubtitleAsset> smpte = dynamic_pointer_cast<dcp::SMPTESubtitleAsset> (sc); if (smpte) { subtitle->set_subtitle_language (smpte->language().get_value_or ("")); - _frame_rate = smpte->edit_rate().numerator; + subtitle->set_subtitle_video_frame_rate (smpte->edit_rate().numerator); } _length = ContentTime::from_seconds (sc->latest_subtitle_out().as_seconds ()); @@ -81,7 +80,7 @@ DCPSubtitleContent::examine (shared_ptr<Job> job) DCPTime DCPSubtitleContent::full_length () const { - FrameRateChange const frc (subtitle_video_frame_rate(), film()->video_frame_rate()); + FrameRateChange const frc (subtitle->subtitle_video_frame_rate(), film()->video_frame_rate()); return DCPTime (_length, frc); } @@ -105,30 +104,3 @@ DCPSubtitleContent::as_xml (xmlpp::Node* node) const subtitle->as_xml (node); node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ())); } - -void -DCPSubtitleContent::set_subtitle_video_frame_rate (int r) -{ - { - boost::mutex::scoped_lock lm (_mutex); - _frame_rate = r; - } - - signal_changed (SubtitleContentProperty::SUBTITLE_VIDEO_FRAME_RATE); -} - -double -DCPSubtitleContent::subtitle_video_frame_rate () const -{ - { - boost::mutex::scoped_lock lm (_mutex); - if (_frame_rate) { - return _frame_rate.get (); - } - } - - /* No frame rate specified, so assume this content has been - prepared for any concurrent video content. - */ - return film()->active_frame_rate_change(position()).source; -} diff --git a/src/lib/dcp_subtitle_content.h b/src/lib/dcp_subtitle_content.h index de9fa68ec..211765796 100644 --- a/src/lib/dcp_subtitle_content.h +++ b/src/lib/dcp_subtitle_content.h @@ -43,11 +43,6 @@ public: return false; } - double subtitle_video_frame_rate () const; - void set_subtitle_video_frame_rate (int r); - private: ContentTime _length; - /** Video frame rate that this content has been prepared for, if known */ - boost::optional<double> _frame_rate; }; diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index f276a16a3..c67d643a5 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -19,6 +19,7 @@ #include "ffmpeg_content.h" #include "video_content.h" +#include "audio_content.h" #include "ffmpeg_examiner.h" #include "ffmpeg_subtitle_stream.h" #include "ffmpeg_audio_stream.h" @@ -62,9 +63,9 @@ int const FFmpegContentProperty::FILTERS = 102; FFmpegContent::FFmpegContent (shared_ptr<const Film> film, boost::filesystem::path p) : Content (film, p) - , AudioContent (film, p) { video.reset (new VideoContent (this, film)); + audio.reset (new AudioContent (this, film)); subtitle.reset (new SubtitleContent (this, film)); set_default_colour_conversion (); @@ -72,9 +73,9 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, boost::filesystem::pa FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version, list<string>& notes) : Content (film, node) - , AudioContent (film, node) { video.reset (new VideoContent (this, film, node, version)); + audio.reset (new AudioContent (this, film, node)); subtitle.reset (new SubtitleContent (this, film, node, version)); list<cxml::NodePtr> c = node->node_children ("SubtitleStream"); @@ -87,10 +88,11 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr no c = node->node_children ("AudioStream"); for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) { - _audio_streams.push_back (shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (*i, version))); + shared_ptr<FFmpegAudioStream> as (new FFmpegAudioStream (*i, version)); + audio->add_stream (as); if (version < 11 && !(*i)->optional_node_child ("Selected")) { /* This is an old file and this stream is not selected, so un-map it */ - _audio_streams.back()->set_mapping (AudioMapping (_audio_streams.back()->channels (), MAX_DCP_AUDIO_CHANNELS)); + as->set_mapping (AudioMapping (_audio_streams.back()->channels (), MAX_DCP_AUDIO_CHANNELS)); } } @@ -121,9 +123,9 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr no FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<boost::shared_ptr<Content> > c) : Content (film, c) - , AudioContent (film, c) { video.reset (new VideoContent (this, film, c)); + audio.reset (new AudioContent (this, film, c)); subtitle.reset (new SubtitleContent (this, film, c)); shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]); @@ -140,7 +142,6 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<boost::shared_ _subtitle_streams = ref->subtitle_streams (); _subtitle_stream = ref->subtitle_stream (); - _audio_streams = ref->ffmpeg_audio_streams (); _first_video = ref->_first_video; _filters = ref->_filters; _color_range = ref->_color_range; @@ -156,7 +157,7 @@ FFmpegContent::as_xml (xmlpp::Node* node) const node->add_child("Type")->add_child_text ("FFmpeg"); Content::as_xml (node); video->as_xml (node); - AudioContent::as_xml (node); + audio->as_xml (node); subtitle->as_xml (node); boost::mutex::scoped_lock lm (_mutex); @@ -169,8 +170,10 @@ FFmpegContent::as_xml (xmlpp::Node* node) const (*i)->as_xml (t); } - for (vector<shared_ptr<FFmpegAudioStream> >::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { - (*i)->as_xml (node->add_child("AudioStream")); + BOOST_FOREACH (AudioStreamPtr i, audio->streams ()) { + shared_ptr<FFmpegAudioStream> f = dynamic_pointer_cast<FFmpegAudioStream> (i); + DCPOMATIC_ASSERT (f); + f->as_xml (node->add_child("AudioStream")); } for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { @@ -209,12 +212,15 @@ FFmpegContent::examine (shared_ptr<Job> job) _subtitle_stream = _subtitle_streams.front (); } - _audio_streams = examiner->audio_streams (); + BOOST_FOREACH (shared_ptr<FFmpegAudioStream> i, examiner->audio_streams ()) { + audio->add_stream (i); + } - if (!_audio_streams.empty ()) { - AudioMapping m = _audio_streams.front()->mapping (); + if (!audio->streams().empty ()) { + AudioStreamPtr as = audio->streams().front(); + AudioMapping m = as->mapping (); film()->make_audio_mapping_default (m); - _audio_streams.front()->set_mapping (m); + as->set_mapping (m); } _first_video = examiner->first_video (); @@ -228,7 +234,6 @@ FFmpegContent::examine (shared_ptr<Job> job) signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS); signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); - signal_changed (AudioContentProperty::AUDIO_STREAMS); } string @@ -259,7 +264,7 @@ FFmpegContent::technical_summary () const return Content::technical_summary() + " - " + video->technical_summary() + " - " - + AudioContent::technical_summary() + " - " + + audio->technical_summary() + " - " + String::compose ( "ffmpeg: audio %1 subtitle %2 filters %3", as, ss, filt ); @@ -403,7 +408,7 @@ FFmpegContent::add_properties (list<UserProperty>& p) const { Content::add_properties (p); video->add_properties (p); - AudioContent::add_properties (p); + audio->add_properties (p); if (_bits_per_pixel) { int const sub = 219 * pow (2, _bits_per_pixel.get() - 8); @@ -528,8 +533,10 @@ FFmpegContent::signal_subtitle_stream_changed () signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); } -double -FFmpegContent::subtitle_video_frame_rate () const +void +FFmpegContent::changed (int property) { - return video->video_frame_rate (); + if (property == VideoContentProperty::VIDEO_FRAME_RATE && subtitle) { + subtitle->set_subtitle_video_frame_rate (video->video_frame_rate ()); + } } diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index da0eb48af..f39414a61 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -20,7 +20,8 @@ #ifndef DCPOMATIC_FFMPEG_CONTENT_H #define DCPOMATIC_FFMPEG_CONTENT_H -#include "audio_content.h" +#include "content.h" +#include "audio_stream.h" struct AVFormatContext; struct AVStream; @@ -41,7 +42,7 @@ public: static int const FILTERS; }; -class FFmpegContent : public AudioContent +class FFmpegContent : public Content { public: FFmpegContent (boost::shared_ptr<const Film>, boost::filesystem::path); @@ -60,19 +61,17 @@ public: std::string identifier () const; - /* VideoContent */ void set_default_colour_conversion (); - /* AudioContent */ std::vector<AudioStreamPtr> audio_streams () const; - /* SubtitleContent */ bool has_text_subtitles () const; bool has_image_subtitles () const; - double subtitle_video_frame_rate () const; void set_filters (std::vector<Filter const *> const &); + void changed (int property); + std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_streams; @@ -105,10 +104,9 @@ public: void signal_subtitle_stream_changed (); -protected: +private: void add_properties (std::list<UserProperty> &) const; -private: friend struct ffmpeg_pts_offset_test; friend struct audio_sampling_rate_test; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 15cc9b256..8e4a1cc23 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -73,7 +73,7 @@ using dcp::Size; FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log, bool fast) : VideoDecoder (c->video, log) - , AudioDecoder (c, fast) + , AudioDecoder (c->audio, fast, log) , SubtitleDecoder (c->subtitle) , FFmpeg (c) , _log (log) diff --git a/src/lib/film.cc b/src/lib/film.cc index 7d319fc1e..49a0a9b13 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -245,13 +245,12 @@ Film::audio_analysis_path (shared_ptr<const Playlist> playlist) const MD5Digester digester; BOOST_FOREACH (shared_ptr<Content> i, playlist->content ()) { - shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (i); - if (!ac) { + if (!i->audio) { continue; } - digester.add (ac->digest ()); - digester.add (ac->audio_mapping().digest ()); + digester.add (i->digest ()); + digester.add (i->audio->audio_mapping().digest ()); if (playlist->content().size() != 1) { /* Analyses should be considered equal regardless of gain if they were made from just one piece of content. This @@ -259,7 +258,7 @@ Film::audio_analysis_path (shared_ptr<const Playlist> playlist) const analysis at the plotting stage rather than having to recompute it. */ - digester.add (ac->audio_gain ()); + digester.add (i->audio->audio_gain ()); } } @@ -505,9 +504,8 @@ Film::mapped_audio_channels () const } } else { BOOST_FOREACH (shared_ptr<Content> i, content ()) { - shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (i); - if (ac) { - list<int> c = ac->audio_mapping().mapped_output_channels (); + if (i->audio) { + list<int> c = i->audio->mapping().mapped_output_channels (); copy (c.begin(), c.end(), back_inserter (mapped)); } } @@ -639,12 +637,11 @@ Film::isdcf_name (bool if_created_now) const bool burnt_in = true; BOOST_FOREACH (shared_ptr<Content> i, content ()) { - shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (i); - if (!sc) { + if (!i->subtitle) { continue; } - if (sc->use_subtitles() && !sc->burn_subtitles()) { + if (i->subtitle->use_subtitles() && !i->subtitle->burn_subtitles()) { burnt_in = false; } } @@ -1033,7 +1030,7 @@ Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c) } add_content (content); - if (Config::instance()->automatic_audio_analysis() && dynamic_pointer_cast<AudioContent> (content)) { + if (Config::instance()->automatic_audio_analysis() && content->audio) { shared_ptr<Playlist> playlist (new Playlist); playlist->add (content); boost::signals2::connection c; @@ -1050,7 +1047,7 @@ Film::add_content (shared_ptr<Content> c) /* Add {video,subtitle} content after any existing {video,subtitle} content */ if (c->video) { c->set_position (_playlist->video_end ()); - } else if (dynamic_pointer_cast<SubtitleContent> (c)) { + } else if (c->subtitle) { c->set_position (_playlist->subtitle_end ()); } @@ -1125,8 +1122,7 @@ int Film::audio_frame_rate () const { BOOST_FOREACH (shared_ptr<Content> i, content ()) { - shared_ptr<AudioContent> a = dynamic_pointer_cast<AudioContent> (i); - if (a && a->has_rate_above_48k ()) { + if (i->audio && i->audio->has_rate_above_48k ()) { return 96000; } } @@ -1271,9 +1267,8 @@ Film::subtitle_language () const ContentList cl = content (); BOOST_FOREACH (shared_ptr<Content>& c, cl) { - shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (c); - if (sc) { - languages.insert (sc->subtitle_language ()); + if (c->subtitle) { + languages.insert (c->subtitle->subtitle_language ()); } } diff --git a/src/lib/player.cc b/src/lib/player.cc index 9c216c253..ce048ed79 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include "film.h" #include "ffmpeg_decoder.h" #include "audio_buffers.h" +#include "audio_content.h" #include "ffmpeg_content.h" #include "image_decoder.h" #include "image_content.h" @@ -143,7 +144,7 @@ Player::setup_pieces () /* SndfileContent */ shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (i); if (sc) { - decoder.reset (new SndfileDecoder (sc, _fast)); + decoder.reset (new SndfileDecoder (sc, _fast, _film->log())); /* Work out a FrameRateChange for the best overlap video for this content */ DCPTime best_overlap_t; @@ -177,14 +178,14 @@ Player::setup_pieces () shared_ptr<const TextSubtitleContent> rc = dynamic_pointer_cast<const TextSubtitleContent> (i); if (rc) { decoder.reset (new TextSubtitleDecoder (rc)); - frc = FrameRateChange (rc->subtitle_video_frame_rate(), _film->video_frame_rate()); + frc = FrameRateChange (rc->subtitle->subtitle_video_frame_rate(), _film->video_frame_rate()); } /* DCPSubtitleContent */ shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (i); if (dsc) { decoder.reset (new DCPSubtitleDecoder (dsc)); - frc = FrameRateChange (dsc->subtitle_video_frame_rate(), _film->video_frame_rate()); + frc = FrameRateChange (dsc->subtitle->subtitle_video_frame_rate(), _film->video_frame_rate()); } shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (decoder); @@ -480,9 +481,8 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) bool all_referenced = true; BOOST_FOREACH (shared_ptr<Piece> i, ov) { - shared_ptr<AudioContent> audio_content = dynamic_pointer_cast<AudioContent> (i->content); shared_ptr<DCPContent> dcp_content = dynamic_pointer_cast<DCPContent> (i->content); - if (audio_content && (!dcp_content || !dcp_content->reference_audio ())) { + if (i->content->audio && (!dcp_content || !dcp_content->reference_audio ())) { /* There is audio content which is not from a DCP or not set to be referenced */ all_referenced = false; } @@ -494,13 +494,12 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) BOOST_FOREACH (shared_ptr<Piece> i, ov) { - shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (i->content); - DCPOMATIC_ASSERT (content); + DCPOMATIC_ASSERT (i->content->audio); shared_ptr<AudioDecoder> decoder = dynamic_pointer_cast<AudioDecoder> (i->decoder); DCPOMATIC_ASSERT (decoder); /* The time that we should request from the content */ - DCPTime request = time - DCPTime::from_seconds (content->audio_delay() / 1000.0); + DCPTime request = time - DCPTime::from_seconds (i->content->audio->audio_delay() / 1000.0); Frame request_frames = length_frames; DCPTime offset; if (request < DCPTime ()) { @@ -517,7 +516,7 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) Frame const content_frame = dcp_to_resampled_audio (i, request); - BOOST_FOREACH (AudioStreamPtr j, content->audio_streams ()) { + BOOST_FOREACH (AudioStreamPtr j, i->content->audio->streams ()) { if (j->channels() == 0) { /* Some content (e.g. DCPs) can have streams with no channels */ @@ -528,9 +527,9 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) ContentAudio all = decoder->get_audio (j, content_frame, request_frames, accurate); /* Gain */ - if (content->audio_gain() != 0) { + if (i->content->audio->audio_gain() != 0) { shared_ptr<AudioBuffers> gain (new AudioBuffers (all.audio)); - gain->apply_gain (content->audio_gain ()); + gain->apply_gain (i->content->audio->audio_gain ()); all.audio = gain; } @@ -572,7 +571,6 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate) Frame Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const { - shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (piece->content); DCPTime s = t - piece->content->position (); s = min (piece->content->length_after_trim(), s); s = max (DCPTime(), s + DCPTime (piece->content->trim_start(), piece->frc)); @@ -590,7 +588,6 @@ Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const DCPTime Player::content_video_to_dcp (shared_ptr<const Piece> piece, Frame f) const { - shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (piece->content); /* See comment in dcp_to_content_video */ DCPTime const d = DCPTime::from_frames (f * piece->frc.factor(), piece->frc.dcp) - DCPTime (piece->content->trim_start (), piece->frc); return max (DCPTime (), d + piece->content->position ()); @@ -704,12 +701,11 @@ Player::get_subtitle_fonts () list<shared_ptr<Font> > fonts; BOOST_FOREACH (shared_ptr<Piece>& p, _pieces) { - shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (p->content); - if (sc) { + if (p->content->subtitle) { /* XXX: things may go wrong if there are duplicate font IDs with different font files. */ - list<shared_ptr<Font> > f = sc->fonts (); + list<shared_ptr<Font> > f = p->content->subtitle->fonts (); copy (f.begin(), f.end(), back_inserter (fonts)); } } diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 645993050..092060fa0 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -150,12 +150,8 @@ Playlist::video_identifier () const string t; BOOST_FOREACH (shared_ptr<const Content> i, _content) { - shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (i); - shared_ptr<const SubtitleContent> sc = dynamic_pointer_cast<const SubtitleContent> (i); - if (vc) { - t += vc->identifier (); - } else if (sc && sc->burn_subtitles ()) { - t += sc->identifier (); + if (i->video || (i->subtitle && i->subtitle->burn_subtitles())) { + t += i->identifier (); } } @@ -346,7 +342,7 @@ Playlist::video_end () const { DCPTime end; BOOST_FOREACH (shared_ptr<Content> i, _content) { - if (dynamic_pointer_cast<const VideoContent> (i)) { + if (i->video) { end = max (end, i->end ()); } } @@ -359,7 +355,7 @@ Playlist::subtitle_end () const { DCPTime end; BOOST_FOREACH (shared_ptr<Content> i, _content) { - if (dynamic_pointer_cast<const SubtitleContent> (i)) { + if (i->subtitle) { end = max (end, i->end ()); } } diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index d8435613d..d023b27d6 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -20,6 +20,7 @@ #include "sndfile_content.h" #include "sndfile_decoder.h" #include "sndfile_examiner.h" +#include "audio_content.h" #include "film.h" #include "compose.hpp" #include "job.h" @@ -39,18 +40,19 @@ using boost::shared_ptr; SndfileContent::SndfileContent (shared_ptr<const Film> film, boost::filesystem::path p) : Content (film, p) - , AudioContent (film, p) { - + audio.reset (new AudioContent (this, film)); } SndfileContent::SndfileContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version) : Content (film, node) - , AudioContent (film, node) , _audio_length (node->number_child<Frame> ("AudioLength")) - , _audio_stream (new AudioStream (node->number_child<int> ("AudioFrameRate"), AudioMapping (node->node_child ("AudioMapping"), version))) { - + audio.reset (new AudioContent (this, film, node)); + audio->set_stream ( + AudioStreamPtr ( + new AudioStream (node->number_child<int> ("AudioFrameRate"), AudioMapping (node->node_child ("AudioMapping"), version))) + ); } void @@ -58,9 +60,9 @@ SndfileContent::as_xml (xmlpp::Node* node) const { node->add_child("Type")->add_child_text ("Sndfile"); Content::as_xml (node); - AudioContent::as_xml (node); - node->add_child("AudioFrameRate")->add_child_text (raw_convert<string> (audio_stream()->frame_rate ())); - audio_stream()->mapping().as_xml (node->add_child("AudioMapping")); + audio->as_xml (node); + node->add_child("AudioFrameRate")->add_child_text (raw_convert<string> (audio->stream()->frame_rate ())); + audio->stream()->mapping().as_xml (node->add_child("AudioMapping")); node->add_child("AudioLength")->add_child_text (raw_convert<string> (audio_length ())); } @@ -76,7 +78,7 @@ string SndfileContent::technical_summary () const { return Content::technical_summary() + " - " - + AudioContent::technical_summary () + + audio->technical_summary () + " - sndfile"; } @@ -103,10 +105,11 @@ SndfileContent::take_from_audio_examiner (shared_ptr<AudioExaminer> examiner) { { boost::mutex::scoped_lock lm (_mutex); - _audio_stream.reset (new AudioStream (examiner->audio_frame_rate(), examiner->audio_channels ())); - AudioMapping m = _audio_stream->mapping (); + AudioStreamPtr as (new AudioStream (examiner->audio_frame_rate(), examiner->audio_channels ())); + audio->set_stream (as); + AudioMapping m = as->mapping (); film()->make_audio_mapping_default (m); - _audio_stream->set_mapping (m); + as->set_mapping (m); _audio_length = examiner->audio_length (); } @@ -116,14 +119,6 @@ SndfileContent::take_from_audio_examiner (shared_ptr<AudioExaminer> examiner) DCPTime SndfileContent::full_length () const { - FrameRateChange const frc (audio_video_frame_rate(), film()->video_frame_rate()); - return DCPTime::from_frames (audio_length() / frc.speed_up, audio_stream()->frame_rate ()); -} - -vector<AudioStreamPtr> -SndfileContent::audio_streams () const -{ - vector<AudioStreamPtr> s; - s.push_back (_audio_stream); - return s; + FrameRateChange const frc (audio->audio_video_frame_rate(), film->video_frame_rate()); + return DCPTime::from_frames (audio_length() / frc.speed_up, audio->stream()->frame_rate ()); } diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index 5f89b7cc8..dfd36971d 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -20,11 +20,11 @@ #ifndef DCPOMATIC_SNDFILE_CONTENT_H #define DCPOMATIC_SNDFILE_CONTENT_H -#include "audio_content.h" +#include "content.h" class AudioExaminer; -class SndfileContent : public AudioContent +class SndfileContent : public Content { public: SndfileContent (boost::shared_ptr<const Film>, boost::filesystem::path); @@ -44,12 +44,6 @@ public: void take_from_audio_examiner (boost::shared_ptr<AudioExaminer>); - std::vector<AudioStreamPtr> audio_streams () const; - - AudioStreamPtr audio_stream () const { - return _audio_stream; - } - static bool valid_file (boost::filesystem::path); private: @@ -59,8 +53,6 @@ private: } Frame _audio_length; - - boost::shared_ptr<AudioStream> _audio_stream; }; #endif diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index ac01e0da8..b05750ac8 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include <iostream> #include <sndfile.h> +#include "audio_content.h" #include "sndfile_content.h" #include "sndfile_decoder.h" #include "exceptions.h" @@ -32,9 +33,9 @@ using std::min; using std::cout; using boost::shared_ptr; -SndfileDecoder::SndfileDecoder (shared_ptr<const SndfileContent> c, bool fast) +SndfileDecoder::SndfileDecoder (shared_ptr<const SndfileContent> c, bool fast, shared_ptr<Log> log) : Sndfile (c) - , AudioDecoder (c, fast) + , AudioDecoder (c->audio, fast, log) , _done (0) , _remaining (_info.frames) , _deinterleave_buffer (0) @@ -57,14 +58,14 @@ SndfileDecoder::pass (PassReason, bool) /* Do things in half second blocks as I think there may be limits to what FFmpeg (and in particular the resampler) can cope with. */ - sf_count_t const block = _sndfile_content->audio_stream()->frame_rate() / 2; + sf_count_t const block = _sndfile_content->audio->stream()->frame_rate() / 2; sf_count_t const this_time = min (block, _remaining); - int const channels = _sndfile_content->audio_stream()->channels (); + int const channels = _sndfile_content->audio->stream()->channels (); shared_ptr<AudioBuffers> data (new AudioBuffers (channels, this_time)); - if (_sndfile_content->audio_stream()->channels() == 1) { + if (_sndfile_content->audio->stream()->channels() == 1) { /* No de-interleaving required */ sf_read_float (_sndfile, data->data(0), this_time); } else { @@ -86,7 +87,7 @@ SndfileDecoder::pass (PassReason, bool) } data->set_frames (this_time); - audio (_sndfile_content->audio_stream (), data, ContentTime::from_frames (_done, _info.samplerate)); + audio (_sndfile_content->audio->stream (), data, ContentTime::from_frames (_done, _info.samplerate)); _done += this_time; _remaining -= this_time; diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index 844d1cdc4..6f3a6cc48 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ class SndfileContent; class SndfileDecoder : public Sndfile, public AudioDecoder { public: - SndfileDecoder (boost::shared_ptr<const SndfileContent> c, bool fast); + SndfileDecoder (boost::shared_ptr<const SndfileContent> c, bool fast, boost::shared_ptr<Log> log); ~SndfileDecoder (); private: diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc index 03c188b89..089e3a3fc 100644 --- a/src/lib/subtitle_content.cc +++ b/src/lib/subtitle_content.cc @@ -24,6 +24,7 @@ #include "font.h" #include "raw_convert.h" #include "content.h" +#include "film.h" #include <libcxml/cxml.h> #include <libxml++/libxml++.h> #include <boost/foreach.hpp> @@ -85,6 +86,7 @@ SubtitleContent::SubtitleContent (Content* parent, shared_ptr<const Film> film, node->optional_number_child<int>("OutlineGreen").get_value_or(255), node->optional_number_child<int>("OutlineBlue").get_value_or(255) ) + , _frame_rate (node->optional_number_child<double>("SubtitleFrameRate")) { if (version >= 32) { _use_subtitles = node->bool_child ("UseSubtitles"); @@ -118,38 +120,37 @@ SubtitleContent::SubtitleContent (Content* parent, shared_ptr<const Film> film, SubtitleContent::SubtitleContent (Content* parent, shared_ptr<const Film> film, vector<shared_ptr<Content> > c) : ContentPart (parent, film) { - shared_ptr<SubtitleContent> ref = dynamic_pointer_cast<SubtitleContent> (c[0]); + shared_ptr<SubtitleContent> ref = c[0]->subtitle; DCPOMATIC_ASSERT (ref); list<shared_ptr<Font> > ref_fonts = ref->fonts (); - for (size_t i = 0; i < c.size(); ++i) { - shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (c[i]); + for (size_t i = 1; i < c.size(); ++i) { - if (sc->use_subtitles() != ref->use_subtitles()) { + if (c[i]->subtitle->use_subtitles() != ref->use_subtitles()) { throw JoinError (_("Content to be joined must have the same 'use subtitles' setting.")); } - if (sc->burn_subtitles() != ref->burn_subtitles()) { + if (c[i]->subtitle->burn_subtitles() != ref->burn_subtitles()) { throw JoinError (_("Content to be joined must have the same 'burn subtitles' setting.")); } - if (sc->subtitle_x_offset() != ref->subtitle_x_offset()) { + if (c[i]->subtitle->subtitle_x_offset() != ref->subtitle_x_offset()) { throw JoinError (_("Content to be joined must have the same subtitle X offset.")); } - if (sc->subtitle_y_offset() != ref->subtitle_y_offset()) { + if (c[i]->subtitle->subtitle_y_offset() != ref->subtitle_y_offset()) { throw JoinError (_("Content to be joined must have the same subtitle Y offset.")); } - if (sc->subtitle_x_scale() != ref->subtitle_x_scale()) { + if (c[i]->subtitle->subtitle_x_scale() != ref->subtitle_x_scale()) { throw JoinError (_("Content to be joined must have the same subtitle X scale.")); } - if (sc->subtitle_y_scale() != ref->subtitle_y_scale()) { + if (c[i]->subtitle->subtitle_y_scale() != ref->subtitle_y_scale()) { throw JoinError (_("Content to be joined must have the same subtitle Y scale.")); } - list<shared_ptr<Font> > fonts = sc->fonts (); + list<shared_ptr<Font> > fonts = c[i]->subtitle->fonts (); if (fonts.size() != ref_fonts.size()) { throw JoinError (_("Content to be joined must use the same fonts.")); } @@ -315,3 +316,27 @@ SubtitleContent::set_subtitle_language (string language) { maybe_set (_subtitle_language, language, SubtitleContentProperty::SUBTITLE_LANGUAGE); } + +void +SubtitleContent::set_subtitle_video_frame_rate (double r) +{ + maybe_set (_frame_rate, r, SubtitleContentProperty::SUBTITLE_VIDEO_FRAME_RATE); +} + +double +SubtitleContent::subtitle_video_frame_rate () const +{ + { + boost::mutex::scoped_lock lm (_mutex); + if (_frame_rate) { + return _frame_rate.get (); + } + } + + /* No frame rate specified, so assume this content has been + prepared for any concurrent video content. + */ + shared_ptr<const Film> film = _film.lock (); + DCPOMATIC_ASSERT (film); + return film->active_frame_rate_change(_parent->position()).source; +} diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h index 5982cc52c..0adb12c0d 100644 --- a/src/lib/subtitle_content.h +++ b/src/lib/subtitle_content.h @@ -130,6 +130,9 @@ public: return _outline_colour; } + double subtitle_video_frame_rate () const; + void set_subtitle_video_frame_rate (double r); + protected: /** subtitle language (e.g. "German") or empty if it is not known */ std::string _subtitle_language; @@ -158,6 +161,8 @@ private: bool _outline; dcp::Colour _outline_colour; std::list<boost::signals2::connection> _font_connections; + /** Video frame rate that this content has been prepared for, if known */ + boost::optional<double> _frame_rate; }; #endif diff --git a/src/lib/text_subtitle_content.cc b/src/lib/text_subtitle_content.cc index c7dd19d03..79a225c47 100644 --- a/src/lib/text_subtitle_content.cc +++ b/src/lib/text_subtitle_content.cc @@ -86,33 +86,6 @@ TextSubtitleContent::as_xml (xmlpp::Node* node) const DCPTime TextSubtitleContent::full_length () const { - FrameRateChange const frc (subtitle_video_frame_rate(), film()->video_frame_rate ()); + FrameRateChange const frc (subtitle->subtitle_video_frame_rate(), film()->video_frame_rate ()); return DCPTime (_length, frc); } - -void -TextSubtitleContent::set_subtitle_video_frame_rate (double r) -{ - { - boost::mutex::scoped_lock lm (_mutex); - _frame_rate = r; - } - - signal_changed (SubtitleContentProperty::SUBTITLE_VIDEO_FRAME_RATE); -} - -double -TextSubtitleContent::subtitle_video_frame_rate () const -{ - { - boost::mutex::scoped_lock lm (_mutex); - if (_frame_rate) { - return _frame_rate.get (); - } - } - - /* No frame rate specified, so assume this content has been - prepared for any concurrent video content. - */ - return film()->active_frame_rate_change(position()).source; -} diff --git a/src/lib/text_subtitle_content.h b/src/lib/text_subtitle_content.h index 76440ba9b..61dac4830 100644 --- a/src/lib/text_subtitle_content.h +++ b/src/lib/text_subtitle_content.h @@ -40,13 +40,8 @@ public: void as_xml (xmlpp::Node *) const; DCPTime full_length () const; - double subtitle_video_frame_rate () const; - void set_subtitle_video_frame_rate (double r); - static std::string const font_id; private: ContentTime _length; - /** Video frame rate that this content has been prepared for, if known */ - boost::optional<double> _frame_rate; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index c018c9243..b7b056612 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -72,9 +72,8 @@ Transcoder::go () int burnt_subtitles = 0; int non_burnt_subtitles = 0; BOOST_FOREACH (shared_ptr<const Content> c, _film->content ()) { - shared_ptr<const SubtitleContent> sc = dynamic_pointer_cast<const SubtitleContent> (c); - if (sc && sc->use_subtitles()) { - if (sc->burn_subtitles()) { + if (c->subtitle && c->subtitle->use_subtitles()) { + if (c->subtitle->burn_subtitles()) { ++burnt_subtitles; } else { ++non_burnt_subtitles; diff --git a/src/lib/types.h b/src/lib/types.h index 2bc6fa3a4..8eabdbf27 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,7 +48,6 @@ namespace xmlpp { #define SERVER_LINK_VERSION (64+0) typedef std::vector<boost::shared_ptr<Content> > ContentList; -typedef std::vector<boost::shared_ptr<AudioContent> > AudioContentList; typedef std::vector<boost::shared_ptr<FFmpegContent> > FFmpegContentList; typedef int64_t Frame; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 561ebb62c..567ab3cf8 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -119,43 +119,42 @@ VideoContent::VideoContent (Content* parent, shared_ptr<const Film> film, vector , _video_length (0) , _yuv (false) { - shared_ptr<VideoContent> ref = dynamic_pointer_cast<VideoContent> (c[0]); + shared_ptr<VideoContent> ref = c[0]->video; DCPOMATIC_ASSERT (ref); - for (size_t i = 0; i < c.size(); ++i) { - shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (c[i]); + for (size_t i = 1; i < c.size(); ++i) { - if (vc->video_size() != ref->video_size()) { + if (c[i]->video->video_size() != ref->video_size()) { throw JoinError (_("Content to be joined must have the same picture size.")); } - if (vc->video_frame_rate() != ref->video_frame_rate()) { + if (c[i]->video->video_frame_rate() != ref->video_frame_rate()) { throw JoinError (_("Content to be joined must have the same video frame rate.")); } - if (vc->video_frame_type() != ref->video_frame_type()) { + if (c[i]->video->video_frame_type() != ref->video_frame_type()) { throw JoinError (_("Content to be joined must have the same video frame type.")); } - if (vc->crop() != ref->crop()) { + if (c[i]->video->crop() != ref->crop()) { throw JoinError (_("Content to be joined must have the same crop.")); } - if (vc->scale() != ref->scale()) { + if (c[i]->video->scale() != ref->scale()) { throw JoinError (_("Content to be joined must have the same scale setting.")); } - if (vc->colour_conversion() != ref->colour_conversion()) { + if (c[i]->video->colour_conversion() != ref->colour_conversion()) { throw JoinError (_("Content to be joined must have the same colour conversion.")); } - if (vc->fade_in() != ref->fade_in() || vc->fade_out() != ref->fade_out()) { + if (c[i]->video->fade_in() != ref->fade_in() || c[i]->video->fade_out() != ref->fade_out()) { throw JoinError (_("Content to be joined must have the same fades.")); } - _video_length += vc->video_length (); + _video_length += c[i]->video->video_length (); - if (vc->yuv ()) { + if (c[i]->video->yuv ()) { _yuv = true; } } |
