X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fsmpte_subtitle_asset.cc;h=00a9299aacf7957cff023375267dac1ba83a84da;hb=c4db5b5396c6401c63d80777a812e8adc642ce02;hp=e426ae22efd94365c9f78edda4e671a9fdb056bf;hpb=8771c1f7b00ab0fb5c252adaa437d753155b7c18;p=libdcp.git diff --git a/src/smpte_subtitle_asset.cc b/src/smpte_subtitle_asset.cc index e426ae22..00a9299a 100644 --- a/src/smpte_subtitle_asset.cc +++ b/src/smpte_subtitle_asset.cc @@ -31,6 +31,7 @@ #include "util.h" #include "AS_DCP.h" #include "KM_util.h" +#include "compose.hpp" #include #include #include @@ -49,36 +50,46 @@ using boost::dynamic_pointer_cast; using namespace dcp; SMPTESubtitleAsset::SMPTESubtitleAsset () - : _edit_rate (24, 1) + : _intrinsic_duration (0) + , _edit_rate (24, 1) , _time_code_rate (24) { - + } -/** Construct a SMPTESubtitleAsset by reading an MXF file. +/** Construct a SMPTESubtitleAsset by reading an MXF or XML file. * @param file Filename. */ SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file) : SubtitleAsset (file) { - ASDCP::TimedText::MXFReader reader; - Kumu::Result_t r = reader.OpenRead (file.string().c_str ()); - if (ASDCP_FAILURE (r)) { - boost::throw_exception (MXFFileError ("could not open MXF file for reading", file, r)); - } - - /* Read the subtitle XML */ - - string s; - reader.ReadTimedTextResource (s, 0, 0); - stringstream t; - t << s; shared_ptr xml (new cxml::Document ("SubtitleReel")); - xml->read_stream (t); - - ASDCP::WriterInfo info; - reader.FillWriterInfo (info); - _id = read_writer_info (info); + + shared_ptr reader (new ASDCP::TimedText::MXFReader ()); + Kumu::Result_t r = reader->OpenRead (file.string().c_str ()); + + if (!ASDCP_FAILURE (r)) { + string s; + reader->ReadTimedTextResource (s, 0, 0); + stringstream t; + t << s; + xml->read_stream (t); + ASDCP::WriterInfo info; + reader->FillWriterInfo (info); + _id = read_writer_info (info); + } else { + reader.reset (); + try { + xml->read_file (file); + _id = xml->string_child ("Id").substr (9); + } catch (cxml::Error& e) { + boost::throw_exception ( + DCPReadError ( + String::compose ("could not read subtitles from %1; MXF failed with %2, XML failed with %3", file, static_cast (r), e.what ()) + ) + ); + } + } _load_font_nodes = type_children (xml, "LoadFont"); @@ -107,49 +118,57 @@ SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file) shared_ptr subtitle_list = xml->optional_node_child ("SubtitleList"); - list f = subtitle_list->node_children ("Font"); list > font_nodes; - BOOST_FOREACH (cxml::NodePtr& i, f) { - font_nodes.push_back (shared_ptr (new FontNode (i, _time_code_rate))); + BOOST_FOREACH (cxml::NodePtr const & i, subtitle_list->node_children ("Font")) { + font_nodes.push_back (shared_ptr (new FontNode (i, _time_code_rate, "ID"))); } - - parse_subtitles (xml, font_nodes); - /* Read fonts */ + list > subtitle_nodes; + BOOST_FOREACH (cxml::NodePtr const & i, subtitle_list->node_children ("Subtitle")) { + subtitle_nodes.push_back (shared_ptr (new SubtitleNode (i, _time_code_rate, "ID"))); + } - ASDCP::TimedText::TimedTextDescriptor text_descriptor; - reader.FillTimedTextDescriptor (text_descriptor); - for ( - ASDCP::TimedText::ResourceList_t::const_iterator i = text_descriptor.ResourceList.begin(); - i != text_descriptor.ResourceList.end(); - ++i) { + parse_subtitles (xml, font_nodes, subtitle_nodes); - if (i->Type == ASDCP::TimedText::MT_OPENTYPE) { - ASDCP::TimedText::FrameBuffer buffer; - buffer.Capacity (10 * 1024 * 1024); - reader.ReadAncillaryResource (i->ResourceID, buffer); + if (reader) { + ASDCP::TimedText::TimedTextDescriptor descriptor; + reader->FillTimedTextDescriptor (descriptor); - char id[64]; - Kumu::bin2UUIDhex (i->ResourceID, ASDCP::UUIDlen, id, sizeof (id)); + /* Load fonts */ - shared_array data (new uint8_t[buffer.Size()]); - memcpy (data.get(), buffer.RoData(), buffer.Size()); + for ( + ASDCP::TimedText::ResourceList_t::const_iterator i = descriptor.ResourceList.begin(); + i != descriptor.ResourceList.end(); + ++i) { - /* The IDs in the MXF have a 9 character prefix of unknown origin and meaning... */ - string check_id = string (id).substr (9); + if (i->Type == ASDCP::TimedText::MT_OPENTYPE) { + ASDCP::TimedText::FrameBuffer buffer; + buffer.Capacity (10 * 1024 * 1024); + reader->ReadAncillaryResource (i->ResourceID, buffer); - list >::const_iterator j = _load_font_nodes.begin (); - while (j != _load_font_nodes.end() && (*j)->urn != check_id) { - ++j; - } + char id[64]; + Kumu::bin2UUIDhex (i->ResourceID, ASDCP::UUIDlen, id, sizeof (id)); + + shared_array data (new uint8_t[buffer.Size()]); + memcpy (data.get(), buffer.RoData(), buffer.Size()); - if (j != _load_font_nodes.end ()) { - _fonts[(*j)->id] = FileData (data, buffer.Size ()); + list >::const_iterator j = _load_font_nodes.begin (); + while (j != _load_font_nodes.end() && (*j)->urn != id) { + ++j; + } + + if (j != _load_font_nodes.end ()) { + _fonts.push_back (Font ((*j)->id, (*j)->urn, Data (data, buffer.Size ()))); + } } } + + /* Get intrinsic duration */ + _intrinsic_duration = descriptor.ContainerDuration; + } else { + /* Guess intrinsic duration */ + _intrinsic_duration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator); } - - } list > @@ -168,7 +187,7 @@ SMPTESubtitleAsset::valid_mxf (boost::filesystem::path file) return !ASDCP_FAILURE (r); } -Glib::ustring +string SMPTESubtitleAsset::xml_as_string () const { xmlpp::Document doc; @@ -176,7 +195,7 @@ SMPTESubtitleAsset::xml_as_string () const root->set_namespace_declaration ("http://www.smpte-ra.org/schemas/428-7/2010/DCST", "dcst"); root->set_namespace_declaration ("http://www.w3.org/2001/XMLSchema", "xs"); - root->add_child("ID", "dcst")->add_child_text (_id); + root->add_child("Id", "dcst")->add_child_text ("urn:uuid:" + _id); root->add_child("ContentTitleText", "dcst")->add_child_text (_content_title_text); if (_annotation_text) { root->add_child("AnnotationText", "dcst")->add_child_text (_annotation_text.get ()); @@ -191,17 +210,17 @@ SMPTESubtitleAsset::xml_as_string () const root->add_child("EditRate", "dcst")->add_child_text (_edit_rate.as_string ()); root->add_child("TimeCodeRate", "dcst")->add_child_text (raw_convert (_time_code_rate)); if (_start_time) { - root->add_child("StartTime", "dcst")->add_child_text (_start_time.get().as_string ()); + root->add_child("StartTime", "dcst")->add_child_text (_start_time.get().as_string (SMPTE)); } BOOST_FOREACH (shared_ptr i, _load_font_nodes) { xmlpp::Element* load_font = root->add_child("LoadFont", "dcst"); - load_font->add_child_text (i->urn); + load_font->add_child_text ("urn:uuid:" + i->urn); load_font->set_attribute ("ID", i->id); } - - subtitles_as_xml (root->add_child ("SubtitleList", "dcst"), _time_code_rate, "dcst"); - + + subtitles_as_xml (root->add_child ("SubtitleList", "dcst"), _time_code_rate, SMPTE); + return doc.write_to_string_formatted ("UTF-8"); } @@ -211,13 +230,16 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const { ASDCP::WriterInfo writer_info; fill_writer_info (&writer_info, _id, SMPTE); - + ASDCP::TimedText::TimedTextDescriptor descriptor; descriptor.EditRate = ASDCP::Rational (_edit_rate.numerator, _edit_rate.denominator); descriptor.EncodingName = "UTF-8"; BOOST_FOREACH (shared_ptr i, _load_font_nodes) { - map::const_iterator j = _fonts.find (i->id); + list::const_iterator j = _fonts.begin (); + while (j != _fonts.end() && j->load_id != i->id) { + ++j; + } if (j != _fonts.end ()) { ASDCP::TimedText::TimedTextResourceDescriptor res; unsigned int c; @@ -227,10 +249,10 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const descriptor.ResourceList.push_back (res); } } - + descriptor.NamespaceName = "dcst"; memcpy (descriptor.AssetID, writer_info.AssetUUID, ASDCP::UUIDlen); - descriptor.ContainerDuration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator); + descriptor.ContainerDuration = _intrinsic_duration; ASDCP::TimedText::MXFWriter writer; ASDCP::Result_t r = writer.OpenWrite (p.string().c_str(), writer_info, descriptor); @@ -245,11 +267,14 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const } BOOST_FOREACH (shared_ptr i, _load_font_nodes) { - map::const_iterator j = _fonts.find (i->id); + list::const_iterator j = _fonts.begin (); + while (j != _fonts.end() && j->load_id != i->id) { + ++j; + } if (j != _fonts.end ()) { ASDCP::TimedText::FrameBuffer buffer; - buffer.SetData (j->second.data.get(), j->second.size); - buffer.Size (j->second.size); + buffer.SetData (j->data.data().get(), j->data.size()); + buffer.Size (j->data.size()); r = writer.WriteAncillaryResource (buffer); if (ASDCP_FAILURE (r)) { boost::throw_exception (MXFFileError ("could not write font to timed text resource", p.string(), r)); @@ -297,7 +322,7 @@ SMPTESubtitleAsset::equals (shared_ptr other_asset, EqualityOptions note (DCP_ERROR, "Subtitle content title texts differ"); return false; } - + if (_language != other->_language) { note (DCP_ERROR, "Subtitle languages differ"); return false; @@ -307,7 +332,7 @@ SMPTESubtitleAsset::equals (shared_ptr other_asset, EqualityOptions note (DCP_ERROR, "Subtitle annotation texts differ"); return false; } - + if (_issue_date != other->_issue_date) { if (options.issue_dates_can_differ) { note (DCP_NOTE, "Subtitle issue dates differ"); @@ -316,12 +341,12 @@ SMPTESubtitleAsset::equals (shared_ptr other_asset, EqualityOptions return false; } } - + if (_reel_number != other->_reel_number) { note (DCP_ERROR, "Subtitle reel numbers differ"); return false; } - + if (_edit_rate != other->_edit_rate) { note (DCP_ERROR, "Subtitle edit rates differ"); return false; @@ -331,7 +356,7 @@ SMPTESubtitleAsset::equals (shared_ptr other_asset, EqualityOptions note (DCP_ERROR, "Subtitle time code rates differ"); return false; } - + if (_start_time != other->_start_time) { note (DCP_ERROR, "Subtitle start times differ"); return false; @@ -341,8 +366,16 @@ SMPTESubtitleAsset::equals (shared_ptr other_asset, EqualityOptions } void -SMPTESubtitleAsset::add_font (string id, boost::filesystem::path file) +SMPTESubtitleAsset::add_font (string load_id, boost::filesystem::path file) +{ + string const uuid = make_uuid (); + _fonts.push_back (Font (load_id, uuid, file)); + _load_font_nodes.push_back (shared_ptr (new SMPTELoadFontNode (load_id, uuid))); +} + +void +SMPTESubtitleAsset::add (dcp::SubtitleString s) { - add_font_data (id, file); - _load_font_nodes.push_back (shared_ptr (new SMPTELoadFontNode (id, make_uuid ()))); + SubtitleAsset::add (s); + _intrinsic_duration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator); }