--- /dev/null
+#!/usr/bin/python
+
+import re
+import os
+
+files = "src/lib/*.cc src/lib/*.h src/wx/*.cc src/wx/*.h src/tools/*.cc test/*.cc"
+
+def convert(name):
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
+
+def try_to_rename(f, t):
+ try:
+ print '%s -> %s' % (f, t),
+ os.rename(f, t)
+ print 'OK'
+ except:
+ print 'Failed'
+
+def rename_class(f, t):
+ os.system('sed -i "s/%s/%s/g" %s' % (f, t, files))
+ os.system('sed -i "s/%s/%s/g" src/lib/wscript src/wx/wscript' % (convert(f), convert(t)))
+ try_to_rename('src/lib/%s.cc' % convert(f), 'src/lib/%s.cc' % convert(t))
+ try_to_rename('src/lib/%s.h' % convert(f), 'src/lib/%s.h' % convert(t))
+ try_to_rename('src/wx/%s.cc' % convert(f), 'src/wx/%s.cc' % convert(t))
+ try_to_rename('src/wx/%s.h' % convert(f), 'src/wx/%s.h' % convert(t))
+ os.system('sed -i "s/include \\"%s.h\\"/include \\"%s.h\\"/g" %s' % (convert(f), convert(t), files))
+ os.system('sed -i "s/include \\"lib\/%s.h\\"/include \\"lib\/%s.h\\"/g" %s' % (convert(f), convert(t), files))
+
+rename_class("ActiveCaptions", "ActiveText")
+rename_class("BitmapCaption", "BitmapText")
+rename_class("ContentCaption", "ContentText")
+rename_class("ContentTextCaption", "ContentStringText")
+rename_class("TextCaptionFileContent", "StringTextFileContent")
+rename_class("TextCaptionFileDecoder", "StringTextFileDecoder")
+rename_class("TextCaptionFile", "StringTextFile")
+rename_class("TextCaption", "StringText")
+rename_class("PlayerCaption", "PlayerText")
+rename_class("CaptionContent", "TextContent")
+rename_class("CaptionDecoder", "TextDecoder")
+rename_class("CaptionPanel", "TextPanel")
+rename_class("CaptionView", "TextView")
+rename_class("CaptionAppearanceDialog", "SubtitleAppearanceDialog")
+rename_class("CaptionType", "TextType")
+++ /dev/null
-/*
- Copyright (C) 2017-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 "active_captions.h"
-#include "caption_content.h"
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-using std::list;
-using std::pair;
-using std::make_pair;
-using boost::weak_ptr;
-using boost::shared_ptr;
-using boost::optional;
-
-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.
- */
-list<PlayerCaption>
-ActiveCaptions::get_burnt (DCPTimePeriod period, bool always_burn_captions) 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) {
- continue;
- }
-
- if (!caption->use() || (!always_burn_captions && !caption->burn())) {
- /* Not burning this content */
- continue;
- }
-
- add (period, ps, i->second);
- }
-
- return ps;
-}
-
-/** Remove subtitles that finish before a given time from our list.
- * @param time Time to remove before.
- */
-void
-ActiveCaptions::clear_before (DCPTime time)
-{
- Map updated;
- for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) {
- list<Period> as;
- BOOST_FOREACH (Period j, i->second) {
- if (!j.to || j.to.get() >= time) {
- as.push_back (j);
- }
- }
- if (!as.empty ()) {
- updated[i->first] = as;
- }
- }
- _data = updated;
-}
-
-/** Add a new subtitle with a from time.
- * @param content Content that the subtitle is from.
- * @param ps Subtitles.
- * @param from From time for these subtitles.
- */
-void
-ActiveCaptions::add_from (weak_ptr<const CaptionContent> content, PlayerCaption ps, DCPTime from)
-{
- if (_data.find(content) == _data.end()) {
- _data[content] = list<Period>();
- }
- _data[content].push_back (Period (ps, from));
-}
-
-/** Add the to time for the last subtitle added from a piece of content.
- * @param content Content that the subtitle is from.
- * @param to To time for the last subtitle submitted to add_from for this content.
- * @return Return the corresponding subtitles and their from time.
- */
-pair<PlayerCaption, DCPTime>
-ActiveCaptions::add_to (weak_ptr<const CaptionContent> content, DCPTime to)
-{
- DCPOMATIC_ASSERT (_data.find(content) != _data.end());
-
- _data[content].back().to = to;
-
- BOOST_FOREACH (TextCaption& i, _data[content].back().subs.text) {
- i.set_out (dcp::Time(to.seconds(), 1000));
- }
-
- return make_pair (_data[content].back().subs, _data[content].back().from);
-}
-
-/** @param content Some content.
- * @return true if we have any active subtitles from this content.
- */
-bool
-ActiveCaptions::have (weak_ptr<const CaptionContent> content) const
-{
- Map::const_iterator i = _data.find(content);
- if (i == _data.end()) {
- return false;
- }
-
- return !i->second.empty();
-}
-
-void
-ActiveCaptions::clear ()
-{
- _data.clear ();
-}
+++ /dev/null
-/*
- Copyright (C) 2017-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/>.
-
-*/
-
-/** @file src/lib/active_captions.h
- * @brief ActiveCaptions class.
- */
-
-#include "dcpomatic_time.h"
-#include "player_caption.h"
-#include <boost/noncopyable.hpp>
-#include <list>
-#include <map>
-
-class CaptionContent;
-
-/** @class ActiveCaptions
- * @brief A class to maintain information on active subtitles for Player.
- */
-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 ();
- void add_from (boost::weak_ptr<const CaptionContent> content, PlayerCaption ps, DCPTime from);
- std::pair<PlayerCaption, DCPTime> add_to (boost::weak_ptr<const CaptionContent> content, DCPTime to);
- bool have (boost::weak_ptr<const CaptionContent> content) const;
-
-private:
- class Period
- {
- public:
- Period () {}
-
- Period (PlayerCaption s, DCPTime f)
- : subs (s)
- , from (f)
- {}
-
- PlayerCaption subs;
- DCPTime from;
- boost::optional<DCPTime> to;
- };
-
- 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;
-};
--- /dev/null
+/*
+ Copyright (C) 2017-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 "active_text.h"
+#include "text_content.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+using std::list;
+using std::pair;
+using std::make_pair;
+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
+{
+ 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.
+ */
+list<PlayerText>
+ActiveText::get_burnt (DCPTimePeriod period, bool always_burn_captions) const
+{
+ list<PlayerText> ps;
+
+ for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) {
+
+ shared_ptr<const TextContent> caption = i->first.lock ();
+ if (!caption) {
+ continue;
+ }
+
+ if (!caption->use() || (!always_burn_captions && !caption->burn())) {
+ /* Not burning this content */
+ continue;
+ }
+
+ add (period, ps, i->second);
+ }
+
+ return ps;
+}
+
+/** Remove subtitles that finish before a given time from our list.
+ * @param time Time to remove before.
+ */
+void
+ActiveText::clear_before (DCPTime time)
+{
+ Map updated;
+ for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) {
+ list<Period> as;
+ BOOST_FOREACH (Period j, i->second) {
+ if (!j.to || j.to.get() >= time) {
+ as.push_back (j);
+ }
+ }
+ if (!as.empty ()) {
+ updated[i->first] = as;
+ }
+ }
+ _data = updated;
+}
+
+/** Add a new subtitle with a from time.
+ * @param content Content that the subtitle is from.
+ * @param ps Subtitles.
+ * @param from From time for these subtitles.
+ */
+void
+ActiveText::add_from (weak_ptr<const TextContent> content, PlayerText ps, DCPTime from)
+{
+ if (_data.find(content) == _data.end()) {
+ _data[content] = list<Period>();
+ }
+ _data[content].push_back (Period (ps, from));
+}
+
+/** Add the to time for the last subtitle added from a piece of content.
+ * @param content Content that the subtitle is from.
+ * @param to To time for the last subtitle submitted to add_from for this content.
+ * @return Return the corresponding subtitles and their from time.
+ */
+pair<PlayerText, DCPTime>
+ActiveText::add_to (weak_ptr<const TextContent> content, DCPTime to)
+{
+ DCPOMATIC_ASSERT (_data.find(content) != _data.end());
+
+ _data[content].back().to = to;
+
+ BOOST_FOREACH (StringText& i, _data[content].back().subs.text) {
+ i.set_out (dcp::Time(to.seconds(), 1000));
+ }
+
+ return make_pair (_data[content].back().subs, _data[content].back().from);
+}
+
+/** @param content Some content.
+ * @return true if we have any active subtitles from this content.
+ */
+bool
+ActiveText::have (weak_ptr<const TextContent> content) const
+{
+ Map::const_iterator i = _data.find(content);
+ if (i == _data.end()) {
+ return false;
+ }
+
+ return !i->second.empty();
+}
+
+void
+ActiveText::clear ()
+{
+ _data.clear ();
+}
--- /dev/null
+/*
+ Copyright (C) 2017-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/>.
+
+*/
+
+/** @file src/lib/active_captions.h
+ * @brief ActiveText class.
+ */
+
+#include "dcpomatic_time.h"
+#include "player_text.h"
+#include <boost/noncopyable.hpp>
+#include <list>
+#include <map>
+
+class TextContent;
+
+/** @class ActiveText
+ * @brief A class to maintain information on active subtitles for Player.
+ */
+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 ();
+ void add_from (boost::weak_ptr<const TextContent> content, PlayerText ps, DCPTime from);
+ std::pair<PlayerText, DCPTime> add_to (boost::weak_ptr<const TextContent> content, DCPTime to);
+ bool have (boost::weak_ptr<const TextContent> content) const;
+
+private:
+ class Period
+ {
+ public:
+ Period () {}
+
+ Period (PlayerText s, DCPTime f)
+ : subs (s)
+ , from (f)
+ {}
+
+ PlayerText subs;
+ DCPTime from;
+ boost::optional<DCPTime> to;
+ };
+
+ 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;
+
+ Map _data;
+};
+++ /dev/null
-/*
- Copyright (C) 2014-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/>.
-
-*/
-
-#ifndef DCPOMATIC_BITMAP_CAPTION_H
-#define DCPOMATIC_BITMAP_CAPTION_H
-
-#include "rect.h"
-#include <boost/shared_ptr.hpp>
-
-class Image;
-
-class BitmapCaption
-{
-public:
- BitmapCaption (boost::shared_ptr<Image> i, dcpomatic::Rect<double> r)
- : image (i)
- , rectangle (r)
- {}
-
- boost::shared_ptr<Image> image;
- /** Area that the subtitle covers on its corresponding video, expressed in
- * proportions of the image size; e.g. rectangle.x = 0.5 would mean that
- * the rectangle starts half-way across the video.
- *
- * This rectangle may or may not have had a TextContent's offsets and
- * scale applied to it, depending on context.
- */
- dcpomatic::Rect<double> rectangle;
-};
-
-#endif
--- /dev/null
+/*
+ Copyright (C) 2014-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/>.
+
+*/
+
+#ifndef DCPOMATIC_BITMAP_CAPTION_H
+#define DCPOMATIC_BITMAP_CAPTION_H
+
+#include "rect.h"
+#include <boost/shared_ptr.hpp>
+
+class Image;
+
+class BitmapText
+{
+public:
+ BitmapText (boost::shared_ptr<Image> i, dcpomatic::Rect<double> r)
+ : image (i)
+ , rectangle (r)
+ {}
+
+ boost::shared_ptr<Image> image;
+ /** Area that the subtitle covers on its corresponding video, expressed in
+ * proportions of the image size; e.g. rectangle.x = 0.5 would mean that
+ * the rectangle starts half-way across the video.
+ *
+ * This rectangle may or may not have had a TextContent's offsets and
+ * scale applied to it, depending on context.
+ */
+ dcpomatic::Rect<double> rectangle;
+};
+
+#endif
+++ /dev/null
-/*
- Copyright (C) 2013-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 "caption_content.h"
-#include "util.h"
-#include "exceptions.h"
-#include "font.h"
-#include "content.h"
-#include <dcp/raw_convert.h>
-#include <libcxml/cxml.h>
-#include <libxml++/libxml++.h>
-#include <boost/foreach.hpp>
-#include <iostream>
-
-#include "i18n.h"
-
-using std::string;
-using std::vector;
-using std::cout;
-using std::list;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::optional;
-using dcp::raw_convert;
-
-int const CaptionContentProperty::X_OFFSET = 500;
-int const CaptionContentProperty::Y_OFFSET = 501;
-int const CaptionContentProperty::X_SCALE = 502;
-int const CaptionContentProperty::Y_SCALE = 503;
-int const CaptionContentProperty::USE = 504;
-int const CaptionContentProperty::BURN = 505;
-int const CaptionContentProperty::LANGUAGE = 506;
-int const CaptionContentProperty::FONTS = 507;
-int const CaptionContentProperty::COLOUR = 508;
-int const CaptionContentProperty::EFFECT = 509;
-int const CaptionContentProperty::EFFECT_COLOUR = 510;
-int const CaptionContentProperty::LINE_SPACING = 511;
-int const CaptionContentProperty::FADE_IN = 512;
-int const CaptionContentProperty::FADE_OUT = 513;
-int const CaptionContentProperty::OUTLINE_WIDTH = 514;
-int const CaptionContentProperty::TYPE = 515;
-
-CaptionContent::CaptionContent (Content* parent, CaptionType original_type)
- : ContentPart (parent)
- , _use (false)
- , _burn (false)
- , _x_offset (0)
- , _y_offset (0)
- , _x_scale (1)
- , _y_scale (1)
- , _line_spacing (1)
- , _outline_width (2)
- , _type (original_type)
- , _original_type (original_type)
-{
-
-}
-
-/** @return CaptionContents from node or <Caption> nodes under node (according to version).
- * The list could be empty if no CaptionContents are found.
- */
-list<shared_ptr<CaptionContent> >
-CaptionContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version)
-{
- if (version < 34) {
- /* With old metadata FFmpeg content has the subtitle-related tags even with no
- subtitle streams, so check for that.
- */
- if (node->string_child("Type") == "FFmpeg" && node->node_children("SubtitleStream").empty()) {
- return list<shared_ptr<CaptionContent> >();
- }
-
- /* Otherwise we can drop through to the newer logic */
- }
-
- if (version < 37) {
- if (!node->optional_number_child<double>("SubtitleXOffset") && !node->optional_number_child<double>("SubtitleOffset")) {
- return list<shared_ptr<CaptionContent> >();
- }
- list<shared_ptr<CaptionContent> > c;
- c.push_back (shared_ptr<CaptionContent> (new CaptionContent (parent, node, version)));
- return c;
- }
-
- if (!node->optional_node_child("Caption")) {
- return list<shared_ptr<CaptionContent> >();
- }
-
- list<shared_ptr<CaptionContent> > c;
- BOOST_FOREACH (cxml::ConstNodePtr i, node->node_children("Caption")) {
- c.push_back (shared_ptr<CaptionContent> (new CaptionContent (parent, i, version)));
- }
- return c;
-}
-
-CaptionContent::CaptionContent (Content* parent, cxml::ConstNodePtr node, int version)
- : ContentPart (parent)
- , _use (false)
- , _burn (false)
- , _x_offset (0)
- , _y_offset (0)
- , _x_scale (1)
- , _y_scale (1)
- , _line_spacing (node->optional_number_child<double>("LineSpacing").get_value_or (1))
- , _outline_width (node->optional_number_child<int>("OutlineWidth").get_value_or (2))
- , _type (CAPTION_OPEN)
- , _original_type (CAPTION_OPEN)
-{
- if (version >= 37) {
- _use = node->bool_child ("Use");
- _burn = node->bool_child ("Burn");
- } else if (version >= 32) {
- _use = node->bool_child ("UseSubtitles");
- _burn = node->bool_child ("BurnSubtitles");
- }
-
- if (version >= 37) {
- _x_offset = node->number_child<double> ("XOffset");
- _y_offset = node->number_child<double> ("YOffset");
- } else if (version >= 7) {
- _x_offset = node->number_child<double> ("SubtitleXOffset");
- _y_offset = node->number_child<double> ("SubtitleYOffset");
- } else {
- _y_offset = node->number_child<double> ("SubtitleOffset");
- }
-
- if (node->optional_bool_child("Outline").get_value_or(false)) {
- _effect = dcp::BORDER;
- } else if (node->optional_bool_child("Shadow").get_value_or(false)) {
- _effect = dcp::SHADOW;
- } else {
- _effect = dcp::NONE;
- }
-
- optional<string> effect = node->optional_string_child("Effect");
- if (effect) {
- if (*effect == "none") {
- _effect = dcp::NONE;
- } else if (*effect == "outline") {
- _effect = dcp::BORDER;
- } else if (*effect == "shadow") {
- _effect = dcp::SHADOW;
- }
- }
-
- if (version >= 37) {
- _x_scale = node->number_child<double> ("XScale");
- _y_scale = node->number_child<double> ("YScale");
- } else if (version >= 10) {
- _x_scale = node->number_child<double> ("SubtitleXScale");
- _y_scale = node->number_child<double> ("SubtitleYScale");
- } else {
- _x_scale = _y_scale = node->number_child<double> ("SubtitleScale");
- }
-
- optional<int> r = node->optional_number_child<int>("Red");
- optional<int> g = node->optional_number_child<int>("Green");
- optional<int> b = node->optional_number_child<int>("Blue");
- if (r && g && b) {
- _colour = dcp::Colour (*r, *g, *b);
- }
-
- if (version >= 36) {
- optional<int> er = node->optional_number_child<int>("EffectRed");
- optional<int> eg = node->optional_number_child<int>("EffectGreen");
- optional<int> eb = node->optional_number_child<int>("EffectBlue");
- if (er && eg && eb) {
- _effect_colour = dcp::Colour (*er, *eg, *eb);
- }
- } else {
- _effect_colour = dcp::Colour (
- node->optional_number_child<int>("OutlineRed").get_value_or(255),
- node->optional_number_child<int>("OutlineGreen").get_value_or(255),
- node->optional_number_child<int>("OutlineBlue").get_value_or(255)
- );
- }
-
- optional<Frame> fi;
- if (version >= 37) {
- fi = node->optional_number_child<Frame>("FadeIn");
- } else {
- fi = node->optional_number_child<Frame>("SubtitleFadeIn");
- }
- if (fi) {
- _fade_in = ContentTime (*fi);
- }
-
- optional<Frame> fo;
- if (version >= 37) {
- fo = node->optional_number_child<Frame>("FadeOut");
- } else {
- fo = node->optional_number_child<Frame>("SubtitleFadeOut");
- }
- if (fo) {
- _fade_out = ContentTime (*fo);
- }
-
- if (version >= 37) {
- _language = node->optional_string_child ("Language").get_value_or ("");
- } else {
- _language = node->optional_string_child ("SubtitleLanguage").get_value_or ("");
- }
-
- list<cxml::NodePtr> fonts = node->node_children ("Font");
- for (list<cxml::NodePtr>::const_iterator i = fonts.begin(); i != fonts.end(); ++i) {
- _fonts.push_back (shared_ptr<Font> (new Font (*i)));
- }
-
- connect_to_fonts ();
-
- _type = string_to_caption_type (node->optional_string_child("Type").get_value_or("open"));
- _original_type = string_to_caption_type (node->optional_string_child("OriginalType").get_value_or("open"));
-}
-
-CaptionContent::CaptionContent (Content* parent, vector<shared_ptr<Content> > c)
- : ContentPart (parent)
-{
- /* This constructor is for join which is only supported for content types
- that have a single caption, so we can use only_caption() here.
- */
- shared_ptr<CaptionContent> ref = c[0]->only_caption();
- DCPOMATIC_ASSERT (ref);
- list<shared_ptr<Font> > ref_fonts = ref->fonts ();
-
- for (size_t i = 1; i < c.size(); ++i) {
-
- if (c[i]->only_caption()->use() != ref->use()) {
- throw JoinError (_("Content to be joined must have the same 'use subtitles' setting."));
- }
-
- if (c[i]->only_caption()->burn() != ref->burn()) {
- throw JoinError (_("Content to be joined must have the same 'burn subtitles' setting."));
- }
-
- if (c[i]->only_caption()->x_offset() != ref->x_offset()) {
- throw JoinError (_("Content to be joined must have the same subtitle X offset."));
- }
-
- if (c[i]->only_caption()->y_offset() != ref->y_offset()) {
- throw JoinError (_("Content to be joined must have the same subtitle Y offset."));
- }
-
- if (c[i]->only_caption()->x_scale() != ref->x_scale()) {
- throw JoinError (_("Content to be joined must have the same subtitle X scale."));
- }
-
- if (c[i]->only_caption()->y_scale() != ref->y_scale()) {
- throw JoinError (_("Content to be joined must have the same subtitle Y scale."));
- }
-
- if (c[i]->only_caption()->line_spacing() != ref->line_spacing()) {
- throw JoinError (_("Content to be joined must have the same subtitle line spacing."));
- }
-
- if ((c[i]->only_caption()->fade_in() != ref->fade_in()) || (c[i]->only_caption()->fade_out() != ref->fade_out())) {
- throw JoinError (_("Content to be joined must have the same subtitle fades."));
- }
-
- if ((c[i]->only_caption()->outline_width() != ref->outline_width())) {
- throw JoinError (_("Content to be joined must have the same outline width."));
- }
-
- list<shared_ptr<Font> > fonts = c[i]->only_caption()->fonts ();
- if (fonts.size() != ref_fonts.size()) {
- throw JoinError (_("Content to be joined must use the same fonts."));
- }
-
- list<shared_ptr<Font> >::const_iterator j = ref_fonts.begin ();
- list<shared_ptr<Font> >::const_iterator k = fonts.begin ();
-
- while (j != ref_fonts.end ()) {
- if (**j != **k) {
- throw JoinError (_("Content to be joined must use the same fonts."));
- }
- ++j;
- ++k;
- }
- }
-
- _use = ref->use ();
- _burn = ref->burn ();
- _x_offset = ref->x_offset ();
- _y_offset = ref->y_offset ();
- _x_scale = ref->x_scale ();
- _y_scale = ref->y_scale ();
- _language = ref->language ();
- _fonts = ref_fonts;
- _line_spacing = ref->line_spacing ();
- _fade_in = ref->fade_in ();
- _fade_out = ref->fade_out ();
- _outline_width = ref->outline_width ();
- _type = ref->type ();
- _original_type = ref->original_type ();
-
- connect_to_fonts ();
-}
-
-/** _mutex must not be held on entry */
-void
-CaptionContent::as_xml (xmlpp::Node* root) const
-{
- boost::mutex::scoped_lock lm (_mutex);
-
- xmlpp::Element* caption = root->add_child ("Caption");
-
- caption->add_child("Use")->add_child_text (_use ? "1" : "0");
- caption->add_child("Burn")->add_child_text (_burn ? "1" : "0");
- caption->add_child("XOffset")->add_child_text (raw_convert<string> (_x_offset));
- caption->add_child("YOffset")->add_child_text (raw_convert<string> (_y_offset));
- caption->add_child("XScale")->add_child_text (raw_convert<string> (_x_scale));
- caption->add_child("YScale")->add_child_text (raw_convert<string> (_y_scale));
- caption->add_child("Language")->add_child_text (_language);
- if (_colour) {
- caption->add_child("Red")->add_child_text (raw_convert<string> (_colour->r));
- caption->add_child("Green")->add_child_text (raw_convert<string> (_colour->g));
- caption->add_child("Blue")->add_child_text (raw_convert<string> (_colour->b));
- }
- if (_effect) {
- switch (*_effect) {
- case dcp::NONE:
- caption->add_child("Effect")->add_child_text("none");
- break;
- case dcp::BORDER:
- caption->add_child("Effect")->add_child_text("outline");
- break;
- case dcp::SHADOW:
- caption->add_child("Effect")->add_child_text("shadow");
- break;
- }
- }
- if (_effect_colour) {
- caption->add_child("EffectRed")->add_child_text (raw_convert<string> (_effect_colour->r));
- caption->add_child("EffectGreen")->add_child_text (raw_convert<string> (_effect_colour->g));
- caption->add_child("EffectBlue")->add_child_text (raw_convert<string> (_effect_colour->b));
- }
- caption->add_child("LineSpacing")->add_child_text (raw_convert<string> (_line_spacing));
- if (_fade_in) {
- caption->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in->get()));
- }
- if (_fade_out) {
- caption->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out->get()));
- }
- caption->add_child("OutlineWidth")->add_child_text (raw_convert<string> (_outline_width));
-
- for (list<shared_ptr<Font> >::const_iterator i = _fonts.begin(); i != _fonts.end(); ++i) {
- (*i)->as_xml (caption->add_child("Font"));
- }
-
- caption->add_child("Type")->add_child_text (caption_type_to_string(_type));
- caption->add_child("OriginalType")->add_child_text (caption_type_to_string(_original_type));
-}
-
-string
-CaptionContent::identifier () const
-{
- string s = raw_convert<string> (x_scale())
- + "_" + raw_convert<string> (y_scale())
- + "_" + raw_convert<string> (x_offset())
- + "_" + raw_convert<string> (y_offset())
- + "_" + raw_convert<string> (line_spacing())
- + "_" + raw_convert<string> (fade_in().get_value_or(ContentTime()).get())
- + "_" + raw_convert<string> (fade_out().get_value_or(ContentTime()).get())
- + "_" + raw_convert<string> (outline_width())
- + "_" + raw_convert<string> (colour().get_value_or(dcp::Colour(255, 255, 255)).to_argb_string())
- + "_" + raw_convert<string> (dcp::effect_to_string(effect().get_value_or(dcp::NONE)))
- + "_" + raw_convert<string> (effect_colour().get_value_or(dcp::Colour(0, 0, 0)).to_argb_string());
-
- /* XXX: I suppose really _fonts shouldn't be in here, since not all
- types of subtitle content involve fonts.
- */
- BOOST_FOREACH (shared_ptr<Font> f, _fonts) {
- for (int i = 0; i < FontFiles::VARIANTS; ++i) {
- s += "_" + f->file(static_cast<FontFiles::Variant>(i)).get_value_or("Default").string();
- }
- }
-
- /* The language is for metadata only, and doesn't affect
- how this content looks.
- */
-
- return s;
-}
-
-void
-CaptionContent::add_font (shared_ptr<Font> font)
-{
- _fonts.push_back (font);
- connect_to_fonts ();
-}
-
-void
-CaptionContent::connect_to_fonts ()
-{
- BOOST_FOREACH (boost::signals2::connection& i, _font_connections) {
- i.disconnect ();
- }
-
- _font_connections.clear ();
-
- BOOST_FOREACH (shared_ptr<Font> i, _fonts) {
- _font_connections.push_back (i->Changed.connect (boost::bind (&CaptionContent::font_changed, this)));
- }
-}
-
-void
-CaptionContent::font_changed ()
-{
- _parent->signal_changed (CaptionContentProperty::FONTS);
-}
-
-void
-CaptionContent::set_colour (dcp::Colour colour)
-{
- maybe_set (_colour, colour, CaptionContentProperty::COLOUR);
-}
-
-void
-CaptionContent::unset_colour ()
-{
- maybe_set (_colour, optional<dcp::Colour>(), CaptionContentProperty::COLOUR);
-}
-
-void
-CaptionContent::set_effect (dcp::Effect e)
-{
- maybe_set (_effect, e, CaptionContentProperty::EFFECT);
-}
-
-void
-CaptionContent::unset_effect ()
-{
- maybe_set (_effect, optional<dcp::Effect>(), CaptionContentProperty::EFFECT);
-}
-
-void
-CaptionContent::set_effect_colour (dcp::Colour colour)
-{
- maybe_set (_effect_colour, colour, CaptionContentProperty::EFFECT_COLOUR);
-}
-
-void
-CaptionContent::unset_effect_colour ()
-{
- maybe_set (_effect_colour, optional<dcp::Colour>(), CaptionContentProperty::EFFECT_COLOUR);
-}
-
-void
-CaptionContent::set_use (bool u)
-{
- maybe_set (_use, u, CaptionContentProperty::USE);
-}
-
-void
-CaptionContent::set_burn (bool b)
-{
- maybe_set (_burn, b, CaptionContentProperty::BURN);
-}
-
-void
-CaptionContent::set_x_offset (double o)
-{
- maybe_set (_x_offset, o, CaptionContentProperty::X_OFFSET);
-}
-
-void
-CaptionContent::set_y_offset (double o)
-{
- maybe_set (_y_offset, o, CaptionContentProperty::Y_OFFSET);
-}
-
-void
-CaptionContent::set_x_scale (double s)
-{
- maybe_set (_x_scale, s, CaptionContentProperty::X_SCALE);
-}
-
-void
-CaptionContent::set_y_scale (double s)
-{
- maybe_set (_y_scale, s, CaptionContentProperty::Y_SCALE);
-}
-
-void
-CaptionContent::set_language (string language)
-{
- maybe_set (_language, language, CaptionContentProperty::LANGUAGE);
-}
-
-void
-CaptionContent::set_line_spacing (double s)
-{
- maybe_set (_line_spacing, s, CaptionContentProperty::LINE_SPACING);
-}
-
-void
-CaptionContent::set_fade_in (ContentTime t)
-{
- maybe_set (_fade_in, t, CaptionContentProperty::FADE_IN);
-}
-
-void
-CaptionContent::unset_fade_in ()
-{
- maybe_set (_fade_in, optional<ContentTime>(), CaptionContentProperty::FADE_IN);
-}
-
-void
-CaptionContent::set_fade_out (ContentTime t)
-{
- maybe_set (_fade_out, t, CaptionContentProperty::FADE_OUT);
-}
-
-void
-CaptionContent::unset_fade_out ()
-{
- maybe_set (_fade_out, optional<ContentTime>(), CaptionContentProperty::FADE_OUT);
-}
-
-void
-CaptionContent::set_type (CaptionType type)
-{
- maybe_set (_type, type, CaptionContentProperty::TYPE);
-}
-
-void
-CaptionContent::set_outline_width (int w)
-{
- maybe_set (_outline_width, w, CaptionContentProperty::OUTLINE_WIDTH);
-}
-
-void
-CaptionContent::take_settings_from (shared_ptr<const CaptionContent> c)
-{
- set_use (c->_use);
- set_burn (c->_burn);
- set_x_offset (c->_x_offset);
- set_y_offset (c->_y_offset);
- set_x_scale (c->_x_scale);
- set_y_scale (c->_y_scale);
- maybe_set (_fonts, c->_fonts, CaptionContentProperty::FONTS);
- if (c->_colour) {
- set_colour (*c->_colour);
- } else {
- unset_colour ();
- }
- if (c->_effect) {
- set_effect (*c->_effect);
- }
- if (c->_effect_colour) {
- set_effect_colour (*c->_effect_colour);
- } else {
- unset_effect_colour ();
- }
- set_line_spacing (c->_line_spacing);
- if (c->_fade_in) {
- set_fade_in (*c->_fade_in);
- }
- if (c->_fade_out) {
- set_fade_out (*c->_fade_out);
- }
- set_outline_width (c->_outline_width);
-}
+++ /dev/null
-/*
- Copyright (C) 2013-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/>.
-
-*/
-
-#ifndef DCPOMATIC_CAPTION_CONTENT_H
-#define DCPOMATIC_CAPTION_CONTENT_H
-
-#include "content_part.h"
-#include <libcxml/cxml.h>
-#include <dcp/types.h>
-#include <boost/signals2.hpp>
-
-class Font;
-
-class CaptionContentProperty
-{
-public:
- static int const X_OFFSET;
- static int const Y_OFFSET;
- static int const X_SCALE;
- static int const Y_SCALE;
- static int const USE;
- static int const BURN;
- static int const LANGUAGE;
- static int const FONTS;
- static int const COLOUR;
- static int const EFFECT;
- static int const EFFECT_COLOUR;
- static int const LINE_SPACING;
- static int const FADE_IN;
- static int const FADE_OUT;
- static int const OUTLINE_WIDTH;
- static int const TYPE;
-};
-
-/** @class CaptionContent
- * @brief Description of how some text content should be presented.
- *
- * There are `bitmap' subtitles and `plain' subtitles (plain text),
- * and not all of the settings in this class correspond to both types.
- */
-class CaptionContent : public ContentPart
-{
-public:
- CaptionContent (Content* parent, CaptionType original_type);
- CaptionContent (Content* parent, std::vector<boost::shared_ptr<Content> >);
-
- void as_xml (xmlpp::Node *) const;
- std::string identifier () const;
- void take_settings_from (boost::shared_ptr<const CaptionContent> c);
-
- void add_font (boost::shared_ptr<Font> font);
-
- void set_use (bool);
- void set_burn (bool);
- void set_x_offset (double);
- void set_y_offset (double);
- void set_x_scale (double);
- void set_y_scale (double);
- void set_language (std::string language);
- void set_colour (dcp::Colour);
- void unset_colour ();
- void set_effect (dcp::Effect);
- void unset_effect ();
- void set_effect_colour (dcp::Colour);
- void unset_effect_colour ();
- void set_line_spacing (double s);
- void set_fade_in (ContentTime);
- void unset_fade_in ();
- void set_fade_out (ContentTime);
- void set_outline_width (int);
- void unset_fade_out ();
- void set_type (CaptionType type);
-
- bool use () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _use;
- }
-
- bool burn () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _burn;
- }
-
- double x_offset () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _x_offset;
- }
-
- double y_offset () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _y_offset;
- }
-
- double x_scale () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _x_scale;
- }
-
- double y_scale () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _y_scale;
- }
-
- std::list<boost::shared_ptr<Font> > fonts () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _fonts;
- }
-
- std::string language () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _language;
- }
-
- boost::optional<dcp::Colour> colour () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _colour;
- }
-
- boost::optional<dcp::Effect> effect () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _effect;
- }
-
- boost::optional<dcp::Colour> effect_colour () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _effect_colour;
- }
-
- double line_spacing () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _line_spacing;
- }
-
- boost::optional<ContentTime> fade_in () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _fade_in;
- }
-
- boost::optional<ContentTime> fade_out () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _fade_out;
- }
-
- int outline_width () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _outline_width;
- }
-
- CaptionType type () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _type;
- }
-
- CaptionType original_type () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _original_type;
- }
-
- static std::list<boost::shared_ptr<CaptionContent> > from_xml (Content* parent, cxml::ConstNodePtr, int version);
-
-protected:
- /** subtitle language (e.g. "German") or empty if it is not known */
- std::string _language;
-
-private:
- friend struct ffmpeg_pts_offset_test;
-
- CaptionContent (Content* parent, cxml::ConstNodePtr, int version);
- void font_changed ();
- void connect_to_fonts ();
-
- std::list<boost::signals2::connection> _font_connections;
-
- bool _use;
- bool _burn;
- /** x offset for placing subtitles, as a proportion of the container width;
- * +ve is further right, -ve is further left.
- */
- double _x_offset;
- /** y offset for placing subtitles, as a proportion of the container height;
- * +ve is further down the frame, -ve is further up.
- */
- double _y_offset;
- /** x scale factor to apply to subtitles */
- double _x_scale;
- /** y scale factor to apply to subtitles */
- double _y_scale;
- std::list<boost::shared_ptr<Font> > _fonts;
- boost::optional<dcp::Colour> _colour;
- boost::optional<dcp::Effect> _effect;
- boost::optional<dcp::Colour> _effect_colour;
- /** scaling factor for line spacing; 1 is "standard", < 1 is closer together, > 1 is further apart */
- double _line_spacing;
- boost::optional<ContentTime> _fade_in;
- boost::optional<ContentTime> _fade_out;
- int _outline_width;
- /** what these captions will be used for in the output DCP (not necessarily what
- * they were originally).
- */
- CaptionType _type;
- /** the original type of these captions in their content */
- CaptionType _original_type;
-};
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2013-2017 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 "caption_decoder.h"
-#include "caption_content.h"
-#include "util.h"
-#include "log.h"
-#include "compose.hpp"
-#include <sub/subtitle.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/foreach.hpp>
-#include <boost/algorithm/string.hpp>
-#include <iostream>
-
-using std::list;
-using std::cout;
-using std::string;
-using std::min;
-using boost::shared_ptr;
-using boost::optional;
-using boost::function;
-
-CaptionDecoder::CaptionDecoder (
- Decoder* parent,
- shared_ptr<const CaptionContent> c,
- shared_ptr<Log> log,
- ContentTime first
- )
- : DecoderPart (parent, log)
- , _content (c)
- , _position (first)
-{
-
-}
-
-/** Called by subclasses when an image subtitle is starting.
- * @param from From time of the subtitle.
- * @param image Subtitle image.
- * @param rect Area expressed as a fraction of the video frame that this subtitle
- * is for (e.g. a width of 0.5 means the width of the subtitle is half the width
- * of the video frame)
- */
-void
-CaptionDecoder::emit_bitmap_start (ContentTime from, shared_ptr<Image> image, dcpomatic::Rect<double> rect)
-{
- BitmapStart (ContentBitmapCaption (from, _content->type(), image, rect));
- _position = from;
-}
-
-void
-CaptionDecoder::emit_plain_start (ContentTime from, list<dcp::SubtitleString> s)
-{
- BOOST_FOREACH (dcp::SubtitleString& i, s) {
- /* We must escape < and > in strings, otherwise they might confuse our subtitle
- renderer (which uses some HTML-esque markup to do bold/italic etc.)
- */
- string t = i.text ();
- boost::algorithm::replace_all (t, "<", "<");
- boost::algorithm::replace_all (t, ">", ">");
- i.set_text (t);
-
- /* Set any forced appearance */
- if (content()->colour()) {
- i.set_colour (*content()->colour());
- }
- if (content()->effect_colour()) {
- i.set_effect_colour (*content()->effect_colour());
- }
- if (content()->effect()) {
- i.set_effect (*content()->effect());
- }
- if (content()->fade_in()) {
- i.set_fade_up_time (dcp::Time(content()->fade_in()->seconds(), 1000));
- }
- if (content()->fade_out()) {
- i.set_fade_down_time (dcp::Time(content()->fade_out()->seconds(), 1000));
- }
- }
-
- PlainStart (ContentTextCaption (from, _content->type(), s));
- _position = from;
-}
-
-void
-CaptionDecoder::emit_plain_start (ContentTime from, sub::Subtitle const & subtitle)
-{
- /* See if our next subtitle needs to be vertically placed on screen by us */
- bool needs_placement = false;
- optional<int> bottom_line;
- BOOST_FOREACH (sub::Line i, subtitle.lines) {
- if (!i.vertical_position.reference || i.vertical_position.reference.get() == sub::TOP_OF_SUBTITLE) {
- needs_placement = true;
- DCPOMATIC_ASSERT (i.vertical_position.line);
- if (!bottom_line || bottom_line.get() < i.vertical_position.line.get()) {
- bottom_line = i.vertical_position.line.get();
- }
- }
- }
-
- /* Find the lowest proportional position */
- optional<float> lowest_proportional;
- BOOST_FOREACH (sub::Line i, subtitle.lines) {
- if (i.vertical_position.proportional) {
- if (!lowest_proportional) {
- lowest_proportional = i.vertical_position.proportional;
- } else {
- lowest_proportional = min (lowest_proportional.get(), i.vertical_position.proportional.get());
- }
- }
- }
-
- list<dcp::SubtitleString> out;
- BOOST_FOREACH (sub::Line i, subtitle.lines) {
- BOOST_FOREACH (sub::Block j, i.blocks) {
-
- if (!j.font_size.specified()) {
- /* Fallback default font size if no other has been specified */
- j.font_size.set_points (48);
- }
-
- float v_position;
- dcp::VAlign v_align;
- if (needs_placement) {
- DCPOMATIC_ASSERT (i.vertical_position.line);
- /* This 1.015 is an arbitrary value to lift the bottom sub off the bottom
- of the screen a bit to a pleasing degree.
- */
- v_position = 1.015 -
- (1 + bottom_line.get() - i.vertical_position.line.get())
- * 1.2 * content()->line_spacing() * content()->y_scale() * j.font_size.proportional (72 * 11);
-
- v_align = dcp::VALIGN_TOP;
- } else {
- DCPOMATIC_ASSERT (i.vertical_position.proportional);
- DCPOMATIC_ASSERT (i.vertical_position.reference);
- v_position = i.vertical_position.proportional.get();
-
- if (lowest_proportional) {
- /* Adjust line spacing */
- v_position = ((v_position - lowest_proportional.get()) * content()->line_spacing()) + lowest_proportional.get();
- }
-
- switch (i.vertical_position.reference.get()) {
- case sub::TOP_OF_SCREEN:
- v_align = dcp::VALIGN_TOP;
- break;
- case sub::VERTICAL_CENTRE_OF_SCREEN:
- v_align = dcp::VALIGN_CENTER;
- break;
- case sub::BOTTOM_OF_SCREEN:
- v_align = dcp::VALIGN_BOTTOM;
- break;
- default:
- v_align = dcp::VALIGN_TOP;
- break;
- }
- }
-
- dcp::HAlign h_align;
- switch (i.horizontal_position.reference) {
- case sub::LEFT_OF_SCREEN:
- h_align = dcp::HALIGN_LEFT;
- break;
- case sub::HORIZONTAL_CENTRE_OF_SCREEN:
- h_align = dcp::HALIGN_CENTER;
- break;
- case sub::RIGHT_OF_SCREEN:
- h_align = dcp::HALIGN_RIGHT;
- break;
- default:
- h_align = dcp::HALIGN_CENTER;
- break;
- }
-
- /* The idea here (rightly or wrongly) is that we set the appearance based on the
- values in the libsub objects, and these are overridden with values from the
- content by the other emit_plain_start() above.
- */
-
- out.push_back (
- dcp::SubtitleString (
- string(TEXT_FONT_ID),
- j.italic,
- j.bold,
- j.underline,
- j.colour.dcp(),
- j.font_size.points (72 * 11),
- 1.0,
- dcp::Time (from.seconds(), 1000),
- /* XXX: hmm; this is a bit ugly (we don't know the to time yet) */
- dcp::Time (),
- i.horizontal_position.proportional,
- h_align,
- v_position,
- v_align,
- dcp::DIRECTION_LTR,
- j.text,
- dcp::NONE,
- j.effect_colour.get_value_or(sub::Colour(0, 0, 0)).dcp(),
- /* Hack: we should use subtitle.fade_up and subtitle.fade_down here
- but the times of these often don't have a frame rate associated
- with them so the sub::Time won't convert them to milliseconds without
- throwing an exception. Since only DCP subs fill those in (and we don't
- use libsub for DCP subs) we can cheat by just putting 0 in here.
- */
- dcp::Time (),
- dcp::Time ()
- )
- );
- }
- }
-
- emit_plain_start (from, out);
-}
-
-void
-CaptionDecoder::emit_stop (ContentTime to)
-{
- Stop (to, _content->type());
-}
-
-void
-CaptionDecoder::emit_plain (ContentTimePeriod period, list<dcp::SubtitleString> s)
-{
- emit_plain_start (period.from, s);
- emit_stop (period.to);
-}
-
-void
-CaptionDecoder::emit_plain (ContentTimePeriod period, sub::Subtitle const & s)
-{
- emit_plain_start (period.from, s);
- emit_stop (period.to);
-}
-
-void
-CaptionDecoder::seek ()
-{
- _position = ContentTime ();
-}
+++ /dev/null
-/*
- Copyright (C) 2013-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/>.
-
-*/
-
-#ifndef DCPOMATIC_CAPTION_DECODER_H
-#define DCPOMATIC_CAPTION_DECODER_H
-
-#include "decoder.h"
-#include "rect.h"
-#include "types.h"
-#include "content_caption.h"
-#include "decoder_part.h"
-#include <dcp/subtitle_string.h>
-#include <boost/signals2.hpp>
-
-namespace sub {
- class Subtitle;
-}
-
-class Image;
-
-class CaptionDecoder : public DecoderPart
-{
-public:
- CaptionDecoder (
- Decoder* parent,
- boost::shared_ptr<const CaptionContent>,
- boost::shared_ptr<Log> log,
- ContentTime first
- );
-
- ContentTime position () const {
- return _position;
- }
-
- void emit_bitmap_start (ContentTime from, boost::shared_ptr<Image> image, dcpomatic::Rect<double> rect);
- void emit_plain_start (ContentTime from, std::list<dcp::SubtitleString> s);
- void emit_plain_start (ContentTime from, sub::Subtitle const & subtitle);
- void emit_plain (ContentTimePeriod period, std::list<dcp::SubtitleString> s);
- void emit_plain (ContentTimePeriod period, sub::Subtitle const & subtitle);
- void emit_stop (ContentTime to);
-
- void seek ();
-
- boost::shared_ptr<const CaptionContent> content () const {
- return _content;
- }
-
- boost::signals2::signal<void (ContentBitmapCaption)> BitmapStart;
- boost::signals2::signal<void (ContentTextCaption)> PlainStart;
- boost::signals2::signal<void (ContentTime, CaptionType)> Stop;
-
-private:
- boost::shared_ptr<const CaptionContent> _content;
- ContentTime _position;
-};
-
-#endif
#include "content_factory.h"
#include "video_content.h"
#include "audio_content.h"
-#include "caption_content.h"
+#include "text_content.h"
#include "exceptions.h"
#include "film.h"
#include "job.h"
audio->take_settings_from (c->audio);
}
- list<shared_ptr<CaptionContent> >::iterator i = caption.begin ();
- list<shared_ptr<CaptionContent> >::const_iterator j = c->caption.begin ();
+ list<shared_ptr<TextContent> >::iterator i = caption.begin ();
+ list<shared_ptr<TextContent> >::const_iterator j = c->caption.begin ();
while (i != caption.end() && j != c->caption.end()) {
(*i)->take_settings_from (*j);
++i;
}
}
-shared_ptr<CaptionContent>
+shared_ptr<TextContent>
Content::only_caption () const
{
DCPOMATIC_ASSERT (caption.size() < 2);
if (caption.empty ()) {
- return shared_ptr<CaptionContent> ();
+ return shared_ptr<TextContent> ();
}
return caption.front ();
}
-shared_ptr<CaptionContent>
-Content::caption_of_original_type (CaptionType type) const
+shared_ptr<TextContent>
+Content::caption_of_original_type (TextType type) const
{
- BOOST_FOREACH (shared_ptr<CaptionContent> i, caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> i, caption) {
if (i->original_type() == type) {
return i;
}
}
- return shared_ptr<CaptionContent> ();
+ return shared_ptr<TextContent> ();
}
boost::shared_ptr<VideoContent> video;
boost::shared_ptr<AudioContent> audio;
- std::list<boost::shared_ptr<CaptionContent> > caption;
+ std::list<boost::shared_ptr<TextContent> > caption;
- boost::shared_ptr<CaptionContent> only_caption () const;
- boost::shared_ptr<CaptionContent> caption_of_original_type (CaptionType type) const;
+ boost::shared_ptr<TextContent> only_caption () const;
+ boost::shared_ptr<TextContent> caption_of_original_type (TextType type) const;
void signal_changed (int);
+++ /dev/null
-/*
- Copyright (C) 2014-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/>.
-
-*/
-
-#ifndef DCPOMATIC_CONTENT_TEXT_H
-#define DCPOMATIC_CONTENT_TEXT_H
-
-#include "dcpomatic_time.h"
-#include "rect.h"
-#include "types.h"
-#include "bitmap_caption.h"
-#include <dcp/subtitle_string.h>
-#include <list>
-
-class Image;
-
-class ContentCaption
-{
-public:
- explicit ContentCaption (ContentTime f, CaptionType t)
- : _from (f)
- , _type (t)
- {}
-
- ContentTime from () const {
- return _from;
- }
-
- CaptionType type () const {
- return _type;
- }
-
-private:
- ContentTime _from;
- CaptionType _type;
-};
-
-class ContentBitmapCaption : public ContentCaption
-{
-public:
- ContentBitmapCaption (ContentTime f, CaptionType type, boost::shared_ptr<Image> im, dcpomatic::Rect<double> r)
- : ContentCaption (f, type)
- , sub (im, r)
- {}
-
- /* Our text, with its rectangle unmodified by any offsets or scales that the content specifies */
- BitmapCaption sub;
-};
-
-/** A text caption. We store the time period separately (as well as in the dcp::SubtitleStrings)
- * as the dcp::SubtitleString timings are sometimes quite heavily quantised and this causes problems
- * when we want to compare the quantised periods to the unquantised ones.
- */
-class ContentTextCaption : public ContentCaption
-{
-public:
- ContentTextCaption (ContentTime f, CaptionType type, std::list<dcp::SubtitleString> s)
- : ContentCaption (f, type)
- , subs (s)
- {}
-
- std::list<dcp::SubtitleString> subs;
-};
-
-#endif
#include "audio_content.h"
#include "image_content.h"
#include "atmos_mxf_content.h"
-#include "text_caption_file_content.h"
+#include "string_text_file_content.h"
#include "dcp_content.h"
#include "dcp_subtitle_content.h"
#include "util.h"
);
} else if (type == "SubRip" || type == "TextSubtitle") {
- content.reset (new TextCaptionFileContent (film, node, version));
+ content.reset (new StringTextFileContent (film, node, version));
} else if (type == "DCP") {
content.reset (new DCPContent (film, node, version));
} else if (type == "DCPSubtitle") {
if (valid_image_file (path)) {
single.reset (new ImageContent (film, path));
} else if (ext == ".srt" || ext == ".ssa" || ext == ".ass") {
- single.reset (new TextCaptionFileContent (film, path));
+ single.reset (new StringTextFileContent (film, path));
} else if (ext == ".xml") {
cxml::Document doc;
doc.read_file (path);
--- /dev/null
+/*
+ Copyright (C) 2014-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/>.
+
+*/
+
+#ifndef DCPOMATIC_CONTENT_TEXT_H
+#define DCPOMATIC_CONTENT_TEXT_H
+
+#include "dcpomatic_time.h"
+#include "rect.h"
+#include "types.h"
+#include "bitmap_text.h"
+#include <dcp/subtitle_string.h>
+#include <list>
+
+class Image;
+
+class ContentText
+{
+public:
+ explicit ContentText (ContentTime f, TextType t)
+ : _from (f)
+ , _type (t)
+ {}
+
+ ContentTime from () const {
+ return _from;
+ }
+
+ TextType type () const {
+ return _type;
+ }
+
+private:
+ ContentTime _from;
+ TextType _type;
+};
+
+class ContentBitmapText : public ContentText
+{
+public:
+ ContentBitmapText (ContentTime f, TextType type, boost::shared_ptr<Image> im, dcpomatic::Rect<double> r)
+ : ContentText (f, type)
+ , sub (im, r)
+ {}
+
+ /* Our text, with its rectangle unmodified by any offsets or scales that the content specifies */
+ BitmapText sub;
+};
+
+/** A text caption. We store the time period separately (as well as in the dcp::SubtitleStrings)
+ * as the dcp::SubtitleString timings are sometimes quite heavily quantised and this causes problems
+ * when we want to compare the quantised periods to the unquantised ones.
+ */
+class ContentStringText : public ContentText
+{
+public:
+ ContentStringText (ContentTime f, TextType type, std::list<dcp::SubtitleString> s)
+ : ContentText (f, type)
+ , subs (s)
+ {}
+
+ std::list<dcp::SubtitleString> subs;
+};
+
+#endif
#include "overlaps.h"
#include "compose.hpp"
#include "dcp_decoder.h"
-#include "caption_content.h"
+#include "text_content.h"
#include <dcp/dcp.h>
#include <dcp/raw_convert.h>
#include <dcp/exceptions.h>
{
video = VideoContent::from_xml (this, node, version);
audio = AudioContent::from_xml (this, node, version);
- caption = CaptionContent::from_xml (this, node, version);
+ caption = TextContent::from_xml (this, node, version);
for (int i = 0; i < CAPTION_COUNT; ++i) {
_reference_caption[i] = false;
boost::mutex::scoped_lock lm (_mutex);
_name = examiner->name ();
for (int i = 0; i < CAPTION_COUNT; ++i) {
- if (examiner->has_caption(static_cast<CaptionType>(i))) {
- caption.push_back (shared_ptr<CaptionContent>(new CaptionContent(this, static_cast<CaptionType>(i))));
+ if (examiner->has_caption(static_cast<TextType>(i))) {
+ caption.push_back (shared_ptr<TextContent>(new TextContent(this, static_cast<TextType>(i))));
}
}
captions = caption.size ();
audio->stream()->mapping().as_xml (node->add_child("AudioMapping"));
}
- BOOST_FOREACH (shared_ptr<CaptionContent> i, caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> i, caption) {
i->as_xml (node);
}
s += video->identifier() + "_";
}
- BOOST_FOREACH (shared_ptr<CaptionContent> i, caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> i, caption) {
s += i->identifier () + " ";
}
}
void
-DCPContent::set_reference_caption (CaptionType type, bool r)
+DCPContent::set_reference_caption (TextType type, bool r)
{
{
boost::mutex::scoped_lock lm (_mutex);
return !c->caption.empty();
}
bool
-DCPContent::can_reference_caption (CaptionType type, string& why_not) const
+DCPContent::can_reference_caption (TextType type, string& why_not) const
{
shared_ptr<DCPDecoder> decoder;
try {
bool can_reference_audio (std::string &) const;
- void set_reference_caption (CaptionType type, bool r);
+ void set_reference_caption (TextType type, bool r);
/** @param type Original type of captions in the DCP.
* @return true if these captions are to be referenced.
*/
- bool reference_caption (CaptionType type) const {
+ bool reference_caption (TextType type) const {
boost::mutex::scoped_lock lm (_mutex);
return _reference_caption[type];
}
- bool can_reference_caption (CaptionType type, std::string &) const;
+ bool can_reference_caption (TextType type, std::string &) const;
void set_cpl (std::string id);
#include "video_decoder.h"
#include "audio_decoder.h"
#include "j2k_image_proxy.h"
-#include "caption_decoder.h"
+#include "text_decoder.h"
#include "image.h"
#include "config.h"
#include <dcp/dcp.h>
if (c->audio) {
audio.reset (new AudioDecoder (this, c->audio, log, fast));
}
- BOOST_FOREACH (shared_ptr<CaptionContent> i, c->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> i, c->caption) {
/* XXX: this time here should be the time of the first subtitle, not 0 */
- caption.push_back (shared_ptr<CaptionDecoder> (new CaptionDecoder (this, i, log, ContentTime())));
+ caption.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, i, log, ContentTime())));
}
list<shared_ptr<dcp::CPL> > cpl_list = cpls ();
void
DCPDecoder::pass_captions (ContentTime next)
{
- list<shared_ptr<CaptionDecoder> >::const_iterator decoder = caption.begin ();
+ list<shared_ptr<TextDecoder> >::const_iterator decoder = caption.begin ();
if ((*_reel)->main_subtitle()) {
pass_captions (
next, (*_reel)->main_subtitle()->asset(), _dcp_content->reference_caption(CAPTION_OPEN), (*_reel)->main_subtitle()->entry_point(), *decoder
}
void
-DCPDecoder::pass_captions (ContentTime next, shared_ptr<dcp::SubtitleAsset> asset, bool reference, int64_t entry_point, shared_ptr<CaptionDecoder> decoder)
+DCPDecoder::pass_captions (ContentTime next, shared_ptr<dcp::SubtitleAsset> asset, bool reference, int64_t entry_point, shared_ptr<TextDecoder> decoder)
{
double const vfr = _dcp_content->active_video_frame_rate ();
/* Frame within the (played part of the) reel that is coming up next */
void next_reel ();
void get_readers ();
void pass_captions (ContentTime next);
- void pass_captions (ContentTime next, boost::shared_ptr<dcp::SubtitleAsset> asset, bool reference, int64_t entry_point, boost::shared_ptr<CaptionDecoder> decoder);
+ void pass_captions (ContentTime next, boost::shared_ptr<dcp::SubtitleAsset> asset, bool reference, int64_t entry_point, boost::shared_ptr<TextDecoder> decoder);
/** Time of next thing to return from pass relative to the start of _reel */
ContentTime _next;
#include "writer.h"
#include "compose.hpp"
#include "referenced_reel_asset.h"
-#include "caption_content.h"
+#include "text_content.h"
#include "player_video.h"
#include <boost/signals2.hpp>
#include <boost/foreach.hpp>
_player_caption_connection = _player->Caption.connect (bind (&DCPEncoder::caption, this, _1, _2, _3));
BOOST_FOREACH (shared_ptr<const Content> c, film->content ()) {
- BOOST_FOREACH (shared_ptr<CaptionContent> i, c->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> i, c->caption) {
if (i->use() && !i->burn()) {
_non_burnt_subtitles = true;
}
}
void
-DCPEncoder::caption (PlayerCaption data, CaptionType type, DCPTimePeriod period)
+DCPEncoder::caption (PlayerText data, TextType type, DCPTimePeriod period)
{
if (type == CAPTION_CLOSED || _non_burnt_subtitles) {
_writer->write (data, type, period);
*/
#include "types.h"
-#include "player_caption.h"
+#include "player_text.h"
#include "encoder.h"
#include <boost/weak_ptr.hpp>
void video (boost::shared_ptr<PlayerVideo>, DCPTime);
void audio (boost::shared_ptr<AudioBuffers>, DCPTime);
- void caption (PlayerCaption, CaptionType, DCPTimePeriod);
+ void caption (PlayerText, TextType, DCPTimePeriod);
boost::shared_ptr<Writer> _writer;
boost::shared_ptr<J2KEncoder> _j2k_encoder;
return _audio_frame_rate.get_value_or (48000);
}
- bool has_caption (CaptionType type) const {
+ bool has_caption (TextType type) const {
return _has_caption[type];
}
#include "font.h"
#include "dcp_subtitle_content.h"
#include "film.h"
-#include "caption_content.h"
+#include "text_content.h"
#include <dcp/raw_convert.h>
#include <dcp/interop_subtitle_asset.h>
#include <dcp/smpte_subtitle_asset.h>
DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, boost::filesystem::path path)
: Content (film, path)
{
- caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, CAPTION_OPEN)));
+ caption.push_back (shared_ptr<TextContent> (new TextContent (this, CAPTION_OPEN)));
}
DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
: Content (film, node)
, _length (node->number_child<ContentTime::Type> ("Length"))
{
- caption = CaptionContent::from_xml (this, node, version);
+ caption = TextContent::from_xml (this, node, version);
}
void
if (_next != _subtitles.end()) {
first = content_time_period(*_next).from;
}
- caption.push_back (shared_ptr<CaptionDecoder> (new CaptionDecoder (this, content->only_caption(), log, first)));
+ caption.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, content->only_caption(), log, first)));
}
void
/* Gather all subtitles with the same time period that are next
on the list. We must emit all subtitles for the same time
period with the same plain_text() call otherwise the
- CaptionDecoder will assume there is nothing else at the
+ TextDecoder will assume there is nothing else at the
time of emit the first.
*/
*/
-#include "caption_decoder.h"
+#include "text_decoder.h"
#include "dcp_subtitle.h"
class DCPSubtitleContent;
#include "decoder.h"
#include "video_decoder.h"
#include "audio_decoder.h"
-#include "caption_decoder.h"
+#include "text_decoder.h"
#include <boost/optional.hpp>
#include <iostream>
pos = audio->position();
}
- BOOST_FOREACH (shared_ptr<CaptionDecoder> i, caption) {
+ BOOST_FOREACH (shared_ptr<TextDecoder> i, caption) {
if (!i->ignore() && (!pos || i->position() < *pos)) {
pos = i->position();
}
if (audio) {
audio->seek ();
}
- BOOST_FOREACH (shared_ptr<CaptionDecoder> i, caption) {
+ BOOST_FOREACH (shared_ptr<TextDecoder> i, caption) {
i->seek ();
}
}
-shared_ptr<CaptionDecoder>
+shared_ptr<TextDecoder>
Decoder::only_caption () const
{
DCPOMATIC_ASSERT (caption.size() < 2);
if (caption.empty ()) {
- return shared_ptr<CaptionDecoder> ();
+ return shared_ptr<TextDecoder> ();
}
return caption.front ();
}
class Decoded;
class VideoDecoder;
class AudioDecoder;
-class CaptionDecoder;
+class TextDecoder;
class DecoderPart;
/** @class Decoder.
boost::shared_ptr<VideoDecoder> video;
boost::shared_ptr<AudioDecoder> audio;
- std::list<boost::shared_ptr<CaptionDecoder> > caption;
+ std::list<boost::shared_ptr<TextDecoder> > caption;
- boost::shared_ptr<CaptionDecoder> only_caption () const;
+ boost::shared_ptr<TextDecoder> only_caption () const;
/** Do some decoding and perhaps emit video, audio or subtitle data.
* @return true if this decoder will emit no more data unless a seek() happens.
#include "dcp_decoder.h"
#include "image_content.h"
#include "image_decoder.h"
-#include "text_caption_file_content.h"
-#include "text_caption_file_decoder.h"
+#include "string_text_file_content.h"
+#include "string_text_file_decoder.h"
#include "dcp_subtitle_content.h"
#include "dcp_subtitle_decoder.h"
#include "video_mxf_content.h"
return shared_ptr<Decoder> (new ImageDecoder (ic, log));
}
- shared_ptr<const TextCaptionFileContent> rc = dynamic_pointer_cast<const TextCaptionFileContent> (content);
+ shared_ptr<const StringTextFileContent> rc = dynamic_pointer_cast<const StringTextFileContent> (content);
if (rc) {
- return shared_ptr<Decoder> (new TextCaptionFileDecoder (rc, log));
+ return shared_ptr<Decoder> (new StringTextFileDecoder (rc, log));
}
shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (content);
#define DCPOMATIC_ENCODER_H
#include "types.h"
-#include "player_caption.h"
+#include "player_text.h"
#include <boost/weak_ptr.hpp>
#include <boost/signals2.hpp>
#include "log.h"
#include "exceptions.h"
#include "frame_rate_change.h"
-#include "caption_content.h"
+#include "text_content.h"
#include <dcp/raw_convert.h>
#include <libcxml/cxml.h>
extern "C" {
{
video = VideoContent::from_xml (this, node, version);
audio = AudioContent::from_xml (this, node, version);
- caption = CaptionContent::from_xml (this, node, version);
+ caption = TextContent::from_xml (this, node, version);
list<cxml::NodePtr> c = node->node_children ("SubtitleStream");
for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
audio.reset (new AudioContent (this, c));
}
if (need_caption) {
- caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, c)));
+ caption.push_back (shared_ptr<TextContent> (new TextContent (this, c)));
}
shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]);
_subtitle_streams = examiner->subtitle_streams ();
if (!_subtitle_streams.empty ()) {
caption.clear ();
- caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, CAPTION_OPEN)));
+ caption.push_back (shared_ptr<TextContent> (new TextContent (this, CAPTION_OPEN)));
_subtitle_stream = _subtitle_streams.front ();
}
#include "util.h"
#include "log.h"
#include "ffmpeg_decoder.h"
-#include "caption_decoder.h"
+#include "text_decoder.h"
#include "ffmpeg_audio_stream.h"
#include "ffmpeg_subtitle_stream.h"
#include "video_filter_graph.h"
#include "film.h"
#include "audio_decoder.h"
#include "compose.hpp"
-#include "caption_content.h"
+#include "text_content.h"
#include "audio_content.h"
#include <dcp/subtitle_string.h>
#include <sub/ssa_reader.h>
if (c->only_caption()) {
/* XXX: this time here should be the time of the first subtitle, not 0 */
- caption.push_back (shared_ptr<CaptionDecoder> (new CaptionDecoder (this, c->only_caption(), log, ContentTime())));
+ caption.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, c->only_caption(), log, ContentTime())));
}
_next_time.resize (_format_context->nb_streams);
}
void
-FFmpegEncoder::subtitle (PlayerCaption, DCPTimePeriod)
+FFmpegEncoder::subtitle (PlayerText, DCPTimePeriod)
{
}
private:
void video (boost::shared_ptr<PlayerVideo>, DCPTime);
void audio (boost::shared_ptr<AudioBuffers>);
- void subtitle (PlayerCaption, DCPTimePeriod);
+ void subtitle (PlayerText, DCPTimePeriod);
void setup_video ();
void setup_audio ();
#include "screen.h"
#include "audio_content.h"
#include "video_content.h"
-#include "caption_content.h"
+#include "text_content.h"
#include "ffmpeg_content.h"
#include "dcp_content.h"
#include "screen_kdm.h"
* 35 -> 36
* EffectColour rather than OutlineColour in Subtitle.
* 36 -> 37
- * CaptionContent can be in a Caption tag, and some of the tag names
+ * TextContent can be in a Caption tag, and some of the tag names
* have had Subtitle prefixes or suffixes removed.
*/
int const Film::current_state_version = 37;
bool burnt_in = true;
bool ccap = false;
BOOST_FOREACH (shared_ptr<Content> i, content()) {
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->caption) {
if (j->type() == CAPTION_OPEN && j->use() && !j->burn()) {
burnt_in = false;
} else if (j->type() == CAPTION_CLOSED) {
bool any_caption = false;
for (int i = 0; i < CAPTION_COUNT; ++i) {
- if (dc->reference_caption(static_cast<CaptionType>(i))) {
+ if (dc->reference_caption(static_cast<TextType>(i))) {
any_caption = true;
}
}
set<string> languages;
BOOST_FOREACH (shared_ptr<Content> i, content()) {
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->caption) {
languages.insert (j->language ());
}
}
#include "film.h"
#include "content.h"
#include "video_content.h"
-#include "caption_content.h"
+#include "text_content.h"
#include "audio_processor.h"
#include "font.h"
#include "ratio.h"
bool big_font_files = false;
if (film->interop ()) {
BOOST_FOREACH (shared_ptr<Content> i, content) {
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->caption) {
BOOST_FOREACH (shared_ptr<Font> k, j->fonts()) {
for (int l = 0; l < FontFiles::VARIANTS; ++l) {
optional<boost::filesystem::path> const p = k->file (static_cast<FontFiles::Variant>(l));
#include "decoder.h"
#include "video_decoder.h"
#include "audio_decoder.h"
-#include "caption_content.h"
-#include "caption_decoder.h"
+#include "text_content.h"
+#include "text_decoder.h"
#include "ffmpeg_content.h"
#include "audio_content.h"
#include "dcp_decoder.h"
}
if (_ignore_caption) {
- BOOST_FOREACH (shared_ptr<CaptionDecoder> i, decoder->caption) {
+ BOOST_FOREACH (shared_ptr<TextDecoder> i, decoder->caption) {
i->set_ignore (true);
}
}
decoder->audio->Data.connect (bind (&Player::audio, this, weak_ptr<Piece> (piece), _1, _2));
}
- list<shared_ptr<CaptionDecoder> >::const_iterator j = decoder->caption.begin();
+ list<shared_ptr<TextDecoder> >::const_iterator j = decoder->caption.begin();
while (j != decoder->caption.end()) {
(*j)->BitmapStart.connect (
- bind(&Player::bitmap_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const CaptionContent>((*j)->content()), _1)
+ bind(&Player::bitmap_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>((*j)->content()), _1)
);
(*j)->PlainStart.connect (
- bind(&Player::plain_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const CaptionContent>((*j)->content()), _1)
+ bind(&Player::plain_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>((*j)->content()), _1)
);
(*j)->Stop.connect (
- bind(&Player::subtitle_stop, this, weak_ptr<Piece>(piece), weak_ptr<const CaptionContent>((*j)->content()), _1, _2)
+ bind(&Player::subtitle_stop, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>((*j)->content()), _1, _2)
);
++j;
property == AudioContentProperty::STREAMS ||
property == DCPContentProperty::NEEDS_ASSETS ||
property == DCPContentProperty::NEEDS_KDM ||
- property == CaptionContentProperty::COLOUR ||
- property == CaptionContentProperty::EFFECT ||
- property == CaptionContentProperty::EFFECT_COLOUR ||
+ property == TextContentProperty::COLOUR ||
+ property == TextContentProperty::EFFECT ||
+ property == TextContentProperty::EFFECT_COLOUR ||
property == FFmpegContentProperty::SUBTITLE_STREAM ||
property == FFmpegContentProperty::FILTERS
) {
Changed (property, frequent);
} else if (
- property == CaptionContentProperty::LINE_SPACING ||
- property == CaptionContentProperty::OUTLINE_WIDTH ||
- property == CaptionContentProperty::Y_SCALE ||
- property == CaptionContentProperty::FADE_IN ||
- property == CaptionContentProperty::FADE_OUT ||
+ property == TextContentProperty::LINE_SPACING ||
+ property == TextContentProperty::OUTLINE_WIDTH ||
+ property == TextContentProperty::Y_SCALE ||
+ property == TextContentProperty::FADE_IN ||
+ property == TextContentProperty::FADE_OUT ||
property == ContentProperty::VIDEO_FRAME_RATE ||
- property == CaptionContentProperty::USE ||
- property == CaptionContentProperty::X_OFFSET ||
- property == CaptionContentProperty::Y_OFFSET ||
- property == CaptionContentProperty::X_SCALE ||
- property == CaptionContentProperty::FONTS ||
- property == CaptionContentProperty::TYPE ||
+ property == TextContentProperty::USE ||
+ property == TextContentProperty::X_OFFSET ||
+ property == TextContentProperty::Y_OFFSET ||
+ property == TextContentProperty::X_SCALE ||
+ property == TextContentProperty::FONTS ||
+ property == TextContentProperty::TYPE ||
property == VideoContentProperty::CROP ||
property == VideoContentProperty::SCALE ||
property == VideoContentProperty::FADE_IN ||
}
list<PositionImage>
-Player::transform_bitmap_captions (list<BitmapCaption> subs) const
+Player::transform_bitmap_captions (list<BitmapText> subs) const
{
list<PositionImage> all;
- for (list<BitmapCaption>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
+ for (list<BitmapText>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
if (!i->image) {
continue;
}
list<shared_ptr<Font> > fonts;
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->content->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->content->caption) {
/* XXX: things may go wrong if there are duplicate font IDs
with different font files.
*/
return done;
}
-list<PlayerCaption>
+list<PlayerText>
Player::closed_captions_for_frame (DCPTime time) const
{
return _active_captions[CAPTION_CLOSED].get (
int const vfr = _film->video_frame_rate();
BOOST_FOREACH (
- PlayerCaption j,
+ PlayerText j,
_active_captions[CAPTION_OPEN].get_burnt(DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), _always_burn_open_captions)
) {
}
void
-Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const CaptionContent> wc, ContentBitmapCaption subtitle)
+Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, ContentBitmapText subtitle)
{
shared_ptr<Piece> piece = wp.lock ();
- shared_ptr<const CaptionContent> caption = wc.lock ();
+ shared_ptr<const TextContent> caption = wc.lock ();
if (!piece || !caption) {
return;
}
subtitle.sub.rectangle.width *= caption->x_scale ();
subtitle.sub.rectangle.height *= caption->y_scale ();
- PlayerCaption ps;
+ PlayerText ps;
ps.image.push_back (subtitle.sub);
DCPTime from (content_time_to_dcp (piece, subtitle.from()));
}
void
-Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const CaptionContent> wc, ContentTextCaption subtitle)
+Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, ContentStringText subtitle)
{
shared_ptr<Piece> piece = wp.lock ();
- shared_ptr<const CaptionContent> caption = wc.lock ();
+ shared_ptr<const TextContent> caption = wc.lock ();
if (!piece || !caption) {
return;
}
- PlayerCaption ps;
+ PlayerText ps;
DCPTime const from (content_time_to_dcp (piece, subtitle.from()));
if (from > piece->content->end()) {
}
s.set_in (dcp::Time(from.seconds(), 1000));
- ps.text.push_back (TextCaption (s, caption->outline_width()));
+ ps.text.push_back (StringText (s, caption->outline_width()));
ps.add_fonts (caption->fonts ());
}
}
void
-Player::subtitle_stop (weak_ptr<Piece> wp, weak_ptr<const CaptionContent> wc, ContentTime to, CaptionType type)
+Player::subtitle_stop (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, ContentTime to, TextType type)
{
if (!_active_captions[type].have (wc)) {
return;
}
shared_ptr<Piece> piece = wp.lock ();
- shared_ptr<const CaptionContent> caption = wc.lock ();
+ shared_ptr<const TextContent> caption = wc.lock ();
if (!piece || !caption) {
return;
}
return;
}
- pair<PlayerCaption, DCPTime> from = _active_captions[type].add_to (wc, dcp_to);
+ pair<PlayerText, DCPTime> from = _active_captions[type].add_to (wc, dcp_to);
bool const always = type == CAPTION_OPEN && _always_burn_open_captions;
if (caption->use() && !always && !caption->burn()) {
#ifndef DCPOMATIC_PLAYER_H
#define DCPOMATIC_PLAYER_H
-#include "player_caption.h"
-#include "active_captions.h"
-#include "content_caption.h"
+#include "player_text.h"
+#include "active_text.h"
+#include "content_text.h"
#include "film.h"
#include "content.h"
#include "position_image.h"
DCPTime content_time_to_dcp (boost::shared_ptr<Content> content, ContentTime t);
- std::list<PlayerCaption> closed_captions_for_frame (DCPTime time) const;
+ 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
/** Emitted when a caption is ready. This signal may be emitted considerably
* after the corresponding Video.
*/
- boost::signals2::signal<void (PlayerCaption, CaptionType, DCPTimePeriod)> Caption;
+ boost::signals2::signal<void (PlayerText, TextType, DCPTimePeriod)> Caption;
private:
friend class PlayerWrapper;
void film_changed (Film::Property);
void playlist_changed ();
void playlist_content_changed (boost::weak_ptr<Content>, int, bool);
- std::list<PositionImage> transform_bitmap_captions (std::list<BitmapCaption>) const;
+ std::list<PositionImage> transform_bitmap_captions (std::list<BitmapText>) const;
Frame dcp_to_content_video (boost::shared_ptr<const Piece> piece, DCPTime t) const;
DCPTime content_video_to_dcp (boost::shared_ptr<const Piece> piece, Frame f) const;
Frame dcp_to_resampled_audio (boost::shared_ptr<const Piece> piece, DCPTime t) const;
boost::shared_ptr<PlayerVideo> black_player_video_frame (Eyes eyes) const;
void video (boost::weak_ptr<Piece>, ContentVideo);
void audio (boost::weak_ptr<Piece>, AudioStreamPtr, ContentAudio);
- void bitmap_text_start (boost::weak_ptr<Piece>, boost::weak_ptr<const CaptionContent>, ContentBitmapCaption);
- void plain_text_start (boost::weak_ptr<Piece>, boost::weak_ptr<const CaptionContent>, ContentTextCaption);
- void subtitle_stop (boost::weak_ptr<Piece>, boost::weak_ptr<const CaptionContent>, ContentTime, CaptionType);
+ void bitmap_text_start (boost::weak_ptr<Piece>, boost::weak_ptr<const TextContent>, ContentBitmapText);
+ void plain_text_start (boost::weak_ptr<Piece>, boost::weak_ptr<const TextContent>, ContentStringText);
+ void subtitle_stop (boost::weak_ptr<Piece>, boost::weak_ptr<const TextContent>, ContentTime, TextType);
DCPTime one_video_frame () const;
void fill_audio (DCPTimePeriod period);
std::pair<boost::shared_ptr<AudioBuffers>, DCPTime> discard_audio (
Empty _black;
Empty _silent;
- ActiveCaptions _active_captions[CAPTION_COUNT];
+ ActiveText _active_captions[CAPTION_COUNT];
boost::shared_ptr<AudioProcessor> _audio_processor;
boost::signals2::scoped_connection _film_changed_connection;
+++ /dev/null
-/*
- Copyright (C) 2014-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 "player_caption.h"
-#include "font.h"
-#include <boost/foreach.hpp>
-
-using std::list;
-using boost::shared_ptr;
-
-void
-PlayerCaption::add_fonts (list<shared_ptr<Font> > fonts_)
-{
- BOOST_FOREACH (shared_ptr<Font> i, fonts_) {
- bool got = false;
- BOOST_FOREACH (shared_ptr<Font> j, fonts) {
- if (*i == *j) {
- got = true;
- }
- }
- if (!got) {
- fonts.push_back (i);
- }
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2014-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/>.
-
-*/
-
-#ifndef DCPOMATIC_PLAYER_CAPTION_H
-#define DCPOMATIC_PLAYER_CAPTION_H
-
-#include "bitmap_caption.h"
-#include "dcpomatic_time.h"
-#include "text_caption.h"
-
-class Font;
-
-/** A set of text (subtitle/CCAP) which span the same time period */
-class PlayerCaption
-{
-public:
- void add_fonts (std::list<boost::shared_ptr<Font> > fonts_);
- std::list<boost::shared_ptr<Font> > fonts;
-
- /** BitmapCaptions, with their rectangles transformed as specified by their content */
- std::list<BitmapCaption> image;
- std::list<TextCaption> text;
-};
-
-#endif
--- /dev/null
+/*
+ Copyright (C) 2014-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 "player_text.h"
+#include "font.h"
+#include <boost/foreach.hpp>
+
+using std::list;
+using boost::shared_ptr;
+
+void
+PlayerText::add_fonts (list<shared_ptr<Font> > fonts_)
+{
+ BOOST_FOREACH (shared_ptr<Font> i, fonts_) {
+ bool got = false;
+ BOOST_FOREACH (shared_ptr<Font> j, fonts) {
+ if (*i == *j) {
+ got = true;
+ }
+ }
+ if (!got) {
+ fonts.push_back (i);
+ }
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2014-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/>.
+
+*/
+
+#ifndef DCPOMATIC_PLAYER_CAPTION_H
+#define DCPOMATIC_PLAYER_CAPTION_H
+
+#include "bitmap_text.h"
+#include "dcpomatic_time.h"
+#include "string_text.h"
+
+class Font;
+
+/** A set of text (subtitle/CCAP) which span the same time period */
+class PlayerText
+{
+public:
+ void add_fonts (std::list<boost::shared_ptr<Font> > fonts_);
+ std::list<boost::shared_ptr<Font> > fonts;
+
+ /** BitmapTexts, with their rectangles transformed as specified by their content */
+ std::list<BitmapText> image;
+ std::list<StringText> text;
+};
+
+#endif
#include "playlist.h"
#include "video_content.h"
-#include "caption_content.h"
+#include "text_content.h"
#include "ffmpeg_decoder.h"
#include "ffmpeg_content.h"
#include "image_decoder.h"
BOOST_FOREACH (shared_ptr<const Content> i, _content) {
bool burn = false;
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->caption) {
if (j->burn()) {
burn = true;
}
}
void
-ReelWriter::write (PlayerCaption subs, CaptionType type, DCPTimePeriod period)
+ReelWriter::write (PlayerText subs, TextType type, DCPTimePeriod period)
{
if (!_caption_asset[type]) {
string lang = _film->subtitle_language ();
}
}
- BOOST_FOREACH (TextCaption i, subs.text) {
+ BOOST_FOREACH (StringText i, subs.text) {
/* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */
i.set_in (i.in() - dcp::Time (_period.from.seconds(), i.in().tcr));
i.set_out (i.out() - dcp::Time (_period.from.seconds(), i.out().tcr));
_caption_asset[type]->add (shared_ptr<dcp::Subtitle>(new dcp::SubtitleString(i)));
}
- BOOST_FOREACH (BitmapCaption i, subs.image) {
+ BOOST_FOREACH (BitmapText i, subs.image) {
_caption_asset[type]->add (
shared_ptr<dcp::Subtitle>(
new dcp::SubtitleImage(
#include "types.h"
#include "dcpomatic_time.h"
#include "referenced_reel_asset.h"
-#include "player_caption.h"
+#include "player_text.h"
#include <dcp/picture_asset_writer.h>
#include <boost/shared_ptr.hpp>
void fake_write (Frame frame, Eyes eyes, int size);
void repeat_write (Frame frame, Eyes eyes);
void write (boost::shared_ptr<const AudioBuffers> audio);
- void write (PlayerCaption text, CaptionType type, DCPTimePeriod period);
+ void write (PlayerText text, TextType type, DCPTimePeriod period);
void finish ();
boost::shared_ptr<dcp::Reel> create_reel (std::list<ReferencedReelAsset> const & refs, std::list<boost::shared_ptr<Font> > const & fonts);
static list<pair<FontFiles, string> > fc_config_fonts;
string
-marked_up (list<TextCaption> subtitles, int target_height, float fade_factor)
+marked_up (list<StringText> subtitles, int target_height, float fade_factor)
{
string out;
- BOOST_FOREACH (TextCaption const & i, subtitles) {
+ BOOST_FOREACH (StringText const & i, subtitles) {
out += "<span ";
if (i.italic()) {
out += "style=\"italic\" ";
* at the same time and with the same fade in/out.
*/
static PositionImage
-render_line (list<TextCaption> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate)
+render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate)
{
/* XXX: this method can only handle italic / bold changes mid-line,
nothing else yet.
* @param frame_rate DCP frame rate.
*/
list<PositionImage>
-render_text (list<TextCaption> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate)
+render_text (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate)
{
- list<TextCaption> pending;
+ list<StringText> pending;
list<PositionImage> images;
- BOOST_FOREACH (TextCaption const & i, subtitles) {
+ BOOST_FOREACH (StringText const & i, subtitles) {
if (!pending.empty() && fabs (i.v_position() - pending.back().v_position()) > 1e-4) {
images.push_back (render_line (pending, fonts, target, time, frame_rate));
pending.clear ();
#include "position_image.h"
#include "dcpomatic_time.h"
-#include "text_caption.h"
+#include "string_text.h"
#include <dcp/util.h>
class Font;
-std::string marked_up (std::list<TextCaption> subtitles, int target_height, float fade_factor);
+std::string marked_up (std::list<StringText> subtitles, int target_height, float fade_factor);
std::list<PositionImage> render_text (
- std::list<TextCaption>, std::list<boost::shared_ptr<Font> > fonts, dcp::Size, DCPTime, int
+ std::list<StringText>, std::list<boost::shared_ptr<Font> > fonts, dcp::Size, DCPTime, int
);
--- /dev/null
+/*
+ Copyright (C) 2016-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/>.
+
+*/
+
+#ifndef DCPOMATIC_PLAIN_TEXT_H
+#define DCPOMATIC_PLAIN_TEXT_H
+
+#include <dcp/subtitle_string.h>
+
+/** A wrapper for SubtitleString which allows us to include settings that are not
+ * applicable to true DCP subtitles. For example, we can set outline width for burn-in
+ * but this cannot be specified in DCP XML.
+ */
+class StringText : public dcp::SubtitleString
+{
+public:
+ explicit StringText (dcp::SubtitleString dcp_)
+ : dcp::SubtitleString (dcp_)
+ , outline_width (2)
+ {}
+
+ StringText (dcp::SubtitleString dcp_, int outline_width_)
+ : dcp::SubtitleString (dcp_)
+ , outline_width (outline_width_)
+ {}
+
+ int outline_width;
+};
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014-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 "string_text_file.h"
+#include "cross.h"
+#include "exceptions.h"
+#include "string_text_file_content.h"
+#include <sub/subrip_reader.h>
+#include <sub/ssa_reader.h>
+#include <sub/collect.h>
+#include <unicode/ucsdet.h>
+#include <unicode/ucnv.h>
+#include <iostream>
+
+#include "i18n.h"
+
+using std::vector;
+using std::cout;
+using std::string;
+using boost::shared_ptr;
+using boost::scoped_array;
+using boost::optional;
+using dcp::Data;
+
+StringTextFile::StringTextFile (shared_ptr<const StringTextFileContent> content)
+{
+ Data in (content->path (0));
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCharsetDetector* detector = ucsdet_open (&status);
+ ucsdet_setText (detector, reinterpret_cast<const char *> (in.data().get()), in.size(), &status);
+
+ UCharsetMatch const * match = ucsdet_detect (detector, &status);
+ char const * in_charset = ucsdet_getName (match, &status);
+
+ UConverter* to_utf16 = ucnv_open (in_charset, &status);
+ /* This is a guess; I think we should be able to encode any input in 4 times its input size */
+ scoped_array<uint16_t> utf16 (new uint16_t[in.size() * 2]);
+ int const utf16_len = ucnv_toUChars (
+ to_utf16, reinterpret_cast<UChar*>(utf16.get()), in.size() * 2,
+ reinterpret_cast<const char *> (in.data().get()), in.size(),
+ &status
+ );
+
+ UConverter* to_utf8 = ucnv_open ("UTF-8", &status);
+ /* Another guess */
+ scoped_array<char> utf8 (new char[utf16_len * 2]);
+ ucnv_fromUChars (to_utf8, utf8.get(), utf16_len * 2, reinterpret_cast<UChar*>(utf16.get()), utf16_len, &status);
+
+ /* Fix OS X line endings */
+ size_t utf8_len = strlen (utf8.get ());
+ for (size_t i = 0; i < utf8_len; ++i) {
+ if (utf8[i] == '\r' && ((i == utf8_len - 1) || utf8[i + 1] != '\n')) {
+ utf8[i] = '\n';
+ }
+ }
+
+ ucsdet_close (detector);
+ ucnv_close (to_utf16);
+ ucnv_close (to_utf8);
+
+ sub::Reader* reader = 0;
+
+ string ext = content->path(0).extension().string();
+ transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
+
+ if (ext == ".srt") {
+ reader = new sub::SubripReader (utf8.get());
+ } else if (ext == ".ssa" || ext == ".ass") {
+ reader = new sub::SSAReader (utf8.get());
+ }
+
+ if (reader) {
+ _subtitles = sub::collect<vector<sub::Subtitle> > (reader->subtitles ());
+ }
+
+ delete reader;
+}
+
+/** @return time of first subtitle, if there is one */
+optional<ContentTime>
+StringTextFile::first () const
+{
+ if (_subtitles.empty()) {
+ return optional<ContentTime>();
+ }
+
+ return ContentTime::from_seconds(_subtitles[0].from.all_as_seconds());
+}
+
+ContentTime
+StringTextFile::length () const
+{
+ if (_subtitles.empty ()) {
+ return ContentTime ();
+ }
+
+ return ContentTime::from_seconds (_subtitles.back().to.all_as_seconds ());
+}
--- /dev/null
+/*
+ Copyright (C) 2014-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/>.
+
+*/
+
+#ifndef DCPOMATIC_TEXT_CAPTION_FILE_H
+#define DCPOMATIC_TEXT_CAPTION_FILE_H
+
+#include "dcpomatic_time.h"
+#include <sub/subtitle.h>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+class StringTextFileContent;
+class plain_text_time_test;
+class plain_text_coordinate_test;
+class plain_text_content_test;
+class plain_text_parse_test;
+
+/** @class StringTextFile
+ * @brief Base for StringTextFile decoder and examiner.
+ *
+ * In fact this is sufficient for the examiner, so it's used as-is rather than deriving
+ * a pointless StringTextFileExaminer.
+ */
+class StringTextFile
+{
+public:
+ explicit StringTextFile (boost::shared_ptr<const StringTextFileContent>);
+
+ boost::optional<ContentTime> first () const;
+ ContentTime length () const;
+
+protected:
+ std::vector<sub::Subtitle> _subtitles;
+};
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014-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 "string_text_file_content.h"
+#include "util.h"
+#include "string_text_file.h"
+#include "film.h"
+#include "font.h"
+#include "text_content.h"
+#include <dcp/raw_convert.h>
+#include <libxml++/libxml++.h>
+#include <iostream>
+
+#include "i18n.h"
+
+using std::string;
+using std::cout;
+using boost::shared_ptr;
+using dcp::raw_convert;
+
+StringTextFileContent::StringTextFileContent (shared_ptr<const Film> film, boost::filesystem::path path)
+ : Content (film, path)
+{
+ caption.push_back (shared_ptr<TextContent> (new TextContent (this, CAPTION_OPEN)));
+}
+
+StringTextFileContent::StringTextFileContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
+ : Content (film, node)
+ , _length (node->number_child<ContentTime::Type> ("Length"))
+{
+ caption = TextContent::from_xml (this, node, version);
+}
+
+void
+StringTextFileContent::examine (boost::shared_ptr<Job> job)
+{
+ Content::examine (job);
+ StringTextFile s (shared_from_this ());
+
+ /* Default to turning these subtitles on */
+ only_caption()->set_use (true);
+
+ boost::mutex::scoped_lock lm (_mutex);
+ _length = s.length ();
+ only_caption()->add_font (shared_ptr<Font> (new Font (TEXT_FONT_ID)));
+}
+
+string
+StringTextFileContent::summary () const
+{
+ return path_summary() + " " + _("[subtitles]");
+}
+
+string
+StringTextFileContent::technical_summary () const
+{
+ return Content::technical_summary() + " - " + _("Text subtitles");
+}
+
+void
+StringTextFileContent::as_xml (xmlpp::Node* node, bool with_paths) const
+{
+ node->add_child("Type")->add_child_text ("TextSubtitle");
+ Content::as_xml (node, with_paths);
+
+ if (only_caption()) {
+ only_caption()->as_xml (node);
+ }
+
+ node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ()));
+}
+
+DCPTime
+StringTextFileContent::full_length () const
+{
+ FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate ());
+ return DCPTime (_length, frc);
+}
--- /dev/null
+/*
+ Copyright (C) 2014-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 "content.h"
+
+class Job;
+
+/** @class StringTextFileContent
+ * @brief A SubRip, SSA or ASS file.
+ */
+class StringTextFileContent : public Content
+{
+public:
+ StringTextFileContent (boost::shared_ptr<const Film>, boost::filesystem::path);
+ StringTextFileContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
+
+ boost::shared_ptr<StringTextFileContent> shared_from_this () {
+ return boost::dynamic_pointer_cast<StringTextFileContent> (Content::shared_from_this ());
+ }
+
+ void examine (boost::shared_ptr<Job>);
+ std::string summary () const;
+ std::string technical_summary () const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
+ DCPTime full_length () const;
+
+private:
+ ContentTime _length;
+};
--- /dev/null
+/*
+ Copyright (C) 2014-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 "string_text_file_decoder.h"
+#include "string_text_file_content.h"
+#include "text_content.h"
+#include "text_decoder.h"
+#include <dcp/subtitle_string.h>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+using std::list;
+using std::vector;
+using std::string;
+using std::cout;
+using std::max;
+using boost::shared_ptr;
+using boost::optional;
+using boost::dynamic_pointer_cast;
+
+StringTextFileDecoder::StringTextFileDecoder (shared_ptr<const StringTextFileContent> content, shared_ptr<Log> log)
+ : StringTextFile (content)
+ , _next (0)
+{
+ ContentTime first;
+ if (!_subtitles.empty()) {
+ first = content_time_period(_subtitles[0]).from;
+ }
+ caption.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, content->only_caption(), log, first)));
+}
+
+void
+StringTextFileDecoder::seek (ContentTime time, bool accurate)
+{
+ /* It's worth back-tracking a little here as decoding is cheap and it's nice if we don't miss
+ too many subtitles when seeking.
+ */
+ time -= ContentTime::from_seconds (5);
+ if (time < ContentTime()) {
+ time = ContentTime();
+ }
+
+ Decoder::seek (time, accurate);
+
+ _next = 0;
+ while (_next < _subtitles.size() && ContentTime::from_seconds (_subtitles[_next].from.all_as_seconds ()) < time) {
+ ++_next;
+ }
+}
+
+bool
+StringTextFileDecoder::pass ()
+{
+ if (_next >= _subtitles.size ()) {
+ return true;
+ }
+
+ ContentTimePeriod const p = content_time_period (_subtitles[_next]);
+ only_caption()->emit_plain (p, _subtitles[_next]);
+
+ ++_next;
+ return false;
+}
+
+ContentTimePeriod
+StringTextFileDecoder::content_time_period (sub::Subtitle s) const
+{
+ return ContentTimePeriod (
+ ContentTime::from_seconds (s.from.all_as_seconds()),
+ ContentTime::from_seconds (s.to.all_as_seconds())
+ );
+}
--- /dev/null
+/*
+ Copyright (C) 2014-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/>.
+
+*/
+
+#ifndef DCPOMATIC_TEXT_CAPTION_FILE_DECODER_H
+#define DCPOMATIC_TEXT_CAPTION_FILE_DECODER_H
+
+#include "string_text_file.h"
+#include "decoder.h"
+
+class StringTextFileContent;
+class Log;
+
+class StringTextFileDecoder : public Decoder, public StringTextFile
+{
+public:
+ StringTextFileDecoder (boost::shared_ptr<const StringTextFileContent>, boost::shared_ptr<Log> log);
+
+ void seek (ContentTime time, bool accurate);
+ bool pass ();
+
+private:
+ ContentTimePeriod content_time_period (sub::Subtitle s) const;
+
+ size_t _next;
+};
+
+#endif
+++ /dev/null
-/*
- Copyright (C) 2016-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/>.
-
-*/
-
-#ifndef DCPOMATIC_PLAIN_TEXT_H
-#define DCPOMATIC_PLAIN_TEXT_H
-
-#include <dcp/subtitle_string.h>
-
-/** A wrapper for SubtitleString which allows us to include settings that are not
- * applicable to true DCP subtitles. For example, we can set outline width for burn-in
- * but this cannot be specified in DCP XML.
- */
-class TextCaption : public dcp::SubtitleString
-{
-public:
- explicit TextCaption (dcp::SubtitleString dcp_)
- : dcp::SubtitleString (dcp_)
- , outline_width (2)
- {}
-
- TextCaption (dcp::SubtitleString dcp_, int outline_width_)
- : dcp::SubtitleString (dcp_)
- , outline_width (outline_width_)
- {}
-
- int outline_width;
-};
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2014-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 "text_caption_file.h"
-#include "cross.h"
-#include "exceptions.h"
-#include "text_caption_file_content.h"
-#include <sub/subrip_reader.h>
-#include <sub/ssa_reader.h>
-#include <sub/collect.h>
-#include <unicode/ucsdet.h>
-#include <unicode/ucnv.h>
-#include <iostream>
-
-#include "i18n.h"
-
-using std::vector;
-using std::cout;
-using std::string;
-using boost::shared_ptr;
-using boost::scoped_array;
-using boost::optional;
-using dcp::Data;
-
-TextCaptionFile::TextCaptionFile (shared_ptr<const TextCaptionFileContent> content)
-{
- Data in (content->path (0));
-
- UErrorCode status = U_ZERO_ERROR;
- UCharsetDetector* detector = ucsdet_open (&status);
- ucsdet_setText (detector, reinterpret_cast<const char *> (in.data().get()), in.size(), &status);
-
- UCharsetMatch const * match = ucsdet_detect (detector, &status);
- char const * in_charset = ucsdet_getName (match, &status);
-
- UConverter* to_utf16 = ucnv_open (in_charset, &status);
- /* This is a guess; I think we should be able to encode any input in 4 times its input size */
- scoped_array<uint16_t> utf16 (new uint16_t[in.size() * 2]);
- int const utf16_len = ucnv_toUChars (
- to_utf16, reinterpret_cast<UChar*>(utf16.get()), in.size() * 2,
- reinterpret_cast<const char *> (in.data().get()), in.size(),
- &status
- );
-
- UConverter* to_utf8 = ucnv_open ("UTF-8", &status);
- /* Another guess */
- scoped_array<char> utf8 (new char[utf16_len * 2]);
- ucnv_fromUChars (to_utf8, utf8.get(), utf16_len * 2, reinterpret_cast<UChar*>(utf16.get()), utf16_len, &status);
-
- /* Fix OS X line endings */
- size_t utf8_len = strlen (utf8.get ());
- for (size_t i = 0; i < utf8_len; ++i) {
- if (utf8[i] == '\r' && ((i == utf8_len - 1) || utf8[i + 1] != '\n')) {
- utf8[i] = '\n';
- }
- }
-
- ucsdet_close (detector);
- ucnv_close (to_utf16);
- ucnv_close (to_utf8);
-
- sub::Reader* reader = 0;
-
- string ext = content->path(0).extension().string();
- transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
-
- if (ext == ".srt") {
- reader = new sub::SubripReader (utf8.get());
- } else if (ext == ".ssa" || ext == ".ass") {
- reader = new sub::SSAReader (utf8.get());
- }
-
- if (reader) {
- _subtitles = sub::collect<vector<sub::Subtitle> > (reader->subtitles ());
- }
-
- delete reader;
-}
-
-/** @return time of first subtitle, if there is one */
-optional<ContentTime>
-TextCaptionFile::first () const
-{
- if (_subtitles.empty()) {
- return optional<ContentTime>();
- }
-
- return ContentTime::from_seconds(_subtitles[0].from.all_as_seconds());
-}
-
-ContentTime
-TextCaptionFile::length () const
-{
- if (_subtitles.empty ()) {
- return ContentTime ();
- }
-
- return ContentTime::from_seconds (_subtitles.back().to.all_as_seconds ());
-}
+++ /dev/null
-/*
- Copyright (C) 2014-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/>.
-
-*/
-
-#ifndef DCPOMATIC_TEXT_CAPTION_FILE_H
-#define DCPOMATIC_TEXT_CAPTION_FILE_H
-
-#include "dcpomatic_time.h"
-#include <sub/subtitle.h>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-
-class TextCaptionFileContent;
-class plain_text_time_test;
-class plain_text_coordinate_test;
-class plain_text_content_test;
-class plain_text_parse_test;
-
-/** @class TextCaptionFile
- * @brief Base for TextCaptionFile decoder and examiner.
- *
- * In fact this is sufficient for the examiner, so it's used as-is rather than deriving
- * a pointless TextCaptionFileExaminer.
- */
-class TextCaptionFile
-{
-public:
- explicit TextCaptionFile (boost::shared_ptr<const TextCaptionFileContent>);
-
- boost::optional<ContentTime> first () const;
- ContentTime length () const;
-
-protected:
- std::vector<sub::Subtitle> _subtitles;
-};
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2014-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 "text_caption_file_content.h"
-#include "util.h"
-#include "text_caption_file.h"
-#include "film.h"
-#include "font.h"
-#include "caption_content.h"
-#include <dcp/raw_convert.h>
-#include <libxml++/libxml++.h>
-#include <iostream>
-
-#include "i18n.h"
-
-using std::string;
-using std::cout;
-using boost::shared_ptr;
-using dcp::raw_convert;
-
-TextCaptionFileContent::TextCaptionFileContent (shared_ptr<const Film> film, boost::filesystem::path path)
- : Content (film, path)
-{
- caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, CAPTION_OPEN)));
-}
-
-TextCaptionFileContent::TextCaptionFileContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
- : Content (film, node)
- , _length (node->number_child<ContentTime::Type> ("Length"))
-{
- caption = CaptionContent::from_xml (this, node, version);
-}
-
-void
-TextCaptionFileContent::examine (boost::shared_ptr<Job> job)
-{
- Content::examine (job);
- TextCaptionFile s (shared_from_this ());
-
- /* Default to turning these subtitles on */
- only_caption()->set_use (true);
-
- boost::mutex::scoped_lock lm (_mutex);
- _length = s.length ();
- only_caption()->add_font (shared_ptr<Font> (new Font (TEXT_FONT_ID)));
-}
-
-string
-TextCaptionFileContent::summary () const
-{
- return path_summary() + " " + _("[subtitles]");
-}
-
-string
-TextCaptionFileContent::technical_summary () const
-{
- return Content::technical_summary() + " - " + _("Text subtitles");
-}
-
-void
-TextCaptionFileContent::as_xml (xmlpp::Node* node, bool with_paths) const
-{
- node->add_child("Type")->add_child_text ("TextSubtitle");
- Content::as_xml (node, with_paths);
-
- if (only_caption()) {
- only_caption()->as_xml (node);
- }
-
- node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ()));
-}
-
-DCPTime
-TextCaptionFileContent::full_length () const
-{
- FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate ());
- return DCPTime (_length, frc);
-}
+++ /dev/null
-/*
- Copyright (C) 2014-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 "content.h"
-
-class Job;
-
-/** @class TextCaptionFileContent
- * @brief A SubRip, SSA or ASS file.
- */
-class TextCaptionFileContent : public Content
-{
-public:
- TextCaptionFileContent (boost::shared_ptr<const Film>, boost::filesystem::path);
- TextCaptionFileContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
-
- boost::shared_ptr<TextCaptionFileContent> shared_from_this () {
- return boost::dynamic_pointer_cast<TextCaptionFileContent> (Content::shared_from_this ());
- }
-
- void examine (boost::shared_ptr<Job>);
- std::string summary () const;
- std::string technical_summary () const;
- void as_xml (xmlpp::Node *, bool with_paths) const;
- DCPTime full_length () const;
-
-private:
- ContentTime _length;
-};
+++ /dev/null
-/*
- Copyright (C) 2014-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 "text_caption_file_decoder.h"
-#include "text_caption_file_content.h"
-#include "caption_content.h"
-#include "caption_decoder.h"
-#include <dcp/subtitle_string.h>
-#include <boost/foreach.hpp>
-#include <iostream>
-
-using std::list;
-using std::vector;
-using std::string;
-using std::cout;
-using std::max;
-using boost::shared_ptr;
-using boost::optional;
-using boost::dynamic_pointer_cast;
-
-TextCaptionFileDecoder::TextCaptionFileDecoder (shared_ptr<const TextCaptionFileContent> content, shared_ptr<Log> log)
- : TextCaptionFile (content)
- , _next (0)
-{
- ContentTime first;
- if (!_subtitles.empty()) {
- first = content_time_period(_subtitles[0]).from;
- }
- caption.push_back (shared_ptr<CaptionDecoder> (new CaptionDecoder (this, content->only_caption(), log, first)));
-}
-
-void
-TextCaptionFileDecoder::seek (ContentTime time, bool accurate)
-{
- /* It's worth back-tracking a little here as decoding is cheap and it's nice if we don't miss
- too many subtitles when seeking.
- */
- time -= ContentTime::from_seconds (5);
- if (time < ContentTime()) {
- time = ContentTime();
- }
-
- Decoder::seek (time, accurate);
-
- _next = 0;
- while (_next < _subtitles.size() && ContentTime::from_seconds (_subtitles[_next].from.all_as_seconds ()) < time) {
- ++_next;
- }
-}
-
-bool
-TextCaptionFileDecoder::pass ()
-{
- if (_next >= _subtitles.size ()) {
- return true;
- }
-
- ContentTimePeriod const p = content_time_period (_subtitles[_next]);
- only_caption()->emit_plain (p, _subtitles[_next]);
-
- ++_next;
- return false;
-}
-
-ContentTimePeriod
-TextCaptionFileDecoder::content_time_period (sub::Subtitle s) const
-{
- return ContentTimePeriod (
- ContentTime::from_seconds (s.from.all_as_seconds()),
- ContentTime::from_seconds (s.to.all_as_seconds())
- );
-}
+++ /dev/null
-/*
- Copyright (C) 2014-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/>.
-
-*/
-
-#ifndef DCPOMATIC_TEXT_CAPTION_FILE_DECODER_H
-#define DCPOMATIC_TEXT_CAPTION_FILE_DECODER_H
-
-#include "text_caption_file.h"
-#include "decoder.h"
-
-class TextCaptionFileContent;
-class Log;
-
-class TextCaptionFileDecoder : public Decoder, public TextCaptionFile
-{
-public:
- TextCaptionFileDecoder (boost::shared_ptr<const TextCaptionFileContent>, boost::shared_ptr<Log> log);
-
- void seek (ContentTime time, bool accurate);
- bool pass ();
-
-private:
- ContentTimePeriod content_time_period (sub::Subtitle s) const;
-
- size_t _next;
-};
-
-#endif
--- /dev/null
+/*
+ Copyright (C) 2013-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 "text_content.h"
+#include "util.h"
+#include "exceptions.h"
+#include "font.h"
+#include "content.h"
+#include <dcp/raw_convert.h>
+#include <libcxml/cxml.h>
+#include <libxml++/libxml++.h>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+#include "i18n.h"
+
+using std::string;
+using std::vector;
+using std::cout;
+using std::list;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using boost::optional;
+using dcp::raw_convert;
+
+int const TextContentProperty::X_OFFSET = 500;
+int const TextContentProperty::Y_OFFSET = 501;
+int const TextContentProperty::X_SCALE = 502;
+int const TextContentProperty::Y_SCALE = 503;
+int const TextContentProperty::USE = 504;
+int const TextContentProperty::BURN = 505;
+int const TextContentProperty::LANGUAGE = 506;
+int const TextContentProperty::FONTS = 507;
+int const TextContentProperty::COLOUR = 508;
+int const TextContentProperty::EFFECT = 509;
+int const TextContentProperty::EFFECT_COLOUR = 510;
+int const TextContentProperty::LINE_SPACING = 511;
+int const TextContentProperty::FADE_IN = 512;
+int const TextContentProperty::FADE_OUT = 513;
+int const TextContentProperty::OUTLINE_WIDTH = 514;
+int const TextContentProperty::TYPE = 515;
+
+TextContent::TextContent (Content* parent, TextType original_type)
+ : ContentPart (parent)
+ , _use (false)
+ , _burn (false)
+ , _x_offset (0)
+ , _y_offset (0)
+ , _x_scale (1)
+ , _y_scale (1)
+ , _line_spacing (1)
+ , _outline_width (2)
+ , _type (original_type)
+ , _original_type (original_type)
+{
+
+}
+
+/** @return TextContents from node or <Caption> nodes under node (according to version).
+ * The list could be empty if no TextContents are found.
+ */
+list<shared_ptr<TextContent> >
+TextContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version)
+{
+ if (version < 34) {
+ /* With old metadata FFmpeg content has the subtitle-related tags even with no
+ subtitle streams, so check for that.
+ */
+ if (node->string_child("Type") == "FFmpeg" && node->node_children("SubtitleStream").empty()) {
+ return list<shared_ptr<TextContent> >();
+ }
+
+ /* Otherwise we can drop through to the newer logic */
+ }
+
+ if (version < 37) {
+ if (!node->optional_number_child<double>("SubtitleXOffset") && !node->optional_number_child<double>("SubtitleOffset")) {
+ return list<shared_ptr<TextContent> >();
+ }
+ list<shared_ptr<TextContent> > c;
+ c.push_back (shared_ptr<TextContent> (new TextContent (parent, node, version)));
+ return c;
+ }
+
+ if (!node->optional_node_child("Caption")) {
+ return list<shared_ptr<TextContent> >();
+ }
+
+ list<shared_ptr<TextContent> > c;
+ BOOST_FOREACH (cxml::ConstNodePtr i, node->node_children("Caption")) {
+ c.push_back (shared_ptr<TextContent> (new TextContent (parent, i, version)));
+ }
+ return c;
+}
+
+TextContent::TextContent (Content* parent, cxml::ConstNodePtr node, int version)
+ : ContentPart (parent)
+ , _use (false)
+ , _burn (false)
+ , _x_offset (0)
+ , _y_offset (0)
+ , _x_scale (1)
+ , _y_scale (1)
+ , _line_spacing (node->optional_number_child<double>("LineSpacing").get_value_or (1))
+ , _outline_width (node->optional_number_child<int>("OutlineWidth").get_value_or (2))
+ , _type (CAPTION_OPEN)
+ , _original_type (CAPTION_OPEN)
+{
+ if (version >= 37) {
+ _use = node->bool_child ("Use");
+ _burn = node->bool_child ("Burn");
+ } else if (version >= 32) {
+ _use = node->bool_child ("UseSubtitles");
+ _burn = node->bool_child ("BurnSubtitles");
+ }
+
+ if (version >= 37) {
+ _x_offset = node->number_child<double> ("XOffset");
+ _y_offset = node->number_child<double> ("YOffset");
+ } else if (version >= 7) {
+ _x_offset = node->number_child<double> ("SubtitleXOffset");
+ _y_offset = node->number_child<double> ("SubtitleYOffset");
+ } else {
+ _y_offset = node->number_child<double> ("SubtitleOffset");
+ }
+
+ if (node->optional_bool_child("Outline").get_value_or(false)) {
+ _effect = dcp::BORDER;
+ } else if (node->optional_bool_child("Shadow").get_value_or(false)) {
+ _effect = dcp::SHADOW;
+ } else {
+ _effect = dcp::NONE;
+ }
+
+ optional<string> effect = node->optional_string_child("Effect");
+ if (effect) {
+ if (*effect == "none") {
+ _effect = dcp::NONE;
+ } else if (*effect == "outline") {
+ _effect = dcp::BORDER;
+ } else if (*effect == "shadow") {
+ _effect = dcp::SHADOW;
+ }
+ }
+
+ if (version >= 37) {
+ _x_scale = node->number_child<double> ("XScale");
+ _y_scale = node->number_child<double> ("YScale");
+ } else if (version >= 10) {
+ _x_scale = node->number_child<double> ("SubtitleXScale");
+ _y_scale = node->number_child<double> ("SubtitleYScale");
+ } else {
+ _x_scale = _y_scale = node->number_child<double> ("SubtitleScale");
+ }
+
+ optional<int> r = node->optional_number_child<int>("Red");
+ optional<int> g = node->optional_number_child<int>("Green");
+ optional<int> b = node->optional_number_child<int>("Blue");
+ if (r && g && b) {
+ _colour = dcp::Colour (*r, *g, *b);
+ }
+
+ if (version >= 36) {
+ optional<int> er = node->optional_number_child<int>("EffectRed");
+ optional<int> eg = node->optional_number_child<int>("EffectGreen");
+ optional<int> eb = node->optional_number_child<int>("EffectBlue");
+ if (er && eg && eb) {
+ _effect_colour = dcp::Colour (*er, *eg, *eb);
+ }
+ } else {
+ _effect_colour = dcp::Colour (
+ node->optional_number_child<int>("OutlineRed").get_value_or(255),
+ node->optional_number_child<int>("OutlineGreen").get_value_or(255),
+ node->optional_number_child<int>("OutlineBlue").get_value_or(255)
+ );
+ }
+
+ optional<Frame> fi;
+ if (version >= 37) {
+ fi = node->optional_number_child<Frame>("FadeIn");
+ } else {
+ fi = node->optional_number_child<Frame>("SubtitleFadeIn");
+ }
+ if (fi) {
+ _fade_in = ContentTime (*fi);
+ }
+
+ optional<Frame> fo;
+ if (version >= 37) {
+ fo = node->optional_number_child<Frame>("FadeOut");
+ } else {
+ fo = node->optional_number_child<Frame>("SubtitleFadeOut");
+ }
+ if (fo) {
+ _fade_out = ContentTime (*fo);
+ }
+
+ if (version >= 37) {
+ _language = node->optional_string_child ("Language").get_value_or ("");
+ } else {
+ _language = node->optional_string_child ("SubtitleLanguage").get_value_or ("");
+ }
+
+ list<cxml::NodePtr> fonts = node->node_children ("Font");
+ for (list<cxml::NodePtr>::const_iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ _fonts.push_back (shared_ptr<Font> (new Font (*i)));
+ }
+
+ connect_to_fonts ();
+
+ _type = string_to_caption_type (node->optional_string_child("Type").get_value_or("open"));
+ _original_type = string_to_caption_type (node->optional_string_child("OriginalType").get_value_or("open"));
+}
+
+TextContent::TextContent (Content* parent, vector<shared_ptr<Content> > c)
+ : ContentPart (parent)
+{
+ /* This constructor is for join which is only supported for content types
+ that have a single caption, so we can use only_caption() here.
+ */
+ shared_ptr<TextContent> ref = c[0]->only_caption();
+ DCPOMATIC_ASSERT (ref);
+ list<shared_ptr<Font> > ref_fonts = ref->fonts ();
+
+ for (size_t i = 1; i < c.size(); ++i) {
+
+ if (c[i]->only_caption()->use() != ref->use()) {
+ throw JoinError (_("Content to be joined must have the same 'use subtitles' setting."));
+ }
+
+ if (c[i]->only_caption()->burn() != ref->burn()) {
+ throw JoinError (_("Content to be joined must have the same 'burn subtitles' setting."));
+ }
+
+ if (c[i]->only_caption()->x_offset() != ref->x_offset()) {
+ throw JoinError (_("Content to be joined must have the same subtitle X offset."));
+ }
+
+ if (c[i]->only_caption()->y_offset() != ref->y_offset()) {
+ throw JoinError (_("Content to be joined must have the same subtitle Y offset."));
+ }
+
+ if (c[i]->only_caption()->x_scale() != ref->x_scale()) {
+ throw JoinError (_("Content to be joined must have the same subtitle X scale."));
+ }
+
+ if (c[i]->only_caption()->y_scale() != ref->y_scale()) {
+ throw JoinError (_("Content to be joined must have the same subtitle Y scale."));
+ }
+
+ if (c[i]->only_caption()->line_spacing() != ref->line_spacing()) {
+ throw JoinError (_("Content to be joined must have the same subtitle line spacing."));
+ }
+
+ if ((c[i]->only_caption()->fade_in() != ref->fade_in()) || (c[i]->only_caption()->fade_out() != ref->fade_out())) {
+ throw JoinError (_("Content to be joined must have the same subtitle fades."));
+ }
+
+ if ((c[i]->only_caption()->outline_width() != ref->outline_width())) {
+ throw JoinError (_("Content to be joined must have the same outline width."));
+ }
+
+ list<shared_ptr<Font> > fonts = c[i]->only_caption()->fonts ();
+ if (fonts.size() != ref_fonts.size()) {
+ throw JoinError (_("Content to be joined must use the same fonts."));
+ }
+
+ list<shared_ptr<Font> >::const_iterator j = ref_fonts.begin ();
+ list<shared_ptr<Font> >::const_iterator k = fonts.begin ();
+
+ while (j != ref_fonts.end ()) {
+ if (**j != **k) {
+ throw JoinError (_("Content to be joined must use the same fonts."));
+ }
+ ++j;
+ ++k;
+ }
+ }
+
+ _use = ref->use ();
+ _burn = ref->burn ();
+ _x_offset = ref->x_offset ();
+ _y_offset = ref->y_offset ();
+ _x_scale = ref->x_scale ();
+ _y_scale = ref->y_scale ();
+ _language = ref->language ();
+ _fonts = ref_fonts;
+ _line_spacing = ref->line_spacing ();
+ _fade_in = ref->fade_in ();
+ _fade_out = ref->fade_out ();
+ _outline_width = ref->outline_width ();
+ _type = ref->type ();
+ _original_type = ref->original_type ();
+
+ connect_to_fonts ();
+}
+
+/** _mutex must not be held on entry */
+void
+TextContent::as_xml (xmlpp::Node* root) const
+{
+ boost::mutex::scoped_lock lm (_mutex);
+
+ xmlpp::Element* caption = root->add_child ("Caption");
+
+ caption->add_child("Use")->add_child_text (_use ? "1" : "0");
+ caption->add_child("Burn")->add_child_text (_burn ? "1" : "0");
+ caption->add_child("XOffset")->add_child_text (raw_convert<string> (_x_offset));
+ caption->add_child("YOffset")->add_child_text (raw_convert<string> (_y_offset));
+ caption->add_child("XScale")->add_child_text (raw_convert<string> (_x_scale));
+ caption->add_child("YScale")->add_child_text (raw_convert<string> (_y_scale));
+ caption->add_child("Language")->add_child_text (_language);
+ if (_colour) {
+ caption->add_child("Red")->add_child_text (raw_convert<string> (_colour->r));
+ caption->add_child("Green")->add_child_text (raw_convert<string> (_colour->g));
+ caption->add_child("Blue")->add_child_text (raw_convert<string> (_colour->b));
+ }
+ if (_effect) {
+ switch (*_effect) {
+ case dcp::NONE:
+ caption->add_child("Effect")->add_child_text("none");
+ break;
+ case dcp::BORDER:
+ caption->add_child("Effect")->add_child_text("outline");
+ break;
+ case dcp::SHADOW:
+ caption->add_child("Effect")->add_child_text("shadow");
+ break;
+ }
+ }
+ if (_effect_colour) {
+ caption->add_child("EffectRed")->add_child_text (raw_convert<string> (_effect_colour->r));
+ caption->add_child("EffectGreen")->add_child_text (raw_convert<string> (_effect_colour->g));
+ caption->add_child("EffectBlue")->add_child_text (raw_convert<string> (_effect_colour->b));
+ }
+ caption->add_child("LineSpacing")->add_child_text (raw_convert<string> (_line_spacing));
+ if (_fade_in) {
+ caption->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in->get()));
+ }
+ if (_fade_out) {
+ caption->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out->get()));
+ }
+ caption->add_child("OutlineWidth")->add_child_text (raw_convert<string> (_outline_width));
+
+ for (list<shared_ptr<Font> >::const_iterator i = _fonts.begin(); i != _fonts.end(); ++i) {
+ (*i)->as_xml (caption->add_child("Font"));
+ }
+
+ caption->add_child("Type")->add_child_text (caption_type_to_string(_type));
+ caption->add_child("OriginalType")->add_child_text (caption_type_to_string(_original_type));
+}
+
+string
+TextContent::identifier () const
+{
+ string s = raw_convert<string> (x_scale())
+ + "_" + raw_convert<string> (y_scale())
+ + "_" + raw_convert<string> (x_offset())
+ + "_" + raw_convert<string> (y_offset())
+ + "_" + raw_convert<string> (line_spacing())
+ + "_" + raw_convert<string> (fade_in().get_value_or(ContentTime()).get())
+ + "_" + raw_convert<string> (fade_out().get_value_or(ContentTime()).get())
+ + "_" + raw_convert<string> (outline_width())
+ + "_" + raw_convert<string> (colour().get_value_or(dcp::Colour(255, 255, 255)).to_argb_string())
+ + "_" + raw_convert<string> (dcp::effect_to_string(effect().get_value_or(dcp::NONE)))
+ + "_" + raw_convert<string> (effect_colour().get_value_or(dcp::Colour(0, 0, 0)).to_argb_string());
+
+ /* XXX: I suppose really _fonts shouldn't be in here, since not all
+ types of subtitle content involve fonts.
+ */
+ BOOST_FOREACH (shared_ptr<Font> f, _fonts) {
+ for (int i = 0; i < FontFiles::VARIANTS; ++i) {
+ s += "_" + f->file(static_cast<FontFiles::Variant>(i)).get_value_or("Default").string();
+ }
+ }
+
+ /* The language is for metadata only, and doesn't affect
+ how this content looks.
+ */
+
+ return s;
+}
+
+void
+TextContent::add_font (shared_ptr<Font> font)
+{
+ _fonts.push_back (font);
+ connect_to_fonts ();
+}
+
+void
+TextContent::connect_to_fonts ()
+{
+ BOOST_FOREACH (boost::signals2::connection& i, _font_connections) {
+ i.disconnect ();
+ }
+
+ _font_connections.clear ();
+
+ BOOST_FOREACH (shared_ptr<Font> i, _fonts) {
+ _font_connections.push_back (i->Changed.connect (boost::bind (&TextContent::font_changed, this)));
+ }
+}
+
+void
+TextContent::font_changed ()
+{
+ _parent->signal_changed (TextContentProperty::FONTS);
+}
+
+void
+TextContent::set_colour (dcp::Colour colour)
+{
+ maybe_set (_colour, colour, TextContentProperty::COLOUR);
+}
+
+void
+TextContent::unset_colour ()
+{
+ maybe_set (_colour, optional<dcp::Colour>(), TextContentProperty::COLOUR);
+}
+
+void
+TextContent::set_effect (dcp::Effect e)
+{
+ maybe_set (_effect, e, TextContentProperty::EFFECT);
+}
+
+void
+TextContent::unset_effect ()
+{
+ maybe_set (_effect, optional<dcp::Effect>(), TextContentProperty::EFFECT);
+}
+
+void
+TextContent::set_effect_colour (dcp::Colour colour)
+{
+ maybe_set (_effect_colour, colour, TextContentProperty::EFFECT_COLOUR);
+}
+
+void
+TextContent::unset_effect_colour ()
+{
+ maybe_set (_effect_colour, optional<dcp::Colour>(), TextContentProperty::EFFECT_COLOUR);
+}
+
+void
+TextContent::set_use (bool u)
+{
+ maybe_set (_use, u, TextContentProperty::USE);
+}
+
+void
+TextContent::set_burn (bool b)
+{
+ maybe_set (_burn, b, TextContentProperty::BURN);
+}
+
+void
+TextContent::set_x_offset (double o)
+{
+ maybe_set (_x_offset, o, TextContentProperty::X_OFFSET);
+}
+
+void
+TextContent::set_y_offset (double o)
+{
+ maybe_set (_y_offset, o, TextContentProperty::Y_OFFSET);
+}
+
+void
+TextContent::set_x_scale (double s)
+{
+ maybe_set (_x_scale, s, TextContentProperty::X_SCALE);
+}
+
+void
+TextContent::set_y_scale (double s)
+{
+ maybe_set (_y_scale, s, TextContentProperty::Y_SCALE);
+}
+
+void
+TextContent::set_language (string language)
+{
+ maybe_set (_language, language, TextContentProperty::LANGUAGE);
+}
+
+void
+TextContent::set_line_spacing (double s)
+{
+ maybe_set (_line_spacing, s, TextContentProperty::LINE_SPACING);
+}
+
+void
+TextContent::set_fade_in (ContentTime t)
+{
+ maybe_set (_fade_in, t, TextContentProperty::FADE_IN);
+}
+
+void
+TextContent::unset_fade_in ()
+{
+ maybe_set (_fade_in, optional<ContentTime>(), TextContentProperty::FADE_IN);
+}
+
+void
+TextContent::set_fade_out (ContentTime t)
+{
+ maybe_set (_fade_out, t, TextContentProperty::FADE_OUT);
+}
+
+void
+TextContent::unset_fade_out ()
+{
+ maybe_set (_fade_out, optional<ContentTime>(), TextContentProperty::FADE_OUT);
+}
+
+void
+TextContent::set_type (TextType type)
+{
+ maybe_set (_type, type, TextContentProperty::TYPE);
+}
+
+void
+TextContent::set_outline_width (int w)
+{
+ maybe_set (_outline_width, w, TextContentProperty::OUTLINE_WIDTH);
+}
+
+void
+TextContent::take_settings_from (shared_ptr<const TextContent> c)
+{
+ set_use (c->_use);
+ set_burn (c->_burn);
+ set_x_offset (c->_x_offset);
+ set_y_offset (c->_y_offset);
+ set_x_scale (c->_x_scale);
+ set_y_scale (c->_y_scale);
+ maybe_set (_fonts, c->_fonts, TextContentProperty::FONTS);
+ if (c->_colour) {
+ set_colour (*c->_colour);
+ } else {
+ unset_colour ();
+ }
+ if (c->_effect) {
+ set_effect (*c->_effect);
+ }
+ if (c->_effect_colour) {
+ set_effect_colour (*c->_effect_colour);
+ } else {
+ unset_effect_colour ();
+ }
+ set_line_spacing (c->_line_spacing);
+ if (c->_fade_in) {
+ set_fade_in (*c->_fade_in);
+ }
+ if (c->_fade_out) {
+ set_fade_out (*c->_fade_out);
+ }
+ set_outline_width (c->_outline_width);
+}
--- /dev/null
+/*
+ Copyright (C) 2013-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/>.
+
+*/
+
+#ifndef DCPOMATIC_CAPTION_CONTENT_H
+#define DCPOMATIC_CAPTION_CONTENT_H
+
+#include "content_part.h"
+#include <libcxml/cxml.h>
+#include <dcp/types.h>
+#include <boost/signals2.hpp>
+
+class Font;
+
+class TextContentProperty
+{
+public:
+ static int const X_OFFSET;
+ static int const Y_OFFSET;
+ static int const X_SCALE;
+ static int const Y_SCALE;
+ static int const USE;
+ static int const BURN;
+ static int const LANGUAGE;
+ static int const FONTS;
+ static int const COLOUR;
+ static int const EFFECT;
+ static int const EFFECT_COLOUR;
+ static int const LINE_SPACING;
+ static int const FADE_IN;
+ static int const FADE_OUT;
+ static int const OUTLINE_WIDTH;
+ static int const TYPE;
+};
+
+/** @class TextContent
+ * @brief Description of how some text content should be presented.
+ *
+ * There are `bitmap' subtitles and `plain' subtitles (plain text),
+ * and not all of the settings in this class correspond to both types.
+ */
+class TextContent : public ContentPart
+{
+public:
+ TextContent (Content* parent, TextType original_type);
+ TextContent (Content* parent, std::vector<boost::shared_ptr<Content> >);
+
+ void as_xml (xmlpp::Node *) const;
+ std::string identifier () const;
+ void take_settings_from (boost::shared_ptr<const TextContent> c);
+
+ void add_font (boost::shared_ptr<Font> font);
+
+ void set_use (bool);
+ void set_burn (bool);
+ void set_x_offset (double);
+ void set_y_offset (double);
+ void set_x_scale (double);
+ void set_y_scale (double);
+ void set_language (std::string language);
+ void set_colour (dcp::Colour);
+ void unset_colour ();
+ void set_effect (dcp::Effect);
+ void unset_effect ();
+ void set_effect_colour (dcp::Colour);
+ void unset_effect_colour ();
+ void set_line_spacing (double s);
+ void set_fade_in (ContentTime);
+ void unset_fade_in ();
+ void set_fade_out (ContentTime);
+ void set_outline_width (int);
+ void unset_fade_out ();
+ void set_type (TextType type);
+
+ bool use () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _use;
+ }
+
+ bool burn () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _burn;
+ }
+
+ double x_offset () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _x_offset;
+ }
+
+ double y_offset () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _y_offset;
+ }
+
+ double x_scale () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _x_scale;
+ }
+
+ double y_scale () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _y_scale;
+ }
+
+ std::list<boost::shared_ptr<Font> > fonts () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fonts;
+ }
+
+ std::string language () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _language;
+ }
+
+ boost::optional<dcp::Colour> colour () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _colour;
+ }
+
+ boost::optional<dcp::Effect> effect () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _effect;
+ }
+
+ boost::optional<dcp::Colour> effect_colour () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _effect_colour;
+ }
+
+ double line_spacing () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _line_spacing;
+ }
+
+ boost::optional<ContentTime> fade_in () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fade_in;
+ }
+
+ boost::optional<ContentTime> fade_out () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fade_out;
+ }
+
+ int outline_width () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _outline_width;
+ }
+
+ TextType type () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _type;
+ }
+
+ TextType original_type () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _original_type;
+ }
+
+ static std::list<boost::shared_ptr<TextContent> > from_xml (Content* parent, cxml::ConstNodePtr, int version);
+
+protected:
+ /** subtitle language (e.g. "German") or empty if it is not known */
+ std::string _language;
+
+private:
+ friend struct ffmpeg_pts_offset_test;
+
+ TextContent (Content* parent, cxml::ConstNodePtr, int version);
+ void font_changed ();
+ void connect_to_fonts ();
+
+ std::list<boost::signals2::connection> _font_connections;
+
+ bool _use;
+ bool _burn;
+ /** x offset for placing subtitles, as a proportion of the container width;
+ * +ve is further right, -ve is further left.
+ */
+ double _x_offset;
+ /** y offset for placing subtitles, as a proportion of the container height;
+ * +ve is further down the frame, -ve is further up.
+ */
+ double _y_offset;
+ /** x scale factor to apply to subtitles */
+ double _x_scale;
+ /** y scale factor to apply to subtitles */
+ double _y_scale;
+ std::list<boost::shared_ptr<Font> > _fonts;
+ boost::optional<dcp::Colour> _colour;
+ boost::optional<dcp::Effect> _effect;
+ boost::optional<dcp::Colour> _effect_colour;
+ /** scaling factor for line spacing; 1 is "standard", < 1 is closer together, > 1 is further apart */
+ double _line_spacing;
+ boost::optional<ContentTime> _fade_in;
+ boost::optional<ContentTime> _fade_out;
+ int _outline_width;
+ /** what these captions will be used for in the output DCP (not necessarily what
+ * they were originally).
+ */
+ TextType _type;
+ /** the original type of these captions in their content */
+ TextType _original_type;
+};
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2013-2017 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 "text_decoder.h"
+#include "text_content.h"
+#include "util.h"
+#include "log.h"
+#include "compose.hpp"
+#include <sub/subtitle.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+#include <iostream>
+
+using std::list;
+using std::cout;
+using std::string;
+using std::min;
+using boost::shared_ptr;
+using boost::optional;
+using boost::function;
+
+TextDecoder::TextDecoder (
+ Decoder* parent,
+ shared_ptr<const TextContent> c,
+ shared_ptr<Log> log,
+ ContentTime first
+ )
+ : DecoderPart (parent, log)
+ , _content (c)
+ , _position (first)
+{
+
+}
+
+/** Called by subclasses when an image subtitle is starting.
+ * @param from From time of the subtitle.
+ * @param image Subtitle image.
+ * @param rect Area expressed as a fraction of the video frame that this subtitle
+ * is for (e.g. a width of 0.5 means the width of the subtitle is half the width
+ * of the video frame)
+ */
+void
+TextDecoder::emit_bitmap_start (ContentTime from, shared_ptr<Image> image, dcpomatic::Rect<double> rect)
+{
+ BitmapStart (ContentBitmapText (from, _content->type(), image, rect));
+ _position = from;
+}
+
+void
+TextDecoder::emit_plain_start (ContentTime from, list<dcp::SubtitleString> s)
+{
+ BOOST_FOREACH (dcp::SubtitleString& i, s) {
+ /* We must escape < and > in strings, otherwise they might confuse our subtitle
+ renderer (which uses some HTML-esque markup to do bold/italic etc.)
+ */
+ string t = i.text ();
+ boost::algorithm::replace_all (t, "<", "<");
+ boost::algorithm::replace_all (t, ">", ">");
+ i.set_text (t);
+
+ /* Set any forced appearance */
+ if (content()->colour()) {
+ i.set_colour (*content()->colour());
+ }
+ if (content()->effect_colour()) {
+ i.set_effect_colour (*content()->effect_colour());
+ }
+ if (content()->effect()) {
+ i.set_effect (*content()->effect());
+ }
+ if (content()->fade_in()) {
+ i.set_fade_up_time (dcp::Time(content()->fade_in()->seconds(), 1000));
+ }
+ if (content()->fade_out()) {
+ i.set_fade_down_time (dcp::Time(content()->fade_out()->seconds(), 1000));
+ }
+ }
+
+ PlainStart (ContentStringText (from, _content->type(), s));
+ _position = from;
+}
+
+void
+TextDecoder::emit_plain_start (ContentTime from, sub::Subtitle const & subtitle)
+{
+ /* See if our next subtitle needs to be vertically placed on screen by us */
+ bool needs_placement = false;
+ optional<int> bottom_line;
+ BOOST_FOREACH (sub::Line i, subtitle.lines) {
+ if (!i.vertical_position.reference || i.vertical_position.reference.get() == sub::TOP_OF_SUBTITLE) {
+ needs_placement = true;
+ DCPOMATIC_ASSERT (i.vertical_position.line);
+ if (!bottom_line || bottom_line.get() < i.vertical_position.line.get()) {
+ bottom_line = i.vertical_position.line.get();
+ }
+ }
+ }
+
+ /* Find the lowest proportional position */
+ optional<float> lowest_proportional;
+ BOOST_FOREACH (sub::Line i, subtitle.lines) {
+ if (i.vertical_position.proportional) {
+ if (!lowest_proportional) {
+ lowest_proportional = i.vertical_position.proportional;
+ } else {
+ lowest_proportional = min (lowest_proportional.get(), i.vertical_position.proportional.get());
+ }
+ }
+ }
+
+ list<dcp::SubtitleString> out;
+ BOOST_FOREACH (sub::Line i, subtitle.lines) {
+ BOOST_FOREACH (sub::Block j, i.blocks) {
+
+ if (!j.font_size.specified()) {
+ /* Fallback default font size if no other has been specified */
+ j.font_size.set_points (48);
+ }
+
+ float v_position;
+ dcp::VAlign v_align;
+ if (needs_placement) {
+ DCPOMATIC_ASSERT (i.vertical_position.line);
+ /* This 1.015 is an arbitrary value to lift the bottom sub off the bottom
+ of the screen a bit to a pleasing degree.
+ */
+ v_position = 1.015 -
+ (1 + bottom_line.get() - i.vertical_position.line.get())
+ * 1.2 * content()->line_spacing() * content()->y_scale() * j.font_size.proportional (72 * 11);
+
+ v_align = dcp::VALIGN_TOP;
+ } else {
+ DCPOMATIC_ASSERT (i.vertical_position.proportional);
+ DCPOMATIC_ASSERT (i.vertical_position.reference);
+ v_position = i.vertical_position.proportional.get();
+
+ if (lowest_proportional) {
+ /* Adjust line spacing */
+ v_position = ((v_position - lowest_proportional.get()) * content()->line_spacing()) + lowest_proportional.get();
+ }
+
+ switch (i.vertical_position.reference.get()) {
+ case sub::TOP_OF_SCREEN:
+ v_align = dcp::VALIGN_TOP;
+ break;
+ case sub::VERTICAL_CENTRE_OF_SCREEN:
+ v_align = dcp::VALIGN_CENTER;
+ break;
+ case sub::BOTTOM_OF_SCREEN:
+ v_align = dcp::VALIGN_BOTTOM;
+ break;
+ default:
+ v_align = dcp::VALIGN_TOP;
+ break;
+ }
+ }
+
+ dcp::HAlign h_align;
+ switch (i.horizontal_position.reference) {
+ case sub::LEFT_OF_SCREEN:
+ h_align = dcp::HALIGN_LEFT;
+ break;
+ case sub::HORIZONTAL_CENTRE_OF_SCREEN:
+ h_align = dcp::HALIGN_CENTER;
+ break;
+ case sub::RIGHT_OF_SCREEN:
+ h_align = dcp::HALIGN_RIGHT;
+ break;
+ default:
+ h_align = dcp::HALIGN_CENTER;
+ break;
+ }
+
+ /* The idea here (rightly or wrongly) is that we set the appearance based on the
+ values in the libsub objects, and these are overridden with values from the
+ content by the other emit_plain_start() above.
+ */
+
+ out.push_back (
+ dcp::SubtitleString (
+ string(TEXT_FONT_ID),
+ j.italic,
+ j.bold,
+ j.underline,
+ j.colour.dcp(),
+ j.font_size.points (72 * 11),
+ 1.0,
+ dcp::Time (from.seconds(), 1000),
+ /* XXX: hmm; this is a bit ugly (we don't know the to time yet) */
+ dcp::Time (),
+ i.horizontal_position.proportional,
+ h_align,
+ v_position,
+ v_align,
+ dcp::DIRECTION_LTR,
+ j.text,
+ dcp::NONE,
+ j.effect_colour.get_value_or(sub::Colour(0, 0, 0)).dcp(),
+ /* Hack: we should use subtitle.fade_up and subtitle.fade_down here
+ but the times of these often don't have a frame rate associated
+ with them so the sub::Time won't convert them to milliseconds without
+ throwing an exception. Since only DCP subs fill those in (and we don't
+ use libsub for DCP subs) we can cheat by just putting 0 in here.
+ */
+ dcp::Time (),
+ dcp::Time ()
+ )
+ );
+ }
+ }
+
+ emit_plain_start (from, out);
+}
+
+void
+TextDecoder::emit_stop (ContentTime to)
+{
+ Stop (to, _content->type());
+}
+
+void
+TextDecoder::emit_plain (ContentTimePeriod period, list<dcp::SubtitleString> s)
+{
+ emit_plain_start (period.from, s);
+ emit_stop (period.to);
+}
+
+void
+TextDecoder::emit_plain (ContentTimePeriod period, sub::Subtitle const & s)
+{
+ emit_plain_start (period.from, s);
+ emit_stop (period.to);
+}
+
+void
+TextDecoder::seek ()
+{
+ _position = ContentTime ();
+}
--- /dev/null
+/*
+ Copyright (C) 2013-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/>.
+
+*/
+
+#ifndef DCPOMATIC_CAPTION_DECODER_H
+#define DCPOMATIC_CAPTION_DECODER_H
+
+#include "decoder.h"
+#include "rect.h"
+#include "types.h"
+#include "content_text.h"
+#include "decoder_part.h"
+#include <dcp/subtitle_string.h>
+#include <boost/signals2.hpp>
+
+namespace sub {
+ class Subtitle;
+}
+
+class Image;
+
+class TextDecoder : public DecoderPart
+{
+public:
+ TextDecoder (
+ Decoder* parent,
+ boost::shared_ptr<const TextContent>,
+ boost::shared_ptr<Log> log,
+ ContentTime first
+ );
+
+ ContentTime position () const {
+ return _position;
+ }
+
+ void emit_bitmap_start (ContentTime from, boost::shared_ptr<Image> image, dcpomatic::Rect<double> rect);
+ void emit_plain_start (ContentTime from, std::list<dcp::SubtitleString> s);
+ void emit_plain_start (ContentTime from, sub::Subtitle const & subtitle);
+ void emit_plain (ContentTimePeriod period, std::list<dcp::SubtitleString> s);
+ void emit_plain (ContentTimePeriod period, sub::Subtitle const & subtitle);
+ void emit_stop (ContentTime to);
+
+ void seek ();
+
+ boost::shared_ptr<const TextContent> content () const {
+ return _content;
+ }
+
+ boost::signals2::signal<void (ContentBitmapText)> BitmapStart;
+ boost::signals2::signal<void (ContentStringText)> PlainStart;
+ boost::signals2::signal<void (ContentTime, TextType)> Stop;
+
+private:
+ boost::shared_ptr<const TextContent> _content;
+ ContentTime _position;
+};
+
+#endif
node->add_child("BottomCrop")->add_child_text (raw_convert<string> (bottom));
}
-CaptionType
+TextType
string_to_caption_type (string s)
{
if (s == "open") {
}
string
-caption_type_to_string (CaptionType t)
+caption_type_to_string (TextType t)
{
switch (t) {
case CAPTION_OPEN:
}
string
-caption_type_to_name (CaptionType t)
+caption_type_to_name (TextType t)
{
switch (t) {
case CAPTION_OPEN:
class Content;
class VideoContent;
class AudioContent;
-class CaptionContent;
+class TextContent;
class FFmpegContent;
namespace cxml {
* There is also still use of the word `subtitle' in the code; these are the
* same as open captions in DoM.
*/
-enum CaptionType
+enum TextType
{
CAPTION_OPEN,
CAPTION_CLOSED,
CAPTION_COUNT
};
-extern std::string caption_type_to_string (CaptionType t);
-extern std::string caption_type_to_name (CaptionType t);
-extern CaptionType string_to_caption_type (std::string s);
+extern std::string caption_type_to_string (TextType t);
+extern std::string caption_type_to_name (TextType t);
+extern TextType string_to_caption_type (std::string s);
/** @struct Crop
* @brief A description of the crop of an image or video.
}
void
-Writer::write (PlayerCaption text, CaptionType type, DCPTimePeriod period)
+Writer::write (PlayerText text, TextType type, DCPTimePeriod period)
{
while (_caption_reel[type]->period().to <= period.from) {
++_caption_reel[type];
*/
#include "types.h"
-#include "player_caption.h"
+#include "player_text.h"
#include "exception_store.h"
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
bool can_repeat (Frame) const;
void repeat (Frame, Eyes);
void write (boost::shared_ptr<const AudioBuffers>, DCPTime time);
- void write (PlayerCaption text, CaptionType type, DCPTimePeriod period);
+ void write (PlayerText text, TextType type, DCPTimePeriod period);
void write (std::list<boost::shared_ptr<Font> > fonts);
void write (ReferencedReelAsset asset);
void finish ();
import i18n
sources = """
- active_captions.cc
+ active_text.cc
analyse_audio_job.cc
atmos_mxf_content.cc
audio_analysis.cc
audio_ring_buffers.cc
audio_stream.cc
butler.cc
- caption_content.cc
- caption_decoder.cc
+ text_content.cc
+ text_decoder.cc
case_insensitive_sorter.cc
cinema.cc
cinema_kdms.cc
mid_side_decoder.cc
overlaps.cc
player.cc
- player_caption.cc
+ player_text.cc
player_video.cc
playlist.cc
position_image.cc
server.cc
shuffler.cc
string_log_entry.cc
- text_caption_file.cc
- text_caption_file_content.cc
- text_caption_file_decoder.cc
+ string_text_file.cc
+ string_text_file_content.cc
+ string_text_file_decoder.cc
timer.cc
transcode_job.cc
types.cc
#include "lib/transcode_job.h"
#include "lib/dkdm_wrapper.h"
#include "lib/audio_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include <dcp/exceptions.h>
#include <dcp/raw_convert.h>
#include <wx/generic/aboutdlgg.h>
}
if (d->caption()) {
- list<shared_ptr<CaptionContent> >::iterator j = i->caption.begin ();
- list<shared_ptr<CaptionContent> >::const_iterator k = _clipboard->caption.begin ();
+ list<shared_ptr<TextContent> >::iterator j = i->caption.begin ();
+ list<shared_ptr<TextContent> >::const_iterator k = _clipboard->caption.begin ();
while (j != i->caption.end() && k != _clipboard->caption.end()) {
(*j)->take_settings_from (*k);
++j;
#include "lib/job_manager.h"
#include "lib/job.h"
#include "lib/video_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/ratio.h"
#include "lib/verify_dcp_job.h"
#include "lib/dcp_examiner.h"
void setup_from_dcp (shared_ptr<DCPContent> dcp)
{
- BOOST_FOREACH (shared_ptr<CaptionContent> i, dcp->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> i, dcp->caption) {
i->set_use (true);
}
+++ /dev/null
-/*
- Copyright (C) 2015-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 "caption_appearance_dialog.h"
-#include "rgba_colour_picker.h"
-#include "lib/text_caption_file_content.h"
-#include "lib/caption_content.h"
-#include "lib/ffmpeg_subtitle_stream.h"
-#include "lib/ffmpeg_content.h"
-#include <wx/wx.h>
-#include <wx/clrpicker.h>
-#include <wx/spinctrl.h>
-#include <wx/gbsizer.h>
-
-using std::map;
-using boost::shared_ptr;
-using boost::bind;
-using boost::dynamic_pointer_cast;
-using boost::optional;
-
-int const CaptionAppearanceDialog::NONE = 0;
-int const CaptionAppearanceDialog::OUTLINE = 1;
-int const CaptionAppearanceDialog::SHADOW = 2;
-
-CaptionAppearanceDialog::CaptionAppearanceDialog (wxWindow* parent, shared_ptr<Content> content, shared_ptr<CaptionContent> caption)
- : wxDialog (parent, wxID_ANY, _("Caption appearance"))
- , _content (content)
- , _caption (caption)
-{
- shared_ptr<FFmpegContent> ff = dynamic_pointer_cast<FFmpegContent> (content);
- if (ff) {
- _stream = ff->subtitle_stream ();
- }
-
- wxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
- SetSizer (overall_sizer);
-
- _table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
-
- overall_sizer->Add (_table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
-
- int r = 0;
-
- add_label_to_sizer (_table, this, _("Colour"), true, wxGBPosition (r, 0));
- _force_colour = set_to (_colour = new wxColourPickerCtrl (this, wxID_ANY), r);
-
- add_label_to_sizer (_table, this, _("Effect"), true, wxGBPosition (r, 0));
- _force_effect = set_to (_effect = new wxChoice (this, wxID_ANY), r);
-
- add_label_to_sizer (_table, this, _("Effect colour"), true, wxGBPosition (r, 0));
- _force_effect_colour = set_to (_effect_colour = new wxColourPickerCtrl (this, wxID_ANY), r);
-
- add_label_to_sizer (_table, this, _("Outline width"), true, wxGBPosition (r, 0));
- _outline_width = new wxSpinCtrl (this, wxID_ANY);
- _table->Add (_outline_width, wxGBPosition (r, 1));
- ++r;
-
- add_label_to_sizer (_table, this, _("Fade in time"), true, wxGBPosition (r, 0));
- _force_fade_in = set_to (_fade_in = new Timecode<ContentTime> (this), r);
-
- add_label_to_sizer (_table, this, _("Fade out time"), true, wxGBPosition (r, 0));
- _force_fade_out = set_to (_fade_out = new Timecode<ContentTime> (this), r);
-
- if (_stream) {
- wxScrolled<wxPanel>* colours_panel = new wxScrolled<wxPanel> (this);
- colours_panel->EnableScrolling (false, true);
- colours_panel->ShowScrollbars (wxSHOW_SB_NEVER, wxSHOW_SB_ALWAYS);
- colours_panel->SetScrollRate (0, 16);
-
- wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
- table->AddGrowableCol (1, 1);
-
- map<RGBA, RGBA> colours = _stream->colours ();
-
- wxStaticText* t = new wxStaticText (colours_panel, wxID_ANY, "");
- t->SetLabelMarkup (_("<b>Original colour</b>"));
- table->Add (t, 1, wxEXPAND);
- t = new wxStaticText (colours_panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
- t->SetLabelMarkup (_("<b>New colour</b>"));
- table->Add (t, 1, wxALIGN_CENTER);
-
- for (map<RGBA, RGBA>::const_iterator i = colours.begin(); i != colours.end(); ++i) {
- wxPanel* from = new wxPanel (colours_panel, wxID_ANY);
- from->SetBackgroundColour (wxColour (i->first.r, i->first.g, i->first.b, i->first.a));
- table->Add (from, 1, wxEXPAND);
- RGBAColourPicker* to = new RGBAColourPicker (colours_panel, i->second);
- table->Add (to, 1, wxEXPAND);
- _pickers[i->first] = to;
- }
-
- colours_panel->SetSizer (table);
-
- overall_sizer->Add (colours_panel, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
-
- wxButton* restore = new wxButton (this, wxID_ANY, _("Restore to original colours"));
- restore->Bind (wxEVT_BUTTON, bind (&CaptionAppearanceDialog::restore, this));
- overall_sizer->Add (restore, 0, wxALL, DCPOMATIC_SIZER_X_GAP);
- }
-
- wxSizer* buttons = CreateSeparatedButtonSizer (wxOK);
- if (buttons) {
- overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
- }
-
- overall_sizer->Layout ();
- overall_sizer->SetSizeHints (this);
-
- /* Keep these Appends() up to date with NONE/OUTLINE/SHADOW variables */
- _effect->Append (_("None"));
- _effect->Append (_("Outline"));
- _effect->Append (_("Shadow"));;
-
- optional<dcp::Colour> colour = _caption->colour();
- _force_colour->SetValue (static_cast<bool>(colour));
- if (colour) {
- _colour->SetColour (wxColour (colour->r, colour->g, colour->b));
- } else {
- _colour->SetColour (wxColour (255, 255, 255));
- }
-
- optional<dcp::Effect> effect = _caption->effect();
- _force_effect->SetValue (static_cast<bool>(effect));
- if (effect) {
- switch (*effect) {
- case dcp::NONE:
- _effect->SetSelection (NONE);
- break;
- case dcp::BORDER:
- _effect->SetSelection (OUTLINE);
- break;
- case dcp::SHADOW:
- _effect->SetSelection (SHADOW);
- break;
- }
- } else {
- _effect->SetSelection (NONE);
- }
-
- optional<dcp::Colour> effect_colour = _caption->effect_colour();
- _force_effect_colour->SetValue (static_cast<bool>(effect_colour));
- if (effect_colour) {
- _effect_colour->SetColour (wxColour (effect_colour->r, effect_colour->g, effect_colour->b));
- } else {
- _effect_colour->SetColour (wxColour (0, 0, 0));
- }
-
- optional<ContentTime> fade_in = _caption->fade_in();
- _force_fade_in->SetValue (static_cast<bool>(fade_in));
- if (fade_in) {
- _fade_in->set (*fade_in, _content->active_video_frame_rate());
- } else {
- _fade_in->set (ContentTime(), _content->active_video_frame_rate());
- }
-
- optional<ContentTime> fade_out = _caption->fade_out();
- _force_fade_out->SetValue (static_cast<bool>(fade_out));
- if (fade_out) {
- _fade_out->set (*fade_out, _content->active_video_frame_rate ());
- } else {
- _fade_out->set (ContentTime(), _content->active_video_frame_rate ());
- }
-
- _outline_width->SetValue (_caption->outline_width ());
-
- _force_colour->Bind (wxEVT_CHECKBOX, bind (&CaptionAppearanceDialog::setup_sensitivity, this));
- _force_effect_colour->Bind (wxEVT_CHECKBOX, bind (&CaptionAppearanceDialog::setup_sensitivity, this));
- _force_effect->Bind (wxEVT_CHECKBOX, bind (&CaptionAppearanceDialog::setup_sensitivity, this));
- _force_fade_in->Bind (wxEVT_CHECKBOX, bind (&CaptionAppearanceDialog::setup_sensitivity, this));
- _force_fade_out->Bind (wxEVT_CHECKBOX, bind (&CaptionAppearanceDialog::setup_sensitivity, this));
- _effect->Bind (wxEVT_CHOICE, bind (&CaptionAppearanceDialog::setup_sensitivity, this));
- _content_connection = _content->Changed.connect (bind (&CaptionAppearanceDialog::setup_sensitivity, this));
-
- setup_sensitivity ();
-}
-
-wxCheckBox*
-CaptionAppearanceDialog::set_to (wxWindow* w, int& r)
-{
- wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- wxCheckBox* set_to = new wxCheckBox (this, wxID_ANY, _("Set to"));
- s->Add (set_to, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 8);
- s->Add (w, 0, wxALIGN_CENTER_VERTICAL);
- _table->Add (s, wxGBPosition (r, 1));
- ++r;
- return set_to;
-}
-
-void
-CaptionAppearanceDialog::apply ()
-{
- if (_force_colour->GetValue ()) {
- wxColour const c = _colour->GetColour ();
- _caption->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue()));
- } else {
- _caption->unset_colour ();
- }
- if (_force_effect->GetValue()) {
- switch (_effect->GetSelection()) {
- case NONE:
- _caption->set_effect (dcp::NONE);
- break;
- case OUTLINE:
- _caption->set_effect (dcp::BORDER);
- break;
- case SHADOW:
- _caption->set_effect (dcp::SHADOW);
- break;
- }
- } else {
- _caption->unset_effect ();
- }
- if (_force_effect_colour->GetValue ()) {
- wxColour const ec = _effect_colour->GetColour ();
- _caption->set_effect_colour (dcp::Colour (ec.Red(), ec.Green(), ec.Blue()));
- } else {
- _caption->unset_effect_colour ();
- }
- if (_force_fade_in->GetValue ()) {
- _caption->set_fade_in (_fade_in->get (_content->active_video_frame_rate ()));
- } else {
- _caption->unset_fade_in ();
- }
- if (_force_fade_out->GetValue ()) {
- _caption->set_fade_out (_fade_out->get (_content->active_video_frame_rate ()));
- } else {
- _caption->unset_fade_out ();
- }
- _caption->set_outline_width (_outline_width->GetValue ());
-
- if (_stream) {
- for (map<RGBA, RGBAColourPicker*>::const_iterator i = _pickers.begin(); i != _pickers.end(); ++i) {
- _stream->set_colour (i->first, i->second->colour ());
- }
- }
-
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (_content);
- if (fc) {
- fc->signal_subtitle_stream_changed ();
- }
-}
-
-void
-CaptionAppearanceDialog::restore ()
-{
- for (map<RGBA, RGBAColourPicker*>::const_iterator i = _pickers.begin(); i != _pickers.end(); ++i) {
- i->second->set (i->first);
- }
-}
-
-void
-CaptionAppearanceDialog::setup_sensitivity ()
-{
- _colour->Enable (_force_colour->GetValue ());
- _effect_colour->Enable (_force_effect_colour->GetValue ());
- _effect->Enable (_force_effect->GetValue ());
- _fade_in->Enable (_force_fade_in->GetValue ());
- _fade_out->Enable (_force_fade_out->GetValue ());
-
- bool const can_outline_width = _effect->GetSelection() == OUTLINE && _caption->burn ();
- _outline_width->Enable (can_outline_width);
- if (can_outline_width) {
- _outline_width->UnsetToolTip ();
- } else {
- _outline_width->SetToolTip (_("Outline width cannot be set unless you are burning in captions"));
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2015-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 "timecode.h"
-#include "lib/rgba.h"
-#include <wx/wx.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/signals2.hpp>
-
-class wxRadioButton;
-class wxColourPickerCtrl;
-class wxGridBagSizer;
-class Content;
-class RGBAColourPicker;
-class FFmpegSubtitleStream;
-class wxCheckBox;
-class wxWidget;
-
-class CaptionAppearanceDialog : public wxDialog
-{
-public:
- CaptionAppearanceDialog (wxWindow* parent, boost::shared_ptr<Content> content, boost::shared_ptr<CaptionContent> caption);
-
- void apply ();
-
-private:
- void setup_sensitivity ();
- void restore ();
- wxCheckBox* set_to (wxWindow* w, int& r);
-
- wxCheckBox* _force_colour;
- wxColourPickerCtrl* _colour;
- wxCheckBox* _force_effect;
- wxChoice* _effect;
- wxCheckBox* _force_effect_colour;
- wxColourPickerCtrl* _effect_colour;
- wxCheckBox* _force_fade_in;
- Timecode<ContentTime>* _fade_in;
- wxCheckBox* _force_fade_out;
- Timecode<ContentTime>* _fade_out;
- wxSpinCtrl* _outline_width;
- wxGridBagSizer* _table;
- std::map<RGBA, RGBAColourPicker*> _pickers;
-
- boost::shared_ptr<Content> _content;
- boost::shared_ptr<CaptionContent> _caption;
- boost::shared_ptr<FFmpegSubtitleStream> _stream;
-
- boost::signals2::scoped_connection _content_connection;
-
- static int const NONE;
- static int const OUTLINE;
- static int const SHADOW;
-};
+++ /dev/null
-/*
- Copyright (C) 2012-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 "caption_panel.h"
-#include "film_editor.h"
-#include "wx_util.h"
-#include "caption_view.h"
-#include "content_panel.h"
-#include "fonts_dialog.h"
-#include "caption_appearance_dialog.h"
-#include "lib/ffmpeg_content.h"
-#include "lib/text_caption_file_content.h"
-#include "lib/ffmpeg_subtitle_stream.h"
-#include "lib/dcp_subtitle_content.h"
-#include "lib/text_caption_file_decoder.h"
-#include "lib/dcp_subtitle_decoder.h"
-#include "lib/dcp_content.h"
-#include "lib/caption_content.h"
-#include "lib/decoder_factory.h"
-#include <wx/spinctrl.h>
-#include <boost/foreach.hpp>
-
-using std::vector;
-using std::string;
-using std::list;
-using std::cout;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-
-CaptionPanel::CaptionPanel (ContentPanel* p, CaptionType t)
- : ContentSubPanel (p, std_to_wx(caption_type_to_name(t)))
- , _caption_view (0)
- , _fonts_dialog (0)
- , _original_type (t)
-{
- wxBoxSizer* reference_sizer = new wxBoxSizer (wxVERTICAL);
-
- _reference = new wxCheckBox (this, wxID_ANY, _("Use this DCP's subtitle as OV and make VF"));
- reference_sizer->Add (_reference, 0, wxLEFT | wxRIGHT | wxTOP, DCPOMATIC_SIZER_GAP);
-
- _reference_note = new wxStaticText (this, wxID_ANY, _(""));
- _reference_note->Wrap (200);
- reference_sizer->Add (_reference_note, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP);
- wxFont font = _reference_note->GetFont();
- font.SetStyle(wxFONTSTYLE_ITALIC);
- font.SetPointSize(font.GetPointSize() - 1);
- _reference_note->SetFont(font);
-
- _sizer->Add (reference_sizer);
-
- wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
- _sizer->Add (grid, 0, wxALL, 8);
- int r = 0;
-
- wxBoxSizer* use = new wxBoxSizer (wxHORIZONTAL);
- _use = new wxCheckBox (this, wxID_ANY, _("Use as"));
- use->Add (_use, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
- _type = new wxChoice (this, wxID_ANY);
- _type->Append (_("subtitles (open captions)"));
- _type->Append (_("closed captions"));
- use->Add (_type, 1, wxEXPAND, 0);
- grid->Add (use, wxGBPosition (r, 0), wxGBSpan (1, 2));
- ++r;
-
- _burn = new wxCheckBox (this, wxID_ANY, _("Burn subtitles into image"));
- grid->Add (_burn, wxGBPosition (r, 0), wxGBSpan (1, 2));
- ++r;
-
- {
- add_label_to_sizer (grid, this, _("X Offset"), true, wxGBPosition (r, 0));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _x_offset = new wxSpinCtrl (this);
- s->Add (_x_offset);
- add_label_to_sizer (s, this, _("%"), false);
- grid->Add (s, wxGBPosition (r, 1));
- ++r;
- }
-
- {
- add_label_to_sizer (grid, this, _("Y Offset"), true, wxGBPosition (r, 0));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _y_offset = new wxSpinCtrl (this);
- s->Add (_y_offset);
- add_label_to_sizer (s, this, _("%"), false);
- grid->Add (s, wxGBPosition (r, 1));
- ++r;
- }
-
- {
- add_label_to_sizer (grid, this, _("X Scale"), true, wxGBPosition (r, 0));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _x_scale = new wxSpinCtrl (this);
- s->Add (_x_scale);
- add_label_to_sizer (s, this, _("%"), false);
- grid->Add (s, wxGBPosition (r, 1));
- ++r;
- }
-
- {
- add_label_to_sizer (grid, this, _("Y Scale"), true, wxGBPosition (r, 0));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _y_scale = new wxSpinCtrl (this);
- s->Add (_y_scale);
- add_label_to_sizer (s, this, _("%"), false);
- grid->Add (s, wxGBPosition (r, 1));
- ++r;
- }
-
- {
- add_label_to_sizer (grid, this, _("Line spacing"), true, wxGBPosition (r, 0));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _line_spacing = new wxSpinCtrl (this);
- s->Add (_line_spacing);
- add_label_to_sizer (s, this, _("%"), false);
- grid->Add (s, wxGBPosition (r, 1));
- ++r;
- }
-
- add_label_to_sizer (grid, this, _("Language"), true, wxGBPosition (r, 0));
- _language = new wxTextCtrl (this, wxID_ANY);
- grid->Add (_language, wxGBPosition (r, 1));
- ++r;
-
- add_label_to_sizer (grid, this, _("Stream"), true, wxGBPosition (r, 0));
- _stream = new wxChoice (this, wxID_ANY);
- grid->Add (_stream, wxGBPosition (r, 1));
- ++r;
-
- {
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-
- _caption_view_button = new wxButton (this, wxID_ANY, _("View..."));
- s->Add (_caption_view_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
- _fonts_dialog_button = new wxButton (this, wxID_ANY, _("Fonts..."));
- s->Add (_fonts_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
- _appearance_dialog_button = new wxButton (this, wxID_ANY, _("Appearance..."));
- s->Add (_appearance_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
-
- grid->Add (s, wxGBPosition (r, 0), wxGBSpan (1, 2));
- ++r;
- }
-
- _x_offset->SetRange (-100, 100);
- _y_offset->SetRange (-100, 100);
- _x_scale->SetRange (10, 1000);
- _y_scale->SetRange (10, 1000);
- _line_spacing->SetRange (10, 1000);
-
- _reference->Bind (wxEVT_CHECKBOX, boost::bind (&CaptionPanel::reference_clicked, this));
- _use->Bind (wxEVT_CHECKBOX, boost::bind (&CaptionPanel::use_toggled, this));
- _type->Bind (wxEVT_CHOICE, boost::bind (&CaptionPanel::type_changed, this));
- _burn->Bind (wxEVT_CHECKBOX, boost::bind (&CaptionPanel::burn_toggled, this));
- _x_offset->Bind (wxEVT_SPINCTRL, boost::bind (&CaptionPanel::x_offset_changed, this));
- _y_offset->Bind (wxEVT_SPINCTRL, boost::bind (&CaptionPanel::y_offset_changed, this));
- _x_scale->Bind (wxEVT_SPINCTRL, boost::bind (&CaptionPanel::x_scale_changed, this));
- _y_scale->Bind (wxEVT_SPINCTRL, boost::bind (&CaptionPanel::y_scale_changed, this));
- _line_spacing->Bind (wxEVT_SPINCTRL, boost::bind (&CaptionPanel::line_spacing_changed, this));
- _language->Bind (wxEVT_TEXT, boost::bind (&CaptionPanel::language_changed, this));
- _stream->Bind (wxEVT_CHOICE, boost::bind (&CaptionPanel::stream_changed, this));
- _caption_view_button->Bind (wxEVT_BUTTON, boost::bind (&CaptionPanel::caption_view_clicked, this));
- _fonts_dialog_button->Bind (wxEVT_BUTTON, boost::bind (&CaptionPanel::fonts_dialog_clicked, this));
- _appearance_dialog_button->Bind (wxEVT_BUTTON, boost::bind (&CaptionPanel::appearance_dialog_clicked, this));
-}
-
-void
-CaptionPanel::film_changed (Film::Property property)
-{
- if (property == Film::CONTENT || property == Film::REEL_TYPE) {
- setup_sensitivity ();
- }
-}
-
-void
-CaptionPanel::film_content_changed (int property)
-{
- FFmpegContentList fc = _parent->selected_ffmpeg ();
- ContentList sc = _parent->selected_caption ();
-
- shared_ptr<FFmpegContent> fcs;
- if (fc.size() == 1) {
- fcs = fc.front ();
- }
-
- shared_ptr<Content> scs;
- if (sc.size() == 1) {
- scs = sc.front ();
- }
-
- shared_ptr<CaptionContent> caption;
- if (scs) {
- caption = scs->caption_of_original_type(_original_type);
- }
-
- if (property == FFmpegContentProperty::SUBTITLE_STREAMS) {
- _stream->Clear ();
- if (fcs) {
- vector<shared_ptr<FFmpegSubtitleStream> > s = fcs->subtitle_streams ();
- for (vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = s.begin(); i != s.end(); ++i) {
- _stream->Append (std_to_wx ((*i)->name), new wxStringClientData (std_to_wx ((*i)->identifier ())));
- }
-
- if (fcs->subtitle_stream()) {
- checked_set (_stream, fcs->subtitle_stream()->identifier ());
- } else {
- _stream->SetSelection (wxNOT_FOUND);
- }
- }
- setup_sensitivity ();
- } else if (property == CaptionContentProperty::USE) {
- checked_set (_use, caption ? caption->use() : false);
- setup_sensitivity ();
- } else if (property == CaptionContentProperty::TYPE) {
- if (caption) {
- switch (caption->type()) {
- case CAPTION_OPEN:
- _type->SetSelection (0);
- break;
- case CAPTION_CLOSED:
- _type->SetSelection (1);
- break;
- default:
- DCPOMATIC_ASSERT (false);
- }
- } else {
- _type->SetSelection (0);
- }
- setup_sensitivity ();
- } else if (property == CaptionContentProperty::BURN) {
- checked_set (_burn, caption ? caption->burn() : false);
- } else if (property == CaptionContentProperty::X_OFFSET) {
- checked_set (_x_offset, caption ? lrint (caption->x_offset() * 100) : 0);
- } else if (property == CaptionContentProperty::Y_OFFSET) {
- checked_set (_y_offset, caption ? lrint (caption->y_offset() * 100) : 0);
- } else if (property == CaptionContentProperty::X_SCALE) {
- checked_set (_x_scale, caption ? lrint (caption->x_scale() * 100) : 100);
- } else if (property == CaptionContentProperty::Y_SCALE) {
- checked_set (_y_scale, caption ? lrint (caption->y_scale() * 100) : 100);
- } else if (property == CaptionContentProperty::LINE_SPACING) {
- checked_set (_line_spacing, caption ? lrint (caption->line_spacing() * 100) : 100);
- } else if (property == CaptionContentProperty::LANGUAGE) {
- checked_set (_language, caption ? caption->language() : "");
- } else if (property == DCPContentProperty::REFERENCE_CAPTION) {
- if (scs) {
- shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent> (scs);
- checked_set (_reference, dcp ? dcp->reference_caption(_original_type) : false);
- } else {
- checked_set (_reference, false);
- }
-
- setup_sensitivity ();
- } else if (property == DCPContentProperty::CAPTIONS) {
- setup_sensitivity ();
- }
-}
-
-void
-CaptionPanel::use_toggled ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption()) {
- i->caption_of_original_type(_original_type)->set_use (_use->GetValue());
- }
-}
-
-void
-CaptionPanel::type_changed ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption()) {
- switch (_type->GetSelection()) {
- case 0:
- i->caption_of_original_type(_original_type)->set_type (CAPTION_OPEN);
- break;
- case 1:
- i->caption_of_original_type(_original_type)->set_type (CAPTION_CLOSED);
- break;
- }
- }
-}
-
-void
-CaptionPanel::burn_toggled ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
- i->caption_of_original_type(_original_type)->set_burn (_burn->GetValue());
- }
-}
-
-void
-CaptionPanel::setup_sensitivity ()
-{
- int any_subs = 0;
- int ffmpeg_subs = 0;
- ContentList sel = _parent->selected_caption ();
- BOOST_FOREACH (shared_ptr<Content> i, sel) {
- /* These are the content types that could include subtitles */
- shared_ptr<const FFmpegContent> fc = boost::dynamic_pointer_cast<const FFmpegContent> (i);
- shared_ptr<const TextCaptionFileContent> sc = boost::dynamic_pointer_cast<const TextCaptionFileContent> (i);
- shared_ptr<const DCPContent> dc = boost::dynamic_pointer_cast<const DCPContent> (i);
- shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (i);
- if (fc) {
- if (!fc->caption.empty()) {
- ++ffmpeg_subs;
- ++any_subs;
- }
- } else if (sc || dc || dsc) {
- /* XXX: in the future there could be bitmap subs from DCPs */
- ++any_subs;
- }
- }
-
- /* Decide whether we can reference these subs */
-
- shared_ptr<DCPContent> dcp;
- if (sel.size() == 1) {
- dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
- }
-
- string why_not;
- bool const can_reference = dcp && dcp->can_reference_caption (_original_type, why_not);
- setup_refer_button (_reference, _reference_note, dcp, can_reference, why_not);
-
- bool const reference = _reference->GetValue ();
-
- /* Set up sensitivity */
- _use->Enable (!reference && any_subs > 0);
- bool const use = _use->GetValue ();
- _type->Enable (!reference && any_subs > 0 && use);
- _burn->Enable (!reference && any_subs > 0 && use && _type->GetSelection() == 0);
- _x_offset->Enable (!reference && any_subs > 0 && use);
- _y_offset->Enable (!reference && any_subs > 0 && use);
- _x_scale->Enable (!reference && any_subs > 0 && use);
- _y_scale->Enable (!reference && any_subs > 0 && use);
- _line_spacing->Enable (!reference && use);
- _language->Enable (!reference && any_subs > 0 && use);
- _stream->Enable (!reference && ffmpeg_subs == 1);
- _caption_view_button->Enable (!reference);
- _fonts_dialog_button->Enable (!reference);
- _appearance_dialog_button->Enable (!reference && any_subs > 0 && use);
-}
-
-void
-CaptionPanel::stream_changed ()
-{
- FFmpegContentList fc = _parent->selected_ffmpeg ();
- if (fc.size() != 1) {
- return;
- }
-
- shared_ptr<FFmpegContent> fcs = fc.front ();
-
- vector<shared_ptr<FFmpegSubtitleStream> > a = fcs->subtitle_streams ();
- vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = a.begin ();
- string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
- while (i != a.end() && (*i)->identifier () != s) {
- ++i;
- }
-
- if (i != a.end ()) {
- fcs->set_subtitle_stream (*i);
- }
-}
-
-void
-CaptionPanel::x_offset_changed ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
- i->caption_of_original_type(_original_type)->set_x_offset (_x_offset->GetValue() / 100.0);
- }
-}
-
-void
-CaptionPanel::y_offset_changed ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
- i->caption_of_original_type(_original_type)->set_y_offset (_y_offset->GetValue() / 100.0);
- }
-}
-
-void
-CaptionPanel::x_scale_changed ()
-{
- ContentList c = _parent->selected_caption ();
- if (c.size() == 1) {
- c.front()->caption_of_original_type(_original_type)->set_x_scale (_x_scale->GetValue() / 100.0);
- }
-}
-
-void
-CaptionPanel::y_scale_changed ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
- i->caption_of_original_type(_original_type)->set_y_scale (_y_scale->GetValue() / 100.0);
- }
-}
-
-void
-CaptionPanel::line_spacing_changed ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
- i->caption_of_original_type(_original_type)->set_line_spacing (_line_spacing->GetValue() / 100.0);
- }
-}
-
-void
-CaptionPanel::language_changed ()
-{
- BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
- i->caption_of_original_type(_original_type)->set_language (wx_to_std (_language->GetValue()));
- }
-}
-
-void
-CaptionPanel::content_selection_changed ()
-{
- film_content_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
- film_content_changed (CaptionContentProperty::USE);
- film_content_changed (CaptionContentProperty::BURN);
- film_content_changed (CaptionContentProperty::X_OFFSET);
- film_content_changed (CaptionContentProperty::Y_OFFSET);
- film_content_changed (CaptionContentProperty::X_SCALE);
- film_content_changed (CaptionContentProperty::Y_SCALE);
- film_content_changed (CaptionContentProperty::LINE_SPACING);
- film_content_changed (CaptionContentProperty::LANGUAGE);
- film_content_changed (CaptionContentProperty::FONTS);
- film_content_changed (CaptionContentProperty::TYPE);
- film_content_changed (DCPContentProperty::REFERENCE_CAPTION);
-}
-
-void
-CaptionPanel::caption_view_clicked ()
-{
- if (_caption_view) {
- _caption_view->Destroy ();
- _caption_view = 0;
- }
-
- ContentList c = _parent->selected_caption ();
- DCPOMATIC_ASSERT (c.size() == 1);
-
- shared_ptr<Decoder> decoder = decoder_factory (c.front(), _parent->film()->log(), false);
-
- if (decoder) {
- _caption_view = new CaptionView (this, _parent->film(), c.front(), c.front()->caption_of_original_type(_original_type), decoder, _parent->film_viewer());
- _caption_view->Show ();
- }
-}
-
-void
-CaptionPanel::fonts_dialog_clicked ()
-{
- if (_fonts_dialog) {
- _fonts_dialog->Destroy ();
- _fonts_dialog = 0;
- }
-
- ContentList c = _parent->selected_caption ();
- DCPOMATIC_ASSERT (c.size() == 1);
-
- _fonts_dialog = new FontsDialog (this, c.front(), c.front()->caption_of_original_type(_original_type));
- _fonts_dialog->Show ();
-}
-
-void
-CaptionPanel::reference_clicked ()
-{
- ContentList c = _parent->selected ();
- if (c.size() != 1) {
- return;
- }
-
- shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (c.front ());
- if (!d) {
- return;
- }
-
- d->set_reference_caption (_original_type, _reference->GetValue ());
-}
-
-void
-CaptionPanel::appearance_dialog_clicked ()
-{
- ContentList c = _parent->selected_caption ();
- DCPOMATIC_ASSERT (c.size() == 1);
-
- CaptionAppearanceDialog* d = new CaptionAppearanceDialog (this, c.front(), c.front()->caption_of_original_type(_original_type));
- if (d->ShowModal () == wxID_OK) {
- d->apply ();
- }
- d->Destroy ();
-}
+++ /dev/null
-/*
- Copyright (C) 2012-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 "content_sub_panel.h"
-
-class wxCheckBox;
-class wxSpinCtrl;
-class CaptionView;
-class FontsDialog;
-
-class CaptionPanel : public ContentSubPanel
-{
-public:
- CaptionPanel (ContentPanel *, CaptionType t);
-
- void film_changed (Film::Property);
- void film_content_changed (int);
- void content_selection_changed ();
-
-private:
- void use_toggled ();
- void type_changed ();
- void burn_toggled ();
- void x_offset_changed ();
- void y_offset_changed ();
- void x_scale_changed ();
- void y_scale_changed ();
- void line_spacing_changed ();
- void language_changed ();
- void stream_changed ();
- void caption_view_clicked ();
- void fonts_dialog_clicked ();
- void reference_clicked ();
- void appearance_dialog_clicked ();
-
- void setup_sensitivity ();
-
- wxCheckBox* _reference;
- wxStaticText* _reference_note;
- wxCheckBox* _use;
- wxChoice* _type;
- wxCheckBox* _burn;
- wxSpinCtrl* _x_offset;
- wxSpinCtrl* _y_offset;
- wxSpinCtrl* _x_scale;
- wxSpinCtrl* _y_scale;
- wxSpinCtrl* _line_spacing;
- wxTextCtrl* _language;
- wxChoice* _stream;
- wxButton* _caption_view_button;
- CaptionView* _caption_view;
- wxButton* _fonts_dialog_button;
- FontsDialog* _fonts_dialog;
- wxButton* _appearance_dialog_button;
- CaptionType _original_type;
-};
+++ /dev/null
-/*
- Copyright (C) 2014-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/text_caption_file_decoder.h"
-#include "lib/content_caption.h"
-#include "lib/video_decoder.h"
-#include "lib/audio_decoder.h"
-#include "lib/film.h"
-#include "lib/config.h"
-#include "lib/text_caption_file_content.h"
-#include "lib/caption_decoder.h"
-#include "caption_view.h"
-#include "film_viewer.h"
-#include "wx_util.h"
-
-using std::list;
-using boost::shared_ptr;
-using boost::bind;
-using boost::dynamic_pointer_cast;
-
-CaptionView::CaptionView (wxWindow* parent, shared_ptr<Film> film, shared_ptr<Content> content, shared_ptr<CaptionContent> caption, shared_ptr<Decoder> decoder, FilmViewer* viewer)
- : wxDialog (parent, wxID_ANY, _("Captions"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
- , _content (content)
- , _film_viewer (viewer)
-{
- _list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);
-
- {
- wxListItem ip;
- ip.SetId (0);
- ip.SetText (_("Start"));
- ip.SetWidth (100);
- _list->InsertColumn (0, ip);
- }
-
- {
- wxListItem ip;
- ip.SetId (1);
- ip.SetText (_("End"));
- ip.SetWidth (100);
- _list->InsertColumn (1, ip);
- }
-
- {
- wxListItem ip;
- ip.SetId (2);
- ip.SetText (_("Caption"));
- ip.SetWidth (640);
- _list->InsertColumn (2, ip);
- }
-
- wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
- sizer->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_X_GAP);
-
- _list->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&CaptionView::subtitle_selected, this, _1));
-
- wxSizer* buttons = CreateSeparatedButtonSizer (wxOK);
- if (buttons) {
- sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
- }
-
- if (decoder->video) {
- decoder->video->set_ignore (true);
- }
- if (decoder->audio) {
- decoder->audio->set_ignore (true);
- }
-
- _subs = 0;
- _frc = film->active_frame_rate_change (content->position());
-
- /* Find the decoder that is being used for our CaptionContent and attach to it */
- BOOST_FOREACH (shared_ptr<CaptionDecoder> i, decoder->caption) {
- if (i->content() == caption) {
- i->PlainStart.connect (bind (&CaptionView::data_start, this, _1));
- i->Stop.connect (bind (&CaptionView::data_stop, this, _1));
- }
- }
- while (!decoder->pass ()) {}
- SetSizerAndFit (sizer);
-}
-
-void
-CaptionView::data_start (ContentTextCaption cts)
-{
- BOOST_FOREACH (dcp::SubtitleString const & i, cts.subs) {
- wxListItem list_item;
- list_item.SetId (_subs);
- _list->InsertItem (list_item);
- _list->SetItem (_subs, 0, std_to_wx (cts.from().timecode (_frc->source)));
- _list->SetItem (_subs, 2, std_to_wx (i.text ()));
- _start_times.push_back (cts.from ());
- ++_subs;
- }
-
- _last_count = cts.subs.size ();
-}
-
-void
-CaptionView::data_stop (ContentTime time)
-{
- if (!_last_count) {
- return;
- }
-
- for (int i = _subs - *_last_count; i < _subs; ++i) {
- _list->SetItem (i, 1, std_to_wx (time.timecode (_frc->source)));
- }
-}
-
-void
-CaptionView::subtitle_selected (wxListEvent& ev)
-{
- if (!Config::instance()->jump_to_selected ()) {
- return;
- }
-
- DCPOMATIC_ASSERT (ev.GetIndex() < int(_start_times.size()));
- shared_ptr<Content> locked = _content.lock ();
- DCPOMATIC_ASSERT (locked);
- _film_viewer->set_position (locked, _start_times[ev.GetIndex()]);
-}
+++ /dev/null
-/*
- Copyright (C) 2014-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/content_caption.h"
-#include <boost/shared_ptr.hpp>
-#include <wx/wx.h>
-#include <wx/listctrl.h>
-
-class Decoder;
-class FilmViewer;
-
-class CaptionView : public wxDialog
-{
-public:
- CaptionView (
- wxWindow *, boost::shared_ptr<Film>, boost::shared_ptr<Content> content, boost::shared_ptr<CaptionContent> caption, boost::shared_ptr<Decoder>, FilmViewer* viewer
- );
-
-private:
- void data_start (ContentTextCaption cts);
- void data_stop (ContentTime time);
- void subtitle_selected (wxListEvent &);
-
- wxListCtrl* _list;
- int _subs;
- boost::optional<FrameRateChange> _frc;
- boost::optional<int> _last_count;
- std::vector<ContentTime> _start_times;
- boost::weak_ptr<Content> _content;
- FilmViewer* _film_viewer;
-};
*/
#include "closed_captions_dialog.h"
-#include "lib/text_caption.h"
+#include "lib/string_text.h"
#include <boost/bind.hpp>
using std::list;
class ClosedCaptionSorter
{
public:
- bool operator() (TextCaption const & a, TextCaption const & b)
+ bool operator() (StringText const & a, StringText const & b)
{
return from_top(a) < from_top(b);
}
private:
- float from_top (TextCaption const & c) const
+ float from_top (StringText const & c) const
{
switch (c.v_align()) {
case dcp::VALIGN_TOP:
{
shared_ptr<Player> player = _player.lock ();
DCPOMATIC_ASSERT (player);
- list<TextCaption> to_show;
- BOOST_FOREACH (PlayerCaption i, player->closed_captions_for_frame(time)) {
- BOOST_FOREACH (TextCaption j, i.text) {
+ list<StringText> to_show;
+ BOOST_FOREACH (PlayerText i, player->closed_captions_for_frame(time)) {
+ BOOST_FOREACH (StringText j, i.text) {
to_show.push_back (j);
}
}
to_show.sort (ClosedCaptionSorter());
- list<TextCaption>::const_iterator j = to_show.begin();
+ list<StringText>::const_iterator j = to_show.begin();
int k = 0;
while (j != to_show.end() && k < _num_lines) {
_lines[k] = j->text();
#include "wx_util.h"
#include "video_panel.h"
#include "audio_panel.h"
-#include "caption_panel.h"
+#include "text_panel.h"
#include "timing_panel.h"
#include "timeline_dialog.h"
#include "image_sequence_dialog.h"
#include "film_viewer.h"
#include "lib/audio_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/video_content.h"
#include "lib/ffmpeg_content.h"
#include "lib/content_factory.h"
#include "lib/config.h"
#include "lib/log.h"
#include "lib/compose.hpp"
-#include "lib/text_caption_file_content.h"
-#include "lib/text_caption_file.h"
+#include "lib/string_text_file_content.h"
+#include "lib/string_text_file.h"
#include <wx/wx.h>
#include <wx/notebook.h>
#include <wx/listctrl.h>
_audio_panel = new AudioPanel (this);
_panels.push_back (_audio_panel);
for (int i = 0; i < CAPTION_COUNT; ++i) {
- _caption_panel[i] = new CaptionPanel (this, static_cast<CaptionType>(i));
+ _caption_panel[i] = new TextPanel (this, static_cast<TextType>(i));
_panels.push_back (_caption_panel[i]);
}
_timing_panel = new TimingPanel (this, _film_viewer);
BOOST_FOREACH (shared_ptr<Content> i, selected()) {
DCPTime p;
p = i->position();
- if (dynamic_pointer_cast<TextCaptionFileContent>(i) && i->paths_valid()) {
+ if (dynamic_pointer_cast<StringTextFileContent>(i) && i->paths_valid()) {
/* Rather special case; if we select a text subtitle file jump to its
first subtitle.
*/
- TextCaptionFile ts (dynamic_pointer_cast<TextCaptionFileContent>(i));
+ StringTextFile ts (dynamic_pointer_cast<StringTextFileContent>(i));
if (ts.first()) {
p += DCPTime(ts.first().get(), _film->active_frame_rate_change(i->position()));
}
if (i->audio) {
have_audio = true;
}
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->caption) {
have_caption[j->original_type()] = true;
}
}
class TimelineDialog;
class FilmEditor;
class ContentSubPanel;
-class CaptionPanel;
+class TextPanel;
class AudioPanel;
class Film;
class FilmViewer;
wxButton* _timeline;
ContentSubPanel* _video_panel;
AudioPanel* _audio_panel;
- CaptionPanel* _caption_panel[CAPTION_COUNT];
+ TextPanel* _caption_panel[CAPTION_COUNT];
ContentSubPanel* _timing_panel;
std::list<ContentSubPanel *> _panels;
ContentMenu* _menu;
#include "lib/ffmpeg_content.h"
#include "lib/audio_processor.h"
#include "lib/video_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/dcp_content.h"
#include "lib/audio_content.h"
#include <dcp/locale_convert.h>
DCPPanel::film_content_changed (int property)
{
if (property == AudioContentProperty::STREAMS ||
- property == CaptionContentProperty::USE ||
- property == CaptionContentProperty::BURN ||
+ property == TextContentProperty::USE ||
+ property == TextContentProperty::BURN ||
property == VideoContentProperty::SCALE ||
property == DCPContentProperty::REFERENCE_VIDEO ||
property == DCPContentProperty::REFERENCE_AUDIO ||
#include "lib/film.h"
#include "lib/config.h"
-#include "lib/player_caption.h"
+#include "lib/player_text.h"
#include <RtAudio.h>
#include <wx/wx.h>
#include "font_files_dialog.h"
#include "lib/font.h"
#include "lib/content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include <wx/wx.h>
#include <boost/foreach.hpp>
#include <iostream>
using std::cout;
using boost::shared_ptr;
-FontsDialog::FontsDialog (wxWindow* parent, shared_ptr<Content> content, shared_ptr<CaptionContent> caption)
+FontsDialog::FontsDialog (wxWindow* parent, shared_ptr<Content> content, shared_ptr<TextContent> caption)
: wxDialog (parent, wxID_ANY, _("Fonts"))
, _content (content)
, _caption (caption)
FontsDialog::setup ()
{
shared_ptr<Content> content = _content.lock ();
- shared_ptr<CaptionContent> caption = _caption.lock ();
+ shared_ptr<TextContent> caption = _caption.lock ();
if (!content || !caption) {
return;
}
FontsDialog::edit_clicked ()
{
shared_ptr<Content> content = _content.lock ();
- shared_ptr<CaptionContent> caption = _caption.lock ();
+ shared_ptr<TextContent> caption = _caption.lock ();
if (!content || !caption) {
return;
}
#include <boost/filesystem.hpp>
class Content;
-class CaptionContent;
+class TextContent;
class FontsDialog : public wxDialog
{
public:
- FontsDialog (wxWindow* parent, boost::shared_ptr<Content>, boost::shared_ptr<CaptionContent> caption);
+ FontsDialog (wxWindow* parent, boost::shared_ptr<Content>, boost::shared_ptr<TextContent> caption);
private:
void setup ();
void edit_clicked ();
boost::weak_ptr<Content> _content;
- boost::weak_ptr<CaptionContent> _caption;
+ boost::weak_ptr<TextContent> _caption;
wxListCtrl* _fonts;
wxButton* _edit;
};
--- /dev/null
+/*
+ Copyright (C) 2015-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 "subtitle_appearance_dialog.h"
+#include "rgba_colour_picker.h"
+#include "lib/string_text_file_content.h"
+#include "lib/text_content.h"
+#include "lib/ffmpeg_subtitle_stream.h"
+#include "lib/ffmpeg_content.h"
+#include <wx/wx.h>
+#include <wx/clrpicker.h>
+#include <wx/spinctrl.h>
+#include <wx/gbsizer.h>
+
+using std::map;
+using boost::shared_ptr;
+using boost::bind;
+using boost::dynamic_pointer_cast;
+using boost::optional;
+
+int const SubtitleAppearanceDialog::NONE = 0;
+int const SubtitleAppearanceDialog::OUTLINE = 1;
+int const SubtitleAppearanceDialog::SHADOW = 2;
+
+SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr<Content> content, shared_ptr<TextContent> caption)
+ : wxDialog (parent, wxID_ANY, _("Caption appearance"))
+ , _content (content)
+ , _caption (caption)
+{
+ shared_ptr<FFmpegContent> ff = dynamic_pointer_cast<FFmpegContent> (content);
+ if (ff) {
+ _stream = ff->subtitle_stream ();
+ }
+
+ wxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+ SetSizer (overall_sizer);
+
+ _table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+
+ overall_sizer->Add (_table, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+
+ int r = 0;
+
+ add_label_to_sizer (_table, this, _("Colour"), true, wxGBPosition (r, 0));
+ _force_colour = set_to (_colour = new wxColourPickerCtrl (this, wxID_ANY), r);
+
+ add_label_to_sizer (_table, this, _("Effect"), true, wxGBPosition (r, 0));
+ _force_effect = set_to (_effect = new wxChoice (this, wxID_ANY), r);
+
+ add_label_to_sizer (_table, this, _("Effect colour"), true, wxGBPosition (r, 0));
+ _force_effect_colour = set_to (_effect_colour = new wxColourPickerCtrl (this, wxID_ANY), r);
+
+ add_label_to_sizer (_table, this, _("Outline width"), true, wxGBPosition (r, 0));
+ _outline_width = new wxSpinCtrl (this, wxID_ANY);
+ _table->Add (_outline_width, wxGBPosition (r, 1));
+ ++r;
+
+ add_label_to_sizer (_table, this, _("Fade in time"), true, wxGBPosition (r, 0));
+ _force_fade_in = set_to (_fade_in = new Timecode<ContentTime> (this), r);
+
+ add_label_to_sizer (_table, this, _("Fade out time"), true, wxGBPosition (r, 0));
+ _force_fade_out = set_to (_fade_out = new Timecode<ContentTime> (this), r);
+
+ if (_stream) {
+ wxScrolled<wxPanel>* colours_panel = new wxScrolled<wxPanel> (this);
+ colours_panel->EnableScrolling (false, true);
+ colours_panel->ShowScrollbars (wxSHOW_SB_NEVER, wxSHOW_SB_ALWAYS);
+ colours_panel->SetScrollRate (0, 16);
+
+ wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+ table->AddGrowableCol (1, 1);
+
+ map<RGBA, RGBA> colours = _stream->colours ();
+
+ wxStaticText* t = new wxStaticText (colours_panel, wxID_ANY, "");
+ t->SetLabelMarkup (_("<b>Original colour</b>"));
+ table->Add (t, 1, wxEXPAND);
+ t = new wxStaticText (colours_panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
+ t->SetLabelMarkup (_("<b>New colour</b>"));
+ table->Add (t, 1, wxALIGN_CENTER);
+
+ for (map<RGBA, RGBA>::const_iterator i = colours.begin(); i != colours.end(); ++i) {
+ wxPanel* from = new wxPanel (colours_panel, wxID_ANY);
+ from->SetBackgroundColour (wxColour (i->first.r, i->first.g, i->first.b, i->first.a));
+ table->Add (from, 1, wxEXPAND);
+ RGBAColourPicker* to = new RGBAColourPicker (colours_panel, i->second);
+ table->Add (to, 1, wxEXPAND);
+ _pickers[i->first] = to;
+ }
+
+ colours_panel->SetSizer (table);
+
+ overall_sizer->Add (colours_panel, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+
+ wxButton* restore = new wxButton (this, wxID_ANY, _("Restore to original colours"));
+ restore->Bind (wxEVT_BUTTON, bind (&SubtitleAppearanceDialog::restore, this));
+ overall_sizer->Add (restore, 0, wxALL, DCPOMATIC_SIZER_X_GAP);
+ }
+
+ wxSizer* buttons = CreateSeparatedButtonSizer (wxOK);
+ if (buttons) {
+ overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+ }
+
+ overall_sizer->Layout ();
+ overall_sizer->SetSizeHints (this);
+
+ /* Keep these Appends() up to date with NONE/OUTLINE/SHADOW variables */
+ _effect->Append (_("None"));
+ _effect->Append (_("Outline"));
+ _effect->Append (_("Shadow"));;
+
+ optional<dcp::Colour> colour = _caption->colour();
+ _force_colour->SetValue (static_cast<bool>(colour));
+ if (colour) {
+ _colour->SetColour (wxColour (colour->r, colour->g, colour->b));
+ } else {
+ _colour->SetColour (wxColour (255, 255, 255));
+ }
+
+ optional<dcp::Effect> effect = _caption->effect();
+ _force_effect->SetValue (static_cast<bool>(effect));
+ if (effect) {
+ switch (*effect) {
+ case dcp::NONE:
+ _effect->SetSelection (NONE);
+ break;
+ case dcp::BORDER:
+ _effect->SetSelection (OUTLINE);
+ break;
+ case dcp::SHADOW:
+ _effect->SetSelection (SHADOW);
+ break;
+ }
+ } else {
+ _effect->SetSelection (NONE);
+ }
+
+ optional<dcp::Colour> effect_colour = _caption->effect_colour();
+ _force_effect_colour->SetValue (static_cast<bool>(effect_colour));
+ if (effect_colour) {
+ _effect_colour->SetColour (wxColour (effect_colour->r, effect_colour->g, effect_colour->b));
+ } else {
+ _effect_colour->SetColour (wxColour (0, 0, 0));
+ }
+
+ optional<ContentTime> fade_in = _caption->fade_in();
+ _force_fade_in->SetValue (static_cast<bool>(fade_in));
+ if (fade_in) {
+ _fade_in->set (*fade_in, _content->active_video_frame_rate());
+ } else {
+ _fade_in->set (ContentTime(), _content->active_video_frame_rate());
+ }
+
+ optional<ContentTime> fade_out = _caption->fade_out();
+ _force_fade_out->SetValue (static_cast<bool>(fade_out));
+ if (fade_out) {
+ _fade_out->set (*fade_out, _content->active_video_frame_rate ());
+ } else {
+ _fade_out->set (ContentTime(), _content->active_video_frame_rate ());
+ }
+
+ _outline_width->SetValue (_caption->outline_width ());
+
+ _force_colour->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+ _force_effect_colour->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+ _force_effect->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+ _force_fade_in->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+ _force_fade_out->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+ _effect->Bind (wxEVT_CHOICE, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+ _content_connection = _content->Changed.connect (bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
+
+ setup_sensitivity ();
+}
+
+wxCheckBox*
+SubtitleAppearanceDialog::set_to (wxWindow* w, int& r)
+{
+ wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ wxCheckBox* set_to = new wxCheckBox (this, wxID_ANY, _("Set to"));
+ s->Add (set_to, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 8);
+ s->Add (w, 0, wxALIGN_CENTER_VERTICAL);
+ _table->Add (s, wxGBPosition (r, 1));
+ ++r;
+ return set_to;
+}
+
+void
+SubtitleAppearanceDialog::apply ()
+{
+ if (_force_colour->GetValue ()) {
+ wxColour const c = _colour->GetColour ();
+ _caption->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue()));
+ } else {
+ _caption->unset_colour ();
+ }
+ if (_force_effect->GetValue()) {
+ switch (_effect->GetSelection()) {
+ case NONE:
+ _caption->set_effect (dcp::NONE);
+ break;
+ case OUTLINE:
+ _caption->set_effect (dcp::BORDER);
+ break;
+ case SHADOW:
+ _caption->set_effect (dcp::SHADOW);
+ break;
+ }
+ } else {
+ _caption->unset_effect ();
+ }
+ if (_force_effect_colour->GetValue ()) {
+ wxColour const ec = _effect_colour->GetColour ();
+ _caption->set_effect_colour (dcp::Colour (ec.Red(), ec.Green(), ec.Blue()));
+ } else {
+ _caption->unset_effect_colour ();
+ }
+ if (_force_fade_in->GetValue ()) {
+ _caption->set_fade_in (_fade_in->get (_content->active_video_frame_rate ()));
+ } else {
+ _caption->unset_fade_in ();
+ }
+ if (_force_fade_out->GetValue ()) {
+ _caption->set_fade_out (_fade_out->get (_content->active_video_frame_rate ()));
+ } else {
+ _caption->unset_fade_out ();
+ }
+ _caption->set_outline_width (_outline_width->GetValue ());
+
+ if (_stream) {
+ for (map<RGBA, RGBAColourPicker*>::const_iterator i = _pickers.begin(); i != _pickers.end(); ++i) {
+ _stream->set_colour (i->first, i->second->colour ());
+ }
+ }
+
+ shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (_content);
+ if (fc) {
+ fc->signal_subtitle_stream_changed ();
+ }
+}
+
+void
+SubtitleAppearanceDialog::restore ()
+{
+ for (map<RGBA, RGBAColourPicker*>::const_iterator i = _pickers.begin(); i != _pickers.end(); ++i) {
+ i->second->set (i->first);
+ }
+}
+
+void
+SubtitleAppearanceDialog::setup_sensitivity ()
+{
+ _colour->Enable (_force_colour->GetValue ());
+ _effect_colour->Enable (_force_effect_colour->GetValue ());
+ _effect->Enable (_force_effect->GetValue ());
+ _fade_in->Enable (_force_fade_in->GetValue ());
+ _fade_out->Enable (_force_fade_out->GetValue ());
+
+ bool const can_outline_width = _effect->GetSelection() == OUTLINE && _caption->burn ();
+ _outline_width->Enable (can_outline_width);
+ if (can_outline_width) {
+ _outline_width->UnsetToolTip ();
+ } else {
+ _outline_width->SetToolTip (_("Outline width cannot be set unless you are burning in captions"));
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2015-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 "timecode.h"
+#include "lib/rgba.h"
+#include <wx/wx.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/signals2.hpp>
+
+class wxRadioButton;
+class wxColourPickerCtrl;
+class wxGridBagSizer;
+class Content;
+class RGBAColourPicker;
+class FFmpegSubtitleStream;
+class wxCheckBox;
+class wxWidget;
+
+class SubtitleAppearanceDialog : public wxDialog
+{
+public:
+ SubtitleAppearanceDialog (wxWindow* parent, boost::shared_ptr<Content> content, boost::shared_ptr<TextContent> caption);
+
+ void apply ();
+
+private:
+ void setup_sensitivity ();
+ void restore ();
+ wxCheckBox* set_to (wxWindow* w, int& r);
+
+ wxCheckBox* _force_colour;
+ wxColourPickerCtrl* _colour;
+ wxCheckBox* _force_effect;
+ wxChoice* _effect;
+ wxCheckBox* _force_effect_colour;
+ wxColourPickerCtrl* _effect_colour;
+ wxCheckBox* _force_fade_in;
+ Timecode<ContentTime>* _fade_in;
+ wxCheckBox* _force_fade_out;
+ Timecode<ContentTime>* _fade_out;
+ wxSpinCtrl* _outline_width;
+ wxGridBagSizer* _table;
+ std::map<RGBA, RGBAColourPicker*> _pickers;
+
+ boost::shared_ptr<Content> _content;
+ boost::shared_ptr<TextContent> _caption;
+ boost::shared_ptr<FFmpegSubtitleStream> _stream;
+
+ boost::signals2::scoped_connection _content_connection;
+
+ static int const NONE;
+ static int const OUTLINE;
+ static int const SHADOW;
+};
--- /dev/null
+/*
+ Copyright (C) 2012-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 "text_panel.h"
+#include "film_editor.h"
+#include "wx_util.h"
+#include "text_view.h"
+#include "content_panel.h"
+#include "fonts_dialog.h"
+#include "subtitle_appearance_dialog.h"
+#include "lib/ffmpeg_content.h"
+#include "lib/string_text_file_content.h"
+#include "lib/ffmpeg_subtitle_stream.h"
+#include "lib/dcp_subtitle_content.h"
+#include "lib/string_text_file_decoder.h"
+#include "lib/dcp_subtitle_decoder.h"
+#include "lib/dcp_content.h"
+#include "lib/text_content.h"
+#include "lib/decoder_factory.h"
+#include <wx/spinctrl.h>
+#include <boost/foreach.hpp>
+
+using std::vector;
+using std::string;
+using std::list;
+using std::cout;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+
+TextPanel::TextPanel (ContentPanel* p, TextType t)
+ : ContentSubPanel (p, std_to_wx(caption_type_to_name(t)))
+ , _caption_view (0)
+ , _fonts_dialog (0)
+ , _original_type (t)
+{
+ wxBoxSizer* reference_sizer = new wxBoxSizer (wxVERTICAL);
+
+ _reference = new wxCheckBox (this, wxID_ANY, _("Use this DCP's subtitle as OV and make VF"));
+ reference_sizer->Add (_reference, 0, wxLEFT | wxRIGHT | wxTOP, DCPOMATIC_SIZER_GAP);
+
+ _reference_note = new wxStaticText (this, wxID_ANY, _(""));
+ _reference_note->Wrap (200);
+ reference_sizer->Add (_reference_note, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP);
+ wxFont font = _reference_note->GetFont();
+ font.SetStyle(wxFONTSTYLE_ITALIC);
+ font.SetPointSize(font.GetPointSize() - 1);
+ _reference_note->SetFont(font);
+
+ _sizer->Add (reference_sizer);
+
+ wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+ _sizer->Add (grid, 0, wxALL, 8);
+ int r = 0;
+
+ wxBoxSizer* use = new wxBoxSizer (wxHORIZONTAL);
+ _use = new wxCheckBox (this, wxID_ANY, _("Use as"));
+ use->Add (_use, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
+ _type = new wxChoice (this, wxID_ANY);
+ _type->Append (_("subtitles (open captions)"));
+ _type->Append (_("closed captions"));
+ use->Add (_type, 1, wxEXPAND, 0);
+ grid->Add (use, wxGBPosition (r, 0), wxGBSpan (1, 2));
+ ++r;
+
+ _burn = new wxCheckBox (this, wxID_ANY, _("Burn subtitles into image"));
+ grid->Add (_burn, wxGBPosition (r, 0), wxGBSpan (1, 2));
+ ++r;
+
+ {
+ add_label_to_sizer (grid, this, _("X Offset"), true, wxGBPosition (r, 0));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _x_offset = new wxSpinCtrl (this);
+ s->Add (_x_offset);
+ add_label_to_sizer (s, this, _("%"), false);
+ grid->Add (s, wxGBPosition (r, 1));
+ ++r;
+ }
+
+ {
+ add_label_to_sizer (grid, this, _("Y Offset"), true, wxGBPosition (r, 0));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _y_offset = new wxSpinCtrl (this);
+ s->Add (_y_offset);
+ add_label_to_sizer (s, this, _("%"), false);
+ grid->Add (s, wxGBPosition (r, 1));
+ ++r;
+ }
+
+ {
+ add_label_to_sizer (grid, this, _("X Scale"), true, wxGBPosition (r, 0));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _x_scale = new wxSpinCtrl (this);
+ s->Add (_x_scale);
+ add_label_to_sizer (s, this, _("%"), false);
+ grid->Add (s, wxGBPosition (r, 1));
+ ++r;
+ }
+
+ {
+ add_label_to_sizer (grid, this, _("Y Scale"), true, wxGBPosition (r, 0));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _y_scale = new wxSpinCtrl (this);
+ s->Add (_y_scale);
+ add_label_to_sizer (s, this, _("%"), false);
+ grid->Add (s, wxGBPosition (r, 1));
+ ++r;
+ }
+
+ {
+ add_label_to_sizer (grid, this, _("Line spacing"), true, wxGBPosition (r, 0));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _line_spacing = new wxSpinCtrl (this);
+ s->Add (_line_spacing);
+ add_label_to_sizer (s, this, _("%"), false);
+ grid->Add (s, wxGBPosition (r, 1));
+ ++r;
+ }
+
+ add_label_to_sizer (grid, this, _("Language"), true, wxGBPosition (r, 0));
+ _language = new wxTextCtrl (this, wxID_ANY);
+ grid->Add (_language, wxGBPosition (r, 1));
+ ++r;
+
+ add_label_to_sizer (grid, this, _("Stream"), true, wxGBPosition (r, 0));
+ _stream = new wxChoice (this, wxID_ANY);
+ grid->Add (_stream, wxGBPosition (r, 1));
+ ++r;
+
+ {
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+
+ _caption_view_button = new wxButton (this, wxID_ANY, _("View..."));
+ s->Add (_caption_view_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
+ _fonts_dialog_button = new wxButton (this, wxID_ANY, _("Fonts..."));
+ s->Add (_fonts_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
+ _appearance_dialog_button = new wxButton (this, wxID_ANY, _("Appearance..."));
+ s->Add (_appearance_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
+
+ grid->Add (s, wxGBPosition (r, 0), wxGBSpan (1, 2));
+ ++r;
+ }
+
+ _x_offset->SetRange (-100, 100);
+ _y_offset->SetRange (-100, 100);
+ _x_scale->SetRange (10, 1000);
+ _y_scale->SetRange (10, 1000);
+ _line_spacing->SetRange (10, 1000);
+
+ _reference->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::reference_clicked, this));
+ _use->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::use_toggled, this));
+ _type->Bind (wxEVT_CHOICE, boost::bind (&TextPanel::type_changed, this));
+ _burn->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::burn_toggled, this));
+ _x_offset->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::x_offset_changed, this));
+ _y_offset->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::y_offset_changed, this));
+ _x_scale->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::x_scale_changed, this));
+ _y_scale->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::y_scale_changed, this));
+ _line_spacing->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::line_spacing_changed, this));
+ _language->Bind (wxEVT_TEXT, boost::bind (&TextPanel::language_changed, this));
+ _stream->Bind (wxEVT_CHOICE, boost::bind (&TextPanel::stream_changed, this));
+ _caption_view_button->Bind (wxEVT_BUTTON, boost::bind (&TextPanel::caption_view_clicked, this));
+ _fonts_dialog_button->Bind (wxEVT_BUTTON, boost::bind (&TextPanel::fonts_dialog_clicked, this));
+ _appearance_dialog_button->Bind (wxEVT_BUTTON, boost::bind (&TextPanel::appearance_dialog_clicked, this));
+}
+
+void
+TextPanel::film_changed (Film::Property property)
+{
+ if (property == Film::CONTENT || property == Film::REEL_TYPE) {
+ setup_sensitivity ();
+ }
+}
+
+void
+TextPanel::film_content_changed (int property)
+{
+ FFmpegContentList fc = _parent->selected_ffmpeg ();
+ ContentList sc = _parent->selected_caption ();
+
+ shared_ptr<FFmpegContent> fcs;
+ if (fc.size() == 1) {
+ fcs = fc.front ();
+ }
+
+ shared_ptr<Content> scs;
+ if (sc.size() == 1) {
+ scs = sc.front ();
+ }
+
+ shared_ptr<TextContent> caption;
+ if (scs) {
+ caption = scs->caption_of_original_type(_original_type);
+ }
+
+ if (property == FFmpegContentProperty::SUBTITLE_STREAMS) {
+ _stream->Clear ();
+ if (fcs) {
+ vector<shared_ptr<FFmpegSubtitleStream> > s = fcs->subtitle_streams ();
+ for (vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = s.begin(); i != s.end(); ++i) {
+ _stream->Append (std_to_wx ((*i)->name), new wxStringClientData (std_to_wx ((*i)->identifier ())));
+ }
+
+ if (fcs->subtitle_stream()) {
+ checked_set (_stream, fcs->subtitle_stream()->identifier ());
+ } else {
+ _stream->SetSelection (wxNOT_FOUND);
+ }
+ }
+ setup_sensitivity ();
+ } else if (property == TextContentProperty::USE) {
+ checked_set (_use, caption ? caption->use() : false);
+ setup_sensitivity ();
+ } else if (property == TextContentProperty::TYPE) {
+ if (caption) {
+ switch (caption->type()) {
+ case CAPTION_OPEN:
+ _type->SetSelection (0);
+ break;
+ case CAPTION_CLOSED:
+ _type->SetSelection (1);
+ break;
+ default:
+ DCPOMATIC_ASSERT (false);
+ }
+ } else {
+ _type->SetSelection (0);
+ }
+ setup_sensitivity ();
+ } else if (property == TextContentProperty::BURN) {
+ checked_set (_burn, caption ? caption->burn() : false);
+ } else if (property == TextContentProperty::X_OFFSET) {
+ checked_set (_x_offset, caption ? lrint (caption->x_offset() * 100) : 0);
+ } else if (property == TextContentProperty::Y_OFFSET) {
+ checked_set (_y_offset, caption ? lrint (caption->y_offset() * 100) : 0);
+ } else if (property == TextContentProperty::X_SCALE) {
+ checked_set (_x_scale, caption ? lrint (caption->x_scale() * 100) : 100);
+ } else if (property == TextContentProperty::Y_SCALE) {
+ checked_set (_y_scale, caption ? lrint (caption->y_scale() * 100) : 100);
+ } else if (property == TextContentProperty::LINE_SPACING) {
+ checked_set (_line_spacing, caption ? lrint (caption->line_spacing() * 100) : 100);
+ } else if (property == TextContentProperty::LANGUAGE) {
+ checked_set (_language, caption ? caption->language() : "");
+ } else if (property == DCPContentProperty::REFERENCE_CAPTION) {
+ if (scs) {
+ shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent> (scs);
+ checked_set (_reference, dcp ? dcp->reference_caption(_original_type) : false);
+ } else {
+ checked_set (_reference, false);
+ }
+
+ setup_sensitivity ();
+ } else if (property == DCPContentProperty::CAPTIONS) {
+ setup_sensitivity ();
+ }
+}
+
+void
+TextPanel::use_toggled ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption()) {
+ i->caption_of_original_type(_original_type)->set_use (_use->GetValue());
+ }
+}
+
+void
+TextPanel::type_changed ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption()) {
+ switch (_type->GetSelection()) {
+ case 0:
+ i->caption_of_original_type(_original_type)->set_type (CAPTION_OPEN);
+ break;
+ case 1:
+ i->caption_of_original_type(_original_type)->set_type (CAPTION_CLOSED);
+ break;
+ }
+ }
+}
+
+void
+TextPanel::burn_toggled ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
+ i->caption_of_original_type(_original_type)->set_burn (_burn->GetValue());
+ }
+}
+
+void
+TextPanel::setup_sensitivity ()
+{
+ int any_subs = 0;
+ int ffmpeg_subs = 0;
+ ContentList sel = _parent->selected_caption ();
+ BOOST_FOREACH (shared_ptr<Content> i, sel) {
+ /* These are the content types that could include subtitles */
+ shared_ptr<const FFmpegContent> fc = boost::dynamic_pointer_cast<const FFmpegContent> (i);
+ shared_ptr<const StringTextFileContent> sc = boost::dynamic_pointer_cast<const StringTextFileContent> (i);
+ shared_ptr<const DCPContent> dc = boost::dynamic_pointer_cast<const DCPContent> (i);
+ shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (i);
+ if (fc) {
+ if (!fc->caption.empty()) {
+ ++ffmpeg_subs;
+ ++any_subs;
+ }
+ } else if (sc || dc || dsc) {
+ /* XXX: in the future there could be bitmap subs from DCPs */
+ ++any_subs;
+ }
+ }
+
+ /* Decide whether we can reference these subs */
+
+ shared_ptr<DCPContent> dcp;
+ if (sel.size() == 1) {
+ dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+ }
+
+ string why_not;
+ bool const can_reference = dcp && dcp->can_reference_caption (_original_type, why_not);
+ setup_refer_button (_reference, _reference_note, dcp, can_reference, why_not);
+
+ bool const reference = _reference->GetValue ();
+
+ /* Set up sensitivity */
+ _use->Enable (!reference && any_subs > 0);
+ bool const use = _use->GetValue ();
+ _type->Enable (!reference && any_subs > 0 && use);
+ _burn->Enable (!reference && any_subs > 0 && use && _type->GetSelection() == 0);
+ _x_offset->Enable (!reference && any_subs > 0 && use);
+ _y_offset->Enable (!reference && any_subs > 0 && use);
+ _x_scale->Enable (!reference && any_subs > 0 && use);
+ _y_scale->Enable (!reference && any_subs > 0 && use);
+ _line_spacing->Enable (!reference && use);
+ _language->Enable (!reference && any_subs > 0 && use);
+ _stream->Enable (!reference && ffmpeg_subs == 1);
+ _caption_view_button->Enable (!reference);
+ _fonts_dialog_button->Enable (!reference);
+ _appearance_dialog_button->Enable (!reference && any_subs > 0 && use);
+}
+
+void
+TextPanel::stream_changed ()
+{
+ FFmpegContentList fc = _parent->selected_ffmpeg ();
+ if (fc.size() != 1) {
+ return;
+ }
+
+ shared_ptr<FFmpegContent> fcs = fc.front ();
+
+ vector<shared_ptr<FFmpegSubtitleStream> > a = fcs->subtitle_streams ();
+ vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = a.begin ();
+ string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
+ while (i != a.end() && (*i)->identifier () != s) {
+ ++i;
+ }
+
+ if (i != a.end ()) {
+ fcs->set_subtitle_stream (*i);
+ }
+}
+
+void
+TextPanel::x_offset_changed ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
+ i->caption_of_original_type(_original_type)->set_x_offset (_x_offset->GetValue() / 100.0);
+ }
+}
+
+void
+TextPanel::y_offset_changed ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
+ i->caption_of_original_type(_original_type)->set_y_offset (_y_offset->GetValue() / 100.0);
+ }
+}
+
+void
+TextPanel::x_scale_changed ()
+{
+ ContentList c = _parent->selected_caption ();
+ if (c.size() == 1) {
+ c.front()->caption_of_original_type(_original_type)->set_x_scale (_x_scale->GetValue() / 100.0);
+ }
+}
+
+void
+TextPanel::y_scale_changed ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
+ i->caption_of_original_type(_original_type)->set_y_scale (_y_scale->GetValue() / 100.0);
+ }
+}
+
+void
+TextPanel::line_spacing_changed ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
+ i->caption_of_original_type(_original_type)->set_line_spacing (_line_spacing->GetValue() / 100.0);
+ }
+}
+
+void
+TextPanel::language_changed ()
+{
+ BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_caption ()) {
+ i->caption_of_original_type(_original_type)->set_language (wx_to_std (_language->GetValue()));
+ }
+}
+
+void
+TextPanel::content_selection_changed ()
+{
+ film_content_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
+ film_content_changed (TextContentProperty::USE);
+ film_content_changed (TextContentProperty::BURN);
+ film_content_changed (TextContentProperty::X_OFFSET);
+ film_content_changed (TextContentProperty::Y_OFFSET);
+ film_content_changed (TextContentProperty::X_SCALE);
+ film_content_changed (TextContentProperty::Y_SCALE);
+ film_content_changed (TextContentProperty::LINE_SPACING);
+ film_content_changed (TextContentProperty::LANGUAGE);
+ film_content_changed (TextContentProperty::FONTS);
+ film_content_changed (TextContentProperty::TYPE);
+ film_content_changed (DCPContentProperty::REFERENCE_CAPTION);
+}
+
+void
+TextPanel::caption_view_clicked ()
+{
+ if (_caption_view) {
+ _caption_view->Destroy ();
+ _caption_view = 0;
+ }
+
+ ContentList c = _parent->selected_caption ();
+ DCPOMATIC_ASSERT (c.size() == 1);
+
+ shared_ptr<Decoder> decoder = decoder_factory (c.front(), _parent->film()->log(), false);
+
+ if (decoder) {
+ _caption_view = new TextView (this, _parent->film(), c.front(), c.front()->caption_of_original_type(_original_type), decoder, _parent->film_viewer());
+ _caption_view->Show ();
+ }
+}
+
+void
+TextPanel::fonts_dialog_clicked ()
+{
+ if (_fonts_dialog) {
+ _fonts_dialog->Destroy ();
+ _fonts_dialog = 0;
+ }
+
+ ContentList c = _parent->selected_caption ();
+ DCPOMATIC_ASSERT (c.size() == 1);
+
+ _fonts_dialog = new FontsDialog (this, c.front(), c.front()->caption_of_original_type(_original_type));
+ _fonts_dialog->Show ();
+}
+
+void
+TextPanel::reference_clicked ()
+{
+ ContentList c = _parent->selected ();
+ if (c.size() != 1) {
+ return;
+ }
+
+ shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (c.front ());
+ if (!d) {
+ return;
+ }
+
+ d->set_reference_caption (_original_type, _reference->GetValue ());
+}
+
+void
+TextPanel::appearance_dialog_clicked ()
+{
+ ContentList c = _parent->selected_caption ();
+ DCPOMATIC_ASSERT (c.size() == 1);
+
+ SubtitleAppearanceDialog* d = new SubtitleAppearanceDialog (this, c.front(), c.front()->caption_of_original_type(_original_type));
+ if (d->ShowModal () == wxID_OK) {
+ d->apply ();
+ }
+ d->Destroy ();
+}
--- /dev/null
+/*
+ Copyright (C) 2012-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 "content_sub_panel.h"
+
+class wxCheckBox;
+class wxSpinCtrl;
+class TextView;
+class FontsDialog;
+
+class TextPanel : public ContentSubPanel
+{
+public:
+ TextPanel (ContentPanel *, TextType t);
+
+ void film_changed (Film::Property);
+ void film_content_changed (int);
+ void content_selection_changed ();
+
+private:
+ void use_toggled ();
+ void type_changed ();
+ void burn_toggled ();
+ void x_offset_changed ();
+ void y_offset_changed ();
+ void x_scale_changed ();
+ void y_scale_changed ();
+ void line_spacing_changed ();
+ void language_changed ();
+ void stream_changed ();
+ void caption_view_clicked ();
+ void fonts_dialog_clicked ();
+ void reference_clicked ();
+ void appearance_dialog_clicked ();
+
+ void setup_sensitivity ();
+
+ wxCheckBox* _reference;
+ wxStaticText* _reference_note;
+ wxCheckBox* _use;
+ wxChoice* _type;
+ wxCheckBox* _burn;
+ wxSpinCtrl* _x_offset;
+ wxSpinCtrl* _y_offset;
+ wxSpinCtrl* _x_scale;
+ wxSpinCtrl* _y_scale;
+ wxSpinCtrl* _line_spacing;
+ wxTextCtrl* _language;
+ wxChoice* _stream;
+ wxButton* _caption_view_button;
+ TextView* _caption_view;
+ wxButton* _fonts_dialog_button;
+ FontsDialog* _fonts_dialog;
+ wxButton* _appearance_dialog_button;
+ TextType _original_type;
+};
--- /dev/null
+/*
+ Copyright (C) 2014-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/string_text_file_decoder.h"
+#include "lib/content_text.h"
+#include "lib/video_decoder.h"
+#include "lib/audio_decoder.h"
+#include "lib/film.h"
+#include "lib/config.h"
+#include "lib/string_text_file_content.h"
+#include "lib/text_decoder.h"
+#include "text_view.h"
+#include "film_viewer.h"
+#include "wx_util.h"
+
+using std::list;
+using boost::shared_ptr;
+using boost::bind;
+using boost::dynamic_pointer_cast;
+
+TextView::TextView (wxWindow* parent, shared_ptr<Film> film, shared_ptr<Content> content, shared_ptr<TextContent> caption, shared_ptr<Decoder> decoder, FilmViewer* viewer)
+ : wxDialog (parent, wxID_ANY, _("Captions"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+ , _content (content)
+ , _film_viewer (viewer)
+{
+ _list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);
+
+ {
+ wxListItem ip;
+ ip.SetId (0);
+ ip.SetText (_("Start"));
+ ip.SetWidth (100);
+ _list->InsertColumn (0, ip);
+ }
+
+ {
+ wxListItem ip;
+ ip.SetId (1);
+ ip.SetText (_("End"));
+ ip.SetWidth (100);
+ _list->InsertColumn (1, ip);
+ }
+
+ {
+ wxListItem ip;
+ ip.SetId (2);
+ ip.SetText (_("Caption"));
+ ip.SetWidth (640);
+ _list->InsertColumn (2, ip);
+ }
+
+ wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
+ sizer->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_X_GAP);
+
+ _list->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&TextView::subtitle_selected, this, _1));
+
+ wxSizer* buttons = CreateSeparatedButtonSizer (wxOK);
+ if (buttons) {
+ sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+ }
+
+ if (decoder->video) {
+ decoder->video->set_ignore (true);
+ }
+ if (decoder->audio) {
+ decoder->audio->set_ignore (true);
+ }
+
+ _subs = 0;
+ _frc = film->active_frame_rate_change (content->position());
+
+ /* Find the decoder that is being used for our TextContent and attach to it */
+ BOOST_FOREACH (shared_ptr<TextDecoder> i, decoder->caption) {
+ if (i->content() == caption) {
+ i->PlainStart.connect (bind (&TextView::data_start, this, _1));
+ i->Stop.connect (bind (&TextView::data_stop, this, _1));
+ }
+ }
+ while (!decoder->pass ()) {}
+ SetSizerAndFit (sizer);
+}
+
+void
+TextView::data_start (ContentStringText cts)
+{
+ BOOST_FOREACH (dcp::SubtitleString const & i, cts.subs) {
+ wxListItem list_item;
+ list_item.SetId (_subs);
+ _list->InsertItem (list_item);
+ _list->SetItem (_subs, 0, std_to_wx (cts.from().timecode (_frc->source)));
+ _list->SetItem (_subs, 2, std_to_wx (i.text ()));
+ _start_times.push_back (cts.from ());
+ ++_subs;
+ }
+
+ _last_count = cts.subs.size ();
+}
+
+void
+TextView::data_stop (ContentTime time)
+{
+ if (!_last_count) {
+ return;
+ }
+
+ for (int i = _subs - *_last_count; i < _subs; ++i) {
+ _list->SetItem (i, 1, std_to_wx (time.timecode (_frc->source)));
+ }
+}
+
+void
+TextView::subtitle_selected (wxListEvent& ev)
+{
+ if (!Config::instance()->jump_to_selected ()) {
+ return;
+ }
+
+ DCPOMATIC_ASSERT (ev.GetIndex() < int(_start_times.size()));
+ shared_ptr<Content> locked = _content.lock ();
+ DCPOMATIC_ASSERT (locked);
+ _film_viewer->set_position (locked, _start_times[ev.GetIndex()]);
+}
--- /dev/null
+/*
+ Copyright (C) 2014-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/content_text.h"
+#include <boost/shared_ptr.hpp>
+#include <wx/wx.h>
+#include <wx/listctrl.h>
+
+class Decoder;
+class FilmViewer;
+
+class TextView : public wxDialog
+{
+public:
+ TextView (
+ wxWindow *, boost::shared_ptr<Film>, boost::shared_ptr<Content> content, boost::shared_ptr<TextContent> caption, boost::shared_ptr<Decoder>, FilmViewer* viewer
+ );
+
+private:
+ void data_start (ContentStringText cts);
+ void data_stop (ContentTime time);
+ void subtitle_selected (wxListEvent &);
+
+ wxListCtrl* _list;
+ int _subs;
+ boost::optional<FrameRateChange> _frc;
+ boost::optional<int> _last_count;
+ std::vector<ContentTime> _start_times;
+ boost::weak_ptr<Content> _content;
+ FilmViewer* _film_viewer;
+};
#include "lib/image_content.h"
#include "lib/timer.h"
#include "lib/audio_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/video_content.h"
#include "lib/atmos_mxf_content.h"
#include <wx/graphics.h>
_views.push_back (shared_ptr<TimelineView> (new TimelineAudioContentView (*this, i)));
}
- BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->caption) {
_views.push_back (shared_ptr<TimelineView> (new TimelineTextContentView (*this, i, j)));
}
*/
#include "timeline_text_content_view.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/content.h"
using boost::shared_ptr;
-TimelineTextContentView::TimelineTextContentView (Timeline& tl, shared_ptr<Content> c, shared_ptr<CaptionContent> caption)
+TimelineTextContentView::TimelineTextContentView (Timeline& tl, shared_ptr<Content> c, shared_ptr<TextContent> caption)
: TimelineContentView (tl, c)
, _caption (caption)
{
#include "timeline_content_view.h"
class TextContent;
-class CaptionContent;
+class TextContent;
/** @class TimelineTextContentView
* @brief Timeline view for TextContent.
class TimelineTextContentView : public TimelineContentView
{
public:
- TimelineTextContentView (Timeline& tl, boost::shared_ptr<Content>, boost::shared_ptr<CaptionContent>);
+ TimelineTextContentView (Timeline& tl, boost::shared_ptr<Content>, boost::shared_ptr<TextContent>);
private:
bool active () const;
wxColour background_colour () const;
wxColour foreground_colour () const;
- boost::shared_ptr<CaptionContent> _caption;
+ boost::shared_ptr<TextContent> _caption;
};
#include "move_to_dialog.h"
#include "lib/content.h"
#include "lib/image_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/dcp_subtitle_content.h"
#include "lib/audio_content.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/video_content.h"
#include <dcp/locale_convert.h>
#include <boost/foreach.hpp>
audio_panel.cc
audio_plot.cc
batch_job_view.cc
- caption_appearance_dialog.cc
- caption_panel.cc
- caption_view.cc
+ subtitle_appearance_dialog.cc
+ text_panel.cc
+ text_view.cc
cinema_dialog.cc
colour_conversion_editor.cc
config_dialog.cc
film->set_container (Ratio::from_id ("185"));
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
- shared_ptr<TextCaption> content (new TextCaption (film, "test/data/subrip2.srt"));
+ shared_ptr<StringText> content (new StringText (film, "test/data/subrip2.srt"));
content->subtitle->set_use (true);
content->subtitle->set_burn (true);
film->examine_and_add_content (content);
film2->set_name ("frobozz");
shared_ptr<DCPContent> background_dcp (new DCPContent(film2, film->dir(film->dcp_name())));
film2->examine_and_add_content (background_dcp);
- shared_ptr<TextCaption> sub = dynamic_pointer_cast<TextCaption> (
+ shared_ptr<StringText> sub = dynamic_pointer_cast<StringText> (
content_factory(film2, "test/data/subrip2.srt").front()
);
sub->subtitle->set_burn (true);
*/
#include "lib/film.h"
-#include "lib/caption_content.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/text_content.h"
+#include "lib/string_text_file_content.h"
#include "test.h"
#include <dcp/dcp.h>
#include <dcp/cpl.h>
BOOST_AUTO_TEST_CASE (closed_caption_test1)
{
shared_ptr<Film> film = new_test_film2 ("closed_caption_test1");
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
#include "lib/dcp_decoder.h"
#include "lib/dcp_content_type.h"
#include "lib/dcp_subtitle_decoder.h"
-#include "lib/caption_content.h"
-#include "lib/content_caption.h"
+#include "lib/text_content.h"
+#include "lib/content_text.h"
#include "lib/font.h"
-#include "lib/caption_decoder.h"
+#include "lib/text_decoder.h"
#include "test.h"
#include <iostream>
using boost::shared_ptr;
using boost::optional;
-optional<ContentTextCaption> stored;
+optional<ContentStringText> stored;
static void
-store (ContentTextCaption sub)
+store (ContentStringText sub)
{
if (!stored) {
stored = sub;
shared_ptr<DCPDecoder> decoder (new DCPDecoder (content, film->log(), false));
decoder->only_caption()->PlainStart.connect (bind (store, _1));
- stored = optional<ContentTextCaption> ();
+ stored = optional<ContentStringText> ();
while (!decoder->pass() && !stored) {}
BOOST_REQUIRE (stored);
shared_ptr<DCPSubtitleDecoder> decoder (new DCPSubtitleDecoder (content, film->log()));
decoder->only_caption()->PlainStart.connect (bind (store, _1));
- stored = optional<ContentTextCaption> ();
+ stored = optional<ContentStringText> ();
while (!decoder->pass ()) {
if (stored && stored->from() == ContentTime(0)) {
BOOST_CHECK_EQUAL (stored->subs.front().text(), "<b>Hello world!</b>");
BOOST_REQUIRE (!wait_for_jobs ());
shared_ptr<DCPSubtitleDecoder> decoder (new DCPSubtitleDecoder (content, film->log()));
- stored = optional<ContentTextCaption> ();
+ stored = optional<ContentStringText> ();
while (!decoder->pass ()) {
decoder->only_caption()->PlainStart.connect (bind (store, _1));
if (stored && stored->from() == ContentTime::from_seconds(0.08)) {
#include "lib/image_content.h"
#include "lib/video_content.h"
#include "lib/audio_content.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/ratio.h"
#include "lib/transcode_job.h"
#include "lib/dcp_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/compose.hpp"
#include "test.h"
#include <boost/test/unit_test.hpp>
film->set_container (Ratio::from_id ("185"));
film->set_audio_channels (6);
- shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
+ shared_ptr<StringTextFileContent> s (new StringTextFileContent (film, "test/data/subrip2.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
s->only_caption()->set_colour (dcp::Colour (255, 255, 0));
film->examine_and_add_content (c);
BOOST_REQUIRE (!wait_for_jobs ());
- shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip.srt"));
+ shared_ptr<StringTextFileContent> s (new StringTextFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
s->only_caption()->set_colour (dcp::Colour (255, 255, 0));
film->set_container (Ratio::from_id ("185"));
film->set_audio_channels (6);
- shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
+ shared_ptr<StringTextFileContent> s (new StringTextFileContent (film, "test/data/subrip2.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
s->only_caption()->set_colour (dcp::Colour (255, 255, 0));
film->examine_and_add_content (c);
BOOST_REQUIRE (!wait_for_jobs ());
- shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip.srt"));
+ shared_ptr<StringTextFileContent> s (new StringTextFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
s->only_caption()->set_colour (dcp::Colour (255, 255, 0));
#include "lib/player.h"
#include "lib/video_content.h"
#include "lib/image_content.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/content_factory.h"
#include "lib/dcp_content.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/butler.h"
#include "lib/compose.hpp"
#include "test.h"
film->examine_and_add_content (c);
BOOST_REQUIRE (!wait_for_jobs ());
- shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip.srt"));
+ shared_ptr<StringTextFileContent> s (new StringTextFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
#include "lib/dcp_content_type.h"
#include "lib/dcp_content.h"
#include "lib/video_content.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/content_factory.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
shared_ptr<Content> dcp (new DCPContent (film, "test/data/reels_test2"));
film->examine_and_add_content (dcp);
- shared_ptr<Content> sub (new TextCaptionFileContent (film, "test/data/subrip.srt"));
+ shared_ptr<Content> sub (new StringTextFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (sub);
wait_for_jobs ();
content[i]->video->set_length (24);
}
- shared_ptr<TextCaptionFileContent> subs (new TextCaptionFileContent (film, "test/data/subrip3.srt"));
+ shared_ptr<StringTextFileContent> subs (new StringTextFileContent (film, "test/data/subrip3.srt"));
film->examine_and_add_content (subs);
wait_for_jobs ();
#include "lib/ffmpeg_content.h"
#include "lib/content_factory.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/job_manager.h"
#include "lib/film.h"
#include "lib/dcp_content.h"
#include "lib/ffmpeg_content.h"
#include "lib/content_factory.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/film.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test.hpp>
static void
-add (std::list<TextCaption>& s, std::string text, bool italic, bool bold, bool underline)
+add (std::list<StringText>& s, std::string text, bool italic, bool bold, bool underline)
{
s.push_back (
- TextCaption (
+ StringText (
dcp::SubtitleString (
boost::optional<std::string> (),
italic,
/** Test marked_up() in render_text.cc */
BOOST_AUTO_TEST_CASE (render_markup_test1)
{
- std::list<TextCaption> s;
+ std::list<StringText> s;
add (s, "Hello", false, false, false);
BOOST_CHECK_EQUAL (marked_up (s, 1024, 1), "<span size=\"41472\" alpha=\"65535\" color=\"#FFFFFF\">Hello</span>");
}
/** Test marked_up() in render_text.cc */
BOOST_AUTO_TEST_CASE (render_markup_test2)
{
- std::list<TextCaption> s;
+ std::list<StringText> s;
add (s, "Hello", false, true, false);
BOOST_CHECK_EQUAL (marked_up (s, 1024, 1), "<span weight=\"bold\" size=\"41472\" alpha=\"65535\" color=\"#FFFFFF\">Hello</span>");
}
/** Test marked_up() in render_text.cc */
BOOST_AUTO_TEST_CASE (render_markup_test3)
{
- std::list<TextCaption> s;
+ std::list<StringText> s;
add (s, "Hello", true, true, false);
BOOST_CHECK_EQUAL (marked_up (s, 1024, 1), "<span style=\"italic\" weight=\"bold\" size=\"41472\" alpha=\"65535\" color=\"#FFFFFF\">Hello</span>");
}
/** Test marked_up() in render_text.cc */
BOOST_AUTO_TEST_CASE (render_markup_test4)
{
- std::list<TextCaption> s;
+ std::list<StringText> s;
add (s, "Hello", true, true, true);
BOOST_CHECK_EQUAL (marked_up (s, 1024, 1), "<span style=\"italic\" weight=\"bold\" underline=\"single\" size=\"41472\" alpha=\"65535\" color=\"#FFFFFF\">Hello</span>");
}
/** Test marked_up() in render_text.cc */
BOOST_AUTO_TEST_CASE (render_markup_test5)
{
- std::list<TextCaption> s;
+ std::list<StringText> s;
add (s, "Hello", false, true, false);
add (s, " world.", false, false, false);
BOOST_CHECK_EQUAL (marked_up (s, 1024, 1), "<span weight=\"bold\" size=\"41472\" alpha=\"65535\" color=\"#FFFFFF\">Hello</span><span size=\"41472\" alpha=\"65535\" color=\"#FFFFFF\"> world.</span>");
/** Test marked_up() in render_text.cc */
BOOST_AUTO_TEST_CASE (render_markup_test6)
{
- std::list<TextCaption> s;
+ std::list<StringText> s;
add (s, "Hello", true, false, false);
add (s, " world ", false, false, false);
add (s, "we are bold.", false, true, false);
*/
#include "lib/film.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/dcp_content_type.h"
#include "lib/font.h"
#include "lib/ratio.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
film->set_name ("frobozz");
film->set_audio_channels (6);
film->set_interop (false);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/subrip2.srt"));
film->examine_and_add_content (content);
wait_for_jobs ();
film->set_name ("frobozz");
film->set_audio_channels (6);
film->set_interop (false);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/subrip2.srt"));
film->examine_and_add_content (content);
wait_for_jobs ();
film->set_name ("frobozz");
film->set_interop (true);
film->set_audio_channels (6);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, private_data / "Ankoemmling_short.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, private_data / "Ankoemmling_short.srt"));
film->examine_and_add_content (content);
wait_for_jobs ();
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
film->set_interop (false);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/subrip2.srt"));
content->only_caption()->set_use (true);
content->only_caption()->set_burn (false);
film->examine_and_add_content (content);
film->set_name ("frobozz");
film->set_interop (true);
film->set_sequence (false);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/subrip2.srt"));
content->only_caption()->set_use (true);
content->only_caption()->set_burn (false);
film->examine_and_add_content (content);
{
shared_ptr<Film> film = new_test_film2 ("srt_subtitle_test6");
film->set_interop (false);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/frames.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/frames.srt"));
content->only_caption()->set_use (true);
content->only_caption()->set_burn (false);
film->examine_and_add_content (content);
BOOST_AUTO_TEST_CASE (srt_subtitle_test4)
{
shared_ptr<Film> film = new_test_film ("subrip_render_test");
- shared_ptr<TextCaptionFile> content (new TextCaptionFile (film, "test/data/subrip.srt"));
+ shared_ptr<StringTextFile> content (new StringTextFile (film, "test/data/subrip.srt"));
content->examine (shared_ptr<Job> (), true);
BOOST_CHECK_EQUAL (content->full_length(), DCPTime::from_seconds ((3 * 60) + 56.471));
shared_ptr<SubRipDecoder> decoder (new SubRipDecoder (content));
- list<ContentTextCaption> cts = decoder->get_plain_texts (
+ list<ContentStringText> cts = decoder->get_plain_texts (
ContentTimePeriod (
ContentTime::from_seconds (109), ContentTime::from_seconds (110)
), false
*/
#include "lib/film.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/dcp_content_type.h"
#include "lib/font.h"
#include "lib/ratio.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
film->set_interop (true);
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, private_data / "DKH_UT_EN20160601def.ssa"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, private_data / "DKH_UT_EN20160601def.ssa"));
film->examine_and_add_content (content);
wait_for_jobs ();
#include "lib/content.h"
#include "lib/film.h"
#include "lib/content_factory.h"
-#include "lib/text_caption_file.h"
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file.h"
+#include "lib/string_text_file_content.h"
#include <boost/test/unit_test.hpp>
using boost::shared_ptr;
shared_ptr<Content> content = content_factory (film, "test/data/osx.srt").front ();
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
- shared_ptr<TextCaptionFileContent> ts = dynamic_pointer_cast<TextCaptionFileContent> (content);
+ shared_ptr<StringTextFileContent> ts = dynamic_pointer_cast<StringTextFileContent> (content);
BOOST_REQUIRE (ts);
/* Make sure we got the subtitle data from the file */
BOOST_REQUIRE_EQUAL (content->full_length().get(), 6052032);
*/
-#include "lib/text_caption_file_content.h"
+#include "lib/string_text_file_content.h"
#include "lib/film.h"
#include "lib/ratio.h"
-#include "lib/caption_content.h"
+#include "lib/text_content.h"
#include "lib/dcp_content_type.h"
#include "test.h"
#include <dcp/cpl.h>
film->set_container (Ratio::from_id ("185"));
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
- shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip5.srt"));
+ shared_ptr<StringTextFileContent> content (new StringTextFileContent (film, "test/data/subrip5.srt"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
content->only_caption()->set_use (true);