diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/active_captions.cc | 40 | ||||
| -rw-r--r-- | src/lib/active_captions.h | 3 | ||||
| -rw-r--r-- | src/lib/caption_content.cc | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 43 | ||||
| -rw-r--r-- | src/lib/player.h | 4 | ||||
| -rw-r--r-- | src/tools/dcpomatic_player.cc | 15 | ||||
| -rw-r--r-- | src/wx/closed_captions_dialog.cc | 34 | ||||
| -rw-r--r-- | src/wx/closed_captions_dialog.h | 15 | ||||
| -rw-r--r-- | src/wx/closed_captions_view.cc | 143 | ||||
| -rw-r--r-- | src/wx/closed_captions_view.h | 42 | ||||
| -rw-r--r-- | src/wx/film_viewer.cc | 16 | ||||
| -rw-r--r-- | src/wx/film_viewer.h | 1 |
12 files changed, 100 insertions, 258 deletions
diff --git a/src/lib/active_captions.cc b/src/lib/active_captions.cc index b4252e0c3..1d3a53609 100644 --- a/src/lib/active_captions.cc +++ b/src/lib/active_captions.cc @@ -30,7 +30,37 @@ using boost::weak_ptr; using boost::shared_ptr; using boost::optional; -/** Get the subtitles that should be burnt into a given period. +void +ActiveCaptions::add (DCPTimePeriod period, list<PlayerCaption>& 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<PlayerCaption> +ActiveCaptions::get (DCPTimePeriod period) const +{ + list<PlayerCaption> ps; + + for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) { + + shared_ptr<const CaptionContent> 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. */ @@ -51,13 +81,7 @@ ActiveCaptions::get_burnt (DCPTimePeriod period, bool always_burn_captions) cons continue; } - 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); - } - } + add (period, ps, i->second); } return ps; diff --git a/src/lib/active_captions.h b/src/lib/active_captions.h index 10b0b5da9..8e38564f5 100644 --- a/src/lib/active_captions.h +++ b/src/lib/active_captions.h @@ -36,6 +36,7 @@ class CaptionContent; class ActiveCaptions : public boost::noncopyable { public: + std::list<PlayerCaption> get (DCPTimePeriod period) const; std::list<PlayerCaption> get_burnt (DCPTimePeriod period, bool always_burn_captions) const; void clear_before (DCPTime time); void clear (); @@ -61,5 +62,7 @@ private: typedef std::map<boost::weak_ptr<const CaptionContent>, std::list<Period> > Map; + void add (DCPTimePeriod period, std::list<PlayerCaption>& pc, std::list<Period> p) const; + Map _data; }; diff --git a/src/lib/caption_content.cc b/src/lib/caption_content.cc index 37a3e7c70..bbb1bacf3 100644 --- a/src/lib/caption_content.cc +++ b/src/lib/caption_content.cc @@ -67,7 +67,7 @@ CaptionContent::CaptionContent (Content* parent, CaptionType original_type) , _y_scale (1) , _line_spacing (1) , _outline_width (2) - , _type (CAPTION_OPEN) + , _type (original_type) , _original_type (original_type) { diff --git a/src/lib/player.cc b/src/lib/player.cc index dfd309774..4635233ff 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -676,29 +676,34 @@ Player::pass () return done; } +list<PlayerCaption> +Player::closed_captions_for_frame (DCPTime time) const +{ + return _active_captions[CAPTION_CLOSED].get ( + DCPTimePeriod(time, time + DCPTime::from_frames(1, _film->video_frame_rate())) + ); +} + +/** @return Open captions for the frame at the given time, converted to images */ optional<PositionImage> -Player::captions_for_frame (DCPTime time) const +Player::open_captions_for_frame (DCPTime time) const { list<PositionImage> captions; - int const vfr = _film->video_frame_rate(); - for (int i = 0; i < CAPTION_COUNT; ++i) { - bool const always = i == CAPTION_OPEN && _always_burn_open_captions; - BOOST_FOREACH ( - PlayerCaption j, - _active_captions[i].get_burnt(DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), always) - ) { - - /* Image subtitles */ - list<PositionImage> c = transform_bitmap_captions (j.image); - copy (c.begin(), c.end(), back_inserter (captions)); - - /* Text subtitles (rendered to an image) */ - if (!j.text.empty ()) { - list<PositionImage> s = render_text (j.text, j.fonts, _video_container_size, time, vfr); - copy (s.begin(), s.end(), back_inserter (captions)); - } + BOOST_FOREACH ( + PlayerCaption j, + _active_captions[CAPTION_OPEN].get_burnt(DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), _always_burn_open_captions) + ) { + + /* Image subtitles */ + list<PositionImage> c = transform_bitmap_captions (j.image); + copy (c.begin(), c.end(), back_inserter (captions)); + + /* Text subtitles (rendered to an image) */ + if (!j.text.empty ()) { + list<PositionImage> s = render_text (j.text, j.fonts, _video_container_size, time, vfr); + copy (s.begin(), s.end(), back_inserter (captions)); } } @@ -1047,7 +1052,7 @@ Player::do_emit_video (shared_ptr<PlayerVideo> pv, DCPTime time) } } - optional<PositionImage> captions = captions_for_frame (time); + optional<PositionImage> captions = open_captions_for_frame (time); if (captions) { pv->set_caption (captions.get ()); } diff --git a/src/lib/player.h b/src/lib/player.h index d54d927cd..8b85a011f 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -86,6 +86,8 @@ public: DCPTime content_time_to_dcp (boost::shared_ptr<Content> content, ContentTime t); + std::list<PlayerCaption> 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. @@ -134,7 +136,7 @@ private: std::pair<boost::shared_ptr<AudioBuffers>, DCPTime> discard_audio ( boost::shared_ptr<const AudioBuffers> audio, DCPTime time, DCPTime discard_to ) const; - boost::optional<PositionImage> captions_for_frame (DCPTime time) const; + boost::optional<PositionImage> open_captions_for_frame (DCPTime time) const; void emit_video (boost::shared_ptr<PlayerVideo> pv, DCPTime time); void do_emit_video (boost::shared_ptr<PlayerVideo> pv, DCPTime time); void emit_audio (boost::shared_ptr<AudioBuffers> data, DCPTime time); diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index d357e566b..e5745403d 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -82,7 +82,8 @@ enum { ID_file_close = 100, ID_view_cpl, /* Allow spare IDs for CPLs */ - ID_view_scale_appropriate = 200, + ID_view_closed_captions = 200, + ID_view_scale_appropriate, ID_view_scale_full, ID_view_scale_half, ID_view_scale_quarter, @@ -134,6 +135,7 @@ public: Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_close, this), ID_file_close); Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT); Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_closed_captions, this), ID_view_closed_captions); Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_cpl, this, _1), ID_view_cpl, ID_view_cpl + MAX_CPLS); Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(0)), ID_view_scale_full); Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(1)), ID_view_scale_half); @@ -267,6 +269,7 @@ private: wxMenu* view = new wxMenu; optional<int> c = Config::instance()->decode_reduction(); _view_cpl = view->Append(ID_view_cpl, _("CPL"), _cpl_menu); + view->Append(ID_view_closed_captions, _("Closed captions...")); view->AppendSeparator(); view->AppendRadioItem(ID_view_scale_appropriate, _("Set decode resolution to match display"))->Check(!static_cast<bool>(c)); view->AppendRadioItem(ID_view_scale_full, _("Decode at full resolution"))->Check(c && c.get() == 0); @@ -430,6 +433,11 @@ private: dcp->examine (shared_ptr<Job>()); } + void view_closed_captions () + { + _viewer->show_closed_captions (); + } + void tools_verify () { shared_ptr<DCPContent> dcp = boost::dynamic_pointer_cast<DCPContent>(_film->content().front()); @@ -619,10 +627,7 @@ private: void setup_from_dcp (shared_ptr<DCPContent> dcp) { BOOST_FOREACH (shared_ptr<CaptionContent> i, dcp->caption) { - /* XXX: we should offer the option to view closed captions */ - if (i->type() == CAPTION_OPEN) { - i->set_use (true); - } + i->set_use (true); } if (dcp->video) { diff --git a/src/wx/closed_captions_dialog.cc b/src/wx/closed_captions_dialog.cc index 3463ac27a..0b2e63035 100644 --- a/src/wx/closed_captions_dialog.cc +++ b/src/wx/closed_captions_dialog.cc @@ -18,12 +18,15 @@ */ -#include "closed_captions_view.h" +#include "closed_captions_dialog.h" +#include "lib/text_caption.h" #include <boost/bind.hpp> using std::list; using std::cout; using std::make_pair; +using boost::shared_ptr; +using boost::weak_ptr; int const ClosedCaptionsDialog::_num_lines = 3; int const ClosedCaptionsDialog::_num_chars_per_line = 30; @@ -89,22 +92,14 @@ private: }; void -ClosedCaptionsDialog::refresh (DCPTime time) +ClosedCaptionsDialog::update (DCPTime time) { + shared_ptr<Player> player = _player.lock (); + DCPOMATIC_ASSERT (player); list<TextCaption> to_show; - list<Caption>::iterator i = _captions.begin (); - while (i != _captions.end ()) { - if (time > i->second.to) { - list<Caption>::iterator tmp = i; - ++i; - _captions.erase (tmp); - } else if (i->second.contains (time)) { - BOOST_FOREACH (TextCaption j, i->first.text) { - to_show.push_back (j); - } - ++i; - } else { - ++i; + BOOST_FOREACH (PlayerCaption i, player->closed_captions_for_frame(time)) { + BOOST_FOREACH (TextCaption j, i.text) { + to_show.push_back (j); } } @@ -126,14 +121,13 @@ ClosedCaptionsDialog::refresh (DCPTime time) } void -ClosedCaptionsDialog::caption (PlayerCaption caption, DCPTimePeriod period) +ClosedCaptionsDialog::clear () { - _captions.push_back (make_pair (caption, period)); + Refresh (); } void -ClosedCaptionsDialog::clear () +ClosedCaptionsDialog::set_player (weak_ptr<Player> player) { - _captions.clear (); - Refresh (); + _player = player; } diff --git a/src/wx/closed_captions_dialog.h b/src/wx/closed_captions_dialog.h index ca19cc95a..a599bc703 100644 --- a/src/wx/closed_captions_dialog.h +++ b/src/wx/closed_captions_dialog.h @@ -19,24 +19,25 @@ */ #include "lib/dcpomatic_time.h" -#include "lib/player_caption.h" +#include "lib/player.h" #include <wx/wx.h> -class ClosedCaptionsView : public wxDialog +class Player; + +class ClosedCaptionsDialog : public wxDialog { public: - ClosedCaptionsView (wxWindow* parent); + ClosedCaptionsDialog (wxWindow* parent); - void refresh (DCPTime); - void caption (PlayerCaption, DCPTimePeriod); + void update (DCPTime); void clear (); + void set_player (boost::weak_ptr<Player>); private: void paint (); - typedef std::pair<PlayerCaption, DCPTimePeriod> Caption; - std::list<Caption> _captions; std::vector<wxString> _lines; + boost::weak_ptr<Player> _player; static int const _num_lines; static int const _num_chars_per_line; }; diff --git a/src/wx/closed_captions_view.cc b/src/wx/closed_captions_view.cc deleted file mode 100644 index be520057b..000000000 --- a/src/wx/closed_captions_view.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright (C) 2018 Carl Hetherington <cth@carlh.net> - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. - -*/ - -#include "closed_captions_view.h" -#include <boost/bind.hpp> - -using std::list; -using std::cout; -using std::make_pair; - -int const ClosedCaptionsDialog::_num_lines = 3; -int const ClosedCaptionsDialog::_num_chars_per_line = 30; - -ClosedCaptionsDialog::ClosedCaptionsDialog (wxWindow* parent) - : wxDialog (parent, wxID_ANY, _("Closed captions"), wxDefaultPosition, wxDefaultSize, -#ifdef DCPOMATIC_OSX - /* I can't get wxFRAME_FLOAT_ON_PARENT to work on OS X, and although wxSTAY_ON_TOP keeps - the window above all others (and not just our own) it's better than nothing for now. - */ - wxDEFAULT_FRAME_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE | wxSTAY_ON_TOP -#else - wxDEFAULT_FRAME_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE | wxFRAME_FLOAT_ON_PARENT -#endif - ) - -{ - _lines.resize (_num_lines); - Bind (wxEVT_PAINT, boost::bind (&ClosedCaptionsDialog::paint, this)); -} - -void -ClosedCaptionsDialog::paint () -{ - wxPaintDC dc (this); - dc.SetBackground (*wxBLACK_BRUSH); - dc.Clear (); - dc.SetTextForeground (*wxWHITE); - - /* Choose a font which fits vertically */ - int const line_height = dc.GetSize().GetHeight() / _num_lines; - wxFont font (*wxNORMAL_FONT); - font.SetPixelSize (wxSize (0, line_height * 0.8)); - dc.SetFont (font); - - for (int i = 0; i < _num_lines; ++i) { - if (_lines[i].IsEmpty()) { - dc.DrawText (wxString::Format("Line %d", i + 1), 8, line_height * i); - } else { - dc.DrawText (_lines[i], 8, line_height * i); - } - } -} - -class ClosedCaptionSorter -{ -public: - bool operator() (TextCaption const & a, TextCaption const & b) - { - return from_top(a) < from_top(b); - } - -private: - float from_top (TextCaption const & c) const - { - switch (c.v_align()) { - case dcp::VALIGN_TOP: - return c.v_position(); - case dcp::VALIGN_CENTER: - return c.v_position() + 0.5; - case dcp::VALIGN_BOTTOM: - return 1.0 - c.v_position(); - } - DCPOMATIC_ASSERT (false); - return 0; - } -}; - -void -ClosedCaptionsDialog::refresh (DCPTime time) -{ - list<TextCaption> to_show; - list<Caption>::iterator i = _captions.begin (); - while (i != _captions.end ()) { - if (time > i->second.to) { - list<Caption>::iterator tmp = i; - ++i; - _captions.erase (tmp); - } else if (i->second.contains (time)) { - BOOST_FOREACH (TextCaption j, i->first.text) { - to_show.push_back (j); - } - ++i; - } else { - ++i; - } - } - - for (int j = 0; j < _num_lines; ++j) { - _lines[j] = ""; - } - - to_show.sort (ClosedCaptionSorter()); - - list<TextCaption>::const_iterator j = to_show.begin(); - int k = 0; - while (j != to_show.end() && k < _num_lines) { - _lines[k] = j->text(); - ++j; - ++k; - } - - Refresh (); -} - -void -ClosedCaptionsDialog::caption (PlayerCaption caption, DCPTimePeriod period) -{ - _captions.push_back (make_pair (caption, period)); -} - -void -ClosedCaptionsDialog::clear () -{ - _captions.clear (); - Refresh (); -} diff --git a/src/wx/closed_captions_view.h b/src/wx/closed_captions_view.h deleted file mode 100644 index 9469b975c..000000000 --- a/src/wx/closed_captions_view.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Copyright (C) 2018 Carl Hetherington <cth@carlh.net> - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. - -*/ - -#include "lib/dcpomatic_time.h" -#include "lib/player_caption.h" -#include <wx/wx.h> - -class ClosedCaptionsDialog : public wxDialog -{ -public: - ClosedCaptionsDialog (wxWindow* parent); - - void refresh (DCPTime); - void caption (PlayerCaption, DCPTimePeriod); - void clear (); - -private: - void paint (); - - typedef std::pair<PlayerCaption, DCPTimePeriod> Caption; - std::list<Caption> _captions; - std::vector<wxString> _lines; - static int const _num_lines; - static int const _num_chars_per_line; -}; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 9c714b562..651196d3c 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -26,7 +26,7 @@ #include "playhead_to_timecode_dialog.h" #include "playhead_to_frame_dialog.h" #include "wx_util.h" -#include "closed_captions_view.h" +#include "closed_captions_dialog.h" #include "lib/film.h" #include "lib/ratio.h" #include "lib/util.h" @@ -203,6 +203,7 @@ FilmViewer::set_film (shared_ptr<Film> film) if (!_film) { _player.reset (); + _closed_captions_dialog->set_player (_player); recreate_butler (); _frame.reset (); refresh_panel (); @@ -221,12 +222,13 @@ FilmViewer::set_film (shared_ptr<Film> film) return; } + _closed_captions_dialog->set_player (_player); + _player->set_always_burn_open_captions (); _player->set_play_referenced (); _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1, _2)); - _player->Caption.connect (boost::bind (&FilmViewer::caption, this, _1, _2, _3)); /* Keep about 1 second's worth of history samples */ _latency_history_count = _film->audio_frame_rate() / _audio_block_size; @@ -354,7 +356,7 @@ FilmViewer::display_player_video () refresh_panel (); - _closed_captions_dialog->refresh (time()); + _closed_captions_dialog->update (time()); } void @@ -948,11 +950,3 @@ FilmViewer::show_closed_captions () { _closed_captions_dialog->Show(); } - -void -FilmViewer::caption (PlayerCaption c, CaptionType t, DCPTimePeriod p) -{ - if (t == CAPTION_CLOSED) { - _closed_captions_dialog->caption (c, p); - } -} diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 6825ef2c0..266509a44 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -116,7 +116,6 @@ private: DCPTime time () const; Frame average_latency () const; DCPTime one_video_frame () const; - void caption (PlayerCaption caption, CaptionType type, DCPTimePeriod period); boost::shared_ptr<Film> _film; boost::shared_ptr<Player> _player; |
