From: Carl Hetherington Date: Thu, 19 Jul 2018 21:44:53 +0000 (+0100) Subject: Clean up after previous commit. X-Git-Tag: v2.13.36~7 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=27b83475435dda4e84a90cf59a52f150905c4ab1 Clean up after previous commit. --- diff --git a/src/lib/active_captions.cc b/src/lib/active_captions.cc index 972095e37..d41270382 100644 --- a/src/lib/active_captions.cc +++ b/src/lib/active_captions.cc @@ -20,7 +20,7 @@ #include "active_captions.h" #include "piece.h" -#include "text_content.h" +#include "caption_content.h" #include #include @@ -47,7 +47,7 @@ ActiveCaptions::get_burnt (DCPTimePeriod period, bool always_burn_subtitles) con 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; } diff --git a/src/lib/bitmap_caption.h b/src/lib/bitmap_caption.h new file mode 100644 index 000000000..8883272ad --- /dev/null +++ b/src/lib/bitmap_caption.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2014-2018 Carl Hetherington + + 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 . + +*/ + +#ifndef DCPOMATIC_BITMAP_CAPTION_H +#define DCPOMATIC_BITMAP_CAPTION_H + +#include "rect.h" +#include + +class Image; + +class BitmapCaption +{ +public: + BitmapCaption (boost::shared_ptr i, dcpomatic::Rect r) + : image (i) + , rectangle (r) + {} + + boost::shared_ptr 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 rectangle; +}; + +#endif diff --git a/src/lib/bitmap_text.h b/src/lib/bitmap_text.h deleted file mode 100644 index 64de7686d..000000000 --- a/src/lib/bitmap_text.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright (C) 2014-2018 Carl Hetherington - - 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 . - -*/ - -#ifndef DCPOMATIC_BITMAP_TEXT_H -#define DCPOMATIC_BITMAP_TEXT_H - -#include "rect.h" -#include - -class Image; - -class BitmapText -{ -public: - BitmapText (boost::shared_ptr i, dcpomatic::Rect r) - : image (i) - , rectangle (r) - {} - - boost::shared_ptr 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 rectangle; -}; - -#endif diff --git a/src/lib/caption_content.cc b/src/lib/caption_content.cc new file mode 100644 index 000000000..33e21bc4a --- /dev/null +++ b/src/lib/caption_content.cc @@ -0,0 +1,528 @@ +/* + Copyright (C) 2013-2018 Carl Hetherington + + 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 . + +*/ + +#include "caption_content.h" +#include "util.h" +#include "exceptions.h" +#include "font.h" +#include "content.h" +#include +#include +#include +#include +#include + +#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::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 (); + } + + /* Otherwise we can drop through to the newer logic */ + } + + if (!node->optional_number_child("SubtitleXOffset") && !node->optional_number_child("SubtitleOffset")) { + return shared_ptr (); + } + + return shared_ptr (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("LineSpacing").get_value_or (1)) + , _outline_width (node->optional_number_child("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 ("SubtitleXOffset"); + _y_offset = node->number_child ("SubtitleYOffset"); + } else { + _y_offset = node->number_child ("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 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 ("SubtitleXScale"); + _y_scale = node->number_child ("SubtitleYScale"); + } else { + _x_scale = _y_scale = node->number_child ("SubtitleScale"); + } + + optional r = node->optional_number_child("Red"); + optional g = node->optional_number_child("Green"); + optional b = node->optional_number_child("Blue"); + if (r && g && b) { + _colour = dcp::Colour (*r, *g, *b); + } + + if (version >= 36) { + optional er = node->optional_number_child("EffectRed"); + optional eg = node->optional_number_child("EffectGreen"); + optional eb = node->optional_number_child("EffectBlue"); + if (er && eg && eb) { + _effect_colour = dcp::Colour (*er, *eg, *eb); + } + } else { + _effect_colour = dcp::Colour ( + node->optional_number_child("OutlineRed").get_value_or(255), + node->optional_number_child("OutlineGreen").get_value_or(255), + node->optional_number_child("OutlineBlue").get_value_or(255) + ); + } + + optional fi = node->optional_number_child("SubtitleFadeIn"); + if (fi) { + _fade_in = ContentTime (*fi); + } + optional fo = node->optional_number_child("SubtitleFadeOut"); + if (fo) { + _fade_out = ContentTime (*fo); + } + + _language = node->optional_string_child ("SubtitleLanguage").get_value_or (""); + + list fonts = node->node_children ("Font"); + for (list::const_iterator i = fonts.begin(); i != fonts.end(); ++i) { + _fonts.push_back (shared_ptr (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 > c) + : ContentPart (parent) +{ + shared_ptr ref = c[0]->caption; + DCPOMATIC_ASSERT (ref); + list > 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 > fonts = c[i]->caption->fonts (); + if (fonts.size() != ref_fonts.size()) { + throw JoinError (_("Content to be joined must use the same fonts.")); + } + + list >::const_iterator j = ref_fonts.begin (); + list >::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 (_x_offset)); + root->add_child("SubtitleYOffset")->add_child_text (raw_convert (_y_offset)); + root->add_child("SubtitleXScale")->add_child_text (raw_convert (_x_scale)); + root->add_child("SubtitleYScale")->add_child_text (raw_convert (_y_scale)); + root->add_child("SubtitleLanguage")->add_child_text (_language); + if (_colour) { + root->add_child("Red")->add_child_text (raw_convert (_colour->r)); + root->add_child("Green")->add_child_text (raw_convert (_colour->g)); + root->add_child("Blue")->add_child_text (raw_convert (_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 (_effect_colour->r)); + root->add_child("EffectGreen")->add_child_text (raw_convert (_effect_colour->g)); + root->add_child("EffectBlue")->add_child_text (raw_convert (_effect_colour->b)); + } + root->add_child("LineSpacing")->add_child_text (raw_convert (_line_spacing)); + if (_fade_in) { + root->add_child("SubtitleFadeIn")->add_child_text (raw_convert (_fade_in->get())); + } + if (_fade_out) { + root->add_child("SubtitleFadeOut")->add_child_text (raw_convert (_fade_out->get())); + } + root->add_child("OutlineWidth")->add_child_text (raw_convert (_outline_width)); + + for (list >::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 (x_scale()) + + "_" + raw_convert (y_scale()) + + "_" + raw_convert (x_offset()) + + "_" + raw_convert (y_offset()) + + "_" + raw_convert (line_spacing()) + + "_" + raw_convert (fade_in().get_value_or(ContentTime()).get()) + + "_" + raw_convert (fade_out().get_value_or(ContentTime()).get()) + + "_" + raw_convert (outline_width()) + + "_" + raw_convert (colour().get_value_or(dcp::Colour(255, 255, 255)).to_argb_string()) + + "_" + raw_convert (dcp::effect_to_string(effect().get_value_or(dcp::NONE))) + + "_" + raw_convert (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 f, _fonts) { + for (int i = 0; i < FontFiles::VARIANTS; ++i) { + s += "_" + f->file(static_cast(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) +{ + _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 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(), CaptionContentProperty::COLOUR); +} + +void +CaptionContent::set_effect (dcp::Effect e) +{ + maybe_set (_effect, e, CaptionContentProperty::EFFECT); +} + +void +CaptionContent::unset_effect () +{ + maybe_set (_effect, optional(), 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(), 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(), 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(), 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 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); +} diff --git a/src/lib/caption_content.h b/src/lib/caption_content.h new file mode 100644 index 000000000..25f7a1d66 --- /dev/null +++ b/src/lib/caption_content.h @@ -0,0 +1,212 @@ +/* + Copyright (C) 2013-2018 Carl Hetherington + + 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 . + +*/ + +#ifndef DCPOMATIC_CAPTION_CONTENT_H +#define DCPOMATIC_CAPTION_CONTENT_H + +#include "content_part.h" +#include +#include +#include + +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 >); + + void as_xml (xmlpp::Node *) const; + std::string identifier () const; + void take_settings_from (boost::shared_ptr c); + + void add_font (boost::shared_ptr 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 > fonts () const { + boost::mutex::scoped_lock lm (_mutex); + return _fonts; + } + + std::string language () const { + boost::mutex::scoped_lock lm (_mutex); + return _language; + } + + boost::optional colour () const { + boost::mutex::scoped_lock lm (_mutex); + return _colour; + } + + boost::optional effect () const { + boost::mutex::scoped_lock lm (_mutex); + return _effect; + } + + boost::optional 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 fade_in () const { + boost::mutex::scoped_lock lm (_mutex); + return _fade_in; + } + + boost::optional 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 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 _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 > _fonts; + boost::optional _colour; + boost::optional _effect; + boost::optional _effect_colour; + /** scaling factor for line spacing; 1 is "standard", < 1 is closer together, > 1 is further apart */ + double _line_spacing; + boost::optional _fade_in; + boost::optional _fade_out; + int _outline_width; + CaptionType _type; +}; + +#endif diff --git a/src/lib/caption_decoder.cc b/src/lib/caption_decoder.cc new file mode 100644 index 000000000..1a2221024 --- /dev/null +++ b/src/lib/caption_decoder.cc @@ -0,0 +1,257 @@ +/* + Copyright (C) 2013-2017 Carl Hetherington + + 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 . + +*/ + +#include "caption_decoder.h" +#include "caption_content.h" +#include "util.h" +#include "log.h" +#include "compose.hpp" +#include +#include +#include +#include +#include + +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 c, + shared_ptr 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, dcpomatic::Rect rect) +{ + BitmapStart (ContentBitmapCaption (from, _content->type(), image, rect)); + _position = from; +} + +void +CaptionDecoder::emit_plain_start (ContentTime from, list 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 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 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 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 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 (); +} diff --git a/src/lib/caption_decoder.h b/src/lib/caption_decoder.h new file mode 100644 index 000000000..d555446c7 --- /dev/null +++ b/src/lib/caption_decoder.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2013-2018 Carl Hetherington + + 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 . + +*/ + +#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 +#include + +namespace sub { + class Subtitle; +} + +class Image; + +class CaptionDecoder : public DecoderPart +{ +public: + CaptionDecoder ( + Decoder* parent, + boost::shared_ptr, + boost::shared_ptr log, + ContentTime first + ); + + ContentTime position () const { + return _position; + } + + void emit_bitmap_start (ContentTime from, boost::shared_ptr image, dcpomatic::Rect rect); + void emit_plain_start (ContentTime from, std::list s); + void emit_plain_start (ContentTime from, sub::Subtitle const & subtitle); + void emit_plain (ContentTimePeriod period, std::list s); + void emit_plain (ContentTimePeriod period, sub::Subtitle const & subtitle); + void emit_stop (ContentTime to); + + void seek (); + + boost::shared_ptr content () const { + return _content; + } + + boost::signals2::signal BitmapStart; + boost::signals2::signal PlainStart; + boost::signals2::signal Stop; + +private: + boost::shared_ptr _content; + ContentTime _position; +}; + +#endif diff --git a/src/lib/content.cc b/src/lib/content.cc index 1a8bc9eb2..af4c6c701 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -27,7 +27,7 @@ #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" @@ -436,7 +436,7 @@ Content::take_settings_from (shared_ptr c) 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); } } diff --git a/src/lib/content.h b/src/lib/content.h index 63d03fd71..7ff20e96c 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -182,7 +182,7 @@ public: boost::shared_ptr video; boost::shared_ptr audio; - boost::shared_ptr subtitle; + boost::shared_ptr caption; void signal_changed (int); diff --git a/src/lib/content_caption.h b/src/lib/content_caption.h new file mode 100644 index 000000000..ad83fcb89 --- /dev/null +++ b/src/lib/content_caption.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2014-2018 Carl Hetherington + + 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 . + +*/ + +#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 +#include + +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 im, dcpomatic::Rect 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 s) + : ContentCaption (f, type) + , subs (s) + {} + + std::list subs; +}; + +#endif diff --git a/src/lib/content_factory.cc b/src/lib/content_factory.cc index 9429f1c46..8c473b7bc 100644 --- a/src/lib/content_factory.cc +++ b/src/lib/content_factory.cc @@ -28,7 +28,7 @@ #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" @@ -92,7 +92,7 @@ content_factory (shared_ptr film, cxml::NodePtr node, int version, l } 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") { @@ -217,9 +217,9 @@ content_factory (shared_ptr film, boost::filesystem::path path) 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)) { diff --git a/src/lib/content_text.h b/src/lib/content_text.h deleted file mode 100644 index 1b550c96d..000000000 --- a/src/lib/content_text.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright (C) 2014-2018 Carl Hetherington - - 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 . - -*/ - -#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 -#include - -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 im, dcpomatic::Rect 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 s) - : ContentText (f, type) - , subs (s) - {} - - std::list subs; -}; - -#endif diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index d4891ad45..e02eb7bd9 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -28,7 +28,7 @@ #include "overlaps.h" #include "compose.hpp" #include "dcp_decoder.h" -#include "text_content.h" +#include "caption_content.h" #include #include #include @@ -81,7 +81,7 @@ DCPContent::DCPContent (shared_ptr film, cxml::ConstNodePtr node, in { 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 ( @@ -143,7 +143,7 @@ DCPContent::examine (shared_ptr job) bool const needed_assets = needs_assets (); bool const needed_kdm = needs_kdm (); string const old_name = name (); - bool had_subtitles = static_cast (subtitle); + bool had_subtitles = static_cast (caption); if (job) { job->set_progress_unknown (); @@ -179,11 +179,11 @@ DCPContent::examine (shared_ptr job) 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 (subtitle); + has_subtitles = static_cast (caption); _encrypted = examiner->encrypted (); _needs_assets = examiner->needs_assets (); _kdm_valid = examiner->kdm_valid (); @@ -254,8 +254,8 @@ DCPContent::as_xml (xmlpp::Node* node, bool with_paths) const 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); @@ -309,8 +309,8 @@ DCPContent::identifier () const s += video->identifier() + "_"; } - if (subtitle) { - s += subtitle->identifier () + " "; + if (caption) { + s += caption->identifier () + " "; } s += string (_reference_video ? "1" : "0") + string (_reference_subtitle ? "1" : "0"); @@ -584,7 +584,7 @@ DCPContent::can_reference_subtitle (string& why_not) const } /// 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 diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index 6a9de841d..cc415629b 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -24,7 +24,7 @@ #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 @@ -62,9 +62,9 @@ DCPDecoder::DCPDecoder (shared_ptr c, shared_ptr log, boo 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 > cpl_list = cpls (); @@ -209,7 +209,7 @@ DCPDecoder::pass_subtitles (ContentTime next) if (is) { list 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 ()) diff --git a/src/lib/dcp_encoder.cc b/src/lib/dcp_encoder.cc index 9766aad33..541c23b6c 100644 --- a/src/lib/dcp_encoder.cc +++ b/src/lib/dcp_encoder.cc @@ -35,7 +35,7 @@ #include "writer.h" #include "compose.hpp" #include "referenced_reel_asset.h" -#include "text_content.h" +#include "caption_content.h" #include "player_video.h" #include #include @@ -61,10 +61,10 @@ DCPEncoder::DCPEncoder (shared_ptr film, weak_ptr job) { _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 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; } } @@ -75,7 +75,7 @@ DCPEncoder::~DCPEncoder () /* 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 @@ -141,9 +141,9 @@ DCPEncoder::audio (shared_ptr data, DCPTime time) } 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); } } diff --git a/src/lib/dcp_encoder.h b/src/lib/dcp_encoder.h index 850ead656..9808987c3 100644 --- a/src/lib/dcp_encoder.h +++ b/src/lib/dcp_encoder.h @@ -52,7 +52,7 @@ private: void video (boost::shared_ptr, DCPTime); void audio (boost::shared_ptr, DCPTime); - void text (PlayerCaption, TextType, DCPTimePeriod); + void caption (PlayerCaption, CaptionType, DCPTimePeriod); boost::shared_ptr _writer; boost::shared_ptr _j2k_encoder; @@ -61,5 +61,5 @@ private: 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; }; diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc new file mode 100644 index 000000000..17477cfb8 --- /dev/null +++ b/src/lib/dcp_subtitle_content.cc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2014-2018 Carl Hetherington + + 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 . + +*/ + +#include "font.h" +#include "dcp_subtitle_content.h" +#include "film.h" +#include "caption_content.h" +#include +#include +#include +#include +#include +#include + +#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 film, boost::filesystem::path path) + : Content (film, path) +{ + caption.reset (new CaptionContent (this)); +} + +DCPSubtitleContent::DCPSubtitleContent (shared_ptr film, cxml::ConstNodePtr node, int version) + : Content (film, node) + , _length (node->number_child ("Length")) +{ + caption = CaptionContent::from_xml (this, node, version); +} + +void +DCPSubtitleContent::examine (shared_ptr job) +{ + Content::examine (job); + + shared_ptr sc = load (path (0)); + + shared_ptr iop = dynamic_pointer_cast (sc); + shared_ptr smpte = dynamic_pointer_cast (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 i, sc->load_font_nodes ()) { + caption->add_font (shared_ptr (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 (_length.get ())); +} diff --git a/src/lib/dcp_subtitle_content.h b/src/lib/dcp_subtitle_content.h new file mode 100644 index 000000000..36945adcd --- /dev/null +++ b/src/lib/dcp_subtitle_content.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2014-2016 Carl Hetherington + + 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 . + +*/ + +#include "dcp_subtitle.h" +#include "content.h" + +class DCPSubtitleContent : public DCPSubtitle, public Content +{ +public: + DCPSubtitleContent (boost::shared_ptr, boost::filesystem::path); + DCPSubtitleContent (boost::shared_ptr, cxml::ConstNodePtr, int); + + void examine (boost::shared_ptr); + std::string summary () const; + std::string technical_summary () const; + void as_xml (xmlpp::Node *, bool with_paths) const; + DCPTime full_length () const; + +private: + ContentTime _length; +}; diff --git a/src/lib/dcp_subtitle_decoder.cc b/src/lib/dcp_subtitle_decoder.cc new file mode 100644 index 000000000..c7a9a863f --- /dev/null +++ b/src/lib/dcp_subtitle_decoder.cc @@ -0,0 +1,95 @@ +/* + Copyright (C) 2014-2018 Carl Hetherington + + 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 . + +*/ + +#include "dcp_subtitle_decoder.h" +#include "dcp_subtitle_content.h" +#include +#include + +using std::list; +using std::cout; +using boost::shared_ptr; +using boost::dynamic_pointer_cast; +using boost::bind; + +DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr content, shared_ptr log) +{ + shared_ptr 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 >::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 s; + ContentTimePeriod const p = content_time_period (*_next); + + while (_next != _subtitles.end () && content_time_period (*_next) == p) { + shared_ptr ns = dynamic_pointer_cast(*_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 s) const +{ + return ContentTimePeriod ( + ContentTime::from_seconds (s->in().as_seconds ()), + ContentTime::from_seconds (s->out().as_seconds ()) + ); +} diff --git a/src/lib/dcp_subtitle_decoder.h b/src/lib/dcp_subtitle_decoder.h new file mode 100644 index 000000000..ef4dad3f5 --- /dev/null +++ b/src/lib/dcp_subtitle_decoder.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2014 Carl Hetherington + + 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 . + +*/ + +#include "caption_decoder.h" +#include "dcp_subtitle.h" + +class DCPSubtitleContent; + +class DCPSubtitleDecoder : public DCPSubtitle, public Decoder +{ +public: + DCPSubtitleDecoder (boost::shared_ptr, boost::shared_ptr log); + + bool pass (); + void seek (ContentTime time, bool accurate); + +private: + ContentTimePeriod content_time_period (boost::shared_ptr s) const; + + std::list > _subtitles; + std::list >::const_iterator _next; +}; diff --git a/src/lib/dcp_text_content.cc b/src/lib/dcp_text_content.cc deleted file mode 100644 index 9e7524be3..000000000 --- a/src/lib/dcp_text_content.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - Copyright (C) 2014-2015 Carl Hetherington - - 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 . - -*/ - -#include "font.h" -#include "dcp_text_content.h" -#include "film.h" -#include "text_content.h" -#include -#include -#include -#include -#include -#include - -#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 film, boost::filesystem::path path) - : Content (film, path) -{ - subtitle.reset (new TextContent (this)); -} - -DCPTextContent::DCPTextContent (shared_ptr film, cxml::ConstNodePtr node, int version) - : Content (film, node) - , _length (node->number_child ("Length")) -{ - subtitle = TextContent::from_xml (this, node, version); -} - -void -DCPTextContent::examine (shared_ptr job) -{ - Content::examine (job); - - shared_ptr sc = load (path (0)); - - shared_ptr iop = dynamic_pointer_cast (sc); - shared_ptr smpte = dynamic_pointer_cast (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 i, sc->load_font_nodes ()) { - subtitle->add_font (shared_ptr (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 (_length.get ())); -} diff --git a/src/lib/dcp_text_content.h b/src/lib/dcp_text_content.h deleted file mode 100644 index 894cc0384..000000000 --- a/src/lib/dcp_text_content.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2014-2016 Carl Hetherington - - 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 . - -*/ - -#include "dcp_subtitle.h" -#include "content.h" - -class DCPTextContent : public DCPSubtitle, public Content -{ -public: - DCPTextContent (boost::shared_ptr, boost::filesystem::path); - DCPTextContent (boost::shared_ptr, cxml::ConstNodePtr, int); - - void examine (boost::shared_ptr); - 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; -}; diff --git a/src/lib/dcp_text_decoder.cc b/src/lib/dcp_text_decoder.cc deleted file mode 100644 index 168bfa5cc..000000000 --- a/src/lib/dcp_text_decoder.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - Copyright (C) 2014-2018 Carl Hetherington - - 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 . - -*/ - -#include "dcp_text_decoder.h" -#include "dcp_text_content.h" -#include -#include - -using std::list; -using std::cout; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; -using boost::bind; - -DCPTextDecoder::DCPTextDecoder (shared_ptr content, shared_ptr log) -{ - shared_ptr 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 >::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 s; - ContentTimePeriod const p = content_time_period (*_next); - - while (_next != _subtitles.end () && content_time_period (*_next) == p) { - shared_ptr ns = dynamic_pointer_cast(*_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 s) const -{ - return ContentTimePeriod ( - ContentTime::from_seconds (s->in().as_seconds ()), - ContentTime::from_seconds (s->out().as_seconds ()) - ); -} diff --git a/src/lib/dcp_text_decoder.h b/src/lib/dcp_text_decoder.h deleted file mode 100644 index f1b51b823..000000000 --- a/src/lib/dcp_text_decoder.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2014 Carl Hetherington - - 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 . - -*/ - -#include "text_decoder.h" -#include "dcp_subtitle.h" - -class DCPTextContent; - -class DCPTextDecoder : public DCPSubtitle, public Decoder -{ -public: - DCPTextDecoder (boost::shared_ptr, boost::shared_ptr log); - - bool pass (); - void seek (ContentTime time, bool accurate); - -private: - ContentTimePeriod content_time_period (boost::shared_ptr s) const; - - std::list > _subtitles; - std::list >::const_iterator _next; -}; diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index e7e6b8620..70eb5b61a 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington + Copyright (C) 2012-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -21,7 +21,7 @@ #include "decoder.h" #include "video_decoder.h" #include "audio_decoder.h" -#include "text_decoder.h" +#include "caption_decoder.h" #include #include @@ -42,8 +42,8 @@ Decoder::position () const 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()); @@ -58,7 +58,7 @@ Decoder::seek (ContentTime, bool) if (audio) { audio->seek (); } - if (subtitle) { - subtitle->seek (); + if (caption) { + caption->seek (); } } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 27f0b1141..c3b330cfb 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington + Copyright (C) 2012-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -32,7 +32,7 @@ class Decoded; class VideoDecoder; class AudioDecoder; -class TextDecoder; +class CaptionDecoder; class DecoderPart; /** @class Decoder. @@ -45,7 +45,7 @@ public: boost::shared_ptr video; boost::shared_ptr audio; - boost::shared_ptr subtitle; + boost::shared_ptr 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. diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index 3d4ce8a7b..bb3bdb13e 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -26,8 +26,8 @@ #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 @@ -59,9 +59,9 @@ decoder_factory (shared_ptr content, shared_ptr log, bool fa return shared_ptr (new TextCaptionFileDecoder (rc, log)); } - shared_ptr dsc = dynamic_pointer_cast (content); + shared_ptr dsc = dynamic_pointer_cast (content); if (dsc) { - return shared_ptr (new DCPTextDecoder (dsc, log)); + return shared_ptr (new DCPSubtitleDecoder (dsc, log)); } shared_ptr vmc = dynamic_pointer_cast (content); diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index e18977944..dd4ed7063 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -32,7 +32,7 @@ #include "log.h" #include "exceptions.h" #include "frame_rate_change.h" -#include "text_content.h" +#include "caption_content.h" #include #include extern "C" { @@ -85,7 +85,7 @@ FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr no { 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 c = node->node_children ("SubtitleStream"); for (list::const_iterator i = c.begin(); i != c.end(); ++i) { @@ -135,12 +135,12 @@ FFmpegContent::FFmpegContent (shared_ptr film, vector ((*i)->video); need_audio = static_cast ((*i)->audio); - need_subtitle = static_cast ((*i)->subtitle); + need_caption = static_cast ((*i)->caption); } while (i != c.end ()) { @@ -150,8 +150,8 @@ FFmpegContent::FFmpegContent (shared_ptr film, vector ((*i)->audio)) { throw JoinError (_("Content to be joined must all have or not have audio")); } - if (need_subtitle != static_cast ((*i)->subtitle)) { - throw JoinError (_("Content to be joined must all have or not have subtitles")); + if (need_caption != static_cast ((*i)->caption)) { + throw JoinError (_("Content to be joined must all have or not have captions")); } ++i; } @@ -162,8 +162,8 @@ FFmpegContent::FFmpegContent (shared_ptr film, vector ref = dynamic_pointer_cast (c[0]); @@ -171,7 +171,7 @@ FFmpegContent::FFmpegContent (shared_ptr film, vector fc = dynamic_pointer_cast (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.")); } } @@ -209,8 +209,8 @@ FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const } } - if (subtitle) { - subtitle->as_xml (node); + if (caption) { + caption->as_xml (node); } boost::mutex::scoped_lock lm (_mutex); @@ -303,7 +303,7 @@ FFmpegContent::examine (shared_ptr job) _subtitle_streams = examiner->subtitle_streams (); if (!_subtitle_streams.empty ()) { - subtitle.reset (new TextContent (this)); + caption.reset (new CaptionContent (this)); _subtitle_stream = _subtitle_streams.front (); } @@ -426,8 +426,8 @@ FFmpegContent::identifier () const 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); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 909a9d443..9478d8816 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -28,7 +28,7 @@ #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" @@ -39,7 +39,7 @@ #include "film.h" #include "audio_decoder.h" #include "compose.hpp" -#include "text_content.h" +#include "caption_content.h" #include "audio_content.h" #include #include @@ -97,9 +97,9 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr 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); @@ -184,7 +184,7 @@ FFmpegDecoder::pass () 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 (); @@ -549,9 +549,9 @@ FFmpegDecoder::decode_subtitle_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; } @@ -593,7 +593,7 @@ FFmpegDecoder::decode_subtitle_packet () } if (_current_subtitle_to) { - subtitle->emit_stop (*_current_subtitle_to); + caption->emit_stop (*_current_subtitle_to); } avsubtitle_free (&sub); @@ -669,7 +669,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime static_cast (rect->h) / target_height ); - subtitle->emit_bitmap_start (from, image, scaled_rect); + caption->emit_bitmap_start (from, image, scaled_rect); } void @@ -702,6 +702,6 @@ FFmpegDecoder::decode_ass_subtitle (string ass, ContentTime from) ); BOOST_FOREACH (sub::Subtitle const & i, sub::collect > (raw)) { - subtitle->emit_plain_start (from, i); + caption->emit_plain_start (from, i); } } diff --git a/src/lib/film.cc b/src/lib/film.cc index 0be1ddd7b..f6941c1c7 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -46,7 +46,7 @@ #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" @@ -696,11 +696,11 @@ Film::isdcf_name (bool if_created_now) const bool burnt_in = true; BOOST_FOREACH (shared_ptr 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; } } @@ -1081,7 +1081,7 @@ Film::add_content (shared_ptr c) /* 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 ()); } @@ -1371,8 +1371,8 @@ Film::subtitle_language () const ContentList cl = content (); BOOST_FOREACH (shared_ptr& c, cl) { - if (c->subtitle) { - languages.insert (c->subtitle->language ()); + if (c->caption) { + languages.insert (c->caption->language ()); } } diff --git a/src/lib/hints.cc b/src/lib/hints.cc index d29002ad5..eb3ea1d02 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -23,7 +23,7 @@ #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" @@ -56,8 +56,8 @@ get_hints (shared_ptr film) bool big_font_files = false; if (film->interop ()) { BOOST_FOREACH (shared_ptr i, content) { - if (i->subtitle) { - BOOST_FOREACH (shared_ptr j, i->subtitle->fonts ()) { + if (i->caption) { + BOOST_FOREACH (shared_ptr j, i->caption->fonts ()) { for (int k = 0; k < FontFiles::VARIANTS; ++k) { optional const p = j->file (static_cast (k)); if (p && boost::filesystem::file_size (p.get()) >= (640 * 1024)) { diff --git a/src/lib/plain_text_file.cc b/src/lib/plain_text_file.cc deleted file mode 100644 index 666953c40..000000000 --- a/src/lib/plain_text_file.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright (C) 2014-2018 Carl Hetherington - - 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 . - -*/ - -#include "plain_text_file.h" -#include "cross.h" -#include "exceptions.h" -#include "text_caption_file_content.h" -#include -#include -#include -#include -#include -#include - -#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 content) -{ - Data in (content->path (0)); - - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector* detector = ucsdet_open (&status); - ucsdet_setText (detector, reinterpret_cast (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 utf16 (new uint16_t[in.size() * 2]); - int const utf16_len = ucnv_toUChars ( - to_utf16, reinterpret_cast(utf16.get()), in.size() * 2, - reinterpret_cast (in.data().get()), in.size(), - &status - ); - - UConverter* to_utf8 = ucnv_open ("UTF-8", &status); - /* Another guess */ - scoped_array utf8 (new char[utf16_len * 2]); - ucnv_fromUChars (to_utf8, utf8.get(), utf16_len * 2, reinterpret_cast(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 > (reader->subtitles ()); - } - - delete reader; -} - -/** @return time of first subtitle, if there is one */ -optional -TextCaptionFile::first () const -{ - if (_subtitles.empty()) { - return optional(); - } - - 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 ()); -} diff --git a/src/lib/plain_text_file.h b/src/lib/plain_text_file.h deleted file mode 100644 index 8c74d9e59..000000000 --- a/src/lib/plain_text_file.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Copyright (C) 2014-2018 Carl Hetherington - - 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 . - -*/ - -#ifndef DCPOMATIC_PLAIN_TEXT_FILE_H -#define DCPOMATIC_PLAIN_TEXT_FILE_H - -#include "dcpomatic_time.h" -#include -#include -#include - -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); - - boost::optional first () const; - ContentTime length () const; - -protected: - std::vector _subtitles; -}; - -#endif diff --git a/src/lib/player.cc b/src/lib/player.cc index a7cd0fd94..7040bd530 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -40,8 +40,8 @@ #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" @@ -137,8 +137,8 @@ Player::setup_pieces () 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 dcp = dynamic_pointer_cast (decoder); @@ -165,10 +165,10 @@ Player::setup_pieces () decoder->audio->Data.connect (bind (&Player::audio, this, weak_ptr (piece), _1, _2)); } - if (decoder->subtitle) { - decoder->subtitle->BitmapStart.connect (bind (&Player::bitmap_text_start, this, weak_ptr (piece), _1)); - decoder->subtitle->PlainStart.connect (bind (&Player::plain_text_start, this, weak_ptr (piece), _1)); - decoder->subtitle->Stop.connect (bind (&Player::subtitle_stop, this, weak_ptr (piece), _1, _2)); + if (decoder->caption) { + decoder->caption->BitmapStart.connect (bind (&Player::bitmap_text_start, this, weak_ptr (piece), _1)); + decoder->caption->PlainStart.connect (bind (&Player::plain_text_start, this, weak_ptr (piece), _1)); + decoder->caption->Stop.connect (bind (&Player::subtitle_stop, this, weak_ptr (piece), _1, _2)); } } @@ -209,9 +209,9 @@ Player::playlist_content_changed (weak_ptr w, int property, bool freque 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 ) { @@ -220,17 +220,17 @@ Player::playlist_content_changed (weak_ptr w, int property, bool freque 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 || @@ -289,11 +289,11 @@ Player::film_changed (Film::Property p) } list -Player::transform_bitmap_texts (list subs) const +Player::transform_bitmap_captions (list subs) const { list all; - for (list::const_iterator i = subs.begin(); i != subs.end(); ++i) { + for (list::const_iterator i = subs.begin(); i != subs.end(); ++i) { if (!i->image) { continue; } @@ -406,11 +406,11 @@ Player::get_subtitle_fonts () list > fonts; BOOST_FOREACH (shared_ptr& 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 > f = p->content->subtitle->fonts (); + list > f = p->content->caption->fonts (); copy (f.begin(), f.end(), back_inserter (fonts)); } } @@ -553,7 +553,7 @@ Player::pass () /* 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; } @@ -663,10 +663,10 @@ Player::subtitles_for_frame (DCPTime time) const 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 c = transform_bitmap_texts (i.image); + list c = transform_bitmap_captions (i.image); copy (c.begin(), c.end(), back_inserter (subtitles)); /* Text subtitles (rendered to an image) */ @@ -847,22 +847,22 @@ Player::bitmap_text_start (weak_ptr wp, ContentBitmapCaption subtitle) } /* 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 @@ -881,10 +881,10 @@ Player::plain_text_start (weak_ptr wp, ContentTextCaption subtitle) } 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; @@ -901,17 +901,17 @@ Player::plain_text_start (weak_ptr wp, ContentTextCaption subtitle) } 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 wp, ContentTime to, TextType type) +Player::subtitle_stop (weak_ptr wp, ContentTime to, CaptionType type) { - if (!_active_text[type].have (wp)) { + if (!_active_captions[type].have (wp)) { return; } @@ -926,10 +926,10 @@ Player::subtitle_stop (weak_ptr wp, ContentTime to, TextType type) return; } - pair from = _active_text[type].add_to (wp, dcp_to); + pair 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)); } } @@ -951,8 +951,8 @@ Player::seek (DCPTime time, bool accurate) } _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 i, _pieces) { @@ -1012,8 +1012,8 @@ void Player::do_emit_video (shared_ptr 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); } } diff --git a/src/lib/player.h b/src/lib/player.h index 16e9d57a5..5b6a0b7b4 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -23,7 +23,7 @@ #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" @@ -101,7 +101,7 @@ public: /** Emitted when a caption is ready. This signal may be emitted considerably * after the corresponding Video. */ - boost::signals2::signal Text; + boost::signals2::signal Caption; private: friend class PlayerWrapper; @@ -116,7 +116,7 @@ private: void film_changed (Film::Property); void playlist_changed (); void playlist_content_changed (boost::weak_ptr, int, bool); - std::list transform_bitmap_texts (std::list) const; + std::list transform_bitmap_captions (std::list) const; Frame dcp_to_content_video (boost::shared_ptr piece, DCPTime t) const; DCPTime content_video_to_dcp (boost::shared_ptr piece, Frame f) const; Frame dcp_to_resampled_audio (boost::shared_ptr piece, DCPTime t) const; @@ -128,7 +128,7 @@ private: void audio (boost::weak_ptr, AudioStreamPtr, ContentAudio); void bitmap_text_start (boost::weak_ptr, ContentBitmapCaption); void plain_text_start (boost::weak_ptr, ContentTextCaption); - void subtitle_stop (boost::weak_ptr, ContentTime, TextType); + void subtitle_stop (boost::weak_ptr, ContentTime, CaptionType); DCPTime one_video_frame () const; void fill_audio (DCPTimePeriod period); std::pair, DCPTime> discard_audio ( @@ -196,7 +196,7 @@ private: Empty _black; Empty _silent; - ActiveCaptions _active_text[TEXT_COUNT]; + ActiveCaptions _active_captions[CAPTION_COUNT]; boost::shared_ptr _audio_processor; boost::signals2::scoped_connection _film_changed_connection; diff --git a/src/lib/player_caption.h b/src/lib/player_caption.h index 2875790df..2f7e909aa 100644 --- a/src/lib/player_caption.h +++ b/src/lib/player_caption.h @@ -18,10 +18,10 @@ */ -#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" @@ -34,8 +34,8 @@ public: void add_fonts (std::list > fonts_); std::list > fonts; - /** BitmapTexts, with their rectangles transformed as specified by their content */ - std::list image; + /** BitmapCaptions, with their rectangles transformed as specified by their content */ + std::list image; std::list text; }; diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 13b4d7337..a5451bafa 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 Carl Hetherington + Copyright (C) 2013-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -20,7 +20,7 @@ #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" @@ -135,7 +135,7 @@ Playlist::maybe_sequence () DCPTime next; BOOST_FOREACH (shared_ptr 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; } @@ -155,7 +155,7 @@ Playlist::video_identifier () const string t; BOOST_FOREACH (shared_ptr i, _content) { - if (i->video || (i->subtitle && i->subtitle->burn())) { + if (i->video || (i->caption && i->caption->burn())) { t += i->identifier (); } } @@ -366,7 +366,7 @@ Playlist::subtitle_end () const { DCPTime end; BOOST_FOREACH (shared_ptr i, _content) { - if (i->subtitle) { + if (i->caption) { end = max (end, i->end ()); } } diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 77d583353..8fb15c133 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -528,7 +528,7 @@ ReelWriter::write (shared_ptr audio) } 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 */ @@ -565,7 +565,7 @@ ReelWriter::write (PlayerCaption subs, TextType type, DCPTimePeriod period) _subtitle_asset->add (shared_ptr(new dcp::SubtitleString(i))); } - BOOST_FOREACH (BitmapText i, subs.image) { + BOOST_FOREACH (BitmapCaption i, subs.image) { _subtitle_asset->add ( shared_ptr( new dcp::SubtitleImage( diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index cd22fa775..06f19f15a 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -60,7 +60,7 @@ public: void fake_write (Frame frame, Eyes eyes, int size); void repeat_write (Frame frame, Eyes eyes); void write (boost::shared_ptr audio); - void write (PlayerCaption text, TextType type, DCPTimePeriod period); + void write (PlayerCaption text, CaptionType type, DCPTimePeriod period); void finish (); boost::shared_ptr create_reel (std::list const & refs, std::list > const & fonts); diff --git a/src/lib/text_caption_file.cc b/src/lib/text_caption_file.cc new file mode 100644 index 000000000..11d4517db --- /dev/null +++ b/src/lib/text_caption_file.cc @@ -0,0 +1,116 @@ +/* + Copyright (C) 2014-2018 Carl Hetherington + + 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 . + +*/ + +#include "text_caption_file.h" +#include "cross.h" +#include "exceptions.h" +#include "text_caption_file_content.h" +#include +#include +#include +#include +#include +#include + +#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 content) +{ + Data in (content->path (0)); + + UErrorCode status = U_ZERO_ERROR; + UCharsetDetector* detector = ucsdet_open (&status); + ucsdet_setText (detector, reinterpret_cast (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 utf16 (new uint16_t[in.size() * 2]); + int const utf16_len = ucnv_toUChars ( + to_utf16, reinterpret_cast(utf16.get()), in.size() * 2, + reinterpret_cast (in.data().get()), in.size(), + &status + ); + + UConverter* to_utf8 = ucnv_open ("UTF-8", &status); + /* Another guess */ + scoped_array utf8 (new char[utf16_len * 2]); + ucnv_fromUChars (to_utf8, utf8.get(), utf16_len * 2, reinterpret_cast(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 > (reader->subtitles ()); + } + + delete reader; +} + +/** @return time of first subtitle, if there is one */ +optional +TextCaptionFile::first () const +{ + if (_subtitles.empty()) { + return optional(); + } + + 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 ()); +} diff --git a/src/lib/text_caption_file.h b/src/lib/text_caption_file.h new file mode 100644 index 000000000..4a5657a08 --- /dev/null +++ b/src/lib/text_caption_file.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014-2018 Carl Hetherington + + 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 . + +*/ + +#ifndef DCPOMATIC_TEXT_CAPTION_FILE_H +#define DCPOMATIC_TEXT_CAPTION_FILE_H + +#include "dcpomatic_time.h" +#include +#include +#include + +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); + + boost::optional first () const; + ContentTime length () const; + +protected: + std::vector _subtitles; +}; + +#endif diff --git a/src/lib/text_caption_file_content.cc b/src/lib/text_caption_file_content.cc index df5de93ef..cb7d1511b 100644 --- a/src/lib/text_caption_file_content.cc +++ b/src/lib/text_caption_file_content.cc @@ -20,10 +20,10 @@ #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 #include #include @@ -38,14 +38,14 @@ using dcp::raw_convert; TextCaptionFileContent::TextCaptionFileContent (shared_ptr film, boost::filesystem::path path) : Content (film, path) { - subtitle.reset (new TextContent (this)); + caption.reset (new CaptionContent (this)); } TextCaptionFileContent::TextCaptionFileContent (shared_ptr film, cxml::ConstNodePtr node, int version) : Content (film, node) , _length (node->number_child ("Length")) { - subtitle = TextContent::from_xml (this, node, version); + caption = CaptionContent::from_xml (this, node, version); } void @@ -55,11 +55,11 @@ TextCaptionFileContent::examine (boost::shared_ptr job) 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 (new Font (TEXT_FONT_ID))); + caption->add_font (shared_ptr (new Font (TEXT_FONT_ID))); } string @@ -80,8 +80,8 @@ TextCaptionFileContent::as_xml (xmlpp::Node* node, bool with_paths) const node->add_child("Type")->add_child_text ("TextSubtitle"); Content::as_xml (node, with_paths); - if (subtitle) { - subtitle->as_xml (node); + if (caption) { + caption->as_xml (node); } node->add_child("Length")->add_child_text (raw_convert (_length.get ())); diff --git a/src/lib/text_caption_file_decoder.cc b/src/lib/text_caption_file_decoder.cc index d1a72faeb..46217e49b 100644 --- a/src/lib/text_caption_file_decoder.cc +++ b/src/lib/text_caption_file_decoder.cc @@ -20,8 +20,8 @@ #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 #include #include @@ -43,7 +43,7 @@ TextCaptionFileDecoder::TextCaptionFileDecoder (shared_ptrsubtitle, log, first)); + caption.reset (new CaptionDecoder (this, content->caption, log, first)); } void @@ -73,7 +73,7 @@ TextCaptionFileDecoder::pass () } ContentTimePeriod const p = content_time_period (_subtitles[_next]); - subtitle->emit_plain (p, _subtitles[_next]); + caption->emit_plain (p, _subtitles[_next]); ++_next; return false; diff --git a/src/lib/text_caption_file_decoder.h b/src/lib/text_caption_file_decoder.h index 7f889e72d..769777571 100644 --- a/src/lib/text_caption_file_decoder.h +++ b/src/lib/text_caption_file_decoder.h @@ -18,10 +18,10 @@ */ -#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; diff --git a/src/lib/text_content.cc b/src/lib/text_content.cc deleted file mode 100644 index 8e1e416eb..000000000 --- a/src/lib/text_content.cc +++ /dev/null @@ -1,528 +0,0 @@ -/* - Copyright (C) 2013-2018 Carl Hetherington - - 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 . - -*/ - -#include "text_content.h" -#include "util.h" -#include "exceptions.h" -#include "font.h" -#include "content.h" -#include -#include -#include -#include -#include - -#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::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 (); - } - - /* Otherwise we can drop through to the newer logic */ - } - - if (!node->optional_number_child("SubtitleXOffset") && !node->optional_number_child("SubtitleOffset")) { - return shared_ptr (); - } - - return shared_ptr (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("LineSpacing").get_value_or (1)) - , _outline_width (node->optional_number_child("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 ("SubtitleXOffset"); - _y_offset = node->number_child ("SubtitleYOffset"); - } else { - _y_offset = node->number_child ("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 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 ("SubtitleXScale"); - _y_scale = node->number_child ("SubtitleYScale"); - } else { - _x_scale = _y_scale = node->number_child ("SubtitleScale"); - } - - optional r = node->optional_number_child("Red"); - optional g = node->optional_number_child("Green"); - optional b = node->optional_number_child("Blue"); - if (r && g && b) { - _colour = dcp::Colour (*r, *g, *b); - } - - if (version >= 36) { - optional er = node->optional_number_child("EffectRed"); - optional eg = node->optional_number_child("EffectGreen"); - optional eb = node->optional_number_child("EffectBlue"); - if (er && eg && eb) { - _effect_colour = dcp::Colour (*er, *eg, *eb); - } - } else { - _effect_colour = dcp::Colour ( - node->optional_number_child("OutlineRed").get_value_or(255), - node->optional_number_child("OutlineGreen").get_value_or(255), - node->optional_number_child("OutlineBlue").get_value_or(255) - ); - } - - optional fi = node->optional_number_child("SubtitleFadeIn"); - if (fi) { - _fade_in = ContentTime (*fi); - } - optional fo = node->optional_number_child("SubtitleFadeOut"); - if (fo) { - _fade_out = ContentTime (*fo); - } - - _language = node->optional_string_child ("SubtitleLanguage").get_value_or (""); - - list fonts = node->node_children ("Font"); - for (list::const_iterator i = fonts.begin(); i != fonts.end(); ++i) { - _fonts.push_back (shared_ptr (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 > c) - : ContentPart (parent) -{ - shared_ptr ref = c[0]->subtitle; - DCPOMATIC_ASSERT (ref); - list > 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 > fonts = c[i]->subtitle->fonts (); - if (fonts.size() != ref_fonts.size()) { - throw JoinError (_("Content to be joined must use the same fonts.")); - } - - list >::const_iterator j = ref_fonts.begin (); - list >::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 (_x_offset)); - root->add_child("SubtitleYOffset")->add_child_text (raw_convert (_y_offset)); - root->add_child("SubtitleXScale")->add_child_text (raw_convert (_x_scale)); - root->add_child("SubtitleYScale")->add_child_text (raw_convert (_y_scale)); - root->add_child("SubtitleLanguage")->add_child_text (_language); - if (_colour) { - root->add_child("Red")->add_child_text (raw_convert (_colour->r)); - root->add_child("Green")->add_child_text (raw_convert (_colour->g)); - root->add_child("Blue")->add_child_text (raw_convert (_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 (_effect_colour->r)); - root->add_child("EffectGreen")->add_child_text (raw_convert (_effect_colour->g)); - root->add_child("EffectBlue")->add_child_text (raw_convert (_effect_colour->b)); - } - root->add_child("LineSpacing")->add_child_text (raw_convert (_line_spacing)); - if (_fade_in) { - root->add_child("SubtitleFadeIn")->add_child_text (raw_convert (_fade_in->get())); - } - if (_fade_out) { - root->add_child("SubtitleFadeOut")->add_child_text (raw_convert (_fade_out->get())); - } - root->add_child("OutlineWidth")->add_child_text (raw_convert (_outline_width)); - - for (list >::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 (x_scale()) - + "_" + raw_convert (y_scale()) - + "_" + raw_convert (x_offset()) - + "_" + raw_convert (y_offset()) - + "_" + raw_convert (line_spacing()) - + "_" + raw_convert (fade_in().get_value_or(ContentTime()).get()) - + "_" + raw_convert (fade_out().get_value_or(ContentTime()).get()) - + "_" + raw_convert (outline_width()) - + "_" + raw_convert (colour().get_value_or(dcp::Colour(255, 255, 255)).to_argb_string()) - + "_" + raw_convert (dcp::effect_to_string(effect().get_value_or(dcp::NONE))) - + "_" + raw_convert (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 f, _fonts) { - for (int i = 0; i < FontFiles::VARIANTS; ++i) { - s += "_" + f->file(static_cast(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) -{ - _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 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(), TextContentProperty::COLOUR); -} - -void -TextContent::set_effect (dcp::Effect e) -{ - maybe_set (_effect, e, TextContentProperty::EFFECT); -} - -void -TextContent::unset_effect () -{ - maybe_set (_effect, optional(), 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(), 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(), 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(), 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 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); -} diff --git a/src/lib/text_content.h b/src/lib/text_content.h deleted file mode 100644 index cca678ad2..000000000 --- a/src/lib/text_content.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - Copyright (C) 2013-2018 Carl Hetherington - - 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 . - -*/ - -#ifndef DCPOMATIC_SUBTITLE_CONTENT_H -#define DCPOMATIC_SUBTITLE_CONTENT_H - -#include "content_part.h" -#include -#include -#include - -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 >); - - void as_xml (xmlpp::Node *) const; - std::string identifier () const; - void take_settings_from (boost::shared_ptr c); - - void add_font (boost::shared_ptr 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 > fonts () const { - boost::mutex::scoped_lock lm (_mutex); - return _fonts; - } - - std::string language () const { - boost::mutex::scoped_lock lm (_mutex); - return _language; - } - - boost::optional colour () const { - boost::mutex::scoped_lock lm (_mutex); - return _colour; - } - - boost::optional effect () const { - boost::mutex::scoped_lock lm (_mutex); - return _effect; - } - - boost::optional 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 fade_in () const { - boost::mutex::scoped_lock lm (_mutex); - return _fade_in; - } - - boost::optional 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 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 _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 > _fonts; - boost::optional _colour; - boost::optional _effect; - boost::optional _effect_colour; - /** scaling factor for line spacing; 1 is "standard", < 1 is closer together, > 1 is further apart */ - double _line_spacing; - boost::optional _fade_in; - boost::optional _fade_out; - int _outline_width; - TextType _type; -}; - -#endif diff --git a/src/lib/text_decoder.cc b/src/lib/text_decoder.cc deleted file mode 100644 index 932a57564..000000000 --- a/src/lib/text_decoder.cc +++ /dev/null @@ -1,257 +0,0 @@ -/* - Copyright (C) 2013-2017 Carl Hetherington - - 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 . - -*/ - -#include "text_decoder.h" -#include "text_content.h" -#include "util.h" -#include "log.h" -#include "compose.hpp" -#include -#include -#include -#include -#include - -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 c, - shared_ptr 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, dcpomatic::Rect rect) -{ - BitmapStart (ContentBitmapCaption (from, _content->type(), image, rect)); - _position = from; -} - -void -TextDecoder::emit_plain_start (ContentTime from, list 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 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 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 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 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 (); -} diff --git a/src/lib/text_decoder.h b/src/lib/text_decoder.h deleted file mode 100644 index ed2763916..000000000 --- a/src/lib/text_decoder.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - Copyright (C) 2013-2017 Carl Hetherington - - 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 . - -*/ - -#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 -#include - -namespace sub { - class Subtitle; -} - -class Image; - -class TextDecoder : public DecoderPart -{ -public: - TextDecoder ( - Decoder* parent, - boost::shared_ptr, - boost::shared_ptr log, - ContentTime first - ); - - ContentTime position () const { - return _position; - } - - void emit_bitmap_start (ContentTime from, boost::shared_ptr image, dcpomatic::Rect rect); - void emit_plain_start (ContentTime from, std::list s); - void emit_plain_start (ContentTime from, sub::Subtitle const & subtitle); - void emit_plain (ContentTimePeriod period, std::list s); - void emit_plain (ContentTimePeriod period, sub::Subtitle const & subtitle); - void emit_stop (ContentTime to); - - void seek (); - - boost::shared_ptr content () const { - return _content; - } - - boost::signals2::signal BitmapStart; - boost::signals2::signal PlainStart; - boost::signals2::signal Stop; - -private: - boost::shared_ptr _content; - ContentTime _position; -}; - -#endif diff --git a/src/lib/types.cc b/src/lib/types.cc index 68e00c8d5..97373b24e 100644 --- a/src/lib/types.cc +++ b/src/lib/types.cc @@ -91,26 +91,26 @@ Crop::as_xml (xmlpp::Node* node) const node->add_child("BottomCrop")->add_child_text (raw_convert (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); } diff --git a/src/lib/types.h b/src/lib/types.h index e52daca00..3337087eb 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -31,7 +31,7 @@ class Content; class VideoContent; class AudioContent; -class TextContent; +class CaptionContent; class FFmpegContent; namespace cxml { @@ -129,15 +129,15 @@ enum ReelType 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. diff --git a/src/lib/writer.cc b/src/lib/writer.cc index ea4a6d29b..c0a774f03 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -95,8 +95,8 @@ Writer::Writer (shared_ptr film, weak_ptr j) 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 */ @@ -665,16 +665,16 @@ Writer::can_fake_write (Frame frame) const } 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 diff --git a/src/lib/writer.h b/src/lib/writer.h index a776e54c3..f67419072 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -104,7 +104,7 @@ public: bool can_repeat (Frame) const; void repeat (Frame, Eyes); void write (boost::shared_ptr, DCPTime time); - void write (PlayerCaption text, TextType type, DCPTimePeriod period); + void write (PlayerCaption text, CaptionType type, DCPTimePeriod period); void write (std::list > fonts); void write (ReferencedReelAsset asset); void finish (); @@ -124,7 +124,7 @@ private: boost::weak_ptr _job; std::vector _reels; std::vector::iterator _audio_reel; - std::vector::iterator _text_reel[TEXT_COUNT]; + std::vector::iterator _caption_reel[CAPTION_COUNT]; /** our thread, or 0 */ boost::thread* _thread; diff --git a/src/lib/wscript b/src/lib/wscript index 71c94c28b..a841e5b55 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -38,6 +38,8 @@ sources = """ audio_ring_buffers.cc audio_stream.cc butler.cc + caption_content.cc + caption_decoder.cc case_insensitive_sorter.cc cinema.cc cinema_kdms.cc @@ -55,8 +57,8 @@ sources = """ 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 @@ -132,9 +134,7 @@ sources = """ 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 diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 934e57505..9262be1b5 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -71,7 +71,7 @@ #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 #include #include @@ -563,7 +563,7 @@ private: { DCPOMATIC_ASSERT (_clipboard); - PasteDialog* d = new PasteDialog (this, static_cast(_clipboard->video), static_cast(_clipboard->audio), static_cast(_clipboard->subtitle)); + PasteDialog* d = new PasteDialog (this, static_cast(_clipboard->video), static_cast(_clipboard->audio), static_cast(_clipboard->caption)); if (d->ShowModal() == wxID_OK) { BOOST_FOREACH (shared_ptr i, _film_editor->content_panel()->selected()) { if (d->video() && i->video) { @@ -574,9 +574,9 @@ private: 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); } } } diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index 3f56f4752..0af44fd05 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -27,7 +27,7 @@ #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" @@ -618,8 +618,8 @@ private: void setup_from_dcp (shared_ptr dcp) { - if (dcp->subtitle) { - dcp->subtitle->set_use (true); + if (dcp->caption) { + dcp->caption->set_use (true); } if (dcp->video) { diff --git a/src/wx/caption_panel.cc b/src/wx/caption_panel.cc index 20a0ad143..c70a9ad8c 100644 --- a/src/wx/caption_panel.cc +++ b/src/wx/caption_panel.cc @@ -28,11 +28,11 @@ #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 #include @@ -216,16 +216,16 @@ CaptionPanel::film_content_changed (int property) } } 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: @@ -235,20 +235,20 @@ CaptionPanel::film_content_changed (int property) _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 dcp = dynamic_pointer_cast (scs); @@ -267,7 +267,7 @@ void CaptionPanel::use_toggled () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_use (_use->GetValue()); + i->caption->set_use (_use->GetValue()); } } @@ -277,10 +277,10 @@ CaptionPanel::type_changed () BOOST_FOREACH (shared_ptr 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; } } @@ -290,7 +290,7 @@ void CaptionPanel::burn_toggled () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_burn (_burn->GetValue()); + i->caption->set_burn (_burn->GetValue()); } } @@ -305,9 +305,9 @@ CaptionPanel::setup_sensitivity () shared_ptr fc = boost::dynamic_pointer_cast (i); shared_ptr sc = boost::dynamic_pointer_cast (i); shared_ptr dc = boost::dynamic_pointer_cast (i); - shared_ptr dsc = boost::dynamic_pointer_cast (i); + shared_ptr dsc = boost::dynamic_pointer_cast (i); if (fc) { - if (fc->subtitle) { + if (fc->caption) { ++ffmpeg_subs; ++any_subs; } @@ -373,7 +373,7 @@ void CaptionPanel::x_offset_changed () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_x_offset (_x_offset->GetValue() / 100.0); + i->caption->set_x_offset (_x_offset->GetValue() / 100.0); } } @@ -381,7 +381,7 @@ void CaptionPanel::y_offset_changed () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_y_offset (_y_offset->GetValue() / 100.0); + i->caption->set_y_offset (_y_offset->GetValue() / 100.0); } } @@ -390,7 +390,7 @@ CaptionPanel::x_scale_changed () { 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); } } @@ -398,7 +398,7 @@ void CaptionPanel::y_scale_changed () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_y_scale (_y_scale->GetValue() / 100.0); + i->caption->set_y_scale (_y_scale->GetValue() / 100.0); } } @@ -406,7 +406,7 @@ void CaptionPanel::line_spacing_changed () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_line_spacing (_line_spacing->GetValue() / 100.0); + i->caption->set_line_spacing (_line_spacing->GetValue() / 100.0); } } @@ -414,7 +414,7 @@ void CaptionPanel::language_changed () { BOOST_FOREACH (shared_ptr i, _parent->selected_subtitle ()) { - i->subtitle->set_language (wx_to_std (_language->GetValue())); + i->caption->set_language (wx_to_std (_language->GetValue())); } } @@ -422,16 +422,16 @@ void 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); } diff --git a/src/wx/content_panel.cc b/src/wx/content_panel.cc index 3dc0e2b63..9d6d9a006 100644 --- a/src/wx/content_panel.cc +++ b/src/wx/content_panel.cc @@ -28,7 +28,7 @@ #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" @@ -40,7 +40,7 @@ #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 #include #include @@ -196,7 +196,7 @@ ContentPanel::selected_subtitle () ContentList sc; BOOST_FOREACH (shared_ptr i, selected ()) { - if (i->subtitle) { + if (i->caption) { sc.push_back (i); } } @@ -447,7 +447,7 @@ ContentPanel::setup_sensitivity () _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); } diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 5a380ec4e..fcec93a31 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -32,7 +32,7 @@ #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 @@ -433,8 +433,8 @@ void 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 || diff --git a/src/wx/fonts_dialog.cc b/src/wx/fonts_dialog.cc index c295ec327..528b3999b 100644 --- a/src/wx/fonts_dialog.cc +++ b/src/wx/fonts_dialog.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2016 Carl Hetherington + Copyright (C) 2014-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -24,7 +24,7 @@ #include "font_files_dialog.h" #include "lib/font.h" #include "lib/content.h" -#include "lib/text_content.h" +#include "lib/caption_content.h" #include #include #include @@ -105,7 +105,7 @@ FontsDialog::setup () _fonts->DeleteAllItems (); size_t n = 0; - BOOST_FOREACH (shared_ptr i, content->subtitle->fonts ()) { + BOOST_FOREACH (shared_ptr i, content->caption->fonts ()) { wxListItem item; item.SetId (n); _fonts->InsertItem (item); @@ -145,7 +145,7 @@ FontsDialog::edit_clicked () 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; - BOOST_FOREACH (shared_ptr i, content->subtitle->fonts()) { + BOOST_FOREACH (shared_ptr i, content->caption->fonts()) { if (i->id() == id) { font = i; } diff --git a/src/wx/paste_dialog.cc b/src/wx/paste_dialog.cc index eade31490..07a3b156c 100644 --- a/src/wx/paste_dialog.cc +++ b/src/wx/paste_dialog.cc @@ -20,7 +20,7 @@ #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")); @@ -29,9 +29,9 @@ PasteDialog::PasteDialog (wxWindow* parent, bool video, bool audio, bool subtitl _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 (); } @@ -49,7 +49,7 @@ PasteDialog::audio () const } bool -PasteDialog::subtitle () const +PasteDialog::caption () const { - return _subtitle->GetValue (); + return _caption->GetValue (); } diff --git a/src/wx/paste_dialog.h b/src/wx/paste_dialog.h index 204f421d8..7de38fd2c 100644 --- a/src/wx/paste_dialog.h +++ b/src/wx/paste_dialog.h @@ -23,14 +23,14 @@ 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; }; diff --git a/src/wx/player_information.cc b/src/wx/player_information.cc index 9c5684e74..aab8c2cd5 100644 --- a/src/wx/player_information.cc +++ b/src/wx/player_information.cc @@ -131,7 +131,7 @@ PlayerInformation::triggered_update () 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")); diff --git a/src/wx/subtitle_appearance_dialog.cc b/src/wx/subtitle_appearance_dialog.cc index de6f1c8e8..c0a6a0df6 100644 --- a/src/wx/subtitle_appearance_dialog.cc +++ b/src/wx/subtitle_appearance_dialog.cc @@ -21,7 +21,7 @@ #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 @@ -126,7 +126,7 @@ SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr _effect->Append (_("Outline")); _effect->Append (_("Shadow"));; - optional colour = _content->subtitle->colour(); + optional colour = _content->caption->colour(); _force_colour->SetValue (static_cast(colour)); if (colour) { _colour->SetColour (wxColour (colour->r, colour->g, colour->b)); @@ -134,7 +134,7 @@ SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr _colour->SetColour (wxColour (255, 255, 255)); } - optional effect = _content->subtitle->effect(); + optional effect = _content->caption->effect(); _force_effect->SetValue (static_cast(effect)); if (effect) { switch (*effect) { @@ -152,7 +152,7 @@ SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr _effect->SetSelection (NONE); } - optional effect_colour = _content->subtitle->effect_colour(); + optional effect_colour = _content->caption->effect_colour(); _force_effect_colour->SetValue (static_cast(effect_colour)); if (effect_colour) { _effect_colour->SetColour (wxColour (effect_colour->r, effect_colour->g, effect_colour->b)); @@ -160,7 +160,7 @@ SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr _effect_colour->SetColour (wxColour (0, 0, 0)); } - optional fade_in = _content->subtitle->fade_in(); + optional fade_in = _content->caption->fade_in(); _force_fade_in->SetValue (static_cast(fade_in)); if (fade_in) { _fade_in->set (*fade_in, _content->active_video_frame_rate()); @@ -168,7 +168,7 @@ SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr _fade_in->set (ContentTime(), _content->active_video_frame_rate()); } - optional fade_out = _content->subtitle->fade_out(); + optional fade_out = _content->caption->fade_out(); _force_fade_out->SetValue (static_cast(fade_out)); if (fade_out) { _fade_out->set (*fade_out, _content->active_video_frame_rate ()); @@ -176,7 +176,7 @@ SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr _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)); @@ -206,42 +206,42 @@ SubtitleAppearanceDialog::apply () { 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::const_iterator i = _pickers.begin(); i != _pickers.end(); ++i) { @@ -272,11 +272,11 @@ SubtitleAppearanceDialog::setup_sensitivity () _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")); } } diff --git a/src/wx/subtitle_view.cc b/src/wx/subtitle_view.cc index f33d6eddf..6d34a93db 100644 --- a/src/wx/subtitle_view.cc +++ b/src/wx/subtitle_view.cc @@ -19,13 +19,13 @@ */ #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" @@ -85,8 +85,8 @@ SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr< _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); } diff --git a/src/wx/subtitle_view.h b/src/wx/subtitle_view.h index 222fc3890..445f646aa 100644 --- a/src/wx/subtitle_view.h +++ b/src/wx/subtitle_view.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2016 Carl Hetherington + Copyright (C) 2014-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -18,7 +18,7 @@ */ -#include "lib/content_text.h" +#include "lib/content_caption.h" #include #include #include diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc index d0a898b18..d3b291a9b 100644 --- a/src/wx/timeline.cc +++ b/src/wx/timeline.cc @@ -34,7 +34,7 @@ #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 @@ -228,7 +228,7 @@ Timeline::recreate_views () _views.push_back (shared_ptr (new TimelineAudioContentView (*this, i))); } - if (i->subtitle) { + if (i->caption) { _views.push_back (shared_ptr (new TimelineTextContentView (*this, i))); } diff --git a/src/wx/timeline_text_content_view.cc b/src/wx/timeline_text_content_view.cc index b4820bfea..bb874449e 100644 --- a/src/wx/timeline_text_content_view.cc +++ b/src/wx/timeline_text_content_view.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 Carl Hetherington + Copyright (C) 2013-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -19,7 +19,7 @@ */ #include "timeline_text_content_view.h" -#include "lib/text_content.h" +#include "lib/caption_content.h" #include "lib/content.h" using boost::shared_ptr; @@ -55,5 +55,5 @@ TimelineTextContentView::active () const { shared_ptr c = _content.lock (); DCPOMATIC_ASSERT (c); - return c->subtitle && c->subtitle->use(); + return c->caption && c->caption->use(); } diff --git a/src/wx/timing_panel.cc b/src/wx/timing_panel.cc index 2a97f405f..9b516ccfa 100644 --- a/src/wx/timing_panel.cc +++ b/src/wx/timing_panel.cc @@ -26,8 +26,8 @@ #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" @@ -282,7 +282,7 @@ TimingPanel::film_content_changed (int property) ++count_ac; content = i; } - if (i->subtitle && i->video_frame_rate()) { + if (i->caption && i->video_frame_rate()) { ++count_sc; content = i; } diff --git a/test/dcp_subtitle_test.cc b/test/dcp_subtitle_test.cc index e5d0408bb..48f88f8dc 100644 --- a/test/dcp_subtitle_test.cc +++ b/test/dcp_subtitle_test.cc @@ -25,16 +25,16 @@ #include #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 @@ -65,14 +65,14 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_test) film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR")); film->set_name ("frobozz"); film->set_interop (false); - shared_ptr content (new DCPTextContent (film, "test/data/dcp_sub.xml")); + shared_ptr 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 ()); @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_within_dcp_test) BOOST_REQUIRE (!wait_for_jobs ()); shared_ptr decoder (new DCPDecoder (content, film->log(), false)); - decoder->subtitle->PlainStart.connect (bind (store, _1)); + decoder->caption->PlainStart.connect (bind (store, _1)); stored = optional (); while (!decoder->pass() && !stored) {} @@ -109,12 +109,12 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_test2) film->set_container (Ratio::from_id ("185")); film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR")); film->set_name ("frobozz"); - shared_ptr content (new DCPTextContent (film, "test/data/dcp_sub2.xml")); + shared_ptr content (new DCPSubtitleContent (film, "test/data/dcp_sub2.xml")); film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - shared_ptr decoder (new DCPTextDecoder (content, film->log())); - decoder->subtitle->PlainStart.connect (bind (store, _1)); + shared_ptr decoder (new DCPSubtitleDecoder (content, film->log())); + decoder->caption->PlainStart.connect (bind (store, _1)); stored = optional (); while (!decoder->pass ()) { @@ -132,17 +132,17 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_test3) film->set_dcp_content_type (DCPContentType::from_isdcf_name ("TLR")); film->set_name ("frobozz"); film->set_interop (true); - shared_ptr content (new DCPTextContent (film, "test/data/dcp_sub3.xml")); + shared_ptr 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 decoder (new DCPTextDecoder (content, film->log())); + shared_ptr decoder (new DCPSubtitleDecoder (content, film->log())); stored = optional (); 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 s = stored->subs; list::const_iterator i = s.begin (); @@ -165,14 +165,14 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_test4) shared_ptr film = new_test_film2 ("dcp_subtitle_test4"); film->set_interop (true); - shared_ptr content (new DCPTextContent (film, "test/data/dcp_sub3.xml")); + shared_ptr content (new DCPSubtitleContent (film, "test/data/dcp_sub3.xml")); film->examine_and_add_content (content); - shared_ptr content2 (new DCPTextContent (film, "test/data/dcp_sub3.xml")); + shared_ptr 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 (new Font ("font1"))); - content2->subtitle->add_font (shared_ptr (new Font ("font2"))); + content->caption->add_font (shared_ptr (new Font ("font1"))); + content2->caption->add_font (shared_ptr (new Font ("font2"))); film->make_dcp (); BOOST_REQUIRE (!wait_for_jobs ()); diff --git a/test/ffmpeg_encoder_test.cc b/test/ffmpeg_encoder_test.cc index 65ca59d34..d9dd0f383 100644 --- a/test/ffmpeg_encoder_test.cc +++ b/test/ffmpeg_encoder_test.cc @@ -28,7 +28,7 @@ #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 @@ -124,9 +124,9 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test6) shared_ptr 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 (new TranscodeJob (film)); @@ -149,9 +149,9 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test7) shared_ptr 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 (new TranscodeJob (film)); FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test7.mov", FFmpegEncoder::FORMAT_PRORES, false); @@ -175,9 +175,9 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test2) shared_ptr 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 (new TranscodeJob (film)); @@ -200,9 +200,9 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test3) shared_ptr 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 (new TranscodeJob (film)); diff --git a/test/import_dcp_test.cc b/test/import_dcp_test.cc index c12f15fa1..1f5247392 100644 --- a/test/import_dcp_test.cc +++ b/test/import_dcp_test.cc @@ -25,7 +25,7 @@ #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" diff --git a/test/player_test.cc b/test/player_test.cc index d3b6df6da..4ff79b436 100644 --- a/test/player_test.cc +++ b/test/player_test.cc @@ -34,7 +34,7 @@ #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" @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test) shared_ptr 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 (new Player (film, film->playlist())); player->set_fast (); @@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test2) shared_ptr 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 (new Player (film, film->playlist())); player->set_fast (); diff --git a/test/remake_id_test.cc b/test/remake_id_test.cc index e7e9c67b2..79e12f7a0 100644 --- a/test/remake_id_test.cc +++ b/test/remake_id_test.cc @@ -20,7 +20,7 @@ #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" diff --git a/test/remake_with_subtitle_test.cc b/test/remake_with_subtitle_test.cc index 4e286523f..5c371e855 100644 --- a/test/remake_with_subtitle_test.cc +++ b/test/remake_with_subtitle_test.cc @@ -20,7 +20,7 @@ #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 @@ -37,14 +37,14 @@ BOOST_AUTO_TEST_CASE (remake_with_subtitle_test) shared_ptr content = dynamic_pointer_cast(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 ()); diff --git a/test/srt_subtitle_test.cc b/test/srt_subtitle_test.cc index 6fe430d77..28ef9606f 100644 --- a/test/srt_subtitle_test.cc +++ b/test/srt_subtitle_test.cc @@ -28,7 +28,7 @@ #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 #include @@ -51,8 +51,8 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test) 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 (); @@ -73,10 +73,10 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test2) 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 (); @@ -108,8 +108,8 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test3) 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 (); @@ -126,8 +126,8 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test4) film->set_name ("frobozz"); film->set_interop (false); shared_ptr 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 (); @@ -147,8 +147,8 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test5) film->set_interop (true); film->set_sequence (false); shared_ptr 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 (); @@ -165,8 +165,8 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test6) shared_ptr film = new_test_film2 ("srt_subtitle_test6"); film->set_interop (false); shared_ptr 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 (); @@ -190,7 +190,7 @@ BOOST_AUTO_TEST_CASE (srt_subtitle_test4) BOOST_CHECK_EQUAL (content->full_length(), DCPTime::from_seconds ((3 * 60) + 56.471)); shared_ptr decoder (new SubRipDecoder (content)); - list cts = decoder->get_plain_texts ( + list cts = decoder->get_plain_texts ( ContentTimePeriod ( ContentTime::from_seconds (109), ContentTime::from_seconds (110) ), false diff --git a/test/ssa_subtitle_test.cc b/test/ssa_subtitle_test.cc index b3e4f9d33..6d4eecd92 100644 --- a/test/ssa_subtitle_test.cc +++ b/test/ssa_subtitle_test.cc @@ -28,7 +28,7 @@ #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 #include @@ -51,8 +51,8 @@ BOOST_AUTO_TEST_CASE (ssa_subtitle_test1) 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 (); diff --git a/test/subtitle_charset_test.cc b/test/subtitle_charset_test.cc index 3e7df0a61..b15e3e70e 100644 --- a/test/subtitle_charset_test.cc +++ b/test/subtitle_charset_test.cc @@ -22,7 +22,7 @@ #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 diff --git a/test/subtitle_reel_number_test.cc b/test/subtitle_reel_number_test.cc index 27c6e2d0e..a82094a73 100644 --- a/test/subtitle_reel_number_test.cc +++ b/test/subtitle_reel_number_test.cc @@ -21,7 +21,7 @@ #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 @@ -46,8 +46,8 @@ BOOST_AUTO_TEST_CASE (subtitle_reel_number_test) shared_ptr 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); diff --git a/test/subtitle_trim_test.cc b/test/subtitle_trim_test.cc index 1174eb583..33bcf823f 100644 --- a/test/subtitle_trim_test.cc +++ b/test/subtitle_trim_test.cc @@ -19,7 +19,7 @@ */ #include "lib/film.h" -#include "lib/dcp_text_content.h" +#include "lib/dcp_subtitle_content.h" #include "test.h" #include @@ -29,7 +29,7 @@ using boost::shared_ptr; BOOST_AUTO_TEST_CASE (subtitle_trim_test1) { shared_ptr film = new_test_film2 ("subtitle_trim_test1"); - shared_ptr content (new DCPTextContent (film, "test/data/dcp_sub5.xml")); + shared_ptr content (new DCPSubtitleContent (film, "test/data/dcp_sub5.xml")); film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); diff --git a/test/vf_kdm_test.cc b/test/vf_kdm_test.cc index 1ed5ac810..8b6e215ba 100644 --- a/test/vf_kdm_test.cc +++ b/test/vf_kdm_test.cc @@ -25,7 +25,7 @@ #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"