#include "active_captions.h"
#include "piece.h"
-#include "text_content.h"
+#include "caption_content.h"
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
continue;
}
- if (!piece->content->subtitle->use() || (!always_burn_subtitles && !piece->content->subtitle->burn())) {
+ if (!piece->content->caption->use() || (!always_burn_subtitles && !piece->content->caption->burn())) {
/* Not burning this piece */
continue;
}
--- /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_TEXT_H
-#define DCPOMATIC_BITMAP_TEXT_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)
+ : 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 (CAPTION_OPEN)
+{
+
+}
+
+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 shared_ptr<CaptionContent> ();
+ }
+
+ /* Otherwise we can drop through to the newer logic */
+ }
+
+ if (!node->optional_number_child<double>("SubtitleXOffset") && !node->optional_number_child<double>("SubtitleOffset")) {
+ return shared_ptr<CaptionContent> ();
+ }
+
+ return shared_ptr<CaptionContent> (new CaptionContent (parent, node, version));
+}
+
+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)
+{
+ if (version >= 32) {
+ _use = node->bool_child ("UseSubtitles");
+ _burn = node->bool_child ("BurnSubtitles");
+ }
+
+ 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 >= 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 = node->optional_number_child<Frame>("SubtitleFadeIn");
+ if (fi) {
+ _fade_in = ContentTime (*fi);
+ }
+ optional<Frame> fo = node->optional_number_child<Frame>("SubtitleFadeOut");
+ if (fo) {
+ _fade_out = ContentTime (*fo);
+ }
+
+ _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("CaptionType").get_value_or("open"));
+}
+
+CaptionContent::CaptionContent (Content* parent, vector<shared_ptr<Content> > c)
+ : ContentPart (parent)
+{
+ shared_ptr<CaptionContent> ref = c[0]->caption;
+ DCPOMATIC_ASSERT (ref);
+ list<shared_ptr<Font> > ref_fonts = ref->fonts ();
+
+ for (size_t i = 1; i < c.size(); ++i) {
+
+ if (c[i]->caption->use() != ref->use()) {
+ throw JoinError (_("Content to be joined must have the same 'use subtitles' setting."));
+ }
+
+ if (c[i]->caption->burn() != ref->burn()) {
+ throw JoinError (_("Content to be joined must have the same 'burn subtitles' setting."));
+ }
+
+ if (c[i]->caption->x_offset() != ref->x_offset()) {
+ throw JoinError (_("Content to be joined must have the same subtitle X offset."));
+ }
+
+ if (c[i]->caption->y_offset() != ref->y_offset()) {
+ throw JoinError (_("Content to be joined must have the same subtitle Y offset."));
+ }
+
+ if (c[i]->caption->x_scale() != ref->x_scale()) {
+ throw JoinError (_("Content to be joined must have the same subtitle X scale."));
+ }
+
+ if (c[i]->caption->y_scale() != ref->y_scale()) {
+ throw JoinError (_("Content to be joined must have the same subtitle Y scale."));
+ }
+
+ if (c[i]->caption->line_spacing() != ref->line_spacing()) {
+ throw JoinError (_("Content to be joined must have the same subtitle line spacing."));
+ }
+
+ if ((c[i]->caption->fade_in() != ref->fade_in()) || (c[i]->caption->fade_out() != ref->fade_out())) {
+ throw JoinError (_("Content to be joined must have the same subtitle fades."));
+ }
+
+ if ((c[i]->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]->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 ();
+
+ connect_to_fonts ();
+}
+
+/** _mutex must not be held on entry */
+void
+CaptionContent::as_xml (xmlpp::Node* root) const
+{
+ boost::mutex::scoped_lock lm (_mutex);
+
+ root->add_child("UseSubtitles")->add_child_text (_use ? "1" : "0");
+ root->add_child("BurnSubtitles")->add_child_text (_burn ? "1" : "0");
+ root->add_child("SubtitleXOffset")->add_child_text (raw_convert<string> (_x_offset));
+ root->add_child("SubtitleYOffset")->add_child_text (raw_convert<string> (_y_offset));
+ root->add_child("SubtitleXScale")->add_child_text (raw_convert<string> (_x_scale));
+ root->add_child("SubtitleYScale")->add_child_text (raw_convert<string> (_y_scale));
+ root->add_child("SubtitleLanguage")->add_child_text (_language);
+ if (_colour) {
+ root->add_child("Red")->add_child_text (raw_convert<string> (_colour->r));
+ root->add_child("Green")->add_child_text (raw_convert<string> (_colour->g));
+ root->add_child("Blue")->add_child_text (raw_convert<string> (_colour->b));
+ }
+ if (_effect) {
+ switch (*_effect) {
+ case dcp::NONE:
+ root->add_child("Effect")->add_child_text("none");
+ break;
+ case dcp::BORDER:
+ root->add_child("Effect")->add_child_text("outline");
+ break;
+ case dcp::SHADOW:
+ root->add_child("Effect")->add_child_text("shadow");
+ break;
+ }
+ }
+ if (_effect_colour) {
+ root->add_child("EffectRed")->add_child_text (raw_convert<string> (_effect_colour->r));
+ root->add_child("EffectGreen")->add_child_text (raw_convert<string> (_effect_colour->g));
+ root->add_child("EffectBlue")->add_child_text (raw_convert<string> (_effect_colour->b));
+ }
+ root->add_child("LineSpacing")->add_child_text (raw_convert<string> (_line_spacing));
+ if (_fade_in) {
+ root->add_child("SubtitleFadeIn")->add_child_text (raw_convert<string> (_fade_in->get()));
+ }
+ if (_fade_out) {
+ root->add_child("SubtitleFadeOut")->add_child_text (raw_convert<string> (_fade_out->get()));
+ }
+ root->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 (root->add_child("Font"));
+ }
+
+ root->add_child("CaptionType")->add_child_text (caption_type_to_string(_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:
+ explicit CaptionContent (Content* parent);
+ 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;
+ }
+
+ static 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;
+ CaptionType _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 "text_content.h"
+#include "caption_content.h"
#include "exceptions.h"
#include "film.h"
#include "job.h"
if (audio && c->audio) {
audio->take_settings_from (c->audio);
}
- if (subtitle && c->subtitle) {
- subtitle->take_settings_from (c->subtitle);
+ if (caption && c->caption) {
+ caption->take_settings_from (c->caption);
}
}
boost::shared_ptr<VideoContent> video;
boost::shared_ptr<AudioContent> audio;
- boost::shared_ptr<TextContent> subtitle;
+ boost::shared_ptr<CaptionContent> caption;
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 "atmos_mxf_content.h"
#include "text_caption_file_content.h"
#include "dcp_content.h"
-#include "dcp_text_content.h"
+#include "dcp_subtitle_content.h"
#include "util.h"
#include "ffmpeg_audio_stream.h"
#include "video_mxf_content.h"
} else if (type == "DCP") {
content.reset (new DCPContent (film, node, version));
} else if (type == "DCPSubtitle") {
- content.reset (new DCPTextContent (film, node, version));
+ content.reset (new DCPSubtitleContent (film, node, version));
} else if (type == "VideoMXF") {
content.reset (new VideoMXFContent (film, node, version));
} else if (type == "AtmosMXF") {
if (doc.root_name() == "DCinemaSecurityMessage") {
throw KDMAsContentError ();
}
- single.reset (new DCPTextContent (film, path));
+ single.reset (new DCPSubtitleContent (film, path));
} else if (ext == ".mxf" && dcp::SMPTESubtitleAsset::valid_mxf (path)) {
- single.reset (new DCPTextContent (film, path));
+ single.reset (new DCPSubtitleContent (film, path));
} else if (ext == ".mxf" && VideoMXFContent::valid_mxf (path)) {
single.reset (new VideoMXFContent (film, path));
} else if (ext == ".mxf" && AtmosMXFContent::valid_mxf (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 ContentBitmapCaption : public ContentText
-{
-public:
- ContentBitmapCaption (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 ContentTextCaption : public ContentText
-{
-public:
- ContentTextCaption (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 "text_content.h"
+#include "caption_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);
- subtitle = TextContent::from_xml (this, node, version);
+ caption = CaptionContent::from_xml (this, node, version);
if (video && audio) {
audio->set_stream (
bool const needed_assets = needs_assets ();
bool const needed_kdm = needs_kdm ();
string const old_name = name ();
- bool had_subtitles = static_cast<bool> (subtitle);
+ bool had_subtitles = static_cast<bool> (caption);
if (job) {
job->set_progress_unknown ();
boost::mutex::scoped_lock lm (_mutex);
_name = examiner->name ();
if (examiner->has_subtitles ()) {
- subtitle.reset (new TextContent (this));
+ caption.reset (new CaptionContent (this));
} else {
- subtitle.reset ();
+ caption.reset ();
}
- has_subtitles = static_cast<bool> (subtitle);
+ has_subtitles = static_cast<bool> (caption);
_encrypted = examiner->encrypted ();
_needs_assets = examiner->needs_assets ();
_kdm_valid = examiner->kdm_valid ();
audio->stream()->mapping().as_xml (node->add_child("AudioMapping"));
}
- if (subtitle) {
- subtitle->as_xml (node);
+ if (caption) {
+ caption->as_xml (node);
}
boost::mutex::scoped_lock lm (_mutex);
s += video->identifier() + "_";
}
- if (subtitle) {
- s += subtitle->identifier () + " ";
+ if (caption) {
+ s += caption->identifier () + " ";
}
s += string (_reference_video ? "1" : "0") + string (_reference_subtitle ? "1" : "0");
}
/// TRANSLATORS: this string will follow "Cannot reference this DCP: "
- return can_reference (bind (&Content::subtitle, _1), _("it overlaps other subtitle content; remove the other content."), why_not);
+ return can_reference (bind (&Content::caption, _1), _("it overlaps other caption content; remove the other content."), why_not);
}
void
#include "video_decoder.h"
#include "audio_decoder.h"
#include "j2k_image_proxy.h"
-#include "text_decoder.h"
+#include "caption_decoder.h"
#include "image.h"
#include "config.h"
#include <dcp/dcp.h>
if (c->audio) {
audio.reset (new AudioDecoder (this, c->audio, log, fast));
}
- if (c->subtitle) {
+ if (c->caption) {
/* XXX: this time here should be the time of the first subtitle, not 0 */
- subtitle.reset (new TextDecoder (this, c->subtitle, log, ContentTime()));
+ caption.reset (new CaptionDecoder (this, c->caption, log, ContentTime()));
}
list<shared_ptr<dcp::CPL> > cpl_list = cpls ();
if (is) {
list<dcp::SubtitleString> s;
s.push_back (*is);
- subtitle->emit_plain (
+ caption->emit_plain (
ContentTimePeriod (
ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->in().as_seconds ()),
ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->out().as_seconds ())
#include "writer.h"
#include "compose.hpp"
#include "referenced_reel_asset.h"
-#include "text_content.h"
+#include "caption_content.h"
#include "player_video.h"
#include <boost/signals2.hpp>
#include <boost/foreach.hpp>
{
_player_video_connection = _player->Video.connect (bind (&DCPEncoder::video, this, _1, _2));
_player_audio_connection = _player->Audio.connect (bind (&DCPEncoder::audio, this, _1, _2));
- _player_text_connection = _player->Text.connect (bind (&DCPEncoder::text, this, _1, _2, _3));
+ _player_caption_connection = _player->Caption.connect (bind (&DCPEncoder::caption, this, _1, _2, _3));
BOOST_FOREACH (shared_ptr<const Content> c, film->content ()) {
- if (c->subtitle && c->subtitle->use() && !c->subtitle->burn()) {
+ if (c->caption && c->caption->use() && !c->caption->burn()) {
_non_burnt_subtitles = true;
}
}
/* We must stop receiving more video data before we die */
_player_video_connection.release ();
_player_audio_connection.release ();
- _player_text_connection.release ();
+ _player_caption_connection.release ();
}
void
}
void
-DCPEncoder::text (PlayerCaption data, TextType type, DCPTimePeriod period)
+DCPEncoder::caption (PlayerCaption data, CaptionType type, DCPTimePeriod period)
{
- if (type == TEXT_CLOSED_CAPTION || _non_burnt_subtitles) {
+ if (type == CAPTION_CLOSED || _non_burnt_subtitles) {
_writer->write (data, type, period);
}
}
void video (boost::shared_ptr<PlayerVideo>, DCPTime);
void audio (boost::shared_ptr<AudioBuffers>, DCPTime);
- void text (PlayerCaption, TextType, DCPTimePeriod);
+ void caption (PlayerCaption, CaptionType, DCPTimePeriod);
boost::shared_ptr<Writer> _writer;
boost::shared_ptr<J2KEncoder> _j2k_encoder;
boost::signals2::scoped_connection _player_video_connection;
boost::signals2::scoped_connection _player_audio_connection;
- boost::signals2::scoped_connection _player_text_connection;
+ boost::signals2::scoped_connection _player_caption_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 "font.h"
+#include "dcp_subtitle_content.h"
+#include "film.h"
+#include "caption_content.h"
+#include <dcp/raw_convert.h>
+#include <dcp/interop_subtitle_asset.h>
+#include <dcp/smpte_subtitle_asset.h>
+#include <dcp/interop_load_font_node.h>
+#include <libxml++/libxml++.h>
+#include <boost/foreach.hpp>
+
+#include "i18n.h"
+
+using std::string;
+using std::list;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using dcp::raw_convert;
+
+DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, boost::filesystem::path path)
+ : Content (film, path)
+{
+ caption.reset (new CaptionContent (this));
+}
+
+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);
+}
+
+void
+DCPSubtitleContent::examine (shared_ptr<Job> job)
+{
+ Content::examine (job);
+
+ shared_ptr<dcp::SubtitleAsset> sc = load (path (0));
+
+ shared_ptr<dcp::InteropSubtitleAsset> iop = dynamic_pointer_cast<dcp::InteropSubtitleAsset> (sc);
+ shared_ptr<dcp::SMPTESubtitleAsset> smpte = dynamic_pointer_cast<dcp::SMPTESubtitleAsset> (sc);
+ if (smpte) {
+ set_video_frame_rate (smpte->edit_rate().numerator);
+ }
+
+ boost::mutex::scoped_lock lm (_mutex);
+
+ /* Default to turning these subtitles on */
+ caption->set_use (true);
+
+ if (iop) {
+ caption->set_language (iop->language ());
+ } else if (smpte) {
+ caption->set_language (smpte->language().get_value_or (""));
+ }
+
+ _length = ContentTime::from_seconds (sc->latest_subtitle_out().as_seconds ());
+
+ BOOST_FOREACH (shared_ptr<dcp::LoadFontNode> i, sc->load_font_nodes ()) {
+ caption->add_font (shared_ptr<Font> (new Font (i->id)));
+ }
+}
+
+DCPTime
+DCPSubtitleContent::full_length () const
+{
+ FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate());
+ return DCPTime (_length, frc);
+}
+
+string
+DCPSubtitleContent::summary () const
+{
+ return path_summary() + " " + _("[subtitles]");
+}
+
+string
+DCPSubtitleContent::technical_summary () const
+{
+ return Content::technical_summary() + " - " + _("DCP XML subtitles");
+}
+
+void
+DCPSubtitleContent::as_xml (xmlpp::Node* node, bool with_paths) const
+{
+ node->add_child("Type")->add_child_text ("DCPSubtitle");
+ Content::as_xml (node, with_paths);
+
+ if (caption) {
+ caption->as_xml (node);
+ }
+
+ node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ()));
+}
--- /dev/null
+/*
+ Copyright (C) 2014-2016 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 "dcp_subtitle.h"
+#include "content.h"
+
+class DCPSubtitleContent : public DCPSubtitle, public Content
+{
+public:
+ DCPSubtitleContent (boost::shared_ptr<const Film>, boost::filesystem::path);
+ DCPSubtitleContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
+
+ void examine (boost::shared_ptr<Job>);
+ std::string summary () const;
+ std::string technical_summary () const;
+ 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 "dcp_subtitle_decoder.h"
+#include "dcp_subtitle_content.h"
+#include <dcp/interop_subtitle_asset.h>
+#include <iostream>
+
+using std::list;
+using std::cout;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using boost::bind;
+
+DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr<const DCPSubtitleContent> content, shared_ptr<Log> log)
+{
+ shared_ptr<dcp::SubtitleAsset> c (load (content->path (0)));
+ _subtitles = c->subtitles ();
+ _next = _subtitles.begin ();
+
+ ContentTime first;
+ if (_next != _subtitles.end()) {
+ first = content_time_period(*_next).from;
+ }
+ caption.reset (new CaptionDecoder (this, content->caption, log, first));
+}
+
+void
+DCPSubtitleDecoder::seek (ContentTime time, bool accurate)
+{
+ Decoder::seek (time, accurate);
+
+ _next = _subtitles.begin ();
+ list<shared_ptr<dcp::Subtitle> >::const_iterator i = _subtitles.begin ();
+ while (i != _subtitles.end() && ContentTime::from_seconds ((*_next)->in().as_seconds()) < time) {
+ ++i;
+ }
+}
+
+bool
+DCPSubtitleDecoder::pass ()
+{
+ if (_next == _subtitles.end ()) {
+ return true;
+ }
+
+ /* 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
+ time of emit the first.
+ */
+
+ list<dcp::SubtitleString> s;
+ ContentTimePeriod const p = content_time_period (*_next);
+
+ while (_next != _subtitles.end () && content_time_period (*_next) == p) {
+ shared_ptr<dcp::SubtitleString> ns = dynamic_pointer_cast<dcp::SubtitleString>(*_next);
+ if (ns) {
+ s.push_back (*ns);
+ ++_next;
+ }
+
+ /* XXX: image subtitles */
+ }
+
+ caption->emit_plain (p, s);
+ return false;
+}
+
+ContentTimePeriod
+DCPSubtitleDecoder::content_time_period (shared_ptr<dcp::Subtitle> s) const
+{
+ return ContentTimePeriod (
+ ContentTime::from_seconds (s->in().as_seconds ()),
+ ContentTime::from_seconds (s->out().as_seconds ())
+ );
+}
--- /dev/null
+/*
+ Copyright (C) 2014 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 "dcp_subtitle.h"
+
+class DCPSubtitleContent;
+
+class DCPSubtitleDecoder : public DCPSubtitle, public Decoder
+{
+public:
+ DCPSubtitleDecoder (boost::shared_ptr<const DCPSubtitleContent>, boost::shared_ptr<Log> log);
+
+ bool pass ();
+ void seek (ContentTime time, bool accurate);
+
+private:
+ ContentTimePeriod content_time_period (boost::shared_ptr<dcp::Subtitle> s) const;
+
+ std::list<boost::shared_ptr<dcp::Subtitle> > _subtitles;
+ std::list<boost::shared_ptr<dcp::Subtitle> >::const_iterator _next;
+};
+++ /dev/null
-/*
- Copyright (C) 2014-2015 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 "font.h"
-#include "dcp_text_content.h"
-#include "film.h"
-#include "text_content.h"
-#include <dcp/raw_convert.h>
-#include <dcp/interop_subtitle_asset.h>
-#include <dcp/smpte_subtitle_asset.h>
-#include <dcp/interop_load_font_node.h>
-#include <libxml++/libxml++.h>
-#include <boost/foreach.hpp>
-
-#include "i18n.h"
-
-using std::string;
-using std::list;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using dcp::raw_convert;
-
-DCPTextContent::DCPTextContent (shared_ptr<const Film> film, boost::filesystem::path path)
- : Content (film, path)
-{
- subtitle.reset (new TextContent (this));
-}
-
-DCPTextContent::DCPTextContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
- : Content (film, node)
- , _length (node->number_child<ContentTime::Type> ("Length"))
-{
- subtitle = TextContent::from_xml (this, node, version);
-}
-
-void
-DCPTextContent::examine (shared_ptr<Job> job)
-{
- Content::examine (job);
-
- shared_ptr<dcp::SubtitleAsset> sc = load (path (0));
-
- shared_ptr<dcp::InteropSubtitleAsset> iop = dynamic_pointer_cast<dcp::InteropSubtitleAsset> (sc);
- shared_ptr<dcp::SMPTESubtitleAsset> smpte = dynamic_pointer_cast<dcp::SMPTESubtitleAsset> (sc);
- if (smpte) {
- set_video_frame_rate (smpte->edit_rate().numerator);
- }
-
- boost::mutex::scoped_lock lm (_mutex);
-
- /* Default to turning these subtitles on */
- subtitle->set_use (true);
-
- if (iop) {
- subtitle->set_language (iop->language ());
- } else if (smpte) {
- subtitle->set_language (smpte->language().get_value_or (""));
- }
-
- _length = ContentTime::from_seconds (sc->latest_subtitle_out().as_seconds ());
-
- BOOST_FOREACH (shared_ptr<dcp::LoadFontNode> i, sc->load_font_nodes ()) {
- subtitle->add_font (shared_ptr<Font> (new Font (i->id)));
- }
-}
-
-DCPTime
-DCPTextContent::full_length () const
-{
- FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate());
- return DCPTime (_length, frc);
-}
-
-string
-DCPTextContent::summary () const
-{
- return path_summary() + " " + _("[subtitles]");
-}
-
-string
-DCPTextContent::technical_summary () const
-{
- return Content::technical_summary() + " - " + _("DCP XML subtitles");
-}
-
-void
-DCPTextContent::as_xml (xmlpp::Node* node, bool with_paths) const
-{
- node->add_child("Type")->add_child_text ("DCPSubtitle");
- Content::as_xml (node, with_paths);
-
- if (subtitle) {
- subtitle->as_xml (node);
- }
-
- node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ()));
-}
+++ /dev/null
-/*
- Copyright (C) 2014-2016 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 "dcp_subtitle.h"
-#include "content.h"
-
-class DCPTextContent : public DCPSubtitle, public Content
-{
-public:
- DCPTextContent (boost::shared_ptr<const Film>, boost::filesystem::path);
- DCPTextContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int);
-
- 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 "dcp_text_decoder.h"
-#include "dcp_text_content.h"
-#include <dcp/interop_subtitle_asset.h>
-#include <iostream>
-
-using std::list;
-using std::cout;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::bind;
-
-DCPTextDecoder::DCPTextDecoder (shared_ptr<const DCPTextContent> content, shared_ptr<Log> log)
-{
- shared_ptr<dcp::SubtitleAsset> c (load (content->path (0)));
- _subtitles = c->subtitles ();
- _next = _subtitles.begin ();
-
- ContentTime first;
- if (_next != _subtitles.end()) {
- first = content_time_period(*_next).from;
- }
- subtitle.reset (new TextDecoder (this, content->subtitle, log, first));
-}
-
-void
-DCPTextDecoder::seek (ContentTime time, bool accurate)
-{
- Decoder::seek (time, accurate);
-
- _next = _subtitles.begin ();
- list<shared_ptr<dcp::Subtitle> >::const_iterator i = _subtitles.begin ();
- while (i != _subtitles.end() && ContentTime::from_seconds ((*_next)->in().as_seconds()) < time) {
- ++i;
- }
-}
-
-bool
-DCPTextDecoder::pass ()
-{
- if (_next == _subtitles.end ()) {
- return true;
- }
-
- /* 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
- TextDecoder will assume there is nothing else at the
- time of emit the first.
- */
-
- list<dcp::SubtitleString> s;
- ContentTimePeriod const p = content_time_period (*_next);
-
- while (_next != _subtitles.end () && content_time_period (*_next) == p) {
- shared_ptr<dcp::SubtitleString> ns = dynamic_pointer_cast<dcp::SubtitleString>(*_next);
- if (ns) {
- s.push_back (*ns);
- ++_next;
- }
-
- /* XXX: image subtitles */
- }
-
- subtitle->emit_plain (p, s);
- return false;
-}
-
-ContentTimePeriod
-DCPTextDecoder::content_time_period (shared_ptr<dcp::Subtitle> s) const
-{
- return ContentTimePeriod (
- ContentTime::from_seconds (s->in().as_seconds ()),
- ContentTime::from_seconds (s->out().as_seconds ())
- );
-}
+++ /dev/null
-/*
- Copyright (C) 2014 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 "dcp_subtitle.h"
-
-class DCPTextContent;
-
-class DCPTextDecoder : public DCPSubtitle, public Decoder
-{
-public:
- DCPTextDecoder (boost::shared_ptr<const DCPTextContent>, boost::shared_ptr<Log> log);
-
- bool pass ();
- void seek (ContentTime time, bool accurate);
-
-private:
- ContentTimePeriod content_time_period (boost::shared_ptr<dcp::Subtitle> s) const;
-
- std::list<boost::shared_ptr<dcp::Subtitle> > _subtitles;
- std::list<boost::shared_ptr<dcp::Subtitle> >::const_iterator _next;
-};
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "decoder.h"
#include "video_decoder.h"
#include "audio_decoder.h"
-#include "text_decoder.h"
+#include "caption_decoder.h"
#include <boost/optional.hpp>
#include <iostream>
pos = audio->position();
}
- if (subtitle && !subtitle->ignore() && (!pos || subtitle->position() < *pos)) {
- pos = subtitle->position();
+ if (caption && !caption->ignore() && (!pos || caption->position() < *pos)) {
+ pos = caption->position();
}
return pos.get_value_or(ContentTime());
if (audio) {
audio->seek ();
}
- if (subtitle) {
- subtitle->seek ();
+ if (caption) {
+ caption->seek ();
}
}
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
class Decoded;
class VideoDecoder;
class AudioDecoder;
-class TextDecoder;
+class CaptionDecoder;
class DecoderPart;
/** @class Decoder.
boost::shared_ptr<VideoDecoder> video;
boost::shared_ptr<AudioDecoder> audio;
- boost::shared_ptr<TextDecoder> subtitle;
+ boost::shared_ptr<CaptionDecoder> caption;
/** 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 "image_decoder.h"
#include "text_caption_file_content.h"
#include "text_caption_file_decoder.h"
-#include "dcp_text_content.h"
-#include "dcp_text_decoder.h"
+#include "dcp_subtitle_content.h"
+#include "dcp_subtitle_decoder.h"
#include "video_mxf_content.h"
#include "video_mxf_decoder.h"
#include <boost/foreach.hpp>
return shared_ptr<Decoder> (new TextCaptionFileDecoder (rc, log));
}
- shared_ptr<const DCPTextContent> dsc = dynamic_pointer_cast<const DCPTextContent> (content);
+ shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (content);
if (dsc) {
- return shared_ptr<Decoder> (new DCPTextDecoder (dsc, log));
+ return shared_ptr<Decoder> (new DCPSubtitleDecoder (dsc, log));
}
shared_ptr<const VideoMXFContent> vmc = dynamic_pointer_cast<const VideoMXFContent> (content);
#include "log.h"
#include "exceptions.h"
#include "frame_rate_change.h"
-#include "text_content.h"
+#include "caption_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);
- subtitle = TextContent::from_xml (this, node, version);
+ caption = CaptionContent::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) {
bool need_video = false;
bool need_audio = false;
- bool need_subtitle = false;
+ bool need_caption = false;
if (i != c.end ()) {
need_video = static_cast<bool> ((*i)->video);
need_audio = static_cast<bool> ((*i)->audio);
- need_subtitle = static_cast<bool> ((*i)->subtitle);
+ need_caption = static_cast<bool> ((*i)->caption);
}
while (i != c.end ()) {
if (need_audio != static_cast<bool> ((*i)->audio)) {
throw JoinError (_("Content to be joined must all have or not have audio"));
}
- if (need_subtitle != static_cast<bool> ((*i)->subtitle)) {
- throw JoinError (_("Content to be joined must all have or not have subtitles"));
+ if (need_caption != static_cast<bool> ((*i)->caption)) {
+ throw JoinError (_("Content to be joined must all have or not have captions"));
}
++i;
}
if (need_audio) {
audio.reset (new AudioContent (this, c));
}
- if (need_subtitle) {
- subtitle.reset (new TextContent (this, c));
+ if (need_caption) {
+ caption.reset (new CaptionContent (this, c));
}
shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]);
for (size_t i = 0; i < c.size(); ++i) {
shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c[i]);
- if (fc->subtitle && fc->subtitle->use() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) {
+ if (fc->caption && fc->caption->use() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) {
throw JoinError (_("Content to be joined must use the same subtitle stream."));
}
}
}
}
- if (subtitle) {
- subtitle->as_xml (node);
+ if (caption) {
+ caption->as_xml (node);
}
boost::mutex::scoped_lock lm (_mutex);
_subtitle_streams = examiner->subtitle_streams ();
if (!_subtitle_streams.empty ()) {
- subtitle.reset (new TextContent (this));
+ caption.reset (new CaptionContent (this));
_subtitle_stream = _subtitle_streams.front ();
}
s += "_" + video->identifier();
}
- if (subtitle && subtitle->use() && subtitle->burn()) {
- s += "_" + subtitle->identifier();
+ if (caption && caption->use() && caption->burn()) {
+ s += "_" + caption->identifier();
}
boost::mutex::scoped_lock lm (_mutex);
#include "util.h"
#include "log.h"
#include "ffmpeg_decoder.h"
-#include "text_decoder.h"
+#include "caption_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 "text_content.h"
+#include "caption_content.h"
#include "audio_content.h"
#include <dcp/subtitle_string.h>
#include <sub/ssa_reader.h>
audio.reset (new AudioDecoder (this, c->audio, log, fast));
}
- if (c->subtitle) {
+ if (c->caption) {
/* XXX: this time here should be the time of the first subtitle, not 0 */
- subtitle.reset (new TextDecoder (this, c->subtitle, log, ContentTime()));
+ caption.reset (new CaptionDecoder (this, c->caption, log, ContentTime()));
}
_next_time.resize (_format_context->nb_streams);
if (_video_stream && si == _video_stream.get() && !video->ignore()) {
decode_video_packet ();
- } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index(_format_context, si) && !subtitle->ignore()) {
+ } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index(_format_context, si) && !caption->ignore()) {
decode_subtitle_packet ();
} else {
decode_audio_packet ();
/* Stop any current subtitle, either at the time it was supposed to stop, or now if now is sooner */
if (_have_current_subtitle) {
if (_current_subtitle_to) {
- subtitle->emit_stop (min(*_current_subtitle_to, subtitle_period(sub).from + _pts_offset));
+ caption->emit_stop (min(*_current_subtitle_to, subtitle_period(sub).from + _pts_offset));
} else {
- subtitle->emit_stop (subtitle_period(sub).from + _pts_offset);
+ caption->emit_stop (subtitle_period(sub).from + _pts_offset);
}
_have_current_subtitle = false;
}
}
if (_current_subtitle_to) {
- subtitle->emit_stop (*_current_subtitle_to);
+ caption->emit_stop (*_current_subtitle_to);
}
avsubtitle_free (&sub);
static_cast<double> (rect->h) / target_height
);
- subtitle->emit_bitmap_start (from, image, scaled_rect);
+ caption->emit_bitmap_start (from, image, scaled_rect);
}
void
);
BOOST_FOREACH (sub::Subtitle const & i, sub::collect<list<sub::Subtitle> > (raw)) {
- subtitle->emit_plain_start (from, i);
+ caption->emit_plain_start (from, i);
}
}
#include "screen.h"
#include "audio_content.h"
#include "video_content.h"
-#include "text_content.h"
+#include "caption_content.h"
#include "ffmpeg_content.h"
#include "dcp_content.h"
#include "screen_kdm.h"
bool burnt_in = true;
BOOST_FOREACH (shared_ptr<Content> i, content ()) {
- if (!i->subtitle) {
+ if (!i->caption) {
continue;
}
- if (i->subtitle->use() && !i->subtitle->burn()) {
+ if (i->caption->use() && !i->caption->burn()) {
burnt_in = false;
}
}
/* Add {video,subtitle} content after any existing {video,subtitle} content */
if (c->video) {
c->set_position (_playlist->video_end ());
- } else if (c->subtitle) {
+ } else if (c->caption) {
c->set_position (_playlist->subtitle_end ());
}
ContentList cl = content ();
BOOST_FOREACH (shared_ptr<Content>& c, cl) {
- if (c->subtitle) {
- languages.insert (c->subtitle->language ());
+ if (c->caption) {
+ languages.insert (c->caption->language ());
}
}
#include "film.h"
#include "content.h"
#include "video_content.h"
-#include "text_content.h"
+#include "caption_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) {
- if (i->subtitle) {
- BOOST_FOREACH (shared_ptr<Font> j, i->subtitle->fonts ()) {
+ if (i->caption) {
+ BOOST_FOREACH (shared_ptr<Font> j, i->caption->fonts ()) {
for (int k = 0; k < FontFiles::VARIANTS; ++k) {
optional<boost::filesystem::path> const p = j->file (static_cast<FontFiles::Variant> (k));
if (p && boost::filesystem::file_size (p.get()) >= (640 * 1024)) {
+++ /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 "plain_text_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_PLAIN_TEXT_FILE_H
-#define DCPOMATIC_PLAIN_TEXT_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
#include "decoder.h"
#include "video_decoder.h"
#include "audio_decoder.h"
-#include "text_content.h"
-#include "text_decoder.h"
+#include "caption_content.h"
+#include "caption_decoder.h"
#include "ffmpeg_content.h"
#include "audio_content.h"
#include "dcp_decoder.h"
decoder->video->set_ignore (true);
}
- if (decoder->subtitle && _ignore_subtitle) {
- decoder->subtitle->set_ignore (true);
+ if (decoder->caption && _ignore_subtitle) {
+ decoder->caption->set_ignore (true);
}
shared_ptr<DCPDecoder> dcp = dynamic_pointer_cast<DCPDecoder> (decoder);
decoder->audio->Data.connect (bind (&Player::audio, this, weak_ptr<Piece> (piece), _1, _2));
}
- if (decoder->subtitle) {
- decoder->subtitle->BitmapStart.connect (bind (&Player::bitmap_text_start, this, weak_ptr<Piece> (piece), _1));
- decoder->subtitle->PlainStart.connect (bind (&Player::plain_text_start, this, weak_ptr<Piece> (piece), _1));
- decoder->subtitle->Stop.connect (bind (&Player::subtitle_stop, this, weak_ptr<Piece> (piece), _1, _2));
+ if (decoder->caption) {
+ decoder->caption->BitmapStart.connect (bind (&Player::bitmap_text_start, this, weak_ptr<Piece> (piece), _1));
+ decoder->caption->PlainStart.connect (bind (&Player::plain_text_start, this, weak_ptr<Piece> (piece), _1));
+ decoder->caption->Stop.connect (bind (&Player::subtitle_stop, this, weak_ptr<Piece> (piece), _1, _2));
}
}
property == AudioContentProperty::STREAMS ||
property == DCPContentProperty::NEEDS_ASSETS ||
property == DCPContentProperty::NEEDS_KDM ||
- property == TextContentProperty::COLOUR ||
- property == TextContentProperty::EFFECT ||
- property == TextContentProperty::EFFECT_COLOUR ||
+ property == CaptionContentProperty::COLOUR ||
+ property == CaptionContentProperty::EFFECT ||
+ property == CaptionContentProperty::EFFECT_COLOUR ||
property == FFmpegContentProperty::SUBTITLE_STREAM ||
property == FFmpegContentProperty::FILTERS
) {
Changed (property, frequent);
} else if (
- property == TextContentProperty::LINE_SPACING ||
- property == TextContentProperty::OUTLINE_WIDTH ||
- property == TextContentProperty::Y_SCALE ||
- property == TextContentProperty::FADE_IN ||
- property == TextContentProperty::FADE_OUT ||
+ property == CaptionContentProperty::LINE_SPACING ||
+ property == CaptionContentProperty::OUTLINE_WIDTH ||
+ property == CaptionContentProperty::Y_SCALE ||
+ property == CaptionContentProperty::FADE_IN ||
+ property == CaptionContentProperty::FADE_OUT ||
property == ContentProperty::VIDEO_FRAME_RATE ||
- property == TextContentProperty::USE ||
- property == TextContentProperty::X_OFFSET ||
- property == TextContentProperty::Y_OFFSET ||
- property == TextContentProperty::X_SCALE ||
- property == TextContentProperty::FONTS ||
+ property == CaptionContentProperty::USE ||
+ property == CaptionContentProperty::X_OFFSET ||
+ property == CaptionContentProperty::Y_OFFSET ||
+ property == CaptionContentProperty::X_SCALE ||
+ property == CaptionContentProperty::FONTS ||
property == VideoContentProperty::CROP ||
property == VideoContentProperty::SCALE ||
property == VideoContentProperty::FADE_IN ||
}
list<PositionImage>
-Player::transform_bitmap_texts (list<BitmapText> subs) const
+Player::transform_bitmap_captions (list<BitmapCaption> subs) const
{
list<PositionImage> all;
- for (list<BitmapText>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
+ for (list<BitmapCaption>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
if (!i->image) {
continue;
}
list<shared_ptr<Font> > fonts;
BOOST_FOREACH (shared_ptr<Piece>& p, _pieces) {
- if (p->content->subtitle) {
+ if (p->content->caption) {
/* XXX: things may go wrong if there are duplicate font IDs
with different font files.
*/
- list<shared_ptr<Font> > f = p->content->subtitle->fonts ();
+ list<shared_ptr<Font> > f = p->content->caption->fonts ();
copy (f.begin(), f.end(), back_inserter (fonts));
}
}
/* Given two choices at the same time, pick the one with a subtitle so we see it before
the video.
*/
- if (!earliest_time || t < *earliest_time || (t == *earliest_time && i->decoder->subtitle)) {
+ if (!earliest_time || t < *earliest_time || (t == *earliest_time && i->decoder->caption)) {
earliest_time = t;
earliest_content = i;
}
int const vfr = _film->video_frame_rate();
- BOOST_FOREACH (PlayerCaption i, _active_text[TEXT_SUBTITLE].get_burnt (DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), _always_burn_subtitles)) {
+ BOOST_FOREACH (PlayerCaption i, _active_captions[CAPTION_OPEN].get_burnt (DCPTimePeriod(time, time + DCPTime::from_frames(1, vfr)), _always_burn_subtitles)) {
/* Image subtitles */
- list<PositionImage> c = transform_bitmap_texts (i.image);
+ list<PositionImage> c = transform_bitmap_captions (i.image);
copy (c.begin(), c.end(), back_inserter (subtitles));
/* Text subtitles (rendered to an image) */
}
/* Apply content's subtitle offsets */
- subtitle.sub.rectangle.x += piece->content->subtitle->x_offset ();
- subtitle.sub.rectangle.y += piece->content->subtitle->y_offset ();
+ subtitle.sub.rectangle.x += piece->content->caption->x_offset ();
+ subtitle.sub.rectangle.y += piece->content->caption->y_offset ();
/* Apply a corrective translation to keep the subtitle centred after the scale that is coming up */
- subtitle.sub.rectangle.x -= subtitle.sub.rectangle.width * ((piece->content->subtitle->x_scale() - 1) / 2);
- subtitle.sub.rectangle.y -= subtitle.sub.rectangle.height * ((piece->content->subtitle->y_scale() - 1) / 2);
+ subtitle.sub.rectangle.x -= subtitle.sub.rectangle.width * ((piece->content->caption->x_scale() - 1) / 2);
+ subtitle.sub.rectangle.y -= subtitle.sub.rectangle.height * ((piece->content->caption->y_scale() - 1) / 2);
/* Apply content's subtitle scale */
- subtitle.sub.rectangle.width *= piece->content->subtitle->x_scale ();
- subtitle.sub.rectangle.height *= piece->content->subtitle->y_scale ();
+ subtitle.sub.rectangle.width *= piece->content->caption->x_scale ();
+ subtitle.sub.rectangle.height *= piece->content->caption->y_scale ();
PlayerCaption ps;
ps.image.push_back (subtitle.sub);
DCPTime from (content_time_to_dcp (piece, subtitle.from()));
- _active_text[subtitle.type()].add_from (wp, ps, from);
+ _active_captions[subtitle.type()].add_from (wp, ps, from);
}
void
}
BOOST_FOREACH (dcp::SubtitleString s, subtitle.subs) {
- s.set_h_position (s.h_position() + piece->content->subtitle->x_offset ());
- s.set_v_position (s.v_position() + piece->content->subtitle->y_offset ());
- float const xs = piece->content->subtitle->x_scale();
- float const ys = piece->content->subtitle->y_scale();
+ s.set_h_position (s.h_position() + piece->content->caption->x_offset ());
+ s.set_v_position (s.v_position() + piece->content->caption->y_offset ());
+ float const xs = piece->content->caption->x_scale();
+ float const ys = piece->content->caption->y_scale();
float size = s.size();
/* Adjust size to express the common part of the scaling;
}
s.set_in (dcp::Time(from.seconds(), 1000));
- ps.text.push_back (TextCaption (s, piece->content->subtitle->outline_width()));
- ps.add_fonts (piece->content->subtitle->fonts ());
+ ps.text.push_back (TextCaption (s, piece->content->caption->outline_width()));
+ ps.add_fonts (piece->content->caption->fonts ());
}
- _active_text[subtitle.type()].add_from (wp, ps, from);
+ _active_captions[subtitle.type()].add_from (wp, ps, from);
}
void
-Player::subtitle_stop (weak_ptr<Piece> wp, ContentTime to, TextType type)
+Player::subtitle_stop (weak_ptr<Piece> wp, ContentTime to, CaptionType type)
{
- if (!_active_text[type].have (wp)) {
+ if (!_active_captions[type].have (wp)) {
return;
}
return;
}
- pair<PlayerCaption, DCPTime> from = _active_text[type].add_to (wp, dcp_to);
+ pair<PlayerCaption, DCPTime> from = _active_captions[type].add_to (wp, dcp_to);
- if (piece->content->subtitle->use() && !_always_burn_subtitles && !piece->content->subtitle->burn()) {
- Text (from.first, type, DCPTimePeriod (from.second, dcp_to));
+ if (piece->content->caption->use() && !_always_burn_subtitles && !piece->content->caption->burn()) {
+ Caption (from.first, type, DCPTimePeriod (from.second, dcp_to));
}
}
}
_audio_merger.clear ();
- for (int i = 0; i < TEXT_COUNT; ++i) {
- _active_text[i].clear ();
+ for (int i = 0; i < CAPTION_COUNT; ++i) {
+ _active_captions[i].clear ();
}
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
Player::do_emit_video (shared_ptr<PlayerVideo> pv, DCPTime time)
{
if (pv->eyes() == EYES_BOTH || pv->eyes() == EYES_RIGHT) {
- for (int i = 0; i < TEXT_COUNT; ++i) {
- _active_text[i].clear_before (time);
+ for (int i = 0; i < CAPTION_COUNT; ++i) {
+ _active_captions[i].clear_before (time);
}
}
#include "player_caption.h"
#include "active_captions.h"
-#include "content_text.h"
+#include "content_caption.h"
#include "film.h"
#include "content.h"
#include "position_image.h"
/** Emitted when a caption is ready. This signal may be emitted considerably
* after the corresponding Video.
*/
- boost::signals2::signal<void (PlayerCaption, TextType, DCPTimePeriod)> Text;
+ boost::signals2::signal<void (PlayerCaption, CaptionType, 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_texts (std::list<BitmapText>) const;
+ std::list<PositionImage> transform_bitmap_captions (std::list<BitmapCaption>) 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;
void audio (boost::weak_ptr<Piece>, AudioStreamPtr, ContentAudio);
void bitmap_text_start (boost::weak_ptr<Piece>, ContentBitmapCaption);
void plain_text_start (boost::weak_ptr<Piece>, ContentTextCaption);
- void subtitle_stop (boost::weak_ptr<Piece>, ContentTime, TextType);
+ void subtitle_stop (boost::weak_ptr<Piece>, ContentTime, CaptionType);
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_text[TEXT_COUNT];
+ ActiveCaptions _active_captions[CAPTION_COUNT];
boost::shared_ptr<AudioProcessor> _audio_processor;
boost::signals2::scoped_connection _film_changed_connection;
*/
-#ifndef DCPOMATIC_PLAYER_TEXT_H
-#define DCPOMATIC_PLAYER_TEXT_H
+#ifndef DCPOMATIC_PLAYER_CAPTION_H
+#define DCPOMATIC_PLAYER_CAPTION_H
-#include "bitmap_text.h"
+#include "bitmap_caption.h"
#include "dcpomatic_time.h"
#include "text_caption.h"
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;
+ /** BitmapCaptions, with their rectangles transformed as specified by their content */
+ std::list<BitmapCaption> image;
std::list<TextCaption> text;
};
/*
- Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "playlist.h"
#include "video_content.h"
-#include "text_content.h"
+#include "caption_content.h"
#include "ffmpeg_decoder.h"
#include "ffmpeg_content.h"
#include "image_decoder.h"
DCPTime next;
BOOST_FOREACH (shared_ptr<Content> i, _content) {
- if (!i->subtitle || find (placed.begin(), placed.end(), i) != placed.end()) {
+ if (!i->caption || find (placed.begin(), placed.end(), i) != placed.end()) {
continue;
}
string t;
BOOST_FOREACH (shared_ptr<const Content> i, _content) {
- if (i->video || (i->subtitle && i->subtitle->burn())) {
+ if (i->video || (i->caption && i->caption->burn())) {
t += i->identifier ();
}
}
{
DCPTime end;
BOOST_FOREACH (shared_ptr<Content> i, _content) {
- if (i->subtitle) {
+ if (i->caption) {
end = max (end, i->end ());
}
}
}
void
-ReelWriter::write (PlayerCaption subs, TextType type, DCPTimePeriod period)
+ReelWriter::write (PlayerCaption subs, CaptionType type, DCPTimePeriod period)
{
/* XXX: we need separate libdcp asset types here and to know how different they are */
_subtitle_asset->add (shared_ptr<dcp::Subtitle>(new dcp::SubtitleString(i)));
}
- BOOST_FOREACH (BitmapText i, subs.image) {
+ BOOST_FOREACH (BitmapCaption i, subs.image) {
_subtitle_asset->add (
shared_ptr<dcp::Subtitle>(
new dcp::SubtitleImage(
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, TextType type, DCPTimePeriod period);
+ void write (PlayerCaption text, CaptionType 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);
--- /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
#include "text_caption_file_content.h"
#include "util.h"
-#include "plain_text_file.h"
+#include "text_caption_file.h"
#include "film.h"
#include "font.h"
-#include "text_content.h"
+#include "caption_content.h"
#include <dcp/raw_convert.h>
#include <libxml++/libxml++.h>
#include <iostream>
TextCaptionFileContent::TextCaptionFileContent (shared_ptr<const Film> film, boost::filesystem::path path)
: Content (film, path)
{
- subtitle.reset (new TextContent (this));
+ caption.reset (new CaptionContent (this));
}
TextCaptionFileContent::TextCaptionFileContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
: Content (film, node)
, _length (node->number_child<ContentTime::Type> ("Length"))
{
- subtitle = TextContent::from_xml (this, node, version);
+ caption = CaptionContent::from_xml (this, node, version);
}
void
TextCaptionFile s (shared_from_this ());
/* Default to turning these subtitles on */
- subtitle->set_use (true);
+ caption->set_use (true);
boost::mutex::scoped_lock lm (_mutex);
_length = s.length ();
- subtitle->add_font (shared_ptr<Font> (new Font (TEXT_FONT_ID)));
+ caption->add_font (shared_ptr<Font> (new Font (TEXT_FONT_ID)));
}
string
node->add_child("Type")->add_child_text ("TextSubtitle");
Content::as_xml (node, with_paths);
- if (subtitle) {
- subtitle->as_xml (node);
+ if (caption) {
+ caption->as_xml (node);
}
node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ()));
#include "text_caption_file_decoder.h"
#include "text_caption_file_content.h"
-#include "text_content.h"
-#include "text_decoder.h"
+#include "caption_content.h"
+#include "caption_decoder.h"
#include <dcp/subtitle_string.h>
#include <boost/foreach.hpp>
#include <iostream>
if (!_subtitles.empty()) {
first = content_time_period(_subtitles[0]).from;
}
- subtitle.reset (new TextDecoder (this, content->subtitle, log, first));
+ caption.reset (new CaptionDecoder (this, content->caption, log, first));
}
void
}
ContentTimePeriod const p = content_time_period (_subtitles[_next]);
- subtitle->emit_plain (p, _subtitles[_next]);
+ caption->emit_plain (p, _subtitles[_next]);
++_next;
return false;
*/
-#ifndef DCPOMATIC_PLAIN_TEXT_FILE_DECODER_H
-#define DCPOMATIC_PLAIN_TEXT_FILE_DECODER_H
+#ifndef DCPOMATIC_TEXT_CAPTION_FILE_DECODER_H
+#define DCPOMATIC_TEXT_CAPTION_FILE_DECODER_H
-#include "plain_text_file.h"
+#include "text_caption_file.h"
#include "decoder.h"
class TextCaptionFileContent;
+++ /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)
- : 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 (TEXT_SUBTITLE)
-{
-
-}
-
-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 shared_ptr<TextContent> ();
- }
-
- /* Otherwise we can drop through to the newer logic */
- }
-
- if (!node->optional_number_child<double>("SubtitleXOffset") && !node->optional_number_child<double>("SubtitleOffset")) {
- return shared_ptr<TextContent> ();
- }
-
- return shared_ptr<TextContent> (new TextContent (parent, node, version));
-}
-
-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 (TEXT_SUBTITLE)
-{
- if (version >= 32) {
- _use = node->bool_child ("UseSubtitles");
- _burn = node->bool_child ("BurnSubtitles");
- }
-
- 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 >= 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 = node->optional_number_child<Frame>("SubtitleFadeIn");
- if (fi) {
- _fade_in = ContentTime (*fi);
- }
- optional<Frame> fo = node->optional_number_child<Frame>("SubtitleFadeOut");
- if (fo) {
- _fade_out = ContentTime (*fo);
- }
-
- _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_text_type (node->optional_string_child("TextType").get_value_or("subtitle"));
-}
-
-TextContent::TextContent (Content* parent, vector<shared_ptr<Content> > c)
- : ContentPart (parent)
-{
- shared_ptr<TextContent> ref = c[0]->subtitle;
- DCPOMATIC_ASSERT (ref);
- list<shared_ptr<Font> > ref_fonts = ref->fonts ();
-
- for (size_t i = 1; i < c.size(); ++i) {
-
- if (c[i]->subtitle->use() != ref->use()) {
- throw JoinError (_("Content to be joined must have the same 'use subtitles' setting."));
- }
-
- if (c[i]->subtitle->burn() != ref->burn()) {
- throw JoinError (_("Content to be joined must have the same 'burn subtitles' setting."));
- }
-
- if (c[i]->subtitle->x_offset() != ref->x_offset()) {
- throw JoinError (_("Content to be joined must have the same subtitle X offset."));
- }
-
- if (c[i]->subtitle->y_offset() != ref->y_offset()) {
- throw JoinError (_("Content to be joined must have the same subtitle Y offset."));
- }
-
- if (c[i]->subtitle->x_scale() != ref->x_scale()) {
- throw JoinError (_("Content to be joined must have the same subtitle X scale."));
- }
-
- if (c[i]->subtitle->y_scale() != ref->y_scale()) {
- throw JoinError (_("Content to be joined must have the same subtitle Y scale."));
- }
-
- if (c[i]->subtitle->line_spacing() != ref->line_spacing()) {
- throw JoinError (_("Content to be joined must have the same subtitle line spacing."));
- }
-
- if ((c[i]->subtitle->fade_in() != ref->fade_in()) || (c[i]->subtitle->fade_out() != ref->fade_out())) {
- throw JoinError (_("Content to be joined must have the same subtitle fades."));
- }
-
- if ((c[i]->subtitle->outline_width() != ref->outline_width())) {
- throw JoinError (_("Content to be joined must have the same outline width."));
- }
-
- list<shared_ptr<Font> > fonts = c[i]->subtitle->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 ();
-
- connect_to_fonts ();
-}
-
-/** _mutex must not be held on entry */
-void
-TextContent::as_xml (xmlpp::Node* root) const
-{
- boost::mutex::scoped_lock lm (_mutex);
-
- root->add_child("UseSubtitles")->add_child_text (_use ? "1" : "0");
- root->add_child("BurnSubtitles")->add_child_text (_burn ? "1" : "0");
- root->add_child("SubtitleXOffset")->add_child_text (raw_convert<string> (_x_offset));
- root->add_child("SubtitleYOffset")->add_child_text (raw_convert<string> (_y_offset));
- root->add_child("SubtitleXScale")->add_child_text (raw_convert<string> (_x_scale));
- root->add_child("SubtitleYScale")->add_child_text (raw_convert<string> (_y_scale));
- root->add_child("SubtitleLanguage")->add_child_text (_language);
- if (_colour) {
- root->add_child("Red")->add_child_text (raw_convert<string> (_colour->r));
- root->add_child("Green")->add_child_text (raw_convert<string> (_colour->g));
- root->add_child("Blue")->add_child_text (raw_convert<string> (_colour->b));
- }
- if (_effect) {
- switch (*_effect) {
- case dcp::NONE:
- root->add_child("Effect")->add_child_text("none");
- break;
- case dcp::BORDER:
- root->add_child("Effect")->add_child_text("outline");
- break;
- case dcp::SHADOW:
- root->add_child("Effect")->add_child_text("shadow");
- break;
- }
- }
- if (_effect_colour) {
- root->add_child("EffectRed")->add_child_text (raw_convert<string> (_effect_colour->r));
- root->add_child("EffectGreen")->add_child_text (raw_convert<string> (_effect_colour->g));
- root->add_child("EffectBlue")->add_child_text (raw_convert<string> (_effect_colour->b));
- }
- root->add_child("LineSpacing")->add_child_text (raw_convert<string> (_line_spacing));
- if (_fade_in) {
- root->add_child("SubtitleFadeIn")->add_child_text (raw_convert<string> (_fade_in->get()));
- }
- if (_fade_out) {
- root->add_child("SubtitleFadeOut")->add_child_text (raw_convert<string> (_fade_out->get()));
- }
- root->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 (root->add_child("Font"));
- }
-
- root->add_child("TextType")->add_child_text (text_type_to_string(_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_SUBTITLE_CONTENT_H
-#define DCPOMATIC_SUBTITLE_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:
- explicit TextContent (Content* parent);
- 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;
- }
-
- static 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;
- TextType _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 (ContentBitmapCaption (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 (ContentTextCaption (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-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/>.
-
-*/
-
-#ifndef DCPOMATIC_SUBTITLE_DECODER_H
-#define DCPOMATIC_SUBTITLE_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 (ContentBitmapCaption)> BitmapStart;
- boost::signals2::signal<void (ContentTextCaption)> 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));
}
-TextType
-string_to_text_type (string s)
+CaptionType
+string_to_caption_type (string s)
{
- if (s == "subtitle") {
- return TEXT_SUBTITLE;
- } else if (s == "ccap") {
- return TEXT_CLOSED_CAPTION;
+ if (s == "open") {
+ return CAPTION_OPEN;
+ } else if (s == "closed") {
+ return CAPTION_CLOSED;
} else {
- throw MetadataError (String::compose ("Unknown text type %1", s));
+ throw MetadataError (String::compose ("Unknown caption type %1", s));
}
}
string
-text_type_to_string (TextType t)
+caption_type_to_string (CaptionType t)
{
switch (t) {
- case TEXT_SUBTITLE:
- return "subtitle";
- case TEXT_CLOSED_CAPTION:
- return "ccap";
+ case CAPTION_OPEN:
+ return "open";
+ case CAPTION_CLOSED:
+ return "closed";
default:
DCPOMATIC_ASSERT (false);
}
class Content;
class VideoContent;
class AudioContent;
-class TextContent;
+class CaptionContent;
class FFmpegContent;
namespace cxml {
REELTYPE_BY_LENGTH
};
-enum TextType
+enum CaptionType
{
- TEXT_SUBTITLE,
- TEXT_CLOSED_CAPTION,
- TEXT_COUNT
+ CAPTION_OPEN,
+ CAPTION_CLOSED,
+ CAPTION_COUNT
};
-extern std::string text_type_to_string (TextType t);
-extern TextType string_to_text_type (std::string s);
+extern std::string caption_type_to_string (CaptionType t);
+extern CaptionType string_to_caption_type (std::string s);
/** @struct Crop
* @brief A description of the crop of an image or video.
and captions arrive to the Writer in sequence. This is not so for video.
*/
_audio_reel = _reels.begin ();
- for (int i = 0; i < TEXT_COUNT; ++i) {
- _text_reel[i] = _reels.begin ();
+ for (int i = 0; i < CAPTION_COUNT; ++i) {
+ _caption_reel[i] = _reels.begin ();
}
/* Check that the signer is OK if we need one */
}
void
-Writer::write (PlayerCaption text, TextType type, DCPTimePeriod period)
+Writer::write (PlayerCaption text, CaptionType type, DCPTimePeriod period)
{
- while (_text_reel[type]->period().to <= period.from) {
- ++_text_reel[type];
- DCPOMATIC_ASSERT (_text_reel[type] != _reels.end());
+ while (_caption_reel[type]->period().to <= period.from) {
+ ++_caption_reel[type];
+ DCPOMATIC_ASSERT (_caption_reel[type] != _reels.end());
}
- DCPOMATIC_ASSERT (_text_reel[type] != _reels.end());
+ DCPOMATIC_ASSERT (_caption_reel[type] != _reels.end());
- _text_reel[type]->write (text, type, period);
+ _caption_reel[type]->write (text, type, period);
}
void
bool can_repeat (Frame) const;
void repeat (Frame, Eyes);
void write (boost::shared_ptr<const AudioBuffers>, DCPTime time);
- void write (PlayerCaption text, TextType type, DCPTimePeriod period);
+ void write (PlayerCaption text, CaptionType type, DCPTimePeriod period);
void write (std::list<boost::shared_ptr<Font> > fonts);
void write (ReferencedReelAsset asset);
void finish ();
boost::weak_ptr<Job> _job;
std::vector<ReelWriter> _reels;
std::vector<ReelWriter>::iterator _audio_reel;
- std::vector<ReelWriter>::iterator _text_reel[TEXT_COUNT];
+ std::vector<ReelWriter>::iterator _caption_reel[CAPTION_COUNT];
/** our thread, or 0 */
boost::thread* _thread;
audio_ring_buffers.cc
audio_stream.cc
butler.cc
+ caption_content.cc
+ caption_decoder.cc
case_insensitive_sorter.cc
cinema.cc
cinema_kdms.cc
dcp_encoder.cc
dcp_examiner.cc
dcp_subtitle.cc
- dcp_text_content.cc
- dcp_text_decoder.cc
+ dcp_subtitle_content.cc
+ dcp_subtitle_decoder.cc
dcp_video.cc
dcpomatic_socket.cc
dcpomatic_time.cc
server.cc
shuffler.cc
string_log_entry.cc
- text_content.cc
- text_decoder.cc
- plain_text_file.cc
+ text_caption_file.cc
text_caption_file_content.cc
text_caption_file_decoder.cc
timer.cc
#include "lib/transcode_job.h"
#include "lib/dkdm_wrapper.h"
#include "lib/audio_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include <dcp/exceptions.h>
#include <dcp/raw_convert.h>
#include <wx/generic/aboutdlgg.h>
{
DCPOMATIC_ASSERT (_clipboard);
- PasteDialog* d = new PasteDialog (this, static_cast<bool>(_clipboard->video), static_cast<bool>(_clipboard->audio), static_cast<bool>(_clipboard->subtitle));
+ PasteDialog* d = new PasteDialog (this, static_cast<bool>(_clipboard->video), static_cast<bool>(_clipboard->audio), static_cast<bool>(_clipboard->caption));
if (d->ShowModal() == wxID_OK) {
BOOST_FOREACH (shared_ptr<Content> i, _film_editor->content_panel()->selected()) {
if (d->video() && i->video) {
DCPOMATIC_ASSERT (_clipboard->audio);
i->audio->take_settings_from (_clipboard->audio);
}
- if (d->subtitle() && i->subtitle) {
- DCPOMATIC_ASSERT (_clipboard->subtitle);
- i->subtitle->take_settings_from (_clipboard->subtitle);
+ if (d->caption() && i->caption) {
+ DCPOMATIC_ASSERT (_clipboard->caption);
+ i->caption->take_settings_from (_clipboard->caption);
}
}
}
#include "lib/job_manager.h"
#include "lib/job.h"
#include "lib/video_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_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)
{
- if (dcp->subtitle) {
- dcp->subtitle->set_use (true);
+ if (dcp->caption) {
+ dcp->caption->set_use (true);
}
if (dcp->video) {
#include "lib/ffmpeg_content.h"
#include "lib/text_caption_file_content.h"
#include "lib/ffmpeg_subtitle_stream.h"
-#include "lib/dcp_text_content.h"
+#include "lib/dcp_subtitle_content.h"
#include "lib/text_caption_file_decoder.h"
-#include "lib/dcp_text_decoder.h"
+#include "lib/dcp_subtitle_decoder.h"
#include "lib/dcp_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/decoder_factory.h"
#include <wx/spinctrl.h>
#include <boost/foreach.hpp>
}
}
setup_sensitivity ();
- } else if (property == TextContentProperty::USE) {
- checked_set (_use, scs ? scs->subtitle->use() : false);
+ } else if (property == CaptionContentProperty::USE) {
+ checked_set (_use, scs ? scs->caption->use() : false);
setup_sensitivity ();
- } else if (property == TextContentProperty::TYPE) {
+ } else if (property == CaptionContentProperty::TYPE) {
if (scs) {
- switch (scs->subtitle->type()) {
- case TEXT_SUBTITLE:
+ switch (scs->caption->type()) {
+ case CAPTION_OPEN:
_type->SetSelection (0);
break;
- case TEXT_CLOSED_CAPTION:
+ case CAPTION_CLOSED:
_type->SetSelection (1);
break;
default:
_type->SetSelection (0);
}
setup_sensitivity ();
- } else if (property == TextContentProperty::BURN) {
- checked_set (_burn, scs ? scs->subtitle->burn() : false);
- } else if (property == TextContentProperty::X_OFFSET) {
- checked_set (_x_offset, scs ? lrint (scs->subtitle->x_offset() * 100) : 0);
- } else if (property == TextContentProperty::Y_OFFSET) {
- checked_set (_y_offset, scs ? lrint (scs->subtitle->y_offset() * 100) : 0);
- } else if (property == TextContentProperty::X_SCALE) {
- checked_set (_x_scale, scs ? lrint (scs->subtitle->x_scale() * 100) : 100);
- } else if (property == TextContentProperty::Y_SCALE) {
- checked_set (_y_scale, scs ? lrint (scs->subtitle->y_scale() * 100) : 100);
- } else if (property == TextContentProperty::LINE_SPACING) {
- checked_set (_line_spacing, scs ? lrint (scs->subtitle->line_spacing() * 100) : 100);
- } else if (property == TextContentProperty::LANGUAGE) {
- checked_set (_language, scs ? scs->subtitle->language() : "");
+ } else if (property == CaptionContentProperty::BURN) {
+ checked_set (_burn, scs ? scs->caption->burn() : false);
+ } else if (property == CaptionContentProperty::X_OFFSET) {
+ checked_set (_x_offset, scs ? lrint (scs->caption->x_offset() * 100) : 0);
+ } else if (property == CaptionContentProperty::Y_OFFSET) {
+ checked_set (_y_offset, scs ? lrint (scs->caption->y_offset() * 100) : 0);
+ } else if (property == CaptionContentProperty::X_SCALE) {
+ checked_set (_x_scale, scs ? lrint (scs->caption->x_scale() * 100) : 100);
+ } else if (property == CaptionContentProperty::Y_SCALE) {
+ checked_set (_y_scale, scs ? lrint (scs->caption->y_scale() * 100) : 100);
+ } else if (property == CaptionContentProperty::LINE_SPACING) {
+ checked_set (_line_spacing, scs ? lrint (scs->caption->line_spacing() * 100) : 100);
+ } else if (property == CaptionContentProperty::LANGUAGE) {
+ checked_set (_language, scs ? scs->caption->language() : "");
} else if (property == DCPContentProperty::REFERENCE_SUBTITLE) {
if (scs) {
shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent> (scs);
CaptionPanel::use_toggled ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_use (_use->GetValue());
+ i->caption->set_use (_use->GetValue());
}
}
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle()) {
switch (_type->GetSelection()) {
case 0:
- i->subtitle->set_type (TEXT_SUBTITLE);
+ i->caption->set_type (CAPTION_OPEN);
break;
case 1:
- i->subtitle->set_type (TEXT_CLOSED_CAPTION);
+ i->caption->set_type (CAPTION_CLOSED);
break;
}
}
CaptionPanel::burn_toggled ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_burn (_burn->GetValue());
+ i->caption->set_burn (_burn->GetValue());
}
}
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 DCPTextContent> dsc = boost::dynamic_pointer_cast<const DCPTextContent> (i);
+ shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (i);
if (fc) {
- if (fc->subtitle) {
+ if (fc->caption) {
++ffmpeg_subs;
++any_subs;
}
CaptionPanel::x_offset_changed ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_x_offset (_x_offset->GetValue() / 100.0);
+ i->caption->set_x_offset (_x_offset->GetValue() / 100.0);
}
}
CaptionPanel::y_offset_changed ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_y_offset (_y_offset->GetValue() / 100.0);
+ i->caption->set_y_offset (_y_offset->GetValue() / 100.0);
}
}
{
ContentList c = _parent->selected_subtitle ();
if (c.size() == 1) {
- c.front()->subtitle->set_x_scale (_x_scale->GetValue() / 100.0);
+ c.front()->caption->set_x_scale (_x_scale->GetValue() / 100.0);
}
}
CaptionPanel::y_scale_changed ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_y_scale (_y_scale->GetValue() / 100.0);
+ i->caption->set_y_scale (_y_scale->GetValue() / 100.0);
}
}
CaptionPanel::line_spacing_changed ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_line_spacing (_line_spacing->GetValue() / 100.0);
+ i->caption->set_line_spacing (_line_spacing->GetValue() / 100.0);
}
}
CaptionPanel::language_changed ()
{
BOOST_FOREACH (shared_ptr<Content> i, _parent->selected_subtitle ()) {
- i->subtitle->set_language (wx_to_std (_language->GetValue()));
+ i->caption->set_language (wx_to_std (_language->GetValue()));
}
}
CaptionPanel::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 (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_SUBTITLE);
}
#include "image_sequence_dialog.h"
#include "film_viewer.h"
#include "lib/audio_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/video_content.h"
#include "lib/ffmpeg_content.h"
#include "lib/content_factory.h"
#include "lib/log.h"
#include "lib/compose.hpp"
#include "lib/text_caption_file_content.h"
-#include "lib/plain_text_file.h"
+#include "lib/text_caption_file.h"
#include <wx/wx.h>
#include <wx/notebook.h>
#include <wx/listctrl.h>
ContentList sc;
BOOST_FOREACH (shared_ptr<Content> i, selected ()) {
- if (i->subtitle) {
+ if (i->caption) {
sc.push_back (i);
}
}
_video_panel->Enable (_generally_sensitive && video_selection.size() > 0);
_audio_panel->Enable (_generally_sensitive && audio_selection.size() > 0);
- _caption_panel->Enable (_generally_sensitive && selection.size() == 1 && selection.front()->subtitle);
+ _caption_panel->Enable (_generally_sensitive && selection.size() == 1 && selection.front()->caption);
_timing_panel->Enable (_generally_sensitive);
}
#include "lib/ffmpeg_content.h"
#include "lib/audio_processor.h"
#include "lib/video_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_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 == TextContentProperty::USE ||
- property == TextContentProperty::BURN ||
+ property == CaptionContentProperty::USE ||
+ property == CaptionContentProperty::BURN ||
property == VideoContentProperty::SCALE ||
property == DCPContentProperty::REFERENCE_VIDEO ||
property == DCPContentProperty::REFERENCE_AUDIO ||
/*
- Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "font_files_dialog.h"
#include "lib/font.h"
#include "lib/content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include <wx/wx.h>
#include <boost/foreach.hpp>
#include <iostream>
_fonts->DeleteAllItems ();
size_t n = 0;
- BOOST_FOREACH (shared_ptr<Font> i, content->subtitle->fonts ()) {
+ BOOST_FOREACH (shared_ptr<Font> i, content->caption->fonts ()) {
wxListItem item;
item.SetId (n);
_fonts->InsertItem (item);
int const item = _fonts->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
string const id = wx_to_std (_fonts->GetItemText (item, 0));
shared_ptr<Font> font;
- BOOST_FOREACH (shared_ptr<Font> i, content->subtitle->fonts()) {
+ BOOST_FOREACH (shared_ptr<Font> i, content->caption->fonts()) {
if (i->id() == id) {
font = i;
}
#include "paste_dialog.h"
-PasteDialog::PasteDialog (wxWindow* parent, bool video, bool audio, bool subtitle)
+PasteDialog::PasteDialog (wxWindow* parent, bool video, bool audio, bool caption)
: TableDialog (parent, _("Paste"), 1, 0, true)
{
_video = new wxCheckBox (this, wxID_ANY, _("Paste video settings"));
_audio = new wxCheckBox (this, wxID_ANY, _("Paste audio settings"));
_audio->Enable (audio);
add (_audio);
- _subtitle = new wxCheckBox (this, wxID_ANY, _("Paste subtitle settings"));
- _subtitle->Enable (subtitle);
- add (_subtitle);
+ _caption = new wxCheckBox (this, wxID_ANY, _("Paste caption settings"));
+ _caption->Enable (caption);
+ add (_caption);
layout ();
}
}
bool
-PasteDialog::subtitle () const
+PasteDialog::caption () const
{
- return _subtitle->GetValue ();
+ return _caption->GetValue ();
}
class PasteDialog : public TableDialog
{
public:
- PasteDialog (wxWindow* parent, bool video, bool audio, bool subtitle);
+ PasteDialog (wxWindow* parent, bool video, bool audio, bool caption);
bool video () const;
bool audio () const;
- bool subtitle () const;
+ bool caption () const;
private:
wxCheckBox* _video;
wxCheckBox* _audio;
- wxCheckBox* _subtitle;
+ wxCheckBox* _caption;
};
if (dcp->audio && !dcp->audio->streams().empty()) {
checked_set (_dcp[r++], wxString::Format(_("Audio channels: %d"), dcp->audio->streams().front()->channels()));
}
- if (dcp->subtitle) {
+ if (dcp->caption) {
checked_set (_dcp[r++], _("Subtitles: yes"));
} else {
checked_set (_dcp[r++], _("Subtitles: no"));
#include "subtitle_appearance_dialog.h"
#include "rgba_colour_picker.h"
#include "lib/text_caption_file_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/ffmpeg_subtitle_stream.h"
#include "lib/ffmpeg_content.h"
#include <wx/wx.h>
_effect->Append (_("Outline"));
_effect->Append (_("Shadow"));;
- optional<dcp::Colour> colour = _content->subtitle->colour();
+ optional<dcp::Colour> colour = _content->caption->colour();
_force_colour->SetValue (static_cast<bool>(colour));
if (colour) {
_colour->SetColour (wxColour (colour->r, colour->g, colour->b));
_colour->SetColour (wxColour (255, 255, 255));
}
- optional<dcp::Effect> effect = _content->subtitle->effect();
+ optional<dcp::Effect> effect = _content->caption->effect();
_force_effect->SetValue (static_cast<bool>(effect));
if (effect) {
switch (*effect) {
_effect->SetSelection (NONE);
}
- optional<dcp::Colour> effect_colour = _content->subtitle->effect_colour();
+ optional<dcp::Colour> effect_colour = _content->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));
_effect_colour->SetColour (wxColour (0, 0, 0));
}
- optional<ContentTime> fade_in = _content->subtitle->fade_in();
+ optional<ContentTime> fade_in = _content->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());
_fade_in->set (ContentTime(), _content->active_video_frame_rate());
}
- optional<ContentTime> fade_out = _content->subtitle->fade_out();
+ optional<ContentTime> fade_out = _content->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 ());
_fade_out->set (ContentTime(), _content->active_video_frame_rate ());
}
- _outline_width->SetValue (_content->subtitle->outline_width ());
+ _outline_width->SetValue (_content->caption->outline_width ());
_force_colour->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
_force_effect_colour->Bind (wxEVT_CHECKBOX, bind (&SubtitleAppearanceDialog::setup_sensitivity, this));
{
if (_force_colour->GetValue ()) {
wxColour const c = _colour->GetColour ();
- _content->subtitle->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue()));
+ _content->caption->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue()));
} else {
- _content->subtitle->unset_colour ();
+ _content->caption->unset_colour ();
}
if (_force_effect->GetValue()) {
switch (_effect->GetSelection()) {
case NONE:
- _content->subtitle->set_effect (dcp::NONE);
+ _content->caption->set_effect (dcp::NONE);
break;
case OUTLINE:
- _content->subtitle->set_effect (dcp::BORDER);
+ _content->caption->set_effect (dcp::BORDER);
break;
case SHADOW:
- _content->subtitle->set_effect (dcp::SHADOW);
+ _content->caption->set_effect (dcp::SHADOW);
break;
}
} else {
- _content->subtitle->unset_effect ();
+ _content->caption->unset_effect ();
}
if (_force_effect_colour->GetValue ()) {
wxColour const ec = _effect_colour->GetColour ();
- _content->subtitle->set_effect_colour (dcp::Colour (ec.Red(), ec.Green(), ec.Blue()));
+ _content->caption->set_effect_colour (dcp::Colour (ec.Red(), ec.Green(), ec.Blue()));
} else {
- _content->subtitle->unset_effect_colour ();
+ _content->caption->unset_effect_colour ();
}
if (_force_fade_in->GetValue ()) {
- _content->subtitle->set_fade_in (_fade_in->get (_content->active_video_frame_rate ()));
+ _content->caption->set_fade_in (_fade_in->get (_content->active_video_frame_rate ()));
} else {
- _content->subtitle->unset_fade_in ();
+ _content->caption->unset_fade_in ();
}
if (_force_fade_out->GetValue ()) {
- _content->subtitle->set_fade_out (_fade_out->get (_content->active_video_frame_rate ()));
+ _content->caption->set_fade_out (_fade_out->get (_content->active_video_frame_rate ()));
} else {
- _content->subtitle->unset_fade_out ();
+ _content->caption->unset_fade_out ();
}
- _content->subtitle->set_outline_width (_outline_width->GetValue ());
+ _content->caption->set_outline_width (_outline_width->GetValue ());
if (_stream) {
for (map<RGBA, RGBAColourPicker*>::const_iterator i = _pickers.begin(); i != _pickers.end(); ++i) {
_fade_in->Enable (_force_fade_in->GetValue ());
_fade_out->Enable (_force_fade_out->GetValue ());
- bool const can_outline_width = _effect->GetSelection() == OUTLINE && _content->subtitle->burn ();
+ bool const can_outline_width = _effect->GetSelection() == OUTLINE && _content->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 subtitles"));
+ _outline_width->SetToolTip (_("Outline width cannot be set unless you are burning in captions"));
}
}
*/
#include "lib/text_caption_file_decoder.h"
-#include "lib/content_text.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/text_decoder.h"
+#include "lib/caption_decoder.h"
#include "subtitle_view.h"
#include "film_viewer.h"
#include "wx_util.h"
_subs = 0;
_frc = film->active_frame_rate_change (content->position());
- decoder->subtitle->PlainStart.connect (bind (&SubtitleView::data_start, this, _1));
- decoder->subtitle->Stop.connect (bind (&SubtitleView::data_stop, this, _1));
+ decoder->caption->PlainStart.connect (bind (&SubtitleView::data_start, this, _1));
+ decoder->caption->Stop.connect (bind (&SubtitleView::data_stop, this, _1));
while (!decoder->pass ()) {}
SetSizerAndFit (sizer);
}
/*
- Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
-#include "lib/content_text.h"
+#include "lib/content_caption.h"
#include <boost/shared_ptr.hpp>
#include <wx/wx.h>
#include <wx/listctrl.h>
#include "lib/image_content.h"
#include "lib/timer.h"
#include "lib/audio_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_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)));
}
- if (i->subtitle) {
+ if (i->caption) {
_views.push_back (shared_ptr<TimelineView> (new TimelineTextContentView (*this, i)));
}
/*
- Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
#include "timeline_text_content_view.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/content.h"
using boost::shared_ptr;
{
shared_ptr<Content> c = _content.lock ();
DCPOMATIC_ASSERT (c);
- return c->subtitle && c->subtitle->use();
+ return c->caption && c->caption->use();
}
#include "move_to_dialog.h"
#include "lib/content.h"
#include "lib/image_content.h"
-#include "lib/text_content.h"
-#include "lib/dcp_text_content.h"
+#include "lib/caption_content.h"
+#include "lib/dcp_subtitle_content.h"
#include "lib/audio_content.h"
#include "lib/text_caption_file_content.h"
#include "lib/video_content.h"
++count_ac;
content = i;
}
- if (i->subtitle && i->video_frame_rate()) {
+ if (i->caption && i->video_frame_rate()) {
++count_sc;
content = i;
}
#include <boost/test/unit_test.hpp>
#include "lib/film.h"
-#include "lib/dcp_text_content.h"
+#include "lib/dcp_subtitle_content.h"
#include "lib/dcp_content.h"
#include "lib/ratio.h"
#include "lib/dcp_decoder.h"
#include "lib/dcp_content_type.h"
-#include "lib/dcp_text_decoder.h"
-#include "lib/text_content.h"
-#include "lib/content_text.h"
+#include "lib/dcp_subtitle_decoder.h"
+#include "lib/caption_content.h"
+#include "lib/content_caption.h"
#include "lib/font.h"
-#include "lib/text_decoder.h"
+#include "lib/caption_decoder.h"
#include "test.h"
#include <iostream>
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
film->set_interop (false);
- shared_ptr<DCPTextContent> content (new DCPTextContent (film, "test/data/dcp_sub.xml"));
+ shared_ptr<DCPSubtitleContent> content (new DCPSubtitleContent (film, "test/data/dcp_sub.xml"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
BOOST_CHECK_EQUAL (content->full_length().get(), DCPTime::from_seconds(2).get());
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs ());
BOOST_REQUIRE (!wait_for_jobs ());
shared_ptr<DCPDecoder> decoder (new DCPDecoder (content, film->log(), false));
- decoder->subtitle->PlainStart.connect (bind (store, _1));
+ decoder->caption->PlainStart.connect (bind (store, _1));
stored = optional<ContentTextCaption> ();
while (!decoder->pass() && !stored) {}
film->set_container (Ratio::from_id ("185"));
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
- shared_ptr<DCPTextContent> content (new DCPTextContent (film, "test/data/dcp_sub2.xml"));
+ shared_ptr<DCPSubtitleContent> content (new DCPSubtitleContent (film, "test/data/dcp_sub2.xml"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
- shared_ptr<DCPTextDecoder> decoder (new DCPTextDecoder (content, film->log()));
- decoder->subtitle->PlainStart.connect (bind (store, _1));
+ shared_ptr<DCPSubtitleDecoder> decoder (new DCPSubtitleDecoder (content, film->log()));
+ decoder->caption->PlainStart.connect (bind (store, _1));
stored = optional<ContentTextCaption> ();
while (!decoder->pass ()) {
film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR"));
film->set_name ("frobozz");
film->set_interop (true);
- shared_ptr<DCPTextContent> content (new DCPTextContent (film, "test/data/dcp_sub3.xml"));
+ shared_ptr<DCPSubtitleContent> content (new DCPSubtitleContent (film, "test/data/dcp_sub3.xml"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs ());
- shared_ptr<DCPTextDecoder> decoder (new DCPTextDecoder (content, film->log()));
+ shared_ptr<DCPSubtitleDecoder> decoder (new DCPSubtitleDecoder (content, film->log()));
stored = optional<ContentTextCaption> ();
while (!decoder->pass ()) {
- decoder->subtitle->PlainStart.connect (bind (store, _1));
+ decoder->caption->PlainStart.connect (bind (store, _1));
if (stored && stored->from() == ContentTime::from_seconds(0.08)) {
list<dcp::SubtitleString> s = stored->subs;
list<dcp::SubtitleString>::const_iterator i = s.begin ();
shared_ptr<Film> film = new_test_film2 ("dcp_subtitle_test4");
film->set_interop (true);
- shared_ptr<DCPTextContent> content (new DCPTextContent (film, "test/data/dcp_sub3.xml"));
+ shared_ptr<DCPSubtitleContent> content (new DCPSubtitleContent (film, "test/data/dcp_sub3.xml"));
film->examine_and_add_content (content);
- shared_ptr<DCPTextContent> content2 (new DCPTextContent (film, "test/data/dcp_sub3.xml"));
+ shared_ptr<DCPSubtitleContent> content2 (new DCPSubtitleContent (film, "test/data/dcp_sub3.xml"));
film->examine_and_add_content (content2);
BOOST_REQUIRE (!wait_for_jobs ());
- content->subtitle->add_font (shared_ptr<Font> (new Font ("font1")));
- content2->subtitle->add_font (shared_ptr<Font> (new Font ("font2")));
+ content->caption->add_font (shared_ptr<Font> (new Font ("font1")));
+ content2->caption->add_font (shared_ptr<Font> (new Font ("font2")));
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs ());
#include "lib/ratio.h"
#include "lib/transcode_job.h"
#include "lib/dcp_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/compose.hpp"
#include "test.h"
#include <boost/test/unit_test.hpp>
shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
- s->subtitle->set_colour (dcp::Colour (255, 255, 0));
- s->subtitle->set_effect (dcp::SHADOW);
- s->subtitle->set_effect_colour (dcp::Colour (0, 255, 255));
+ s->caption->set_colour (dcp::Colour (255, 255, 0));
+ s->caption->set_effect (dcp::SHADOW);
+ s->caption->set_effect_colour (dcp::Colour (0, 255, 255));
film->write_metadata();
shared_ptr<Job> job (new TranscodeJob (film));
shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
- s->subtitle->set_colour (dcp::Colour (255, 255, 0));
- s->subtitle->set_effect (dcp::SHADOW);
- s->subtitle->set_effect_colour (dcp::Colour (0, 255, 255));
+ s->caption->set_colour (dcp::Colour (255, 255, 0));
+ s->caption->set_effect (dcp::SHADOW);
+ s->caption->set_effect_colour (dcp::Colour (0, 255, 255));
shared_ptr<Job> job (new TranscodeJob (film));
FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test7.mov", FFmpegEncoder::FORMAT_PRORES, false);
shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
- s->subtitle->set_colour (dcp::Colour (255, 255, 0));
- s->subtitle->set_effect (dcp::SHADOW);
- s->subtitle->set_effect_colour (dcp::Colour (0, 255, 255));
+ s->caption->set_colour (dcp::Colour (255, 255, 0));
+ s->caption->set_effect (dcp::SHADOW);
+ s->caption->set_effect_colour (dcp::Colour (0, 255, 255));
film->write_metadata();
shared_ptr<Job> job (new TranscodeJob (film));
shared_ptr<TextCaptionFileContent> s (new TextCaptionFileContent (film, "test/data/subrip.srt"));
film->examine_and_add_content (s);
BOOST_REQUIRE (!wait_for_jobs ());
- s->subtitle->set_colour (dcp::Colour (255, 255, 0));
- s->subtitle->set_effect (dcp::SHADOW);
- s->subtitle->set_effect_colour (dcp::Colour (0, 255, 255));
+ s->caption->set_colour (dcp::Colour (255, 255, 0));
+ s->caption->set_effect (dcp::SHADOW);
+ s->caption->set_effect_colour (dcp::Colour (0, 255, 255));
film->write_metadata();
shared_ptr<Job> job (new TranscodeJob (film));
#include "test.h"
#include "lib/film.h"
-#include "lib/dcp_text_content.h"
+#include "lib/dcp_subtitle_content.h"
#include "lib/ratio.h"
#include "lib/dcp_content_type.h"
#include "lib/dcp_content.h"
#include "lib/text_caption_file_content.h"
#include "lib/content_factory.h"
#include "lib/dcp_content.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/butler.h"
#include "lib/compose.hpp"
#include "test.h"
shared_ptr<DCPContent> dcp (new DCPContent (film, private_data / "awkward_subs"));
film->examine_and_add_content (dcp, true);
BOOST_REQUIRE (!wait_for_jobs ());
- dcp->subtitle->set_use (true);
+ dcp->caption->set_use (true);
shared_ptr<Player> player (new Player (film, film->playlist()));
player->set_fast ();
shared_ptr<DCPContent> dcp (new DCPContent (film, private_data / "awkward_subs2"));
film->examine_and_add_content (dcp, true);
BOOST_REQUIRE (!wait_for_jobs ());
- dcp->subtitle->set_use (true);
+ dcp->caption->set_use (true);
shared_ptr<Player> player (new Player (film, film->playlist()));
player->set_fast ();
#include "lib/ffmpeg_content.h"
#include "lib/content_factory.h"
-#include "lib/text_content.h"
+#include "lib/caption_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/text_content.h"
+#include "lib/caption_content.h"
#include "lib/film.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
shared_ptr<FFmpegContent> content = dynamic_pointer_cast<FFmpegContent>(content_factory(film, private_data / "prophet_short_clip.mkv").front());
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
- content->subtitle->set_burn (true);
- content->subtitle->set_use (true);
+ content->caption->set_burn (true);
+ content->caption->set_use (true);
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs ());
boost::filesystem::remove_all (film->dir (film->dcp_name(), false));
- content->subtitle->set_use (false);
+ content->caption->set_use (false);
film->make_dcp ();
BOOST_REQUIRE (!wait_for_jobs ());
#include "lib/dcp_content_type.h"
#include "lib/font.h"
#include "lib/ratio.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
film->examine_and_add_content (content);
wait_for_jobs ();
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->make_dcp ();
wait_for_jobs ();
film->examine_and_add_content (content);
wait_for_jobs ();
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
/* Use test/data/subrip2.srt as if it were a font file */
- content->subtitle->fonts().front()->set_file (FontFiles::NORMAL, "test/data/subrip2.srt");
+ content->caption->fonts().front()->set_file (FontFiles::NORMAL, "test/data/subrip2.srt");
film->make_dcp ();
wait_for_jobs ();
film->examine_and_add_content (content);
wait_for_jobs ();
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->make_dcp ();
wait_for_jobs ();
film->set_name ("frobozz");
film->set_interop (false);
shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->examine_and_add_content (content);
wait_for_jobs ();
film->make_dcp ();
film->set_interop (true);
film->set_sequence (false);
shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip2.srt"));
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->examine_and_add_content (content);
film->examine_and_add_content (content);
wait_for_jobs ();
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"));
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
film->make_dcp ();
BOOST_CHECK_EQUAL (content->full_length(), DCPTime::from_seconds ((3 * 60) + 56.471));
shared_ptr<SubRipDecoder> decoder (new SubRipDecoder (content));
- list<ContentTextSubtitle> cts = decoder->get_plain_texts (
+ list<ContentTextCaption> cts = decoder->get_plain_texts (
ContentTimePeriod (
ContentTime::from_seconds (109), ContentTime::from_seconds (110)
), false
#include "lib/dcp_content_type.h"
#include "lib/font.h"
#include "lib/ratio.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
film->examine_and_add_content (content);
wait_for_jobs ();
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->make_dcp ();
wait_for_jobs ();
#include "lib/content.h"
#include "lib/film.h"
#include "lib/content_factory.h"
-#include "lib/plain_text_file.h"
+#include "lib/text_caption_file.h"
#include "lib/text_caption_file_content.h"
#include <boost/test/unit_test.hpp>
#include "lib/text_caption_file_content.h"
#include "lib/film.h"
#include "lib/ratio.h"
-#include "lib/text_content.h"
+#include "lib/caption_content.h"
#include "lib/dcp_content_type.h"
#include "test.h"
#include <dcp/cpl.h>
shared_ptr<TextCaptionFileContent> content (new TextCaptionFileContent (film, "test/data/subrip5.srt"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
- content->subtitle->set_use (true);
- content->subtitle->set_burn (false);
+ content->caption->set_use (true);
+ content->caption->set_burn (false);
film->set_reel_type (REELTYPE_BY_LENGTH);
film->set_interop (true);
film->set_reel_length (1024 * 1024 * 512);
*/
#include "lib/film.h"
-#include "lib/dcp_text_content.h"
+#include "lib/dcp_subtitle_content.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE (subtitle_trim_test1)
{
shared_ptr<Film> film = new_test_film2 ("subtitle_trim_test1");
- shared_ptr<DCPTextContent> content (new DCPTextContent (film, "test/data/dcp_sub5.xml"));
+ shared_ptr<DCPSubtitleContent> content (new DCPSubtitleContent (film, "test/data/dcp_sub5.xml"));
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs ());
#include "test.h"
#include "lib/film.h"
-#include "lib/dcp_text_content.h"
+#include "lib/dcp_subtitle_content.h"
#include "lib/ratio.h"
#include "lib/dcp_content_type.h"
#include "lib/dcp_content.h"