From: Carl Hetherington Date: Thu, 10 Jul 2014 10:27:26 +0000 (+0100) Subject: Basics of DCP subtitle import. X-Git-Tag: v2.0.48~742 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=bde76c3341775bd02da59932d285e14eade64ae0 Basics of DCP subtitle import. --- diff --git a/src/lib/content_factory.cc b/src/lib/content_factory.cc index 73e333816..16340adb4 100644 --- a/src/lib/content_factory.cc +++ b/src/lib/content_factory.cc @@ -27,6 +27,7 @@ #include "sndfile_content.h" #include "subrip_content.h" #include "dcp_content.h" +#include "dcp_subtitle_content.h" #include "util.h" using std::string; @@ -57,6 +58,8 @@ content_factory (shared_ptr film, cxml::NodePtr node, int version, l content.reset (new SubRipContent (film, node, version)); } else if (type == "DCP") { content.reset (new DCPContent (film, node, version)); + } else if (type == "DCPSubtitle") { + content.reset (new DCPSubtitleContent (film, node, version)); } return content; @@ -81,6 +84,8 @@ content_factory (shared_ptr film, boost::filesystem::path path) content.reset (new SndfileContent (film, path)); } else if (ext == ".srt") { content.reset (new SubRipContent (film, path)); + } else if (ext == ".xml") { + content.reset (new DCPSubtitleContent (film, path)); } else { content.reset (new FFmpegContent (film, path)); } diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index 8ecd52f24..b1d0d9a37 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -110,3 +110,9 @@ DCPContent::full_length () const assert (film); return DCPTime (video_length (), FrameRateChange (video_frame_rate (), film->video_frame_rate ())); } + +string +DCPContent::identifier () const +{ + return SubtitleContent::identifier (); +} diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h index a6ef97400..7ead80ecb 100644 --- a/src/lib/dcp_content.h +++ b/src/lib/dcp_content.h @@ -38,6 +38,7 @@ public: std::string summary () const; std::string technical_summary () const; void as_xml (xmlpp::Node *) const; + std::string identifier () const; boost::filesystem::path directory () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc new file mode 100644 index 000000000..e9998dd2a --- /dev/null +++ b/src/lib/dcp_subtitle_content.cc @@ -0,0 +1,87 @@ +/* + Copyright (C) 2014 Carl Hetherington + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include "dcp_subtitle_content.h" + +#include "i18n.h" + +using std::string; +using boost::shared_ptr; +using dcp::raw_convert; + +DCPSubtitleContent::DCPSubtitleContent (shared_ptr film, boost::filesystem::path path) + : Content (film, path) + , SubtitleContent (film, path) +{ + +} + +DCPSubtitleContent::DCPSubtitleContent (shared_ptr film, cxml::ConstNodePtr node, int version) + : Content (film, node) + , SubtitleContent (film, node, version) + , _length (node->number_child ("Length")) +{ + +} + +void +DCPSubtitleContent::examine (shared_ptr job) +{ + Content::examine (job); + dcp::SubtitleContent sc (path (0), false); + _length = DCPTime::from_frames (sc.intrinsic_duration(), sc.edit_rate().as_float ()); +} + +DCPTime +DCPSubtitleContent::full_length () const +{ + /* XXX: this assumes that the timing of the subtitle file is appropriate + for the DCP's frame rate. + */ + return _length; +} + +string +DCPSubtitleContent::summary () const +{ + return path_summary() + " " + _("[subtitles]"); +} + +string +DCPSubtitleContent::technical_summary () const +{ + return Content::technical_summary() + " - " + _("DCP XML subtitles"); +} + +string +DCPSubtitleContent::information () const +{ + +} + +void +DCPSubtitleContent::as_xml (xmlpp::Node* node) const +{ + node->add_child("Type")->add_child_text ("DCPSubtitle"); + Content::as_xml (node); + SubtitleContent::as_xml (node); + node->add_child("Length")->add_child_text (raw_convert (_length.get ())); +} diff --git a/src/lib/dcp_subtitle_content.h b/src/lib/dcp_subtitle_content.h new file mode 100644 index 000000000..79338c1af --- /dev/null +++ b/src/lib/dcp_subtitle_content.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2014 Carl Hetherington + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "subtitle_content.h" + +class DCPSubtitleContent : public SubtitleContent +{ +public: + DCPSubtitleContent (boost::shared_ptr, boost::filesystem::path); + DCPSubtitleContent (boost::shared_ptr, cxml::ConstNodePtr, int); + + void examine (boost::shared_ptr); + std::string summary () const; + std::string technical_summary () const; + std::string information () const; + void as_xml (xmlpp::Node *) const; + DCPTime full_length () const; + +private: + DCPTime _length; +}; diff --git a/src/lib/dcp_subtitle_decoder.cc b/src/lib/dcp_subtitle_decoder.cc new file mode 100644 index 000000000..c1f0ab500 --- /dev/null +++ b/src/lib/dcp_subtitle_decoder.cc @@ -0,0 +1,82 @@ +/* + Copyright (C) 2014 Carl Hetherington + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include "dcp_subtitle_decoder.h" +#include "dcp_subtitle_content.h" + +using std::list; +using boost::shared_ptr; + +DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr content) + : SubtitleDecoder (content) +{ + dcp::SubtitleContent c (content->path (0), false); + _subtitles = c.subtitles (); + _next = _subtitles.begin (); +} + +void +DCPSubtitleDecoder::seek (ContentTime time, bool accurate) +{ + SubtitleDecoder::seek (time, accurate); + + _next = _subtitles.begin (); + list::const_iterator i = _subtitles.begin (); + while (i != _subtitles.end() && ContentTime::from_seconds (_next->in().to_seconds()) < time) { + ++i; + } +} + +bool +DCPSubtitleDecoder::pass () +{ + if (_next == _subtitles.end ()) { + return true; + } + + list s; + s.push_back (*_next); + text_subtitle (s); + ++_next; + + return false; +} + +list +DCPSubtitleDecoder::subtitles_during (ContentTimePeriod p, bool starting) const +{ + /* XXX: inefficient */ + + list d; + + for (list::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) { + ContentTimePeriod period ( + ContentTime::from_seconds (i->in().to_seconds ()), + ContentTime::from_seconds (i->out().to_seconds ()) + ); + + if ((starting && p.contains (period.from)) || (!starting && p.overlaps (period))) { + d.push_back (period); + } + } + + return d; +} + diff --git a/src/lib/dcp_subtitle_decoder.h b/src/lib/dcp_subtitle_decoder.h new file mode 100644 index 000000000..070562458 --- /dev/null +++ b/src/lib/dcp_subtitle_decoder.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2014 Carl Hetherington + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "subtitle_decoder.h" + +class DCPSubtitleContent; + +class DCPSubtitleDecoder : public SubtitleDecoder +{ +public: + DCPSubtitleDecoder (boost::shared_ptr); + +protected: + void seek (ContentTime time, bool accurate); + bool pass (); + +private: + std::list subtitles_during (ContentTimePeriod, bool starting) const; + + std::list _subtitles; + std::list::const_iterator _next; +}; diff --git a/src/lib/player.cc b/src/lib/player.cc index c855471b4..9e14b65b3 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -45,6 +45,8 @@ #include "frame_rate_change.h" #include "dcp_content.h" #include "dcp_decoder.h" +#include "dcp_subtitle_content.h" +#include "dcp_subtitle_decoder.h" #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); @@ -160,6 +162,13 @@ Player::setup_pieces () frc = best_overlap_frc; } + /* DCPSubtitleContent */ + shared_ptr dsc = dynamic_pointer_cast (*i); + if (dsc) { + decoder.reset (new DCPSubtitleDecoder (dsc)); + frc = best_overlap_frc; + } + _pieces.push_back (shared_ptr (new Piece (*i, decoder, frc.get ()))); } diff --git a/src/lib/subrip_content.cc b/src/lib/subrip_content.cc index 455bd1e8f..c60b05d50 100644 --- a/src/lib/subrip_content.cc +++ b/src/lib/subrip_content.cc @@ -77,7 +77,7 @@ SubRipContent::technical_summary () const string SubRipContent::information () const { - + } void @@ -97,15 +97,3 @@ SubRipContent::full_length () const */ return _length; } - -string -SubRipContent::identifier () const -{ - stringstream s; - s << Content::identifier() - << "_" << raw_convert (subtitle_scale()) - << "_" << raw_convert (subtitle_x_offset()) - << "_" << raw_convert (subtitle_y_offset()); - - return s.str (); -} diff --git a/src/lib/subrip_content.h b/src/lib/subrip_content.h index 5688f81d5..7da6e71f7 100644 --- a/src/lib/subrip_content.h +++ b/src/lib/subrip_content.h @@ -35,7 +35,6 @@ public: std::string information () const; void as_xml (xmlpp::Node *) const; DCPTime full_length () const; - std::string identifier () const; private: DCPTime _length; diff --git a/src/lib/subrip_decoder.cc b/src/lib/subrip_decoder.cc index 4bdf06e7c..e2bdc347b 100644 --- a/src/lib/subrip_decoder.cc +++ b/src/lib/subrip_decoder.cc @@ -75,7 +75,7 @@ SubRipDecoder::pass () } text_subtitle (out); - _next++; + ++_next; return false; } diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc index 88e48b420..8c94a94b9 100644 --- a/src/lib/subtitle_content.cc +++ b/src/lib/subtitle_content.cc @@ -26,6 +26,7 @@ #include "i18n.h" using std::string; +using std::stringstream; using std::vector; using std::cout; using boost::shared_ptr; @@ -155,3 +156,15 @@ SubtitleContent::set_subtitle_scale (double s) } signal_changed (SubtitleContentProperty::SUBTITLE_SCALE); } + +string +SubtitleContent::identifier () const +{ + stringstream s; + s << Content::identifier() + << "_" << raw_convert (subtitle_scale()) + << "_" << raw_convert (subtitle_x_offset()) + << "_" << raw_convert (subtitle_y_offset()); + + return s.str (); +} diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h index f46a87c15..1425c33cd 100644 --- a/src/lib/subtitle_content.h +++ b/src/lib/subtitle_content.h @@ -40,6 +40,7 @@ public: SubtitleContent (boost::shared_ptr, std::vector >); void as_xml (xmlpp::Node *) const; + std::string identifier () const; void set_subtitle_use (bool); void set_subtitle_x_offset (double); diff --git a/src/lib/wscript b/src/lib/wscript index ae6e0b800..d96bb7f96 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -19,6 +19,8 @@ sources = """ dcp_content_type.cc dcp_decoder.cc dcp_examiner.cc + dcp_subtitle_content.cc + dcp_subtitle_decoder.cc dcp_video.cc dcpomatic_time.cc dolby_cp750.cc diff --git a/src/wx/subtitle_panel.cc b/src/wx/subtitle_panel.cc index adbd0f32e..5cfd29504 100644 --- a/src/wx/subtitle_panel.cc +++ b/src/wx/subtitle_panel.cc @@ -22,6 +22,9 @@ #include "lib/ffmpeg_content.h" #include "lib/subrip_content.h" #include "lib/ffmpeg_subtitle_stream.h" +#include "lib/dcp_subtitle_content.h" +#include "lib/subrip_decoder.h" +#include "lib/dcp_subtitle_decoder.h" #include "subtitle_panel.h" #include "film_editor.h" #include "wx_util.h" @@ -156,18 +159,19 @@ SubtitlePanel::setup_sensitivity () { int any_subs = 0; int ffmpeg_subs = 0; - int subrip_subs = 0; + int subrip_or_dcp_subs = 0; SubtitleContentList c = _editor->selected_subtitle_content (); for (SubtitleContentList::const_iterator i = c.begin(); i != c.end(); ++i) { shared_ptr fc = boost::dynamic_pointer_cast (*i); shared_ptr sc = boost::dynamic_pointer_cast (*i); + shared_ptr dsc = boost::dynamic_pointer_cast (*i); if (fc) { if (!fc->subtitle_streams().empty ()) { ++ffmpeg_subs; ++any_subs; } - } else if (sc) { - ++subrip_subs; + } else if (sc || dsc) { + ++subrip_or_dcp_subs; ++any_subs; } else { ++any_subs; @@ -181,7 +185,7 @@ SubtitlePanel::setup_sensitivity () _y_offset->Enable (any_subs > 0 && use); _scale->Enable (any_subs > 0 && use); _stream->Enable (ffmpeg_subs == 1); - _view_button->Enable (subrip_subs == 1); + _view_button->Enable (subrip_or_dcp_subs == 1); } void @@ -253,9 +257,21 @@ SubtitlePanel::view_clicked () SubtitleContentList c = _editor->selected_subtitle_content (); assert (c.size() == 1); + + shared_ptr decoder; + shared_ptr sr = dynamic_pointer_cast (c.front ()); if (sr) { - _view = new SubtitleView (this, _editor->film(), sr); + decoder.reset (new SubRipDecoder (sr)); + } + + shared_ptr dc = dynamic_pointer_cast (c.front ()); + if (dc) { + decoder.reset (new DCPSubtitleDecoder (dc)); + } + + if (decoder) { + _view = new SubtitleView (this, _editor->film(), decoder, c.front()->position ()); _view->Show (); } } diff --git a/src/wx/subtitle_view.cc b/src/wx/subtitle_view.cc index 25392c81a..dc41db2fa 100644 --- a/src/wx/subtitle_view.cc +++ b/src/wx/subtitle_view.cc @@ -28,7 +28,7 @@ using std::list; using boost::shared_ptr; using boost::dynamic_pointer_cast; -SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr content) +SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr decoder, DCPTime position) : wxDialog (parent, wxID_ANY, _("Subtitles")) { _list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); @@ -65,9 +65,8 @@ SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr< sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); } - shared_ptr decoder (new SubRipDecoder (content)); list subs = decoder->get_text_subtitles (ContentTimePeriod (ContentTime(), ContentTime::max ()), true); - FrameRateChange const frc = film->active_frame_rate_change (content->position ()); + FrameRateChange const frc = film->active_frame_rate_change (position); int n = 0; for (list::const_iterator i = subs.begin(); i != subs.end(); ++i) { for (list::const_iterator j = i->subs.begin(); j != i->subs.end(); ++j) { diff --git a/src/wx/subtitle_view.h b/src/wx/subtitle_view.h index 2edc28c09..338742afc 100644 --- a/src/wx/subtitle_view.h +++ b/src/wx/subtitle_view.h @@ -21,12 +21,12 @@ #include #include -class SubRipContent; +class SubtitleDecoder; class SubtitleView : public wxDialog { public: - SubtitleView (wxWindow *, boost::shared_ptr, boost::shared_ptr); + SubtitleView (wxWindow *, boost::shared_ptr, boost::shared_ptr, DCPTime position); private: wxListCtrl* _list;