diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-05-21 17:32:28 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-05-21 17:32:28 +0100 |
| commit | 2255aedd15f985796d2e6f7fcc7fb412a5d98812 (patch) | |
| tree | 744d52adfdd226ce5b0220d62612710873fa77f4 /src/lib | |
| parent | 2de990b0155fcb5c3dac821ef8c2659e903d2f6e (diff) | |
Various more hacks; basically trying to remove Regions as an unnecessary complexity.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/audio_content.h | 2 | ||||
| -rw-r--r-- | src/lib/content.cc | 7 | ||||
| -rw-r--r-- | src/lib/content.h | 6 | ||||
| -rw-r--r-- | src/lib/ffmpeg_content.cc | 47 | ||||
| -rw-r--r-- | src/lib/ffmpeg_content.h | 23 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 6 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.h | 10 | ||||
| -rw-r--r-- | src/lib/film.cc | 16 | ||||
| -rw-r--r-- | src/lib/film.h | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 54 | ||||
| -rw-r--r-- | src/lib/player.h | 12 | ||||
| -rw-r--r-- | src/lib/playlist.cc | 118 | ||||
| -rw-r--r-- | src/lib/playlist.h | 32 | ||||
| -rw-r--r-- | src/lib/sndfile_content.h | 6 |
14 files changed, 189 insertions, 152 deletions
diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index 36c36992e..51f05efb0 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -23,6 +23,7 @@ #define DCPOMATIC_AUDIO_CONTENT_H #include "content.h" +#include "audio_mapping.h" namespace cxml { class Node; @@ -49,6 +50,7 @@ public: virtual ContentAudioFrame audio_length () const = 0; virtual int content_audio_frame_rate () const = 0; virtual int output_audio_frame_rate (boost::shared_ptr<const Film>) const = 0; + virtual AudioMapping audio_mapping () const = 0; }; #endif diff --git a/src/lib/content.cc b/src/lib/content.cc index 9c3bcd39d..578dafd67 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -1,3 +1,5 @@ +/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ + /* Copyright (C) 2013 Carl Hetherington <cth@carlh.net> @@ -25,9 +27,11 @@ using std::string; using boost::shared_ptr; +using boost::lexical_cast; Content::Content (boost::filesystem::path f) : _file (f) + , _time (0) { } @@ -36,12 +40,14 @@ Content::Content (shared_ptr<const cxml::Node> node) { _file = node->string_child ("File"); _digest = node->string_child ("Digest"); + _time = node->number_child<Time> ("Time"); } Content::Content (Content const & o) : boost::enable_shared_from_this<Content> (o) , _file (o._file) , _digest (o._digest) + , _time (o._time) { } @@ -52,6 +58,7 @@ Content::as_xml (xmlpp::Node* node) const boost::mutex::scoped_lock lm (_mutex); node->add_child("File")->add_child_text (_file.string()); node->add_child("Digest")->add_child_text (_digest); + node->add_child("Time")->add_child_text (lexical_cast<string> (_time)); } void diff --git a/src/lib/content.h b/src/lib/content.h index 8db35891a..fd6288acc 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -60,6 +60,11 @@ public: return _digest; } + Time time () const { + boost::mutex::scoped_lock lm (_mutex); + return _time; + } + boost::signals2::signal<void (boost::weak_ptr<Content>, int)> Changed; protected: @@ -70,6 +75,7 @@ protected: private: boost::filesystem::path _file; std::string _digest; + Time _time; }; #endif diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index e898c02d0..fcc775f0a 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -57,7 +57,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const cxml::Node> node) { list<shared_ptr<cxml::Node> > c = node->node_children ("SubtitleStream"); for (list<shared_ptr<cxml::Node> >::const_iterator i = c.begin(); i != c.end(); ++i) { - _subtitle_streams.push_back (FFmpegSubtitleStream (*i)); + _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (*i))); if ((*i)->optional_number_child<int> ("Selected")) { _subtitle_stream = _subtitle_streams.back (); } @@ -65,7 +65,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const cxml::Node> node) c = node->node_children ("AudioStream"); for (list<shared_ptr<cxml::Node> >::const_iterator i = c.begin(); i != c.end(); ++i) { - _audio_streams.push_back (FFmpegAudioStream (*i)); + _audio_streams.push_back (shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (*i))); if ((*i)->optional_number_child<int> ("Selected")) { _audio_stream = _audio_streams.back (); } @@ -94,20 +94,20 @@ FFmpegContent::as_xml (xmlpp::Node* node) const boost::mutex::scoped_lock lm (_mutex); - for (vector<FFmpegSubtitleStream>::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { + for (vector<shared_ptr<FFmpegSubtitleStream> >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { xmlpp::Node* t = node->add_child("SubtitleStream"); - if (_subtitle_stream && *i == _subtitle_stream.get()) { + if (_subtitle_stream && *i == _subtitle_stream) { t->add_child("Selected")->add_child_text("1"); } - i->as_xml (t); + (*i)->as_xml (t); } - for (vector<FFmpegAudioStream>::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { + for (vector<shared_ptr<FFmpegAudioStream> >::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { xmlpp::Node* t = node->add_child("AudioStream"); - if (_audio_stream && *i == _audio_stream.get()) { + if (_audio_stream && *i == _audio_stream) { t->add_child("Selected")->add_child_text("1"); } - i->as_xml (t); + (*i)->as_xml (t); } } @@ -181,7 +181,7 @@ FFmpegContent::information () const } void -FFmpegContent::set_subtitle_stream (FFmpegSubtitleStream s) +FFmpegContent::set_subtitle_stream (shared_ptr<FFmpegSubtitleStream> s) { { boost::mutex::scoped_lock lm (_mutex); @@ -192,7 +192,7 @@ FFmpegContent::set_subtitle_stream (FFmpegSubtitleStream s) } void -FFmpegContent::set_audio_stream (FFmpegAudioStream s) +FFmpegContent::set_audio_stream (shared_ptr<FFmpegAudioStream> s) { { boost::mutex::scoped_lock lm (_mutex); @@ -205,16 +205,23 @@ FFmpegContent::set_audio_stream (FFmpegAudioStream s) ContentAudioFrame FFmpegContent::audio_length () const { + int const cafr = content_audio_frame_rate (); + int const vfr = video_frame_rate (); + ContentVideoFrame const vl = video_length (); + + boost::mutex::scoped_lock lm (_mutex); if (!_audio_stream) { return 0; } - return video_frames_to_audio_frames (_video_length, content_audio_frame_rate(), video_frame_rate()); + return video_frames_to_audio_frames (vl, cafr, vfr); } int FFmpegContent::audio_channels () const { + boost::mutex::scoped_lock lm (_mutex); + if (!_audio_stream) { return 0; } @@ -225,6 +232,8 @@ FFmpegContent::audio_channels () const int FFmpegContent::content_audio_frame_rate () const { + boost::mutex::scoped_lock lm (_mutex); + if (!_audio_stream) { return 0; } @@ -271,6 +280,7 @@ FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node) id = node->number_child<int> ("Id"); frame_rate = node->number_child<int> ("FrameRate"); channels = node->number_child<int64_t> ("Channels"); + mapping = AudioMapping (node->node_child ("Mapping")); } void @@ -280,6 +290,7 @@ FFmpegAudioStream::as_xml (xmlpp::Node* root) const root->add_child("Id")->add_child_text (lexical_cast<string> (id)); root->add_child("FrameRate")->add_child_text (lexical_cast<string> (frame_rate)); root->add_child("Channels")->add_child_text (lexical_cast<string> (channels)); + mapping.as_xml (root->add_child("Mapping")); } /** Construct a SubtitleStream from a value returned from to_string(). @@ -311,3 +322,17 @@ FFmpegContent::length (shared_ptr<const Film> film) const FrameRateConversion frc (video_frame_rate (), film->dcp_video_frame_rate ()); return video_length() * frc.factor() * TIME_HZ / film->dcp_video_frame_rate (); } + +AudioMapping +FFmpegContent::audio_mapping () const +{ + boost::mutex::scoped_lock lm (_mutex); + + if (!_audio_stream) { + return AudioMapping (); + } + + cout << "returning am from stream " << _audio_stream.get() << ".\n"; + return _audio_stream->mapping; +} + diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index 6c141b6c1..d79e4ec35 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -34,6 +34,7 @@ public: , id (i) , frame_rate (f) , channels (c) + , mapping (c) {} FFmpegAudioStream (boost::shared_ptr<const cxml::Node>); @@ -44,6 +45,7 @@ public: int id; int frame_rate; int channels; + AudioMapping mapping; }; extern bool operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b); @@ -98,35 +100,36 @@ public: ContentAudioFrame audio_length () const; int content_audio_frame_rate () const; int output_audio_frame_rate (boost::shared_ptr<const Film>) const; + AudioMapping audio_mapping () const; - std::vector<FFmpegSubtitleStream> subtitle_streams () const { + std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_streams; } - boost::optional<FFmpegSubtitleStream> subtitle_stream () const { + boost::shared_ptr<FFmpegSubtitleStream> subtitle_stream () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_stream; } - std::vector<FFmpegAudioStream> audio_streams () const { + std::vector<boost::shared_ptr<FFmpegAudioStream> > audio_streams () const { boost::mutex::scoped_lock lm (_mutex); return _audio_streams; } - boost::optional<FFmpegAudioStream> audio_stream () const { + boost::shared_ptr<FFmpegAudioStream> audio_stream () const { boost::mutex::scoped_lock lm (_mutex); return _audio_stream; } - void set_subtitle_stream (FFmpegSubtitleStream); - void set_audio_stream (FFmpegAudioStream); + void set_subtitle_stream (boost::shared_ptr<FFmpegSubtitleStream>); + void set_audio_stream (boost::shared_ptr<FFmpegAudioStream>); private: - std::vector<FFmpegSubtitleStream> _subtitle_streams; - boost::optional<FFmpegSubtitleStream> _subtitle_stream; - std::vector<FFmpegAudioStream> _audio_streams; - boost::optional<FFmpegAudioStream> _audio_stream; + std::vector<boost::shared_ptr<FFmpegSubtitleStream> > _subtitle_streams; + boost::shared_ptr<FFmpegSubtitleStream> _subtitle_stream; + std::vector<boost::shared_ptr<FFmpegAudioStream> > _audio_streams; + boost::shared_ptr<FFmpegAudioStream> _audio_stream; }; #endif diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index adf16c940..a637160ae 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -141,11 +141,13 @@ FFmpegDecoder::setup_general () } _audio_streams.push_back ( - FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channels) + shared_ptr<FFmpegAudioStream> ( + new FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channels) + ) ); } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - _subtitle_streams.push_back (FFmpegSubtitleStream (stream_name (s), i)); + _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (stream_name (s), i))); } } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 760fc084d..f3f6b126b 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -1,3 +1,5 @@ +/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ + /* Copyright (C) 2012 Carl Hetherington <cth@carlh.net> @@ -68,11 +70,11 @@ public: int sample_aspect_ratio_numerator () const; int sample_aspect_ratio_denominator () const; - std::vector<FFmpegSubtitleStream> subtitle_streams () const { + std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const { return _subtitle_streams; } - std::vector<FFmpegAudioStream> audio_streams () const { + std::vector<boost::shared_ptr<FFmpegAudioStream> > audio_streams () const { return _audio_streams; } @@ -126,8 +128,8 @@ private: std::list<boost::shared_ptr<FilterGraph> > _filter_graphs; boost::mutex _filter_graphs_mutex; - std::vector<FFmpegSubtitleStream> _subtitle_streams; - std::vector<FFmpegAudioStream> _audio_streams; + std::vector<boost::shared_ptr<FFmpegSubtitleStream> > _subtitle_streams; + std::vector<boost::shared_ptr<FFmpegAudioStream> > _audio_streams; bool _decode_video; bool _decode_audio; diff --git a/src/lib/film.cc b/src/lib/film.cc index 1b5779f2d..37af4cb20 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -317,7 +317,7 @@ Film::make_dcp () throw MissingSettingError (_("format")); } - if (_playlist->regions().empty ()) { + if (_playlist->content().empty ()) { throw StringError (_("You must add some content to the DCP before creating it")); } @@ -697,11 +697,11 @@ Film::set_trust_content_headers (bool t) signal_changed (TRUST_CONTENT_HEADERS); - Playlist::RegionList regions = _playlist->regions (); - if (!_trust_content_headers && !regions.empty()) { + Playlist::ContentList content = _playlist->content (); + if (!_trust_content_headers && !content.empty()) { /* We just said that we don't trust the content's header */ - for (Playlist::RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - examine_content ((*i)->content); + for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) { + examine_content (*i); } } } @@ -1040,10 +1040,10 @@ Film::playlist () const return _playlist; } -Playlist::RegionList -Film::regions () const +Playlist::ContentList +Film::content () const { - return _playlist->regions (); + return _playlist->content (); } void diff --git a/src/lib/film.h b/src/lib/film.h index 03d472cee..c0417382f 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -111,7 +111,7 @@ public: /* Proxies for some Playlist methods */ - Playlist::RegionList regions () const; + Playlist::ContentList content () const; Time length () const; bool has_subtitles () const; diff --git a/src/lib/player.cc b/src/lib/player.cc index 675fcae5c..5d4635e5a 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -89,12 +89,12 @@ Player::pass () */ Time earliest_pos = TIME_MAX; - shared_ptr<RegionDecoder> earliest; + shared_ptr<DecoderRecord> earliest; Time next_wait = TIME_MAX; - for (list<shared_ptr<RegionDecoder> >::iterator i = _decoders.begin(); i != _decoders.end(); ++i) { - Time const ts = (*i)->region->time; - Time const te = (*i)->region->time + (*i)->region->content->length (_film); + for (list<shared_ptr<DecoderRecord> >::iterator i = _decoders.begin(); i != _decoders.end(); ++i) { + Time const ts = (*i)->content->time(); + Time const te = (*i)->content->time() + (*i)->content->length (_film); if (ts <= _position && te > _position) { Time const pos = ts + (*i)->last; if (pos < earliest_pos) { @@ -121,24 +121,24 @@ Player::pass () } void -Player::process_video (shared_ptr<RegionDecoder> rd, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time) +Player::process_video (shared_ptr<DecoderRecord> dr, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time) { - shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (rd->decoder); + shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (dr->decoder); - Time const global_time = rd->region->time + time; + Time const global_time = dr->content->time() + time; while ((global_time - _last_video) > 1) { /* Fill in with black */ emit_black_frame (); } Video (image, same, sub, global_time); - rd->last = time; + dr->last = time; _last_video = global_time; _last_was_black = false; } void -Player::process_audio (shared_ptr<RegionDecoder> rd, shared_ptr<const AudioBuffers> audio, Time time) +Player::process_audio (shared_ptr<DecoderRecord> dr, shared_ptr<const AudioBuffers> audio, Time time) { /* XXX: mapping */ @@ -172,7 +172,7 @@ Player::process_audio (shared_ptr<RegionDecoder> rd, shared_ptr<const AudioBuffe _audio_buffers.ensure_size (time - _last_audio + audio->frames()); _audio_buffers.accumulate (audio.get(), 0, _film->time_to_audio_frames (time - _last_audio)); - rd->last = time + _film->audio_frames_to_time (audio->frames ()); + dr->last = time + _film->audio_frames_to_time (audio->frames ()); } /** @return true on error */ @@ -212,34 +212,34 @@ Player::seek_forward () void Player::setup_decoders () { - list<shared_ptr<RegionDecoder> > old_decoders = _decoders; + list<shared_ptr<DecoderRecord> > old_decoders = _decoders; _decoders.clear (); - Playlist::RegionList regions = _playlist->regions (); - for (Playlist::RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + Playlist::ContentList content = _playlist->content (); + for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) { - shared_ptr<RegionDecoder> rd (new RegionDecoder); - rd->region = *i; + shared_ptr<DecoderRecord> dr (new DecoderRecord); + dr->content = *i; /* XXX: into content? */ - shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> ((*i)->content); + shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i); if (fc) { shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles)); - fd->Video.connect (bind (&Player::process_video, this, rd, _1, _2, _3, _4)); - fd->Audio.connect (bind (&Player::process_audio, this, rd, _1, _2)); + fd->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4)); + fd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2)); - rd->decoder = fd; + dr->decoder = fd; } - shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> ((*i)->content); + shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i); if (ic) { shared_ptr<ImageMagickDecoder> id; /* See if we can re-use an old ImageMagickDecoder */ - for (list<shared_ptr<RegionDecoder> >::const_iterator i = old_decoders.begin(); i != old_decoders.end(); ++i) { + for (list<shared_ptr<DecoderRecord> >::const_iterator i = old_decoders.begin(); i != old_decoders.end(); ++i) { shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*i)->decoder); if (imd && imd->content() == ic) { id = imd; @@ -248,21 +248,21 @@ Player::setup_decoders () if (!id) { id.reset (new ImageMagickDecoder (_film, ic)); - id->Video.connect (bind (&Player::process_video, this, rd, _1, _2, _3, _4)); + id->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4)); } - rd->decoder = id; + dr->decoder = id; } - shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> ((*i)->content); + shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i); if (sc) { shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc)); - sd->Audio.connect (bind (&Player::process_audio, this, rd, _1, _2)); + sd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2)); - rd->decoder = sd; + dr->decoder = sd; } - _decoders.push_back (rd); + _decoders.push_back (dr); } _position = 0; diff --git a/src/lib/player.h b/src/lib/player.h index 4979778ed..44b95e076 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -62,19 +62,19 @@ public: private: - struct RegionDecoder + struct DecoderRecord { - RegionDecoder () + DecoderRecord () : last (0) {} - boost::shared_ptr<Playlist::Region> region; + boost::shared_ptr<Content> content; boost::shared_ptr<Decoder> decoder; Time last; }; - void process_video (boost::shared_ptr<RegionDecoder>, boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, Time); - void process_audio (boost::shared_ptr<RegionDecoder>, boost::shared_ptr<const AudioBuffers>, Time); + void process_video (boost::shared_ptr<DecoderRecord>, boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, Time); + void process_audio (boost::shared_ptr<DecoderRecord>, boost::shared_ptr<const AudioBuffers>, Time); void setup_decoders (); void playlist_changed (); void content_changed (boost::weak_ptr<Content>, int); @@ -90,7 +90,7 @@ private: /** Our decoders are ready to go; if this is false the decoders must be (re-)created before they are used */ bool _have_valid_decoders; - std::list<boost::shared_ptr<RegionDecoder> > _decoders; + std::list<boost::shared_ptr<DecoderRecord> > _decoders; Time _position; AudioBuffers _audio_buffers; diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 8db5c5fc2..ad71f87d7 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -58,11 +58,17 @@ Playlist::Playlist () Playlist::Playlist (shared_ptr<const Playlist> other) : _loop (other->_loop) { - for (RegionList::const_iterator i = other->_regions.begin(); i != other->_regions.end(); ++i) { - _regions.push_back (shared_ptr<Region> (new Region ((*i)->content->clone(), (*i)->time, this))); + for (ContentList::const_iterator i = other->_content.begin(); i != other->_content.end(); ++i) { + _content.push_back ((*i)->clone ()); } } +Playlist::~Playlist () +{ + _content.clear (); + reconnect (); +} + void Playlist::content_changed (weak_ptr<Content> c, int p) { @@ -74,14 +80,14 @@ Playlist::audio_digest () const { string t; - for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { - if (!dynamic_pointer_cast<const AudioContent> ((*i)->content)) { + for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) { + if (!dynamic_pointer_cast<const AudioContent> (*i)) { continue; } - t += (*i)->content->digest (); + t += (*i)->digest (); - shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> ((*i)->content); + shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i); if (fc) { t += lexical_cast<string> (fc->audio_stream()->id); } @@ -97,13 +103,13 @@ Playlist::video_digest () const { string t; - for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { - if (!dynamic_pointer_cast<const VideoContent> ((*i)->content)) { + for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) { + if (!dynamic_pointer_cast<const VideoContent> (*i)) { continue; } - t += (*i)->content->digest (); - shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> ((*i)->content); + t += (*i)->digest (); + shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i); if (fc && fc->subtitle_stream()) { t += fc->subtitle_stream()->id; } @@ -114,22 +120,34 @@ Playlist::video_digest () const return md5_digest (t.c_str(), t.length()); } +/** @param node <Playlist> node */ void Playlist::set_from_xml (shared_ptr<const cxml::Node> node) { - list<shared_ptr<cxml::Node> > c = node->node_children ("Region"); + list<shared_ptr<cxml::Node> > c = node->node_children ("Content"); for (list<shared_ptr<cxml::Node> >::iterator i = c.begin(); i != c.end(); ++i) { - _regions.push_back (shared_ptr<Region> (new Region (*i, this))); + string const type = (*i)->string_child ("Type"); + + boost::shared_ptr<Content> content; + + if (type == "FFmpeg") { + content.reset (new FFmpegContent (*i)); + } else if (type == "ImageMagick") { + content.reset (new ImageMagickContent (*i)); + } else if (type == "Sndfile") { + content.reset (new SndfileContent (*i)); + } } _loop = node->number_child<int> ("Loop"); } +/** @param node <Playlist> node */ void Playlist::as_xml (xmlpp::Node* node) { - for (RegionList::iterator i = _regions.begin(); i != _regions.end(); ++i) { - (*i)->as_xml (node->add_child ("Region")); + for (ContentList::iterator i = _content.begin(); i != _content.end(); ++i) { + (*i)->as_xml (node->add_child ("Content")); } node->add_child("Loop")->add_child_text(lexical_cast<string> (_loop)); @@ -138,20 +156,21 @@ Playlist::as_xml (xmlpp::Node* node) void Playlist::add (shared_ptr<Content> c) { - _regions.push_back (shared_ptr<Region> (new Region (c, 0, this))); + _content.push_back (c); + reconnect (); Changed (); } void Playlist::remove (shared_ptr<Content> c) { - RegionList::iterator i = _regions.begin (); - while (i != _regions.end() && (*i)->content != c) { + ContentList::iterator i = _content.begin (); + while (i != _content.end() && *i != c) { ++i; } - if (i != _regions.end ()) { - _regions.erase (i); + if (i != _content.end ()) { + _content.erase (i); Changed (); } } @@ -166,8 +185,8 @@ Playlist::set_loop (int l) bool Playlist::has_subtitles () const { - for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { - shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> ((*i)->content); + for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) { + shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i); if (fc && !fc->subtitle_streams().empty()) { return true; } @@ -176,40 +195,6 @@ Playlist::has_subtitles () const return false; } -Playlist::Region::Region (shared_ptr<Content> c, Time t, Playlist* p) - : content (c) - , time (t) -{ - connection = c->Changed.connect (bind (&Playlist::content_changed, p, _1, _2)); -} - -Playlist::Region::Region (shared_ptr<const cxml::Node> node, Playlist* p) -{ - shared_ptr<const cxml::Node> content_node = node->node_child ("Content"); - string const type = content_node->string_child ("Type"); - - if (type == "FFmpeg") { - content.reset (new FFmpegContent (content_node)); - } else if (type == "ImageMagick") { - content.reset (new ImageMagickContent (content_node)); - } else if (type == "Sndfile") { - content.reset (new SndfileContent (content_node)); - } - - time = node->number_child<Time> ("Time"); - audio_mapping = AudioMapping (node->node_child ("AudioMapping")); - connection = content->Changed.connect (bind (&Playlist::content_changed, p, _1, _2)); -} - -void -Playlist::Region::as_xml (xmlpp::Node* node) const -{ - xmlpp::Node* sub = node->add_child ("Content"); - content->as_xml (sub); - node->add_child ("Time")->add_child_text (lexical_cast<string> (time)); - audio_mapping.as_xml (node->add_child ("AudioMapping")); -} - class FrameRateCandidate { public: @@ -248,8 +233,8 @@ Playlist::best_dcp_frame_rate () const while (i != candidates.end()) { float this_error = std::numeric_limits<float>::max (); - for (RegionList::const_iterator j = _regions.begin(); j != _regions.end(); ++j) { - shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*j)->content); + for (ContentList::const_iterator j = _content.begin(); j != _content.end(); ++j) { + shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*j); if (!vc) { continue; } @@ -276,10 +261,25 @@ Time Playlist::length (shared_ptr<const Film> film) const { Time len = 0; - for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { - Time const t = (*i)->time + (*i)->content->length (film); + for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) { + Time const t = (*i)->time() + (*i)->length (film); len = max (len, t); } return len; } + +void +Playlist::reconnect () +{ + for (list<boost::signals2::connection>::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) { + i->disconnect (); + } + + _content_connections.clear (); + + for (ContentList::iterator i = _content.begin(); i != _content.end(); ++i) { + _content_connections.push_back ((*i)->Changed.connect (bind (&Playlist::content_changed, this, _1, _2))); + } +} + diff --git a/src/lib/playlist.h b/src/lib/playlist.h index f677f0ad7..e8cac0247 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -41,6 +41,7 @@ class SndfileContent; class SndfileDecoder; class Job; class Film; +class Region; /** @class Playlist * @brief A set of content files (video and audio), with knowledge of how they should be arranged into @@ -57,6 +58,7 @@ class Playlist public: Playlist (); Playlist (boost::shared_ptr<const Playlist>); + ~Playlist (); void as_xml (xmlpp::Node *); void set_from_xml (boost::shared_ptr<const cxml::Node>); @@ -66,30 +68,10 @@ public: bool has_subtitles () const; - struct Region - { - Region () - : time (0) - {} - - Region (boost::shared_ptr<Content> c, Time t, Playlist* p); - Region (boost::shared_ptr<const cxml::Node>, Playlist* p); - - void as_xml (xmlpp::Node *) const; - - boost::shared_ptr<Content> content; - Time time; - /* XXX: obviously not used for video-only; there should - really by AudioRegion / VideoRegion etc. - */ - AudioMapping audio_mapping; - boost::signals2::connection connection; - }; - - typedef std::vector<boost::shared_ptr<Region> > RegionList; + typedef std::vector<boost::shared_ptr<Content> > ContentList; - RegionList regions () const { - return _regions; + ContentList content () const { + return _content; } std::string audio_digest () const; @@ -109,9 +91,11 @@ public: private: void content_changed (boost::weak_ptr<Content>, int); + void reconnect (); - RegionList _regions; + ContentList _content; int _loop; + std::list<boost::signals2::connection> _content_connections; }; #endif diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index d930d7061..1ef4b3f02 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -62,6 +62,11 @@ public: } int output_audio_frame_rate (boost::shared_ptr<const Film>) const; + + AudioMapping audio_mapping () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_mapping; + } static bool valid_file (boost::filesystem::path); @@ -69,4 +74,5 @@ private: int _audio_channels; ContentAudioFrame _audio_length; int _audio_frame_rate; + AudioMapping _audio_mapping; }; |
