X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fsmpte_subtitle_asset.cc;h=27f486da3bd3a9532bd7d8a0d7475872f3611981;hb=9d3e7f716accd67985f23048b4c36e7581348848;hp=267ff27e692f0a79efa321391f395e68d6318623;hpb=87c2c54ebfdc1e6ceb0673058c01fd30e13258c2;p=libdcp.git diff --git a/src/smpte_subtitle_asset.cc b/src/smpte_subtitle_asset.cc index 267ff27e..27f486da 100644 --- a/src/smpte_subtitle_asset.cc +++ b/src/smpte_subtitle_asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2018 Carl Hetherington + Copyright (C) 2012-2019 Carl Hetherington This file is part of libdcp. @@ -47,6 +47,7 @@ #include "subtitle_image.h" #include #include +#include #include #include #include @@ -61,8 +62,11 @@ using boost::is_any_of; using boost::shared_array; using boost::dynamic_pointer_cast; using boost::optional; +using boost::starts_with; using namespace dcp; +static string const subtitle_smpte_ns = "http://www.smpte-ra.org/schemas/428-7/2010/DCST"; + SMPTESubtitleAsset::SMPTESubtitleAsset () : MXF (SMPTE) , _intrinsic_duration (0) @@ -113,6 +117,33 @@ SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file) ) ); } + + /* Try to read PNG files from the same folder that the XML is in; the wisdom of this is + debatable, at best... + */ + BOOST_FOREACH (shared_ptr i, _subtitles) { + shared_ptr im = dynamic_pointer_cast(i); + if (im && im->png_image().size() == 0) { + /* Even more dubious; allow .png or urn:uuid:.png */ + boost::filesystem::path p = file.parent_path() / String::compose("%1.png", im->id()); + if (boost::filesystem::is_regular_file(p)) { + im->read_png_file (p); + } else if (starts_with (im->id(), "urn:uuid:")) { + p = file.parent_path() / String::compose("%1.png", remove_urn_uuid(im->id())); + if (boost::filesystem::is_regular_file(p)) { + im->read_png_file (p); + } + } + } + } + } + + /* Check that all required image data have been found */ + BOOST_FOREACH (shared_ptr i, _subtitles) { + shared_ptr im = dynamic_pointer_cast(i); + if (im && im->png_image().size() == 0) { + throw MissingSubtitleImageError (im->id()); + } } } @@ -173,17 +204,19 @@ SMPTESubtitleAsset::read_mxf_descriptor (shared_ptr i != descriptor.ResourceList.end(); ++i) { - if (i->Type == ASDCP::TimedText::MT_OPENTYPE) { - ASDCP::TimedText::FrameBuffer buffer; - buffer.Capacity (10 * 1024 * 1024); - reader->ReadAncillaryResource (i->ResourceID, buffer, dec->context(), dec->hmac()); + ASDCP::TimedText::FrameBuffer buffer; + buffer.Capacity (10 * 1024 * 1024); + reader->ReadAncillaryResource (i->ResourceID, buffer, dec->context(), dec->hmac()); - char id[64]; - Kumu::bin2UUIDhex (i->ResourceID, ASDCP::UUIDlen, id, sizeof (id)); + 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()); + shared_array data (new uint8_t[buffer.Size()]); + memcpy (data.get(), buffer.RoData(), buffer.Size()); + switch (i->Type) { + case ASDCP::TimedText::MT_OPENTYPE: + { list >::const_iterator j = _load_font_nodes.begin (); while (j != _load_font_nodes.end() && (*j)->urn != id) { ++j; @@ -192,6 +225,22 @@ SMPTESubtitleAsset::read_mxf_descriptor (shared_ptr if (j != _load_font_nodes.end ()) { _fonts.push_back (Font ((*j)->id, (*j)->urn, Data (data, buffer.Size ()))); } + break; + } + case ASDCP::TimedText::MT_PNG: + { + list >::const_iterator j = _subtitles.begin (); + while (j != _subtitles.end() && ((!dynamic_pointer_cast(*j)) || dynamic_pointer_cast(*j)->id() != id)) { + ++j; + } + + if (j != _subtitles.end()) { + dynamic_pointer_cast(*j)->set_png_image (Data(data, buffer.Size())); + } + break; + } + default: + break; } } @@ -250,7 +299,9 @@ bool SMPTESubtitleAsset::valid_mxf (boost::filesystem::path file) { ASDCP::TimedText::MXFReader reader; + Kumu::DefaultLogSink().UnsetFilterFlag(Kumu::LOG_ALLOW_ALL); Kumu::Result_t r = reader.OpenRead (file.string().c_str ()); + Kumu::DefaultLogSink().SetFilterFlag(Kumu::LOG_ALLOW_ALL); return !ASDCP_FAILURE (r); } @@ -259,7 +310,7 @@ SMPTESubtitleAsset::xml_as_string () const { xmlpp::Document doc; xmlpp::Element* root = doc.create_root_node ("dcst:SubtitleReel"); - root->set_namespace_declaration ("http://www.smpte-ra.org/schemas/428-7/2010/DCST", "dcst"); + root->set_namespace_declaration (subtitle_smpte_ns, "dcst"); root->set_namespace_declaration ("http://www.w3.org/2001/XMLSchema", "xs"); root->add_child("Id", "dcst")->add_child_text ("urn:uuid:" + _xml_id); @@ -323,21 +374,29 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const /* Image subtitle references */ - for (ImageUUIDMap::const_iterator i = _image_subtitle_uuid.begin(); i != _image_subtitle_uuid.end(); ++i) { - ASDCP::TimedText::TimedTextResourceDescriptor res; - unsigned int c; - Kumu::hex2bin (i->second.c_str(), res.ResourceID, Kumu::UUID_Length, &c); - DCP_ASSERT (c == Kumu::UUID_Length); - res.Type = ASDCP::TimedText::MT_PNG; - descriptor.ResourceList.push_back (res); + BOOST_FOREACH (shared_ptr i, _subtitles) { + shared_ptr si = dynamic_pointer_cast(i); + if (si) { + ASDCP::TimedText::TimedTextResourceDescriptor res; + unsigned int c; + Kumu::hex2bin (si->id().c_str(), res.ResourceID, Kumu::UUID_Length, &c); + DCP_ASSERT (c == Kumu::UUID_Length); + res.Type = ASDCP::TimedText::MT_PNG; + descriptor.ResourceList.push_back (res); + } } - descriptor.NamespaceName = "dcst"; - memcpy (descriptor.AssetID, writer_info.AssetUUID, ASDCP::UUIDlen); + descriptor.NamespaceName = subtitle_smpte_ns; + unsigned int c; + Kumu::hex2bin (_xml_id.c_str(), descriptor.AssetID, ASDCP::UUIDlen, &c); + DCP_ASSERT (c == Kumu::UUID_Length); descriptor.ContainerDuration = _intrinsic_duration; ASDCP::TimedText::MXFWriter writer; - ASDCP::Result_t r = writer.OpenWrite (p.string().c_str(), writer_info, descriptor); + /* This header size is a guess. Empirically it seems that each subtitle reference is 90 bytes, and we need some extra. + The defualt size is not enough for some feature-length PNG sub projects (see DCP-o-matic #1561). + */ + ASDCP::Result_t r = writer.OpenWrite (p.string().c_str(), writer_info, descriptor, _subtitles.size() * 90 + 16384); if (ASDCP_FAILURE (r)) { boost::throw_exception (FileError ("could not open subtitle MXF for writing", p.string(), r)); } @@ -367,13 +426,16 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const /* Image subtitle payload */ - for (ImageUUIDMap::const_iterator i = _image_subtitle_uuid.begin(); i != _image_subtitle_uuid.end(); ++i) { - ASDCP::TimedText::FrameBuffer buffer; - buffer.SetData (i->first->png_image().data().get(), i->first->png_image().size()); - buffer.Size (i->first->png_image().size()); - r = writer.WriteAncillaryResource (buffer, enc.context(), enc.hmac()); - if (ASDCP_FAILURE(r)) { - boost::throw_exception (MXFFileError ("could not write PNG data to timed text resource", p.string(), r)); + BOOST_FOREACH (shared_ptr i, _subtitles) { + shared_ptr si = dynamic_pointer_cast(i); + if (si) { + ASDCP::TimedText::FrameBuffer buffer; + buffer.SetData (si->png_image().data().get(), si->png_image().size()); + buffer.Size (si->png_image().size()); + r = writer.WriteAncillaryResource (buffer, enc.context(), enc.hmac()); + if (ASDCP_FAILURE(r)) { + boost::throw_exception (MXFFileError ("could not write PNG data to timed text resource", p.string(), r)); + } } }