X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fsubtitle_content.cc;h=1977861e17892798f6eabd27c4e774d59b6d7ba3;hb=4b0ece8d964961598ce4734ce25bb0aed66dbf7a;hp=f338517e407e35a4136eb1864d7db84b7f5bbd30;hpb=ac265d3d008328b9bdaf00c39ebcd86f263605c7;p=libdcp.git diff --git a/src/subtitle_content.cc b/src/subtitle_content.cc index f338517e..1977861e 100644 --- a/src/subtitle_content.cc +++ b/src/subtitle_content.cc @@ -17,15 +17,17 @@ */ +#include "raw_convert.h" #include "subtitle_content.h" #include "util.h" #include "xml.h" -#include "font.h" -#include "text.h" -#include "load_font.h" +#include "font_node.h" +#include "text_node.h" #include "subtitle_string.h" +#include "dcp_assert.h" +#include "AS_DCP.h" +#include "KM_util.h" #include -#include #include #include @@ -36,58 +38,50 @@ using std::ofstream; using std::stringstream; using std::cout; using boost::shared_ptr; -using boost::lexical_cast; using boost::optional; +using boost::dynamic_pointer_cast; using namespace dcp; +SubtitleContent::SubtitleContent () + : _reel_number ("1") +{ + +} + SubtitleContent::SubtitleContent (boost::filesystem::path file) : Content (file) - , _need_sort (false) + , _reel_number ("1") { - shared_ptr xml (new cxml::Document ("DCSubtitle")); - xml->read_file (file); - - _id = xml->string_child ("SubtitleID"); - _movie_title = xml->string_child ("MovieTitle"); - _reel_number = xml->string_child ("ReelNumber"); - _language = xml->string_child ("Language"); - xml->ignore_child ("LoadFont"); +} - list > font_nodes = type_children (xml, "Font"); - _load_font_nodes = type_children (xml, "LoadFont"); +void +SubtitleContent::parse_common (shared_ptr xml, list > font_nodes) +{ + _reel_number = xml->string_child ("ReelNumber"); + _language = xml->string_child ("Language"); /* Now make Subtitle objects to represent the raw XML nodes in a sane way. */ - + ParseState parse_state; examine_font_nodes (xml, font_nodes, parse_state); } -SubtitleContent::SubtitleContent (Fraction edit_rate, string movie_title, string language) - : Content (edit_rate) - , _movie_title (movie_title) - , _reel_number ("1") - , _language (language) - , _need_sort (false) -{ - -} - void SubtitleContent::examine_font_nodes ( shared_ptr xml, - list > const & font_nodes, + list > const & font_nodes, ParseState& parse_state ) { - for (list >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { + for (list >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { parse_state.font_nodes.push_back (*i); maybe_add_subtitle ((*i)->text, parse_state); - for (list >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) { + for (list >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) { parse_state.subtitle_nodes.push_back (*j); examine_text_nodes (xml, (*j)->text_nodes, parse_state); examine_font_nodes (xml, (*j)->font_nodes, parse_state); @@ -104,11 +98,11 @@ SubtitleContent::examine_font_nodes ( void SubtitleContent::examine_text_nodes ( shared_ptr xml, - list > const & text_nodes, + list > const & text_nodes, ParseState& parse_state ) { - for (list >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) { + for (list >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) { parse_state.text_nodes.push_back (*i); maybe_add_subtitle ((*i)->text, parse_state); examine_font_nodes (xml, (*i)->font_nodes, parse_state); @@ -127,40 +121,39 @@ SubtitleContent::maybe_add_subtitle (string text, ParseState const & parse_state return; } - assert (!parse_state.text_nodes.empty ()); - assert (!parse_state.subtitle_nodes.empty ()); + DCP_ASSERT (!parse_state.text_nodes.empty ()); + DCP_ASSERT (!parse_state.subtitle_nodes.empty ()); - dcp::Font effective_font (parse_state.font_nodes); - dcp::Text effective_text (*parse_state.text_nodes.back ()); - dcp::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ()); + dcp::FontNode effective_font (parse_state.font_nodes); + dcp::TextNode effective_text (*parse_state.text_nodes.back ()); + dcp::SubtitleNode effective_subtitle (*parse_state.subtitle_nodes.back ()); _subtitles.push_back ( - shared_ptr ( - new SubtitleString ( - font_id_to_name (effective_font.id), - effective_font.italic.get(), - effective_font.color.get(), - effective_font.size, - effective_subtitle.in, - effective_subtitle.out, - effective_text.v_position, - effective_text.v_align, - text, - effective_font.effect ? effective_font.effect.get() : NONE, - effective_font.effect_color.get(), - effective_subtitle.fade_up_time, - effective_subtitle.fade_down_time - ) + SubtitleString ( + effective_font.id, + effective_font.italic.get_value_or (false), + effective_font.colour.get_value_or (dcp::Colour (255, 255, 255)), + effective_font.size, + effective_font.aspect_adjust.get_value_or (1.0), + effective_subtitle.in, + effective_subtitle.out, + effective_text.v_position, + effective_text.v_align, + text, + effective_font.effect.get_value_or (NONE), + effective_font.effect_colour.get_value_or (dcp::Colour (0, 0, 0)), + effective_subtitle.fade_up_time, + effective_subtitle.fade_down_time ) ); } -list > -SubtitleContent::subtitles_at (Time t) const +list +SubtitleContent::subtitles_during (Time from, Time to) const { - list > s; - for (list >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) { - if ((*i)->in() <= t && t <= (*i)->out ()) { + list s; + for (list::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) { + if (i->out() >= from && i->in() <= to) { s.push_back (*i); } } @@ -168,159 +161,66 @@ SubtitleContent::subtitles_at (Time t) const return s; } -std::string -SubtitleContent::font_id_to_name (string id) const -{ - list >::const_iterator i = _load_font_nodes.begin(); - while (i != _load_font_nodes.end() && (*i)->id != id) { - ++i; - } - - if (i == _load_font_nodes.end ()) { - return ""; - } - - if ((*i)->uri == "arial.ttf") { - return "Arial"; - } - - return ""; -} - void -SubtitleContent::add (shared_ptr s) +SubtitleContent::add (SubtitleString s) { _subtitles.push_back (s); - _need_sort = true; } -struct SubtitleSorter { - bool operator() (shared_ptr a, shared_ptr b) { - if (a->in() != b->in()) { - return a->in() < b->in(); - } - return a->v_position() < b->v_position(); - } -}; - void -SubtitleContent::write_xml () const +SubtitleContent::write_xml (boost::filesystem::path p) const { - FILE* f = fopen_boost (file (), "r"); + FILE* f = fopen_boost (p, "w"); + if (!f) { + throw FileError ("Could not open file for writing", p, -1); + } + Glib::ustring const s = xml_as_string (); - fwrite (s.c_str(), 1, s.length(), f); + fwrite (s.c_str(), 1, s.bytes(), f); fclose (f); + + _file = p; } -Glib::ustring -SubtitleContent::xml_as_string () const +Time +SubtitleContent::latest_subtitle_out () const { - xmlpp::Document doc; - xmlpp::Element* root = doc.create_root_node ("DCSubtitle"); - root->set_attribute ("Version", "1.0"); + Time t; + for (list::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) { + if (i->out() > t) { + t = i->out (); + } + } - root->add_child("SubtitleID")->add_child_text (_id); - root->add_child("MovieTitle")->add_child_text (_movie_title); - root->add_child("ReelNumber")->add_child_text (lexical_cast (_reel_number)); - root->add_child("Language")->add_child_text (_language); + return t; +} - if (_load_font_nodes.size() > 1) { - boost::throw_exception (MiscError ("multiple LoadFont nodes not supported")); +bool +SubtitleContent::equals (shared_ptr other_asset, EqualityOptions options, NoteHandler note) const +{ + if (!Asset::equals (other_asset, options, note)) { + return false; } - - if (!_load_font_nodes.empty ()) { - xmlpp::Element* load_font = root->add_child("LoadFont"); - load_font->set_attribute("Id", _load_font_nodes.front()->id); - load_font->set_attribute("URI", _load_font_nodes.front()->uri); + + shared_ptr other = dynamic_pointer_cast (other_asset); + if (!other) { + return false; } - list > sorted = _subtitles; - if (_need_sort) { - sorted.sort (SubtitleSorter ()); + if (_reel_number != other->_reel_number) { + note (DCP_ERROR, "subtitle reel numbers differ"); + return false; } - /* XXX: multiple fonts not supported */ - /* XXX: script, underlined, weight not supported */ - - bool italic = false; - Color color; - int size = 0; - Effect effect = NONE; - Color effect_color; - int spot_number = 1; - Time last_in; - Time last_out; - Time last_fade_up_time; - Time last_fade_down_time; - - xmlpp::Element* font = 0; - xmlpp::Element* subtitle = 0; - - for (list >::iterator i = sorted.begin(); i != sorted.end(); ++i) { - - /* We will start a new ... whenever some font property changes. - I suppose we should really make an optimal hierarchy of tags, but - that seems hard. - */ - - bool const font_changed = - italic != (*i)->italic() || - color != (*i)->color() || - size != (*i)->size() || - effect != (*i)->effect() || - effect_color != (*i)->effect_color(); - - if (font_changed) { - italic = (*i)->italic (); - color = (*i)->color (); - size = (*i)->size (); - effect = (*i)->effect (); - effect_color = (*i)->effect_color (); - } - - if (!font || font_changed) { - font = root->add_child ("Font"); - string id = "theFontId"; - if (!_load_font_nodes.empty()) { - id = _load_font_nodes.front()->id; - } - font->set_attribute ("Id", id); - font->set_attribute ("Italic", italic ? "yes" : "no"); - font->set_attribute ("Color", color.to_argb_string()); - font->set_attribute ("Size", lexical_cast (size)); - font->set_attribute ("Effect", effect_to_string (effect)); - font->set_attribute ("EffectColor", effect_color.to_argb_string()); - font->set_attribute ("Script", "normal"); - font->set_attribute ("Underlined", "no"); - font->set_attribute ("Weight", "normal"); - } - - if (!subtitle || font_changed || - (last_in != (*i)->in() || - last_out != (*i)->out() || - last_fade_up_time != (*i)->fade_up_time() || - last_fade_down_time != (*i)->fade_down_time() - )) { - - subtitle = font->add_child ("Subtitle"); - subtitle->set_attribute ("SpotNumber", lexical_cast (spot_number++)); - subtitle->set_attribute ("TimeIn", (*i)->in().to_string()); - subtitle->set_attribute ("TimeOut", (*i)->out().to_string()); - subtitle->set_attribute ("FadeUpTime", lexical_cast ((*i)->fade_up_time().to_ticks())); - subtitle->set_attribute ("FadeDownTime", lexical_cast ((*i)->fade_down_time().to_ticks())); - - last_in = (*i)->in (); - last_out = (*i)->out (); - last_fade_up_time = (*i)->fade_up_time (); - last_fade_down_time = (*i)->fade_down_time (); - } + if (_language != other->_language) { + note (DCP_ERROR, "subtitle languages differ"); + return false; + } - xmlpp::Element* text = subtitle->add_child ("Text"); - text->set_attribute ("VAlign", valign_to_string ((*i)->v_align())); - text->set_attribute ("VPosition", lexical_cast ((*i)->v_position())); - text->add_child_text ((*i)->text()); + if (_subtitles != other->_subtitles) { + note (DCP_ERROR, "subtitles differ"); + return false; } - return doc.write_to_string_formatted ("UTF-8"); + return true; } -