Basics of DCP subtitle import.
authorCarl Hetherington <cth@carlh.net>
Thu, 10 Jul 2014 10:27:26 +0000 (11:27 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 10 Jul 2014 10:27:26 +0000 (11:27 +0100)
17 files changed:
src/lib/content_factory.cc
src/lib/dcp_content.cc
src/lib/dcp_content.h
src/lib/dcp_subtitle_content.cc [new file with mode: 0644]
src/lib/dcp_subtitle_content.h [new file with mode: 0644]
src/lib/dcp_subtitle_decoder.cc [new file with mode: 0644]
src/lib/dcp_subtitle_decoder.h [new file with mode: 0644]
src/lib/player.cc
src/lib/subrip_content.cc
src/lib/subrip_content.h
src/lib/subrip_decoder.cc
src/lib/subtitle_content.cc
src/lib/subtitle_content.h
src/lib/wscript
src/wx/subtitle_panel.cc
src/wx/subtitle_view.cc
src/wx/subtitle_view.h

index 73e3338166f76688caf53b308bd4b20f273f772a..16340adb43b0e74f8f14d4b2bc039e258d8e58a9 100644 (file)
@@ -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<const Film> 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<const Film> 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));
        }
index 8ecd52f24e26513ff6ff10705a6b5d9e8386ed44..b1d0d9a378b855b97893e5635d6d11d3cf5b56b5 100644 (file)
@@ -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 ();
+}
index a6ef9740033312da147145dff4cc8aec8fc7d29b..7ead80ecb373730de35d89a2d92c6eaa9cf3bca9 100644 (file)
@@ -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 (file)
index 0000000..e9998dd
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+    Copyright (C) 2014 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
+    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 <dcp/subtitle_content.h>
+#include <dcp/raw_convert.h>
+#include "dcp_subtitle_content.h"
+
+#include "i18n.h"
+
+using std::string;
+using boost::shared_ptr;
+using dcp::raw_convert;
+
+DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, boost::filesystem::path path)
+       : Content (film, path)
+       , SubtitleContent (film, path)
+{
+       
+}
+
+DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
+       : Content (film, node)
+       , SubtitleContent (film, node, version)
+       , _length (node->number_child<DCPTime::Type> ("Length"))
+{
+
+}
+
+void
+DCPSubtitleContent::examine (shared_ptr<Job> 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<string> (_length.get ()));
+}
diff --git a/src/lib/dcp_subtitle_content.h b/src/lib/dcp_subtitle_content.h
new file mode 100644 (file)
index 0000000..79338c1
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    Copyright (C) 2014 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
+    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<const Film>, boost::filesystem::path);
+       DCPSubtitleContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
+
+       void examine (boost::shared_ptr<Job>);
+       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 (file)
index 0000000..c1f0ab5
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    Copyright (C) 2014 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
+    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 <dcp/subtitle_content.h>
+#include "dcp_subtitle_decoder.h"
+#include "dcp_subtitle_content.h"
+
+using std::list;
+using boost::shared_ptr;
+
+DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr<const DCPSubtitleContent> 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<dcp::SubtitleString>::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<dcp::SubtitleString> s;
+       s.push_back (*_next);
+       text_subtitle (s);
+       ++_next;
+       
+       return false;
+}
+
+list<ContentTimePeriod>
+DCPSubtitleDecoder::subtitles_during (ContentTimePeriod p, bool starting) const
+{
+       /* XXX: inefficient */
+
+       list<ContentTimePeriod> d;
+
+       for (list<dcp::SubtitleString>::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 (file)
index 0000000..0705624
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    Copyright (C) 2014 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
+    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<const DCPSubtitleContent>);
+
+protected:
+       void seek (ContentTime time, bool accurate);
+       bool pass ();
+
+private:
+       std::list<ContentTimePeriod> subtitles_during (ContentTimePeriod, bool starting) const;
+
+       std::list<dcp::SubtitleString> _subtitles;
+       std::list<dcp::SubtitleString>::const_iterator _next;
+};
index c855471b4187a72e4545397453c92a7be6d8dfe7..9e14b65b301aa1c2c20f77950a9a893c65a1f5cb 100644 (file)
@@ -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<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (*i);
+               if (dsc) {
+                       decoder.reset (new DCPSubtitleDecoder (dsc));
+                       frc = best_overlap_frc;
+               }
+
                _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder, frc.get ())));
        }
 
index 455bd1e8fb32286c5ceecc00be0714d088e755d7..c60b05d50a1ede29617d30ae2c8733593546b190 100644 (file)
@@ -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<string> (subtitle_scale())
-         << "_" << raw_convert<string> (subtitle_x_offset())
-         << "_" << raw_convert<string> (subtitle_y_offset());
-
-       return s.str ();
-}
index 5688f81d5fe44639450e3d8d8a57d4acb9f4a9b3..7da6e71f7b49e262e0cb741f72bb6fcfcc897116 100644 (file)
@@ -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;
index 4bdf06e7c331f050463a60873c19b5f0f7725dac..e2bdc347b93b202183d483f6a606dfc665324a13 100644 (file)
@@ -75,7 +75,7 @@ SubRipDecoder::pass ()
        }
 
        text_subtitle (out);
-       _next++;
+       ++_next;
        return false;
 }
 
index 88e48b420150192118204d6469b296d5c49aec2d..8c94a94b995f7f35798dc3ec06f1a02a090890a4 100644 (file)
@@ -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<string> (subtitle_scale())
+         << "_" << raw_convert<string> (subtitle_x_offset())
+         << "_" << raw_convert<string> (subtitle_y_offset());
+
+       return s.str ();
+}
index f46a87c156898c4ab6cf1c5ff05d76e31f091c07..1425c33cd695ff5a06941e11db27cd5386c7000b 100644 (file)
@@ -40,6 +40,7 @@ public:
        SubtitleContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
 
        void as_xml (xmlpp::Node *) const;
+       std::string identifier () const;
 
        void set_subtitle_use (bool);
        void set_subtitle_x_offset (double);
index ae6e0b800dfd782dca4d24516a0a65268fcb9b8b..d96bb7f96c8eac8981f8ac74552a14c68686d20d 100644 (file)
@@ -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
index adbd0f32e46445271afeec3602bdd20e3327d2e3..5cfd295042e6bfdc407511a6f2171ca2a041b306 100644 (file)
@@ -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<const FFmpegContent> fc = boost::dynamic_pointer_cast<const FFmpegContent> (*i);
                shared_ptr<const SubRipContent> sc = boost::dynamic_pointer_cast<const SubRipContent> (*i);
+               shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (*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<SubtitleDecoder> decoder;
+       
        shared_ptr<SubRipContent> sr = dynamic_pointer_cast<SubRipContent> (c.front ());
        if (sr) {
-               _view = new SubtitleView (this, _editor->film(), sr);
+               decoder.reset (new SubRipDecoder (sr));
+       }
+       
+       shared_ptr<DCPSubtitleContent> dc = dynamic_pointer_cast<DCPSubtitleContent> (c.front ());
+       if (dc) {
+               decoder.reset (new DCPSubtitleDecoder (dc));
+       }
+       
+       if (decoder) {
+               _view = new SubtitleView (this, _editor->film(), decoder, c.front()->position ());
                _view->Show ();
        }
 }
index 25392c81ad3e8092e278a58198fde5b20a3ad806..dc41db2fa51e82fd49ac5ba9c2165f7149174301 100644 (file)
@@ -28,7 +28,7 @@ using std::list;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
-SubtitleView::SubtitleView (wxWindow* parent, shared_ptr<Film> film, shared_ptr<SubRipContent> content)
+SubtitleView::SubtitleView (wxWindow* parent, shared_ptr<Film> film, shared_ptr<SubtitleDecoder> 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> film, shared_ptr<
                sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
        }
 
-       shared_ptr<SubRipDecoder> decoder (new SubRipDecoder (content));
        list<ContentTextSubtitle> 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<ContentTextSubtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
                for (list<dcp::SubtitleString>::const_iterator j = i->subs.begin(); j != i->subs.end(); ++j) {
index 2edc28c09e9aaf5905c42c18a97f6a8f669f9959..338742afcaac5575f35bc58bc895b9757967106b 100644 (file)
 #include <wx/wx.h>
 #include <wx/listctrl.h>
 
-class SubRipContent;
+class SubtitleDecoder;
 
 class SubtitleView : public wxDialog
 {
 public:
-       SubtitleView (wxWindow *, boost::shared_ptr<Film>, boost::shared_ptr<SubRipContent>);
+       SubtitleView (wxWindow *, boost::shared_ptr<Film>, boost::shared_ptr<SubtitleDecoder>, DCPTime position);
 
 private:       
        wxListCtrl* _list;