diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/active_text.cc | 40 | ||||
| -rw-r--r-- | src/lib/active_text.h | 3 | ||||
| -rw-r--r-- | src/lib/butler.cc | 29 | ||||
| -rw-r--r-- | src/lib/butler.h | 13 | ||||
| -rw-r--r-- | src/lib/player.cc | 9 | ||||
| -rw-r--r-- | src/lib/player.h | 2 | ||||
| -rw-r--r-- | src/lib/wscript | 1 | ||||
| -rw-r--r-- | src/wx/closed_captions_dialog.cc | 65 | ||||
| -rw-r--r-- | src/wx/closed_captions_dialog.h | 8 | ||||
| -rw-r--r-- | src/wx/film_viewer.cc | 5 |
10 files changed, 95 insertions, 80 deletions
diff --git a/src/lib/active_text.cc b/src/lib/active_text.cc index 5f4440728..2988c04a3 100644 --- a/src/lib/active_text.cc +++ b/src/lib/active_text.cc @@ -30,38 +30,6 @@ using boost::weak_ptr; using boost::shared_ptr; using boost::optional; -void -ActiveText::add (DCPTimePeriod period, list<PlayerText>& pc, list<Period> p) const -{ - BOOST_FOREACH (Period i, p) { - DCPTimePeriod test (i.from, i.to.get_value_or(DCPTime::max())); - optional<DCPTimePeriod> overlap = period.overlap (test); - if (overlap && overlap->duration() > DCPTime(period.duration().get() / 2)) { - pc.push_back (i.subs); - } - } -} - -list<PlayerText> -ActiveText::get (DCPTimePeriod period) const -{ - boost::mutex::scoped_lock lm (_mutex); - - list<PlayerText> ps; - - for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) { - - shared_ptr<const TextContent> caption = i->first.lock (); - if (!caption || !caption->use()) { - continue; - } - - add (period, ps, i->second); - } - - return ps; -} - /** Get the open captions that should be burnt into a given period. * @param period Period of interest. * @param always_burn_captions Always burn captions even if their content is not set to burn. @@ -85,7 +53,13 @@ ActiveText::get_burnt (DCPTimePeriod period, bool always_burn_captions) const continue; } - add (period, ps, i->second); + BOOST_FOREACH (Period j, i->second) { + DCPTimePeriod test (j.from, j.to.get_value_or(DCPTime::max())); + optional<DCPTimePeriod> overlap = period.overlap (test); + if (overlap && overlap->duration() > DCPTime(period.duration().get() / 2)) { + ps.push_back (j.subs); + } + } } return ps; diff --git a/src/lib/active_text.h b/src/lib/active_text.h index 1dab7a867..ff4a1bd2f 100644 --- a/src/lib/active_text.h +++ b/src/lib/active_text.h @@ -37,7 +37,6 @@ class TextContent; class ActiveText : public boost::noncopyable { public: - std::list<PlayerText> get (DCPTimePeriod period) const; std::list<PlayerText> get_burnt (DCPTimePeriod period, bool always_burn_captions) const; void clear_before (DCPTime time); void clear (); @@ -63,8 +62,6 @@ private: typedef std::map<boost::weak_ptr<const TextContent>, std::list<Period> > Map; - void add (DCPTimePeriod period, std::list<PlayerText>& pc, std::list<Period> p) const; - mutable boost::mutex _mutex; Map _data; }; diff --git a/src/lib/butler.cc b/src/lib/butler.cc index 6a1cc68fc..45cd5a9db 100644 --- a/src/lib/butler.cc +++ b/src/lib/butler.cc @@ -63,6 +63,7 @@ Butler::Butler (shared_ptr<Player> player, shared_ptr<Log> log, AudioMapping aud { _player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2)); _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1, _2)); + _player_text_connection = _player->Text.connect (bind (&Butler::text, this, _1, _2, _3)); _player_changed_connection = _player->Changed.connect (bind (&Butler::player_changed, this)); _thread = new boost::thread (bind (&Butler::thread, this)); #ifdef DCPOMATIC_LINUX @@ -203,6 +204,13 @@ Butler::get_video () return r; } +optional<pair<PlayerText, DCPTimePeriod> > +Butler::get_closed_caption () +{ + boost::mutex::scoped_lock lm (_mutex); + return _closed_caption.get (); +} + void Butler::seek (DCPTime position, bool accurate) { @@ -218,9 +226,10 @@ Butler::seek_unlocked (DCPTime position, bool accurate) } { - boost::mutex::scoped_lock lm (_video_audio_mutex); + boost::mutex::scoped_lock lm (_buffers_mutex); _video.clear (); _audio.clear (); + _closed_caption.clear (); } _finished = false; @@ -253,7 +262,7 @@ Butler::video (shared_ptr<PlayerVideo> video, DCPTime time) _prepare_service.post (bind (&Butler::prepare, this, weak_ptr<PlayerVideo>(video))); - boost::mutex::scoped_lock lm2 (_video_audio_mutex); + boost::mutex::scoped_lock lm2 (_buffers_mutex); _video.put (video, time); } @@ -268,7 +277,7 @@ Butler::audio (shared_ptr<AudioBuffers> audio, DCPTime time) } } - boost::mutex::scoped_lock lm2 (_video_audio_mutex); + boost::mutex::scoped_lock lm2 (_buffers_mutex); _audio.put (remap (audio, _audio_channels, _audio_mapping), time); } @@ -318,9 +327,10 @@ Butler::player_changed () } { - boost::mutex::scoped_lock lm (_video_audio_mutex); + boost::mutex::scoped_lock lm (_buffers_mutex); _video.clear (); _audio.clear (); + _closed_caption.clear (); } _finished = false; @@ -329,3 +339,14 @@ Butler::player_changed () seek_unlocked (seek_to, true); _awaiting = seek_to; } + +void +Butler::text (PlayerText pt, TextType type, DCPTimePeriod period) +{ + if (type != TEXT_CLOSED_CAPTION) { + return; + } + + boost::mutex::scoped_lock lm2 (_buffers_mutex); + _closed_caption.put (make_pair(pt, period)); +} diff --git a/src/lib/butler.h b/src/lib/butler.h index 7e97bd3c0..0b926047a 100644 --- a/src/lib/butler.h +++ b/src/lib/butler.h @@ -20,6 +20,7 @@ #include "video_ring_buffers.h" #include "audio_ring_buffers.h" +#include "text_ring_buffers.h" #include "audio_mapping.h" #include "exception_store.h" #include <boost/shared_ptr.hpp> @@ -42,6 +43,7 @@ public: void seek (DCPTime position, bool accurate); std::pair<boost::shared_ptr<PlayerVideo>, DCPTime> get_video (); boost::optional<DCPTime> get_audio (float* out, Frame frames); + boost::optional<std::pair<PlayerText, DCPTimePeriod> > get_closed_caption (); void disable_audio (); @@ -51,6 +53,7 @@ private: void thread (); void video (boost::shared_ptr<PlayerVideo> video, DCPTime time); void audio (boost::shared_ptr<AudioBuffers> audio, DCPTime time); + void text (PlayerText pt, TextType type, DCPTimePeriod period); bool should_run () const; void prepare (boost::weak_ptr<PlayerVideo> video) const; void player_changed (); @@ -60,12 +63,15 @@ private: boost::shared_ptr<Log> _log; boost::thread* _thread; - /** mutex to protect _video and _audio for when we are clearing them and they both need to be - cleared together without any data being inserted in the interim. + /** mutex to protect _video, _audio and _closed_caption for when we are clearing them and they all need to be + cleared together without any data being inserted in the interim; + XXX: is this necessary now that all butler output data is timestamped? Perhaps the locked clear-out + is only required if we guarantee that get_video() and get_audio() calls are in sync. */ - boost::mutex _video_audio_mutex; + boost::mutex _buffers_mutex; VideoRingBuffers _video; AudioRingBuffers _audio; + TextRingBuffers _closed_caption; boost::thread_group _prepare_pool; boost::asio::io_service _prepare_service; @@ -93,5 +99,6 @@ private: boost::signals2::scoped_connection _player_video_connection; boost::signals2::scoped_connection _player_audio_connection; + boost::signals2::scoped_connection _player_text_connection; boost::signals2::scoped_connection _player_changed_connection; }; diff --git a/src/lib/player.cc b/src/lib/player.cc index 68b3365ea..c1a6c0f3c 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -724,15 +724,6 @@ Player::pass () return done; } -list<PlayerText> -Player::closed_captions_for_frame (DCPTime time) const -{ - boost::mutex::scoped_lock _lm (_mutex); - return _active_texts[TEXT_CLOSED_CAPTION].get ( - DCPTimePeriod(time, time + DCPTime::from_frames(1, _film->video_frame_rate())) - ); -} - /** @return Open subtitles for the frame at the given time, converted to images */ optional<PositionImage> Player::open_subtitles_for_frame (DCPTime time) const diff --git a/src/lib/player.h b/src/lib/player.h index a4fd80c16..20b68ef77 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -88,8 +88,6 @@ public: DCPTime content_time_to_dcp (boost::shared_ptr<Content> content, ContentTime t); - std::list<PlayerText> closed_captions_for_frame (DCPTime time) const; - /** Emitted when something has changed such that if we went back and emitted * the last frame again it would look different. This is not emitted after * a seek. diff --git a/src/lib/wscript b/src/lib/wscript index a9ed0c621..0cc3d7823 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -137,6 +137,7 @@ sources = """ string_text_file.cc string_text_file_content.cc string_text_file_decoder.cc + text_ring_buffers.cc timer.cc transcode_job.cc types.cc diff --git a/src/wx/closed_captions_dialog.cc b/src/wx/closed_captions_dialog.cc index a504cade9..c07961cc8 100644 --- a/src/wx/closed_captions_dialog.cc +++ b/src/wx/closed_captions_dialog.cc @@ -20,14 +20,17 @@ #include "closed_captions_dialog.h" #include "lib/string_text.h" +#include "lib/butler.h" #include <boost/bind.hpp> using std::list; using std::max; using std::cout; +using std::pair; using std::make_pair; using boost::shared_ptr; using boost::weak_ptr; +using boost::optional; ClosedCaptionsDialog::ClosedCaptionsDialog (wxWindow* parent) : wxDialog (parent, wxID_ANY, _("Closed captions"), wxDefaultPosition, wxDefaultSize, @@ -40,7 +43,7 @@ ClosedCaptionsDialog::ClosedCaptionsDialog (wxWindow* parent) wxDEFAULT_FRAME_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE | wxFRAME_FLOAT_ON_PARENT #endif ) - + , _current_in_lines (false) { _lines.resize (CLOSED_CAPTION_LINES); Bind (wxEVT_PAINT, boost::bind (&ClosedCaptionsDialog::paint, this)); @@ -100,40 +103,62 @@ private: void ClosedCaptionsDialog::update (DCPTime time) { - shared_ptr<Player> player = _player.lock (); - DCPOMATIC_ASSERT (player); - list<StringText> to_show; - BOOST_FOREACH (PlayerText i, player->closed_captions_for_frame(time)) { - BOOST_FOREACH (StringText j, i.string) { - to_show.push_back (j); + if (_current_in_lines && _current->second.to > time) { + /* Current one is fine */ + return; + } + + if (_current && _current->second.to < time) { + /* Current one has finished; clear out */ + for (int j = 0; j < CLOSED_CAPTION_LINES; ++j) { + _lines[j] = ""; } + Refresh (); + _current = optional<pair<PlayerText, DCPTimePeriod> >(); } - for (int j = 0; j < CLOSED_CAPTION_LINES; ++j) { - _lines[j] = ""; + if (!_current) { + /* We have no current one: get another */ + shared_ptr<Butler> butler = _butler.lock (); + DCPOMATIC_ASSERT (butler); + _current = butler->get_closed_caption (); + _current_in_lines = false; } - to_show.sort (ClosedCaptionSorter()); + if (_current && _current->second.contains(time)) { + /* We need to set this new one up */ - list<StringText>::const_iterator j = to_show.begin(); - int k = 0; - while (j != to_show.end() && k < CLOSED_CAPTION_LINES) { - _lines[k] = j->text(); - ++j; - ++k; - } + list<StringText> to_show = _current->first.string; - Refresh (); + for (int j = 0; j < CLOSED_CAPTION_LINES; ++j) { + _lines[j] = ""; + } + + to_show.sort (ClosedCaptionSorter()); + + list<StringText>::const_iterator j = to_show.begin(); + int k = 0; + while (j != to_show.end() && k < CLOSED_CAPTION_LINES) { + _lines[k] = j->text(); + ++j; + ++k; + } + + Refresh (); + _current_in_lines = true; + } } void ClosedCaptionsDialog::clear () { + _current = optional<pair<PlayerText, DCPTimePeriod> >(); + _current_in_lines = false; Refresh (); } void -ClosedCaptionsDialog::set_player (weak_ptr<Player> player) +ClosedCaptionsDialog::set_butler (weak_ptr<Butler> butler) { - _player = player; + _butler = butler; } diff --git a/src/wx/closed_captions_dialog.h b/src/wx/closed_captions_dialog.h index e3f13f62f..3da7f6522 100644 --- a/src/wx/closed_captions_dialog.h +++ b/src/wx/closed_captions_dialog.h @@ -22,7 +22,7 @@ #include "lib/player.h" #include <wx/wx.h> -class Player; +class Butler; class ClosedCaptionsDialog : public wxDialog { @@ -31,11 +31,13 @@ public: void update (DCPTime); void clear (); - void set_player (boost::weak_ptr<Player>); + void set_butler (boost::weak_ptr<Butler>); private: void paint (); + boost::optional<std::pair<PlayerText, DCPTimePeriod> > _current; + bool _current_in_lines; std::vector<wxString> _lines; - boost::weak_ptr<Player> _player; + boost::weak_ptr<Butler> _butler; }; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index ce34b06b7..d00c0bfaf 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -203,7 +203,6 @@ FilmViewer::set_film (shared_ptr<Film> film) if (!_film) { _player.reset (); - _closed_captions_dialog->set_player (_player); recreate_butler (); _frame.reset (); refresh_panel (); @@ -222,8 +221,6 @@ FilmViewer::set_film (shared_ptr<Film> film) return; } - _closed_captions_dialog->set_player (_player); - _player->set_always_burn_open_subtitles (); _player->set_play_referenced (); @@ -277,6 +274,8 @@ FilmViewer::recreate_butler () _butler->disable_audio (); } + _closed_captions_dialog->set_butler (_butler); + if (was_running) { start (); } |
