summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asset_factory.cc23
-rw-r--r--src/asset_list.h4
-rw-r--r--src/asset_map.cc40
-rw-r--r--src/asset_reader.h14
-rw-r--r--src/atmos_asset.cc4
-rw-r--r--src/behaviour.h52
-rw-r--r--src/certificate_chain.cc49
-rw-r--r--src/chromaticity.h4
-rw-r--r--src/colour_conversion.h4
-rw-r--r--src/combine.cc4
-rw-r--r--src/cpl.cc109
-rw-r--r--src/dcp.cc26
-rw-r--r--src/dcp_time.h4
-rw-r--r--src/encrypted_kdm.cc121
-rw-r--r--src/equality_options.h8
-rw-r--r--src/exceptions.cc4
-rw-r--r--src/exceptions.h31
-rw-r--r--src/ffmpeg_image.cc122
-rw-r--r--src/ffmpeg_image.h107
-rw-r--r--src/frame_info.h (renamed from src/reel_closed_caption_asset.cc)91
-rw-r--r--src/interop_text_asset.cc (renamed from src/interop_subtitle_asset.cc)77
-rw-r--r--src/interop_text_asset.h (renamed from src/interop_subtitle_asset.h)18
-rw-r--r--src/j2k_picture_asset.cc229
-rw-r--r--src/j2k_picture_asset.h110
-rw-r--r--src/j2k_picture_asset_writer.cc (renamed from src/picture_asset_writer.cc)12
-rw-r--r--src/j2k_picture_asset_writer.h (renamed from src/picture_asset_writer.h)46
-rw-r--r--src/j2k_picture_asset_writer_common.cc (renamed from src/picture_asset_writer_common.cc)10
-rw-r--r--src/language_tag.h2
-rw-r--r--src/locale_convert.h2
-rw-r--r--src/mono_j2k_picture_asset.cc (renamed from src/mono_picture_asset.cc)50
-rw-r--r--src/mono_j2k_picture_asset.h (renamed from src/mono_picture_asset.h)32
-rw-r--r--src/mono_j2k_picture_asset_reader.h (renamed from src/mono_picture_asset_reader.h)12
-rw-r--r--src/mono_j2k_picture_asset_writer.cc (renamed from src/mono_picture_asset_writer.cc)34
-rw-r--r--src/mono_j2k_picture_asset_writer.h (renamed from src/mono_picture_asset_writer.h)30
-rw-r--r--src/mono_j2k_picture_frame.cc (renamed from src/mono_picture_frame.cc)18
-rw-r--r--src/mono_j2k_picture_frame.h (renamed from src/mono_picture_frame.h)26
-rw-r--r--src/mono_mpeg2_picture_asset.cc86
-rw-r--r--src/mono_mpeg2_picture_asset.h (renamed from src/reel_smpte_subtitle_asset.cc)47
-rw-r--r--src/mono_mpeg2_picture_asset_reader.h58
-rw-r--r--src/mono_mpeg2_picture_asset_writer.cc144
-rw-r--r--src/mono_mpeg2_picture_asset_writer.h68
-rw-r--r--src/mono_mpeg2_picture_frame.cc91
-rw-r--r--src/mono_mpeg2_picture_frame.h81
-rw-r--r--src/mpeg2_picture_asset.cc74
-rw-r--r--src/mpeg2_picture_asset.h90
-rw-r--r--src/mpeg2_picture_asset_writer.cc (renamed from src/reel_interop_subtitle_asset.cc)33
-rw-r--r--src/mpeg2_picture_asset_writer.h73
-rw-r--r--src/mpeg2_picture_asset_writer_common.cc93
-rw-r--r--src/mpeg2_transcode.cc216
-rw-r--r--src/mpeg2_transcode.h (renamed from src/reel_closed_caption_asset.h)85
-rw-r--r--src/mxf.h7
-rw-r--r--src/name_format.h4
-rw-r--r--src/picture_asset.cc187
-rw-r--r--src/picture_asset.h72
-rw-r--r--src/pkl.cc26
-rw-r--r--src/pkl.h2
-rw-r--r--src/rating.cc4
-rw-r--r--src/reel.cc178
-rw-r--r--src/reel.h24
-rw-r--r--src/reel_asset.cc20
-rw-r--r--src/reel_asset.h4
-rw-r--r--src/reel_atmos_asset.cc8
-rw-r--r--src/reel_atmos_asset.h4
-rw-r--r--src/reel_file_asset.cc10
-rw-r--r--src/reel_file_asset.h2
-rw-r--r--src/reel_interop_closed_caption_asset.h77
-rw-r--r--src/reel_interop_text_asset.cc (renamed from src/reel_smpte_closed_caption_asset.cc)64
-rw-r--r--src/reel_interop_text_asset.h (renamed from src/reel_interop_subtitle_asset.h)33
-rw-r--r--src/reel_markers_asset.cc14
-rw-r--r--src/reel_markers_asset.h6
-rw-r--r--src/reel_mono_picture_asset.cc6
-rw-r--r--src/reel_mono_picture_asset.h31
-rw-r--r--src/reel_picture_asset.cc18
-rw-r--r--src/reel_picture_asset.h36
-rw-r--r--src/reel_smpte_closed_caption_asset.h83
-rw-r--r--src/reel_smpte_text_asset.cc (renamed from src/reel_interop_closed_caption_asset.cc)60
-rw-r--r--src/reel_smpte_text_asset.h (renamed from src/reel_smpte_subtitle_asset.h)34
-rw-r--r--src/reel_sound_asset.cc2
-rw-r--r--src/reel_sound_asset.h2
-rw-r--r--src/reel_stereo_picture_asset.cc6
-rw-r--r--src/reel_stereo_picture_asset.h20
-rw-r--r--src/reel_text_asset.cc (renamed from src/reel_subtitle_asset.cc)47
-rw-r--r--src/reel_text_asset.h (renamed from src/reel_subtitle_asset.h)49
-rw-r--r--src/rgb_xyz.h2
-rw-r--r--src/smpte_text_asset.cc (renamed from src/smpte_subtitle_asset.cc)130
-rw-r--r--src/smpte_text_asset.h (renamed from src/smpte_subtitle_asset.h)30
-rw-r--r--src/sound_asset.cc12
-rw-r--r--src/sound_asset.h8
-rw-r--r--src/sound_frame.cc22
-rw-r--r--src/sound_frame.h8
-rw-r--r--src/stereo_j2k_picture_asset.cc (renamed from src/stereo_picture_asset.cc)46
-rw-r--r--src/stereo_j2k_picture_asset.h (renamed from src/stereo_picture_asset.h)26
-rw-r--r--src/stereo_j2k_picture_asset_reader.h (renamed from src/stereo_picture_asset_reader.h)12
-rw-r--r--src/stereo_j2k_picture_asset_writer.cc (renamed from src/stereo_picture_asset_writer.cc)34
-rw-r--r--src/stereo_j2k_picture_asset_writer.h (renamed from src/stereo_picture_asset_writer.h)26
-rw-r--r--src/stereo_j2k_picture_frame.cc (renamed from src/stereo_picture_frame.cc)28
-rw-r--r--src/stereo_j2k_picture_frame.h (renamed from src/stereo_picture_frame.h)28
-rw-r--r--src/text.cc (renamed from src/subtitle.cc)30
-rw-r--r--src/text.h (renamed from src/subtitle.h)20
-rw-r--r--src/text_asset.cc (renamed from src/subtitle_asset.cc)139
-rw-r--r--src/text_asset.h (renamed from src/subtitle_asset.h)50
-rw-r--r--src/text_asset_internal.cc (renamed from src/subtitle_asset_internal.cc)26
-rw-r--r--src/text_asset_internal.h (renamed from src/subtitle_asset_internal.h)12
-rw-r--r--src/text_image.cc (renamed from src/subtitle_image.cc)52
-rw-r--r--src/text_image.h (renamed from src/subtitle_image.h)28
-rw-r--r--src/text_string.cc (renamed from src/subtitle_string.cc)50
-rw-r--r--src/text_string.h (renamed from src/subtitle_string.h)25
-rw-r--r--src/text_type.h55
-rw-r--r--src/types.cc8
-rw-r--r--src/types.h6
-rw-r--r--src/verify.cc999
-rw-r--r--src/verify.h57
-rw-r--r--src/verify_j2k.h4
-rw-r--r--src/verify_report.cc151
-rw-r--r--src/verify_report.h240
-rw-r--r--src/warnings.h17
-rw-r--r--src/wscript114
117 files changed, 4248 insertions, 2155 deletions
diff --git a/src/asset_factory.cc b/src/asset_factory.cc
index be4f6b49..652e1e31 100644
--- a/src/asset_factory.cc
+++ b/src/asset_factory.cc
@@ -40,11 +40,12 @@
#include "asset_factory.h"
#include "atmos_asset.h"
#include "compose.hpp"
-#include "mono_picture_asset.h"
-#include "smpte_subtitle_asset.h"
+#include "mono_j2k_picture_asset.h"
+#include "mono_mpeg2_picture_asset.h"
+#include "smpte_text_asset.h"
#include "sound_asset.h"
-#include "stereo_picture_asset.h"
-#include "stereo_picture_asset.h"
+#include "stereo_j2k_picture_asset.h"
+#include "stereo_j2k_picture_asset.h"
#include <memory>
@@ -61,21 +62,23 @@ dcp::asset_factory (boost::filesystem::path path, bool ignore_incorrect_picture_
*/
ASDCP::EssenceType_t type;
- auto const result = ASDCP::EssenceType(dcp::filesystem::fix_long_path(path).string().c_str(), type);
+ Kumu::FileReaderFactory factory;
+ auto const result = ASDCP::EssenceType(dcp::filesystem::fix_long_path(path).string().c_str(), type, factory);
if (!ASDCP_SUCCESS(result)) {
throw ReadError(String::compose("Could not find essence type (%1)", result.Message()), path.string());
}
switch (type) {
case ASDCP::ESS_UNKNOWN:
+ throw ReadError("Unknown asset type");
case ASDCP::ESS_MPEG2_VES:
- throw ReadError ("MPEG2 video essences are not supported");
+ return make_shared<MonoMPEG2PictureAsset>(path);
case ASDCP::ESS_JPEG_2000:
try {
- return make_shared<MonoPictureAsset>(path);
+ return make_shared<MonoJ2KPictureAsset>(path);
} catch (dcp::MXFFileError& e) {
if (ignore_incorrect_picture_mxf_type && e.number() == ASDCP::RESULT_SFORMAT) {
/* Tried to load it as mono but the error says it's stereo; try that instead */
- auto stereo = make_shared<StereoPictureAsset>(path);
+ auto stereo = make_shared<StereoJ2KPictureAsset>(path);
if (stereo && found_threed_marked_as_twod) {
*found_threed_marked_as_twod = true;
}
@@ -88,9 +91,9 @@ dcp::asset_factory (boost::filesystem::path path, bool ignore_incorrect_picture_
case ASDCP::ESS_PCM_24b_96k:
return make_shared<SoundAsset>(path);
case ASDCP::ESS_JPEG_2000_S:
- return make_shared<StereoPictureAsset>(path);
+ return make_shared<StereoJ2KPictureAsset>(path);
case ASDCP::ESS_TIMED_TEXT:
- return make_shared<SMPTESubtitleAsset>(path);
+ return make_shared<SMPTETextAsset>(path);
case ASDCP::ESS_DCDATA_DOLBY_ATMOS:
return make_shared<AtmosAsset>(path);
default:
diff --git a/src/asset_list.h b/src/asset_list.h
index 5c50495d..29563a8a 100644
--- a/src/asset_list.h
+++ b/src/asset_list.h
@@ -32,8 +32,8 @@
*/
-#ifndef DCP_ASSET_LIST_H
-#define DCP_ASSET_LIST_H
+#ifndef LIBDCP_ASSET_LIST_H
+#define LIBDCP_ASSET_LIST_H
#include "types.h"
diff --git a/src/asset_map.cc b/src/asset_map.cc
index 281f27c3..0ee4b486 100644
--- a/src/asset_map.cc
+++ b/src/asset_map.cc
@@ -165,29 +165,29 @@ AssetMap::write_xml(boost::filesystem::path file) const
DCP_ASSERT (false);
}
- root->add_child("Id")->add_child_text("urn:uuid:" + _id);
+ cxml::add_text_child(root, "Id", "urn:uuid:" + _id);
if (_annotation_text) {
- root->add_child("AnnotationText")->add_child_text(*_annotation_text);
+ cxml::add_text_child(root, "AnnotationText", *_annotation_text);
}
switch (_standard) {
case Standard::INTEROP:
- root->add_child("VolumeCount")->add_child_text("1");
- root->add_child("IssueDate")->add_child_text(_issue_date);
- root->add_child("Issuer")->add_child_text(_issuer);
- root->add_child("Creator")->add_child_text(_creator);
+ cxml::add_text_child(root, "VolumeCount", "1");
+ cxml::add_text_child(root, "IssueDate", _issue_date);
+ cxml::add_text_child(root, "Issuer", _issuer);
+ cxml::add_text_child(root, "Creator", _creator);
break;
case Standard::SMPTE:
- root->add_child("Creator")->add_child_text(_creator);
- root->add_child("VolumeCount")->add_child_text("1");
- root->add_child("IssueDate")->add_child_text(_issue_date);
- root->add_child("Issuer")->add_child_text(_issuer);
+ cxml::add_text_child(root, "Creator", _creator);
+ cxml::add_text_child(root, "VolumeCount", "1");
+ cxml::add_text_child(root, "IssueDate", _issue_date);
+ cxml::add_text_child(root, "Issuer", _issuer);
break;
default:
DCP_ASSERT (false);
}
- auto asset_list = root->add_child("AssetList");
+ auto asset_list = cxml::add_child(root, "AssetList");
for (auto const& asset: _assets) {
asset.write_xml(asset_list, file.parent_path());
}
@@ -200,20 +200,20 @@ AssetMap::write_xml(boost::filesystem::path file) const
void
AssetMap::Asset::write_xml(xmlpp::Element* asset_list, boost::filesystem::path dcp_root_directory) const
{
- auto node = asset_list->add_child("Asset");
- node->add_child("Id")->add_child_text("urn:uuid:" + _id);
+ auto node = cxml::add_child(asset_list, "Asset");
+ cxml::add_text_child(node, "Id", "urn:uuid:" + _id);
if (_pkl) {
- node->add_child("PackingList")->add_child_text("true");
+ cxml::add_text_child(node, "PackingList", "true");
}
- auto chunk_list = node->add_child("ChunkList");
- auto chunk = chunk_list->add_child("Chunk");
+ auto chunk_list = cxml::add_child(node, "ChunkList");
+ auto chunk = cxml::add_child(chunk_list, "Chunk");
auto relative_path = relative_to_root(filesystem::canonical(dcp_root_directory), filesystem::canonical(_path));
DCP_ASSERT(relative_path);
- chunk->add_child("Path")->add_child_text(relative_path->generic_string());
- chunk->add_child("VolumeIndex")->add_child_text("1");
- chunk->add_child("Offset")->add_child_text("0");
- chunk->add_child("Length")->add_child_text(raw_convert<string>(filesystem::file_size(_path)));
+ cxml::add_text_child(chunk, "Path", relative_path->generic_string());
+ cxml::add_text_child(chunk, "VolumeIndex", "1");
+ cxml::add_text_child(chunk, "Offset", "0");
+ cxml::add_text_child(chunk, "Length", raw_convert<string>(filesystem::file_size(_path)));
}
diff --git a/src/asset_reader.h b/src/asset_reader.h
index c8953e09..091ac915 100644
--- a/src/asset_reader.h
+++ b/src/asset_reader.h
@@ -53,9 +53,9 @@ namespace dcp {
class AtmosAsset;
-class MonoPictureAsset;
+class MonoJ2KPictureAsset;
class SoundAsset;
-class StereoPictureAsset;
+class StereoJ2KPictureAsset;
template <class R, class F>
@@ -90,14 +90,16 @@ protected:
private:
friend class AtmosAsset;
- friend class MonoPictureAsset;
+ friend class MonoJ2KPictureAsset;
+ friend class MonoMPEG2PictureAsset;
friend class SoundAsset;
- friend class StereoPictureAsset;
+ friend class StereoJ2KPictureAsset;
- explicit AssetReader (Asset const * asset, boost::optional<Key> key, Standard standard)
+ AssetReader(Asset const * asset, boost::optional<Key> key, Standard standard)
: _crypto_context (new DecryptionContext(key, standard))
{
- _reader = new R ();
+ Kumu::FileReaderFactory factory;
+ _reader = new R(factory);
DCP_ASSERT (asset->file());
auto const r = _reader->OpenRead(dcp::filesystem::fix_long_path(*asset->file()).string().c_str());
if (ASDCP_FAILURE(r)) {
diff --git a/src/atmos_asset.cc b/src/atmos_asset.cc
index 42a0774e..09a22c1e 100644
--- a/src/atmos_asset.cc
+++ b/src/atmos_asset.cc
@@ -42,6 +42,7 @@
#include "atmos_asset_writer.h"
#include "exceptions.h"
#include <asdcp/AS_DCP.h>
+#include <asdcp/KM_fileio.h>
using std::string;
@@ -67,7 +68,8 @@ AtmosAsset::AtmosAsset (boost::filesystem::path file)
: Asset (file)
, MXF (Standard::SMPTE)
{
- ASDCP::ATMOS::MXFReader reader;
+ Kumu::FileReaderFactory factory;
+ ASDCP::ATMOS::MXFReader reader(factory);
auto r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", file.string(), r));
diff --git a/src/behaviour.h b/src/behaviour.h
new file mode 100644
index 00000000..1600966c
--- /dev/null
+++ b/src/behaviour.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_BEHAVIOUR_H
+#define LIBDCP_BEHAVIOUR_H
+
+
+namespace dcp {
+
+
+enum class Behaviour {
+ OVERWRITE_EXISTING,
+ MAKE_NEW
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/certificate_chain.cc b/src/certificate_chain.cc
index c4e3a9b0..2bbddc7f 100644
--- a/src/certificate_chain.cc
+++ b/src/certificate_chain.cc
@@ -606,47 +606,47 @@ CertificateChain::sign (xmlpp::Element* parent, Standard standard) const
/* <Signer> */
parent->add_child_text(" ");
- auto signer = parent->add_child("Signer");
+ auto signer = cxml::add_child(parent, "Signer");
signer->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig");
- auto data = signer->add_child("X509Data", "dsig");
- auto serial_element = data->add_child("X509IssuerSerial", "dsig");
- serial_element->add_child("X509IssuerName", "dsig")->add_child_text (leaf().issuer());
- serial_element->add_child("X509SerialNumber", "dsig")->add_child_text (leaf().serial());
- data->add_child("X509SubjectName", "dsig")->add_child_text (leaf().subject());
+ auto data = cxml::add_child(signer, "X509Data", string("dsig"));
+ auto serial_element = cxml::add_child(data, "X509IssuerSerial", string("dsig"));
+ cxml::add_child(serial_element, "X509IssuerName", string("dsig"))->add_child_text(leaf().issuer());
+ cxml::add_child(serial_element, "X509SerialNumber", string("dsig"))->add_child_text(leaf().serial());
+ cxml::add_child(data, "X509SubjectName", string("dsig"))->add_child_text(leaf().subject());
indent (signer, 2);
/* <Signature> */
parent->add_child_text("\n ");
- auto signature = parent->add_child("Signature");
+ auto signature = cxml::add_child(parent, "Signature");
signature->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig");
signature->set_namespace ("dsig");
parent->add_child_text("\n");
- auto signed_info = signature->add_child ("SignedInfo", "dsig");
- signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
+ auto signed_info = cxml::add_child(signature, "SignedInfo", string("dsig"));
+ cxml::add_child(signed_info, "CanonicalizationMethod", string("dsig"))->set_attribute("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
if (standard == Standard::INTEROP) {
- signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
+ cxml::add_child(signed_info, "SignatureMethod", string("dsig"))->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
} else {
- signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
+ cxml::add_child(signed_info, "SignatureMethod", string("dsig"))->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
}
- auto reference = signed_info->add_child("Reference", "dsig");
+ auto reference = cxml::add_child(signed_info, "Reference", string("dsig"));
reference->set_attribute ("URI", "");
- auto transforms = reference->add_child("Transforms", "dsig");
- transforms->add_child("Transform", "dsig")->set_attribute (
+ auto transforms = cxml::add_child(reference, "Transforms", string("dsig"));
+ cxml::add_child(transforms, "Transform", string("dsig"))->set_attribute(
"Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
);
- reference->add_child("DigestMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
+ cxml::add_child(reference, "DigestMethod", string("dsig"))->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
/* This will be filled in by the signing later */
- reference->add_child("DigestValue", "dsig");
+ cxml::add_child(reference, "DigestValue", string("dsig"));
- signature->add_child("SignatureValue", "dsig");
- signature->add_child("KeyInfo", "dsig");
+ cxml::add_child(signature, "SignatureValue", string("dsig"));
+ cxml::add_child(signature, "KeyInfo", string("dsig"));
add_signature_value (signature, "dsig", true);
}
@@ -655,19 +655,20 @@ void
CertificateChain::add_signature_value (xmlpp::Element* parent, string ns, bool add_indentation) const
{
cxml::Node cp (parent);
- auto key_info = cp.node_child("KeyInfo")->node();
+ auto key_info = dynamic_cast<xmlpp::Element*>(cp.node_child("KeyInfo")->node());
+ DCP_ASSERT(key_info);
/* Add the certificate chain to the KeyInfo child node of parent */
for (auto const& i: leaf_to_root()) {
- auto data = key_info->add_child("X509Data", ns);
+ auto data = cxml::add_child(key_info, "X509Data", ns);
{
- auto serial = data->add_child("X509IssuerSerial", ns);
- serial->add_child("X509IssuerName", ns)->add_child_text (i.issuer ());
- serial->add_child("X509SerialNumber", ns)->add_child_text (i.serial ());
+ auto serial = cxml::add_child(data, "X509IssuerSerial", ns);
+ cxml::add_child(serial, "X509IssuerName", ns)->add_child_text(i.issuer());
+ cxml::add_child(serial, "X509SerialNumber", ns)->add_child_text(i.serial());
}
- data->add_child("X509Certificate", ns)->add_child_text (i.certificate());
+ cxml::add_child(data, "X509Certificate", ns)->add_child_text(i.certificate());
}
auto signature_context = xmlSecDSigCtxCreate (0);
diff --git a/src/chromaticity.h b/src/chromaticity.h
index 41bb8fda..52edd7bf 100644
--- a/src/chromaticity.h
+++ b/src/chromaticity.h
@@ -37,8 +37,8 @@
*/
-#ifndef DCP_CHROMATICITY_H
-#define DCP_CHROMATICITY_H
+#ifndef LIBDCP_CHROMATICITY_H
+#define LIBDCP_CHROMATICITY_H
#include <cmath>
diff --git a/src/colour_conversion.h b/src/colour_conversion.h
index 8501699a..29140541 100644
--- a/src/colour_conversion.h
+++ b/src/colour_conversion.h
@@ -37,8 +37,8 @@
*/
-#ifndef DCP_COLOUR_CONVERSION_H
-#define DCP_COLOUR_CONVERSION_H
+#ifndef LIBDCP_COLOUR_CONVERSION_H
+#define LIBDCP_COLOUR_CONVERSION_H
#include "chromaticity.h"
diff --git a/src/combine.cc b/src/combine.cc
index b7a625f0..74456bfb 100644
--- a/src/combine.cc
+++ b/src/combine.cc
@@ -45,7 +45,7 @@
#include "exceptions.h"
#include "filesystem.h"
#include "font_asset.h"
-#include "interop_subtitle_asset.h"
+#include "interop_text_asset.h"
#include "raw_convert.h"
#include <boost/filesystem.hpp>
#include <set>
@@ -139,7 +139,7 @@ dcp::combine (
continue;
}
- auto sub = dynamic_pointer_cast<dcp::InteropSubtitleAsset>(j);
+ auto sub = dynamic_pointer_cast<dcp::InteropTextAsset>(j);
if (sub) {
/* Interop fonts are really fiddly. The font files are assets (in the ASSETMAP)
* and also linked from the font XML by filename. We have to fix both these things,
diff --git a/src/cpl.cc b/src/cpl.cc
index 6a25863a..79aedc4c 100644
--- a/src/cpl.cc
+++ b/src/cpl.cc
@@ -48,10 +48,9 @@
#include "raw_convert.h"
#include "reel.h"
#include "reel_atmos_asset.h"
-#include "reel_closed_caption_asset.h"
#include "reel_picture_asset.h"
#include "reel_sound_asset.h"
-#include "reel_subtitle_asset.h"
+#include "reel_text_asset.h"
#include "util.h"
#include "version.h"
#include "warnings.h"
@@ -213,15 +212,15 @@ CPL::write_xml(boost::filesystem::path file, shared_ptr<const CertificateChain>
root = doc.create_root_node ("CompositionPlaylist", cpl_smpte_ns);
}
- root->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ cxml::add_text_child(root, "Id", "urn:uuid:" + _id);
if (_annotation_text) {
- root->add_child("AnnotationText")->add_child_text (*_annotation_text);
+ cxml::add_text_child(root, "AnnotationText", *_annotation_text);
}
- root->add_child("IssueDate")->add_child_text (_issue_date);
- root->add_child("Issuer")->add_child_text (_issuer);
- root->add_child("Creator")->add_child_text (_creator);
- root->add_child("ContentTitleText")->add_child_text (_content_title_text);
- auto content_kind = root->add_child("ContentKind");
+ cxml::add_text_child(root, "IssueDate", _issue_date);
+ cxml::add_text_child(root, "Issuer", _issuer);
+ cxml::add_text_child(root, "Creator", _creator);
+ cxml::add_text_child(root, "ContentTitleText", _content_title_text);
+ auto content_kind = cxml::add_child(root, "ContentKind");
content_kind->add_child_text(_content_kind.name());
if (_content_kind.scope()) {
content_kind->set_attribute("scope", *_content_kind.scope());
@@ -233,12 +232,12 @@ CPL::write_xml(boost::filesystem::path file, shared_ptr<const CertificateChain>
_content_versions[0].as_xml (root);
}
- auto rating_list = root->add_child("RatingList");
+ auto rating_list = cxml::add_child(root, "RatingList");
for (auto i: _ratings) {
- i.as_xml (rating_list->add_child("Rating"));
+ i.as_xml(cxml::add_child(rating_list, "Rating"));
}
- auto reel_list = root->add_child ("ReelList");
+ auto reel_list = cxml::add_child(root, "ReelList");
if (_reels.empty()) {
throw NoReelsError ();
@@ -403,27 +402,27 @@ CPL::write_mca_subdescriptors(xmlpp::Element* parent, shared_ptr<const SoundAsse
reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&soundfield)
);
if (KM_SUCCESS(r)) {
- auto mca_subs = parent->add_child("mca:MCASubDescriptors");
+ auto mca_subs = cxml::add_child(parent, "mca:MCASubDescriptors");
mca_subs->set_namespace_declaration (mca_sub_descriptors_ns, "mca");
mca_subs->set_namespace_declaration (smpte_395_ns, "r0");
mca_subs->set_namespace_declaration (smpte_335_ns, "r1");
- auto sf = mca_subs->add_child("SoundfieldGroupLabelSubDescriptor", "r0");
+ auto sf = cxml::add_child(mca_subs, "SoundfieldGroupLabelSubDescriptor", string("r0"));
char buffer[64];
soundfield->InstanceUID.EncodeString(buffer, sizeof(buffer));
- sf->add_child("InstanceID", "r1")->add_child_text("urn:uuid:" + string(buffer));
+ cxml::add_child(sf, "InstanceID", string("r1"))->add_child_text("urn:uuid:" + string(buffer));
soundfield->MCALabelDictionaryID.EncodeString(buffer, sizeof(buffer));
- sf->add_child("MCALabelDictionaryID", "r1")->add_child_text("urn:smpte:ul:" + string(buffer));
+ cxml::add_child(sf, "MCALabelDictionaryID", string("r1"))->add_child_text("urn:smpte:ul:" + string(buffer));
soundfield->MCALinkID.EncodeString(buffer, sizeof(buffer));
- sf->add_child("MCALinkID", "r1")->add_child_text("urn:uuid:" + string(buffer));
+ cxml::add_child(sf, "MCALinkID", string("r1"))->add_child_text("urn:uuid:" + string(buffer));
soundfield->MCATagSymbol.EncodeString(buffer, sizeof(buffer));
- sf->add_child("MCATagSymbol", "r1")->add_child_text(buffer);
+ cxml::add_child(sf, "MCATagSymbol", string("r1"))->add_child_text(buffer);
if (!soundfield->MCATagName.empty()) {
soundfield->MCATagName.get().EncodeString(buffer, sizeof(buffer));
- sf->add_child("MCATagName", "r1")->add_child_text(buffer);
+ cxml::add_child(sf, "MCATagName", string("r1"))->add_child_text(buffer);
}
if (!soundfield->RFC5646SpokenLanguage.empty()) {
soundfield->RFC5646SpokenLanguage.get().EncodeString(buffer, sizeof(buffer));
- sf->add_child("RFC5646SpokenLanguage", "r1")->add_child_text(buffer);
+ cxml::add_child(sf, "RFC5646SpokenLanguage", string("r1"))->add_child_text(buffer);
}
/* Find the MCA subdescriptors in the MXF so that we can also write them here */
@@ -435,29 +434,29 @@ CPL::write_mca_subdescriptors(xmlpp::Element* parent, shared_ptr<const SoundAsse
for (auto i: channels) {
auto channel = reinterpret_cast<ASDCP::MXF::AudioChannelLabelSubDescriptor*>(i);
- auto ch = mca_subs->add_child("AudioChannelLabelSubDescriptor", "r0");
+ auto ch = cxml::add_child(mca_subs, "AudioChannelLabelSubDescriptor", string("r0"));
channel->InstanceUID.EncodeString(buffer, sizeof(buffer));
- ch->add_child("InstanceID", "r1")->add_child_text("urn:uuid:" + string(buffer));
+ cxml::add_child(ch, "InstanceID", string("r1"))->add_child_text("urn:uuid:" + string(buffer));
channel->MCALabelDictionaryID.EncodeString(buffer, sizeof(buffer));
- ch->add_child("MCALabelDictionaryID", "r1")->add_child_text("urn:smpte:ul:" + string(buffer));
+ cxml::add_child(ch, "MCALabelDictionaryID", string("r1"))->add_child_text("urn:smpte:ul:" + string(buffer));
channel->MCALinkID.EncodeString(buffer, sizeof(buffer));
- ch->add_child("MCALinkID", "r1")->add_child_text("urn:uuid:" + string(buffer));
+ cxml::add_child(ch, "MCALinkID", string("r1"))->add_child_text("urn:uuid:" + string(buffer));
channel->MCATagSymbol.EncodeString(buffer, sizeof(buffer));
- ch->add_child("MCATagSymbol", "r1")->add_child_text(buffer);
+ cxml::add_child(ch, "MCATagSymbol", string("r1"))->add_child_text(buffer);
if (!channel->MCATagName.empty()) {
channel->MCATagName.get().EncodeString(buffer, sizeof(buffer));
- ch->add_child("MCATagName", "r1")->add_child_text(buffer);
+ cxml::add_child(ch, "MCATagName", string("r1"))->add_child_text(buffer);
}
if (!channel->MCAChannelID.empty()) {
- ch->add_child("MCAChannelID", "r1")->add_child_text(raw_convert<string>(channel->MCAChannelID.get()));
+ cxml::add_child(ch, "MCAChannelID", string("r1"))->add_child_text(raw_convert<string>(channel->MCAChannelID.get()));
}
if (!channel->RFC5646SpokenLanguage.empty()) {
channel->RFC5646SpokenLanguage.get().EncodeString(buffer, sizeof(buffer));
- ch->add_child("RFC5646SpokenLanguage", "r1")->add_child_text(buffer);
+ cxml::add_child(ch, "RFC5646SpokenLanguage", string("r1"))->add_child_text(buffer);
}
if (!channel->SoundfieldGroupLinkID.empty()) {
channel->SoundfieldGroupLinkID.get().EncodeString(buffer, sizeof(buffer));
- ch->add_child("SoundfieldGroupLinkID", "r1")->add_child_text("urn:uuid:" + string(buffer));
+ cxml::add_child(ch, "SoundfieldGroupLinkID", string("r1"))->add_child_text("urn:uuid:" + string(buffer));
}
}
}
@@ -481,16 +480,16 @@ CPL::maybe_write_composition_metadata_asset(xmlpp::Element* node, bool include_m
return;
}
- auto meta = node->add_child("meta:CompositionMetadataAsset");
+ auto meta = cxml::add_child(node, "meta:CompositionMetadataAsset");
meta->set_namespace_declaration (cpl_metadata_ns, "meta");
- meta->add_child("Id")->add_child_text("urn:uuid:" + _cpl_metadata_id);
+ cxml::add_text_child(meta, "Id", "urn:uuid:" + _cpl_metadata_id);
auto mp = _reels.front()->main_picture();
- meta->add_child("EditRate")->add_child_text(mp->edit_rate().as_string());
- meta->add_child("IntrinsicDuration")->add_child_text(raw_convert<string>(mp->intrinsic_duration()));
+ cxml::add_text_child(meta, "EditRate", mp->edit_rate().as_string());
+ cxml::add_text_child(meta, "IntrinsicDuration", raw_convert<string>(mp->intrinsic_duration()));
- auto fctt = meta->add_child("FullContentTitleText", "meta");
+ auto fctt = cxml::add_child(meta, "FullContentTitleText", string("meta"));
if (_full_content_title_text && !_full_content_title_text->empty()) {
fctt->add_child_text (*_full_content_title_text);
}
@@ -499,11 +498,11 @@ CPL::maybe_write_composition_metadata_asset(xmlpp::Element* node, bool include_m
}
if (_release_territory) {
- meta->add_child("ReleaseTerritory", "meta")->add_child_text(*_release_territory);
+ cxml::add_child(meta, "ReleaseTerritory", string("meta"))->add_child_text(*_release_territory);
}
if (_version_number) {
- xmlpp::Element* vn = meta->add_child("VersionNumber", "meta");
+ auto vn = cxml::add_child(meta, "VersionNumber", string("meta"));
vn->add_child_text(raw_convert<string>(*_version_number));
if (_status) {
vn->set_attribute("status", status_to_string(*_status));
@@ -511,19 +510,19 @@ CPL::maybe_write_composition_metadata_asset(xmlpp::Element* node, bool include_m
}
if (_chain) {
- meta->add_child("Chain", "meta")->add_child_text(*_chain);
+ cxml::add_child(meta, "Chain", string("meta"))->add_child_text(*_chain);
}
if (_distributor) {
- meta->add_child("Distributor", "meta")->add_child_text(*_distributor);
+ cxml::add_child(meta, "Distributor", string("meta"))->add_child_text(*_distributor);
}
if (_facility) {
- meta->add_child("Facility", "meta")->add_child_text(*_facility);
+ cxml::add_child(meta, "Facility", string("meta"))->add_child_text(*_facility);
}
if (_content_versions.size() > 1) {
- xmlpp::Element* vc = meta->add_child("AlternateContentVersionList", "meta");
+ auto vc = cxml::add_child(meta, "AlternateContentVersionList", string("meta"));
for (size_t i = 1; i < _content_versions.size(); ++i) {
_content_versions[i].as_xml (vc);
}
@@ -534,17 +533,17 @@ CPL::maybe_write_composition_metadata_asset(xmlpp::Element* node, bool include_m
}
if (_main_sound_configuration) {
- meta->add_child("MainSoundConfiguration", "meta")->add_child_text(_main_sound_configuration->to_string());
+ cxml::add_child(meta, "MainSoundConfiguration", string("meta"))->add_child_text(_main_sound_configuration->to_string());
}
- meta->add_child("MainSoundSampleRate", "meta")->add_child_text(raw_convert<string>(*_main_sound_sample_rate) + " 1");
+ cxml::add_child(meta, "MainSoundSampleRate", string("meta"))->add_child_text(raw_convert<string>(*_main_sound_sample_rate) + " 1");
- auto stored = meta->add_child("MainPictureStoredArea", "meta");
- stored->add_child("Width", "meta")->add_child_text(raw_convert<string>(_main_picture_stored_area->width));
- stored->add_child("Height", "meta")->add_child_text(raw_convert<string>(_main_picture_stored_area->height));
+ auto stored = cxml::add_child(meta, "MainPictureStoredArea", string("meta"));
+ cxml::add_child(stored, "Width", string("meta"))->add_child_text(raw_convert<string>(_main_picture_stored_area->width));
+ cxml::add_child(stored, "Height", string("meta"))->add_child_text(raw_convert<string>(_main_picture_stored_area->height));
- auto active = meta->add_child("MainPictureActiveArea", "meta");
- active->add_child("Width", "meta")->add_child_text(raw_convert<string>(_main_picture_active_area->width));
- active->add_child("Height", "meta")->add_child_text(raw_convert<string>(_main_picture_active_area->height));
+ auto active = cxml::add_child(meta, "MainPictureActiveArea", string("meta"));
+ cxml::add_child(active, "Width", string("meta"))->add_child_text(raw_convert<string>(_main_picture_active_area->width));
+ cxml::add_child(active, "Height", string("meta"))->add_child_text(raw_convert<string>(_main_picture_active_area->height));
optional<string> first_subtitle_language;
for (auto i: _reels) {
@@ -567,18 +566,18 @@ CPL::maybe_write_composition_metadata_asset(xmlpp::Element* node, bool include_m
}
lang += i;
}
- meta->add_child("MainSubtitleLanguageList", "meta")->add_child_text(lang);
+ cxml::add_child(meta, "MainSubtitleLanguageList", string("meta"))->add_child_text(lang);
}
- auto metadata_list = meta->add_child("ExtensionMetadataList", "meta");
+ auto metadata_list = cxml::add_child(meta, "ExtensionMetadataList", string("meta"));
auto add_extension_metadata = [metadata_list](string scope, string name, string property_name, string property_value) {
- auto extension = metadata_list->add_child("ExtensionMetadata", "meta");
+ auto extension = cxml::add_child(metadata_list, "ExtensionMetadata", string("meta"));
extension->set_attribute("scope", scope);
- extension->add_child("Name", "meta")->add_child_text(name);
- auto property = extension->add_child("PropertyList", "meta")->add_child("Property", "meta");
- property->add_child("Name", "meta")->add_child_text(property_name);
- property->add_child("Value", "meta")->add_child_text(property_value);
+ cxml::add_child(extension, "Name", string("meta"))->add_child_text(name);
+ auto property = cxml::add_child(cxml::add_child(extension, "PropertyList", string("meta")), "Property", string("meta"));
+ cxml::add_child(property, "Name", string("meta"))->add_child_text(property_name);
+ cxml::add_child(property, "Value", string("meta"))->add_child_text(property_value);
};
/* SMPTE Bv2.1 8.6.3 */
diff --git a/src/dcp.cc b/src/dcp.cc
index eb21b47d..92c5cd88 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -49,17 +49,18 @@
#include "exceptions.h"
#include "filesystem.h"
#include "font_asset.h"
-#include "interop_subtitle_asset.h"
+#include "interop_text_asset.h"
#include "metadata.h"
-#include "mono_picture_asset.h"
-#include "picture_asset.h"
+#include "mono_j2k_picture_asset.h"
+#include "mono_mpeg2_picture_asset.h"
+#include "j2k_picture_asset.h"
#include "pkl.h"
#include "raw_convert.h"
#include "reel_asset.h"
-#include "reel_subtitle_asset.h"
-#include "smpte_subtitle_asset.h"
+#include "reel_text_asset.h"
+#include "smpte_text_asset.h"
#include "sound_asset.h"
-#include "stereo_picture_asset.h"
+#include "stereo_j2k_picture_asset.h"
#include "util.h"
#include "verify.h"
#include "warnings.h"
@@ -221,7 +222,7 @@ DCP::read (vector<dcp::VerificationNote>* notes, bool ignore_incorrect_picture_m
if (
pkl_type == remove_parameters(CPL::static_pkl_type(standard)) ||
- pkl_type == remove_parameters(InteropSubtitleAsset::static_pkl_type(standard))) {
+ pkl_type == remove_parameters(InteropTextAsset::static_pkl_type(standard))) {
auto p = new xmlpp::DomParser;
try {
p->parse_file(dcp::filesystem::fix_long_path(path).string());
@@ -243,13 +244,14 @@ DCP::read (vector<dcp::VerificationNote>* notes, bool ignore_incorrect_picture_m
if (standard == Standard::SMPTE && notes) {
notes->push_back (VerificationNote(VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_STANDARD));
}
- other_assets.push_back (make_shared<InteropSubtitleAsset>(path));
+ other_assets.push_back (make_shared<InteropTextAsset>(path));
}
} else if (
- *pkl_type == remove_parameters(PictureAsset::static_pkl_type(standard)) ||
+ *pkl_type == remove_parameters(J2KPictureAsset::static_pkl_type(standard)) ||
+ *pkl_type == remove_parameters(MPEG2PictureAsset::static_pkl_type(standard)) ||
*pkl_type == remove_parameters(SoundAsset::static_pkl_type(standard)) ||
*pkl_type == remove_parameters(AtmosAsset::static_pkl_type(standard)) ||
- *pkl_type == remove_parameters(SMPTESubtitleAsset::static_pkl_type(standard))
+ *pkl_type == remove_parameters(SMPTETextAsset::static_pkl_type(standard))
) {
bool found_threed_marked_as_twod = false;
@@ -441,7 +443,7 @@ DCP::write_volindex (Standard standard) const
DCP_ASSERT (false);
}
- root->add_child("Index")->add_child_text ("1");
+ cxml::add_text_child(root, "Index", "1");
doc.write_to_file_formatted(dcp::filesystem::fix_long_path(p).string(), "UTF-8");
}
@@ -542,7 +544,7 @@ DCP::assets (bool ignore_unresolved) const
auto o = j->asset_ref().asset();
assets.push_back (o);
/* More Interop special-casing */
- auto sub = dynamic_pointer_cast<InteropSubtitleAsset>(o);
+ auto sub = dynamic_pointer_cast<InteropTextAsset>(o);
if (sub) {
add_to_container(assets, sub->font_assets());
}
diff --git a/src/dcp_time.h b/src/dcp_time.h
index 506dafda..21b59921 100644
--- a/src/dcp_time.h
+++ b/src/dcp_time.h
@@ -37,8 +37,8 @@
*/
-#ifndef LIBDCP_TIME_H
-#define LIBDCP_TIME_H
+#ifndef LIBDCP_DCP_TIME_H
+#define LIBDCP_DCP_TIME_H
#include "types.h"
diff --git a/src/encrypted_kdm.cc b/src/encrypted_kdm.cc
index 465a657d..d1089c0b 100644
--- a/src/encrypted_kdm.cc
+++ b/src/encrypted_kdm.cc
@@ -44,6 +44,7 @@
#include "file.h"
#include "util.h"
#include <libcxml/cxml.h>
+#include <libxml++/attributenode.h>
#include <libxml++/document.h>
#include <libxml++/nodes/element.h>
#include <libxml/parser.h>
@@ -85,8 +86,8 @@ public:
void as_xml (xmlpp::Element* node) const
{
- node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
- node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
+ cxml::add_child(node, "X509IssuerName", string("ds"))->add_child_text(x509_issuer_name);
+ cxml::add_child(node, "X509SerialNumber", string("ds"))->add_child_text(x509_serial_number);
}
string x509_issuer_name;
@@ -108,8 +109,8 @@ public:
void as_xml (xmlpp::Element* node) const
{
- x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial", "ds"));
- node->add_child("X509Certificate", "ds")->add_child_text (x509_certificate);
+ x509_issuer_serial.as_xml(cxml::add_child(node, "X509IssuerSerial", string("ds")));
+ cxml::add_child(node, "X509Certificate", string("ds"))->add_child_text(x509_certificate);
}
Signer x509_issuer_serial;
@@ -136,8 +137,8 @@ public:
void as_xml (xmlpp::Element* node) const
{
node->set_attribute ("URI", uri);
- node->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
- node->add_child("DigestValue", "ds")->add_child_text (digest_value);
+ cxml::add_child(node, "DigestMethod", string("ds"))->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
+ cxml::add_child(node, "DigestValue", string("ds"))->add_child_text(digest_value);
}
string uri;
@@ -168,16 +169,16 @@ public:
void as_xml (xmlpp::Element* node) const
{
- node->add_child ("CanonicalizationMethod", "ds")->set_attribute (
+ cxml::add_child(node, "CanonicalizationMethod", string("ds"))->set_attribute(
"Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
);
- node->add_child ("SignatureMethod", "ds")->set_attribute (
+ cxml::add_child(node, "SignatureMethod", string("ds"))->set_attribute(
"Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
);
- authenticated_public.as_xml (node->add_child ("Reference", "ds"));
- authenticated_private.as_xml (node->add_child ("Reference", "ds"));
+ authenticated_public.as_xml(cxml::add_child(node, "Reference", string("ds")));
+ authenticated_private.as_xml(cxml::add_child(node, "Reference", string("ds")));
}
private:
@@ -200,14 +201,14 @@ public:
}
}
- void as_xml (xmlpp::Node* node) const
+ void as_xml(xmlpp::Element* element) const
{
- signed_info.as_xml (node->add_child ("SignedInfo", "ds"));
- node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
+ signed_info.as_xml(cxml::add_child(element, "SignedInfo", string("ds")));
+ cxml::add_child(element, "SignatureValue", string("ds"))->add_child_text(signature_value);
- auto key_info_node = node->add_child("KeyInfo", "ds");
+ auto key_info_node = cxml::add_child(element, "KeyInfo", string("ds"));
for (auto i: x509_data) {
- i.as_xml (key_info_node->add_child("X509Data", "ds"));
+ i.as_xml(cxml::add_child(key_info_node, "X509Data", string("ds")));
}
}
@@ -229,22 +230,22 @@ public:
}
}
- void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
+ void as_xml (xmlpp::Element* node, map<string, xmlpp::AttributeNode*>& references) const
{
- references["ID_AuthenticatedPrivate"] = node->set_attribute ("Id", "ID_AuthenticatedPrivate");
+ references["ID_AuthenticatedPrivate"] = dynamic_cast<xmlpp::AttributeNode*>(node->set_attribute("Id", "ID_AuthenticatedPrivate"));
for (auto i: encrypted_key) {
- auto encrypted_key = node->add_child ("EncryptedKey", "enc");
+ auto encrypted_key = cxml::add_child(node, "EncryptedKey", string("enc"));
/* XXX: hack for testing with Dolby */
encrypted_key->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
- auto encryption_method = encrypted_key->add_child("EncryptionMethod", "enc");
+ auto encryption_method = cxml::add_child(encrypted_key, "EncryptionMethod", string("enc"));
encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
- auto digest_method = encryption_method->add_child ("DigestMethod", "ds");
+ auto digest_method = cxml::add_child(encryption_method, "DigestMethod", string("ds"));
/* XXX: hack for testing with Dolby */
digest_method->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
digest_method->set_attribute ("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
- auto cipher_data = encrypted_key->add_child("CipherData", "enc");
- cipher_data->add_child("CipherValue", "enc")->add_child_text (i);
+ auto cipher_data = cxml::add_child(encrypted_key, "CipherData", string("enc"));
+ cxml::add_child(cipher_data, "CipherValue", string("enc"))->add_child_text(i);
}
}
@@ -271,9 +272,9 @@ public:
void as_xml (xmlpp::Element* node) const
{
- auto type = node->add_child("KeyType");
+ auto type = cxml::add_child(node, "KeyType");
type->add_child_text (key_type);
- node->add_child("KeyId")->add_child_text ("urn:uuid:" + key_id);
+ cxml::add_text_child(node, "KeyId", "urn:uuid:" + key_id);
/* XXX: this feels like a bit of a hack */
if (key_type == "MDEK") {
type->set_attribute ("scope", "http://www.dolby.com/cp850/2012/KDM#kdm-key-type");
@@ -302,7 +303,7 @@ public:
void as_xml (xmlpp::Element* node) const
{
for (auto const& i: typed_key_id) {
- i.as_xml (node->add_child("TypedKeyId"));
+ i.as_xml(cxml::add_child(node, ("TypedKeyId")));
}
}
@@ -326,13 +327,13 @@ public:
void as_xml (xmlpp::Element* node) const
{
- node->add_child ("DeviceListIdentifier")->add_child_text ("urn:uuid:" + device_list_identifier);
+ cxml::add_text_child(node, "DeviceListIdentifier", "urn:uuid:" + device_list_identifier);
if (device_list_description) {
- node->add_child ("DeviceListDescription")->add_child_text (device_list_description.get());
+ cxml::add_text_child(node, "DeviceListDescription", device_list_description.get());
}
- auto device_list = node->add_child ("DeviceList");
+ auto device_list = cxml::add_child(node, "DeviceList");
for (auto i: certificate_thumbprints) {
- device_list->add_child("CertificateThumbprint")->add_child_text (i);
+ cxml::add_text_child(device_list, "CertificateThumbprint", i);
}
}
@@ -357,8 +358,8 @@ public:
void as_xml (xmlpp::Element* node) const
{
- node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
- node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
+ cxml::add_child(node, "X509IssuerName", string("ds"))->add_child_text(x509_issuer_name);
+ cxml::add_child(node, "X509SerialNumber", string("ds"))->add_child_text(x509_serial_number);
}
string x509_issuer_name;
@@ -380,8 +381,8 @@ public:
void as_xml (xmlpp::Element* node) const
{
- x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial"));
- node->add_child("X509SubjectName")->add_child_text (x509_subject_name);
+ x509_issuer_serial.as_xml(cxml::add_child(node, "X509IssuerSerial"));
+ cxml::add_text_child(node, "X509SubjectName", x509_subject_name);
}
X509IssuerSerial x509_issuer_serial;
@@ -428,30 +429,30 @@ public:
{
node->set_attribute ("xmlns", "http://www.smpte-ra.org/schemas/430-1/2006/KDM");
- recipient.as_xml (node->add_child ("Recipient"));
- node->add_child("CompositionPlaylistId")->add_child_text ("urn:uuid:" + composition_playlist_id);
- node->add_child("ContentTitleText")->add_child_text (content_title_text);
+ recipient.as_xml(cxml::add_child(node, "Recipient"));
+ cxml::add_text_child(node, "CompositionPlaylistId", "urn:uuid:" + composition_playlist_id);
+ cxml::add_text_child(node, "ContentTitleText", content_title_text);
if (content_authenticator) {
- node->add_child("ContentAuthenticator")->add_child_text (content_authenticator.get ());
+ cxml::add_text_child(node, "ContentAuthenticator", content_authenticator.get());
}
- node->add_child("ContentKeysNotValidBefore")->add_child_text (not_valid_before.as_string ());
- node->add_child("ContentKeysNotValidAfter")->add_child_text (not_valid_after.as_string ());
+ cxml::add_text_child(node, "ContentKeysNotValidBefore", not_valid_before.as_string());
+ cxml::add_text_child(node, "ContentKeysNotValidAfter", not_valid_after.as_string());
if (authorized_device_info) {
- authorized_device_info->as_xml (node->add_child ("AuthorizedDeviceInfo"));
+ authorized_device_info->as_xml(cxml::add_child(node, "AuthorizedDeviceInfo"));
}
- key_id_list.as_xml (node->add_child ("KeyIdList"));
+ key_id_list.as_xml(cxml::add_child(node, "KeyIdList"));
if (disable_forensic_marking_picture || disable_forensic_marking_audio) {
- auto forensic_mark_flag_list = node->add_child ("ForensicMarkFlagList");
+ auto forensic_mark_flag_list = cxml::add_child(node, "ForensicMarkFlagList");
if (disable_forensic_marking_picture) {
- forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text(picture_disable);
+ cxml::add_text_child(forensic_mark_flag_list, "ForensicMarkFlag", picture_disable);
}
if (disable_forensic_marking_audio) {
auto mrkflg = audio_disable;
if (*disable_forensic_marking_audio > 0) {
mrkflg += String::compose ("-above-channel-%1", *disable_forensic_marking_audio);
}
- forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text (mrkflg);
+ cxml::add_text_child(forensic_mark_flag_list, "ForensicMarkFlag", mrkflg);
}
}
}
@@ -490,7 +491,7 @@ public:
void as_xml (xmlpp::Element* node) const
{
- kdm_required_extensions.as_xml (node->add_child ("KDMRequiredExtensions"));
+ kdm_required_extensions.as_xml(cxml::add_child(node, "KDMRequiredExtensions"));
}
KDMRequiredExtensions kdm_required_extensions;
@@ -517,21 +518,21 @@ public:
}
- void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
+ void as_xml (xmlpp::Element* node, map<string, xmlpp::AttributeNode*>& references) const
{
- references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
+ references["ID_AuthenticatedPublic"] = dynamic_cast<xmlpp::AttributeNode*>(node->set_attribute("Id", "ID_AuthenticatedPublic"));
- node->add_child("MessageId")->add_child_text ("urn:uuid:" + message_id);
- node->add_child("MessageType")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
+ cxml::add_text_child(node, "MessageId", "urn:uuid:" + message_id);
+ cxml::add_text_child(node, "MessageType", "http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
if (annotation_text) {
- node->add_child("AnnotationText")->add_child_text (annotation_text.get ());
+ cxml::add_text_child(node, "AnnotationText", annotation_text.get());
}
- node->add_child("IssueDate")->add_child_text (issue_date);
+ cxml::add_text_child(node, "IssueDate", issue_date);
- signer.as_xml (node->add_child ("Signer"));
- required_extensions.as_xml (node->add_child ("RequiredExtensions"));
+ signer.as_xml(cxml::add_child(node, "Signer"));
+ required_extensions.as_xml(cxml::add_child(node, "RequiredExtensions"));
- node->add_child ("NonCriticalExtensions");
+ cxml::add_child(node, "NonCriticalExtensions");
}
string message_id;
@@ -563,14 +564,14 @@ public:
shared_ptr<xmlpp::Document> as_xml () const
{
- shared_ptr<xmlpp::Document> document (new xmlpp::Document ());
- xmlpp::Element* root = document->create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
+ auto document = make_shared<xmlpp::Document>();
+ auto root = document->create_root_node("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
root->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
- map<string, xmlpp::Attribute *> references;
- authenticated_public.as_xml (root->add_child ("AuthenticatedPublic"), references);
- authenticated_private.as_xml (root->add_child ("AuthenticatedPrivate"), references);
- signature.as_xml (root->add_child ("Signature", "ds"));
+ map<string, xmlpp::AttributeNode*> references;
+ authenticated_public.as_xml(cxml::add_child(root, "AuthenticatedPublic"), references);
+ authenticated_private.as_xml(cxml::add_child(root, "AuthenticatedPrivate"), references);
+ signature.as_xml(cxml::add_child(root, "Signature", string("ds")));
for (auto i: references) {
xmlAddID (0, document->cobj(), (const xmlChar *) i.first.c_str(), i.second->cobj());
diff --git a/src/equality_options.h b/src/equality_options.h
index 1c29be7e..1e890a09 100644
--- a/src/equality_options.h
+++ b/src/equality_options.h
@@ -77,10 +77,10 @@ public:
bool load_font_nodes_can_differ = false;
bool sound_assets_can_differ = false;
bool keep_going = false;
- /** true to save the last pair of different image subtitles to the current working directory */
- bool export_differing_subtitles = false;
- /** The maximum allowable absolute difference between the vertical position of subtitles */
- float max_subtitle_vertical_position_error = 0;
+ /** true to save the last pair of different image subtitles/captions to the current working directory */
+ bool export_differing_texts = false;
+ /** The maximum allowable absolute difference between the vertical position of texts */
+ float max_text_vertical_position_error = 0;
};
diff --git a/src/exceptions.cc b/src/exceptions.cc
index 9c57011d..4420125c 100644
--- a/src/exceptions.cc
+++ b/src/exceptions.cc
@@ -121,8 +121,8 @@ ReadError::ReadError (string message, string detail)
}
-MissingSubtitleImageError::MissingSubtitleImageError (string id)
- : runtime_error (String::compose("Could not load image for subtitle %1", id))
+MissingTextImageError::MissingTextImageError (string id)
+ : runtime_error (String::compose("Could not load image for subtitle/caption %1", id))
{
}
diff --git a/src/exceptions.h b/src/exceptions.h
index 8d85f02a..145df25f 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -140,6 +140,33 @@ public:
};
+class MPEG2CodecError : public MiscError
+{
+public:
+ explicit MPEG2CodecError(std::string message)
+ : MiscError(message)
+ {}
+};
+
+
+class MPEG2DecompressionError : public ReadError
+{
+public:
+ explicit MPEG2DecompressionError(std::string message)
+ : ReadError(message)
+ {}
+};
+
+
+class MPEG2CompressionError : public MiscError
+{
+public:
+ explicit MPEG2CompressionError(std::string message)
+ : MiscError(message)
+ {}
+};
+
+
class BadContentKindError : public ReadError
{
public:
@@ -232,10 +259,10 @@ public:
};
-class MissingSubtitleImageError : public std::runtime_error
+class MissingTextImageError : public std::runtime_error
{
public:
- MissingSubtitleImageError (std::string id);
+ MissingTextImageError (std::string id);
};
diff --git a/src/ffmpeg_image.cc b/src/ffmpeg_image.cc
new file mode 100644
index 00000000..deebe1b6
--- /dev/null
+++ b/src/ffmpeg_image.cc
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "ffmpeg_image.h"
+#include "types.h"
+extern "C" {
+#include <libavutil/pixfmt.h>
+}
+
+
+using namespace dcp;
+
+
+FFmpegImage::FFmpegImage(int64_t pts)
+{
+ auto const width = size().width;
+ auto const height = size().height;
+
+ _frame = av_frame_alloc();
+ if (!_frame) {
+ throw std::bad_alloc();
+ }
+
+ _frame->buf[0] = av_buffer_alloc(width * height);
+ _frame->buf[1] = av_buffer_alloc(width * height / 4);
+ _frame->buf[2] = av_buffer_alloc(width * height / 4);
+
+ _frame->linesize[0] = width;
+ _frame->linesize[1] = width / 2;
+ _frame->linesize[2] = width / 2;
+
+ for (auto i = 0; i < 3; ++i) {
+ _frame->data[i] = _frame->buf[i]->data;
+ }
+
+ _frame->width = width;
+ _frame->height = height;
+ _frame->format = AV_PIX_FMT_YUV420P;
+ _frame->pts = pts;
+}
+
+
+void
+FFmpegImage::set_pts(int64_t pts)
+{
+ _frame->pts = pts;
+}
+
+
+uint8_t*
+FFmpegImage::y()
+{
+ return _frame->data[0];
+}
+
+
+int
+FFmpegImage::y_stride() const
+{
+ return _frame->linesize[0];
+}
+
+
+uint8_t*
+FFmpegImage::u()
+{
+ return _frame->data[1];
+}
+
+
+int
+FFmpegImage::u_stride() const
+{
+ return _frame->linesize[1];
+}
+
+
+uint8_t*
+FFmpegImage::v()
+{
+ return _frame->data[2];
+}
+
+
+int
+FFmpegImage::v_stride() const
+{
+ return _frame->linesize[2];
+}
+
+
diff --git a/src/ffmpeg_image.h b/src/ffmpeg_image.h
new file mode 100644
index 00000000..44eb0db7
--- /dev/null
+++ b/src/ffmpeg_image.h
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_FFMPEG_IMAGE_H
+#define LIBDCP_FFMPEG_IMAGE_H
+
+
+#include "types.h"
+#include "warnings.h"
+LIBDCP_DISABLE_WARNINGS
+extern "C" {
+#include <libavutil/frame.h>
+}
+LIBDCP_ENABLE_WARNINGS
+#include <algorithm>
+#include <vector>
+
+
+namespace dcp {
+
+
+class FFmpegImage
+{
+public:
+ explicit FFmpegImage(int64_t pts);
+
+ explicit FFmpegImage(AVFrame* frame)
+ : _frame(frame)
+ {}
+
+ FFmpegImage(FFmpegImage const& other) = delete;
+ FFmpegImage& operator=(FFmpegImage const& other) = delete;
+
+ FFmpegImage(FFmpegImage&& other) {
+ std::swap(_frame, other._frame);
+ }
+
+ FFmpegImage& operator=(FFmpegImage&& other) {
+ std::swap(_frame, other._frame);
+ return *this;
+ }
+
+ ~FFmpegImage()
+ {
+ av_frame_free(&_frame);
+ }
+
+ AVFrame const * frame() const {
+ return _frame;
+ }
+
+ uint8_t* y();
+ int y_stride() const;
+
+ uint8_t* u();
+ int u_stride() const;
+
+ uint8_t* v();
+ int v_stride() const;
+
+ Size size() const {
+ return { 1920, 1080 };
+ }
+
+ void set_pts(int64_t pts);
+
+private:
+ AVFrame* _frame = nullptr;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/reel_closed_caption_asset.cc b/src/frame_info.h
index e5649d6a..325350c4 100644
--- a/src/reel_closed_caption_asset.cc
+++ b/src/frame_info.h
@@ -32,59 +32,78 @@
*/
-/** @file src/reel_closed_caption_asset.cc
- * @brief ReelClosedCaptionAsset class
- */
+#ifndef LIBDCP_FRAME_INFO_H
+#define LIBDCP_FRAME_INFO_H
-#include "dcp_assert.h"
-#include "reel_closed_caption_asset.h"
-#include "smpte_subtitle_asset.h"
-#include "subtitle_asset.h"
#include "warnings.h"
LIBDCP_DISABLE_WARNINGS
-#include <libxml++/libxml++.h>
+#include <asdcp/AS_DCP.h>
LIBDCP_ENABLE_WARNINGS
+#include <stdint.h>
+#include <string>
-using std::string;
-using std::shared_ptr;
-using std::dynamic_pointer_cast;
-using namespace dcp;
+namespace dcp {
-ReelClosedCaptionAsset::ReelClosedCaptionAsset (std::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
- : ReelFileAsset (
- asset,
- dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : boost::none,
- asset->id(),
- edit_rate,
- intrinsic_duration,
- entry_point
- )
+/** @class FrameInfo
+ * @brief Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame)
+ */
+struct FrameInfo
{
+ FrameInfo () = default;
-}
+ FrameInfo(uint64_t o, uint64_t s, std::string h)
+ : offset(o)
+ , size(s)
+ , hash(h)
+ {}
+
+ uint64_t offset = 0;
+ uint64_t size = 0;
+ std::string hash;
+};
-ReelClosedCaptionAsset::ReelClosedCaptionAsset (std::shared_ptr<const cxml::Node> node)
- : ReelFileAsset (node)
+struct J2KFrameInfo : public FrameInfo
{
- _language = node->optional_string_child ("Language");
-}
+ J2KFrameInfo() = default;
+ J2KFrameInfo(uint64_t offset_, uint64_t size_, std::string hash_)
+ : FrameInfo(offset_, size_, hash_)
+ {}
+};
-bool
-ReelClosedCaptionAsset::equals(shared_ptr<const ReelClosedCaptionAsset> other, EqualityOptions const& opt, NoteHandler note) const
+
+struct MPEG2FrameInfo : public FrameInfo
{
- if (!asset_equals (other, opt, note)) {
- return false;
- }
- if (!file_asset_equals (other, opt, note)) {
- return false;
- }
-
- return true;
+ MPEG2FrameInfo() = default;
+
+ MPEG2FrameInfo(
+ uint64_t offset_,
+ uint64_t size_,
+ std::string hash_,
+ ASDCP::MPEG2::FrameType_t type_,
+ bool gop_start_,
+ bool closed_gop_,
+ uint8_t temporal_offset_
+ )
+ : FrameInfo(offset_, size_, hash_)
+ , type(type_)
+ , gop_start(gop_start_)
+ , closed_gop(closed_gop_)
+ , temporal_offset(temporal_offset_)
+ {}
+
+ ASDCP::MPEG2::FrameType_t type;
+ bool gop_start;
+ bool closed_gop;
+ uint8_t temporal_offset;
+};
+
+
}
+#endif
diff --git a/src/interop_subtitle_asset.cc b/src/interop_text_asset.cc
index 253a0498..01e0f89a 100644
--- a/src/interop_subtitle_asset.cc
+++ b/src/interop_text_asset.cc
@@ -32,8 +32,8 @@
*/
-/** @file src/interop_subtitle_asset.cc
- * @brief InteropSubtitleAsset class
+/** @file src/interop_text_asset.cc
+ * @brief InteropTextAsset class
*/
@@ -44,10 +44,10 @@
#include "font_asset.h"
#include "file.h"
#include "interop_load_font_node.h"
-#include "interop_subtitle_asset.h"
+#include "interop_text_asset.h"
#include "raw_convert.h"
-#include "subtitle_asset_internal.h"
-#include "subtitle_image.h"
+#include "text_asset_internal.h"
+#include "text_image.h"
#include "util.h"
#include "warnings.h"
#include "xml.h"
@@ -70,8 +70,8 @@ using boost::optional;
using namespace dcp;
-InteropSubtitleAsset::InteropSubtitleAsset (boost::filesystem::path file)
- : SubtitleAsset (file)
+InteropTextAsset::InteropTextAsset(boost::filesystem::path file)
+ : TextAsset(file)
{
_raw_xml = dcp::file_to_string(file, 10 * 1024 * 1024);
@@ -89,12 +89,12 @@ InteropSubtitleAsset::InteropSubtitleAsset (boost::filesystem::path file)
for (auto i: xml->node()->get_children()) {
auto e = dynamic_cast<xmlpp::Element const *>(i);
if (e && (e->get_name() == "Font" || e->get_name() == "Subtitle")) {
- parse_subtitles (e, ps, optional<int>(), Standard::INTEROP);
+ parse_texts (e, ps, optional<int>(), Standard::INTEROP);
}
}
- for (auto i: _subtitles) {
- auto si = dynamic_pointer_cast<SubtitleImage>(i);
+ for (auto i: _texts) {
+ auto si = dynamic_pointer_cast<TextImage>(i);
if (si) {
si->read_png_file (file.parent_path() / String::compose("%1.png", si->id()));
}
@@ -102,38 +102,38 @@ InteropSubtitleAsset::InteropSubtitleAsset (boost::filesystem::path file)
}
-InteropSubtitleAsset::InteropSubtitleAsset ()
+InteropTextAsset::InteropTextAsset()
{
}
string
-InteropSubtitleAsset::xml_as_string () const
+InteropTextAsset::xml_as_string() const
{
xmlpp::Document doc;
auto root = doc.create_root_node ("DCSubtitle");
root->set_attribute ("Version", "1.0");
- root->add_child("SubtitleID")->add_child_text (_id);
- root->add_child("MovieTitle")->add_child_text (_movie_title);
- root->add_child("ReelNumber")->add_child_text (raw_convert<string> (_reel_number));
- root->add_child("Language")->add_child_text (_language);
+ cxml::add_text_child(root, "SubtitleID", _id);
+ cxml::add_text_child(root, "MovieTitle", _movie_title);
+ cxml::add_text_child(root, "ReelNumber", raw_convert<string> (_reel_number));
+ cxml::add_text_child(root, "Language", _language);
for (auto i: _load_font_nodes) {
- auto load_font = root->add_child("LoadFont");
+ auto load_font = cxml::add_child(root, "LoadFont");
load_font->set_attribute ("Id", i->id);
load_font->set_attribute ("URI", i->uri);
}
- subtitles_as_xml (root, 250, Standard::INTEROP);
+ texts_as_xml(root, 250, Standard::INTEROP);
return format_xml(doc, {});
}
void
-InteropSubtitleAsset::add_font (string load_id, dcp::ArrayData data)
+InteropTextAsset::add_font(string load_id, dcp::ArrayData data)
{
_fonts.push_back (Font(load_id, make_uuid(), data));
auto const uri = String::compose("font_%1.ttf", _load_font_nodes.size());
@@ -142,13 +142,13 @@ InteropSubtitleAsset::add_font (string load_id, dcp::ArrayData data)
bool
-InteropSubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const& options, NoteHandler note) const
+InteropTextAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const& options, NoteHandler note) const
{
- if (!SubtitleAsset::equals (other_asset, options, note)) {
+ if (!TextAsset::equals (other_asset, options, note)) {
return false;
}
- auto other = dynamic_pointer_cast<const InteropSubtitleAsset> (other_asset);
+ auto other = dynamic_pointer_cast<const InteropTextAsset> (other_asset);
if (!other) {
return false;
}
@@ -174,7 +174,7 @@ InteropSubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOption
}
if (_movie_title != other->_movie_title) {
- note (NoteType::ERROR, "Subtitle movie titles differ");
+ note (NoteType::ERROR, "Subtitle or caption movie titles differ");
return false;
}
@@ -183,7 +183,7 @@ InteropSubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOption
vector<shared_ptr<LoadFontNode>>
-InteropSubtitleAsset::load_font_nodes () const
+InteropTextAsset::load_font_nodes() const
{
vector<shared_ptr<LoadFontNode>> lf;
copy (_load_font_nodes.begin(), _load_font_nodes.end(), back_inserter (lf));
@@ -192,7 +192,7 @@ InteropSubtitleAsset::load_font_nodes () const
void
-InteropSubtitleAsset::write (boost::filesystem::path p) const
+InteropTextAsset::write(boost::filesystem::path p) const
{
File f(p, "wb");
if (!f) {
@@ -206,9 +206,8 @@ InteropSubtitleAsset::write (boost::filesystem::path p) const
_file = p;
/* Image subtitles */
- for (auto i: _subtitles) {
- auto im = dynamic_pointer_cast<dcp::SubtitleImage> (i);
- if (im) {
+ for (auto i: _texts) {
+ if (auto im = dynamic_pointer_cast<dcp::TextImage>(i)) {
im->write_png_file(p.parent_path() / String::compose("%1.png", im->id()));
}
}
@@ -230,7 +229,7 @@ InteropSubtitleAsset::write (boost::filesystem::path p) const
* a list of font ID, load ID and data.
*/
void
-InteropSubtitleAsset::resolve_fonts (vector<shared_ptr<Asset>> assets)
+InteropTextAsset::resolve_fonts(vector<shared_ptr<Asset>> assets)
{
for (auto asset: assets) {
auto font = dynamic_pointer_cast<FontAsset>(asset);
@@ -256,7 +255,7 @@ InteropSubtitleAsset::resolve_fonts (vector<shared_ptr<Asset>> assets)
vector<shared_ptr<Asset>>
-InteropSubtitleAsset::font_assets()
+InteropTextAsset::font_assets()
{
vector<shared_ptr<Asset>> assets;
for (auto const& i: _fonts) {
@@ -268,7 +267,7 @@ InteropSubtitleAsset::font_assets()
vector<shared_ptr<const Asset>>
-InteropSubtitleAsset::font_assets() const
+InteropTextAsset::font_assets() const
{
vector<shared_ptr<const Asset>> assets;
for (auto const& i: _fonts) {
@@ -280,12 +279,12 @@ InteropSubtitleAsset::font_assets() const
void
-InteropSubtitleAsset::add_to_assetmap (AssetMap& asset_map, boost::filesystem::path root) const
+InteropTextAsset::add_to_assetmap(AssetMap& asset_map, boost::filesystem::path root) const
{
Asset::add_to_assetmap(asset_map, root);
- for (auto i: _subtitles) {
- auto im = dynamic_pointer_cast<dcp::SubtitleImage>(i);
+ for (auto i: _texts) {
+ auto im = dynamic_pointer_cast<dcp::TextImage>(i);
if (im) {
DCP_ASSERT(im->file());
add_file_to_assetmap(asset_map, root, im->file().get(), im->id());
@@ -295,12 +294,12 @@ InteropSubtitleAsset::add_to_assetmap (AssetMap& asset_map, boost::filesystem::p
void
-InteropSubtitleAsset::add_to_pkl (shared_ptr<PKL> pkl, boost::filesystem::path root) const
+InteropTextAsset::add_to_pkl(shared_ptr<PKL> pkl, boost::filesystem::path root) const
{
Asset::add_to_pkl (pkl, root);
- for (auto i: _subtitles) {
- auto im = dynamic_pointer_cast<dcp::SubtitleImage> (i);
+ for (auto i: _texts) {
+ auto im = dynamic_pointer_cast<dcp::TextImage>(i);
if (im) {
auto png_image = im->png_image ();
pkl->add_asset(im->id(), optional<string>(), make_digest(png_image), png_image.size(), "image/png", root.filename().string());
@@ -310,7 +309,7 @@ InteropSubtitleAsset::add_to_pkl (shared_ptr<PKL> pkl, boost::filesystem::path r
void
-InteropSubtitleAsset::set_font_file (string load_id, boost::filesystem::path file)
+InteropTextAsset::set_font_file(string load_id, boost::filesystem::path file)
{
for (auto& i: _fonts) {
if (i.load_id == load_id) {
@@ -327,7 +326,7 @@ InteropSubtitleAsset::set_font_file (string load_id, boost::filesystem::path fil
vector<string>
-InteropSubtitleAsset::unresolved_fonts() const
+InteropTextAsset::unresolved_fonts() const
{
vector<string> unresolved;
for (auto load_font_node: _load_font_nodes) {
diff --git a/src/interop_subtitle_asset.h b/src/interop_text_asset.h
index f63740d5..363b1f27 100644
--- a/src/interop_subtitle_asset.h
+++ b/src/interop_text_asset.h
@@ -32,16 +32,16 @@
*/
-/** @file src/interop_subtitle_asset.h
- * @brief InteropSubtitleAsset class
+/** @file src/interop_text_asset.h
+ * @brief InteropTextAsset class
*/
-#ifndef DCP_INTEROP_SUBTITLE_ASSET_H
-#define DCP_INTEROP_SUBTITLE_ASSET_H
+#ifndef LIBDCP_INTEROP_TEXT_ASSET_H
+#define LIBDCP_INTEROP_TEXT_ASSET_H
-#include "subtitle_asset.h"
+#include "text_asset.h"
#include "subtitle_standard.h"
#include <boost/filesystem.hpp>
@@ -52,16 +52,16 @@ namespace dcp {
class InteropLoadFontNode;
-/** @class InteropSubtitleAsset
+/** @class InteropTextAsset
* @brief A set of subtitles to be read and/or written in the Inter-Op format
*
* Inter-Op subtitles are sometimes known as CineCanvas.
*/
-class InteropSubtitleAsset : public SubtitleAsset
+class InteropTextAsset : public TextAsset
{
public:
- InteropSubtitleAsset ();
- explicit InteropSubtitleAsset (boost::filesystem::path file);
+ InteropTextAsset();
+ explicit InteropTextAsset(boost::filesystem::path file);
bool equals (
std::shared_ptr<const Asset>,
diff --git a/src/j2k_picture_asset.cc b/src/j2k_picture_asset.cc
new file mode 100644
index 00000000..98792253
--- /dev/null
+++ b/src/j2k_picture_asset.cc
@@ -0,0 +1,229 @@
+/*
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/picture_asset.cc
+ * @brief J2KPictureAsset class
+ */
+
+
+#include "compose.hpp"
+#include "dcp_assert.h"
+#include "equality_options.h"
+#include "exceptions.h"
+#include "j2k_transcode.h"
+#include "openjpeg_image.h"
+#include "j2k_picture_asset.h"
+#include "j2k_picture_asset_writer.h"
+#include "util.h"
+#include <asdcp/AS_DCP.h>
+#include <asdcp/KM_fileio.h>
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <list>
+#include <stdexcept>
+
+
+using std::string;
+using std::list;
+using std::vector;
+using std::max;
+using std::pair;
+using std::make_pair;
+using std::shared_ptr;
+using namespace dcp;
+
+
+J2KPictureAsset::J2KPictureAsset(boost::filesystem::path file)
+ : PictureAsset(file)
+{
+
+}
+
+
+J2KPictureAsset::J2KPictureAsset(Fraction edit_rate, Standard standard)
+ : PictureAsset(edit_rate, standard)
+{
+
+}
+
+
+void
+J2KPictureAsset::read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const & desc)
+{
+ _size.width = desc.StoredWidth;
+ _size.height = desc.StoredHeight;
+ _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
+ _intrinsic_duration = desc.ContainerDuration;
+ _frame_rate = Fraction (desc.SampleRate.Numerator, desc.SampleRate.Denominator);
+ _screen_aspect_ratio = Fraction (desc.AspectRatio.Numerator, desc.AspectRatio.Denominator);
+}
+
+
+bool
+J2KPictureAsset::descriptor_equals (
+ ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, NoteHandler note
+ ) const
+{
+ if (
+ a.EditRate != b.EditRate ||
+ a.SampleRate != b.SampleRate ||
+ a.StoredWidth != b.StoredWidth ||
+ a.StoredHeight != b.StoredHeight ||
+ a.AspectRatio != b.AspectRatio ||
+ a.Rsize != b.Rsize ||
+ a.Xsize != b.Xsize ||
+ a.Ysize != b.Ysize ||
+ a.XOsize != b.XOsize ||
+ a.YOsize != b.YOsize ||
+ a.XTsize != b.XTsize ||
+ a.YTsize != b.YTsize ||
+ a.XTOsize != b.XTOsize ||
+ a.YTOsize != b.YTOsize ||
+ a.Csize != b.Csize
+// a.CodingStyleDefault != b.CodingStyleDefault ||
+// a.QuantizationDefault != b.QuantizationDefault
+ ) {
+
+ note (NoteType::ERROR, "video MXF picture descriptors differ");
+ return false;
+ }
+
+ if (a.ContainerDuration != b.ContainerDuration) {
+ note (NoteType::ERROR, "video container durations differ");
+ }
+
+// for (unsigned int j = 0; j < ASDCP::JP2K::MaxComponents; ++j) {
+// if (a.ImageComponents[j] != b.ImageComponents[j]) {
+// notes.pack_start ("video MXF picture descriptors differ");
+// }
+// }
+
+ return true;
+}
+
+
+bool
+J2KPictureAsset::frame_buffer_equals (
+ int frame, EqualityOptions const& opt, NoteHandler note,
+ uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
+ ) const
+{
+ if (size_A == size_B && memcmp (data_A, data_B, size_A) == 0) {
+ note (NoteType::NOTE, "J2K identical");
+ /* Easy result; the J2K data is identical */
+ return true;
+ }
+
+ /* Decompress the images to bitmaps */
+ auto image_A = decompress_j2k (const_cast<uint8_t*>(data_A), size_A, 0);
+ auto image_B = decompress_j2k (const_cast<uint8_t*>(data_B), size_B, 0);
+
+ /* Compare them */
+
+ vector<int> abs_diffs (image_A->size().width * image_A->size().height * 3);
+ int d = 0;
+ int max_diff = 0;
+
+ for (int c = 0; c < 3; ++c) {
+
+ if (image_A->size() != image_B->size()) {
+ note (NoteType::ERROR, String::compose ("image sizes for frame %1 differ", frame));
+ return false;
+ }
+
+ int const pixels = image_A->size().width * image_A->size().height;
+ for (int j = 0; j < pixels; ++j) {
+ int const t = abs (image_A->data(c)[j] - image_B->data(c)[j]);
+ abs_diffs[d++] = t;
+ max_diff = max (max_diff, t);
+ }
+ }
+
+ uint64_t total = 0;
+ for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
+ total += *j;
+ }
+
+ double const mean = double (total) / abs_diffs.size ();
+
+ uint64_t total_squared_deviation = 0;
+ for (auto j: abs_diffs) {
+ total_squared_deviation += pow (j - mean, 2);
+ }
+
+ auto const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
+
+ note (NoteType::NOTE, String::compose("mean difference %1 deviation %2", mean, std_dev));
+
+ if (mean > opt.max_mean_pixel_error) {
+ note (
+ NoteType::ERROR,
+ String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
+ );
+
+ return false;
+ }
+
+ if (std_dev > opt.max_std_dev_pixel_error) {
+ note (
+ NoteType::ERROR,
+ String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
+ );
+
+ return false;
+ }
+
+ return true;
+}
+
+
+string
+J2KPictureAsset::static_pkl_type (Standard standard)
+{
+ switch (standard) {
+ case Standard::INTEROP:
+ return "application/x-smpte-mxf;asdcpKind=Picture";
+ case Standard::SMPTE:
+ return "application/mxf";
+ default:
+ DCP_ASSERT (false);
+ }
+}
+
+
+string
+J2KPictureAsset::pkl_type (Standard standard) const
+{
+ return static_pkl_type (standard);
+}
diff --git a/src/j2k_picture_asset.h b/src/j2k_picture_asset.h
new file mode 100644
index 00000000..972de43e
--- /dev/null
+++ b/src/j2k_picture_asset.h
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/j2k_picture_asset.h
+ * @brief J2KPictureAsset class
+ */
+
+
+#ifndef LIBDCP_J2K_PICTURE_ASSET_H
+#define LIBDCP_J2K_PICTURE_ASSET_H
+
+
+#include "behaviour.h"
+#include "mxf.h"
+#include "metadata.h"
+#include "picture_asset.h"
+#include "util.h"
+
+
+namespace ASDCP {
+ namespace JP2K {
+ struct PictureDescriptor;
+ }
+}
+
+
+namespace dcp {
+
+
+class MonoJ2KPictureFrame;
+class StereoJ2KPictureFrame;
+class J2KPictureAssetWriter;
+
+
+/** @class J2KPictureAsset
+ * @brief An asset made up of JPEG2000 data
+ */
+class J2KPictureAsset : public PictureAsset
+{
+public:
+ /** Load a J2KPictureAsset from a file */
+ explicit J2KPictureAsset (boost::filesystem::path file);
+
+ /** Create a new J2KPictureAsset with a given edit rate and standard */
+ J2KPictureAsset (Fraction edit_rate, Standard standard);
+
+ virtual std::shared_ptr<J2KPictureAssetWriter> start_write (
+ boost::filesystem::path file,
+ Behaviour behaviour
+ ) = 0;
+
+ static std::string static_pkl_type (Standard standard);
+
+protected:
+ friend class MonoJ2KPictureAssetWriter;
+ friend class StereoJ2KPictureAssetWriter;
+
+ bool frame_buffer_equals (
+ int frame, EqualityOptions const& opt, NoteHandler note,
+ uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
+ ) const;
+
+ bool descriptor_equals (
+ ASDCP::JP2K::PictureDescriptor const & a,
+ ASDCP::JP2K::PictureDescriptor const & b,
+ NoteHandler note
+ ) const;
+
+ void read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const &);
+
+private:
+ std::string pkl_type (Standard standard) const override;
+};
+
+
+}
+
+
+#endif
diff --git a/src/picture_asset_writer.cc b/src/j2k_picture_asset_writer.cc
index c30be1bc..75be51ba 100644
--- a/src/picture_asset_writer.cc
+++ b/src/j2k_picture_asset_writer.cc
@@ -33,13 +33,13 @@
/** @file src/picture_asset_writer.cc
- * @brief PictureAssetWriter and FrameInfo classes
+ * @brief J2KPictureAssetWriter and FrameInfo classes
*/
-#include "picture_asset_writer.h"
+#include "j2k_picture_asset_writer.h"
#include "exceptions.h"
-#include "picture_asset.h"
+#include "j2k_picture_asset.h"
#include <asdcp/KM_fileio.h>
#include <asdcp/AS_DCP.h>
#include <inttypes.h>
@@ -51,7 +51,7 @@ using std::shared_ptr;
using namespace dcp;
-PictureAssetWriter::PictureAssetWriter (PictureAsset* asset, boost::filesystem::path file, bool overwrite)
+J2KPictureAssetWriter::J2KPictureAssetWriter (J2KPictureAsset* asset, boost::filesystem::path file, bool overwrite)
: AssetWriter (asset, file)
, _picture_asset (asset)
, _overwrite (overwrite)
@@ -60,8 +60,8 @@ PictureAssetWriter::PictureAssetWriter (PictureAsset* asset, boost::filesystem::
}
-FrameInfo
-PictureAssetWriter::write (Data const& data)
+J2KFrameInfo
+J2KPictureAssetWriter::write (Data const& data)
{
return write (data.data(), data.size());
}
diff --git a/src/picture_asset_writer.h b/src/j2k_picture_asset_writer.h
index 0caa8815..0077b3e0 100644
--- a/src/picture_asset_writer.h
+++ b/src/j2k_picture_asset_writer.h
@@ -32,16 +32,17 @@
*/
-/** @file src/picture_asset_writer.h
- * @brief PictureAssetWriter and FrameInfo classes.
+/** @file src/j2k_picture_asset_writer.h
+ * @brief J2KPictureAssetWriter and FrameInfo classes.
*/
-#ifndef LIBDCP_PICTURE_ASSET_WRITER_H
-#define LIBDCP_PICTURE_ASSET_WRITER_H
+#ifndef LIBDCP_J2K_PICTURE_ASSET_WRITER_H
+#define LIBDCP_J2K_PICTURE_ASSET_WRITER_H
#include "asset_writer.h"
+#include "frame_info.h"
#include "metadata.h"
#include <boost/utility.hpp>
#include <memory>
@@ -53,46 +54,27 @@ namespace dcp {
class Data;
-class PictureAsset;
+class J2KPictureAsset;
-/** @class FrameInfo
- * @brief Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame)
- */
-struct FrameInfo
-{
- FrameInfo () {}
-
- FrameInfo (uint64_t o, uint64_t s, std::string h)
- : offset (o)
- , size (s)
- , hash (h)
- {}
-
- uint64_t offset = 0;
- uint64_t size = 0;
- std::string hash;
-};
-
-
-/** @class PictureAssetWriter
+/** @class J2KPictureAssetWriter
* @brief Parent class for classes which write picture assets.
*/
-class PictureAssetWriter : public AssetWriter
+class J2KPictureAssetWriter : public AssetWriter
{
public:
- virtual FrameInfo write (uint8_t const *, int) = 0;
- virtual void fake_write (int) = 0;
+ virtual J2KFrameInfo write(uint8_t const *, int) = 0;
+ virtual void fake_write(J2KFrameInfo const& info) = 0;
- FrameInfo write (Data const& data);
+ J2KFrameInfo write(Data const& data);
protected:
template <class P, class Q>
- friend void start (PictureAssetWriter *, std::shared_ptr<P>, Q *, uint8_t const *, int);
+ friend void start (J2KPictureAssetWriter *, std::shared_ptr<P>, Q *, uint8_t const *, int);
- PictureAssetWriter (PictureAsset *, boost::filesystem::path, bool);
+ J2KPictureAssetWriter (J2KPictureAsset *, boost::filesystem::path, bool);
- PictureAsset* _picture_asset = nullptr;
+ J2KPictureAsset* _picture_asset = nullptr;
bool _overwrite = false;
};
diff --git a/src/picture_asset_writer_common.cc b/src/j2k_picture_asset_writer_common.cc
index 82866aac..a86da194 100644
--- a/src/picture_asset_writer_common.cc
+++ b/src/j2k_picture_asset_writer_common.cc
@@ -32,8 +32,8 @@
*/
-/** @file src/picture_asset_writer_common.cc
- * @brief Common parts of PictureAssetWriter
+/** @file src/j2k_picture_asset_writer_common.cc
+ * @brief Common parts of J2KPictureAssetWriter
*/
@@ -46,9 +46,9 @@ using std::shared_ptr;
namespace dcp {
-struct ASDCPStateBase
+struct ASDCPJ2KStateBase
{
- ASDCPStateBase ()
+ ASDCPJ2KStateBase()
: frame_buffer (4 * Kumu::Megabyte)
{}
@@ -63,7 +63,7 @@ struct ASDCPStateBase
template <class P, class Q>
-void dcp::start (PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t const * data, int size)
+void dcp::start (J2KPictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t const * data, int size)
{
asset->set_file (writer->_file);
diff --git a/src/language_tag.h b/src/language_tag.h
index 6f46c16b..3232dda9 100644
--- a/src/language_tag.h
+++ b/src/language_tag.h
@@ -32,7 +32,7 @@
*/
-/** @file src/language_tag.cc
+/** @file src/language_tag.h
* @brief LanguageTag class
*/
diff --git a/src/locale_convert.h b/src/locale_convert.h
index 37510a96..1323e704 100644
--- a/src/locale_convert.h
+++ b/src/locale_convert.h
@@ -32,7 +32,7 @@
*/
-/** @file src/locale_convert.cc
+/** @file src/locale_convert.h
* @brief Methods to convert to/from string using the current locale
*/
diff --git a/src/mono_picture_asset.cc b/src/mono_j2k_picture_asset.cc
index a72fd7d4..f718525d 100644
--- a/src/mono_picture_asset.cc
+++ b/src/mono_j2k_picture_asset.cc
@@ -33,7 +33,7 @@
/** @file src/mono_picture_asset.cc
- * @brief MonoPictureAsset class
+ * @brief MonoJ2KPictureAsset class
*/
@@ -42,10 +42,10 @@
#include "equality_options.h"
#include "exceptions.h"
#include "filesystem.h"
-#include "mono_picture_asset.h"
-#include "mono_picture_asset_reader.h"
-#include "mono_picture_asset_writer.h"
-#include "mono_picture_frame.h"
+#include "mono_j2k_picture_asset.h"
+#include "mono_j2k_picture_asset_reader.h"
+#include "mono_j2k_picture_asset_writer.h"
+#include "mono_j2k_picture_frame.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_fileio.h>
@@ -63,10 +63,11 @@ using namespace boost::placeholders;
using namespace dcp;
-MonoPictureAsset::MonoPictureAsset (boost::filesystem::path file)
- : PictureAsset (file)
+MonoJ2KPictureAsset::MonoJ2KPictureAsset (boost::filesystem::path file)
+ : J2KPictureAsset (file)
{
- ASDCP::JP2K::MXFReader reader;
+ Kumu::FileReaderFactory factory;
+ ASDCP::JP2K::MXFReader reader(factory);
auto r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", file.string(), r));
@@ -88,8 +89,8 @@ MonoPictureAsset::MonoPictureAsset (boost::filesystem::path file)
}
-MonoPictureAsset::MonoPictureAsset (Fraction edit_rate, Standard standard)
- : PictureAsset (edit_rate, standard)
+MonoJ2KPictureAsset::MonoJ2KPictureAsset (Fraction edit_rate, Standard standard)
+ : J2KPictureAsset (edit_rate, standard)
{
}
@@ -103,20 +104,21 @@ storing_note_handler (list<pair<NoteType, string>>& notes, NoteType t, string s)
bool
-MonoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, NoteHandler note) const
+MonoJ2KPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, NoteHandler note) const
{
- if (!dynamic_pointer_cast<const MonoPictureAsset>(other)) {
+ if (!dynamic_pointer_cast<const MonoJ2KPictureAsset>(other)) {
return false;
}
- ASDCP::JP2K::MXFReader reader_A;
+ Kumu::FileReaderFactory factory;
+ ASDCP::JP2K::MXFReader reader_A(factory);
DCP_ASSERT (_file);
auto r = reader_A.OpenRead(dcp::filesystem::fix_long_path(*_file).string().c_str());
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", _file->string(), r));
}
- ASDCP::JP2K::MXFReader reader_B;
+ ASDCP::JP2K::MXFReader reader_B(factory);
DCP_ASSERT (other->file ());
r = reader_B.OpenRead(dcp::filesystem::fix_long_path(*other->file()).string().c_str());
if (ASDCP_FAILURE (r)) {
@@ -136,7 +138,7 @@ MonoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& o
return false;
}
- auto other_picture = dynamic_pointer_cast<const MonoPictureAsset> (other);
+ auto other_picture = dynamic_pointer_cast<const MonoJ2KPictureAsset> (other);
DCP_ASSERT (other_picture);
bool result = true;
@@ -184,23 +186,23 @@ MonoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& o
}
-shared_ptr<PictureAssetWriter>
-MonoPictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
+shared_ptr<J2KPictureAssetWriter>
+MonoJ2KPictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
{
- /* Can't use make_shared here as the MonoPictureAssetWriter constructor is private */
- return shared_ptr<MonoPictureAssetWriter>(new MonoPictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
+ /* Can't use make_shared here as the MonoJ2KPictureAssetWriter constructor is private */
+ return shared_ptr<MonoJ2KPictureAssetWriter>(new MonoJ2KPictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
}
-shared_ptr<MonoPictureAssetReader>
-MonoPictureAsset::start_read () const
+shared_ptr<MonoJ2KPictureAssetReader>
+MonoJ2KPictureAsset::start_read () const
{
- /* Can't use make_shared here as the MonoPictureAssetReader constructor is private */
- return shared_ptr<MonoPictureAssetReader>(new MonoPictureAssetReader(this, key(), standard()));
+ /* Can't use make_shared here as the MonoJ2KPictureAssetReader constructor is private */
+ return shared_ptr<MonoJ2KPictureAssetReader>(new MonoJ2KPictureAssetReader(this, key(), standard()));
}
string
-MonoPictureAsset::cpl_node_name () const
+MonoJ2KPictureAsset::cpl_node_name () const
{
return "MainPicture";
}
diff --git a/src/mono_picture_asset.h b/src/mono_j2k_picture_asset.h
index 9658dcf6..d716b8ff 100644
--- a/src/mono_picture_asset.h
+++ b/src/mono_j2k_picture_asset.h
@@ -32,50 +32,50 @@
*/
-/** @file src/mono_picture_asset.cc
- * @brief MonoPictureAsset class
+/** @file src/mono_j2k_picture_asset.h
+ * @brief MonoJ2KPictureAsset class
*/
-#ifndef LIBDCP_MONO_PICTURE_ASSET_H
-#define LIBDCP_MONO_PICTURE_ASSET_H
+#ifndef LIBDCP_MONO_J2K_PICTURE_ASSET_H
+#define LIBDCP_MONO_J2K_PICTURE_ASSET_H
-#include "picture_asset.h"
-#include "mono_picture_asset_reader.h"
+#include "j2k_picture_asset.h"
+#include "mono_j2k_picture_asset_reader.h"
namespace dcp {
-class MonoPictureAssetWriter;
+class MonoJ2KPictureAssetWriter;
-/** @class MonoPictureAsset
+/** @class MonoJ2KPictureAsset
* @brief A 2D (monoscopic) picture asset
*/
-class MonoPictureAsset : public PictureAsset
+class MonoJ2KPictureAsset : public J2KPictureAsset
{
public:
- /** Create a MonoPictureAsset by reading a file.
+ /** Create a MonoJ2KPictureAsset by reading a file.
* @param file Asset file to read.
*/
- explicit MonoPictureAsset (boost::filesystem::path file);
+ explicit MonoJ2KPictureAsset (boost::filesystem::path file);
- /** Create a MonoPictureAsset with a given edit rate.
+ /** Create a MonoJ2KPictureAsset with a given edit rate.
* @param edit_rate Edit rate (i.e. frame rate) in frames per second.
* @param standard DCP standard (INTEROP or SMPTE).
*/
- MonoPictureAsset(Fraction edit_rate, Standard standard);
+ MonoJ2KPictureAsset(Fraction edit_rate, Standard standard);
- /** Start a progressive write to a MonoPictureAsset.
+ /** Start a progressive write to a MonoJ2KPictureAsset.
* @path file File to write to.
* @path behaviour OVERWRITE_EXISTING to overwrite and potentially add to an existing file
* (after a write previously failed), MAKE_NEW to create a new file.
* If in doubt, use MAKE_NEW here.
*/
- std::shared_ptr<PictureAssetWriter> start_write(boost::filesystem::path file, Behaviour behaviour) override;
- std::shared_ptr<MonoPictureAssetReader> start_read () const;
+ std::shared_ptr<J2KPictureAssetWriter> start_write(boost::filesystem::path file, Behaviour behaviour) override;
+ std::shared_ptr<MonoJ2KPictureAssetReader> start_read () const;
bool equals (
std::shared_ptr<const Asset> other,
diff --git a/src/mono_picture_asset_reader.h b/src/mono_j2k_picture_asset_reader.h
index 5bead791..8376e939 100644
--- a/src/mono_picture_asset_reader.h
+++ b/src/mono_j2k_picture_asset_reader.h
@@ -32,23 +32,23 @@
*/
-/** @file src/mono_picture_asset_reader.h
- * @brief MonoPictureAssetReader typedef
+/** @file src/mono_j2k_picture_asset_reader.h
+ * @brief MonoJ2KPictureAssetReader typedef
*/
-#ifndef LIBDCP_MONO_PICTURE_ASSET_READER_H
-#define LIBDCP_MONO_PICTURE_ASSET_READER_H
+#ifndef LIBDCP_MONO_J2K_PICTURE_ASSET_READER_H
+#define LIBDCP_MONO_J2K_PICTURE_ASSET_READER_H
#include "asset_reader.h"
-#include "mono_picture_frame.h"
+#include "mono_j2k_picture_frame.h"
namespace dcp {
-typedef AssetReader<ASDCP::JP2K::MXFReader, MonoPictureFrame> MonoPictureAssetReader;
+typedef AssetReader<ASDCP::JP2K::MXFReader, MonoJ2KPictureFrame> MonoJ2KPictureAssetReader;
}
diff --git a/src/mono_picture_asset_writer.cc b/src/mono_j2k_picture_asset_writer.cc
index 7fd58114..1188701e 100644
--- a/src/mono_picture_asset_writer.cc
+++ b/src/mono_j2k_picture_asset_writer.cc
@@ -33,15 +33,15 @@
/** @file src/mono_picture_asset_writer.cc
- * @brief MonoPictureAssetWriter class
+ * @brief MonoJ2KPictureAssetWriter class
*/
#include "crypto_context.h"
#include "dcp_assert.h"
#include "exceptions.h"
-#include "mono_picture_asset_writer.h"
-#include "picture_asset.h"
+#include "mono_j2k_picture_asset_writer.h"
+#include "j2k_picture_asset.h"
#include "warnings.h"
LIBDCP_DISABLE_WARNINGS
#include <asdcp/AS_DCP.h>
@@ -49,7 +49,7 @@ LIBDCP_DISABLE_WARNINGS
LIBDCP_ENABLE_WARNINGS
-#include "picture_asset_writer_common.cc"
+#include "j2k_picture_asset_writer_common.cc"
using std::string;
@@ -57,7 +57,7 @@ using std::shared_ptr;
using namespace dcp;
-struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
+struct MonoJ2KPictureAssetWriter::ASDCPState : public ASDCPJ2KStateBase
{
ASDCP::JP2K::MXFWriter mxf_writer;
};
@@ -66,15 +66,15 @@ struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
/** @param a Asset to write to. `a' must not be deleted while
* this writer class still exists, or bad things will happen.
*/
-MonoPictureAssetWriter::MonoPictureAssetWriter (PictureAsset* asset, boost::filesystem::path file, bool overwrite)
- : PictureAssetWriter (asset, file, overwrite)
- , _state (new MonoPictureAssetWriter::ASDCPState)
+MonoJ2KPictureAssetWriter::MonoJ2KPictureAssetWriter (J2KPictureAsset* asset, boost::filesystem::path file, bool overwrite)
+ : J2KPictureAssetWriter (asset, file, overwrite)
+ , _state (new MonoJ2KPictureAssetWriter::ASDCPState)
{
}
-MonoPictureAssetWriter::~MonoPictureAssetWriter()
+MonoJ2KPictureAssetWriter::~MonoJ2KPictureAssetWriter()
{
try {
/* Last-resort finalization to close the file, at least */
@@ -86,15 +86,15 @@ MonoPictureAssetWriter::~MonoPictureAssetWriter()
void
-MonoPictureAssetWriter::start (uint8_t const * data, int size)
+MonoJ2KPictureAssetWriter::start (uint8_t const * data, int size)
{
dcp::start (this, _state, _picture_asset, data, size);
_picture_asset->set_frame_rate (_picture_asset->edit_rate());
}
-FrameInfo
-MonoPictureAssetWriter::write (uint8_t const * data, int size)
+J2KFrameInfo
+MonoJ2KPictureAssetWriter::write (uint8_t const * data, int size)
{
DCP_ASSERT (!_finalized);
@@ -117,17 +117,17 @@ MonoPictureAssetWriter::write (uint8_t const * data, int size)
}
++_frames_written;
- return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
+ return J2KFrameInfo(before_offset, _state->mxf_writer.Tell() - before_offset, hash);
}
void
-MonoPictureAssetWriter::fake_write (int size)
+MonoJ2KPictureAssetWriter::fake_write(J2KFrameInfo const& info)
{
DCP_ASSERT (_started);
DCP_ASSERT (!_finalized);
- auto r = _state->mxf_writer.FakeWriteFrame (size);
+ auto r = _state->mxf_writer.FakeWriteFrame(info.size);
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("error in writing video MXF", _file.string(), r));
}
@@ -137,7 +137,7 @@ MonoPictureAssetWriter::fake_write (int size)
bool
-MonoPictureAssetWriter::finalize ()
+MonoJ2KPictureAssetWriter::finalize ()
{
if (_started) {
auto r = _state->mxf_writer.Finalize();
@@ -147,5 +147,5 @@ MonoPictureAssetWriter::finalize ()
}
_picture_asset->_intrinsic_duration = _frames_written;
- return PictureAssetWriter::finalize ();
+ return J2KPictureAssetWriter::finalize ();
}
diff --git a/src/mono_picture_asset_writer.h b/src/mono_j2k_picture_asset_writer.h
index 551d8c80..b3f57191 100644
--- a/src/mono_picture_asset_writer.h
+++ b/src/mono_j2k_picture_asset_writer.h
@@ -32,16 +32,16 @@
*/
-/** @file src/mono_picture_asset_writer.h
- * @brief MonoPictureAssetWriter class
+/** @file src/mono_j2k_picture_asset_writer.h
+ * @brief MonoJ2KPictureAssetWriter class
*/
-#ifndef LIBDCP_MONO_PICTURE_ASSET_WRITER_H
-#define LIBDCP_MONO_PICTURE_ASSET_WRITER_H
+#ifndef LIBDCP_MONO_J2K_PICTURE_ASSET_WRITER_H
+#define LIBDCP_MONO_J2K_PICTURE_ASSET_WRITER_H
-#include "picture_asset_writer.h"
+#include "j2k_picture_asset_writer.h"
#include <memory>
#include <boost/utility.hpp>
#include <stdint.h>
@@ -51,29 +51,29 @@
namespace dcp {
-/** @class MonoPictureAssetWriter
- * @brief A helper class for writing to MonoPictureAssets
+/** @class MonoJ2KPictureAssetWriter
+ * @brief A helper class for writing to MonoJ2KPictureAssets
*
- * Objects of this class can only be created with MonoPictureAsset::start_write().
+ * Objects of this class can only be created with MonoJ2KPictureAsset::start_write().
*
- * Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
+ * Frames can be written to the MonoJ2KPictureAsset by calling write() with a JPEG2000 image
* (a verbatim .j2c file). finalize() should be called after the last frame has been written,
* but if it is not, it will be called by the destructor (though in that case any error
* during finalization will be ignored).
*/
-class MonoPictureAssetWriter : public PictureAssetWriter
+class MonoJ2KPictureAssetWriter : public J2KPictureAssetWriter
{
public:
- ~MonoPictureAssetWriter();
+ ~MonoJ2KPictureAssetWriter();
- FrameInfo write (uint8_t const *, int) override;
- void fake_write (int size) override;
+ J2KFrameInfo write(uint8_t const *, int) override;
+ void fake_write(J2KFrameInfo const& info) override;
bool finalize () override;
private:
- friend class MonoPictureAsset;
+ friend class MonoJ2KPictureAsset;
- MonoPictureAssetWriter (PictureAsset* a, boost::filesystem::path file, bool);
+ MonoJ2KPictureAssetWriter (J2KPictureAsset* a, boost::filesystem::path file, bool);
void start (uint8_t const *, int);
diff --git a/src/mono_picture_frame.cc b/src/mono_j2k_picture_frame.cc
index 2abd57e4..69ba9a59 100644
--- a/src/mono_picture_frame.cc
+++ b/src/mono_j2k_picture_frame.cc
@@ -33,7 +33,7 @@
/** @file src/mono_picture_frame.cc
- * @brief MonoPictureFrame class
+ * @brief MonoJ2KPictureFrame class
*/
@@ -44,7 +44,7 @@
#include "file.h"
#include "filesystem.h"
#include "j2k_transcode.h"
-#include "mono_picture_frame.h"
+#include "mono_j2k_picture_frame.h"
#include "rgb_xyz.h"
#include "util.h"
#include <asdcp/KM_fileio.h>
@@ -58,7 +58,7 @@ using boost::optional;
using namespace dcp;
-MonoPictureFrame::MonoPictureFrame (boost::filesystem::path path)
+MonoJ2KPictureFrame::MonoJ2KPictureFrame (boost::filesystem::path path)
{
auto const size = filesystem::file_size(path);
_buffer.reset(new ASDCP::JP2K::FrameBuffer(size));
@@ -81,7 +81,7 @@ MonoPictureFrame::MonoPictureFrame (boost::filesystem::path path)
* @param c Context for decryption, or 0.
* @param check_hmac true to check the HMAC and give an error if it is not as expected.
*/
-MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, shared_ptr<DecryptionContext> c, bool check_hmac)
+MonoJ2KPictureFrame::MonoJ2KPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, shared_ptr<DecryptionContext> c, bool check_hmac)
{
/* XXX: unfortunate guesswork on this buffer size */
_buffer = make_shared<ASDCP::JP2K::FrameBuffer>(4 * Kumu::Megabyte);
@@ -94,7 +94,7 @@ MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, share
}
-MonoPictureFrame::MonoPictureFrame (uint8_t const * data, int size)
+MonoJ2KPictureFrame::MonoJ2KPictureFrame (uint8_t const * data, int size)
{
_buffer = make_shared<ASDCP::JP2K::FrameBuffer>(size);
_buffer->Size (size);
@@ -103,28 +103,28 @@ MonoPictureFrame::MonoPictureFrame (uint8_t const * data, int size)
uint8_t const *
-MonoPictureFrame::data () const
+MonoJ2KPictureFrame::data () const
{
return _buffer->RoData ();
}
uint8_t *
-MonoPictureFrame::data ()
+MonoJ2KPictureFrame::data ()
{
return _buffer->Data ();
}
int
-MonoPictureFrame::size () const
+MonoJ2KPictureFrame::size () const
{
return _buffer->Size ();
}
shared_ptr<OpenJPEGImage>
-MonoPictureFrame::xyz_image (int reduce) const
+MonoJ2KPictureFrame::xyz_image (int reduce) const
{
return decompress_j2k (const_cast<uint8_t*>(_buffer->RoData()), _buffer->Size(), reduce);
}
diff --git a/src/mono_picture_frame.h b/src/mono_j2k_picture_frame.h
index 43575864..f08e7343 100644
--- a/src/mono_picture_frame.h
+++ b/src/mono_j2k_picture_frame.h
@@ -32,13 +32,13 @@
*/
-/** @file src/mono_picture_frame.h
- * @brief MonoPictureFrame class
+/** @file src/mono_j2k_picture_frame.h
+ * @brief MonoJ2KPictureFrame class
*/
-#ifndef LIBDCP_MONO_PICTURE_FRAME_H
-#define LIBDCP_MONO_PICTURE_FRAME_H
+#ifndef LIBDCP_MONO_J2K_PICTURE_FRAME_H
+#define LIBDCP_MONO_J2K_PICTURE_FRAME_H
#include "asset_reader.h"
@@ -64,20 +64,20 @@ namespace dcp {
class OpenJPEGImage;
-/** @class MonoPictureFrame
+/** @class MonoJ2KPictureFrame
* @brief A single frame of a 2D (monoscopic) picture asset
*/
-class MonoPictureFrame : public Data
+class MonoJ2KPictureFrame : public Data
{
public:
/** Make a picture frame from a JPEG2000 file.
* @param path Path to JPEG2000 file.
*/
- explicit MonoPictureFrame (boost::filesystem::path path);
- MonoPictureFrame (uint8_t const * data, int size);
+ explicit MonoJ2KPictureFrame (boost::filesystem::path path);
+ MonoJ2KPictureFrame (uint8_t const * data, int size);
- MonoPictureFrame (MonoPictureFrame const&) = delete;
- MonoPictureFrame& operator= (MonoPictureFrame const&) = delete;
+ MonoJ2KPictureFrame (MonoJ2KPictureFrame const&) = delete;
+ MonoJ2KPictureFrame& operator= (MonoJ2KPictureFrame const&) = delete;
/** @param reduce a factor by which to reduce the resolution
* of the image, expressed as a power of two (pass 0 for no
@@ -95,12 +95,12 @@ public:
int size () const override;
private:
- /* XXX: this is a bit of a shame, but I tried friend MonoPictureAssetReader and it's
+ /* XXX: this is a bit of a shame, but I tried friend MonoJ2KPictureAssetReader and it's
rejected by some (seemingly older) GCCs.
*/
- friend class AssetReader<ASDCP::JP2K::MXFReader, MonoPictureFrame>;
+ friend class AssetReader<ASDCP::JP2K::MXFReader, MonoJ2KPictureFrame>;
- MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
+ MonoJ2KPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
std::shared_ptr<ASDCP::JP2K::FrameBuffer> _buffer;
};
diff --git a/src/mono_mpeg2_picture_asset.cc b/src/mono_mpeg2_picture_asset.cc
new file mode 100644
index 00000000..380da0fe
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset.cc
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "filesystem.h"
+#include "mono_mpeg2_picture_asset.h"
+#include "mono_mpeg2_picture_asset_reader.h"
+#include "mono_mpeg2_picture_asset_writer.h"
+#include <asdcp/AS_DCP.h>
+
+
+using std::shared_ptr;
+using namespace dcp;
+
+
+MonoMPEG2PictureAsset::MonoMPEG2PictureAsset(boost::filesystem::path file)
+ : MPEG2PictureAsset(file)
+{
+ Kumu::FileReaderFactory factory;
+ ASDCP::MPEG2::MXFReader reader(factory);
+ auto const result = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
+ if (ASDCP_FAILURE(result)) {
+ boost::throw_exception(MXFFileError("could not open MXF file for reading", file.string(), result));
+ }
+
+ ASDCP::MPEG2::VideoDescriptor desc;
+ if (ASDCP_FAILURE(reader.FillVideoDescriptor(desc))) {
+ boost::throw_exception(ReadError("could not read video MXF information"));
+ }
+
+ read_video_descriptor(desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE(reader.FillWriterInfo(info))) {
+ boost::throw_exception(ReadError("could not read video MXF information"));
+ }
+
+ _id = read_writer_info(info);
+}
+
+
+shared_ptr<MonoMPEG2PictureAssetReader>
+MonoMPEG2PictureAsset::start_read () const
+{
+ /* Can't use make_shared here as the MonoMPEG2PictureAssetReader constructor is private */
+ return shared_ptr<MonoMPEG2PictureAssetReader>(new MonoMPEG2PictureAssetReader(this, key(), standard()));
+
+}
+
+
+shared_ptr<MPEG2PictureAssetWriter>
+MonoMPEG2PictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
+{
+ /* Can't use make_shared here as the MonoJ2KPictureAssetWriter constructor is private */
+ return shared_ptr<MonoMPEG2PictureAssetWriter>(new MonoMPEG2PictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
+}
diff --git a/src/reel_smpte_subtitle_asset.cc b/src/mono_mpeg2_picture_asset.h
index 64440547..8ef3653e 100644
--- a/src/reel_smpte_subtitle_asset.cc
+++ b/src/mono_mpeg2_picture_asset.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
@@ -32,35 +32,42 @@
*/
-/** @file src/reel_interop_subtitle_asset.cc
- * @brief ReelInteropSubtitleAsset class
+#ifndef LIBDCP_MONO_MPEG2_PICTURE_ASSET_H
+#define LIBDCP_MONO_MPEG2_PICTURE_ASSET_H
+
+
+/** @file src/mono_mpeg2_picture_asset.h
+ * @brief MonoMPEG2PictureAsset class
*/
-#include "reel_smpte_subtitle_asset.h"
-#include "smpte_subtitle_asset.h"
-#include "warnings.h"
-LIBDCP_DISABLE_WARNINGS
-#include <libxml++/libxml++.h>
-LIBDCP_ENABLE_WARNINGS
+#include "behaviour.h"
+#include "mpeg2_picture_asset.h"
+#include "mono_mpeg2_picture_asset_reader.h"
+
+namespace dcp {
-using std::shared_ptr;
-using std::string;
-using boost::optional;
-using namespace dcp;
+class MonoMPEG2PictureAssetWriter;
-ReelSMPTESubtitleAsset::ReelSMPTESubtitleAsset (shared_ptr<SMPTESubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
- : ReelSubtitleAsset (asset, edit_rate, intrinsic_duration, entry_point)
+
+class MonoMPEG2PictureAsset : public MPEG2PictureAsset
{
+public:
+ MonoMPEG2PictureAsset(Fraction edit_rate)
+ : MPEG2PictureAsset(edit_rate)
+ {}
+
+ explicit MonoMPEG2PictureAsset(boost::filesystem::path file);
+
+ std::shared_ptr<MPEG2PictureAssetWriter> start_write(boost::filesystem::path file, Behaviour behaviour) override;
+ std::shared_ptr<MonoMPEG2PictureAssetReader> start_read() const;
+};
-}
-ReelSMPTESubtitleAsset::ReelSMPTESubtitleAsset (shared_ptr<const cxml::Node> node)
- : ReelSubtitleAsset (node)
-{
- node->done ();
}
+
+#endif
diff --git a/src/mono_mpeg2_picture_asset_reader.h b/src/mono_mpeg2_picture_asset_reader.h
new file mode 100644
index 00000000..75155f40
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset_reader.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/mono_mpeg2_picture_asset_reader.h
+ * @brief MonoJ2KPictureAssetReader typedef
+ */
+
+
+#ifndef LIBDCP_MONO_MPEG2_PICTURE_ASSET_READER_H
+#define LIBDCP_MONO_MPEG2_PICTURE_ASSET_READER_H
+
+
+#include "asset_reader.h"
+#include "mono_mpeg2_picture_frame.h"
+
+
+namespace dcp {
+
+
+typedef AssetReader<ASDCP::MPEG2::MXFReader, MonoMPEG2PictureFrame> MonoMPEG2PictureAssetReader;
+
+
+}
+
+
+#endif
+
diff --git a/src/mono_mpeg2_picture_asset_writer.cc b/src/mono_mpeg2_picture_asset_writer.cc
new file mode 100644
index 00000000..f8101c54
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset_writer.cc
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "mono_mpeg2_picture_asset_writer.h"
+#include "mpeg2_picture_asset.h"
+#include "mpeg2_picture_asset_writer.h"
+
+
+using std::string;
+using namespace dcp;
+
+
+struct MonoMPEG2PictureAssetWriter::ASDCPState : public ASDCPMPEG2StateBase
+{
+ ASDCP::MPEG2::MXFWriter mxf_writer;
+};
+
+
+
+
+MonoMPEG2PictureAssetWriter::MonoMPEG2PictureAssetWriter(MPEG2PictureAsset* asset, boost::filesystem::path file, bool overwrite)
+ : MPEG2PictureAssetWriter(asset, file, overwrite)
+ , _state(new MonoMPEG2PictureAssetWriter::ASDCPState)
+{
+ asset->set_file(file);
+}
+
+
+MonoMPEG2PictureAssetWriter::~MonoMPEG2PictureAssetWriter()
+{
+ try {
+ /* Last-resort finalization to close the file, at least */
+ if (!_finalized) {
+ _state->mxf_writer.Finalize();
+ }
+ } catch (...) {}
+}
+
+
+void
+MonoMPEG2PictureAssetWriter::start(uint8_t const * data, int size)
+{
+ dcp::start(this, _state, _picture_asset, data, size);
+ _picture_asset->set_frame_rate (_picture_asset->edit_rate());
+}
+
+
+MPEG2FrameInfo
+MonoMPEG2PictureAssetWriter::write(uint8_t const * data, int size)
+{
+ DCP_ASSERT(!_finalized);
+
+ if (!_started) {
+ start(data, size);
+ }
+
+ ASDCP::MPEG2::FrameBuffer buffer;
+ buffer.SetData(const_cast<uint8_t*>(data), size);
+ buffer.Size(size);
+ buffer.PlaintextOffset(0);
+
+ auto const before_offset = _state->mxf_writer.Tell();
+
+ string hash;
+ auto const r = _state->mxf_writer.WriteFrame(buffer, _crypto_context->context(), _crypto_context->hmac(), &hash);
+ if (ASDCP_FAILURE(r)) {
+ boost::throw_exception(MXFFileError("error in writing video MXF", _file.string(), r));
+ }
+
+ ++_frames_written;
+ return MPEG2FrameInfo(
+ before_offset,
+ _state->mxf_writer.Tell() - before_offset,
+ hash,
+ buffer.FrameType(),
+ buffer.GOPStart(),
+ buffer.ClosedGOP(),
+ buffer.TemporalOffset()
+ );
+}
+
+
+void
+MonoMPEG2PictureAssetWriter::fake_write(MPEG2FrameInfo const& info)
+{
+ DCP_ASSERT(_started);
+ DCP_ASSERT(!_finalized);
+
+ DCP_ASSERT(false);
+
+ auto r = _state->mxf_writer.FakeWriteFrame(info.size, info.type, info.gop_start, info.closed_gop, info.temporal_offset);
+ if (ASDCP_FAILURE(r)) {
+ boost::throw_exception(MXFFileError("error in writing video MXF", _file.string(), r));
+ }
+
+ ++_frames_written;
+}
+
+
+bool
+MonoMPEG2PictureAssetWriter::finalize()
+{
+ if (_started) {
+ auto r = _state->mxf_writer.Finalize();
+ if (ASDCP_FAILURE(r)) {
+ boost::throw_exception(MXFFileError("error in finalizing video MXF", _file.string(), r));
+ }
+ }
+
+ _picture_asset->_intrinsic_duration = _frames_written;
+ return MPEG2PictureAssetWriter::finalize();
+}
+
diff --git a/src/mono_mpeg2_picture_asset_writer.h b/src/mono_mpeg2_picture_asset_writer.h
new file mode 100644
index 00000000..bf7a6cc9
--- /dev/null
+++ b/src/mono_mpeg2_picture_asset_writer.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "mpeg2_picture_asset_writer.h"
+
+
+#include "mpeg2_picture_asset_writer_common.cc"
+
+
+namespace dcp {
+
+
+class MonoMPEG2PictureAsset;
+
+
+class MonoMPEG2PictureAssetWriter : public MPEG2PictureAssetWriter
+{
+public:
+ ~MonoMPEG2PictureAssetWriter();
+
+ MPEG2FrameInfo write(uint8_t const *, int) override;
+ void fake_write(MPEG2FrameInfo const& info) override;
+ bool finalize() override;
+
+private:
+ friend class MonoMPEG2PictureAsset;
+
+ MonoMPEG2PictureAssetWriter(MPEG2PictureAsset* asset, boost::filesystem::path file, bool overwrite);
+
+ void start(uint8_t const *, int);
+
+ struct ASDCPState;
+ std::shared_ptr<ASDCPState> _state;
+};
+
+
+}
diff --git a/src/mono_mpeg2_picture_frame.cc b/src/mono_mpeg2_picture_frame.cc
new file mode 100644
index 00000000..3c79a94c
--- /dev/null
+++ b/src/mono_mpeg2_picture_frame.cc
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "compose.hpp"
+#include "mono_mpeg2_picture_frame.h"
+
+
+using std::make_shared;
+using std::shared_ptr;
+using namespace dcp;
+
+
+
+MonoMPEG2PictureFrame::MonoMPEG2PictureFrame(uint8_t const* data, int size)
+{
+ _buffer = make_shared<ASDCP::MPEG2::FrameBuffer>(size);
+ memcpy(_buffer->Data(), data, size);
+ _buffer->Size(size);
+}
+
+
+/** Make a picture frame from a 2D (monoscopic) asset.
+ * @param reader Reader for the asset's MXF file.
+ * @param n Frame within the asset, not taking EntryPoint into account.
+ * @param c Context for decryption, or 0.
+ * @param check_hmac true to check the HMAC and give an error if it is not as expected.
+ */
+MonoMPEG2PictureFrame::MonoMPEG2PictureFrame(ASDCP::MPEG2::MXFReader* reader, int n, shared_ptr<DecryptionContext> context, bool check_hmac)
+{
+ /* XXX: unfortunate guesswork on this buffer size */
+ _buffer = make_shared<ASDCP::MPEG2::FrameBuffer>(4 * Kumu::Megabyte);
+
+ auto const r = reader->ReadFrame(n, *_buffer, context->context(), check_hmac ? context->hmac() : nullptr);
+
+ if (ASDCP_FAILURE(r)) {
+ boost::throw_exception(ReadError(String::compose("could not read video frame %1 (%2)", n, static_cast<int>(r))));
+ }
+}
+
+
+uint8_t const *
+MonoMPEG2PictureFrame::data() const
+{
+ return _buffer->RoData();
+}
+
+
+uint8_t *
+MonoMPEG2PictureFrame::data()
+{
+ return _buffer->Data();
+}
+
+
+int
+MonoMPEG2PictureFrame::size() const
+{
+ return _buffer->Size();
+}
+
diff --git a/src/mono_mpeg2_picture_frame.h b/src/mono_mpeg2_picture_frame.h
new file mode 100644
index 00000000..6a7669f7
--- /dev/null
+++ b/src/mono_mpeg2_picture_frame.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MONO_MPEG2_PICTURE_FRAME_H
+#define LIBDCP_MONO_MPEG2_PICTURE_FRAME_H
+
+
+#include "asset_reader.h"
+#include "data.h"
+
+
+namespace dcp {
+
+
+class MonoMPEG2PictureFrame : public Data
+{
+public:
+ MonoMPEG2PictureFrame(uint8_t const * data, int size);
+
+ MonoMPEG2PictureFrame(MonoMPEG2PictureFrame const&) = delete;
+ MonoMPEG2PictureFrame& operator=(MonoMPEG2PictureFrame const&) = delete;
+
+ /* XXX: couldn't we just return the frame buffer */
+
+ /** @return Pointer to MPEG2 data */
+ uint8_t const * data() const override;
+
+ /** @return Pointer to MPEG2 data */
+ uint8_t* data () override;
+
+ /** @return Size of MPEG2 data in bytes */
+ int size() const override;
+
+private:
+ /* XXX: this is a bit of a shame, but I tried friend MonoMPEG2PictureAssetReader and it's
+ rejected by some (seemingly older) GCCs.
+ */
+ friend class AssetReader<ASDCP::MPEG2::MXFReader, MonoMPEG2PictureFrame>;
+
+ MonoMPEG2PictureFrame(ASDCP::MPEG2::MXFReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
+
+ /* XXX why is this a shared_ptr? */
+ std::shared_ptr<ASDCP::MPEG2::FrameBuffer> _buffer;
+};
+
+
+}
+
+
+#endif
diff --git a/src/mpeg2_picture_asset.cc b/src/mpeg2_picture_asset.cc
new file mode 100644
index 00000000..6cd0b428
--- /dev/null
+++ b/src/mpeg2_picture_asset.cc
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "mpeg2_picture_asset.h"
+
+
+using std::string;
+using namespace dcp;
+
+
+MPEG2PictureAsset::MPEG2PictureAsset(boost::filesystem::path file)
+ : PictureAsset(file)
+{
+
+}
+
+
+void
+MPEG2PictureAsset::read_video_descriptor(ASDCP::MPEG2::VideoDescriptor const& descriptor)
+{
+ _size.width = descriptor.StoredWidth;
+ _size.height = descriptor.StoredHeight;
+ _edit_rate = Fraction(descriptor.EditRate.Numerator, descriptor.EditRate.Denominator);
+ _intrinsic_duration = descriptor.ContainerDuration;
+ _frame_rate = Fraction(descriptor.SampleRate.Numerator, descriptor.SampleRate.Denominator);
+ _screen_aspect_ratio = Fraction(descriptor.AspectRatio.Numerator, descriptor.AspectRatio.Denominator);
+}
+
+
+string
+MPEG2PictureAsset::pkl_type (Standard standard) const
+{
+ DCP_ASSERT(standard == Standard::INTEROP);
+ return "application/x-smpte-mxf;asdcpKind=Picture";
+}
+
+
+string
+MPEG2PictureAsset::static_pkl_type(Standard standard)
+{
+ DCP_ASSERT(standard == Standard::INTEROP);
+ return "application/x-smpte-mxf;asdcpKind=Picture";
+}
diff --git a/src/mpeg2_picture_asset.h b/src/mpeg2_picture_asset.h
new file mode 100644
index 00000000..38b8e0a0
--- /dev/null
+++ b/src/mpeg2_picture_asset.h
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MPEG2_PICTURE_ASSET_H
+#define LIBDCP_MPEG2_PICTURE_ASSET_H
+
+
+/** @file src/mpeg2_picture_asset.h
+ * @brief MPEG2PictureAsset class
+ */
+
+
+#include "behaviour.h"
+#include "mpeg2_picture_asset_writer.h"
+#include "picture_asset.h"
+#include <boost/filesystem/path.hpp>
+
+
+namespace ASDCP {
+ namespace MPEG2 {
+ struct VideoDescriptor;
+ }
+}
+
+
+namespace dcp {
+
+
+class MPEG2PictureAsset : public PictureAsset
+{
+public:
+ MPEG2PictureAsset(Fraction edit_rate)
+ : PictureAsset(edit_rate, Standard::INTEROP)
+ {}
+
+ explicit MPEG2PictureAsset(boost::filesystem::path file);
+
+ virtual std::shared_ptr<MPEG2PictureAssetWriter> start_write(
+ boost::filesystem::path file,
+ Behaviour behaviour
+ ) = 0;
+
+ static std::string static_pkl_type(Standard standard);
+
+protected:
+ friend class MonoMPEG2PictureAssetWriter;
+
+ void read_video_descriptor(ASDCP::MPEG2::VideoDescriptor const& descriptor);
+
+private:
+ std::string pkl_type(Standard standard) const override;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/reel_interop_subtitle_asset.cc b/src/mpeg2_picture_asset_writer.cc
index 5f295d53..f5ead775 100644
--- a/src/reel_interop_subtitle_asset.cc
+++ b/src/mpeg2_picture_asset_writer.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
@@ -32,34 +32,17 @@
*/
-/** @file src/reel_interop_subtitle_asset.cc
- * @brief ReelInteropSubtitleAsset class
- */
+#include "mpeg2_picture_asset.h"
+#include "mpeg2_picture_asset_writer.h"
-#include "reel_interop_subtitle_asset.h"
-#include "warnings.h"
-LIBDCP_DISABLE_WARNINGS
-#include <libxml++/libxml++.h>
-LIBDCP_ENABLE_WARNINGS
-
-
-using std::shared_ptr;
-using std::string;
-using boost::optional;
using namespace dcp;
-ReelInteropSubtitleAsset::ReelInteropSubtitleAsset (std::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
- : ReelSubtitleAsset (asset, edit_rate, intrinsic_duration, entry_point)
-{
-
-}
-
-
-ReelInteropSubtitleAsset::ReelInteropSubtitleAsset (std::shared_ptr<const cxml::Node> node)
- : ReelSubtitleAsset (node)
+MPEG2PictureAssetWriter::MPEG2PictureAssetWriter(MPEG2PictureAsset* asset, boost::filesystem::path file, bool overwrite)
+ : AssetWriter(asset, file)
+ , _picture_asset(asset)
+ , _overwrite(overwrite)
{
- node->done ();
+ asset->set_file(file);
}
-
diff --git a/src/mpeg2_picture_asset_writer.h b/src/mpeg2_picture_asset_writer.h
new file mode 100644
index 00000000..a370ef9b
--- /dev/null
+++ b/src/mpeg2_picture_asset_writer.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_MPEG2_PICTURE_ASSET_WRITER_H
+#define LIBDCP_MPEG2_PICTURE_ASSET_WRITER_H
+
+
+#include "asset_writer.h"
+#include "frame_info.h"
+
+
+namespace dcp {
+
+
+class Data;
+class MPEG2PictureAsset;
+
+
+class MPEG2PictureAssetWriter : public AssetWriter
+{
+public:
+ virtual MPEG2FrameInfo write(uint8_t const* data, int size) = 0;
+ virtual void fake_write(MPEG2FrameInfo const& info) = 0;
+
+ MPEG2FrameInfo write(Data const& data);
+
+protected:
+ template <class P, class Q>
+ friend void start(MPEG2PictureAssetWriter *, std::shared_ptr<P>, Q *, uint8_t const *, int);
+
+ MPEG2PictureAssetWriter(MPEG2PictureAsset* asset, boost::filesystem::path file, bool overwrite);
+
+ MPEG2PictureAsset* _picture_asset = nullptr;
+ bool _overwrite = false;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/mpeg2_picture_asset_writer_common.cc b/src/mpeg2_picture_asset_writer_common.cc
new file mode 100644
index 00000000..d46057f7
--- /dev/null
+++ b/src/mpeg2_picture_asset_writer_common.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+/** @file src/mpeg2_picture_asset_writer_common.cc
+ * @brief Common parts of MPEG2PictureAssetWriter
+ */
+
+
+#include "filesystem.h"
+
+
+using std::shared_ptr;
+
+
+namespace dcp {
+
+
+class MPEG2PictureAssetWriter;
+
+
+struct ASDCPMPEG2StateBase
+{
+ ASDCP::MPEG2::Parser mpeg2_parser;
+ ASDCP::WriterInfo writer_info;
+ ASDCP::MPEG2::VideoDescriptor video_descriptor;
+};
+
+
+}
+
+
+template <class P, class Q>
+void dcp::start(MPEG2PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t const * data, int size)
+{
+ asset->set_file (writer->_file);
+
+ if (ASDCP_FAILURE(state->mpeg2_parser.OpenRead(data, size))) {
+ boost::throw_exception(MiscError("could not parse MPEG2 frame"));
+ }
+
+ state->mpeg2_parser.FillVideoDescriptor(state->video_descriptor);
+ state->video_descriptor.EditRate = ASDCP::Rational(asset->edit_rate().numerator, asset->edit_rate().denominator);
+
+ asset->set_size(Size(state->video_descriptor.StoredWidth, state->video_descriptor.StoredHeight));
+ asset->set_screen_aspect_ratio(Fraction(state->video_descriptor.AspectRatio.Numerator, state->video_descriptor.AspectRatio.Denominator));
+
+ asset->fill_writer_info(&state->writer_info, asset->id());
+
+ auto r = state->mxf_writer.OpenWrite(
+ dcp::filesystem::fix_long_path(*asset->file()).string().c_str(),
+ state->writer_info,
+ state->video_descriptor,
+ 16384,
+ writer->_overwrite
+ );
+
+ if (ASDCP_FAILURE(r)) {
+ boost::throw_exception(MXFFileError("could not open MXF file for writing", asset->file()->string(), r));
+ }
+
+ writer->_started = true;
+}
diff --git a/src/mpeg2_transcode.cc b/src/mpeg2_transcode.cc
new file mode 100644
index 00000000..0ac2c1af
--- /dev/null
+++ b/src/mpeg2_transcode.cc
@@ -0,0 +1,216 @@
+/*
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "compose.hpp"
+#include "exceptions.h"
+#include "mono_mpeg2_picture_frame.h"
+#include "mpeg2_transcode.h"
+#include "scope_guard.h"
+extern "C" {
+#include <libavcodec/avcodec.h>
+}
+
+
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using boost::optional;
+using namespace dcp;
+
+
+MPEG2Codec::~MPEG2Codec()
+{
+ avcodec_free_context(&_context);
+}
+
+
+
+MPEG2Decompressor::MPEG2Decompressor()
+{
+ _codec = avcodec_find_decoder_by_name("mpeg2video");
+ if (!_codec) {
+ throw MPEG2CodecError("could not find codec");
+ }
+
+ _context = avcodec_alloc_context3(_codec);
+ if (!_context) {
+ throw MPEG2CodecError("could not allocate codec context");
+ }
+
+ int const r = avcodec_open2(_context, _codec, nullptr);
+ if (r < 0) {
+ avcodec_free_context(&_context);
+ throw MPEG2CodecError("could not open codec");
+ }
+
+ _decompressed_frame = av_frame_alloc();
+ if (!_decompressed_frame) {
+ throw std::bad_alloc();
+ }
+}
+
+
+MPEG2Decompressor::~MPEG2Decompressor()
+{
+ av_frame_free(&_decompressed_frame);
+}
+
+
+vector<FFmpegImage>
+MPEG2Decompressor::decompress_frame(shared_ptr<const MonoMPEG2PictureFrame> frame)
+{
+ /* XXX: can we avoid this? */
+ auto copy = av_malloc(frame->size() + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!copy) {
+ throw std::bad_alloc();
+ }
+ memcpy(copy, frame->data(), frame->size());
+
+ AVPacket packet;
+ av_init_packet(&packet);
+ av_packet_from_data(&packet, reinterpret_cast<uint8_t*>(copy), frame->size());
+
+ auto images = decompress_packet(&packet);
+
+ av_packet_unref(&packet);
+
+ return images;
+}
+
+
+vector<FFmpegImage>
+MPEG2Decompressor::flush()
+{
+ return decompress_packet(nullptr);
+}
+
+
+vector<FFmpegImage>
+MPEG2Decompressor::decompress_packet(AVPacket* packet)
+{
+ int const r = avcodec_send_packet(_context, packet);
+ if (r < 0) {
+ throw MPEG2DecompressionError(String::compose("avcodec_send_packet failed (%1)", r));
+ }
+
+ vector<FFmpegImage> images;
+ while (true) {
+ int const r = avcodec_receive_frame(_context, _decompressed_frame);
+ if (r == AVERROR(EAGAIN) || r == AVERROR_EOF) {
+ break;
+ } else if (r < 0) {
+ throw MPEG2DecompressionError("avcodec_receive_frame failed");
+ }
+
+ auto clone = av_frame_clone(_decompressed_frame);
+ if (!clone) {
+ throw std::bad_alloc();
+ }
+
+ images.push_back(FFmpegImage(clone));
+ }
+
+ return images;
+}
+
+
+MPEG2Compressor::MPEG2Compressor(dcp::Size size, int video_frame_rate, int64_t bit_rate)
+{
+ _codec = avcodec_find_encoder_by_name("mpeg2video");
+ if (!_codec) {
+ throw MPEG2CodecError("could not find codec");
+ }
+
+ _context = avcodec_alloc_context3(_codec);
+ if (!_context) {
+ throw MPEG2CodecError("could not allocate codec context");
+ }
+
+ _context->width = size.width;
+ _context->height = size.height;
+ _context->time_base = AVRational{1, video_frame_rate};
+ _context->pix_fmt = AV_PIX_FMT_YUV420P;
+ _context->bit_rate = bit_rate;
+
+ int const r = avcodec_open2(_context, _codec, nullptr);
+ if (r < 0) {
+ avcodec_free_context(&_context);
+ throw MPEG2CodecError("could not open codec");
+ }
+}
+
+
+optional<MPEG2Compressor::IndexedFrame>
+MPEG2Compressor::send_and_receive(AVFrame const* frame)
+{
+ int r = avcodec_send_frame(_context, frame);
+ if (r < 0) {
+ throw MPEG2CompressionError(String::compose("avcodec_send_frame failed (%1", r));
+ }
+
+ auto packet = av_packet_alloc();
+ if (!packet) {
+ throw MPEG2CompressionError("could not allocate packet");
+ }
+
+ r = avcodec_receive_packet(_context, packet);
+ if (r < 0 && r != AVERROR(EAGAIN)) {
+ throw MPEG2CompressionError(String::compose("avcodec_receive_packet failed (%1)", r));
+ }
+
+ ScopeGuard sg = [&packet]() {
+ av_packet_free(&packet);
+ };
+
+ if (packet->size == 0) {
+ return {};
+ }
+
+ DCP_ASSERT(_context->time_base.num == 1);
+ return IndexedFrame{make_shared<MonoMPEG2PictureFrame>(packet->data, packet->size), std::round(static_cast<double>(packet->pts) / _context->time_base.den)};
+}
+
+
+optional<MPEG2Compressor::IndexedFrame>
+MPEG2Compressor::compress_frame(FFmpegImage const& image)
+{
+ return send_and_receive(image.frame());
+}
+
+
+optional<MPEG2Compressor::IndexedFrame>
+MPEG2Compressor::flush()
+{
+ return send_and_receive(nullptr);
+}
diff --git a/src/reel_closed_caption_asset.h b/src/mpeg2_transcode.h
index 405de34b..1f13cfc3 100644
--- a/src/reel_closed_caption_asset.h
+++ b/src/mpeg2_transcode.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2023 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
@@ -32,62 +32,73 @@
*/
-/** @file src/reel_closed_caption_asset.h
- * @brief ReelClosedCaptionAsset class
- */
+#ifndef LIBDCP_MPEG2_TRANSCODE_H
+#define LIBDCP_MPEG2_TRANSCODE_H
-#ifndef LIBDCP_REEL_CLOSED_CAPTION_ASSET_H
-#define LIBDCP_REEL_CLOSED_CAPTION_ASSET_H
+#include "ffmpeg_image.h"
+#include <memory>
-#include "language_tag.h"
-#include "reel_asset.h"
-#include "reel_file_asset.h"
-#include "subtitle_asset.h"
+struct AVCodec;
+struct AVCodecContext;
+struct AVFrame;
+struct AVPacket;
-struct verify_invalid_language2;
+namespace dcp {
-namespace dcp {
+class MonoMPEG2PictureFrame;
-/** @class ReelClosedCaptionAsset
- * @brief Part of a Reel's description which refers to a closed caption XML/MXF file
- */
-class ReelClosedCaptionAsset : public ReelFileAsset
+class MPEG2Codec
{
public:
- ReelClosedCaptionAsset (std::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
- explicit ReelClosedCaptionAsset (std::shared_ptr<const cxml::Node>);
+ MPEG2Codec() = default;
+ virtual ~MPEG2Codec();
- std::shared_ptr<const SubtitleAsset> asset () const {
- return asset_of_type<const SubtitleAsset>();
- }
+ MPEG2Codec(MPEG2Codec const&) = delete;
+ MPEG2Codec& operator=(MPEG2Codec const&) = delete;
- std::shared_ptr<SubtitleAsset> asset () {
- return asset_of_type<SubtitleAsset>();
- }
+protected:
+ AVCodec const* _codec;
+ AVCodecContext* _context;
+};
- bool equals(std::shared_ptr<const ReelClosedCaptionAsset>, EqualityOptions const&, NoteHandler) const;
- void set_language (dcp::LanguageTag l) {
- _language = l.to_string();
- }
+class MPEG2Decompressor : public MPEG2Codec
+{
+public:
+ MPEG2Decompressor();
+ ~MPEG2Decompressor();
- void unset_language () {
- _language = boost::optional<std::string> ();
- }
+ std::vector<FFmpegImage> decompress_frame(std::shared_ptr<const MonoMPEG2PictureFrame> frame);
+ std::vector<FFmpegImage> flush();
- boost::optional<std::string> language () const {
- return _language;
- }
+private:
+ std::vector<FFmpegImage> decompress_packet(AVPacket* packet);
-protected:
- friend struct ::verify_invalid_language2;
+ AVFrame* _decompressed_frame;
+};
+
+
+class MPEG2Compressor : public MPEG2Codec
+{
+public:
+ MPEG2Compressor(dcp::Size size, int video_frame_rate, int64_t bit_rate);
+
+ MPEG2Compressor(MPEG2Compressor const&) = delete;
+ MPEG2Compressor& operator=(MPEG2Compressor const&) = delete;
+
+ /** Frame data with frame index within the asset */
+ typedef std::pair<std::shared_ptr<MonoMPEG2PictureFrame>, int64_t> IndexedFrame;
+
+ boost::optional<IndexedFrame> compress_frame(FFmpegImage const& image);
+ boost::optional<IndexedFrame> flush();
- boost::optional<std::string> _language;
+private:
+ boost::optional<IndexedFrame> send_and_receive(AVFrame const* frame);
};
diff --git a/src/mxf.h b/src/mxf.h
index 19d4a956..1692fbd0 100644
--- a/src/mxf.h
+++ b/src/mxf.h
@@ -64,7 +64,8 @@ namespace dcp
class MXFMetadata;
-class PictureAssetWriter;
+class J2KPictureAssetWriter;
+class MPEG2PictureAssetWriter;
/** @class MXF
@@ -136,7 +137,9 @@ public:
protected:
template <class P, class Q>
- friend void start (PictureAssetWriter* writer, std::shared_ptr<P> state, Q* mxf, uint8_t const * data, int size);
+ friend void start (J2KPictureAssetWriter* writer, std::shared_ptr<P> state, Q* mxf, uint8_t const * data, int size);
+ template <class P, class Q>
+ friend void start (MPEG2PictureAssetWriter* writer, std::shared_ptr<P> state, Q* mxf, uint8_t const * data, int size);
MXF ();
diff --git a/src/name_format.h b/src/name_format.h
index 6401fe82..3eb0277b 100644
--- a/src/name_format.h
+++ b/src/name_format.h
@@ -37,8 +37,8 @@
*/
-#ifndef LIBDCP_NAME_FORMAT
-#define LIBDCP_NAME_FORMAT
+#ifndef LIBDCP_NAME_FORMAT_H
+#define LIBDCP_NAME_FORMAT_H
#include <string>
diff --git a/src/picture_asset.cc b/src/picture_asset.cc
index c9f669a6..3b28bf4b 100644
--- a/src/picture_asset.cc
+++ b/src/picture_asset.cc
@@ -32,199 +32,24 @@
*/
-/** @file src/picture_asset.cc
- * @brief PictureAsset class
- */
-
-
-#include "compose.hpp"
-#include "dcp_assert.h"
-#include "equality_options.h"
-#include "exceptions.h"
-#include "j2k_transcode.h"
-#include "openjpeg_image.h"
#include "picture_asset.h"
-#include "picture_asset_writer.h"
-#include "util.h"
-#include <asdcp/AS_DCP.h>
-#include <asdcp/KM_fileio.h>
-#include <libxml++/nodes/element.h>
-#include <boost/filesystem.hpp>
-#include <list>
-#include <stdexcept>
-
-
-using std::string;
-using std::list;
-using std::vector;
-using std::max;
-using std::pair;
-using std::make_pair;
-using std::shared_ptr;
-using namespace dcp;
-
-
-PictureAsset::PictureAsset (boost::filesystem::path file)
- : Asset (file)
-{
-
-}
-
-PictureAsset::PictureAsset (Fraction edit_rate, Standard standard)
- : MXF (standard)
- , _edit_rate (edit_rate)
-{
-}
+using namespace dcp;
-void
-PictureAsset::read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const & desc)
+PictureAsset::PictureAsset(boost::filesystem::path file)
+ : Asset(file)
{
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
- _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
- _intrinsic_duration = desc.ContainerDuration;
- _frame_rate = Fraction (desc.SampleRate.Numerator, desc.SampleRate.Denominator);
- _screen_aspect_ratio = Fraction (desc.AspectRatio.Numerator, desc.AspectRatio.Denominator);
-}
-
-bool
-PictureAsset::descriptor_equals (
- ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, NoteHandler note
- ) const
-{
- if (
- a.EditRate != b.EditRate ||
- a.SampleRate != b.SampleRate ||
- a.StoredWidth != b.StoredWidth ||
- a.StoredHeight != b.StoredHeight ||
- a.AspectRatio != b.AspectRatio ||
- a.Rsize != b.Rsize ||
- a.Xsize != b.Xsize ||
- a.Ysize != b.Ysize ||
- a.XOsize != b.XOsize ||
- a.YOsize != b.YOsize ||
- a.XTsize != b.XTsize ||
- a.YTsize != b.YTsize ||
- a.XTOsize != b.XTOsize ||
- a.YTOsize != b.YTOsize ||
- a.Csize != b.Csize
-// a.CodingStyleDefault != b.CodingStyleDefault ||
-// a.QuantizationDefault != b.QuantizationDefault
- ) {
-
- note (NoteType::ERROR, "video MXF picture descriptors differ");
- return false;
- }
-
- if (a.ContainerDuration != b.ContainerDuration) {
- note (NoteType::ERROR, "video container durations differ");
- }
-
-// for (unsigned int j = 0; j < ASDCP::JP2K::MaxComponents; ++j) {
-// if (a.ImageComponents[j] != b.ImageComponents[j]) {
-// notes.pack_start ("video MXF picture descriptors differ");
-// }
-// }
-
- return true;
}
-bool
-PictureAsset::frame_buffer_equals (
- int frame, EqualityOptions const& opt, NoteHandler note,
- uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
- ) const
+PictureAsset::PictureAsset(Fraction edit_rate, Standard standard)
+ : MXF(standard)
+ , _edit_rate(edit_rate)
{
- if (size_A == size_B && memcmp (data_A, data_B, size_A) == 0) {
- note (NoteType::NOTE, "J2K identical");
- /* Easy result; the J2K data is identical */
- return true;
- }
-
- /* Decompress the images to bitmaps */
- auto image_A = decompress_j2k (const_cast<uint8_t*>(data_A), size_A, 0);
- auto image_B = decompress_j2k (const_cast<uint8_t*>(data_B), size_B, 0);
-
- /* Compare them */
-
- vector<int> abs_diffs (image_A->size().width * image_A->size().height * 3);
- int d = 0;
- int max_diff = 0;
- for (int c = 0; c < 3; ++c) {
-
- if (image_A->size() != image_B->size()) {
- note (NoteType::ERROR, String::compose ("image sizes for frame %1 differ", frame));
- return false;
- }
-
- int const pixels = image_A->size().width * image_A->size().height;
- for (int j = 0; j < pixels; ++j) {
- int const t = abs (image_A->data(c)[j] - image_B->data(c)[j]);
- abs_diffs[d++] = t;
- max_diff = max (max_diff, t);
- }
- }
-
- uint64_t total = 0;
- for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
- total += *j;
- }
-
- double const mean = double (total) / abs_diffs.size ();
-
- uint64_t total_squared_deviation = 0;
- for (auto j: abs_diffs) {
- total_squared_deviation += pow (j - mean, 2);
- }
-
- auto const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
-
- note (NoteType::NOTE, String::compose("mean difference %1 deviation %2", mean, std_dev));
-
- if (mean > opt.max_mean_pixel_error) {
- note (
- NoteType::ERROR,
- String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
- );
-
- return false;
- }
-
- if (std_dev > opt.max_std_dev_pixel_error) {
- note (
- NoteType::ERROR,
- String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
- );
-
- return false;
- }
-
- return true;
}
-string
-PictureAsset::static_pkl_type (Standard standard)
-{
- switch (standard) {
- case Standard::INTEROP:
- return "application/x-smpte-mxf;asdcpKind=Picture";
- case Standard::SMPTE:
- return "application/mxf";
- default:
- DCP_ASSERT (false);
- }
-}
-
-
-string
-PictureAsset::pkl_type (Standard standard) const
-{
- return static_pkl_type (standard);
-}
diff --git a/src/picture_asset.h b/src/picture_asset.h
index 9ad1eb22..36364485 100644
--- a/src/picture_asset.h
+++ b/src/picture_asset.h
@@ -32,56 +32,31 @@
*/
-/** @file src/picture_asset.h
- * @brief PictureAsset class
- */
-
-
#ifndef LIBDCP_PICTURE_ASSET_H
#define LIBDCP_PICTURE_ASSET_H
+#include "asset.h"
#include "mxf.h"
-#include "util.h"
-#include "metadata.h"
-
-
-namespace ASDCP {
- namespace JP2K {
- struct PictureDescriptor;
- }
-}
+#include "types.h"
namespace dcp {
-class MonoPictureFrame;
-class StereoPictureFrame;
-class PictureAssetWriter;
-
-
-/** @class PictureAsset
- * @brief An asset made up of JPEG2000 data
- */
class PictureAsset : public Asset, public MXF
{
public:
- /** Load a PictureAsset from a file */
- explicit PictureAsset (boost::filesystem::path file);
-
- /** Create a new PictureAsset with a given edit rate and standard */
+ explicit PictureAsset(boost::filesystem::path file);
PictureAsset(Fraction edit_rate, Standard standard);
- enum class Behaviour {
- OVERWRITE_EXISTING,
- MAKE_NEW
- };
+ Fraction edit_rate () const {
+ return _edit_rate;
+ }
- virtual std::shared_ptr<PictureAssetWriter> start_write (
- boost::filesystem::path file,
- Behaviour behaviour
- ) = 0;
+ int64_t intrinsic_duration () const {
+ return _intrinsic_duration;
+ }
Size size () const {
return _size;
@@ -107,33 +82,7 @@ public:
_screen_aspect_ratio = r;
}
- Fraction edit_rate () const {
- return _edit_rate;
- }
-
- int64_t intrinsic_duration () const {
- return _intrinsic_duration;
- }
-
- static std::string static_pkl_type (Standard standard);
-
protected:
- friend class MonoPictureAssetWriter;
- friend class StereoPictureAssetWriter;
-
- bool frame_buffer_equals (
- int frame, EqualityOptions const& opt, NoteHandler note,
- uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
- ) const;
-
- bool descriptor_equals (
- ASDCP::JP2K::PictureDescriptor const & a,
- ASDCP::JP2K::PictureDescriptor const & b,
- NoteHandler note
- ) const;
-
- void read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const &);
-
Fraction _edit_rate;
/** The total length of this content in video frames. The amount of
* content presented may be less than this.
@@ -144,8 +93,6 @@ protected:
Fraction _frame_rate;
Fraction _screen_aspect_ratio;
-private:
- std::string pkl_type (Standard standard) const override;
};
@@ -153,3 +100,4 @@ private:
#endif
+
diff --git a/src/pkl.cc b/src/pkl.cc
index 57eda9da..463d046a 100644
--- a/src/pkl.cc
+++ b/src/pkl.cc
@@ -105,26 +105,26 @@ PKL::write_xml (boost::filesystem::path file, shared_ptr<const CertificateChain>
pkl = doc.create_root_node("PackingList", pkl_smpte_ns);
}
- pkl->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ cxml::add_text_child(pkl, "Id", "urn:uuid:" + _id);
if (_annotation_text) {
- pkl->add_child("AnnotationText")->add_child_text (*_annotation_text);
+ cxml::add_text_child(pkl, "AnnotationText", *_annotation_text);
}
- pkl->add_child("IssueDate")->add_child_text (_issue_date);
- pkl->add_child("Issuer")->add_child_text (_issuer);
- pkl->add_child("Creator")->add_child_text (_creator);
+ cxml::add_text_child(pkl, "IssueDate", _issue_date);
+ cxml::add_text_child(pkl, "Issuer", _issuer);
+ cxml::add_text_child(pkl, "Creator", _creator);
- auto asset_list = pkl->add_child("AssetList");
+ auto asset_list = cxml::add_child(pkl, "AssetList");
for (auto i: _assets) {
- auto asset = asset_list->add_child("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + i->id());
+ auto asset = cxml::add_child(asset_list, "Asset");
+ cxml::add_text_child(asset, "Id", "urn:uuid:" + i->id());
if (i->annotation_text()) {
- asset->add_child("AnnotationText")->add_child_text (*i->annotation_text());
+ cxml::add_text_child(asset, "AnnotationText", *i->annotation_text());
}
- asset->add_child("Hash")->add_child_text (i->hash());
- asset->add_child("Size")->add_child_text (raw_convert<string>(i->size()));
- asset->add_child("Type")->add_child_text (i->type());
+ cxml::add_text_child(asset, "Hash", i->hash());
+ cxml::add_text_child(asset, "Size", raw_convert<string>(i->size()));
+ cxml::add_text_child(asset, "Type", i->type());
if (auto filename = i->original_filename()) {
- asset->add_child("OriginalFileName")->add_child_text(*filename);
+ cxml::add_text_child(asset, "OriginalFileName", *filename);
}
}
diff --git a/src/pkl.h b/src/pkl.h
index d0a11188..88443057 100644
--- a/src/pkl.h
+++ b/src/pkl.h
@@ -32,7 +32,7 @@
*/
-/** @file src/pkl.cc
+/** @file src/pkl.h
* @brief PKL class
*/
diff --git a/src/rating.cc b/src/rating.cc
index 21960365..156d5ad0 100644
--- a/src/rating.cc
+++ b/src/rating.cc
@@ -61,8 +61,8 @@ Rating::Rating (cxml::ConstNodePtr node)
void
Rating::as_xml (xmlpp::Element* parent) const
{
- parent->add_child("Agency")->add_child_text(agency);
- parent->add_child("Label")->add_child_text(label);
+ cxml::add_text_child(parent, "Agency", agency);
+ cxml::add_text_child(parent, "Label", label);
}
diff --git a/src/reel.cc b/src/reel.cc
index a8481d59..ce654f6f 100644
--- a/src/reel.cc
+++ b/src/reel.cc
@@ -40,25 +40,22 @@
#include "decrypted_kdm.h"
#include "decrypted_kdm_key.h"
#include "equality_options.h"
-#include "interop_subtitle_asset.h"
-#include "mono_picture_asset.h"
-#include "picture_asset.h"
+#include "interop_text_asset.h"
+#include "mono_j2k_picture_asset.h"
+#include "j2k_picture_asset.h"
#include "reel.h"
#include "reel_atmos_asset.h"
-#include "reel_closed_caption_asset.h"
-#include "reel_interop_closed_caption_asset.h"
-#include "reel_interop_subtitle_asset.h"
+#include "reel_interop_text_asset.h"
#include "reel_markers_asset.h"
#include "reel_mono_picture_asset.h"
-#include "reel_smpte_closed_caption_asset.h"
-#include "reel_smpte_subtitle_asset.h"
+#include "reel_smpte_text_asset.h"
#include "reel_sound_asset.h"
#include "reel_stereo_picture_asset.h"
-#include "reel_subtitle_asset.h"
-#include "smpte_subtitle_asset.h"
+#include "reel_text_asset.h"
+#include "smpte_text_asset.h"
#include "sound_asset.h"
-#include "stereo_picture_asset.h"
-#include "subtitle_asset.h"
+#include "stereo_j2k_picture_asset.h"
+#include "text_asset.h"
#include "util.h"
#include <libxml++/nodes/element.h>
#include <stdint.h>
@@ -79,38 +76,56 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
{
auto asset_list = node->node_child ("AssetList");
- auto main_picture = asset_list->optional_node_child ("MainPicture");
- if (main_picture) {
+ if (auto main_picture = asset_list->optional_node_child("MainPicture")) {
_main_picture = make_shared<ReelMonoPictureAsset>(main_picture);
}
- auto main_stereoscopic_picture = asset_list->optional_node_child ("MainStereoscopicPicture");
- if (main_stereoscopic_picture) {
+ if (auto main_stereoscopic_picture = asset_list->optional_node_child("MainStereoscopicPicture")) {
_main_picture = make_shared<ReelStereoPictureAsset>(main_stereoscopic_picture);
}
- auto main_sound = asset_list->optional_node_child ("MainSound");
- if (main_sound) {
+ if (auto main_sound = asset_list->optional_node_child("MainSound")) {
_main_sound = make_shared<ReelSoundAsset>(main_sound);
}
- auto main_subtitle = asset_list->optional_node_child ("MainSubtitle");
- if (main_subtitle) {
+ if (auto main_subtitle = asset_list->optional_node_child("MainSubtitle")) {
switch (standard) {
- case Standard::INTEROP:
- _main_subtitle = make_shared<ReelInteropSubtitleAsset>(main_subtitle);
- break;
- case Standard::SMPTE:
- _main_subtitle = make_shared<ReelSMPTESubtitleAsset>(main_subtitle);
- break;
+ case Standard::INTEROP:
+ _main_subtitle = make_shared<ReelInteropTextAsset>(main_subtitle);
+ break;
+ case Standard::SMPTE:
+ _main_subtitle = make_shared<ReelSMPTETextAsset>(main_subtitle);
+ break;
}
}
- auto main_markers = asset_list->optional_node_child ("MainMarkers");
- if (main_markers) {
+ if (auto main_caption = asset_list->optional_node_child("MainCaption")) {
+ switch (standard) {
+ case Standard::INTEROP:
+ DCP_ASSERT(false);
+ break;
+ case Standard::SMPTE:
+ _main_caption = make_shared<ReelSMPTETextAsset>(main_caption);
+ break;
+ }
+ }
+
+ if (auto main_markers = asset_list->optional_node_child("MainMarkers")) {
_main_markers = make_shared<ReelMarkersAsset>(main_markers);
}
+ auto closed_subtitles = asset_list->node_children("ClosedSubtitle");
+ for (auto i: closed_subtitles) {
+ switch (standard) {
+ case Standard::INTEROP:
+ DCP_ASSERT(false);
+ break;
+ case Standard::SMPTE:
+ _closed_subtitles.push_back(make_shared<ReelSMPTETextAsset>(i));
+ break;
+ }
+ }
+
/* XXX: it's not ideal that we silently tolerate Interop or SMPTE nodes here */
/* XXX: not sure if Interop supports multiple closed captions */
auto closed_captions = asset_list->node_children ("MainClosedCaption");
@@ -119,17 +134,16 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
}
for (auto i: closed_captions) {
switch (standard) {
- case Standard::INTEROP:
- _closed_captions.push_back (make_shared<ReelInteropClosedCaptionAsset>(i));
- break;
- case Standard::SMPTE:
- _closed_captions.push_back (make_shared<ReelSMPTEClosedCaptionAsset>(i));
- break;
+ case Standard::INTEROP:
+ _closed_captions.push_back(make_shared<ReelInteropTextAsset>(i));
+ break;
+ case Standard::SMPTE:
+ _closed_captions.push_back(make_shared<ReelSMPTETextAsset>(i));
+ break;
}
}
- auto atmos = asset_list->optional_node_child ("AuxData");
- if (atmos) {
+ if (auto atmos = asset_list->optional_node_child("AuxData")) {
_atmos = make_shared<ReelAtmosAsset>(atmos);
}
@@ -141,9 +155,9 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
xmlpp::Element *
Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
{
- auto reel = node->add_child ("Reel");
- reel->add_child("Id")->add_child_text("urn:uuid:" + _id);
- xmlpp::Element* asset_list = reel->add_child ("AssetList");
+ auto reel = cxml::add_child(node, "Reel");
+ cxml::add_text_child(reel, "Id", "urn:uuid:" + _id);
+ auto asset_list = cxml::add_child(reel, "AssetList");
if (_main_markers) {
_main_markers->write_to_cpl (asset_list, standard);
@@ -162,6 +176,14 @@ Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
_main_subtitle->write_to_cpl (asset_list, standard);
}
+ if (_main_caption) {
+ _main_caption->write_to_cpl(asset_list, standard);
+ }
+
+ for (auto i: _closed_subtitles) {
+ i->write_to_cpl(asset_list, standard);
+ }
+
for (auto i: _closed_captions) {
i->write_to_cpl (asset_list, standard);
}
@@ -208,8 +230,8 @@ Reel::equals(std::shared_ptr<const Reel> other, EqualityOptions const& opt, Note
bool same_type = false;
{
- auto interop = dynamic_pointer_cast<ReelInteropSubtitleAsset>(_main_subtitle);
- auto interop_other = dynamic_pointer_cast<ReelInteropSubtitleAsset>(other->_main_subtitle);
+ auto interop = dynamic_pointer_cast<ReelInteropTextAsset>(_main_subtitle);
+ auto interop_other = dynamic_pointer_cast<ReelInteropTextAsset>(other->_main_subtitle);
if (interop && interop_other) {
same_type = true;
if (!interop->equals(interop_other, opt, note)) {
@@ -219,8 +241,8 @@ Reel::equals(std::shared_ptr<const Reel> other, EqualityOptions const& opt, Note
}
{
- auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(_main_subtitle);
- auto smpte_other = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(other->_main_subtitle);
+ auto smpte = dynamic_pointer_cast<ReelSMPTETextAsset>(_main_subtitle);
+ auto smpte_other = dynamic_pointer_cast<ReelSMPTETextAsset>(other->_main_subtitle);
if (smpte && smpte_other) {
same_type = true;
if (!smpte->equals(smpte_other, opt, note)) {
@@ -327,19 +349,19 @@ Reel::give_kdm_to_assets (DecryptedKDM const & kdm)
{
for (auto const& i: kdm.keys()) {
if (_main_picture && i.id() == _main_picture->key_id() && _main_picture->asset_ref().resolved()) {
- _main_picture->asset()->set_key (i.key());
+ _main_picture->j2k_asset()->set_key(i.key());
}
if (_main_sound && i.id() == _main_sound->key_id() && _main_sound->asset_ref().resolved()) {
_main_sound->asset()->set_key (i.key());
}
if (_main_subtitle) {
- auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(_main_subtitle);
+ auto smpte = dynamic_pointer_cast<ReelSMPTETextAsset>(_main_subtitle);
if (smpte && i.id() == smpte->key_id() && smpte->asset_ref().resolved()) {
smpte->smpte_asset()->set_key(i.key());
}
}
for (auto j: _closed_captions) {
- auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(j);
+ auto smpte = dynamic_pointer_cast<ReelSMPTETextAsset>(j);
if (smpte && i.id() == smpte->key_id() && smpte->asset_ref().resolved()) {
smpte->smpte_asset()->set_key(i.key());
}
@@ -358,12 +380,23 @@ Reel::add (shared_ptr<ReelAsset> asset)
_main_picture = p;
} else if (auto so = dynamic_pointer_cast<ReelSoundAsset>(asset)) {
_main_sound = so;
- } else if (auto su = dynamic_pointer_cast<ReelSubtitleAsset>(asset)) {
- _main_subtitle = su;
+ } else if (auto te = dynamic_pointer_cast<ReelTextAsset>(asset)) {
+ switch (te->type()) {
+ case TextType::OPEN_SUBTITLE:
+ _main_subtitle = te;
+ break;
+ case TextType::OPEN_CAPTION:
+ _main_caption = te;
+ break;
+ case TextType::CLOSED_SUBTITLE:
+ _closed_subtitles.push_back(te);
+ break;
+ case TextType::CLOSED_CAPTION:
+ _closed_captions.push_back(te);
+ break;
+ }
} else if (auto m = dynamic_pointer_cast<ReelMarkersAsset>(asset)) {
_main_markers = m;
- } else if (auto c = dynamic_pointer_cast<ReelClosedCaptionAsset>(asset)) {
- _closed_captions.push_back (c);
} else if (auto a = dynamic_pointer_cast<ReelAtmosAsset>(asset)) {
_atmos = a;
} else {
@@ -385,6 +418,10 @@ Reel::assets () const
if (_main_subtitle) {
a.push_back (_main_subtitle);
}
+ if (_main_caption) {
+ a.push_back(_main_caption);
+ }
+ std::copy (_closed_subtitles.begin(), _closed_subtitles.end(), back_inserter(a));
std::copy (_closed_captions.begin(), _closed_captions.end(), back_inserter(a));
if (_atmos) {
a.push_back (_atmos);
@@ -404,28 +441,33 @@ Reel::resolve_refs (vector<shared_ptr<Asset>> assets)
_main_sound->asset_ref().resolve(assets);
}
- if (_main_subtitle) {
- _main_subtitle->asset_ref().resolve(assets);
-
+ auto resolve_interop_fonts = [&assets](shared_ptr<ReelTextAsset>(asset)) {
/* Interop subtitle handling is all special cases */
- if (_main_subtitle->asset_ref().resolved()) {
- auto iop = dynamic_pointer_cast<InteropSubtitleAsset> (_main_subtitle->asset_ref().asset());
- if (iop) {
- iop->resolve_fonts (assets);
+ if (asset->asset_ref().resolved()) {
+ if (auto iop = dynamic_pointer_cast<InteropTextAsset>(asset->asset_ref().asset())) {
+ iop->resolve_fonts(assets);
}
}
+
+ };
+
+ if (_main_subtitle) {
+ _main_subtitle->asset_ref().resolve(assets);
+ resolve_interop_fonts(_main_subtitle);
}
- for (auto i: _closed_captions) {
+ if (_main_caption) {
+ _main_caption->asset_ref().resolve(assets);
+ }
+
+ for (auto i: _closed_subtitles) {
i->asset_ref().resolve(assets);
+ resolve_interop_fonts(i);
+ }
- /* Interop subtitle handling is all special cases */
- if (i->asset_ref().resolved()) {
- auto iop = dynamic_pointer_cast<InteropSubtitleAsset> (i->asset_ref().asset());
- if (iop) {
- iop->resolve_fonts (assets);
- }
- }
+ for (auto i: _closed_captions) {
+ i->asset_ref().resolve(assets);
+ resolve_interop_fonts(i);
}
if (_atmos) {
@@ -453,9 +495,15 @@ Reel::duration () const
if (_main_subtitle) {
d = min (d, _main_subtitle->actual_duration());
}
+ if (_main_caption) {
+ d = min(d, _main_caption->actual_duration());
+ }
if (_main_markers) {
d = min (d, _main_markers->actual_duration());
}
+ for (auto i: _closed_subtitles) {
+ d = min(d, i->actual_duration());
+ }
for (auto i: _closed_captions) {
d = min (d, i->actual_duration());
}
diff --git a/src/reel.h b/src/reel.h
index 52f41bfa..347013c3 100644
--- a/src/reel.h
+++ b/src/reel.h
@@ -32,7 +32,7 @@
*/
-/** @file src/reel.cc
+/** @file src/reel.h
* @brief Reel class
*/
@@ -68,7 +68,7 @@ class DecryptedKDM;
class ReelAsset;
class ReelPictureAsset;
class ReelSoundAsset;
-class ReelSubtitleAsset;
+class ReelTextAsset;
class ReelMarkersAsset;
class ReelClosedCaptionAsset;
class ReelAtmosAsset;
@@ -84,7 +84,7 @@ public:
Reel (
std::shared_ptr<ReelPictureAsset> picture,
std::shared_ptr<ReelSoundAsset> sound = std::shared_ptr<ReelSoundAsset> (),
- std::shared_ptr<ReelSubtitleAsset> subtitle = std::shared_ptr<ReelSubtitleAsset> (),
+ std::shared_ptr<ReelTextAsset> subtitle = std::shared_ptr<ReelTextAsset> (),
std::shared_ptr<ReelMarkersAsset> markers = std::shared_ptr<ReelMarkersAsset> (),
std::shared_ptr<ReelAtmosAsset> atmos = std::shared_ptr<ReelAtmosAsset> ()
)
@@ -105,15 +105,23 @@ public:
return _main_sound;
}
- std::shared_ptr<ReelSubtitleAsset> main_subtitle () const {
+ std::shared_ptr<ReelTextAsset> main_subtitle () const {
return _main_subtitle;
}
+ std::shared_ptr<ReelTextAsset> main_caption() const {
+ return _main_caption;
+ }
+
std::shared_ptr<ReelMarkersAsset> main_markers () const {
return _main_markers;
}
- std::vector<std::shared_ptr<ReelClosedCaptionAsset>> closed_captions () const {
+ std::vector<std::shared_ptr<ReelTextAsset>> closed_subtitles() const {
+ return _closed_subtitles;
+ }
+
+ std::vector<std::shared_ptr<ReelTextAsset>> closed_captions () const {
return _closed_captions;
}
@@ -145,9 +153,11 @@ private:
std::shared_ptr<ReelPictureAsset> _main_picture;
std::shared_ptr<ReelSoundAsset> _main_sound;
- std::shared_ptr<ReelSubtitleAsset> _main_subtitle;
+ std::shared_ptr<ReelTextAsset> _main_subtitle;
+ std::shared_ptr<ReelTextAsset> _main_caption;
std::shared_ptr<ReelMarkersAsset> _main_markers;
- std::vector<std::shared_ptr<ReelClosedCaptionAsset>> _closed_captions;
+ std::vector<std::shared_ptr<ReelTextAsset>> _closed_subtitles;
+ std::vector<std::shared_ptr<ReelTextAsset>> _closed_captions;
std::shared_ptr<ReelAtmosAsset> _atmos;
std::vector<dcp::DecryptedKDM> _kdms;
diff --git a/src/reel_asset.cc b/src/reel_asset.cc
index 3a3ae731..1d3d1d1f 100644
--- a/src/reel_asset.cc
+++ b/src/reel_asset.cc
@@ -84,10 +84,10 @@ ReelAsset::ReelAsset (shared_ptr<const cxml::Node> node)
}
-xmlpp::Node*
-ReelAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+xmlpp::Element*
+ReelAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
- auto a = node->add_child (cpl_node_name (standard));
+ auto a = cxml::add_child(node, cpl_node_name());
auto const attr = cpl_node_attribute (standard);
if (!attr.first.empty ()) {
a->set_attribute (attr.first, attr.second);
@@ -96,18 +96,18 @@ ReelAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
if (!ns.first.empty()) {
a->set_namespace_declaration (ns.first, ns.second);
}
- a->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ cxml::add_text_child(a, "Id", "urn:uuid:" + _id);
/* Empty <AnnotationText> tags cause refusal to play on some Sony SRX320 / LMT3000 systems (DoM bug #2124) */
if (_annotation_text && !_annotation_text->empty()) {
- a->add_child("AnnotationText")->add_child_text(*_annotation_text);
+ cxml::add_text_child(a, "AnnotationText", *_annotation_text);
}
- a->add_child("EditRate")->add_child_text (_edit_rate.as_string());
- a->add_child("IntrinsicDuration")->add_child_text (raw_convert<string> (_intrinsic_duration));
+ cxml::add_text_child(a, "EditRate", _edit_rate.as_string());
+ cxml::add_text_child(a, "IntrinsicDuration", raw_convert<string>(_intrinsic_duration));
if (_entry_point) {
- a->add_child("EntryPoint")->add_child_text(raw_convert<string>(*_entry_point));
+ cxml::add_text_child(a, "EntryPoint", raw_convert<string>(*_entry_point));
}
if (_duration) {
- a->add_child("Duration")->add_child_text(raw_convert<string>(*_duration));
+ cxml::add_text_child(a, "Duration", raw_convert<string>(*_duration));
}
return a;
}
@@ -138,7 +138,7 @@ optional_to_string (optional<T> o)
bool
ReelAsset::asset_equals(shared_ptr<const ReelAsset> other, EqualityOptions const& opt, NoteHandler note) const
{
- auto const node = cpl_node_name(Standard::SMPTE);
+ auto const node = cpl_node_name();
if (_annotation_text != other->_annotation_text) {
string const s = String::compose("Reel %1: annotation texts differ (%2 vs %3)", node, optional_to_string(_annotation_text), optional_to_string(other->_annotation_text));
diff --git a/src/reel_asset.h b/src/reel_asset.h
index e928cb18..99db60b4 100644
--- a/src/reel_asset.h
+++ b/src/reel_asset.h
@@ -83,7 +83,7 @@ public:
explicit ReelAsset (std::shared_ptr<const cxml::Node>);
- virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const;
+ virtual xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const;
virtual bool encryptable () const {
return false;
@@ -139,7 +139,7 @@ protected:
/** @return the node name that this asset uses in the CPL's &lt;Reel&gt; node
* e.g. MainPicture, MainSound etc.
*/
- virtual std::string cpl_node_name (Standard) const = 0;
+ virtual std::string cpl_node_name() const = 0;
/** @return Any attribute that should be used on the asset's node in the CPL */
virtual std::pair<std::string, std::string> cpl_node_attribute (Standard) const;
diff --git a/src/reel_atmos_asset.cc b/src/reel_atmos_asset.cc
index ef39a4eb..fcecb548 100644
--- a/src/reel_atmos_asset.cc
+++ b/src/reel_atmos_asset.cc
@@ -69,7 +69,7 @@ ReelAtmosAsset::ReelAtmosAsset (std::shared_ptr<const cxml::Node> node)
string
-ReelAtmosAsset::cpl_node_name (Standard) const
+ReelAtmosAsset::cpl_node_name() const
{
return "axd:AuxData";
}
@@ -82,11 +82,11 @@ ReelAtmosAsset::cpl_node_namespace () const
}
-xmlpp::Node *
-ReelAtmosAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+xmlpp::Element*
+ReelAtmosAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
auto asset = ReelFileAsset::write_to_cpl (node, standard);
- asset->add_child("axd:DataType")->add_child_text("urn:smpte:ul:060e2b34.04010105.0e090604.00000000");
+ cxml::add_text_child(asset, "axd:DataType", "urn:smpte:ul:060e2b34.04010105.0e090604.00000000");
return asset;
}
diff --git a/src/reel_atmos_asset.h b/src/reel_atmos_asset.h
index 298cbbfd..ab18d1ab 100644
--- a/src/reel_atmos_asset.h
+++ b/src/reel_atmos_asset.h
@@ -68,7 +68,7 @@ public:
return asset_of_type<AtmosAsset>();
}
- xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
+ xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
bool equals(std::shared_ptr<const ReelAtmosAsset>, EqualityOptions const&, NoteHandler) const;
private:
@@ -76,7 +76,7 @@ private:
return std::string("MDEK");
}
- std::string cpl_node_name (Standard standard) const override;
+ std::string cpl_node_name() const override;
std::pair<std::string, std::string> cpl_node_namespace () const override;
};
diff --git a/src/reel_file_asset.cc b/src/reel_file_asset.cc
index 5fefda27..8fed8012 100644
--- a/src/reel_file_asset.cc
+++ b/src/reel_file_asset.cc
@@ -94,15 +94,15 @@ ReelFileAsset::file_asset_equals(shared_ptr<const ReelFileAsset> other, Equality
}
-xmlpp::Node *
-ReelFileAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+xmlpp::Element*
+ReelFileAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
- auto asset = ReelAsset::write_to_cpl (node, standard);
+ auto asset = ReelAsset::write_to_cpl(node, standard);
if (_key_id) {
- asset->add_child("KeyId")->add_child_text("urn:uuid:" + *_key_id);
+ cxml::add_text_child(asset, "KeyId", "urn:uuid:" + *_key_id);
}
if (_hash) {
- asset->add_child("Hash")->add_child_text(*_hash);
+ cxml::add_text_child(asset, "Hash", *_hash);
}
return asset;
}
diff --git a/src/reel_file_asset.h b/src/reel_file_asset.h
index 687e0d3e..48fdf215 100644
--- a/src/reel_file_asset.h
+++ b/src/reel_file_asset.h
@@ -56,7 +56,7 @@ public:
ReelFileAsset (std::shared_ptr<Asset> asset, boost::optional<std::string> key_id, std::string id, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
explicit ReelFileAsset (std::shared_ptr<const cxml::Node> node);
- virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
+ virtual xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
/** @return a Ref to our actual asset */
Ref const & asset_ref () const {
diff --git a/src/reel_interop_closed_caption_asset.h b/src/reel_interop_closed_caption_asset.h
deleted file mode 100644
index 5e8f7c1e..00000000
--- a/src/reel_interop_closed_caption_asset.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
-
- This file is part of libdcp.
-
- libdcp 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.
-
- libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
-
- In addition, as a special exception, the copyright holders give
- permission to link the code of portions of this program with the
- OpenSSL library under certain conditions as described in each
- individual source file, and distribute linked combinations
- including the two.
-
- You must obey the GNU General Public License in all respects
- for all of the code used other than OpenSSL. If you modify
- file(s) with this exception, you may extend this exception to your
- version of the file(s), but you are not obligated to do so. If you
- do not wish to do so, delete this exception statement from your
- version. If you delete this exception statement from all source
- files in the program, then also delete it here.
-*/
-
-
-/** @file src/reel_interop_closed_caption_asset.h
- * @brief ReelInteropClosedCaptionAsset class
- */
-
-
-#ifndef LIBDCP_REEL_INTEROP_CLOSED_CAPTION_ASSET_H
-#define LIBDCP_REEL_INTEROP_CLOSED_CAPTION_ASSET_H
-
-
-#include "interop_subtitle_asset.h"
-#include "reel_closed_caption_asset.h"
-
-
-namespace dcp {
-
-
-class ReelInteropClosedCaptionAsset : public ReelClosedCaptionAsset
-{
-public:
- ReelInteropClosedCaptionAsset (std::shared_ptr<InteropSubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
- explicit ReelInteropClosedCaptionAsset (std::shared_ptr<const cxml::Node>);
-
- std::shared_ptr<const InteropSubtitleAsset> interop_asset () const {
- return asset_of_type<const InteropSubtitleAsset>();
- }
-
- std::shared_ptr<InteropSubtitleAsset> interop_asset () {
- return asset_of_type<InteropSubtitleAsset>();
- }
-
- xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
-
-private:
- std::string cpl_node_name (Standard) const override;
- std::pair<std::string, std::string> cpl_node_namespace () const override;
-};
-
-
-};
-
-
-#endif
-
diff --git a/src/reel_smpte_closed_caption_asset.cc b/src/reel_interop_text_asset.cc
index a2a68202..0f99b614 100644
--- a/src/reel_smpte_closed_caption_asset.cc
+++ b/src/reel_interop_text_asset.cc
@@ -32,12 +32,13 @@
*/
-/** @file src/reel_smpte_closed_caption_asset.cc
- * @brief ReelSMPTEClosedCaptionAsset class
+/** @file src/reel_interop_text_asset.cc
+ * @brief ReelInteropTextAsset class
*/
-#include "reel_smpte_closed_caption_asset.h"
+#include "dcp_assert.h"
+#include "reel_interop_text_asset.h"
#include "warnings.h"
LIBDCP_DISABLE_WARNINGS
#include <libxml++/libxml++.h>
@@ -46,46 +47,69 @@ LIBDCP_ENABLE_WARNINGS
using std::make_pair;
using std::pair;
-using std::shared_ptr;
using std::string;
+using boost::optional;
using namespace dcp;
-ReelSMPTEClosedCaptionAsset::ReelSMPTEClosedCaptionAsset (shared_ptr<SMPTESubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
- : ReelClosedCaptionAsset (asset, edit_rate, intrinsic_duration, entry_point)
+ReelInteropTextAsset::ReelInteropTextAsset(TextType type, std::shared_ptr<TextAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
+ : ReelTextAsset(type, asset, edit_rate, intrinsic_duration, entry_point)
{
}
-ReelSMPTEClosedCaptionAsset::ReelSMPTEClosedCaptionAsset (shared_ptr<const cxml::Node> node)
- : ReelClosedCaptionAsset (node)
+ReelInteropTextAsset::ReelInteropTextAsset(std::shared_ptr<const cxml::Node> node)
+ : ReelTextAsset(node)
{
node->done ();
}
-xmlpp::Node *
-ReelSMPTEClosedCaptionAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+string
+ReelInteropTextAsset::cpl_node_name() const
{
- auto asset = ReelClosedCaptionAsset::write_to_cpl (node, standard);
- if (_language) {
- asset->add_child("Language", "tt")->add_child_text(*_language);
+ switch (_type) {
+ case TextType::OPEN_SUBTITLE:
+ return "MainSubtitle";
+ case TextType::OPEN_CAPTION:
+ return "cc-cpl:MainCaption";
+ case TextType::CLOSED_SUBTITLE:
+ return "ClosedSubtitle";
+ case TextType::CLOSED_CAPTION:
+ return "cc-cpl:MainClosedCaption";
}
- return asset;
+
+ DCP_ASSERT(false);
+ return "";
}
-string
-ReelSMPTEClosedCaptionAsset::cpl_node_name (Standard) const
+pair<string, string>
+ReelInteropTextAsset::cpl_node_namespace() const
{
- return "tt:ClosedCaption";
+ switch (_type) {
+ case TextType::OPEN_SUBTITLE:
+ case TextType::CLOSED_SUBTITLE:
+ return {};
+ case TextType::OPEN_CAPTION:
+ case TextType::CLOSED_CAPTION:
+ return make_pair("http://www.digicine.com/PROTO-ASDCP-CC-CPL-20070926#", "cc-cpl");
+ }
+
+ DCP_ASSERT(false);
+ return {};
}
-pair<string, string>
-ReelSMPTEClosedCaptionAsset::cpl_node_namespace () const
+xmlpp::Element *
+ReelInteropTextAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
- return make_pair("http://www.smpte-ra.org/schemas/429-12/2008/TT", "tt");
+ auto asset = ReelFileAsset::write_to_cpl (node, standard);
+ if (_language) {
+ cxml::add_text_child(asset, "Language", *_language);
+ }
+ return asset;
}
+
diff --git a/src/reel_interop_subtitle_asset.h b/src/reel_interop_text_asset.h
index 7e90e9e0..4c0648e4 100644
--- a/src/reel_interop_subtitle_asset.h
+++ b/src/reel_interop_text_asset.h
@@ -32,35 +32,40 @@
*/
-/** @file src/reel_interop_subtitle_asset.h
- * @brief ReelInteropSubtitleAsset class
+/** @file src/reel_interop_text_asset.h
+ * @brief ReelInteropTextAsset class
*/
-#include "interop_subtitle_asset.h"
-#include "reel_file_asset.h"
-#include "reel_subtitle_asset.h"
+#include "interop_text_asset.h"
+#include "reel_text_asset.h"
namespace dcp {
-/** @class ReelInteropSubtitleAsset
- * @brief Part of a Reel's description which refers to an Interop subtitle XML file
+/** @class ReelInteropTextAsset
+ * @brief Part of a Reel's description which refers to an Interop subtitle or caption XML file
*/
-class ReelInteropSubtitleAsset : public ReelSubtitleAsset
+class ReelInteropTextAsset : public ReelTextAsset
{
public:
- ReelInteropSubtitleAsset (std::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
- explicit ReelInteropSubtitleAsset (std::shared_ptr<const cxml::Node>);
+ ReelInteropTextAsset(TextType type, std::shared_ptr<TextAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
+ explicit ReelInteropTextAsset (std::shared_ptr<const cxml::Node>);
- std::shared_ptr<const InteropSubtitleAsset> interop_asset () const {
- return asset_of_type<const InteropSubtitleAsset>();
+ std::shared_ptr<const InteropTextAsset> interop_asset() const {
+ return asset_of_type<const InteropTextAsset>();
}
- std::shared_ptr<InteropSubtitleAsset> interop_asset () {
- return asset_of_type<InteropSubtitleAsset>();
+ std::shared_ptr<InteropTextAsset> interop_asset() {
+ return asset_of_type<InteropTextAsset>();
}
+
+ xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
+
+protected:
+ std::string cpl_node_name() const override;
+ std::pair<std::string, std::string> cpl_node_namespace() const override;
};
diff --git a/src/reel_markers_asset.cc b/src/reel_markers_asset.cc
index d71a22ec..df920f44 100644
--- a/src/reel_markers_asset.cc
+++ b/src/reel_markers_asset.cc
@@ -73,7 +73,7 @@ ReelMarkersAsset::ReelMarkersAsset (cxml::ConstNodePtr node)
string
-ReelMarkersAsset::cpl_node_name (Standard) const
+ReelMarkersAsset::cpl_node_name() const
{
return "MainMarkers";
}
@@ -104,16 +104,16 @@ ReelMarkersAsset::get (Marker m) const
}
-xmlpp::Node*
-ReelMarkersAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+xmlpp::Element*
+ReelMarkersAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
int const tcr = edit_rate().numerator / edit_rate().denominator;
auto asset = ReelAsset::write_to_cpl (node, standard);
- auto ml = asset->add_child("MarkerList");
+ auto ml = cxml::add_child(asset, "MarkerList");
for (auto const& i: _markers) {
- auto m = ml->add_child("Marker");
- m->add_child("Label")->add_child_text(marker_to_string(i.first));
- m->add_child("Offset")->add_child_text(raw_convert<string>(i.second.as_editable_units_ceil(tcr)));
+ auto m = cxml::add_child(ml, "Marker");
+ cxml::add_text_child(m, "Label", marker_to_string(i.first));
+ cxml::add_text_child(m, "Offset", raw_convert<string>(i.second.as_editable_units_ceil(tcr)));
}
return asset;
diff --git a/src/reel_markers_asset.h b/src/reel_markers_asset.h
index 2a1480a2..059c0c1f 100644
--- a/src/reel_markers_asset.h
+++ b/src/reel_markers_asset.h
@@ -32,7 +32,7 @@
*/
-/** @file src/reel_markers_asset.cc
+/** @file src/reel_markers_asset.h
* @brief ReelMarkersAsset class
*/
@@ -51,7 +51,7 @@ public:
ReelMarkersAsset (Fraction edit_rate, int64_t intrinsic_duration);
explicit ReelMarkersAsset (std::shared_ptr<const cxml::Node>);
- xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
+ xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
bool equals(std::shared_ptr<const ReelMarkersAsset>, EqualityOptions const&, NoteHandler) const;
void set (Marker, Time);
@@ -62,7 +62,7 @@ public:
}
protected:
- std::string cpl_node_name (Standard) const override;
+ std::string cpl_node_name() const override;
private:
std::map<Marker, Time> _markers;
diff --git a/src/reel_mono_picture_asset.cc b/src/reel_mono_picture_asset.cc
index 9c44ec20..5dbf85d2 100644
--- a/src/reel_mono_picture_asset.cc
+++ b/src/reel_mono_picture_asset.cc
@@ -38,7 +38,7 @@
#include "reel_mono_picture_asset.h"
-#include "mono_picture_asset.h"
+#include "mono_j2k_picture_asset.h"
#include <libcxml/cxml.h>
@@ -47,7 +47,7 @@ using std::shared_ptr;
using namespace dcp;
-ReelMonoPictureAsset::ReelMonoPictureAsset (std::shared_ptr<MonoPictureAsset> asset, int64_t entry_point)
+ReelMonoPictureAsset::ReelMonoPictureAsset(std::shared_ptr<PictureAsset> asset, int64_t entry_point)
: ReelPictureAsset (asset, entry_point)
{
@@ -62,7 +62,7 @@ ReelMonoPictureAsset::ReelMonoPictureAsset (std::shared_ptr<const cxml::Node> no
string
-ReelMonoPictureAsset::cpl_node_name (Standard) const
+ReelMonoPictureAsset::cpl_node_name() const
{
return "MainPicture";
}
diff --git a/src/reel_mono_picture_asset.h b/src/reel_mono_picture_asset.h
index fb2dff70..0c468e0e 100644
--- a/src/reel_mono_picture_asset.h
+++ b/src/reel_mono_picture_asset.h
@@ -42,13 +42,14 @@
#include "reel_picture_asset.h"
-#include "mono_picture_asset.h"
+#include "mono_j2k_picture_asset.h"
+#include "mono_mpeg2_picture_asset.h"
namespace dcp {
-class MonoPictureAsset;
+class MonoJ2KPictureAsset;
/** @class ReelMonoPictureAsset
@@ -57,21 +58,31 @@ class MonoPictureAsset;
class ReelMonoPictureAsset : public ReelPictureAsset
{
public:
- ReelMonoPictureAsset (std::shared_ptr<MonoPictureAsset> asset, int64_t entry_point);
+ ReelMonoPictureAsset(std::shared_ptr<PictureAsset> asset, int64_t entry_point);
explicit ReelMonoPictureAsset (std::shared_ptr<const cxml::Node>);
- /** @return the MonoPictureAsset that this object refers to */
- std::shared_ptr<const MonoPictureAsset> mono_asset () const {
- return asset_of_type<const MonoPictureAsset>();
+ /** @return the MonoJ2KPictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const MonoJ2KPictureAsset> mono_j2k_asset() const {
+ return asset_of_type<const MonoJ2KPictureAsset>();
}
- /** @return the MonoPictureAsset that this object refers to */
- std::shared_ptr<MonoPictureAsset> mono_asset () {
- return asset_of_type<MonoPictureAsset>();
+ /** @return the MonoJ2KPictureAsset that this object refers to */
+ std::shared_ptr<MonoJ2KPictureAsset> mono_j2k_asset() {
+ return asset_of_type<MonoJ2KPictureAsset>();
+ }
+
+ /** @return the MonoMPEG2PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const MonoMPEG2PictureAsset> mono_mpeg2_asset() const {
+ return asset_of_type<const MonoMPEG2PictureAsset>();
+ }
+
+ /** @return the MonoMPEG2PictureAsset that this object refers to */
+ std::shared_ptr<MonoMPEG2PictureAsset> mono_mpeg2_asset() {
+ return asset_of_type<MonoMPEG2PictureAsset>();
}
private:
- std::string cpl_node_name (Standard standard) const override;
+ std::string cpl_node_name() const override;
};
diff --git a/src/reel_picture_asset.cc b/src/reel_picture_asset.cc
index eb87d039..37a6bfcc 100644
--- a/src/reel_picture_asset.cc
+++ b/src/reel_picture_asset.cc
@@ -39,7 +39,7 @@
#include "compose.hpp"
#include "dcp_assert.h"
-#include "picture_asset.h"
+#include "j2k_picture_asset.h"
#include "raw_convert.h"
#include "reel_picture_asset.h"
#include "warnings.h"
@@ -59,7 +59,7 @@ using boost::optional;
using namespace dcp;
-ReelPictureAsset::ReelPictureAsset (shared_ptr<PictureAsset> asset, int64_t entry_point)
+ReelPictureAsset::ReelPictureAsset(shared_ptr<PictureAsset> asset, int64_t entry_point)
: ReelFileAsset (asset, asset->key_id(), asset->id(), asset->edit_rate(), asset->intrinsic_duration(), entry_point)
, _frame_rate (asset->frame_rate ())
, _screen_aspect_ratio (asset->screen_aspect_ratio ())
@@ -86,12 +86,12 @@ ReelPictureAsset::ReelPictureAsset (shared_ptr<const cxml::Node> node)
}
-xmlpp::Node*
-ReelPictureAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+xmlpp::Element*
+ReelPictureAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
auto asset = ReelFileAsset::write_to_cpl (node, standard);
- asset->add_child("FrameRate")->add_child_text(String::compose("%1 %2", _frame_rate.numerator, _frame_rate.denominator));
+ cxml::add_text_child(asset, "FrameRate", String::compose("%1 %2", _frame_rate.numerator, _frame_rate.denominator));
if (standard == Standard::INTEROP) {
@@ -113,10 +113,12 @@ ReelPictureAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
}
}
- asset->add_child("ScreenAspectRatio")->add_child_text(raw_convert<string>(closest.get(), 2, true));
+ cxml::add_text_child(asset, "ScreenAspectRatio", raw_convert<string>(closest.get(), 2, true));
} else {
- asset->add_child("ScreenAspectRatio")->add_child_text(
- String::compose ("%1 %2", _screen_aspect_ratio.numerator, _screen_aspect_ratio.denominator)
+ cxml::add_text_child(
+ asset,
+ "ScreenAspectRatio",
+ String::compose("%1 %2", _screen_aspect_ratio.numerator, _screen_aspect_ratio.denominator)
);
}
diff --git a/src/reel_picture_asset.h b/src/reel_picture_asset.h
index bf7d40aa..9f42a5b6 100644
--- a/src/reel_picture_asset.h
+++ b/src/reel_picture_asset.h
@@ -42,7 +42,8 @@
#include "reel_file_asset.h"
-#include "picture_asset.h"
+#include "j2k_picture_asset.h"
+#include "mpeg2_picture_asset.h"
namespace dcp {
@@ -54,20 +55,41 @@ namespace dcp {
class ReelPictureAsset : public ReelFileAsset
{
public:
- ReelPictureAsset (std::shared_ptr<PictureAsset> asset, int64_t entry_point);
+ ReelPictureAsset(std::shared_ptr<PictureAsset> asset, int64_t entry_point);
explicit ReelPictureAsset (std::shared_ptr<const cxml::Node>);
- /** @return the PictureAsset that this object refers to */
- std::shared_ptr<const PictureAsset> asset () const {
+ /** @return the PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const PictureAsset> asset() const {
return asset_of_type<const PictureAsset>();
}
- /** @return the PictureAsset that this object refers to */
- std::shared_ptr<PictureAsset> asset () {
+ /** @return the PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<PictureAsset> asset() {
return asset_of_type<PictureAsset>();
}
- virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
+ /** @return the J2KPictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const J2KPictureAsset> j2k_asset() const {
+ return asset_of_type<const J2KPictureAsset>();
+ }
+
+ /** @return the J2KPictureAsset that this object refers to, if applicable */
+ std::shared_ptr<J2KPictureAsset> j2k_asset() {
+ return asset_of_type<J2KPictureAsset>();
+ }
+
+ /** @return the MPEG2PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<const MPEG2PictureAsset> mpeg2_asset() const {
+ return asset_of_type<const MPEG2PictureAsset>();
+ }
+
+ /** @return the MPEG2PictureAsset that this object refers to, if applicable */
+ std::shared_ptr<MPEG2PictureAsset> mpeg2_asset() {
+ return asset_of_type<MPEG2PictureAsset>();
+ }
+
+ virtual xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
+
bool equals(std::shared_ptr<const ReelPictureAsset>, EqualityOptions const&, NoteHandler) const;
/** @return picture frame rate */
diff --git a/src/reel_smpte_closed_caption_asset.h b/src/reel_smpte_closed_caption_asset.h
deleted file mode 100644
index 32a79efd..00000000
--- a/src/reel_smpte_closed_caption_asset.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
-
- This file is part of libdcp.
-
- libdcp 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.
-
- libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
-
- In addition, as a special exception, the copyright holders give
- permission to link the code of portions of this program with the
- OpenSSL library under certain conditions as described in each
- individual source file, and distribute linked combinations
- including the two.
-
- You must obey the GNU General Public License in all respects
- for all of the code used other than OpenSSL. If you modify
- file(s) with this exception, you may extend this exception to your
- version of the file(s), but you are not obligated to do so. If you
- do not wish to do so, delete this exception statement from your
- version. If you delete this exception statement from all source
- files in the program, then also delete it here.
-*/
-
-
-/** @file src/reel_smpte_closed_caption_asset.h
- * @brief ReelSMPTEClosedCaptionAsset class
- */
-
-
-#ifndef LIBDCP_REEL_SMPTE_CLOSED_CAPTION_ASSET_H
-#define LIBDCP_REEL_SMPTE_CLOSED_CAPTION_ASSET_H
-
-
-#include "reel_file_asset.h"
-#include "reel_closed_caption_asset.h"
-#include "smpte_subtitle_asset.h"
-
-
-namespace dcp {
-
-
-class ReelSMPTEClosedCaptionAsset : public ReelClosedCaptionAsset
-{
-public:
- ReelSMPTEClosedCaptionAsset (std::shared_ptr<SMPTESubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
- explicit ReelSMPTEClosedCaptionAsset (std::shared_ptr<const cxml::Node>);
-
- std::shared_ptr<SMPTESubtitleAsset> smpte_asset () {
- return asset_of_type<SMPTESubtitleAsset>();
- }
-
- std::shared_ptr<const SMPTESubtitleAsset> smpte_asset () const {
- return asset_of_type<const SMPTESubtitleAsset>();
- }
-
- xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
-
-
-private:
- boost::optional<std::string> key_type () const override {
- return std::string("MDSK");
- }
-
- std::string cpl_node_name (Standard) const override;
- std::pair<std::string, std::string> cpl_node_namespace () const override;
-};
-
-
-};
-
-
-#endif
-
diff --git a/src/reel_interop_closed_caption_asset.cc b/src/reel_smpte_text_asset.cc
index be968068..b1ce34cb 100644
--- a/src/reel_interop_closed_caption_asset.cc
+++ b/src/reel_smpte_text_asset.cc
@@ -32,7 +32,13 @@
*/
-#include "reel_interop_closed_caption_asset.h"
+/** @file src/reel_interop_text_asset.cc
+ * @brief ReelInteropTextAsset class
+ */
+
+
+#include "reel_smpte_text_asset.h"
+#include "smpte_text_asset.h"
#include "warnings.h"
LIBDCP_DISABLE_WARNINGS
#include <libxml++/libxml++.h>
@@ -43,44 +49,70 @@ using std::make_pair;
using std::pair;
using std::shared_ptr;
using std::string;
+using boost::optional;
using namespace dcp;
-ReelInteropClosedCaptionAsset::ReelInteropClosedCaptionAsset (shared_ptr<InteropSubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
- : ReelClosedCaptionAsset (asset, edit_rate, intrinsic_duration, entry_point)
+ReelSMPTETextAsset::ReelSMPTETextAsset(TextType type, shared_ptr<SMPTETextAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
+ : ReelTextAsset(type, asset, edit_rate, intrinsic_duration, entry_point)
{
}
-
-ReelInteropClosedCaptionAsset::ReelInteropClosedCaptionAsset (shared_ptr<const cxml::Node> node)
- : ReelClosedCaptionAsset (node)
+ReelSMPTETextAsset::ReelSMPTETextAsset(shared_ptr<const cxml::Node> node)
+ : ReelTextAsset(node)
{
node->done ();
}
+
string
-ReelInteropClosedCaptionAsset::cpl_node_name (Standard) const
+ReelSMPTETextAsset::cpl_node_name() const
{
- return "cc-cpl:MainClosedCaption";
+ switch (_type) {
+ case TextType::OPEN_SUBTITLE:
+ return "MainSubtitle";
+ case TextType::OPEN_CAPTION:
+ return "tt:MainCaption";
+ case TextType::CLOSED_SUBTITLE:
+ return "ClosedSubtitle";
+ case TextType::CLOSED_CAPTION:
+ return "tt:ClosedCaption";
+ }
+
+ DCP_ASSERT(false);
+ return "";
}
pair<string, string>
-ReelInteropClosedCaptionAsset::cpl_node_namespace () const
+ReelSMPTETextAsset::cpl_node_namespace() const
{
- return make_pair("http://www.digicine.com/PROTO-ASDCP-CC-CPL-20070926#", "cc-cpl");
+ switch (_type) {
+ case TextType::OPEN_SUBTITLE:
+ case TextType::CLOSED_SUBTITLE:
+ return {};
+ case TextType::OPEN_CAPTION:
+ case TextType::CLOSED_CAPTION:
+ return make_pair("http://www.smpte-ra.org/schemas/429-12/2008/TT", "tt");
+ }
+
+ DCP_ASSERT(false);
+ return {};
}
-xmlpp::Node *
-ReelInteropClosedCaptionAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+xmlpp::Element *
+ReelSMPTETextAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const
{
- auto asset = ReelClosedCaptionAsset::write_to_cpl (node, standard);
+ auto asset = ReelFileAsset::write_to_cpl (node, standard);
+ string const ns = _type == TextType::CLOSED_CAPTION ? "tt" : "";
if (_language) {
- asset->add_child("Language")->add_child_text(*_language);
+ cxml::add_child(asset, "Language", ns)->add_child_text(*_language);
}
return asset;
}
+
+
diff --git a/src/reel_smpte_subtitle_asset.h b/src/reel_smpte_text_asset.h
index 2a097309..b3c2f655 100644
--- a/src/reel_smpte_subtitle_asset.h
+++ b/src/reel_smpte_text_asset.h
@@ -32,38 +32,44 @@
*/
-/** @file src/reel_interop_subtitle_asset.h
- * @brief ReelInteropSubtitleAsset class
+/** @file src/reel_smpte_text_asset.h
+ * @brief ReelSMPTETextAsset class
*/
-#include "reel_subtitle_asset.h"
-#include "smpte_subtitle_asset.h"
+#include "reel_text_asset.h"
+#include "smpte_text_asset.h"
namespace dcp {
-class SMPTESubtitleAsset;
+class SMPTETextAsset;
-/** @class ReelSMPTESubtitleAsset
- * @brief Part of a Reel's description which refers to an SMPTE subtitle MXF file
+/** @class ReelSMPTETextAsset
+ * @brief Part of a Reel's description which refers to an SMPTE subtitle or caption MXF file
*/
-class ReelSMPTESubtitleAsset : public ReelSubtitleAsset
+class ReelSMPTETextAsset : public ReelTextAsset
{
public:
- ReelSMPTESubtitleAsset (std::shared_ptr<SMPTESubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
- explicit ReelSMPTESubtitleAsset (std::shared_ptr<const cxml::Node>);
+ ReelSMPTETextAsset(TextType type, std::shared_ptr<SMPTETextAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
+ explicit ReelSMPTETextAsset(std::shared_ptr<const cxml::Node>);
- std::shared_ptr<const SMPTESubtitleAsset> smpte_asset () const {
- return asset_of_type<const SMPTESubtitleAsset>();
+ std::shared_ptr<const SMPTETextAsset> smpte_asset() const {
+ return asset_of_type<const SMPTETextAsset>();
}
- std::shared_ptr<SMPTESubtitleAsset> smpte_asset () {
- return asset_of_type<SMPTESubtitleAsset>();
+ std::shared_ptr<SMPTETextAsset> smpte_asset() {
+ return asset_of_type<SMPTETextAsset>();
}
+ xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override;
+
+protected:
+ std::string cpl_node_name() const override;
+ std::pair<std::string, std::string> cpl_node_namespace() const override;
+
private:
boost::optional<std::string> key_type () const override {
return std::string("MDSK");
diff --git a/src/reel_sound_asset.cc b/src/reel_sound_asset.cc
index 1f2ddcdd..dbac6cb3 100644
--- a/src/reel_sound_asset.cc
+++ b/src/reel_sound_asset.cc
@@ -68,7 +68,7 @@ ReelSoundAsset::ReelSoundAsset (shared_ptr<const cxml::Node> node)
string
-ReelSoundAsset::cpl_node_name (Standard) const
+ReelSoundAsset::cpl_node_name() const
{
return "MainSound";
}
diff --git a/src/reel_sound_asset.h b/src/reel_sound_asset.h
index 16d629d1..6537ab5c 100644
--- a/src/reel_sound_asset.h
+++ b/src/reel_sound_asset.h
@@ -69,7 +69,7 @@ public:
private:
boost::optional<std::string> key_type () const override;
- std::string cpl_node_name (Standard standard) const override;
+ std::string cpl_node_name() const override;
};
diff --git a/src/reel_stereo_picture_asset.cc b/src/reel_stereo_picture_asset.cc
index 5bf4756c..2ee452d9 100644
--- a/src/reel_stereo_picture_asset.cc
+++ b/src/reel_stereo_picture_asset.cc
@@ -38,7 +38,7 @@
#include "reel_stereo_picture_asset.h"
-#include "stereo_picture_asset.h"
+#include "stereo_j2k_picture_asset.h"
#include <libcxml/cxml.h>
@@ -49,7 +49,7 @@ using std::shared_ptr;
using namespace dcp;
-ReelStereoPictureAsset::ReelStereoPictureAsset (std::shared_ptr<StereoPictureAsset> mxf, int64_t entry_point)
+ReelStereoPictureAsset::ReelStereoPictureAsset (std::shared_ptr<StereoJ2KPictureAsset> mxf, int64_t entry_point)
: ReelPictureAsset (mxf, entry_point)
{
@@ -64,7 +64,7 @@ ReelStereoPictureAsset::ReelStereoPictureAsset (std::shared_ptr<const cxml::Node
string
-ReelStereoPictureAsset::cpl_node_name (Standard) const
+ReelStereoPictureAsset::cpl_node_name() const
{
return "msp-cpl:MainStereoscopicPicture";
}
diff --git a/src/reel_stereo_picture_asset.h b/src/reel_stereo_picture_asset.h
index 7cac1c8b..0dd726a4 100644
--- a/src/reel_stereo_picture_asset.h
+++ b/src/reel_stereo_picture_asset.h
@@ -42,13 +42,13 @@
#include "reel_picture_asset.h"
-#include "stereo_picture_asset.h"
+#include "stereo_j2k_picture_asset.h"
namespace dcp {
-class StereoPictureAsset;
+class StereoJ2KPictureAsset;
/** @class ReelStereoPictureAsset
@@ -57,21 +57,21 @@ class StereoPictureAsset;
class ReelStereoPictureAsset : public ReelPictureAsset
{
public:
- ReelStereoPictureAsset (std::shared_ptr<StereoPictureAsset> content, int64_t entry_point);
+ ReelStereoPictureAsset (std::shared_ptr<StereoJ2KPictureAsset> content, int64_t entry_point);
explicit ReelStereoPictureAsset (std::shared_ptr<const cxml::Node>);
- /** @return the StereoPictureAsset that this object refers to */
- std::shared_ptr<const StereoPictureAsset> stereo_asset () const {
- return asset_of_type<const StereoPictureAsset>();
+ /** @return the StereoJ2KPictureAsset that this object refers to */
+ std::shared_ptr<const StereoJ2KPictureAsset> stereo_asset () const {
+ return asset_of_type<const StereoJ2KPictureAsset>();
}
- /** @return the StereoPictureAsset that this object refers to */
- std::shared_ptr<StereoPictureAsset> stereo_asset () {
- return asset_of_type<StereoPictureAsset>();
+ /** @return the StereoJ2KPictureAsset that this object refers to */
+ std::shared_ptr<StereoJ2KPictureAsset> stereo_asset () {
+ return asset_of_type<StereoJ2KPictureAsset>();
}
private:
- std::string cpl_node_name (Standard standard) const override;
+ std::string cpl_node_name() const override;
std::pair<std::string, std::string> cpl_node_attribute (Standard standard) const override;
};
diff --git a/src/reel_subtitle_asset.cc b/src/reel_text_asset.cc
index d856a05e..248a2ab3 100644
--- a/src/reel_subtitle_asset.cc
+++ b/src/reel_text_asset.cc
@@ -32,15 +32,14 @@
*/
-/** @file src/reel_subtitle_asset.cc
- * @brief ReelSubtitleAsset class
+/** @file src/reel_text_asset.cc
+ * @brief ReelTextAsset class
*/
#include "language_tag.h"
-#include "reel_subtitle_asset.h"
-#include "smpte_subtitle_asset.h"
-#include "subtitle_asset.h"
+#include "reel_text_asset.h"
+#include "smpte_text_asset.h"
#include "warnings.h"
LIBDCP_DISABLE_WARNINGS
#include <libxml++/libxml++.h>
@@ -54,43 +53,45 @@ using boost::optional;
using namespace dcp;
-ReelSubtitleAsset::ReelSubtitleAsset (std::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
+ReelTextAsset::ReelTextAsset(TextType type, std::shared_ptr<TextAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
: ReelFileAsset (
asset,
- dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : boost::none,
+ dynamic_pointer_cast<SMPTETextAsset>(asset) ? dynamic_pointer_cast<SMPTETextAsset>(asset)->key_id() : boost::none,
asset->id(),
edit_rate,
intrinsic_duration,
entry_point
)
+ , _type(type)
{
}
-ReelSubtitleAsset::ReelSubtitleAsset (std::shared_ptr<const cxml::Node> node)
+ReelTextAsset::ReelTextAsset(std::shared_ptr<const cxml::Node> node)
: ReelFileAsset (node)
{
- _language = node->optional_string_child("Language");
-}
-
+ if (node->name() == "MainSubtitle") {
+ _type = TextType::OPEN_SUBTITLE;
+ } else if (node->name() == "MainClosedCaption" || node->name() == "ClosedCaption") {
+ _type = TextType::CLOSED_CAPTION;
+ } else {
+ DCP_ASSERT(false);
+ }
-string
-ReelSubtitleAsset::cpl_node_name (Standard) const
-{
- return "MainSubtitle";
+ _language = node->optional_string_child("Language");
}
void
-ReelSubtitleAsset::set_language (dcp::LanguageTag language)
+ReelTextAsset::set_language(dcp::LanguageTag language)
{
_language = language.to_string();
}
bool
-ReelSubtitleAsset::equals(shared_ptr<const ReelSubtitleAsset> other, EqualityOptions const& opt, NoteHandler note) const
+ReelTextAsset::equals(shared_ptr<const ReelTextAsset> other, EqualityOptions const& opt, NoteHandler note) const
{
if (!asset_equals (other, opt, note)) {
return false;
@@ -102,15 +103,3 @@ ReelSubtitleAsset::equals(shared_ptr<const ReelSubtitleAsset> other, EqualityOpt
return true;
}
-
-xmlpp::Node *
-ReelSubtitleAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
-{
- auto asset = ReelFileAsset::write_to_cpl (node, standard);
- if (_language) {
- asset->add_child("Language")->add_child_text(*_language);
- }
- return asset;
-}
-
-
diff --git a/src/reel_subtitle_asset.h b/src/reel_text_asset.h
index 8b694fd6..35efe941 100644
--- a/src/reel_subtitle_asset.h
+++ b/src/reel_text_asset.h
@@ -32,50 +32,50 @@
*/
-/** @file src/reel_subtitle_asset.h
- * @brief ReelSubtitleAsset class.
+/** @file src/reel_text_asset.h
+ * @brief ReelTextAsset class.
*/
-#ifndef LIBDCP_REEL_SUBTITLE_ASSET_H
-#define LIBDCP_REEL_SUBTITLE_ASSET_H
+#ifndef LIBDCP_REEL_TEXT_ASSET_H
+#define LIBDCP_REEL_TEXT_ASSET_H
#include "language_tag.h"
#include "reel_asset.h"
#include "reel_file_asset.h"
-#include "subtitle_asset.h"
+#include "text_asset.h"
+#include "text_type.h"
struct verify_invalid_language1;
+struct verify_invalid_language2;
namespace dcp {
-class SubtitleAsset;
+class TextAsset;
-/** @class ReelSubtitleAsset
- * @brief Part of a Reel's description which refers to a subtitle XML/MXF file
+/** @class ReelTextAsset
+ * @brief Part of a Reel's description which refers to a subtitle or caption XML/MXF file
*/
-class ReelSubtitleAsset : public ReelFileAsset
+class ReelTextAsset : public ReelFileAsset
{
public:
- ReelSubtitleAsset (std::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
- explicit ReelSubtitleAsset (std::shared_ptr<const cxml::Node>);
+ ReelTextAsset(TextType type, std::shared_ptr<TextAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point);
+ explicit ReelTextAsset(std::shared_ptr<const cxml::Node>);
- std::shared_ptr<const SubtitleAsset> asset () const {
- return asset_of_type<const SubtitleAsset>();
+ std::shared_ptr<const TextAsset> asset() const {
+ return asset_of_type<const TextAsset>();
}
- std::shared_ptr<SubtitleAsset> asset () {
- return asset_of_type<SubtitleAsset>();
+ std::shared_ptr<TextAsset> asset() {
+ return asset_of_type<TextAsset>();
}
- xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const override;
-
- bool equals(std::shared_ptr<const ReelSubtitleAsset>, EqualityOptions const&, NoteHandler) const;
+ bool equals(std::shared_ptr<const ReelTextAsset>, EqualityOptions const&, NoteHandler) const;
void set_language (dcp::LanguageTag language);
@@ -83,17 +83,20 @@ public:
return _language;
}
+ TextType type() const {
+ return _type;
+ }
+
protected:
+ friend struct ::verify_invalid_language1;
+ friend struct ::verify_invalid_language2;
+
/** As in other places, this is stored and returned as a string so that
* we can tolerate non-RFC-5646 strings, but must be set as a dcp::LanguageTag
* to try to ensure that we create compliant output.
*/
boost::optional<std::string> _language;
-
-private:
- friend struct ::verify_invalid_language1;
-
- std::string cpl_node_name (Standard standard) const override;
+ TextType _type;
};
diff --git a/src/rgb_xyz.h b/src/rgb_xyz.h
index c41fdee0..315295ea 100644
--- a/src/rgb_xyz.h
+++ b/src/rgb_xyz.h
@@ -32,7 +32,7 @@
*/
-/** @file rgb_xyz.h
+/** @file src/rgb_xyz.h
* @brief Conversion between RGB and XYZ
*/
diff --git a/src/smpte_subtitle_asset.cc b/src/smpte_text_asset.cc
index 0ff1d7ef..f92a091a 100644
--- a/src/smpte_subtitle_asset.cc
+++ b/src/smpte_text_asset.cc
@@ -32,8 +32,8 @@
*/
-/** @file src/smpte_subtitle_asset.cc
- * @brief SMPTESubtitleAsset class
+/** @file src/smpte_text_asset.cc
+ * @brief SMPTETextAsset class
*/
@@ -45,8 +45,8 @@
#include "filesystem.h"
#include "raw_convert.h"
#include "smpte_load_font_node.h"
-#include "smpte_subtitle_asset.h"
-#include "subtitle_image.h"
+#include "smpte_text_asset.h"
+#include "text_image.h"
#include "util.h"
#include "warnings.h"
#include "xml.h"
@@ -79,7 +79,7 @@ static string const subtitle_smpte_ns_2010 = "http://www.smpte-ra.org/schemas/42
static string const subtitle_smpte_ns_2014 = "http://www.smpte-ra.org/schemas/428-7/2014/DCST";
-SMPTESubtitleAsset::SMPTESubtitleAsset(SubtitleStandard standard)
+SMPTETextAsset::SMPTETextAsset(SubtitleStandard standard)
: MXF(Standard::SMPTE)
, _edit_rate (24, 1)
, _time_code_rate (24)
@@ -90,12 +90,13 @@ SMPTESubtitleAsset::SMPTESubtitleAsset(SubtitleStandard standard)
}
-SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file)
- : SubtitleAsset (file)
+SMPTETextAsset::SMPTETextAsset(boost::filesystem::path file)
+ : TextAsset (file)
{
auto xml = make_shared<cxml::Document>("SubtitleReel");
- auto reader = make_shared<ASDCP::TimedText::MXFReader>();
+ Kumu::FileReaderFactory factory;
+ auto reader = make_shared<ASDCP::TimedText::MXFReader>(factory);
auto r = Kumu::RESULT_OK;
{
ASDCPErrorSuspender sus;
@@ -139,8 +140,8 @@ 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...
*/
- for (auto i: _subtitles) {
- auto im = dynamic_pointer_cast<SubtitleImage>(i);
+ for (auto i: _texts) {
+ auto im = dynamic_pointer_cast<TextImage>(i);
if (im && im->png_image().size() == 0) {
/* Even more dubious; allow <id>.png or urn:uuid:<id>.png */
auto p = file.parent_path() / String::compose("%1.png", im->id());
@@ -158,17 +159,17 @@ SMPTESubtitleAsset::SMPTESubtitleAsset (boost::filesystem::path file)
}
/* Check that all required image data have been found */
- for (auto i: _subtitles) {
- auto im = dynamic_pointer_cast<SubtitleImage>(i);
+ for (auto i: _texts) {
+ auto im = dynamic_pointer_cast<TextImage>(i);
if (im && im->png_image().size() == 0) {
- throw MissingSubtitleImageError (im->id());
+ throw MissingTextImageError (im->id());
}
}
}
void
-SMPTESubtitleAsset::parse_xml (shared_ptr<cxml::Document> xml)
+SMPTETextAsset::parse_xml(shared_ptr<cxml::Document> xml)
{
if (xml->namespace_uri() == subtitle_smpte_ns_2007) {
_subtitle_standard = SubtitleStandard::SMPTE_2007;
@@ -211,17 +212,17 @@ SMPTESubtitleAsset::parse_xml (shared_ptr<cxml::Document> xml)
for (auto i: xml->node()->get_children()) {
auto const e = dynamic_cast<xmlpp::Element const *>(i);
if (e && e->get_name() == "SubtitleList") {
- parse_subtitles (e, ps, _time_code_rate, Standard::SMPTE);
+ parse_texts(e, ps, _time_code_rate, Standard::SMPTE);
}
}
/* Guess intrinsic duration */
- _intrinsic_duration = latest_subtitle_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator);
+ _intrinsic_duration = latest_text_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator);
}
void
-SMPTESubtitleAsset::read_mxf_resources (shared_ptr<ASDCP::TimedText::MXFReader> reader, shared_ptr<DecryptionContext> dec)
+SMPTETextAsset::read_mxf_resources(shared_ptr<ASDCP::TimedText::MXFReader> reader, shared_ptr<DecryptionContext> dec)
{
ASDCP::TimedText::TimedTextDescriptor descriptor;
reader->FillTimedTextDescriptor (descriptor);
@@ -265,13 +266,13 @@ SMPTESubtitleAsset::read_mxf_resources (shared_ptr<ASDCP::TimedText::MXFReader>
}
case ASDCP::TimedText::MT_PNG:
{
- auto j = _subtitles.begin();
- while (j != _subtitles.end() && ((!dynamic_pointer_cast<SubtitleImage>(*j)) || dynamic_pointer_cast<SubtitleImage>(*j)->id() != id)) {
+ auto j = _texts.begin();
+ while (j != _texts.end() && ((!dynamic_pointer_cast<TextImage>(*j)) || dynamic_pointer_cast<TextImage>(*j)->id() != id)) {
++j;
}
- if (j != _subtitles.end()) {
- dynamic_pointer_cast<SubtitleImage>(*j)->set_png_image(ArrayData(buffer.RoData(), buffer.Size()));
+ if (j != _texts.end()) {
+ dynamic_pointer_cast<TextImage>(*j)->set_png_image(ArrayData(buffer.RoData(), buffer.Size()));
}
break;
}
@@ -283,7 +284,7 @@ SMPTESubtitleAsset::read_mxf_resources (shared_ptr<ASDCP::TimedText::MXFReader>
void
-SMPTESubtitleAsset::read_mxf_descriptor (shared_ptr<ASDCP::TimedText::MXFReader> reader)
+SMPTETextAsset::read_mxf_descriptor(shared_ptr<ASDCP::TimedText::MXFReader> reader)
{
ASDCP::TimedText::TimedTextDescriptor descriptor;
reader->FillTimedTextDescriptor (descriptor);
@@ -300,7 +301,7 @@ SMPTESubtitleAsset::read_mxf_descriptor (shared_ptr<ASDCP::TimedText::MXFReader>
void
-SMPTESubtitleAsset::set_key (Key key)
+SMPTETextAsset::set_key(Key key)
{
/* See if we already have a key; if we do, and we have a file, we'll already
have read that file.
@@ -320,7 +321,8 @@ SMPTESubtitleAsset::set_key (Key key)
/* Our data was encrypted; now we can decrypt it */
- auto reader = make_shared<ASDCP::TimedText::MXFReader>();
+ Kumu::FileReaderFactory factory;
+ auto reader = make_shared<ASDCP::TimedText::MXFReader>(factory);
auto r = reader->OpenRead(dcp::filesystem::fix_long_path(*_file).string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (
@@ -343,7 +345,7 @@ SMPTESubtitleAsset::set_key (Key key)
vector<shared_ptr<LoadFontNode>>
-SMPTESubtitleAsset::load_font_nodes () const
+SMPTETextAsset::load_font_nodes() const
{
vector<shared_ptr<LoadFontNode>> lf;
copy (_load_font_nodes.begin(), _load_font_nodes.end(), back_inserter(lf));
@@ -352,9 +354,10 @@ SMPTESubtitleAsset::load_font_nodes () const
bool
-SMPTESubtitleAsset::valid_mxf (boost::filesystem::path file)
+SMPTETextAsset::valid_mxf(boost::filesystem::path file)
{
- ASDCP::TimedText::MXFReader reader;
+ Kumu::FileReaderFactory factory;
+ ASDCP::TimedText::MXFReader reader(factory);
Kumu::DefaultLogSink().UnsetFilterFlag(Kumu::LOG_ALLOW_ALL);
auto r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
Kumu::DefaultLogSink().SetFilterFlag(Kumu::LOG_ALLOW_ALL);
@@ -363,44 +366,44 @@ SMPTESubtitleAsset::valid_mxf (boost::filesystem::path file)
string
-SMPTESubtitleAsset::xml_as_string () const
+SMPTETextAsset::xml_as_string() const
{
xmlpp::Document doc;
auto root = doc.create_root_node ("SubtitleReel");
DCP_ASSERT (_xml_id);
- root->add_child("Id")->add_child_text("urn:uuid:" + *_xml_id);
- root->add_child("ContentTitleText")->add_child_text(_content_title_text);
+ cxml::add_text_child(root, "Id", "urn:uuid:" + *_xml_id);
+ cxml::add_text_child(root, "ContentTitleText", _content_title_text);
if (_annotation_text) {
- root->add_child("AnnotationText")->add_child_text(_annotation_text.get());
+ cxml::add_text_child(root, "AnnotationText", _annotation_text.get());
}
- root->add_child("IssueDate")->add_child_text(_issue_date.as_string(false, false));
+ cxml::add_text_child(root, "IssueDate", _issue_date.as_string(false, false));
if (_reel_number) {
- root->add_child("ReelNumber")->add_child_text(raw_convert<string>(_reel_number.get()));
+ cxml::add_text_child(root, "ReelNumber", raw_convert<string>(_reel_number.get()));
}
if (_language) {
- root->add_child("Language")->add_child_text(_language.get());
+ cxml::add_text_child(root, "Language", _language.get());
}
- root->add_child("EditRate")->add_child_text(_edit_rate.as_string());
- root->add_child("TimeCodeRate")->add_child_text(raw_convert<string>(_time_code_rate));
+ cxml::add_text_child(root, "EditRate", _edit_rate.as_string());
+ cxml::add_text_child(root, "TimeCodeRate", raw_convert<string>(_time_code_rate));
if (_start_time) {
- root->add_child("StartTime")->add_child_text(_start_time.get().as_string(Standard::SMPTE));
+ cxml::add_text_child(root, "StartTime", _start_time.get().as_string(Standard::SMPTE));
}
for (auto i: _load_font_nodes) {
- auto load_font = root->add_child("LoadFont");
+ auto load_font = cxml::add_child(root, "LoadFont");
load_font->add_child_text ("urn:uuid:" + i->urn);
load_font->set_attribute ("ID", i->id);
}
- subtitles_as_xml (root->add_child("SubtitleList"), _time_code_rate, Standard::SMPTE);
+ texts_as_xml(cxml::add_child(root, "SubtitleList"), _time_code_rate, Standard::SMPTE);
return format_xml(doc, std::make_pair(string{}, schema_namespace()));
}
void
-SMPTESubtitleAsset::write (boost::filesystem::path p) const
+SMPTETextAsset::write(boost::filesystem::path p) const
{
EncryptionContext enc (key(), Standard::SMPTE);
@@ -430,8 +433,8 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const
/* Image subtitle references */
- for (auto i: _subtitles) {
- auto si = dynamic_pointer_cast<SubtitleImage>(i);
+ for (auto i: _texts) {
+ auto si = dynamic_pointer_cast<TextImage>(i);
if (si) {
ASDCP::TimedText::TimedTextResourceDescriptor res;
unsigned int c;
@@ -453,7 +456,7 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const
/* This header size is a guess. Empirically it seems that each subtitle reference is 90 bytes, and we need some extra.
The default size is not enough for some feature-length PNG sub projects (see DCP-o-matic #1561).
*/
- ASDCP::Result_t r = writer.OpenWrite(dcp::filesystem::fix_long_path(p).string().c_str(), writer_info, descriptor, _subtitles.size() * 90 + 16384);
+ ASDCP::Result_t r = writer.OpenWrite(dcp::filesystem::fix_long_path(p).string().c_str(), writer_info, descriptor, _texts.size() * 90 + 16384);
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open subtitle MXF for writing", p.string(), r));
}
@@ -486,9 +489,8 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const
/* Image subtitle payload */
- for (auto i: _subtitles) {
- auto si = dynamic_pointer_cast<SubtitleImage>(i);
- if (si) {
+ for (auto i: _texts) {
+ if (auto si = dynamic_pointer_cast<TextImage>(i)) {
ASDCP::TimedText::FrameBuffer buffer;
buffer.SetData (si->png_image().data(), si->png_image().size());
buffer.Size (si->png_image().size());
@@ -505,15 +507,15 @@ SMPTESubtitleAsset::write (boost::filesystem::path p) const
}
bool
-SMPTESubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const& options, NoteHandler note) const
+SMPTETextAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const& options, NoteHandler note) const
{
- if (!SubtitleAsset::equals (other_asset, options, note)) {
+ if (!TextAsset::equals (other_asset, options, note)) {
return false;
}
- auto other = dynamic_pointer_cast<const SMPTESubtitleAsset>(other_asset);
+ auto other = dynamic_pointer_cast<const SMPTETextAsset>(other_asset);
if (!other) {
- note (NoteType::ERROR, "Subtitles are in different standards");
+ note (NoteType::ERROR, "Subtitles/captions are in different standards");
return false;
}
@@ -536,46 +538,46 @@ SMPTESubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions
}
if (_content_title_text != other->_content_title_text) {
- note (NoteType::ERROR, "Subtitle content title texts differ");
+ note (NoteType::ERROR, "Subtitle/caption content title texts differ");
return false;
}
if (_language != other->_language) {
- note (NoteType::ERROR, String::compose("Subtitle languages differ (`%1' vs `%2')", _language.get_value_or("[none]"), other->_language.get_value_or("[none]")));
+ note (NoteType::ERROR, String::compose("Subtitle/caption languages differ (`%1' vs `%2')", _language.get_value_or("[none]"), other->_language.get_value_or("[none]")));
return false;
}
if (_annotation_text != other->_annotation_text) {
- note (NoteType::ERROR, "Subtitle annotation texts differ");
+ note (NoteType::ERROR, "Subtitle/caption annotation texts differ");
return false;
}
if (_issue_date != other->_issue_date) {
if (options.issue_dates_can_differ) {
- note (NoteType::NOTE, "Subtitle issue dates differ");
+ note (NoteType::NOTE, "Subtitle/caption issue dates differ");
} else {
- note (NoteType::ERROR, "Subtitle issue dates differ");
+ note (NoteType::ERROR, "Subtitle/caption issue dates differ");
return false;
}
}
if (_reel_number != other->_reel_number) {
- note (NoteType::ERROR, "Subtitle reel numbers differ");
+ note (NoteType::ERROR, "Subtitle/caption reel numbers differ");
return false;
}
if (_edit_rate != other->_edit_rate) {
- note (NoteType::ERROR, "Subtitle edit rates differ");
+ note (NoteType::ERROR, "Subtitle/caption edit rates differ");
return false;
}
if (_time_code_rate != other->_time_code_rate) {
- note (NoteType::ERROR, "Subtitle time code rates differ");
+ note (NoteType::ERROR, "Subtitle/caption time code rates differ");
return false;
}
if (_start_time != other->_start_time) {
- note (NoteType::ERROR, "Subtitle start times differ");
+ note (NoteType::ERROR, "Subtitle/caption start times differ");
return false;
}
@@ -584,7 +586,7 @@ SMPTESubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions
void
-SMPTESubtitleAsset::add_font (string load_id, dcp::ArrayData data)
+SMPTETextAsset::add_font(string load_id, dcp::ArrayData data)
{
string const uuid = make_uuid ();
_fonts.push_back (Font(load_id, uuid, data));
@@ -593,15 +595,15 @@ SMPTESubtitleAsset::add_font (string load_id, dcp::ArrayData data)
void
-SMPTESubtitleAsset::add (shared_ptr<Subtitle> s)
+SMPTETextAsset::add(shared_ptr<Text> s)
{
- SubtitleAsset::add (s);
- _intrinsic_duration = latest_subtitle_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator);
+ TextAsset::add(s);
+ _intrinsic_duration = latest_text_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator);
}
string
-SMPTESubtitleAsset::schema_namespace() const
+SMPTETextAsset::schema_namespace() const
{
switch (_subtitle_standard) {
case SubtitleStandard::SMPTE_2007:
diff --git a/src/smpte_subtitle_asset.h b/src/smpte_text_asset.h
index 26144fe1..24665d3a 100644
--- a/src/smpte_subtitle_asset.h
+++ b/src/smpte_text_asset.h
@@ -32,12 +32,12 @@
*/
-#ifndef LIBDCP_SMPTE_SUBTITLE_ASSET_H
-#define LIBDCP_SMPTE_SUBTITLE_ASSET_H
+#ifndef LIBDCP_SMPTE_TEXT_ASSET_H
+#define LIBDCP_SMPTE_TEXT_ASSET_H
-/** @file src/smpte_subtitle_asset.h
- * @brief SMPTESubtitleAsset class
+/** @file src/smpte_text_asset.h
+ * @brief SMPTETextAsset class
*/
@@ -45,7 +45,7 @@
#include "language_tag.h"
#include "local_time.h"
#include "mxf.h"
-#include "subtitle_asset.h"
+#include "text_asset.h"
#include "subtitle_standard.h"
#include <boost/filesystem.hpp>
@@ -69,18 +69,18 @@ namespace dcp {
class SMPTELoadFontNode;
-/** @class SMPTESubtitleAsset
- * @brief A set of subtitles to be read and/or written in the SMPTE format
+/** @class SMPTETextAsset
+ * @brief A set of subtitles/captions to be read and/or written in the SMPTE format
*/
-class SMPTESubtitleAsset : public SubtitleAsset, public MXF
+class SMPTETextAsset : public TextAsset, public MXF
{
public:
- explicit SMPTESubtitleAsset(SubtitleStandard standard = SubtitleStandard::SMPTE_2014);
+ explicit SMPTETextAsset(SubtitleStandard standard = SubtitleStandard::SMPTE_2014);
- /** Construct a SMPTESubtitleAsset by reading an MXF or XML file
+ /** Construct a SMPTETextAsset by reading an MXF or XML file
* @param file Filename
*/
- explicit SMPTESubtitleAsset (boost::filesystem::path file);
+ explicit SMPTETextAsset(boost::filesystem::path file);
bool equals (
std::shared_ptr<const Asset>,
@@ -95,7 +95,7 @@ public:
/** Write this content to a MXF file */
void write (boost::filesystem::path path) const override;
- void add (std::shared_ptr<Subtitle>) override;
+ void add(std::shared_ptr<Text>) override;
void add_font (std::string id, dcp::ArrayData data) override;
void set_key (Key key) override;
@@ -135,7 +135,7 @@ public:
return _intrinsic_duration;
}
- /** @return title of the film that these subtitles are for,
+ /** @return title of the film that these subtitles/captions are for,
* to be presented to the user
*/
std::string content_title_text () const {
@@ -167,8 +167,8 @@ public:
return _edit_rate;
}
- /** @return subdivision of 1 second that is used for subtitle times;
- * e.g. a time_code_rate of 250 means that a subtitle time of 0:0:0:001
+ /** @return subdivision of 1 second that is used for text times;
+ * e.g. a time_code_rate of 250 means that a text time of 0:0:0:001
* represents 4ms.
*/
int time_code_rate () const override {
diff --git a/src/sound_asset.cc b/src/sound_asset.cc
index 0ceba53d..c73255b8 100644
--- a/src/sound_asset.cc
+++ b/src/sound_asset.cc
@@ -70,7 +70,8 @@ using namespace dcp;
SoundAsset::SoundAsset (boost::filesystem::path file)
: Asset (file)
{
- ASDCP::PCM::MXFReader reader;
+ Kumu::FileReaderFactory factory;
+ ASDCP::PCM::MXFReader reader(factory);
auto r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", file.string(), r));
@@ -82,6 +83,7 @@ SoundAsset::SoundAsset (boost::filesystem::path file)
}
_sampling_rate = desc.AudioSamplingRate.Denominator ? (desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator) : 0;
+ _bit_depth = desc.QuantizationBits;
_channels = desc.ChannelCount;
_edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
@@ -138,14 +140,15 @@ SoundAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, No
return true;
}
- ASDCP::PCM::MXFReader reader_A;
+ Kumu::FileReaderFactory factory;
+ ASDCP::PCM::MXFReader reader_A(factory);
DCP_ASSERT (file());
auto r = reader_A.OpenRead(dcp::filesystem::fix_long_path(*file()).string().c_str());
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", file()->string(), r));
}
- ASDCP::PCM::MXFReader reader_B;
+ ASDCP::PCM::MXFReader reader_B(factory);
r = reader_B.OpenRead(dcp::filesystem::fix_long_path(*other->file()).string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", other->file()->string(), r));
@@ -278,7 +281,8 @@ SoundAsset::static_pkl_type (Standard standard)
bool
SoundAsset::valid_mxf (boost::filesystem::path file)
{
- ASDCP::PCM::MXFReader reader;
+ Kumu::FileReaderFactory factory;
+ ASDCP::PCM::MXFReader reader(factory);
Kumu::Result_t r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
return !ASDCP_FAILURE (r);
}
diff --git a/src/sound_asset.h b/src/sound_asset.h
index e69c3988..e5acb119 100644
--- a/src/sound_asset.h
+++ b/src/sound_asset.h
@@ -115,6 +115,13 @@ public:
return _sampling_rate;
}
+ /** @return Bit depth of samples. This should always be 24, but we return it
+ * so the verification code can check
+ */
+ int bit_depth() const {
+ return _bit_depth;
+ }
+
Fraction edit_rate () const {
return _edit_rate;
}
@@ -148,6 +155,7 @@ private:
int _channels = 0; ///< number of channels in the MXF
boost::optional<int> _active_channels; ///< estimate of the number of active channels
int _sampling_rate = 0; ///< sampling rate in Hz
+ int _bit_depth = 24;
boost::optional<std::string> _language;
};
diff --git a/src/sound_frame.cc b/src/sound_frame.cc
index 25845d88..4d90c9c2 100644
--- a/src/sound_frame.cc
+++ b/src/sound_frame.cc
@@ -37,6 +37,7 @@
*/
+#include "dcp_assert.h"
#include "sound_frame.h"
#include <asdcp/AS_DCP.h>
#include <iostream>
@@ -52,15 +53,28 @@ SoundFrame::SoundFrame (ASDCP::PCM::MXFReader* reader, int n, std::shared_ptr<co
ASDCP::PCM::AudioDescriptor desc;
reader->FillAudioDescriptor (desc);
_channels = desc.ChannelCount;
+ _bits = desc.QuantizationBits;
}
int32_t
SoundFrame::get (int channel, int frame) const
{
- uint8_t const * d = data() + (frame * _channels * 3) + (channel * 3);
- /* This is slightly dubious I think */
- return (d[0] << 8 | (d[1] << 16) | (d[2] << 24)) >> 8;
+ switch (_bits) {
+ case 24:
+ {
+ uint8_t const * d = data() + (frame * _channels * 3) + (channel * 3);
+ /* This is slightly dubious I think */
+ return (d[0] << 8 | (d[1] << 16) | (d[2] << 24)) >> 8;
+ }
+ case 16:
+ {
+ uint8_t const * d = data() + (frame * _channels * 2) + (channel * 2);
+ return d[0] | (d[1] << 8);
+ }
+ default:
+ DCP_ASSERT(false);
+ }
}
@@ -74,5 +88,5 @@ SoundFrame::channels () const
int
SoundFrame::samples () const
{
- return size() / (_channels * 3);
+ return size() / (_channels * _bits / 8);
}
diff --git a/src/sound_frame.h b/src/sound_frame.h
index 0f5021e2..72ab5925 100644
--- a/src/sound_frame.h
+++ b/src/sound_frame.h
@@ -54,10 +54,16 @@ public:
SoundFrame (ASDCP::PCM::MXFReader* reader, int n, std::shared_ptr<const DecryptionContext> c, bool check_hmac);
int channels () const;
int samples () const;
+
+ int bits() const {
+ return _bits;
+ }
+
int32_t get (int channel, int sample) const;
private:
- int _channels = 0;
+ int _channels;
+ int _bits;
};
diff --git a/src/stereo_picture_asset.cc b/src/stereo_j2k_picture_asset.cc
index 2ce3cdc9..6a5e7d79 100644
--- a/src/stereo_picture_asset.cc
+++ b/src/stereo_j2k_picture_asset.cc
@@ -33,7 +33,7 @@
/** @file src/stereo_picture_asset.cc
- * @brief StereoPictureAsset class
+ * @brief StereoJ2KPictureAsset class
*/
@@ -41,10 +41,10 @@
#include "equality_options.h"
#include "exceptions.h"
#include "filesystem.h"
-#include "stereo_picture_asset.h"
-#include "stereo_picture_asset_reader.h"
-#include "stereo_picture_asset_writer.h"
-#include "stereo_picture_frame.h"
+#include "stereo_j2k_picture_asset.h"
+#include "stereo_j2k_picture_asset_reader.h"
+#include "stereo_j2k_picture_asset_writer.h"
+#include "stereo_j2k_picture_frame.h"
#include <asdcp/AS_DCP.h>
@@ -56,10 +56,11 @@ using std::dynamic_pointer_cast;
using namespace dcp;
-StereoPictureAsset::StereoPictureAsset (boost::filesystem::path file)
- : PictureAsset (file)
+StereoJ2KPictureAsset::StereoJ2KPictureAsset (boost::filesystem::path file)
+ : J2KPictureAsset (file)
{
- ASDCP::JP2K::MXFSReader reader;
+ Kumu::FileReaderFactory factory;
+ ASDCP::JP2K::MXFSReader reader(factory);
auto r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("could not open MXF file for reading", file.string(), r));
@@ -81,38 +82,39 @@ StereoPictureAsset::StereoPictureAsset (boost::filesystem::path file)
}
-StereoPictureAsset::StereoPictureAsset (Fraction edit_rate, Standard standard)
- : PictureAsset (edit_rate, standard)
+StereoJ2KPictureAsset::StereoJ2KPictureAsset (Fraction edit_rate, Standard standard)
+ : J2KPictureAsset (edit_rate, standard)
{
}
-shared_ptr<PictureAssetWriter>
-StereoPictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
+shared_ptr<J2KPictureAssetWriter>
+StereoJ2KPictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
{
- return shared_ptr<StereoPictureAssetWriter>(new StereoPictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
+ return shared_ptr<StereoJ2KPictureAssetWriter>(new StereoJ2KPictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
}
-shared_ptr<StereoPictureAssetReader>
-StereoPictureAsset::start_read () const
+shared_ptr<StereoJ2KPictureAssetReader>
+StereoJ2KPictureAsset::start_read () const
{
- return shared_ptr<StereoPictureAssetReader> (new StereoPictureAssetReader(this, key(), standard()));
+ return shared_ptr<StereoJ2KPictureAssetReader> (new StereoJ2KPictureAssetReader(this, key(), standard()));
}
bool
-StereoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, NoteHandler note) const
+StereoJ2KPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, NoteHandler note) const
{
- ASDCP::JP2K::MXFSReader reader_A;
+ Kumu::FileReaderFactory factory;
+ ASDCP::JP2K::MXFSReader reader_A(factory);
DCP_ASSERT (file());
auto r = reader_A.OpenRead(dcp::filesystem::fix_long_path(*file()).string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", file()->string(), r));
}
- ASDCP::JP2K::MXFSReader reader_B;
+ ASDCP::JP2K::MXFSReader reader_B(factory);
DCP_ASSERT (other->file());
r = reader_B.OpenRead(dcp::filesystem::fix_long_path(*other->file()).string().c_str());
if (ASDCP_FAILURE (r)) {
@@ -132,7 +134,7 @@ StereoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const&
return false;
}
- auto other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
+ auto other_picture = dynamic_pointer_cast<const StereoJ2KPictureAsset> (other);
DCP_ASSERT (other_picture);
auto reader = start_read ();
@@ -141,8 +143,8 @@ StereoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const&
bool result = true;
for (int i = 0; i < _intrinsic_duration; ++i) {
- shared_ptr<const StereoPictureFrame> frame_A;
- shared_ptr<const StereoPictureFrame> frame_B;
+ shared_ptr<const StereoJ2KPictureFrame> frame_A;
+ shared_ptr<const StereoJ2KPictureFrame> frame_B;
try {
frame_A = reader->get_frame (i);
frame_B = other_reader->get_frame (i);
diff --git a/src/stereo_picture_asset.h b/src/stereo_j2k_picture_asset.h
index 6ee1d423..7ef86ec5 100644
--- a/src/stereo_picture_asset.h
+++ b/src/stereo_j2k_picture_asset.h
@@ -32,34 +32,34 @@
*/
-/** @file src/stereo_picture_asset.h
- * @brief StereoPictureAsset class
+/** @file src/stereo_j2k_picture_asset.h
+ * @brief StereoJ2KPictureAsset class
*/
-#ifndef LIBDCP_STEREO_PICTURE_ASSET_H
-#define LIBDCP_STEREO_PICTURE_ASSET_H
+#ifndef LIBDCP_STEREO_J2K_PICTURE_ASSET_H
+#define LIBDCP_STEREO_J2K_PICTURE_ASSET_H
-#include "picture_asset.h"
-#include "stereo_picture_asset_reader.h"
+#include "j2k_picture_asset.h"
+#include "stereo_j2k_picture_asset_reader.h"
namespace dcp {
-/** @class StereoPictureAsset
+/** @class StereoJ2KPictureAsset
* @brief A 3D (stereoscopic) picture asset
*/
-class StereoPictureAsset : public PictureAsset
+class StereoJ2KPictureAsset : public J2KPictureAsset
{
public:
- explicit StereoPictureAsset (boost::filesystem::path file);
- explicit StereoPictureAsset (Fraction edit_rate, Standard standard);
+ explicit StereoJ2KPictureAsset (boost::filesystem::path file);
+ explicit StereoJ2KPictureAsset (Fraction edit_rate, Standard standard);
- /** Start a progressive write to a StereoPictureAsset */
- std::shared_ptr<PictureAssetWriter> start_write(boost::filesystem::path file, Behaviour behaviour) override;
- std::shared_ptr<StereoPictureAssetReader> start_read () const;
+ /** Start a progressive write to a StereoJ2KPictureAsset */
+ std::shared_ptr<J2KPictureAssetWriter> start_write(boost::filesystem::path file, Behaviour behaviour) override;
+ std::shared_ptr<StereoJ2KPictureAssetReader> start_read () const;
bool equals (
std::shared_ptr<const Asset> other,
diff --git a/src/stereo_picture_asset_reader.h b/src/stereo_j2k_picture_asset_reader.h
index 9cb05263..e4812a8e 100644
--- a/src/stereo_picture_asset_reader.h
+++ b/src/stereo_j2k_picture_asset_reader.h
@@ -32,23 +32,23 @@
*/
-/** @file src/stereo_picture_asset_reader.h
- * @brief StereoPictureAssetReader typedef
+/** @file src/stereo_j2k_picture_asset_reader.h
+ * @brief StereoJ2KPictureAssetReader typedef
*/
-#ifndef LIBDCP_STEREO_PICTURE_ASSET_READER_H
-#define LIBDCP_STEREO_PICTURE_ASSET_READER_H
+#ifndef LIBDCP_STEREO_J2K_PICTURE_ASSET_READER_H
+#define LIBDCP_STEREO_J2K_PICTURE_ASSET_READER_H
#include "asset_reader.h"
-#include "stereo_picture_frame.h"
+#include "stereo_j2k_picture_frame.h"
namespace dcp {
-typedef AssetReader<ASDCP::JP2K::MXFSReader, StereoPictureFrame> StereoPictureAssetReader;
+typedef AssetReader<ASDCP::JP2K::MXFSReader, StereoJ2KPictureFrame> StereoJ2KPictureAssetReader;
}
diff --git a/src/stereo_picture_asset_writer.cc b/src/stereo_j2k_picture_asset_writer.cc
index 6ee271bc..e59de02f 100644
--- a/src/stereo_picture_asset_writer.cc
+++ b/src/stereo_j2k_picture_asset_writer.cc
@@ -33,20 +33,20 @@
/** @file src/stereo_picture_asset_writer.cc
- * @brief StereoPictureAssetWriter class
+ * @brief StereoJ2KPictureAssetWriter class
*/
-#include "stereo_picture_asset_writer.h"
+#include "stereo_j2k_picture_asset_writer.h"
#include "exceptions.h"
#include "dcp_assert.h"
-#include "picture_asset.h"
+#include "j2k_picture_asset.h"
#include "crypto_context.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_fileio.h>
-#include "picture_asset_writer_common.cc"
+#include "j2k_picture_asset_writer_common.cc"
using std::string;
@@ -54,21 +54,21 @@ using std::shared_ptr;
using namespace dcp;
-struct StereoPictureAssetWriter::ASDCPState : public ASDCPStateBase
+struct StereoJ2KPictureAssetWriter::ASDCPState : public ASDCPJ2KStateBase
{
ASDCP::JP2K::MXFSWriter mxf_writer;
};
-StereoPictureAssetWriter::StereoPictureAssetWriter (PictureAsset* mxf, boost::filesystem::path file, bool overwrite)
- : PictureAssetWriter (mxf, file, overwrite)
- , _state (new StereoPictureAssetWriter::ASDCPState)
+StereoJ2KPictureAssetWriter::StereoJ2KPictureAssetWriter (J2KPictureAsset* mxf, boost::filesystem::path file, bool overwrite)
+ : J2KPictureAssetWriter (mxf, file, overwrite)
+ , _state (new StereoJ2KPictureAssetWriter::ASDCPState)
{
}
-StereoPictureAssetWriter::~StereoPictureAssetWriter()
+StereoJ2KPictureAssetWriter::~StereoJ2KPictureAssetWriter()
{
try {
/* Last-resort finalization to close the file, at least */
@@ -80,15 +80,15 @@ StereoPictureAssetWriter::~StereoPictureAssetWriter()
void
-StereoPictureAssetWriter::start (uint8_t const * data, int size)
+StereoJ2KPictureAssetWriter::start (uint8_t const * data, int size)
{
dcp::start (this, _state, _picture_asset, data, size);
_picture_asset->set_frame_rate (Fraction (_picture_asset->edit_rate().numerator * 2, _picture_asset->edit_rate().denominator));
}
-FrameInfo
-StereoPictureAssetWriter::write (uint8_t const * data, int size)
+J2KFrameInfo
+StereoJ2KPictureAssetWriter::write (uint8_t const * data, int size)
{
DCP_ASSERT (!_finalized);
@@ -123,17 +123,17 @@ StereoPictureAssetWriter::write (uint8_t const * data, int size)
++_frames_written;
}
- return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
+ return J2KFrameInfo(before_offset, _state->mxf_writer.Tell() - before_offset, hash);
}
void
-StereoPictureAssetWriter::fake_write (int size)
+StereoJ2KPictureAssetWriter::fake_write(J2KFrameInfo const& info)
{
DCP_ASSERT (_started);
DCP_ASSERT (!_finalized);
- auto r = _state->mxf_writer.FakeWriteFrame (size, _next_eye == Eye::LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT);
+ auto r = _state->mxf_writer.FakeWriteFrame(info.size, _next_eye == Eye::LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT);
if (ASDCP_FAILURE(r)) {
boost::throw_exception (MXFFileError("error in writing video MXF", _file.string(), r));
}
@@ -146,7 +146,7 @@ StereoPictureAssetWriter::fake_write (int size)
bool
-StereoPictureAssetWriter::finalize ()
+StereoJ2KPictureAssetWriter::finalize ()
{
if (_started) {
auto r = _state->mxf_writer.Finalize();
@@ -156,5 +156,5 @@ StereoPictureAssetWriter::finalize ()
}
_picture_asset->_intrinsic_duration = _frames_written;
- return PictureAssetWriter::finalize ();
+ return J2KPictureAssetWriter::finalize ();
}
diff --git a/src/stereo_picture_asset_writer.h b/src/stereo_j2k_picture_asset_writer.h
index 1cee1202..e3f39a0b 100644
--- a/src/stereo_picture_asset_writer.h
+++ b/src/stereo_j2k_picture_asset_writer.h
@@ -32,12 +32,12 @@
*/
-/** @file src/stereo_picture_asset_writer.h
- * @brief StereoPictureAssetWriter class
+/** @file src/stereo_j2k_picture_asset_writer.h
+ * @brief StereoJ2KPictureAssetWriter class
*/
-#include "picture_asset_writer.h"
+#include "j2k_picture_asset_writer.h"
#include <memory>
#include <stdint.h>
#include <string>
@@ -46,33 +46,33 @@
namespace dcp {
-/** @class StereoPictureAssetWriter
- * @brief A helper class for writing to StereoPictureAssets.
+/** @class StereoJ2KPictureAssetWriter
+ * @brief A helper class for writing to StereoJ2KPictureAssets.
*
- * Objects of this class can only be created with StereoPictureAsset::start_write().
+ * Objects of this class can only be created with StereoJ2KPictureAsset::start_write().
*
- * Frames can be written to the StereoPictureAsset by calling write() with a JPEG2000 image
+ * Frames can be written to the StereoJ2KPictureAsset by calling write() with a JPEG2000 image
* (a verbatim .j2c file). finalize() should be called after the last frame has been written,
* but if it is not, it will be called by the destructor (though in that case any error
* during finalization will be ignored).
*/
-class StereoPictureAssetWriter : public PictureAssetWriter
+class StereoJ2KPictureAssetWriter : public J2KPictureAssetWriter
{
public:
- ~StereoPictureAssetWriter();
+ ~StereoJ2KPictureAssetWriter();
/** Write a frame for one eye. Frames must be written left, then right, then left etc.
* @param data JPEG2000 data.
* @param size Size of data.
*/
- FrameInfo write (uint8_t const * data, int size) override;
- void fake_write (int size) override;
+ J2KFrameInfo write(uint8_t const * data, int size) override;
+ void fake_write(J2KFrameInfo const& info) override;
bool finalize () override;
private:
- friend class StereoPictureAsset;
+ friend class StereoJ2KPictureAsset;
- StereoPictureAssetWriter (PictureAsset *, boost::filesystem::path file, bool);
+ StereoJ2KPictureAssetWriter (J2KPictureAsset *, boost::filesystem::path file, bool);
void start (uint8_t const *, int);
/* do this with an opaque pointer so we don't have to include
diff --git a/src/stereo_picture_frame.cc b/src/stereo_j2k_picture_frame.cc
index 8d3a2757..9ef91c5c 100644
--- a/src/stereo_picture_frame.cc
+++ b/src/stereo_j2k_picture_frame.cc
@@ -33,7 +33,7 @@
/** @file src/stereo_picture_frame.cc
- * @brief StereoPictureFrame class
+ * @brief StereoJ2KPictureFrame class
*/
@@ -43,7 +43,7 @@
#include "exceptions.h"
#include "j2k_transcode.h"
#include "rgb_xyz.h"
-#include "stereo_picture_frame.h"
+#include "stereo_j2k_picture_frame.h"
#include "util.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_fileio.h>
@@ -55,7 +55,7 @@ using std::make_shared;
using namespace dcp;
-StereoPictureFrame::Part::Part (shared_ptr<ASDCP::JP2K::SFrameBuffer> buffer, Eye eye)
+StereoJ2KPictureFrame::Part::Part (shared_ptr<ASDCP::JP2K::SFrameBuffer> buffer, Eye eye)
: _buffer (buffer)
, _eye (eye)
{
@@ -64,28 +64,28 @@ StereoPictureFrame::Part::Part (shared_ptr<ASDCP::JP2K::SFrameBuffer> buffer, Ey
ASDCP::JP2K::FrameBuffer &
-StereoPictureFrame::Part::mono () const
+StereoJ2KPictureFrame::Part::mono () const
{
return _eye == Eye::LEFT ? _buffer->Left : _buffer->Right;
}
uint8_t const *
-StereoPictureFrame::Part::data () const
+StereoJ2KPictureFrame::Part::data () const
{
return mono().RoData();
}
uint8_t *
-StereoPictureFrame::Part::data ()
+StereoJ2KPictureFrame::Part::data ()
{
return mono().Data();
}
int
-StereoPictureFrame::Part::size () const
+StereoJ2KPictureFrame::Part::size () const
{
return mono().Size();
}
@@ -96,7 +96,7 @@ StereoPictureFrame::Part::size () const
* @param n Frame within the asset, not taking EntryPoint into account.
* @param check_hmac true to check the HMAC and give an error if it is not as expected.
*/
-StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, shared_ptr<DecryptionContext> c, bool check_hmac)
+StereoJ2KPictureFrame::StereoJ2KPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, shared_ptr<DecryptionContext> c, bool check_hmac)
{
/* XXX: unfortunate guesswork on this buffer size */
_buffer = make_shared<ASDCP::JP2K::SFrameBuffer>(4 * Kumu::Megabyte);
@@ -107,7 +107,7 @@ StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n,
}
-StereoPictureFrame::StereoPictureFrame ()
+StereoJ2KPictureFrame::StereoJ2KPictureFrame ()
{
_buffer = make_shared<ASDCP::JP2K::SFrameBuffer>(4 * Kumu::Megabyte);
}
@@ -119,7 +119,7 @@ StereoPictureFrame::StereoPictureFrame ()
* reduction).
*/
shared_ptr<OpenJPEGImage>
-StereoPictureFrame::xyz_image (Eye eye, int reduce) const
+StereoJ2KPictureFrame::xyz_image (Eye eye, int reduce) const
{
switch (eye) {
case Eye::LEFT:
@@ -132,15 +132,15 @@ StereoPictureFrame::xyz_image (Eye eye, int reduce) const
}
-shared_ptr<StereoPictureFrame::Part>
-StereoPictureFrame::right () const
+shared_ptr<StereoJ2KPictureFrame::Part>
+StereoJ2KPictureFrame::right () const
{
return make_shared<Part>(_buffer, Eye::RIGHT);
}
-shared_ptr<StereoPictureFrame::Part>
-StereoPictureFrame::left () const
+shared_ptr<StereoJ2KPictureFrame::Part>
+StereoJ2KPictureFrame::left () const
{
return make_shared<Part>(_buffer, Eye::LEFT);
}
diff --git a/src/stereo_picture_frame.h b/src/stereo_j2k_picture_frame.h
index b0c0f0c8..193960f3 100644
--- a/src/stereo_picture_frame.h
+++ b/src/stereo_j2k_picture_frame.h
@@ -32,13 +32,13 @@
*/
-/** @file src/stereo_picture_frame.h
- * @brief StereoPictureFrame class
+/** @file src/stereo_j2k_picture_frame.h
+ * @brief StereoJ2KPictureFrame class
*/
-#ifndef LIBDCP_STEREO_PICTURE_FRAME_H
-#define LIBDCP_STEREO_PICTURE_FRAME_H
+#ifndef LIBDCP_STEREO_J2K_PICTURE_FRAME_H
+#define LIBDCP_STEREO_J2K_PICTURE_FRAME_H
#include "asset_reader.h"
@@ -61,19 +61,19 @@ namespace dcp {
class OpenJPEGImage;
-class StereoPictureFrame;
+class StereoJ2KPictureFrame;
-/** @class StereoPictureFrame
+/** @class StereoJ2KPictureFrame
* @brief A single frame of a 3D (stereoscopic) picture asset
*/
-class StereoPictureFrame
+class StereoJ2KPictureFrame
{
public:
- StereoPictureFrame ();
+ StereoJ2KPictureFrame ();
- StereoPictureFrame (StereoPictureFrame const &) = delete;
- StereoPictureFrame& operator= (StereoPictureFrame const &) = delete;
+ StereoJ2KPictureFrame (StereoJ2KPictureFrame const &) = delete;
+ StereoJ2KPictureFrame& operator= (StereoJ2KPictureFrame const &) = delete;
std::shared_ptr<OpenJPEGImage> xyz_image (Eye eye, int reduce = 0) const;
@@ -87,7 +87,7 @@ public:
int size () const override;
private:
- friend class StereoPictureFrame;
+ friend class StereoJ2KPictureFrame;
ASDCP::JP2K::FrameBuffer& mono () const;
@@ -99,12 +99,12 @@ public:
std::shared_ptr<Part> right () const;
private:
- /* XXX: this is a bit of a shame, but I tried friend StereoPictureAssetReader and it's
+ /* XXX: this is a bit of a shame, but I tried friend StereoJ2KPictureAssetReader and it's
rejected by some (seemingly older) GCCs.
*/
- friend class AssetReader<ASDCP::JP2K::MXFSReader, StereoPictureFrame>;
+ friend class AssetReader<ASDCP::JP2K::MXFSReader, StereoJ2KPictureFrame>;
- StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
+ StereoJ2KPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
std::shared_ptr<ASDCP::JP2K::SFrameBuffer> _buffer;
};
diff --git a/src/subtitle.cc b/src/text.cc
index 248d0cff..158af38c 100644
--- a/src/subtitle.cc
+++ b/src/text.cc
@@ -32,15 +32,15 @@
*/
-/** @file src/subtitle.cc
- * @brief Subtitle class
+/** @file src/text.cc
+ * @brief Text class
*/
#include "compose.hpp"
#include "dcp_time.h"
#include "equality_options.h"
-#include "subtitle.h"
+#include "text.h"
using std::shared_ptr;
@@ -48,7 +48,7 @@ using namespace dcp;
/** @param v_position Vertical position as a fraction of the screen height (between 0 and 1) from v_align */
-Subtitle::Subtitle (
+Text::Text(
Time in,
Time out,
float h_position,
@@ -74,56 +74,56 @@ Subtitle::Subtitle (
bool
-Subtitle::equals(shared_ptr<const Subtitle> other, EqualityOptions const& options, NoteHandler note) const
+Text::equals(shared_ptr<const Text> other, EqualityOptions const& options, NoteHandler note) const
{
bool same = true;
if (in() != other->in()) {
- note(NoteType::ERROR, "subtitle in times differ");
+ note(NoteType::ERROR, "text in times differ");
same = false;
}
if (out() != other->out()) {
- note(NoteType::ERROR, "subtitle out times differ");
+ note(NoteType::ERROR, "text out times differ");
same = false;
}
if (h_position() != other->h_position()) {
- note(NoteType::ERROR, "subtitle horizontal positions differ");
+ note(NoteType::ERROR, "text horizontal positions differ");
same = false;
}
if (h_align() != other->h_align()) {
- note(NoteType::ERROR, "subtitle horizontal alignments differ");
+ note(NoteType::ERROR, "text horizontal alignments differ");
same = false;
}
auto const vpos = std::abs(v_position() - other->v_position());
- if (vpos > options.max_subtitle_vertical_position_error) {
+ if (vpos > options.max_text_vertical_position_error) {
note(
NoteType::ERROR,
- String::compose("subtitle vertical positions differ by %1 (more than the allowed difference of %2)", vpos, options.max_subtitle_vertical_position_error)
+ String::compose("text vertical positions differ by %1 (more than the allowed difference of %2)", vpos, options.max_text_vertical_position_error)
);
same = false;
}
if (v_align() != other->v_align()) {
- note(NoteType::ERROR, "subtitle vertical alignments differ");
+ note(NoteType::ERROR, "text vertical alignments differ");
same = false;
}
if (z_position() != other->z_position()) {
- note(NoteType::ERROR, "subtitle Z positions differ");
+ note(NoteType::ERROR, "text Z positions differ");
same = false;
}
if (fade_up_time() != other->fade_up_time()) {
- note(NoteType::ERROR, "subtitle fade-up times differ");
+ note(NoteType::ERROR, "text fade-up times differ");
same = false;
}
if (fade_down_time() != other->fade_down_time()) {
- note(NoteType::ERROR, "subtitle fade-down times differ");
+ note(NoteType::ERROR, "text fade-down times differ");
same = false;
}
diff --git a/src/subtitle.h b/src/text.h
index 1ca3f9d4..b8f15757 100644
--- a/src/subtitle.h
+++ b/src/text.h
@@ -32,13 +32,13 @@
*/
-/** @file src/subtitle.h
- * @brief Subtitle class
+/** @file src/text.h
+ * @brief Text class
*/
-#ifndef LIBDCP_SUBTITLE_H
-#define LIBDCP_SUBTITLE_H
+#ifndef LIBDCP_TEXT_H
+#define LIBDCP_TEXT_H
#include "dcp_time.h"
@@ -52,17 +52,17 @@ namespace dcp {
class EqualityOptions;
-class Subtitle
+class Text
{
public:
- virtual ~Subtitle () {}
+ virtual ~Text() {}
- /** @return subtitle start time (relative to the start of the reel) */
+ /** @return text start time (relative to the start of the reel) */
Time in () const {
return _in;
}
- /** @return subtitle finish time (relative to the start of the reel) */
+ /** @return text finish time (relative to the start of the reel) */
Time out () const {
return _out;
}
@@ -130,11 +130,11 @@ public:
_fade_down_time = t;
}
- virtual bool equals(std::shared_ptr<const dcp::Subtitle> other, EqualityOptions const& options, NoteHandler note) const;
+ virtual bool equals(std::shared_ptr<const dcp::Text> other, EqualityOptions const& options, NoteHandler note) const;
protected:
- Subtitle (
+ Text(
Time in,
Time out,
float h_position,
diff --git a/src/subtitle_asset.cc b/src/text_asset.cc
index 1cd4fc07..ff662b69 100644
--- a/src/subtitle_asset.cc
+++ b/src/text_asset.cc
@@ -32,8 +32,8 @@
*/
-/** @file src/subtitle_asset.cc
- * @brief SubtitleAsset class
+/** @file src/text_asset.cc
+ * @brief TextAsset class
*/
@@ -42,10 +42,10 @@
#include "load_font_node.h"
#include "raw_convert.h"
#include "reel_asset.h"
-#include "subtitle_asset.h"
-#include "subtitle_asset_internal.h"
-#include "subtitle_image.h"
-#include "subtitle_string.h"
+#include "text_image.h"
+#include "text_string.h"
+#include "text_asset.h"
+#include "text_asset_internal.h"
#include "util.h"
#include "xml.h"
#include <asdcp/AS_DCP.h>
@@ -71,13 +71,13 @@ using boost::optional;
using namespace dcp;
-SubtitleAsset::SubtitleAsset ()
+TextAsset::TextAsset()
{
}
-SubtitleAsset::SubtitleAsset (boost::filesystem::path file)
+TextAsset::TextAsset(boost::filesystem::path file)
: Asset (file)
{
@@ -133,8 +133,8 @@ optional_number_attribute (xmlpp::Element const * node, string name)
}
-SubtitleAsset::ParseState
-SubtitleAsset::font_node_state (xmlpp::Element const * node, Standard standard) const
+TextAsset::ParseState
+TextAsset::font_node_state(xmlpp::Element const * node, Standard standard) const
{
ParseState ps;
@@ -169,7 +169,7 @@ SubtitleAsset::font_node_state (xmlpp::Element const * node, Standard standard)
}
void
-SubtitleAsset::position_align (SubtitleAsset::ParseState& ps, xmlpp::Element const * node) const
+TextAsset::position_align(TextAsset::ParseState& ps, xmlpp::Element const * node) const
{
auto hp = optional_number_attribute<float> (node, "HPosition");
if (!hp) {
@@ -210,8 +210,8 @@ SubtitleAsset::position_align (SubtitleAsset::ParseState& ps, xmlpp::Element con
}
-SubtitleAsset::ParseState
-SubtitleAsset::text_node_state (xmlpp::Element const * node) const
+TextAsset::ParseState
+TextAsset::text_node_state(xmlpp::Element const * node) const
{
ParseState ps;
@@ -228,8 +228,8 @@ SubtitleAsset::text_node_state (xmlpp::Element const * node) const
}
-SubtitleAsset::ParseState
-SubtitleAsset::image_node_state (xmlpp::Element const * node) const
+TextAsset::ParseState
+TextAsset::image_node_state(xmlpp::Element const * node) const
{
ParseState ps;
@@ -241,8 +241,8 @@ SubtitleAsset::image_node_state (xmlpp::Element const * node) const
}
-SubtitleAsset::ParseState
-SubtitleAsset::subtitle_node_state (xmlpp::Element const * node, optional<int> tcr) const
+TextAsset::ParseState
+TextAsset::subtitle_node_state(xmlpp::Element const * node, optional<int> tcr) const
{
ParseState ps;
ps.in = Time (string_attribute(node, "TimeIn"), tcr);
@@ -254,7 +254,7 @@ SubtitleAsset::subtitle_node_state (xmlpp::Element const * node, optional<int> t
Time
-SubtitleAsset::fade_time (xmlpp::Element const * node, string name, optional<int> tcr) const
+TextAsset::fade_time(xmlpp::Element const * node, string name, optional<int> tcr) const
{
auto const u = optional_string_attribute(node, name).get_value_or ("");
Time t;
@@ -276,7 +276,7 @@ SubtitleAsset::fade_time (xmlpp::Element const * node, string name, optional<int
void
-SubtitleAsset::parse_subtitles (xmlpp::Element const * node, vector<ParseState>& state, optional<int> tcr, Standard standard)
+TextAsset::parse_texts(xmlpp::Element const * node, vector<ParseState>& state, optional<int> tcr, Standard standard)
{
if (node->get_name() == "Font") {
state.push_back (font_node_state (node, standard));
@@ -366,7 +366,7 @@ SubtitleAsset::parse_subtitles (xmlpp::Element const * node, vector<ParseState>&
/* Handle actual content e.g. text */
auto const v = dynamic_cast<xmlpp::ContentNode const *>(i);
if (v) {
- maybe_add_subtitle (v->get_content(), state, space_before, standard, rubies);
+ maybe_add_text(v->get_content(), state, space_before, standard, rubies);
space_before = 0;
}
@@ -383,7 +383,7 @@ SubtitleAsset::parse_subtitles (xmlpp::Element const * node, vector<ParseState>&
}
space_before += raw_convert<float>(size);
} else if (e->get_name() != "Ruby") {
- parse_subtitles (e, state, tcr, standard);
+ parse_texts (e, state, tcr, standard);
}
}
}
@@ -393,7 +393,7 @@ SubtitleAsset::parse_subtitles (xmlpp::Element const * node, vector<ParseState>&
void
-SubtitleAsset::maybe_add_subtitle(
+TextAsset::maybe_add_text(
string text,
vector<ParseState> const & parse_state,
float space_before,
@@ -482,8 +482,8 @@ SubtitleAsset::maybe_add_subtitle(
switch (ps.type.get()) {
case ParseState::Type::TEXT:
- _subtitles.push_back (
- make_shared<SubtitleString>(
+ _texts.push_back (
+ make_shared<TextString>(
ps.font_id,
ps.italic.get_value_or (false),
ps.bold.get_value_or (false),
@@ -530,9 +530,9 @@ SubtitleAsset::maybe_add_subtitle(
break;
}
- /* Add a subtitle with no image data and we'll fill that in later */
- _subtitles.push_back (
- make_shared<SubtitleImage>(
+ /* Add a text with no image data and we'll fill that in later */
+ _texts.push_back(
+ make_shared<TextImage>(
ArrayData(),
text,
ps.in.get(),
@@ -552,22 +552,22 @@ SubtitleAsset::maybe_add_subtitle(
}
-vector<shared_ptr<const Subtitle>>
-SubtitleAsset::subtitles () const
+vector<shared_ptr<const Text>>
+TextAsset::texts() const
{
- vector<shared_ptr<const Subtitle>> s;
- for (auto i: _subtitles) {
+ vector<shared_ptr<const Text>> s;
+ for (auto i: _texts) {
s.push_back (i);
}
return s;
}
-vector<shared_ptr<const Subtitle>>
-SubtitleAsset::subtitles_during (Time from, Time to, bool starting) const
+vector<shared_ptr<const Text>>
+TextAsset::texts_during(Time from, Time to, bool starting) const
{
- vector<shared_ptr<const Subtitle>> s;
- for (auto i: _subtitles) {
+ vector<shared_ptr<const Text>> s;
+ for (auto i: _texts) {
if ((starting && from <= i->in() && i->in() < to) || (!starting && i->out() >= from && i->in() <= to)) {
s.push_back (i);
}
@@ -578,17 +578,17 @@ SubtitleAsset::subtitles_during (Time from, Time to, bool starting) const
void
-SubtitleAsset::add (shared_ptr<Subtitle> s)
+TextAsset::add(shared_ptr<Text> s)
{
- _subtitles.push_back (s);
+ _texts.push_back(s);
}
Time
-SubtitleAsset::latest_subtitle_out () const
+TextAsset::latest_text_out() const
{
Time t;
- for (auto i: _subtitles) {
+ for (auto i: _texts) {
if (i->out() > t) {
t = i->out ();
}
@@ -599,33 +599,33 @@ SubtitleAsset::latest_subtitle_out () const
bool
-SubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const& options, NoteHandler note) const
+TextAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const& options, NoteHandler note) const
{
if (!Asset::equals (other_asset, options, note)) {
return false;
}
- auto other = dynamic_pointer_cast<const SubtitleAsset> (other_asset);
+ auto other = dynamic_pointer_cast<const TextAsset> (other_asset);
if (!other) {
return false;
}
- if (_subtitles.size() != other->_subtitles.size()) {
- note (NoteType::ERROR, String::compose("different number of subtitles: %1 vs %2", _subtitles.size(), other->_subtitles.size()));
+ if (_texts.size() != other->_texts.size()) {
+ note (NoteType::ERROR, String::compose("different number of texts: %1 vs %2", _texts.size(), other->_texts.size()));
return false;
}
- auto i = _subtitles.begin();
- auto j = other->_subtitles.begin();
+ auto i = _texts.begin();
+ auto j = other->_texts.begin();
- while (i != _subtitles.end()) {
- auto string_i = dynamic_pointer_cast<SubtitleString> (*i);
- auto string_j = dynamic_pointer_cast<SubtitleString> (*j);
- auto image_i = dynamic_pointer_cast<SubtitleImage> (*i);
- auto image_j = dynamic_pointer_cast<SubtitleImage> (*j);
+ while (i != _texts.end()) {
+ auto string_i = dynamic_pointer_cast<TextString>(*i);
+ auto string_j = dynamic_pointer_cast<TextString>(*j);
+ auto image_i = dynamic_pointer_cast<TextImage>(*i);
+ auto image_j = dynamic_pointer_cast<TextImage>(*j);
if ((string_i && !string_j) || (image_i && !image_j)) {
- note (NoteType::ERROR, "subtitles differ: string vs. image");
+ note (NoteType::ERROR, "texts differ: string vs. image");
return false;
}
@@ -645,9 +645,9 @@ SubtitleAsset::equals(shared_ptr<const Asset> other_asset, EqualityOptions const
}
-struct SubtitleSorter
+struct TextSorter
{
- bool operator() (shared_ptr<Subtitle> a, shared_ptr<Subtitle> b) {
+ bool operator()(shared_ptr<Text> a, shared_ptr<Text> b) {
if (a->in() != b->in()) {
return a->in() < b->in();
}
@@ -660,7 +660,7 @@ struct SubtitleSorter
void
-SubtitleAsset::pull_fonts (shared_ptr<order::Part> part)
+TextAsset::pull_fonts(shared_ptr<order::Part> part)
{
if (part->children.empty ()) {
return;
@@ -724,12 +724,12 @@ SubtitleAsset::pull_fonts (shared_ptr<order::Part> part)
* class because the differences between the two are fairly subtle.
*/
void
-SubtitleAsset::subtitles_as_xml (xmlpp::Element* xml_root, int time_code_rate, Standard standard) const
+TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard standard) const
{
- auto sorted = _subtitles;
- std::stable_sort(sorted.begin(), sorted.end(), SubtitleSorter());
+ auto sorted = _texts;
+ std::stable_sort(sorted.begin(), sorted.end(), TextSorter());
- /* Gather our subtitles into a hierarchy of Subtitle/Text/String objects, writing
+ /* Gather our texts into a hierarchy of Subtitle/Text/String objects, writing
font information into the bottom level (String) objects.
*/
@@ -766,7 +766,7 @@ SubtitleAsset::subtitles_as_xml (xmlpp::Element* xml_root, int time_code_rate, S
text.reset ();
}
- auto is = dynamic_pointer_cast<SubtitleString>(i);
+ auto is = dynamic_pointer_cast<TextString>(i);
if (is) {
if (!text ||
last_h_align != is->h_align() ||
@@ -799,8 +799,7 @@ SubtitleAsset::subtitles_as_xml (xmlpp::Element* xml_root, int time_code_rate, S
text->children.push_back (make_shared<order::String>(text, order::Font (is, standard), is->text(), is->space_before()));
}
- auto ii = dynamic_pointer_cast<SubtitleImage>(i);
- if (ii) {
+ if (auto ii = dynamic_pointer_cast<TextImage>(i)) {
text.reset ();
subtitle->children.push_back (
make_shared<order::Image>(subtitle, ii->id(), ii->png_image(), ii->h_align(), ii->h_position(), ii->v_align(), ii->v_position(), ii->z_position())
@@ -824,7 +823,7 @@ SubtitleAsset::subtitles_as_xml (xmlpp::Element* xml_root, int time_code_rate, S
map<string, ArrayData>
-SubtitleAsset::font_data () const
+TextAsset::font_data() const
{
map<string, ArrayData> out;
for (auto const& i: _fonts) {
@@ -835,7 +834,7 @@ SubtitleAsset::font_data () const
map<string, boost::filesystem::path>
-SubtitleAsset::font_filenames () const
+TextAsset::font_filenames() const
{
map<string, boost::filesystem::path> out;
for (auto const& i: _fonts) {
@@ -852,7 +851,7 @@ SubtitleAsset::font_filenames () const
* (see DCP-o-matic bug #1689).
*/
void
-SubtitleAsset::fix_empty_font_ids ()
+TextAsset::fix_empty_font_ids()
{
bool have_empty = false;
vector<string> ids;
@@ -876,8 +875,8 @@ SubtitleAsset::fix_empty_font_ids ()
}
}
- for (auto i: _subtitles) {
- auto j = dynamic_pointer_cast<SubtitleString> (i);
+ for (auto i: _texts) {
+ auto j = dynamic_pointer_cast<TextString>(i);
if (j && j->font() && j->font().get() == "") {
j->set_font (empty_id);
}
@@ -957,15 +956,15 @@ format_xml_node (xmlpp::Node const* node, State& state)
/** Format XML much as write_to_string_formatted() would do, except without adding any white space
- * to <Text> nodes. This is an attempt to avoid changing what is actually displayed as subtitles
- * while also formatting the XML in such a way as to avoid DoM bug 2205.
+ * to <Text> nodes. This is an attempt to avoid changing what is actually displayed while also
+ * formatting the XML in such a way as to avoid DoM bug 2205.
*
* xml_namespace is an optional namespace for the root node; it would be nicer to set this up with
* set_namespace_declaration in the caller and then to extract it here but I couldn't find a way
* to get all namespaces with the libxml++ API.
*/
string
-SubtitleAsset::format_xml(xmlpp::Document const& document, optional<pair<string, string>> xml_namespace)
+TextAsset::format_xml(xmlpp::Document const& document, optional<pair<string, string>> xml_namespace)
{
auto root = document.get_root_node();
@@ -997,7 +996,7 @@ SubtitleAsset::format_xml(xmlpp::Document const& document, optional<pair<string,
void
-SubtitleAsset::ensure_font(string load_id, dcp::ArrayData data)
+TextAsset::ensure_font(string load_id, dcp::ArrayData data)
{
if (std::find_if(_fonts.begin(), _fonts.end(), [load_id](Font const& font) { return font.load_id == load_id; }) == _fonts.end()) {
add_font(load_id, data);
diff --git a/src/subtitle_asset.h b/src/text_asset.h
index 25758c2e..4d739027 100644
--- a/src/subtitle_asset.h
+++ b/src/text_asset.h
@@ -32,20 +32,20 @@
*/
-/** @file src/subtitle_asset.h
- * @brief SubtitleAsset class
+/** @file src/text_asset.h
+ * @brief TextAsset class
*/
-#ifndef LIBDCP_SUBTITLE_ASSET_H
-#define LIBDCP_SUBTITLE_ASSET_H
+#ifndef LIBDCP_TEXT_ASSET_H
+#define LIBDCP_TEXT_ASSET_H
#include "array_data.h"
#include "asset.h"
#include "dcp_time.h"
#include "subtitle_standard.h"
-#include "subtitle_string.h"
+#include "text_string.h"
#include <libcxml/cxml.h>
#include <boost/shared_array.hpp>
#include <map>
@@ -70,13 +70,13 @@ struct pull_fonts_test3;
namespace dcp {
-class SubtitleString;
-class SubtitleImage;
class FontNode;
-class TextNode;
-class SubtitleNode;
class LoadFontNode;
class ReelAsset;
+class SubtitleNode;
+class TextImage;
+class TextNode;
+class TextString;
namespace order {
@@ -85,19 +85,19 @@ namespace order {
}
-/** @class SubtitleAsset
- * @brief A parent for classes representing a file containing subtitles
+/** @class TextAsset
+ * @brief A parent for classes representing a file containing subtitles or captions
*
- * This class holds a list of Subtitle objects which it can extract
+ * This class holds a list of Text objects which it can extract
* from the appropriate part of either an Interop or SMPTE XML file.
- * Its subclasses InteropSubtitleAsset and SMPTESubtitleAsset handle the
+ * Its subclasses InteropTextAsset and SMPTETextAsset handle the
* differences between the two types.
*/
-class SubtitleAsset : public Asset
+class TextAsset : public Asset
{
public:
- SubtitleAsset ();
- explicit SubtitleAsset (boost::filesystem::path file);
+ TextAsset();
+ explicit TextAsset(boost::filesystem::path file);
bool equals (
std::shared_ptr<const Asset>,
@@ -105,10 +105,10 @@ public:
NoteHandler note
) const override;
- std::vector<std::shared_ptr<const Subtitle>> subtitles_during (Time from, Time to, bool starting) const;
- std::vector<std::shared_ptr<const Subtitle>> subtitles () const;
+ std::vector<std::shared_ptr<const Text>> texts_during(Time from, Time to, bool starting) const;
+ std::vector<std::shared_ptr<const Text>> texts() const;
- virtual void add (std::shared_ptr<Subtitle>);
+ virtual void add(std::shared_ptr<Text>);
virtual void add_font (std::string id, dcp::ArrayData data) = 0;
void ensure_font(std::string id, dcp::ArrayData data);
std::map<std::string, ArrayData> font_data () const;
@@ -117,7 +117,7 @@ public:
virtual void write (boost::filesystem::path) const = 0;
virtual std::string xml_as_string () const = 0;
- Time latest_subtitle_out () const;
+ Time latest_text_out() const;
void fix_empty_font_ids ();
@@ -169,7 +169,7 @@ protected:
float space_before = 0;
};
- void parse_subtitles (xmlpp::Element const * node, std::vector<ParseState>& state, boost::optional<int> tcr, Standard standard);
+ void parse_texts(xmlpp::Element const * node, std::vector<ParseState>& state, boost::optional<int> tcr, Standard standard);
ParseState font_node_state (xmlpp::Element const * node, Standard standard) const;
ParseState text_node_state (xmlpp::Element const * node) const;
ParseState image_node_state (xmlpp::Element const * node) const;
@@ -177,10 +177,10 @@ protected:
Time fade_time (xmlpp::Element const * node, std::string name, boost::optional<int> tcr) const;
void position_align (ParseState& ps, xmlpp::Element const * node) const;
- void subtitles_as_xml (xmlpp::Element* root, int time_code_rate, Standard standard) const;
+ void texts_as_xml(xmlpp::Element* root, int time_code_rate, Standard standard) const;
- /** All our subtitles, in no particular order */
- std::vector<std::shared_ptr<Subtitle>> _subtitles;
+ /** All our texts, in no particular order */
+ std::vector<std::shared_ptr<Text>> _texts;
class Font
{
@@ -216,7 +216,7 @@ private:
friend struct ::pull_fonts_test2;
friend struct ::pull_fonts_test3;
- void maybe_add_subtitle(
+ void maybe_add_text(
std::string text,
std::vector<ParseState> const & parse_state,
float space_before,
diff --git a/src/subtitle_asset_internal.cc b/src/text_asset_internal.cc
index 99d8411b..aba26edd 100644
--- a/src/subtitle_asset_internal.cc
+++ b/src/text_asset_internal.cc
@@ -32,13 +32,13 @@
*/
-/** @file src/subtitle_asset_internal.cc
- * @brief Internal SubtitleAsset helpers
+/** @file src/text_asset_internal.cc
+ * @brief Internal TextAsset helpers
*/
-#include "subtitle_asset_internal.h"
-#include "subtitle_string.h"
+#include "text_asset_internal.h"
+#include "text_string.h"
#include "compose.hpp"
#include <cmath>
@@ -49,7 +49,7 @@ using std::shared_ptr;
using namespace dcp;
-order::Font::Font (shared_ptr<SubtitleString> s, Standard standard)
+order::Font::Font(shared_ptr<TextString> s, Standard standard)
{
if (s->font()) {
if (standard == Standard::SMPTE) {
@@ -77,7 +77,7 @@ order::Font::Font (shared_ptr<SubtitleString> s, Standard standard)
xmlpp::Element*
order::Font::as_xml (xmlpp::Element* parent, Context&) const
{
- auto e = parent->add_child("Font");
+ auto e = cxml::add_child(parent, "Font");
for (const auto& i: _values) {
e->set_attribute (i.first, i.second);
}
@@ -137,7 +137,7 @@ xmlpp::Element*
order::String::as_xml (xmlpp::Element* parent, Context& context) const
{
if (fabs(_space_before) > SPACE_BEFORE_EPSILON) {
- auto space = parent->add_child("Space");
+ auto space = cxml::add_child(parent, "Space");
auto size = raw_convert<string>(_space_before, 2);
if (context.standard == Standard::INTEROP) {
size += "em";
@@ -212,7 +212,7 @@ position_align (xmlpp::Element* e, order::Context& context, HAlign h_align, floa
xmlpp::Element*
order::Text::as_xml (xmlpp::Element* parent, Context& context) const
{
- auto e = parent->add_child ("Text");
+ auto e = cxml::add_child(parent, "Text");
position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position);
@@ -224,9 +224,9 @@ order::Text::as_xml (xmlpp::Element* parent, Context& context) const
}
for (auto const& ruby: _rubies) {
- auto xml = e->add_child("Ruby");
- xml->add_child("Rb")->add_child_text(ruby.base);
- auto rt = xml->add_child("Rt");
+ auto xml = cxml::add_child(e, "Ruby");
+ cxml::add_child(xml, "Rb")->add_child_text(ruby.base);
+ auto rt = cxml::add_child(xml, "Rt");
rt->add_child_text(ruby.annotation);
rt->set_attribute("Size", dcp::raw_convert<string>(ruby.size, 6));
rt->set_attribute("Position", ruby.position == RubyPosition::BEFORE ? "before" : "after");
@@ -242,7 +242,7 @@ order::Text::as_xml (xmlpp::Element* parent, Context& context) const
xmlpp::Element*
order::Subtitle::as_xml (xmlpp::Element* parent, Context& context) const
{
- auto e = parent->add_child ("Subtitle");
+ auto e = cxml::add_child(parent, "Subtitle");
e->set_attribute ("SpotNumber", raw_convert<string> (context.spot_number++));
e->set_attribute ("TimeIn", _in.rebase(context.time_code_rate).as_string(context.standard));
e->set_attribute ("TimeOut", _out.rebase(context.time_code_rate).as_string(context.standard));
@@ -274,7 +274,7 @@ order::Font::clear ()
xmlpp::Element *
order::Image::as_xml (xmlpp::Element* parent, Context& context) const
{
- auto e = parent->add_child ("Image");
+ auto e = cxml::add_child(parent, "Image");
position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position);
if (context.standard == Standard::SMPTE) {
diff --git a/src/subtitle_asset_internal.h b/src/text_asset_internal.h
index 557db2e4..ddbc8833 100644
--- a/src/subtitle_asset_internal.h
+++ b/src/text_asset_internal.h
@@ -32,13 +32,13 @@
*/
-/** @file src/subtitle_asset_internal.h
- * @brief Internal SubtitleAsset helpers
+/** @file src/text_asset_internal.h
+ * @brief Internal TextAsset helpers
*/
-#ifndef LIBDCP_SUBTITLE_ASSET_INTERNAL_H
-#define LIBDCP_SUBTITLE_ASSET_INTERNAL_H
+#ifndef LIBDCP_TEXT_ASSET_INTERNAL_H
+#define LIBDCP_TEXT_ASSET_INTERNAL_H
#include "array_data.h"
@@ -63,7 +63,7 @@ namespace dcp {
class Ruby;
-class SubtitleString;
+class TextString;
namespace order {
@@ -82,7 +82,7 @@ class Font
public:
Font () {}
- Font (std::shared_ptr<SubtitleString> s, Standard standard);
+ Font (std::shared_ptr<TextString> s, Standard standard);
xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const;
diff --git a/src/subtitle_image.cc b/src/text_image.cc
index 9340bc54..7a6c4222 100644
--- a/src/subtitle_image.cc
+++ b/src/text_image.cc
@@ -32,14 +32,14 @@
*/
-/** @file src/subtitle_image.cc
- * @brief SubtitleImage class
+/** @file src/text_image.cc
+ * @brief TextImage class
*/
#include "equality_options.h"
#include "filesystem.h"
-#include "subtitle_image.h"
+#include "text_image.h"
#include "util.h"
@@ -50,7 +50,7 @@ using std::string;
using namespace dcp;
-SubtitleImage::SubtitleImage (
+TextImage::TextImage(
ArrayData png_image,
Time in,
Time out,
@@ -62,7 +62,7 @@ SubtitleImage::SubtitleImage (
Time fade_up_time,
Time fade_down_time
)
- : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
+ : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
, _png_image (png_image)
, _id (make_uuid ())
{
@@ -70,7 +70,7 @@ SubtitleImage::SubtitleImage (
}
-SubtitleImage::SubtitleImage (
+TextImage::TextImage(
ArrayData png_image,
string id,
Time in,
@@ -83,7 +83,7 @@ SubtitleImage::SubtitleImage (
Time fade_up_time,
Time fade_down_time
)
- : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
+ : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
, _png_image (png_image)
, _id (id)
{
@@ -92,7 +92,7 @@ SubtitleImage::SubtitleImage (
void
-SubtitleImage::read_png_file (boost::filesystem::path file)
+TextImage::read_png_file(boost::filesystem::path file)
{
_file = file;
_png_image = ArrayData (file);
@@ -100,7 +100,7 @@ SubtitleImage::read_png_file (boost::filesystem::path file)
void
-SubtitleImage::write_png_file (boost::filesystem::path file) const
+TextImage::write_png_file(boost::filesystem::path file) const
{
_file = file;
png_image().write (file);
@@ -108,7 +108,7 @@ SubtitleImage::write_png_file (boost::filesystem::path file) const
bool
-dcp::operator== (SubtitleImage const & a, SubtitleImage const & b)
+dcp::operator==(TextImage const & a, TextImage const & b)
{
return (
a.png_image() == b.png_image() &&
@@ -127,36 +127,36 @@ dcp::operator== (SubtitleImage const & a, SubtitleImage const & b)
bool
-dcp::operator!= (SubtitleImage const & a, SubtitleImage const & b)
+dcp::operator!=(TextImage const & a, TextImage const & b)
{
return !(a == b);
}
bool
-SubtitleImage::equals(shared_ptr<const Subtitle> other_sub, EqualityOptions const& options, NoteHandler note) const
+TextImage::equals(shared_ptr<const Text> other_sub, EqualityOptions const& options, NoteHandler note) const
{
- if (!Subtitle::equals(other_sub, options, note)) {
+ if (!Text::equals(other_sub, options, note)) {
return false;
}
- auto other = dynamic_pointer_cast<const SubtitleImage>(other_sub);
+ auto other = dynamic_pointer_cast<const TextImage>(other_sub);
if (!other) {
- note(NoteType::ERROR, "Subtitle types differ: string vs image");
+ note(NoteType::ERROR, "Text types differ: string vs image");
return false;
}
if (png_image() != other->png_image()) {
- note (NoteType::ERROR, "subtitle image PNG data differs");
- if (options.export_differing_subtitles) {
- string const base = "dcpdiff_subtitle_";
+ note (NoteType::ERROR, "text image PNG data differs");
+ if (options.export_differing_texts) {
+ string const base = "dcpdiff_text_";
if (filesystem::exists(base + "A.png")) {
- note (NoteType::ERROR, "could not export subtitle as " + base + "A.png already exists");
+ note (NoteType::ERROR, "could not export text as " + base + "A.png already exists");
} else {
png_image().write(base + "A.png");
}
if (filesystem::exists(base + "B.png")) {
- note (NoteType::ERROR, "could not export subtitle as " + base + "B.png already exists");
+ note (NoteType::ERROR, "could not export text as " + base + "B.png already exists");
} else {
other->png_image().write(base + "B.png");
}
@@ -169,13 +169,13 @@ SubtitleImage::equals(shared_ptr<const Subtitle> other_sub, EqualityOptions cons
ostream&
-dcp::operator<< (ostream& s, SubtitleImage const & sub)
+dcp::operator<<(ostream& s, TextImage const& text)
{
- s << "\n[IMAGE] from " << sub.in() << " to " << sub.out() << ";\n"
- << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
- << "v pos " << sub.v_position() << ", valign " << ((int) sub.v_align())
- << ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align())
- << ", zpos " << sub.z_position() << "\n";
+ s << "\n[IMAGE] from " << text.in() << " to " << text.out() << ";\n"
+ << "fade up " << text.fade_up_time() << ", fade down " << text.fade_down_time() << ";\n"
+ << "v pos " << text.v_position() << ", valign " << ((int) text.v_align())
+ << ", hpos " << text.h_position() << ", halign " << ((int) text.h_align())
+ << ", zpos " << text.z_position() << "\n";
return s;
}
diff --git a/src/subtitle_image.h b/src/text_image.h
index ae733fe4..1f1e464e 100644
--- a/src/subtitle_image.h
+++ b/src/text_image.h
@@ -32,17 +32,17 @@
*/
-/** @file src/subtitle_image.h
- * @brief SubtitleImage class
+/** @file src/text_image.h
+ * @brief TextImage class
*/
-#ifndef LIBDCP_SUBTITLE_IMAGE_H
-#define LIBDCP_SUBTITLE_IMAGE_H
+#ifndef LIBDCP_TEXT_IMAGE_H
+#define LIBDCP_TEXT_IMAGE_H
#include "array_data.h"
-#include "subtitle.h"
+#include "text.h"
#include "dcp_time.h"
#include <boost/optional.hpp>
#include <string>
@@ -51,13 +51,13 @@
namespace dcp {
-/** @class SubtitleImage
- * @brief A bitmap subtitle with all the associated attributes
+/** @class TextImage
+ * @brief A bitmap subtitle or caption with all the associated attributes
*/
-class SubtitleImage : public Subtitle
+class TextImage : public Text
{
public:
- SubtitleImage (
+ TextImage(
ArrayData png_image,
Time in,
Time out,
@@ -70,7 +70,7 @@ public:
Time fade_down_time
);
- SubtitleImage (
+ TextImage(
ArrayData png_image,
std::string id,
Time in,
@@ -104,7 +104,7 @@ public:
return _file;
}
- bool equals(std::shared_ptr<const dcp::Subtitle> other_sub, EqualityOptions const& options, NoteHandler note) const override;
+ bool equals(std::shared_ptr<const dcp::Text> other_text, EqualityOptions const& options, NoteHandler note) const override;
private:
ArrayData _png_image;
@@ -113,9 +113,9 @@ private:
};
-bool operator== (SubtitleImage const & a, SubtitleImage const & b);
-bool operator!= (SubtitleImage const & a, SubtitleImage const & b);
-std::ostream& operator<< (std::ostream& s, SubtitleImage const & sub);
+bool operator==(TextImage const & a, TextImage const& b);
+bool operator!=(TextImage const & a, TextImage const& b);
+std::ostream& operator<<(std::ostream& s, TextImage const& text);
}
diff --git a/src/subtitle_string.cc b/src/text_string.cc
index af61d928..32f9e4ed 100644
--- a/src/subtitle_string.cc
+++ b/src/text_string.cc
@@ -32,13 +32,13 @@
*/
-/** @file src/subtitle_string.cc
- * @brief SubtitleString class
+/** @file src/text_string.cc
+ * @brief TextString class
*/
#include "compose.hpp"
-#include "subtitle_string.h"
+#include "text_string.h"
#include "xml.h"
#include <cmath>
@@ -54,7 +54,7 @@ using boost::optional;
using namespace dcp;
-SubtitleString::SubtitleString (
+TextString::TextString(
optional<string> font,
bool italic,
bool bold,
@@ -78,7 +78,7 @@ SubtitleString::SubtitleString (
float space_before,
vector<Ruby> rubies
)
- : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
+ : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
, _font (font)
, _italic (italic)
, _bold (bold)
@@ -98,7 +98,7 @@ SubtitleString::SubtitleString (
float
-SubtitleString::size_in_pixels (int screen_height) const
+TextString::size_in_pixels(int screen_height) const
{
/* Size in the subtitle file is given in points as if the screen
height is 11 inches, so a 72pt font would be 1/11th of the screen
@@ -110,7 +110,7 @@ SubtitleString::size_in_pixels (int screen_height) const
bool
-dcp::operator== (SubtitleString const & a, SubtitleString const & b)
+dcp::operator==(TextString const & a, TextString const & b)
{
return (
a.font() == b.font() &&
@@ -140,14 +140,14 @@ dcp::operator== (SubtitleString const & a, SubtitleString const & b)
bool
-dcp::operator!= (SubtitleString const & a, SubtitleString const & b)
+dcp::operator!=(TextString const & a, TextString const & b)
{
return !(a == b);
}
ostream&
-dcp::operator<< (ostream& s, SubtitleString const & sub)
+dcp::operator<<(ostream& s, TextString const & sub)
{
s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n"
<< "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
@@ -188,77 +188,77 @@ dcp::operator<< (ostream& s, SubtitleString const & sub)
bool
-SubtitleString::equals(shared_ptr<const Subtitle> other_sub, EqualityOptions const& options, NoteHandler note) const
+TextString::equals(shared_ptr<const Text> other_sub, EqualityOptions const& options, NoteHandler note) const
{
- if (!Subtitle::equals(other_sub, options, note)) {
+ if (!Text::equals(other_sub, options, note)) {
return false;
}
- auto other = dynamic_pointer_cast<const SubtitleString>(other_sub);
+ auto other = dynamic_pointer_cast<const TextString>(other_sub);
if (!other) {
- note(NoteType::ERROR, "Subtitle types differ: string vs image");
+ note(NoteType::ERROR, "Text types differ: string vs image");
return false;
}
bool same = true;
if (_font != other->_font) {
- note(NoteType::ERROR, String::compose("subtitle font differs: %1 vs %2", _font.get_value_or("[none]"), other->_font.get_value_or("[none]")));
+ note(NoteType::ERROR, String::compose("text font differs: %1 vs %2", _font.get_value_or("[none]"), other->_font.get_value_or("[none]")));
same = false;
}
if (_italic != other->_italic) {
- note(NoteType::ERROR, String::compose("subtitle italic flag differs: %1 vs %2", _italic ? "true" : "false", other->_italic ? "true" : "false"));
+ note(NoteType::ERROR, String::compose("text italic flag differs: %1 vs %2", _italic ? "true" : "false", other->_italic ? "true" : "false"));
same = false;
}
if (_bold != other->_bold) {
- note(NoteType::ERROR, String::compose("subtitle bold flag differs: %1 vs %2", _bold ? "true" : "false", other->_bold ? "true" : "false"));
+ note(NoteType::ERROR, String::compose("text bold flag differs: %1 vs %2", _bold ? "true" : "false", other->_bold ? "true" : "false"));
same = false;
}
if (_underline != other->_underline) {
- note(NoteType::ERROR, String::compose("subtitle underline flag differs: %1 vs %2", _underline ? "true" : "false", other->_underline ? "true" : "false"));
+ note(NoteType::ERROR, String::compose("text underline flag differs: %1 vs %2", _underline ? "true" : "false", other->_underline ? "true" : "false"));
same = false;
}
if (_colour != other->_colour) {
- note(NoteType::ERROR, String::compose("subtitle colour differs: %1 vs %2", _colour.to_rgb_string(), other->_colour.to_rgb_string()));
+ note(NoteType::ERROR, String::compose("text colour differs: %1 vs %2", _colour.to_rgb_string(), other->_colour.to_rgb_string()));
same = false;
}
if (_size != other->_size) {
- note(NoteType::ERROR, String::compose("subtitle size differs: %1 vs %2", _size, other->_size));
+ note(NoteType::ERROR, String::compose("text size differs: %1 vs %2", _size, other->_size));
same = false;
}
if (_aspect_adjust != other->_aspect_adjust) {
- note(NoteType::ERROR, String::compose("subtitle aspect_adjust differs: %1 vs %2", _aspect_adjust, other->_aspect_adjust));
+ note(NoteType::ERROR, String::compose("text aspect_adjust differs: %1 vs %2", _aspect_adjust, other->_aspect_adjust));
same = false;
}
if (_direction != other->_direction) {
- note(NoteType::ERROR, String::compose("subtitle direction differs: %1 vs %2", direction_to_string(_direction), direction_to_string(other->_direction)));
+ note(NoteType::ERROR, String::compose("text direction differs: %1 vs %2", direction_to_string(_direction), direction_to_string(other->_direction)));
same = false;
}
if (_text != other->_text) {
- note(NoteType::ERROR, String::compose("subtitle text differs: %1 vs %2", _text, other->_text));
+ note(NoteType::ERROR, String::compose("text text differs: %1 vs %2", _text, other->_text));
same = false;
}
if (_effect != other->_effect) {
- note(NoteType::ERROR, String::compose("subtitle effect differs: %1 vs %2", effect_to_string(_effect), effect_to_string(other->_effect)));
+ note(NoteType::ERROR, String::compose("text effect differs: %1 vs %2", effect_to_string(_effect), effect_to_string(other->_effect)));
same = false;
}
if (_effect_colour != other->_effect_colour) {
- note(NoteType::ERROR, String::compose("subtitle effect colour differs: %1 vs %2", _effect_colour.to_rgb_string(), other->_effect_colour.to_rgb_string()));
+ note(NoteType::ERROR, String::compose("text effect colour differs: %1 vs %2", _effect_colour.to_rgb_string(), other->_effect_colour.to_rgb_string()));
same = false;
}
if (_space_before != other->_space_before) {
- note(NoteType::ERROR, String::compose("subtitle space before differs: %1 vs %2", _space_before, other->_space_before));
+ note(NoteType::ERROR, String::compose("text space before differs: %1 vs %2", _space_before, other->_space_before));
same = false;
}
diff --git a/src/subtitle_string.h b/src/text_string.h
index 1ef57ff2..f532bafe 100644
--- a/src/subtitle_string.h
+++ b/src/text_string.h
@@ -32,18 +32,18 @@
*/
-/** @file src/subtitle_string.h
- * @brief SubtitleString class
+/** @file src/text_string.h
+ * @brief TextString class
*/
-#ifndef LIBDCP_SUBTITLE_STRING_H
-#define LIBDCP_SUBTITLE_STRING_H
+#ifndef LIBDCP_TEXT_STRING_H
+#define LIBDCP_TEXT_STRING_H
#include "dcp_time.h"
#include "ruby.h"
-#include "subtitle.h"
+#include "text.h"
#include <boost/optional.hpp>
#include <string>
@@ -51,10 +51,10 @@
namespace dcp {
-/** @class SubtitleString
+/** @class TextString
* @brief A single line of subtitle text with all the associated attributes.
*/
-class SubtitleString : public Subtitle
+class TextString : public Text
{
public:
/** @param font Font ID, or empty to use the default
@@ -80,7 +80,7 @@ public:
* @param fade_down_time Time to fade the text out
* @param space_before Space to add before this string, in ems (could be negative to remove space).
*/
- SubtitleString (
+ TextString(
boost::optional<std::string> font,
bool italic,
bool bold,
@@ -200,7 +200,7 @@ public:
_rubies = std::move(rubies);
}
- bool equals(std::shared_ptr<const dcp::Subtitle> other_sub, EqualityOptions const& options, NoteHandler node) const override;
+ bool equals(std::shared_ptr<const dcp::Text> other_sub, EqualityOptions const& options, NoteHandler node) const override;
private:
/** font ID */
@@ -226,9 +226,10 @@ private:
std::vector<Ruby> _rubies;
};
-bool operator== (SubtitleString const & a, SubtitleString const & b);
-bool operator!= (SubtitleString const & a, SubtitleString const & b);
-std::ostream& operator<< (std::ostream& s, SubtitleString const & sub);
+
+bool operator==(TextString const & a, TextString const & b);
+bool operator!=(TextString const & a, TextString const & b);
+std::ostream& operator<<(std::ostream& s, TextString const & sub);
}
diff --git a/src/text_type.h b/src/text_type.h
new file mode 100644
index 00000000..9a0abb48
--- /dev/null
+++ b/src/text_type.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2024 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_TEXT_TYPE_H
+#define LIBDCP_TEXT_TYPE_H
+
+
+namespace dcp {
+
+
+enum class TextType
+{
+ OPEN_SUBTITLE,
+ OPEN_CAPTION,
+ CLOSED_SUBTITLE,
+ CLOSED_CAPTION
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/types.cc b/src/types.cc
index e2165548..d58256a5 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -310,9 +310,9 @@ ContentVersion::ContentVersion (string label_text_)
void
ContentVersion::as_xml (xmlpp::Element* parent) const
{
- auto cv = parent->add_child("ContentVersion");
- cv->add_child("Id")->add_child_text(id);
- cv->add_child("LabelText")->add_child_text(label_text);
+ auto cv = cxml::add_child(parent, "ContentVersion");
+ cxml::add_text_child(cv, "Id", id);
+ cxml::add_text_child(cv, "LabelText", label_text);
}
@@ -345,7 +345,7 @@ Luminance::set_value (float v)
void
Luminance::as_xml (xmlpp::Element* parent, string ns) const
{
- auto lum = parent->add_child("Luminance", ns);
+ auto lum = cxml::add_child(parent, "Luminance", ns);
lum->set_attribute("units", unit_to_string(_unit));
lum->add_child_text(raw_convert<string>(_value, 3));
}
diff --git a/src/types.h b/src/types.h
index 65840e6d..80ee8933 100644
--- a/src/types.h
+++ b/src/types.h
@@ -260,19 +260,19 @@ extern bool operator!= (Colour const & a, Colour const & b);
typedef boost::function<void (NoteType, std::string)> NoteHandler;
-/** Maximum absolute difference between dcp::SubtitleString::aspect_adjust values that
+/** Maximum absolute difference between dcp::TextString::aspect_adjust values that
* are considered equal
*/
constexpr float ASPECT_ADJUST_EPSILON = 1e-3;
-/** Maximum absolute difference between dcp::SubtitleString alignment values that
+/** Maximum absolute difference between dcp::TextString alignment values that
* are considered equal.
*/
constexpr float ALIGN_EPSILON = 1e-3;
-/** Maximum absolute difference between dcp::SubtitleString space_before values that
+/** Maximum absolute difference between dcp::TextString space_before values that
* are considered equal.
*/
constexpr float SPACE_BEFORE_EPSILON = 1e-3;
diff --git a/src/verify.cc b/src/verify.cc
index ec8925f2..9abda0ff 100644
--- a/src/verify.cc
+++ b/src/verify.cc
@@ -42,21 +42,20 @@
#include "dcp.h"
#include "exceptions.h"
#include "filesystem.h"
-#include "interop_subtitle_asset.h"
-#include "mono_picture_asset.h"
-#include "mono_picture_frame.h"
+#include "interop_text_asset.h"
+#include "mono_j2k_picture_asset.h"
+#include "mono_j2k_picture_frame.h"
#include "raw_convert.h"
#include "reel.h"
-#include "reel_closed_caption_asset.h"
-#include "reel_interop_subtitle_asset.h"
+#include "reel_interop_text_asset.h"
#include "reel_markers_asset.h"
#include "reel_picture_asset.h"
#include "reel_sound_asset.h"
-#include "reel_smpte_subtitle_asset.h"
-#include "reel_subtitle_asset.h"
-#include "smpte_subtitle_asset.h"
-#include "stereo_picture_asset.h"
-#include "stereo_picture_frame.h"
+#include "reel_smpte_text_asset.h"
+#include "reel_text_asset.h"
+#include "smpte_text_asset.h"
+#include "stereo_j2k_picture_asset.h"
+#include "stereo_j2k_picture_frame.h"
#include "verify.h"
#include "verify_j2k.h"
#include <libxml/parserInternals.h>
@@ -89,6 +88,7 @@
using std::cout;
using std::dynamic_pointer_cast;
+using std::function;
using std::list;
using std::make_shared;
using std::map;
@@ -98,7 +98,6 @@ using std::shared_ptr;
using std::string;
using std::vector;
using boost::optional;
-using boost::function;
using namespace dcp;
@@ -294,9 +293,83 @@ parse (XercesDOMParser& parser, string xml)
}
+class Context
+{
+public:
+ Context(
+ std::vector<VerificationNote>& notes_,
+ boost::filesystem::path xsd_dtd_directory_,
+ function<void (string, optional<boost::filesystem::path>)> stage_,
+ function<void (float)> progress_,
+ VerificationOptions options_
+ )
+ : notes(notes_)
+ , xsd_dtd_directory(xsd_dtd_directory_)
+ , stage(stage_)
+ , progress(progress_)
+ , options(options_)
+ {
+
+ }
+
+ Context(Context const&) = delete;
+ Context& operator=(Context const&) = delete;
+
+ template<typename... Args>
+ void ok(dcp::VerificationNote::Code code, Args... args)
+ {
+ add_note({dcp::VerificationNote::Type::OK, code, std::forward<Args>(args)...});
+ }
+
+ template<typename... Args>
+ void warning(dcp::VerificationNote::Code code, Args... args)
+ {
+ add_note({dcp::VerificationNote::Type::WARNING, code, std::forward<Args>(args)...});
+ }
+
+ template<typename... Args>
+ void bv21_error(dcp::VerificationNote::Code code, Args... args)
+ {
+ add_note({dcp::VerificationNote::Type::BV21_ERROR, code, std::forward<Args>(args)...});
+ }
+
+ template<typename... Args>
+ void error(dcp::VerificationNote::Code code, Args... args)
+ {
+ add_note({dcp::VerificationNote::Type::ERROR, code, std::forward<Args>(args)...});
+ }
+
+ void add_note(dcp::VerificationNote note)
+ {
+ if (cpl) {
+ note.set_cpl_id(cpl->id());
+ }
+ notes.push_back(std::move(note));
+ }
+
+ void add_note_if_not_existing(dcp::VerificationNote note)
+ {
+ if (find(notes.begin(), notes.end(), note) == notes.end()) {
+ add_note(note);
+ }
+ }
+
+ std::vector<VerificationNote>& notes;
+ std::shared_ptr<const DCP> dcp;
+ std::shared_ptr<const CPL> cpl;
+ boost::filesystem::path xsd_dtd_directory;
+ function<void (string, optional<boost::filesystem::path>)> stage;
+ function<void (float)> progress;
+ VerificationOptions options;
+
+ boost::optional<string> subtitle_language;
+ boost::optional<int> audio_channels;
+};
+
+
template <class T>
void
-validate_xml (T xml, boost::filesystem::path xsd_dtd_directory, vector<VerificationNote>& notes)
+validate_xml(Context& context, T xml)
{
try {
XMLPlatformUtils::Initialize ();
@@ -349,7 +422,7 @@ validate_xml (T xml, boost::filesystem::path xsd_dtd_directory, vector<Verificat
parser.setValidationSchemaFullChecking(true);
parser.setErrorHandler(&error_handler);
- LocalFileResolver resolver (xsd_dtd_directory);
+ LocalFileResolver resolver(context.xsd_dtd_directory);
parser.setEntityResolver(&resolver);
try {
@@ -367,13 +440,12 @@ validate_xml (T xml, boost::filesystem::path xsd_dtd_directory, vector<Verificat
XMLPlatformUtils::Terminate ();
for (auto i: error_handler.errors()) {
- notes.push_back ({
- VerificationNote::Type::ERROR,
+ context.error(
VerificationNote::Code::INVALID_XML,
i.message(),
boost::trim_copy(i.public_id() + " " + i.system_id()),
i.line()
- });
+ );
}
}
@@ -387,9 +459,8 @@ enum class VerifyAssetResult {
static VerifyAssetResult
verify_asset(
- shared_ptr<const DCP> dcp,
+ Context& context,
shared_ptr<const ReelFileAsset> reel_file_asset,
- function<void (float)> progress,
string* reference_hash,
string* calculated_hash
)
@@ -403,11 +474,11 @@ verify_asset(
* call to hash().
*/
reel_file_asset->asset_ref()->unset_hash();
- *calculated_hash = reel_file_asset->asset_ref()->hash([progress](int64_t done, int64_t total) {
- progress(float(done) / total);
+ *calculated_hash = reel_file_asset->asset_ref()->hash([&context](int64_t done, int64_t total) {
+ context.progress(float(done) / total);
});
- auto pkls = dcp->pkls();
+ auto pkls = context.dcp->pkls();
/* We've read this DCP in so it must have at least one PKL */
DCP_ASSERT (!pkls.empty());
@@ -437,103 +508,106 @@ verify_asset(
}
-void
-verify_language_tag (string tag, vector<VerificationNote>& notes)
+static void
+verify_language_tag(Context& context, string tag)
{
try {
LanguageTag test (tag);
} catch (LanguageTagError &) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_LANGUAGE, tag});
+ context.bv21_error(VerificationNote::Code::INVALID_LANGUAGE, tag);
}
}
static void
-verify_picture_asset(shared_ptr<const ReelFileAsset> reel_file_asset, boost::filesystem::path file, int64_t start_frame, vector<VerificationNote>& notes, function<void (float)> progress)
+verify_picture_asset(
+ Context& context,
+ shared_ptr<const ReelFileAsset> reel_file_asset,
+ boost::filesystem::path file,
+ int64_t start_frame
+ )
{
- auto asset = dynamic_pointer_cast<PictureAsset>(reel_file_asset->asset_ref().asset());
+ auto asset = dynamic_pointer_cast<J2KPictureAsset>(reel_file_asset->asset_ref().asset());
auto const duration = asset->intrinsic_duration ();
- auto check_and_add = [&notes](vector<VerificationNote> const& j2k_notes) {
+ auto check_and_add = [&context](vector<VerificationNote> const& j2k_notes) {
for (auto i: j2k_notes) {
- if (find(notes.begin(), notes.end(), i) == notes.end()) {
- notes.push_back (i);
- }
+ context.add_note_if_not_existing(i);
}
};
int const max_frame = rint(250 * 1000000 / (8 * asset->edit_rate().as_float()));
int const risky_frame = rint(230 * 1000000 / (8 * asset->edit_rate().as_float()));
- auto check_frame_size = [max_frame, risky_frame, file, start_frame](int index, int size, int frame_rate, vector<VerificationNote>& notes) {
+ bool any_bad_frames_seen = false;
+
+ auto check_frame_size = [max_frame, risky_frame, file, start_frame, &any_bad_frames_seen](Context& context, int index, int size, int frame_rate) {
if (size > max_frame) {
- notes.push_back(
+ context.add_note(
VerificationNote(
VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, file
).set_frame(start_frame + index).set_frame_rate(frame_rate)
);
+ any_bad_frames_seen = true;
} else if (size > risky_frame) {
- notes.push_back(
+ context.add_note(
VerificationNote(
VerificationNote::Type::WARNING, VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, file
).set_frame(start_frame + index).set_frame_rate(frame_rate)
);
+ any_bad_frames_seen = true;
}
};
- if (auto mono_asset = dynamic_pointer_cast<MonoPictureAsset>(reel_file_asset->asset_ref().asset())) {
+ if (auto mono_asset = dynamic_pointer_cast<MonoJ2KPictureAsset>(reel_file_asset->asset_ref().asset())) {
auto reader = mono_asset->start_read ();
for (int64_t i = 0; i < duration; ++i) {
auto frame = reader->get_frame (i);
- check_frame_size(i, frame->size(), mono_asset->frame_rate().numerator, notes);
+ check_frame_size(context, i, frame->size(), mono_asset->frame_rate().numerator);
if (!mono_asset->encrypted() || mono_asset->key()) {
vector<VerificationNote> j2k_notes;
verify_j2k(frame, start_frame, i, mono_asset->frame_rate().numerator, j2k_notes);
check_and_add (j2k_notes);
}
- progress (float(i) / duration);
+ context.progress(float(i) / duration);
}
- } else if (auto stereo_asset = dynamic_pointer_cast<StereoPictureAsset>(asset)) {
+ } else if (auto stereo_asset = dynamic_pointer_cast<StereoJ2KPictureAsset>(asset)) {
auto reader = stereo_asset->start_read ();
for (int64_t i = 0; i < duration; ++i) {
auto frame = reader->get_frame (i);
- check_frame_size(i, frame->left()->size(), stereo_asset->frame_rate().numerator, notes);
- check_frame_size(i, frame->right()->size(), stereo_asset->frame_rate().numerator, notes);
+ check_frame_size(context, i, frame->left()->size(), stereo_asset->frame_rate().numerator);
+ check_frame_size(context, i, frame->right()->size(), stereo_asset->frame_rate().numerator);
if (!stereo_asset->encrypted() || stereo_asset->key()) {
vector<VerificationNote> j2k_notes;
verify_j2k(frame->left(), start_frame, i, stereo_asset->frame_rate().numerator, j2k_notes);
verify_j2k(frame->right(), start_frame, i, stereo_asset->frame_rate().numerator, j2k_notes);
check_and_add (j2k_notes);
}
- progress (float(i) / duration);
+ context.progress(float(i) / duration);
}
}
+
+ if (!any_bad_frames_seen) {
+ context.ok(VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES, file);
+ }
}
static void
-verify_main_picture_asset (
- shared_ptr<const DCP> dcp,
- shared_ptr<const ReelPictureAsset> reel_asset,
- int64_t start_frame,
- function<void (string, optional<boost::filesystem::path>)> stage,
- function<void (float)> progress,
- VerificationOptions options,
- vector<VerificationNote>& notes
- )
+verify_main_picture_asset(Context& context, shared_ptr<const ReelPictureAsset> reel_asset, int64_t start_frame)
{
auto asset = reel_asset->asset();
auto const file = *asset->file();
- if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) {
- stage ("Checking picture asset hash", file);
+ if (context.options.check_asset_hashes && (!context.options.maximum_asset_size_for_hash_check || filesystem::file_size(file) < *context.options.maximum_asset_size_for_hash_check)) {
+ context.stage("Checking picture asset hash", file);
string reference_hash;
string calculated_hash;
- auto const r = verify_asset(dcp, reel_asset, progress, &reference_hash, &calculated_hash);
+ auto const r = verify_asset(context, reel_asset, &reference_hash, &calculated_hash);
switch (r) {
case VerifyAssetResult::BAD:
- notes.push_back(
+ context.add_note(
dcp::VerificationNote(
VerificationNote::Type::ERROR,
VerificationNote::Code::INCORRECT_PICTURE_HASH,
@@ -542,17 +616,16 @@ verify_main_picture_asset (
);
break;
case VerifyAssetResult::CPL_PKL_DIFFER:
- notes.push_back ({
- VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_PICTURE_HASHES, file
- });
+ context.error(VerificationNote::Code::MISMATCHED_PICTURE_HASHES, file);
break;
default:
+ context.ok(VerificationNote::Code::CORRECT_PICTURE_HASH, file);
break;
}
}
- stage ("Checking picture frame sizes", asset->file());
- verify_picture_asset(reel_asset, file, start_frame, notes, progress);
+ context.stage("Checking picture frame sizes", asset->file());
+ verify_picture_asset(context, reel_asset, file, start_frame);
/* Only flat/scope allowed by Bv2.1 */
if (
@@ -560,12 +633,7 @@ verify_main_picture_asset (
asset->size() != Size(1998, 1080) &&
asset->size() != Size(4096, 1716) &&
asset->size() != Size(3996, 2160)) {
- notes.push_back({
- VerificationNote::Type::BV21_ERROR,
- VerificationNote::Code::INVALID_PICTURE_SIZE_IN_PIXELS,
- String::compose("%1x%2", asset->size().width, asset->size().height),
- file
- });
+ context.bv21_error(VerificationNote::Code::INVALID_PICTURE_SIZE_IN_PIXELS, String::compose("%1x%2", asset->size().width, asset->size().height), file);
}
/* Only 24, 25, 48fps allowed for 2K */
@@ -573,69 +641,50 @@ verify_main_picture_asset (
(asset->size() == Size(2048, 858) || asset->size() == Size(1998, 1080)) &&
(asset->edit_rate() != Fraction(24, 1) && asset->edit_rate() != Fraction(25, 1) && asset->edit_rate() != Fraction(48, 1))
) {
- notes.push_back({
- VerificationNote::Type::BV21_ERROR,
+ context.bv21_error(
VerificationNote::Code::INVALID_PICTURE_FRAME_RATE_FOR_2K,
String::compose("%1/%2", asset->edit_rate().numerator, asset->edit_rate().denominator),
file
- });
+ );
}
if (asset->size() == Size(4096, 1716) || asset->size() == Size(3996, 2160)) {
/* Only 24fps allowed for 4K */
if (asset->edit_rate() != Fraction(24, 1)) {
- notes.push_back({
- VerificationNote::Type::BV21_ERROR,
+ context.bv21_error(
VerificationNote::Code::INVALID_PICTURE_FRAME_RATE_FOR_4K,
String::compose("%1/%2", asset->edit_rate().numerator, asset->edit_rate().denominator),
file
- });
+ );
}
/* Only 2D allowed for 4K */
- if (dynamic_pointer_cast<const StereoPictureAsset>(asset)) {
- notes.push_back({
- VerificationNote::Type::BV21_ERROR,
+ if (dynamic_pointer_cast<const StereoJ2KPictureAsset>(asset)) {
+ context.bv21_error(
VerificationNote::Code::INVALID_PICTURE_ASSET_RESOLUTION_FOR_3D,
String::compose("%1/%2", asset->edit_rate().numerator, asset->edit_rate().denominator),
file
- });
+ );
}
}
-
}
-struct State
-{
- boost::optional<string> subtitle_language;
- boost::optional<int> audio_channels;
-};
-
-
static void
-verify_main_sound_asset (
- shared_ptr<const DCP> dcp,
- shared_ptr<const ReelSoundAsset> reel_asset,
- function<void (string, optional<boost::filesystem::path>)> stage,
- function<void (float)> progress,
- VerificationOptions options,
- vector<VerificationNote>& notes,
- State& state
- )
+verify_main_sound_asset(Context& context, shared_ptr<const ReelSoundAsset> reel_asset)
{
auto asset = reel_asset->asset();
auto const file = *asset->file();
- if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) {
- stage("Checking sound asset hash", file);
+ if (context.options.check_asset_hashes && (!context.options.maximum_asset_size_for_hash_check || filesystem::file_size(file) < *context.options.maximum_asset_size_for_hash_check)) {
+ context.stage("Checking sound asset hash", file);
string reference_hash;
string calculated_hash;
- auto const r = verify_asset(dcp, reel_asset, progress, &reference_hash, &calculated_hash);
+ auto const r = verify_asset(context, reel_asset, &reference_hash, &calculated_hash);
switch (r) {
case VerifyAssetResult::BAD:
- notes.push_back(
+ context.add_note(
dcp::VerificationNote(
VerificationNote::Type::ERROR,
VerificationNote::Code::INCORRECT_SOUND_HASH,
@@ -644,58 +693,61 @@ verify_main_sound_asset (
);
break;
case VerifyAssetResult::CPL_PKL_DIFFER:
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_HASHES, file});
+ context.error(VerificationNote::Code::MISMATCHED_SOUND_HASHES, file);
break;
default:
break;
}
}
- if (!state.audio_channels) {
- state.audio_channels = asset->channels();
- } else if (*state.audio_channels != asset->channels()) {
- notes.push_back({ VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, file });
+ if (!context.audio_channels) {
+ context.audio_channels = asset->channels();
+ } else if (*context.audio_channels != asset->channels()) {
+ context.error(VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, file);
}
- stage ("Checking sound asset metadata", file);
+ context.stage("Checking sound asset metadata", file);
if (auto lang = asset->language()) {
- verify_language_tag (*lang, notes);
+ verify_language_tag(context, *lang);
}
if (asset->sampling_rate() != 48000) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_SOUND_FRAME_RATE, raw_convert<string>(asset->sampling_rate()), file});
+ context.bv21_error(VerificationNote::Code::INVALID_SOUND_FRAME_RATE, raw_convert<string>(asset->sampling_rate()), file);
+ }
+ if (asset->bit_depth() != 24) {
+ context.error(VerificationNote::Code::INVALID_SOUND_BIT_DEPTH, raw_convert<string>(asset->bit_depth()), file);
}
}
static void
-verify_main_subtitle_reel (shared_ptr<const ReelSubtitleAsset> reel_asset, vector<VerificationNote>& notes)
+verify_main_subtitle_reel(Context& context, shared_ptr<const ReelTextAsset> reel_asset)
{
/* XXX: is Language compulsory? */
if (reel_asset->language()) {
- verify_language_tag (*reel_asset->language(), notes);
+ verify_language_tag(context, *reel_asset->language());
}
if (!reel_asset->entry_point()) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_SUBTITLE_ENTRY_POINT, reel_asset->id() });
+ context.bv21_error(VerificationNote::Code::MISSING_SUBTITLE_ENTRY_POINT, reel_asset->id());
} else if (reel_asset->entry_point().get()) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_SUBTITLE_ENTRY_POINT, reel_asset->id() });
+ context.bv21_error(VerificationNote::Code::INCORRECT_SUBTITLE_ENTRY_POINT, reel_asset->id());
}
}
static void
-verify_closed_caption_reel (shared_ptr<const ReelClosedCaptionAsset> reel_asset, vector<VerificationNote>& notes)
+verify_closed_caption_reel(Context& context, shared_ptr<const ReelTextAsset> reel_asset)
{
/* XXX: is Language compulsory? */
if (reel_asset->language()) {
- verify_language_tag (*reel_asset->language(), notes);
+ verify_language_tag(context, *reel_asset->language());
}
if (!reel_asset->entry_point()) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT, reel_asset->id() });
+ context.bv21_error(VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT, reel_asset->id());
} else if (reel_asset->entry_point().get()) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT, reel_asset->id() });
+ context.bv21_error(VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT, reel_asset->id());
}
}
@@ -703,22 +755,20 @@ verify_closed_caption_reel (shared_ptr<const ReelClosedCaptionAsset> reel_asset,
/** Verify stuff that is common to both subtitles and closed captions */
void
verify_smpte_timed_text_asset (
- shared_ptr<const SMPTESubtitleAsset> asset,
- optional<int64_t> reel_asset_duration,
- vector<VerificationNote>& notes
+ Context& context,
+ shared_ptr<const SMPTETextAsset> asset,
+ optional<int64_t> reel_asset_duration
)
{
if (asset->language()) {
- verify_language_tag (*asset->language(), notes);
+ verify_language_tag(context, *asset->language());
} else {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, *asset->file() });
+ context.bv21_error(VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, *asset->file());
}
auto const size = filesystem::file_size(asset->file().get());
if (size > 115 * 1024 * 1024) {
- notes.push_back (
- { VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, raw_convert<string>(size), *asset->file() }
- );
+ context.bv21_error(VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, raw_convert<string>(size), *asset->file());
}
/* XXX: I'm not sure what Bv2.1_7.2.1 means when it says "the font resource shall not be larger than 10MB"
@@ -730,54 +780,48 @@ verify_smpte_timed_text_asset (
total_size += i.second.size();
}
if (total_size > 10 * 1024 * 1024) {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES, raw_convert<string>(total_size), asset->file().get() });
+ context.bv21_error(VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES, raw_convert<string>(total_size), asset->file().get());
}
if (!asset->start_time()) {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_SUBTITLE_START_TIME, asset->file().get() });
+ context.bv21_error(VerificationNote::Code::MISSING_SUBTITLE_START_TIME, asset->file().get());
} else if (asset->start_time() != Time()) {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_SUBTITLE_START_TIME, asset->file().get() });
+ context.bv21_error(VerificationNote::Code::INVALID_SUBTITLE_START_TIME, asset->file().get());
}
if (reel_asset_duration && *reel_asset_duration != asset->intrinsic_duration()) {
- notes.push_back (
- {
- VerificationNote::Type::BV21_ERROR,
- VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION,
- String::compose("%1 %2", *reel_asset_duration, asset->intrinsic_duration()),
- asset->file().get()
- });
+ context.bv21_error(
+ VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION,
+ String::compose("%1 %2", *reel_asset_duration, asset->intrinsic_duration()),
+ asset->file().get()
+ );
}
}
/** Verify Interop subtitle / CCAP stuff */
void
-verify_interop_text_asset(shared_ptr<const InteropSubtitleAsset> asset, vector<VerificationNote>& notes)
+verify_interop_text_asset(Context& context, shared_ptr<const InteropTextAsset> asset)
{
- if (asset->subtitles().empty()) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_SUBTITLE, asset->id(), asset->file().get() });
+ if (asset->texts().empty()) {
+ context.error(VerificationNote::Code::MISSING_SUBTITLE, asset->id(), asset->file().get());
}
auto const unresolved = asset->unresolved_fonts();
if (!unresolved.empty()) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_FONT, unresolved.front() });
+ context.error(VerificationNote::Code::MISSING_FONT, unresolved.front());
}
}
/** Verify SMPTE subtitle-only stuff */
void
-verify_smpte_subtitle_asset (
- shared_ptr<const SMPTESubtitleAsset> asset,
- vector<VerificationNote>& notes,
- State& state
- )
+verify_smpte_subtitle_asset(Context& context, shared_ptr<const SMPTETextAsset> asset)
{
if (asset->language()) {
- if (!state.subtitle_language) {
- state.subtitle_language = *asset->language();
- } else if (state.subtitle_language != *asset->language()) {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES });
+ if (!context.subtitle_language) {
+ context.subtitle_language = *asset->language();
+ } else if (context.subtitle_language != *asset->language()) {
+ context.bv21_error(VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES);
}
}
@@ -785,14 +829,14 @@ verify_smpte_subtitle_asset (
auto xml_id = asset->xml_id();
if (xml_id) {
if (asset->resource_id().get() != xml_id) {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID });
+ context.bv21_error(VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID);
}
if (asset->id() == asset->resource_id().get() || asset->id() == xml_id) {
- notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID });
+ context.bv21_error(VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID);
}
} else {
- notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED});
+ context.warning(VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED);
}
if (asset->raw_xml()) {
@@ -802,7 +846,7 @@ verify_smpte_subtitle_asset (
auto issue_date = doc.string_child("IssueDate");
std::regex reg("^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d$");
if (!std::regex_match(issue_date, reg)) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, issue_date});
+ context.warning(VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE, issue_date);
}
}
}
@@ -810,26 +854,19 @@ verify_smpte_subtitle_asset (
/** Verify all subtitle stuff */
static void
-verify_subtitle_asset (
- shared_ptr<const SubtitleAsset> asset,
- optional<int64_t> reel_asset_duration,
- function<void (string, optional<boost::filesystem::path>)> stage,
- boost::filesystem::path xsd_dtd_directory,
- vector<VerificationNote>& notes,
- State& state
- )
+verify_subtitle_asset(Context& context, shared_ptr<const TextAsset> asset, optional<int64_t> reel_asset_duration)
{
- stage ("Checking subtitle XML", asset->file());
- /* Note: we must not use SubtitleAsset::xml_as_string() here as that will mean the data on disk
+ context.stage("Checking subtitle XML", asset->file());
+ /* Note: we must not use TextAsset::xml_as_string() here as that will mean the data on disk
* gets passed through libdcp which may clean up and therefore hide errors.
*/
if (asset->raw_xml()) {
- validate_xml (asset->raw_xml().get(), xsd_dtd_directory, notes);
+ validate_xml(context, asset->raw_xml().get());
} else {
- notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED});
+ context.warning(VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED);
}
- auto namespace_count = [](shared_ptr<const SubtitleAsset> asset, string root_node) {
+ auto namespace_count = [](shared_ptr<const TextAsset> asset, string root_node) {
cxml::Document doc(root_node);
doc.read_string(asset->raw_xml().get());
auto root = dynamic_cast<xmlpp::Element*>(doc.node())->cobj();
@@ -840,21 +877,21 @@ verify_subtitle_asset (
return count;
};
- auto interop = dynamic_pointer_cast<const InteropSubtitleAsset>(asset);
+ auto interop = dynamic_pointer_cast<const InteropTextAsset>(asset);
if (interop) {
- verify_interop_text_asset(interop, notes);
+ verify_interop_text_asset(context, interop);
if (namespace_count(asset, "DCSubtitle") > 1) {
- notes.push_back({ VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id() });
+ context.warning(VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id());
}
}
- auto smpte = dynamic_pointer_cast<const SMPTESubtitleAsset>(asset);
+ auto smpte = dynamic_pointer_cast<const SMPTETextAsset>(asset);
if (smpte) {
- verify_smpte_timed_text_asset (smpte, reel_asset_duration, notes);
- verify_smpte_subtitle_asset (smpte, notes, state);
+ verify_smpte_timed_text_asset(context, smpte, reel_asset_duration);
+ verify_smpte_subtitle_asset(context, smpte);
/* This asset may be encrypted and in that case we'll have no raw_xml() */
if (asset->raw_xml() && namespace_count(asset, "SubtitleReel") > 1) {
- notes.push_back({ VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()});
+ context.warning(VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id());
}
}
}
@@ -863,35 +900,33 @@ verify_subtitle_asset (
/** Verify all closed caption stuff */
static void
verify_closed_caption_asset (
- shared_ptr<const SubtitleAsset> asset,
- optional<int64_t> reel_asset_duration,
- function<void (string, optional<boost::filesystem::path>)> stage,
- boost::filesystem::path xsd_dtd_directory,
- vector<VerificationNote>& notes
+ Context& context,
+ shared_ptr<const TextAsset> asset,
+ optional<int64_t> reel_asset_duration
)
{
- stage ("Checking closed caption XML", asset->file());
- /* Note: we must not use SubtitleAsset::xml_as_string() here as that will mean the data on disk
+ context.stage("Checking closed caption XML", asset->file());
+ /* Note: we must not use TextAsset::xml_as_string() here as that will mean the data on disk
* gets passed through libdcp which may clean up and therefore hide errors.
*/
auto raw_xml = asset->raw_xml();
if (raw_xml) {
- validate_xml (*raw_xml, xsd_dtd_directory, notes);
+ validate_xml(context, *raw_xml);
if (raw_xml->size() > 256 * 1024) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES, raw_convert<string>(raw_xml->size()), *asset->file()});
+ context.bv21_error(VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES, raw_convert<string>(raw_xml->size()), *asset->file());
}
} else {
- notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED});
+ context.warning(VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED);
}
- auto interop = dynamic_pointer_cast<const InteropSubtitleAsset>(asset);
+ auto interop = dynamic_pointer_cast<const InteropTextAsset>(asset);
if (interop) {
- verify_interop_text_asset(interop, notes);
+ verify_interop_text_asset(context, interop);
}
- auto smpte = dynamic_pointer_cast<const SMPTESubtitleAsset>(asset);
+ auto smpte = dynamic_pointer_cast<const SMPTETextAsset>(asset);
if (smpte) {
- verify_smpte_timed_text_asset (smpte, reel_asset_duration, notes);
+ verify_smpte_timed_text_asset(context, smpte, reel_asset_duration);
}
}
@@ -900,10 +935,9 @@ verify_closed_caption_asset (
static
void
verify_text_details (
- dcp::Standard standard,
+ Context& context,
vector<shared_ptr<Reel>> reels,
int edit_rate,
- vector<VerificationNote>& notes,
std::function<bool (shared_ptr<Reel>)> check,
std::function<optional<string> (shared_ptr<Reel>)> xml,
std::function<int64_t (shared_ptr<Reel>)> duration,
@@ -997,7 +1031,7 @@ verify_text_details (
auto reel_xml = xml(reels[i]);
if (!reel_xml) {
- notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED});
+ context.warning(VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED);
continue;
}
@@ -1008,7 +1042,7 @@ verify_text_details (
shared_ptr<cxml::Document> doc;
optional<int> tcr;
optional<Time> start_time;
- switch (standard) {
+ switch (context.dcp->standard().get_value_or(dcp::Standard::SMPTE)) {
case dcp::Standard::INTEROP:
doc = make_shared<cxml::Document>("DCSubtitle");
doc->read_string (*reel_xml);
@@ -1031,8 +1065,8 @@ verify_text_details (
}
reel_offset = end;
- if (standard == dcp::Standard::SMPTE && has_text && font_ids.empty()) {
- notes.push_back(dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_LOAD_FONT).set_id(id(reels[i])));
+ if (context.dcp->standard() && *context.dcp->standard() == dcp::Standard::SMPTE && has_text && font_ids.empty()) {
+ context.add_note(dcp::VerificationNote(dcp::VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_LOAD_FONT).set_id(id(reels[i])));
}
}
@@ -1041,47 +1075,34 @@ verify_text_details (
}
if (too_early) {
- notes.push_back({
- VerificationNote::Type::WARNING, VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME
- });
+ context.warning(VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME);
}
if (too_short) {
- notes.push_back ({
- VerificationNote::Type::WARNING, VerificationNote::Code::INVALID_SUBTITLE_DURATION
- });
+ context.warning(VerificationNote::Code::INVALID_SUBTITLE_DURATION);
}
if (too_close) {
- notes.push_back ({
- VerificationNote::Type::WARNING, VerificationNote::Code::INVALID_SUBTITLE_SPACING
- });
+ context.warning(VerificationNote::Code::INVALID_SUBTITLE_SPACING);
}
if (reel_overlap) {
- notes.push_back ({
- VerificationNote::Type::ERROR, VerificationNote::Code::SUBTITLE_OVERLAPS_REEL_BOUNDARY
- });
+ context.error(VerificationNote::Code::SUBTITLE_OVERLAPS_REEL_BOUNDARY);
}
if (empty_text) {
- notes.push_back ({
- VerificationNote::Type::WARNING, VerificationNote::Code::EMPTY_TEXT
- });
+ context.warning(VerificationNote::Code::EMPTY_TEXT);
}
if (missing_load_font_id) {
- notes.push_back(dcp::VerificationNote(VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id(*missing_load_font_id));
+ context.add_note(dcp::VerificationNote(VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT).set_id(*missing_load_font_id));
}
}
static
void
-verify_closed_caption_details (
- vector<shared_ptr<Reel>> reels,
- vector<VerificationNote>& notes
- )
+verify_closed_caption_details(Context& context, vector<shared_ptr<Reel>> reels)
{
std::function<void (cxml::ConstNodePtr node, std::vector<cxml::ConstNodePtr>& text_or_image)> find_text_or_image;
find_text_or_image = [&find_text_or_image](cxml::ConstNodePtr node, std::vector<cxml::ConstNodePtr>& text_or_image) {
@@ -1147,7 +1168,7 @@ verify_closed_caption_details (
for (auto ccap: reel->closed_captions()) {
auto reel_xml = ccap->asset()->raw_xml();
if (!reel_xml) {
- notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED});
+ context.warning(VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED);
continue;
}
@@ -1170,22 +1191,18 @@ verify_closed_caption_details (
}
if (mismatched_valign) {
- notes.push_back ({
- VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN,
- });
+ context.error(VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN);
}
if (incorrect_order) {
- notes.push_back ({
- VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING,
- });
+ context.error(VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING);
}
}
void
dcp::verify_text_lines_and_characters(
- shared_ptr<const SubtitleAsset> asset,
+ shared_ptr<const TextAsset> asset,
int warning_length,
int error_length,
LinesCharactersResult* result
@@ -1213,7 +1230,7 @@ dcp::verify_text_lines_and_characters(
vector<shared_ptr<Event>> events;
- auto position = [](shared_ptr<const SubtitleString> sub) {
+ auto position = [](shared_ptr<const TextString> sub) {
switch (sub->v_align()) {
case VAlign::TOP:
return lrintf(sub->v_position() * 100);
@@ -1227,8 +1244,8 @@ dcp::verify_text_lines_and_characters(
};
/* Make a list of "subtitle starts" and "subtitle ends" events */
- for (auto j: asset->subtitles()) {
- auto text = dynamic_pointer_cast<const SubtitleString>(j);
+ for (auto j: asset->texts()) {
+ auto text = dynamic_pointer_cast<const TextString>(j);
if (text) {
auto in = make_shared<Event>(text->in(), position(text), text->text().length());
events.push_back(in);
@@ -1284,14 +1301,14 @@ dcp::verify_text_lines_and_characters(
static
void
-verify_text_details(dcp::Standard standard, vector<shared_ptr<Reel>> reels, vector<VerificationNote>& notes)
+verify_text_details(Context& context, vector<shared_ptr<Reel>> reels)
{
if (reels.empty()) {
return;
}
if (reels[0]->main_subtitle() && reels[0]->main_subtitle()->asset_ref().resolved()) {
- verify_text_details(standard, reels, reels[0]->main_subtitle()->edit_rate().numerator, notes,
+ verify_text_details(context, reels, reels[0]->main_subtitle()->edit_rate().numerator,
[](shared_ptr<Reel> reel) {
return static_cast<bool>(reel->main_subtitle());
},
@@ -1308,7 +1325,7 @@ verify_text_details(dcp::Standard standard, vector<shared_ptr<Reel>> reels, vect
}
for (auto i = 0U; i < reels[0]->closed_captions().size(); ++i) {
- verify_text_details(standard, reels, reels[0]->closed_captions()[i]->edit_rate().numerator, notes,
+ verify_text_details(context, reels, reels[0]->closed_captions()[i]->edit_rate().numerator,
[i](shared_ptr<Reel> reel) {
return i < reel->closed_captions().size();
},
@@ -1324,12 +1341,12 @@ verify_text_details(dcp::Standard standard, vector<shared_ptr<Reel>> reels, vect
);
}
- verify_closed_caption_details (reels, notes);
+ verify_closed_caption_details(context, reels);
}
void
-verify_extension_metadata(shared_ptr<const CPL> cpl, vector<VerificationNote>& notes)
+verify_extension_metadata(Context& context, shared_ptr<const CPL> cpl)
{
DCP_ASSERT (cpl->file());
cxml::Document doc ("CompositionPlaylist");
@@ -1379,9 +1396,9 @@ verify_extension_metadata(shared_ptr<const CPL> cpl, vector<VerificationNote>& n
}
if (missing) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->id(), cpl->file().get()});
+ context.bv21_error(VerificationNote::Code::MISSING_EXTENSION_METADATA, cpl->file().get());
} else if (!malformed.empty()) {
- notes.push_back ({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_EXTENSION_METADATA, malformed, cpl->file().get()});
+ context.bv21_error(VerificationNote::Code::INVALID_EXTENSION_METADATA, malformed, cpl->file().get());
}
}
@@ -1414,17 +1431,10 @@ pkl_has_encrypted_assets(shared_ptr<const DCP> dcp, shared_ptr<const PKL> pkl)
static
void
verify_reel(
- shared_ptr<const DCP> dcp,
- shared_ptr<const CPL> cpl,
+ Context& context,
shared_ptr<const Reel> reel,
int64_t start_frame,
optional<dcp::Size> main_picture_active_area,
- function<void (string, optional<boost::filesystem::path>)> stage,
- boost::filesystem::path xsd_dtd_directory,
- function<void (float)> progress,
- VerificationOptions options,
- vector<VerificationNote>& notes,
- State& state,
bool* have_main_subtitle,
bool* have_no_main_subtitle,
size_t* most_closed_captions,
@@ -1434,24 +1444,24 @@ verify_reel(
{
for (auto i: reel->assets()) {
if (i->duration() && (i->duration().get() * i->edit_rate().denominator / i->edit_rate().numerator) < 1) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_DURATION, i->id()});
+ context.error(VerificationNote::Code::INVALID_DURATION, i->id());
}
if ((i->intrinsic_duration() * i->edit_rate().denominator / i->edit_rate().numerator) < 1) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_INTRINSIC_DURATION, i->id()});
+ context.error(VerificationNote::Code::INVALID_INTRINSIC_DURATION, i->id());
}
auto file_asset = dynamic_pointer_cast<ReelFileAsset>(i);
if (i->encryptable() && !file_asset->hash()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_HASH, i->id()});
+ context.bv21_error(VerificationNote::Code::MISSING_HASH, i->id());
}
}
- if (dcp->standard() == Standard::SMPTE) {
+ if (context.dcp->standard() == Standard::SMPTE) {
boost::optional<int64_t> duration;
for (auto i: reel->assets()) {
if (!duration) {
duration = i->actual_duration();
} else if (*duration != i->actual_duration()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_ASSET_DURATION});
+ context.bv21_error(VerificationNote::Code::MISMATCHED_ASSET_DURATION);
break;
}
}
@@ -1468,32 +1478,26 @@ verify_reel(
frame_rate.numerator != 50 &&
frame_rate.numerator != 60 &&
frame_rate.numerator != 96)) {
- notes.push_back({
- VerificationNote::Type::ERROR,
- VerificationNote::Code::INVALID_PICTURE_FRAME_RATE,
- String::compose("%1/%2", frame_rate.numerator, frame_rate.denominator)
- });
+ context.error(VerificationNote::Code::INVALID_PICTURE_FRAME_RATE, String::compose("%1/%2", frame_rate.numerator, frame_rate.denominator));
}
/* Check asset */
if (reel->main_picture()->asset_ref().resolved()) {
- verify_main_picture_asset(dcp, reel->main_picture(), start_frame, stage, progress, options, notes);
+ verify_main_picture_asset(context, reel->main_picture(), start_frame);
auto const asset_size = reel->main_picture()->asset()->size();
if (main_picture_active_area) {
if (main_picture_active_area->width > asset_size.width) {
- notes.push_back({
- VerificationNote::Type::ERROR,
- VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
- String::compose("width %1 is bigger than the asset width %2", main_picture_active_area->width, asset_size.width),
- cpl->file().get()
- });
+ context.error(
+ VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
+ String::compose("width %1 is bigger than the asset width %2", main_picture_active_area->width, asset_size.width),
+ context.cpl->file().get()
+ );
}
if (main_picture_active_area->height > asset_size.height) {
- notes.push_back({
- VerificationNote::Type::ERROR,
- VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
- String::compose("height %1 is bigger than the asset height %2", main_picture_active_area->height, asset_size.height),
- cpl->file().get()
- });
+ context.error(
+ VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
+ String::compose("height %1 is bigger than the asset height %2", main_picture_active_area->height, asset_size.height),
+ context.cpl->file().get()
+ );
}
}
}
@@ -1501,13 +1505,13 @@ verify_reel(
}
if (reel->main_sound() && reel->main_sound()->asset_ref().resolved()) {
- verify_main_sound_asset(dcp, reel->main_sound(), stage, progress, options, notes, state);
+ verify_main_sound_asset(context, reel->main_sound());
}
if (reel->main_subtitle()) {
- verify_main_subtitle_reel(reel->main_subtitle(), notes);
+ verify_main_subtitle_reel(context, reel->main_subtitle());
if (reel->main_subtitle()->asset_ref().resolved()) {
- verify_subtitle_asset(reel->main_subtitle()->asset(), reel->main_subtitle()->duration(), stage, xsd_dtd_directory, notes, state);
+ verify_subtitle_asset(context, reel->main_subtitle()->asset(), reel->main_subtitle()->duration());
}
*have_main_subtitle = true;
} else {
@@ -1515,9 +1519,9 @@ verify_reel(
}
for (auto i: reel->closed_captions()) {
- verify_closed_caption_reel(i, notes);
+ verify_closed_caption_reel(context, i);
if (i->asset_ref().resolved()) {
- verify_closed_caption_asset(i->asset(), i->duration(), stage, xsd_dtd_directory, notes);
+ verify_closed_caption_asset(context, i->asset(), i->duration());
}
}
@@ -1526,10 +1530,10 @@ verify_reel(
markers_seen->insert(i);
}
if (reel->main_markers()->entry_point()) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::UNEXPECTED_ENTRY_POINT});
+ context.error(VerificationNote::Code::UNEXPECTED_ENTRY_POINT);
}
if (reel->main_markers()->duration()) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::UNEXPECTED_DURATION});
+ context.error(VerificationNote::Code::UNEXPECTED_DURATION);
}
}
@@ -1541,26 +1545,21 @@ verify_reel(
static
void
-verify_cpl(
- shared_ptr<const DCP> dcp,
- shared_ptr<const CPL> cpl,
- function<void (string, optional<boost::filesystem::path>)> stage,
- boost::filesystem::path xsd_dtd_directory,
- function<void (float)> progress,
- VerificationOptions options,
- vector<VerificationNote>& notes,
- State& state
- )
+verify_cpl(Context& context, shared_ptr<const CPL> cpl)
{
- stage("Checking CPL", cpl->file());
- validate_xml(cpl->file().get(), xsd_dtd_directory, notes);
+ context.stage("Checking CPL", cpl->file());
+ validate_xml(context, cpl->file().get());
if (cpl->any_encrypted() && !cpl->all_encrypted()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::PARTIALLY_ENCRYPTED});
+ context.bv21_error(VerificationNote::Code::PARTIALLY_ENCRYPTED);
+ } else if (cpl->all_encrypted()) {
+ context.ok(VerificationNote::Code::ALL_ENCRYPTED);
+ } else if (!cpl->all_encrypted()) {
+ context.ok(VerificationNote::Code::NONE_ENCRYPTED);
}
for (auto const& i: cpl->additional_subtitle_languages()) {
- verify_language_tag(i, notes);
+ verify_language_tag(context, i);
}
if (!cpl->content_kind().scope() || *cpl->content_kind().scope() == "http://www.smpte-ra.org/schemas/429-7/2006/CPL#standard-content") {
@@ -1572,61 +1571,71 @@ verify_cpl(
transform(name.begin(), name.end(), name.begin(), ::tolower);
auto iter = std::find_if(all.begin(), all.end(), [name](ContentKind const& k) { return !k.scope() && k.name() == name; });
if (iter == all.end()) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_CONTENT_KIND, cpl->content_kind().name()});
+ context.error(VerificationNote::Code::INVALID_CONTENT_KIND, cpl->content_kind().name());
+ } else {
+ context.ok(VerificationNote::Code::VALID_CONTENT_KIND, cpl->content_kind().name());
}
}
if (cpl->release_territory()) {
if (!cpl->release_territory_scope() || cpl->release_territory_scope().get() != "http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata#scope/release-territory/UNM49") {
auto terr = cpl->release_territory().get();
+ bool valid = true;
/* Must be a valid region tag, or "001" */
try {
LanguageTag::RegionSubtag test(terr);
} catch (...) {
if (terr != "001") {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_LANGUAGE, terr});
+ context.bv21_error(VerificationNote::Code::INVALID_LANGUAGE, terr);
+ valid = false;
}
}
+ if (valid) {
+ context.ok(VerificationNote::Code::VALID_RELEASE_TERRITORY, terr);
+ }
}
}
for (auto version: cpl->content_versions()) {
if (version.label_text.empty()) {
- notes.push_back(
- dcp::VerificationNote(VerificationNote::Type::WARNING, VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, cpl->file().get()).set_id(cpl->id())
- );
+ context.warning(VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT, cpl->file().get());
break;
+ } else {
+ context.ok(VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT, version.label_text);
}
}
- if (dcp->standard() == Standard::SMPTE) {
+ if (context.dcp->standard() == Standard::SMPTE) {
if (!cpl->annotation_text()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, cpl->id(), cpl->file().get()});
+ context.bv21_error(VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT, cpl->file().get());
} else if (cpl->annotation_text().get() != cpl->content_title_text()) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, cpl->id(), cpl->file().get()});
+ context.warning(VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT, cpl->file().get());
+ } else {
+ context.ok(VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT, cpl->annotation_text().get());
}
}
- for (auto i: dcp->pkls()) {
+ for (auto i: context.dcp->pkls()) {
/* Check that the CPL's hash corresponds to the PKL */
optional<string> h = i->hash(cpl->id());
auto calculated_cpl_hash = make_digest(ArrayData(*cpl->file()));
if (h && calculated_cpl_hash != *h) {
- notes.push_back(
+ context.add_note(
dcp::VerificationNote(
VerificationNote::Type::ERROR,
VerificationNote::Code::MISMATCHED_CPL_HASHES,
- cpl->id(),
cpl->file().get()
).set_calculated_hash(calculated_cpl_hash).set_reference_hash(*h)
);
+ } else {
+ context.ok(VerificationNote::Code::MATCHING_CPL_HASHES);
}
/* Check that any PKL with a single CPL has its AnnotationText the same as the CPL's ContentTitleText */
optional<string> required_annotation_text;
for (auto j: i->assets()) {
/* See if this is a CPL */
- for (auto k: dcp->cpls()) {
+ for (auto k: context.dcp->cpls()) {
if (j->id() == k->id()) {
if (!required_annotation_text) {
/* First CPL we have found; this is the required AnnotationText unless we find another */
@@ -1640,7 +1649,9 @@ verify_cpl(
}
if (required_annotation_text && i->annotation_text() != required_annotation_text) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, i->id(), i->file().get()});
+ context.bv21_error(VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL, i->id(), i->file().get());
+ } else {
+ context.ok(VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL);
}
}
@@ -1655,38 +1666,39 @@ verify_cpl(
map<Marker, Time> markers_seen;
auto const main_picture_active_area = cpl->main_picture_active_area();
+ bool active_area_ok = true;
if (main_picture_active_area && (main_picture_active_area->width % 2)) {
- notes.push_back({
- VerificationNote::Type::ERROR,
- VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
- String::compose("width %1 is not a multiple of 2", main_picture_active_area->width),
- cpl->file().get()
- });
+ context.error(
+ VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
+ String::compose("width %1 is not a multiple of 2", main_picture_active_area->width),
+ cpl->file().get()
+ );
+ active_area_ok = false;
}
if (main_picture_active_area && (main_picture_active_area->height % 2)) {
- notes.push_back({
- VerificationNote::Type::ERROR,
- VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
- String::compose("height %1 is not a multiple of 2", main_picture_active_area->height),
- cpl->file().get()
- });
+ context.error(
+ VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA,
+ String::compose("height %1 is not a multiple of 2", main_picture_active_area->height),
+ cpl->file().get()
+ );
+ active_area_ok = false;
+ }
+
+ if (main_picture_active_area && active_area_ok) {
+ context.ok(
+ VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA, String::compose("%1x%2", main_picture_active_area->width, main_picture_active_area->height),
+ cpl->file().get()
+ );
}
int64_t frame = 0;
for (auto reel: cpl->reels()) {
- stage("Checking reel", optional<boost::filesystem::path>());
+ context.stage("Checking reel", optional<boost::filesystem::path>());
verify_reel(
- dcp,
- cpl,
+ context,
reel,
frame,
main_picture_active_area,
- stage,
- xsd_dtd_directory,
- progress,
- options,
- notes,
- state,
&have_main_subtitle,
&have_no_main_subtitle,
&most_closed_captions,
@@ -1696,51 +1708,50 @@ verify_cpl(
frame += reel->duration();
}
- verify_text_details(dcp->standard().get_value_or(dcp::Standard::SMPTE), cpl->reels(), notes);
+ verify_text_details(context, cpl->reels());
- if (dcp->standard() == Standard::SMPTE) {
+ if (context.dcp->standard() == Standard::SMPTE) {
if (auto msc = cpl->main_sound_configuration()) {
- if (state.audio_channels && msc->channels() != *state.audio_channels) {
- notes.push_back({
- VerificationNote::Type::ERROR,
- VerificationNote::Code::INVALID_MAIN_SOUND_CONFIGURATION,
- String::compose("MainSoundConfiguration has %1 channels but sound assets have %2", msc->channels(), *state.audio_channels),
- cpl->file().get()
- });
+ if (context.audio_channels && msc->channels() != *context.audio_channels) {
+ context.error(
+ VerificationNote::Code::INVALID_MAIN_SOUND_CONFIGURATION,
+ String::compose("MainSoundConfiguration has %1 channels but sound assets have %2", msc->channels(), *context.audio_channels),
+ cpl->file().get()
+ );
}
}
if (have_main_subtitle && have_no_main_subtitle) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS});
+ context.bv21_error(VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS);
}
if (fewest_closed_captions != most_closed_captions) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS});
+ context.bv21_error(VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS);
}
if (cpl->content_kind() == ContentKind::FEATURE) {
if (markers_seen.find(Marker::FFEC) == markers_seen.end()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_FFEC_IN_FEATURE});
+ context.bv21_error(VerificationNote::Code::MISSING_FFEC_IN_FEATURE);
}
if (markers_seen.find(Marker::FFMC) == markers_seen.end()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_FFMC_IN_FEATURE});
+ context.bv21_error(VerificationNote::Code::MISSING_FFMC_IN_FEATURE);
}
}
auto ffoc = markers_seen.find(Marker::FFOC);
if (ffoc == markers_seen.end()) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::MISSING_FFOC});
+ context.warning(VerificationNote::Code::MISSING_FFOC);
} else if (ffoc->second.e != 1) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_FFOC, raw_convert<string>(ffoc->second.e)});
+ context.warning(VerificationNote::Code::INCORRECT_FFOC, raw_convert<string>(ffoc->second.e));
}
auto lfoc = markers_seen.find(Marker::LFOC);
if (lfoc == markers_seen.end()) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::MISSING_LFOC});
+ context.warning(VerificationNote::Code::MISSING_LFOC);
} else {
auto lfoc_time = lfoc->second.as_editable_units_ceil(lfoc->second.tcr);
if (lfoc_time != (cpl->reels().back()->duration() - 1)) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_LFOC, raw_convert<string>(lfoc_time)});
+ context.warning(VerificationNote::Code::INCORRECT_LFOC, raw_convert<string>(lfoc_time));
}
}
@@ -1752,12 +1763,12 @@ verify_cpl(
}
if (result.line_count_exceeded) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT});
+ context.warning(VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT);
}
if (result.error_length_exceeded) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH});
+ context.warning(VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH);
} else if (result.warning_length_exceeded) {
- notes.push_back({VerificationNote::Type::WARNING, VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH});
+ context.warning(VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH);
}
result = LinesCharactersResult();
@@ -1770,26 +1781,26 @@ verify_cpl(
}
if (result.line_count_exceeded) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT});
+ context.bv21_error(VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT);
}
if (result.error_length_exceeded) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH});
+ context.bv21_error(VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH);
}
if (!cpl->read_composition_metadata()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get()});
+ context.bv21_error(VerificationNote::Code::MISSING_CPL_METADATA, cpl->file().get());
} else if (!cpl->version_number()) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->id(), cpl->file().get()});
+ context.bv21_error(VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER, cpl->file().get());
}
- verify_extension_metadata(cpl, notes);
+ verify_extension_metadata(context, cpl);
if (cpl->any_encrypted()) {
cxml::Document doc("CompositionPlaylist");
DCP_ASSERT(cpl->file());
doc.read_file(dcp::filesystem::fix_long_path(cpl->file().get()));
if (!doc.optional_node_child("Signature")) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, cpl->id(), cpl->file().get()});
+ context.bv21_error(VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT, cpl->file().get());
}
}
}
@@ -1798,27 +1809,22 @@ verify_cpl(
static
void
-verify_pkl(
- shared_ptr<const DCP> dcp,
- shared_ptr<const PKL> pkl,
- boost::filesystem::path xsd_dtd_directory,
- vector<VerificationNote>& notes
- )
+verify_pkl(Context& context, shared_ptr<const PKL> pkl)
{
- validate_xml(pkl->file().get(), xsd_dtd_directory, notes);
+ validate_xml(context, pkl->file().get());
- if (pkl_has_encrypted_assets(dcp, pkl)) {
+ if (pkl_has_encrypted_assets(context.dcp, pkl)) {
cxml::Document doc("PackingList");
doc.read_file(dcp::filesystem::fix_long_path(pkl->file().get()));
if (!doc.optional_node_child("Signature")) {
- notes.push_back({VerificationNote::Type::BV21_ERROR, VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, pkl->id(), pkl->file().get()});
+ context.bv21_error(VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT, pkl->id(), pkl->file().get());
}
}
set<string> uuid_set;
for (auto asset: pkl->assets()) {
if (!uuid_set.insert(asset->id()).second) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL, pkl->id(), pkl->file().get()});
+ context.error(VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL, pkl->id(), pkl->file().get());
break;
}
}
@@ -1828,28 +1834,24 @@ verify_pkl(
static
void
-verify_assetmap(
- shared_ptr<const DCP> dcp,
- boost::filesystem::path xsd_dtd_directory,
- vector<VerificationNote>& notes
- )
+verify_assetmap(Context& context, shared_ptr<const DCP> dcp)
{
auto asset_map = dcp->asset_map();
DCP_ASSERT(asset_map);
- validate_xml(asset_map->file().get(), xsd_dtd_directory, notes);
+ validate_xml(context, asset_map->file().get());
set<string> uuid_set;
for (auto const& asset: asset_map->assets()) {
if (!uuid_set.insert(asset.id()).second) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP, asset_map->id(), asset_map->file().get()});
+ context.error(VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP, asset_map->id(), asset_map->file().get());
break;
}
}
}
-vector<VerificationNote>
+dcp::VerificationResult
dcp::verify (
vector<boost::filesystem::path> directories,
vector<dcp::DecryptedKDM> kdms,
@@ -1865,7 +1867,7 @@ dcp::verify (
*xsd_dtd_directory = filesystem::canonical(*xsd_dtd_directory);
vector<VerificationNote> notes;
- State state{};
+ Context context(notes, *xsd_dtd_directory, stage, progress, options);
vector<shared_ptr<DCP>> dcps;
for (auto i: directories) {
@@ -1874,22 +1876,25 @@ dcp::verify (
for (auto dcp: dcps) {
stage ("Checking DCP", dcp->directory());
+
+ context.dcp = dcp;
+
bool carry_on = true;
try {
dcp->read (&notes, true);
} catch (MissingAssetmapError& e) {
- notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
+ context.error(VerificationNote::Code::FAILED_READ, string(e.what()));
carry_on = false;
} catch (ReadError& e) {
- notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
+ context.error(VerificationNote::Code::FAILED_READ, string(e.what()));
} catch (XMLError& e) {
- notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
+ context.error(VerificationNote::Code::FAILED_READ, string(e.what()));
} catch (MXFFileError& e) {
- notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
+ context.error(VerificationNote::Code::FAILED_READ, string(e.what()));
} catch (BadURNUUIDError& e) {
- notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
+ context.error(VerificationNote::Code::FAILED_READ, string(e.what()));
} catch (cxml::Error& e) {
- notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
+ context.error(VerificationNote::Code::FAILED_READ, string(e.what()));
}
if (!carry_on) {
@@ -1906,16 +1911,9 @@ dcp::verify (
for (auto cpl: dcp->cpls()) {
try {
- verify_cpl(
- dcp,
- cpl,
- stage,
- *xsd_dtd_directory,
- progress,
- options,
- notes,
- state
- );
+ context.cpl = cpl;
+ verify_cpl(context, cpl);
+ context.cpl.reset();
} catch (ReadError& e) {
notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::FAILED_READ, string(e.what())});
}
@@ -1923,23 +1921,23 @@ dcp::verify (
for (auto pkl: dcp->pkls()) {
stage("Checking PKL", pkl->file());
- verify_pkl(dcp, pkl, *xsd_dtd_directory, notes);
+ verify_pkl(context, pkl);
}
if (dcp->asset_map_file()) {
stage("Checking ASSETMAP", dcp->asset_map_file().get());
- verify_assetmap(dcp, *xsd_dtd_directory, notes);
+ verify_assetmap(context, dcp);
} else {
- notes.push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_ASSETMAP});
+ context.error(VerificationNote::Code::MISSING_ASSETMAP);
}
}
- return notes;
+ return { notes, dcps };
}
string
-dcp::note_to_string (VerificationNote note)
+dcp::note_to_string(VerificationNote note, function<string (string)> process_string, function<string (string)> process_filename)
{
/** These strings should say what is wrong, incorporating any extra details (ID, filenames etc.).
*
@@ -1951,238 +1949,269 @@ dcp::note_to_string (VerificationNote note)
* End messages with a full stop.
* Messages should not mention whether or not their errors are a part of Bv2.1.
*/
+
+ auto filename = [note, process_filename]() {
+ return process_filename(note.file()->filename().string());
+ };
+
+#define compose(format, ...) String::compose(process_string(format), __VA_ARGS__)
+
switch (note.code()) {
case VerificationNote::Code::FAILED_READ:
- return *note.note();
+ return process_string(*note.note());
+ case VerificationNote::Code::MATCHING_CPL_HASHES:
+ return process_string("The hash of the CPL in the PKL matches the CPL file.");
case VerificationNote::Code::MISMATCHED_CPL_HASHES:
- return String::compose("The hash (%1) of the CPL (%2) in the PKL does not agree with the CPL file (%3).", note.reference_hash().get(), note.note().get(), note.calculated_hash().get());
+ return compose("The hash (%1) of the CPL (%2) in the PKL does not agree with the CPL file (%3).", note.reference_hash().get(), note.cpl_id().get(), note.calculated_hash().get());
case VerificationNote::Code::INVALID_PICTURE_FRAME_RATE:
- return String::compose("The picture in a reel has an invalid frame rate %1.", note.note().get());
+ return compose("The picture in a reel has an invalid frame rate %1.", note.note().get());
case VerificationNote::Code::INCORRECT_PICTURE_HASH:
- return String::compose("The hash (%1) of the picture asset %2 does not agree with the PKL file (%3).", note.calculated_hash().get(), note.file()->filename(), note.reference_hash().get());
+ return compose("The hash (%1) of the picture asset %2 does not agree with the PKL file (%3).", note.calculated_hash().get(), filename(), note.reference_hash().get());
+ case VerificationNote::Code::CORRECT_PICTURE_HASH:
+ return compose("The picture asset %1 has the expected hashes in the CPL and PKL.", filename());
case VerificationNote::Code::MISMATCHED_PICTURE_HASHES:
- return String::compose("The PKL and CPL hashes differ for the picture asset %1.", note.file()->filename());
+ return compose("The PKL and CPL hashes differ for the picture asset %1.", filename());
case VerificationNote::Code::INCORRECT_SOUND_HASH:
- return String::compose("The hash (%1) of the sound asset %2 does not agree with the PKL file (%3).", note.calculated_hash().get(), note.file()->filename(), note.reference_hash().get());
+ return compose("The hash (%1) of the sound asset %2 does not agree with the PKL file (%3).", note.calculated_hash().get(), filename(), note.reference_hash().get());
case VerificationNote::Code::MISMATCHED_SOUND_HASHES:
- return String::compose("The PKL and CPL hashes differ for the sound asset %1.", note.file()->filename());
+ return compose("The PKL and CPL hashes differ for the sound asset %1.", filename());
case VerificationNote::Code::EMPTY_ASSET_PATH:
- return "The asset map contains an empty asset path.";
+ return process_string("The asset map contains an empty asset path.");
case VerificationNote::Code::MISSING_ASSET:
- return String::compose("The file %1 for an asset in the asset map cannot be found.", note.file()->filename());
+ return compose("The file %1 for an asset in the asset map cannot be found.", filename());
case VerificationNote::Code::MISMATCHED_STANDARD:
- return "The DCP contains both SMPTE and Interop parts.";
+ return process_string("The DCP contains both SMPTE and Interop parts.");
case VerificationNote::Code::INVALID_XML:
- return String::compose("An XML file is badly formed: %1 (%2:%3)", note.note().get(), note.file()->filename(), note.line().get());
+ return compose("An XML file is badly formed: %1 (%2:%3)", note.note().get(), filename(), note.line().get());
case VerificationNote::Code::MISSING_ASSETMAP:
- return "No valid ASSETMAP or ASSETMAP.xml was found.";
+ return process_string("No valid ASSETMAP or ASSETMAP.xml was found.");
case VerificationNote::Code::INVALID_INTRINSIC_DURATION:
- return String::compose("The intrinsic duration of the asset %1 is less than 1 second.", note.note().get());
+ return compose("The intrinsic duration of the asset %1 is less than 1 second.", note.note().get());
case VerificationNote::Code::INVALID_DURATION:
- return String::compose("The duration of the asset %1 is less than 1 second.", note.note().get());
+ return compose("The duration of the asset %1 is less than 1 second.", note.note().get());
+ case VerificationNote::Code::VALID_PICTURE_FRAME_SIZES_IN_BYTES:
+ return compose("Each frame of the picture asset %1 has a bit rate safely under the limit of 250Mbit/s.", filename());
case VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES:
- return String::compose(
+ return compose(
"Frame %1 (timecode %2) in asset %3 has an instantaneous bit rate that is larger than the limit of 250Mbit/s.",
note.frame().get(),
dcp::Time(note.frame().get(), note.frame_rate().get(), note.frame_rate().get()).as_string(dcp::Standard::SMPTE),
- note.file()->filename()
+ filename()
);
case VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES:
- return String::compose(
+ return compose(
"Frame %1 (timecode %2) in asset %3 has an instantaneous bit rate that is close to the limit of 250Mbit/s.",
note.frame().get(),
dcp::Time(note.frame().get(), note.frame_rate().get(), note.frame_rate().get()).as_string(dcp::Standard::SMPTE),
- note.file()->filename()
+ filename()
);
case VerificationNote::Code::EXTERNAL_ASSET:
- return String::compose("The asset %1 that this DCP refers to is not included in the DCP. It may be a VF.", note.note().get());
+ return compose("The asset %1 that this DCP refers to is not included in the DCP. It may be a VF.", note.note().get());
case VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD:
- return String::compose("The asset %1 is 3D but its MXF is marked as 2D.", note.file()->filename());
+ return compose("The asset %1 is 3D but its MXF is marked as 2D.", filename());
case VerificationNote::Code::INVALID_STANDARD:
return "This DCP does not use the SMPTE standard.";
case VerificationNote::Code::INVALID_LANGUAGE:
- return String::compose("The DCP specifies a language '%1' which does not conform to the RFC 5646 standard.", note.note().get());
+ return compose("The DCP specifies a language '%1' which does not conform to the RFC 5646 standard.", note.note().get());
+ case VerificationNote::Code::VALID_RELEASE_TERRITORY:
+ return compose("Valid release territory %1.", note.note().get());
case VerificationNote::Code::INVALID_PICTURE_SIZE_IN_PIXELS:
- return String::compose("The size %1 of picture asset %2 is not allowed.", note.note().get(), note.file()->filename());
+ return compose("The size %1 of picture asset %2 is not allowed.", note.note().get(), filename());
case VerificationNote::Code::INVALID_PICTURE_FRAME_RATE_FOR_2K:
- return String::compose("The frame rate %1 of picture asset %2 is not allowed for 2K DCPs.", note.note().get(), note.file()->filename());
+ return compose("The frame rate %1 of picture asset %2 is not allowed for 2K DCPs.", note.note().get(), filename());
case VerificationNote::Code::INVALID_PICTURE_FRAME_RATE_FOR_4K:
- return String::compose("The frame rate %1 of picture asset %2 is not allowed for 4K DCPs.", note.note().get(), note.file()->filename());
+ return compose("The frame rate %1 of picture asset %2 is not allowed for 4K DCPs.", note.note().get(), filename());
case VerificationNote::Code::INVALID_PICTURE_ASSET_RESOLUTION_FOR_3D:
- return "3D 4K DCPs are not allowed.";
+ return process_string("3D 4K DCPs are not allowed.");
case VerificationNote::Code::INVALID_CLOSED_CAPTION_XML_SIZE_IN_BYTES:
- return String::compose("The size %1 of the closed caption asset %2 is larger than the 256KB maximum.", note.note().get(), note.file()->filename());
+ return compose("The size %1 of the closed caption asset %2 is larger than the 256KB maximum.", note.note().get(), filename());
case VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES:
- return String::compose("The size %1 of the timed text asset %2 is larger than the 115MB maximum.", note.note().get(), note.file()->filename());
+ return compose("The size %1 of the timed text asset %2 is larger than the 115MB maximum.", note.note().get(), filename());
case VerificationNote::Code::INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES:
- return String::compose("The size %1 of the fonts in timed text asset %2 is larger than the 10MB maximum.", note.note().get(), note.file()->filename());
+ return compose("The size %1 of the fonts in timed text asset %2 is larger than the 10MB maximum.", note.note().get(), filename());
case VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE:
- return String::compose("The XML for the SMPTE subtitle asset %1 has no <Language> tag.", note.file()->filename());
+ return compose("The XML for the SMPTE subtitle asset %1 has no <Language> tag.", filename());
case VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES:
- return "Some subtitle assets have different <Language> tags than others";
+ return process_string("Some subtitle assets have different <Language> tags than others");
case VerificationNote::Code::MISSING_SUBTITLE_START_TIME:
- return String::compose("The XML for the SMPTE subtitle asset %1 has no <StartTime> tag.", note.file()->filename());
+ return compose("The XML for the SMPTE subtitle asset %1 has no <StartTime> tag.", filename());
case VerificationNote::Code::INVALID_SUBTITLE_START_TIME:
- return String::compose("The XML for a SMPTE subtitle asset %1 has a non-zero <StartTime> tag.", note.file()->filename());
+ return compose("The XML for a SMPTE subtitle asset %1 has a non-zero <StartTime> tag.", filename());
case VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME:
- return "The first subtitle or closed caption is less than 4 seconds from the start of the DCP.";
+ return process_string("The first subtitle or closed caption is less than 4 seconds from the start of the DCP.");
case VerificationNote::Code::INVALID_SUBTITLE_DURATION:
- return "At least one subtitle lasts less than 15 frames.";
+ return process_string("At least one subtitle lasts less than 15 frames.");
case VerificationNote::Code::INVALID_SUBTITLE_SPACING:
- return "At least one pair of subtitles is separated by less than 2 frames.";
+ return process_string("At least one pair of subtitles is separated by less than 2 frames.");
case VerificationNote::Code::SUBTITLE_OVERLAPS_REEL_BOUNDARY:
- return "At least one subtitle extends outside of its reel.";
+ return process_string("At least one subtitle extends outside of its reel.");
case VerificationNote::Code::INVALID_SUBTITLE_LINE_COUNT:
- return "There are more than 3 subtitle lines in at least one place in the DCP.";
+ return process_string("There are more than 3 subtitle lines in at least one place in the DCP.");
case VerificationNote::Code::NEARLY_INVALID_SUBTITLE_LINE_LENGTH:
- return "There are more than 52 characters in at least one subtitle line.";
+ return process_string("There are more than 52 characters in at least one subtitle line.");
case VerificationNote::Code::INVALID_SUBTITLE_LINE_LENGTH:
- return "There are more than 79 characters in at least one subtitle line.";
+ return process_string("There are more than 79 characters in at least one subtitle line.");
case VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_COUNT:
- return "There are more than 3 closed caption lines in at least one place.";
+ return process_string("There are more than 3 closed caption lines in at least one place.");
case VerificationNote::Code::INVALID_CLOSED_CAPTION_LINE_LENGTH:
- return "There are more than 32 characters in at least one closed caption line.";
+ return process_string("There are more than 32 characters in at least one closed caption line.");
case VerificationNote::Code::INVALID_SOUND_FRAME_RATE:
- return String::compose("The sound asset %1 has a sampling rate of %2", note.file()->filename(), note.note().get());
+ return compose("The sound asset %1 has a sampling rate of %2", filename(), note.note().get());
+ case VerificationNote::Code::INVALID_SOUND_BIT_DEPTH:
+ return compose("The sound asset %1 has a bit depth of %2", filename(), note.note().get());
case VerificationNote::Code::MISSING_CPL_ANNOTATION_TEXT:
- return String::compose("The CPL %1 has no <AnnotationText> tag.", note.note().get());
+ return compose("The CPL %1 has no <AnnotationText> tag.", note.cpl_id().get());
case VerificationNote::Code::MISMATCHED_CPL_ANNOTATION_TEXT:
- return String::compose("The CPL %1 has an <AnnotationText> which differs from its <ContentTitleText>.", note.note().get());
+ return compose("The CPL %1 has an <AnnotationText> which differs from its <ContentTitleText>.", note.cpl_id().get());
+ case VerificationNote::Code::VALID_CPL_ANNOTATION_TEXT:
+ return compose("Valid CPL annotation text %1", note.note().get());
case VerificationNote::Code::MISMATCHED_ASSET_DURATION:
- return "All assets in a reel do not have the same duration.";
+ return process_string("All assets in a reel do not have the same duration.");
case VerificationNote::Code::MISSING_MAIN_SUBTITLE_FROM_SOME_REELS:
- return "At least one reel contains a subtitle asset, but some reel(s) do not.";
+ return process_string("At least one reel contains a subtitle asset, but some reel(s) do not.");
case VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS:
- return "At least one reel has closed captions, but reels have different numbers of closed caption assets.";
+ return process_string("At least one reel has closed captions, but reels have different numbers of closed caption assets.");
case VerificationNote::Code::MISSING_SUBTITLE_ENTRY_POINT:
- return String::compose("The subtitle asset %1 has no <EntryPoint> tag.", note.note().get());
+ return compose("The subtitle asset %1 has no <EntryPoint> tag.", note.note().get());
case VerificationNote::Code::INCORRECT_SUBTITLE_ENTRY_POINT:
- return String::compose("The subtitle asset %1 has an <EntryPoint> other than 0.", note.note().get());
+ return compose("The subtitle asset %1 has an <EntryPoint> other than 0.", note.note().get());
case VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT:
- return String::compose("The closed caption asset %1 has no <EntryPoint> tag.", note.note().get());
+ return compose("The closed caption asset %1 has no <EntryPoint> tag.", note.note().get());
case VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT:
- return String::compose("The closed caption asset %1 has an <EntryPoint> other than 0.", note.note().get());
+ return compose("The closed caption asset %1 has an <EntryPoint> other than 0.", note.note().get());
case VerificationNote::Code::MISSING_HASH:
- return String::compose("The asset %1 has no <Hash> tag in the CPL.", note.note().get());
+ return compose("The asset %1 has no <Hash> tag in the CPL.", note.note().get());
case VerificationNote::Code::MISSING_FFEC_IN_FEATURE:
- return "The DCP is marked as a Feature but there is no FFEC (first frame of end credits) marker.";
+ return process_string("The DCP is marked as a Feature but there is no FFEC (first frame of end credits) marker.");
case VerificationNote::Code::MISSING_FFMC_IN_FEATURE:
- return "The DCP is marked as a Feature but there is no FFMC (first frame of moving credits) marker.";
+ return process_string("The DCP is marked as a Feature but there is no FFMC (first frame of moving credits) marker.");
case VerificationNote::Code::MISSING_FFOC:
- return "There should be a FFOC (first frame of content) marker.";
+ return process_string("There should be a FFOC (first frame of content) marker.");
case VerificationNote::Code::MISSING_LFOC:
- return "There should be a LFOC (last frame of content) marker.";
+ return process_string("There should be a LFOC (last frame of content) marker.");
case VerificationNote::Code::INCORRECT_FFOC:
- return String::compose("The FFOC marker is %1 instead of 1", note.note().get());
+ return compose("The FFOC marker is %1 instead of 1", note.note().get());
case VerificationNote::Code::INCORRECT_LFOC:
- return String::compose("The LFOC marker is %1 instead of 1 less than the duration of the last reel.", note.note().get());
+ return compose("The LFOC marker is %1 instead of 1 less than the duration of the last reel.", note.note().get());
case VerificationNote::Code::MISSING_CPL_METADATA:
- return String::compose("The CPL %1 has no <CompositionMetadataAsset> tag.", note.note().get());
+ return compose("The CPL %1 has no <CompositionMetadataAsset> tag.", note.cpl_id().get());
case VerificationNote::Code::MISSING_CPL_METADATA_VERSION_NUMBER:
- return String::compose("The CPL %1 has no <VersionNumber> in its <CompositionMetadataAsset>.", note.note().get());
+ return compose("The CPL %1 has no <VersionNumber> in its <CompositionMetadataAsset>.", note.cpl_id().get());
case VerificationNote::Code::MISSING_EXTENSION_METADATA:
- return String::compose("The CPL %1 has no <ExtensionMetadata> in its <CompositionMetadataAsset>.", note.note().get());
+ return compose("The CPL %1 has no <ExtensionMetadata> in its <CompositionMetadataAsset>.", note.cpl_id().get());
case VerificationNote::Code::INVALID_EXTENSION_METADATA:
- return String::compose("The CPL %1 has a malformed <ExtensionMetadata> (%2).", note.file()->filename(), note.note().get());
+ return compose("The CPL %1 has a malformed <ExtensionMetadata> (%2).", filename(), note.note().get());
case VerificationNote::Code::UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT:
- return String::compose("The CPL %1, which has encrypted content, is not signed.", note.note().get());
+ return compose("The CPL %1, which has encrypted content, is not signed.", note.cpl_id().get());
case VerificationNote::Code::UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT:
- return String::compose("The PKL %1, which has encrypted content, is not signed.", note.note().get());
+ return compose("The PKL %1, which has encrypted content, is not signed.", note.note().get());
case VerificationNote::Code::MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL:
- return String::compose("The PKL %1 has only one CPL but its <AnnotationText> does not match the CPL's <ContentTitleText>.", note.note().get());
+ return compose("The PKL %1 has only one CPL but its <AnnotationText> does not match the CPL's <ContentTitleText>.", note.note().get());
+ case VerificationNote::Code::MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL:
+ return process_string("The PKL and CPL annotation texts match.");
+ case VerificationNote::Code::ALL_ENCRYPTED:
+ return process_string("All the assets are encrypted.");
+ case VerificationNote::Code::NONE_ENCRYPTED:
+ return process_string("All the assets are unencrypted.");
case VerificationNote::Code::PARTIALLY_ENCRYPTED:
- return "Some assets are encrypted but some are not.";
+ return process_string("Some assets are encrypted but some are not.");
case VerificationNote::Code::INVALID_JPEG2000_CODESTREAM:
- return String::compose(
+ return compose(
"Frame %1 (timecode %2) has an invalid JPEG2000 codestream (%3).",
note.frame().get(),
dcp::Time(note.frame().get(), note.frame_rate().get(), note.frame_rate().get()).as_string(dcp::Standard::SMPTE),
note.note().get()
);
case VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K:
- return String::compose("The JPEG2000 codestream uses %1 guard bits in a 2K image instead of 1.", note.note().get());
+ return compose("The JPEG2000 codestream uses %1 guard bits in a 2K image instead of 1.", note.note().get());
case VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_4K:
- return String::compose("The JPEG2000 codestream uses %1 guard bits in a 4K image instead of 2.", note.note().get());
+ return compose("The JPEG2000 codestream uses %1 guard bits in a 4K image instead of 2.", note.note().get());
case VerificationNote::Code::INVALID_JPEG2000_TILE_SIZE:
- return "The JPEG2000 tile size is not the same as the image size.";
+ return process_string("The JPEG2000 tile size is not the same as the image size.");
case VerificationNote::Code::INVALID_JPEG2000_CODE_BLOCK_WIDTH:
- return String::compose("The JPEG2000 codestream uses a code block width of %1 instead of 32.", note.note().get());
+ return compose("The JPEG2000 codestream uses a code block width of %1 instead of 32.", note.note().get());
case VerificationNote::Code::INVALID_JPEG2000_CODE_BLOCK_HEIGHT:
- return String::compose("The JPEG2000 codestream uses a code block height of %1 instead of 32.", note.note().get());
+ return compose("The JPEG2000 codestream uses a code block height of %1 instead of 32.", note.note().get());
case VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_2K:
- return String::compose("%1 POC markers found in 2K JPEG2000 codestream instead of 0.", note.note().get());
+ return compose("%1 POC markers found in 2K JPEG2000 codestream instead of 0.", note.note().get());
case VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_4K:
- return String::compose("%1 POC markers found in 4K JPEG2000 codestream instead of 1.", note.note().get());
+ return compose("%1 POC markers found in 4K JPEG2000 codestream instead of 1.", note.note().get());
case VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER:
- return String::compose("Incorrect POC marker content found (%1).", note.note().get());
+ return compose("Incorrect POC marker content found (%1).", note.note().get());
case VerificationNote::Code::INVALID_JPEG2000_POC_MARKER_LOCATION:
- return "POC marker found outside main header.";
+ return process_string("POC marker found outside main header.");
case VerificationNote::Code::INVALID_JPEG2000_TILE_PARTS_FOR_2K:
- return String::compose("The JPEG2000 codestream has %1 tile parts in a 2K image instead of 3.", note.note().get());
+ return compose("The JPEG2000 codestream has %1 tile parts in a 2K image instead of 3.", note.note().get());
case VerificationNote::Code::INVALID_JPEG2000_TILE_PARTS_FOR_4K:
- return String::compose("The JPEG2000 codestream has %1 tile parts in a 4K image instead of 6.", note.note().get());
+ return compose("The JPEG2000 codestream has %1 tile parts in a 4K image instead of 6.", note.note().get());
case VerificationNote::Code::MISSING_JPEG200_TLM_MARKER:
- return "No TLM marker was found in a JPEG2000 codestream.";
+ return process_string("No TLM marker was found in a JPEG2000 codestream.");
case VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID:
- return "The Resource ID in a timed text MXF did not match the ID of the contained XML.";
+ return process_string("The Resource ID in a timed text MXF did not match the ID of the contained XML.");
case VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID:
- return "The Asset ID in a timed text MXF is the same as the Resource ID or that of the contained XML.";
+ return process_string("The Asset ID in a timed text MXF is the same as the Resource ID or that of the contained XML.");
case VerificationNote::Code::MISMATCHED_TIMED_TEXT_DURATION:
{
vector<string> parts;
boost::split (parts, note.note().get(), boost::is_any_of(" "));
DCP_ASSERT (parts.size() == 2);
- return String::compose("The reel duration of some timed text (%1) is not the same as the ContainerDuration of its MXF (%2).", parts[0], parts[1]);
+ return compose("The reel duration of some timed text (%1) is not the same as the ContainerDuration of its MXF (%2).", parts[0], parts[1]);
}
case VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED:
- return "Some aspect of this DCP could not be checked because it is encrypted.";
+ return process_string("Some aspect of this DCP could not be checked because it is encrypted.");
case VerificationNote::Code::EMPTY_TEXT:
- return "There is an empty <Text> node in a subtitle or closed caption.";
+ return process_string("There is an empty <Text> node in a subtitle or closed caption.");
case VerificationNote::Code::MISMATCHED_CLOSED_CAPTION_VALIGN:
- return "Some closed <Text> or <Image> nodes have different vertical alignments within a <Subtitle>.";
+ return process_string("Some closed <Text> or <Image> nodes have different vertical alignments within a <Subtitle>.");
case VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ORDERING:
- return "Some closed captions are not listed in the order of their vertical position.";
+ return process_string("Some closed captions are not listed in the order of their vertical position.");
case VerificationNote::Code::UNEXPECTED_ENTRY_POINT:
- return "There is an <EntryPoint> node inside a <MainMarkers>.";
+ return process_string("There is an <EntryPoint> node inside a <MainMarkers>.");
case VerificationNote::Code::UNEXPECTED_DURATION:
- return "There is an <Duration> node inside a <MainMarkers>.";
+ return process_string("There is an <Duration> node inside a <MainMarkers>.");
case VerificationNote::Code::INVALID_CONTENT_KIND:
- return String::compose("<ContentKind> has an invalid value %1.", note.note().get());
+ return compose("<ContentKind> has an invalid value %1.", note.note().get());
+ case VerificationNote::Code::VALID_CONTENT_KIND:
+ return compose("Valid <ContentKind> %1.", note.note().get());
case VerificationNote::Code::INVALID_MAIN_PICTURE_ACTIVE_AREA:
- return String::compose("<MainPictureActiveaArea> has an invalid value: %1", note.note().get());
+ return compose("<MainPictureActiveaArea> has an invalid value: %1", note.note().get());
+ case VerificationNote::Code::VALID_MAIN_PICTURE_ACTIVE_AREA:
+ return compose("<MainPictureActiveaArea> %1 is valid", note.note().get());
case VerificationNote::Code::DUPLICATE_ASSET_ID_IN_PKL:
- return String::compose("The PKL %1 has more than one asset with the same ID.", note.note().get());
+ return compose("The PKL %1 has more than one asset with the same ID.", note.note().get());
case VerificationNote::Code::DUPLICATE_ASSET_ID_IN_ASSETMAP:
- return String::compose("The ASSETMAP %1 has more than one asset with the same ID.", note.note().get());
+ return compose("The ASSETMAP %1 has more than one asset with the same ID.", note.note().get());
case VerificationNote::Code::MISSING_SUBTITLE:
- return String::compose("The subtitle asset %1 has no subtitles.", note.note().get());
+ return compose("The subtitle asset %1 has no subtitles.", note.note().get());
case VerificationNote::Code::INVALID_SUBTITLE_ISSUE_DATE:
- return String::compose("<IssueDate> has an invalid value: %1", note.note().get());
+ return compose("<IssueDate> has an invalid value: %1", note.note().get());
case VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS:
- return String::compose("The sound assets do not all have the same channel count; the first to differ is %1", note.file()->filename());
+ return compose("The sound assets do not all have the same channel count; the first to differ is %1", filename());
case VerificationNote::Code::INVALID_MAIN_SOUND_CONFIGURATION:
- return String::compose("<MainSoundConfiguration> has an invalid value: %1", note.note().get());
+ return compose("<MainSoundConfiguration> has an invalid value: %1", note.note().get());
case VerificationNote::Code::MISSING_FONT:
- return String::compose("The font file for font ID \"%1\" was not found, or was not referred to in the ASSETMAP.", note.note().get());
+ return compose("The font file for font ID \"%1\" was not found, or was not referred to in the ASSETMAP.", note.note().get());
case VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE:
- return String::compose(
+ return compose(
"Frame %1 has an image component that is too large (component %2 is %3 bytes in size).",
note.frame().get(), note.component().get(), note.size().get()
);
case VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT:
- return String::compose("The XML in the subtitle asset %1 has more than one namespace declaration.", note.note().get());
+ return compose("The XML in the subtitle asset %1 has more than one namespace declaration.", note.note().get());
case VerificationNote::Code::MISSING_LOAD_FONT_FOR_FONT:
- return String::compose("A subtitle or closed caption refers to a font with ID %1 that does not have a corresponding <LoadFont> node", note.id().get());
+ return compose("A subtitle or closed caption refers to a font with ID %1 that does not have a corresponding <LoadFont> node", note.id().get());
case VerificationNote::Code::MISSING_LOAD_FONT:
- return String::compose("The SMPTE subtitle asset %1 has <Text> nodes but no <LoadFont> node", note.id().get());
+ return compose("The SMPTE subtitle asset %1 has <Text> nodes but no <LoadFont> node", note.id().get());
case VerificationNote::Code::MISMATCHED_ASSET_MAP_ID:
- return String::compose("The asset with ID %1 in the asset map actually has an id of %2", note.id().get(), note.other_id().get());
+ return compose("The asset with ID %1 in the asset map actually has an id of %2", note.id().get(), note.other_id().get());
case VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT:
- return String::compose("The <LabelText> in a <ContentVersion> in CPL %1 is empty", note.id().get());
+ return compose("The <LabelText> in a <ContentVersion> in CPL %1 is empty", note.cpl_id().get());
+ case VerificationNote::Code::VALID_CONTENT_VERSION_LABEL_TEXT:
+ return compose("CPL has valid <ContentVersion> %1", note.note().get());
case VerificationNote::Code::INVALID_CPL_NAMESPACE:
- return String::compose("The namespace %1 in CPL %2 is invalid", note.note().get(), note.file()->filename());
+ return compose("The namespace %1 in CPL %2 is invalid", note.note().get(), note.cpl_id().get());
case VerificationNote::Code::MISSING_CPL_CONTENT_VERSION:
- return String::compose("The CPL %1 has no <ContentVersion> tag", note.note().get());
+ return compose("The CPL %1 has no <ContentVersion> tag", note.cpl_id().get());
}
return "";
@@ -2203,12 +2232,20 @@ dcp::operator== (dcp::VerificationNote const& a, dcp::VerificationNote const& b)
a.id() == b.id() &&
a.other_id() == b.other_id() &&
a.frame_rate() == b.frame_rate() &&
+ a.cpl_id() == b.cpl_id() &&
a.reference_hash() == b.reference_hash() &&
a.calculated_hash() == b.calculated_hash();
}
bool
+dcp::operator!=(dcp::VerificationNote const& a, dcp::VerificationNote const& b)
+{
+ return !(a == b);
+}
+
+
+bool
dcp::operator< (dcp::VerificationNote const& a, dcp::VerificationNote const& b)
{
if (a.type() != b.type()) {
diff --git a/src/verify.h b/src/verify.h
index 204d83b0..01ea0efe 100644
--- a/src/verify.h
+++ b/src/verify.h
@@ -58,19 +58,21 @@
namespace dcp {
-class SubtitleAsset;
+class DCP;
+class TextAsset;
class VerificationNote
{
public:
enum class Type {
+ OK,
ERROR,
BV21_ERROR, ///< may not always be considered an error, but violates a "shall" requirement of Bv2.1
WARNING
};
- /** Codes for errors or warnings from verifying DCPs.
+ /** Codes for successful checks, errors or warnings from verifying DCPs.
*
* The names should (in general) answer the question "what is wrong?" with an answer that begins "There is a ..."
* e.g. "There is a INCORRECT_CPL_HASH"
@@ -101,6 +103,7 @@ public:
* note contains (probably technical) details
*/
FAILED_READ,
+ MATCHING_CPL_HASHES,
/** The hash of the CPL in the PKL does not agree with the CPL file
* note contains CPL ID
* file contains CPL filename
@@ -112,6 +115,7 @@ public:
* note contains the invalid frame rate as "<numerator>/<denominator>"
*/
INVALID_PICTURE_FRAME_RATE,
+ CORRECT_PICTURE_HASH,
/** The hash of a main picture asset does not agree with the PKL file
* file contains the picture asset filename
* calculated_hash contains the current hash of the picture MXF
@@ -156,6 +160,7 @@ public:
* note contains asset ID
*/
INVALID_DURATION,
+ VALID_PICTURE_FRAME_SIZES_IN_BYTES,
/** The JPEG2000 data in at least one picture frame is larger than the equivalent of 250Mbit/s
* file contains the picture asset filename
*/
@@ -178,6 +183,7 @@ public:
* note contains the invalid language
*/
INVALID_LANGUAGE,
+ VALID_RELEASE_TERRITORY,
/** A picture asset does not have one of the required Bv2.1 sizes (in pixels) [Bv2.1_7.1]
* note contains the incorrect size as "<width>x<height>"
* file contains the asset filename
@@ -250,6 +256,11 @@ public:
* file contains the asset filename
*/
INVALID_SOUND_FRAME_RATE,
+ /** The audio bit depth must be 24
+ * note contains the invalid bit depth
+ * file contains the asset filename
+ */
+ INVALID_SOUND_BIT_DEPTH,
/** The CPL has no _<AnnotationText>_ tag [Bv2.1_8.1]
* note contains the CPL ID
* file contains the CPL filename
@@ -260,6 +271,7 @@ public:
* file contains the CPL filename
*/
MISMATCHED_CPL_ANNOTATION_TEXT,
+ VALID_CPL_ANNOTATION_TEXT,
/** At least one asset in a reel does not have the same duration as the others */
MISMATCHED_ASSET_DURATION,
/** If one reel has a _MainSubtitle_, all must have them */
@@ -337,6 +349,11 @@ public:
* file contains the PKL filename
*/
MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL,
+ MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL,
+ /** All content is encrypted */
+ ALL_ENCRYPTED,
+ /** No content is encrypted */
+ NONE_ENCRYPTED,
/** Some, but not all content, is encrypted */
PARTIALLY_ENCRYPTED,
/** General error during JPEG2000 codestream verification
@@ -409,11 +426,13 @@ public:
UNEXPECTED_DURATION,
/** A <ContentKind> has been specified with either no scope or the SMPTE 429-7 scope, but which is not one of those allowed */
INVALID_CONTENT_KIND,
+ VALID_CONTENT_KIND,
/** Either the width or height of a <MainPictureActiveArea> in a CPL is either not an even number, or bigger than the corresponding asset dimension.
* note contains details of what is wrong
* file contains the CPL filename
*/
INVALID_MAIN_PICTURE_ACTIVE_AREA,
+ VALID_MAIN_PICTURE_ACTIVE_AREA,
/** A PKL has more than one asset with the same ID
* note contains the PKL ID
* file contains the PKL filename
@@ -478,13 +497,13 @@ public:
* file contains the CPL filename
*/
EMPTY_CONTENT_VERSION_LABEL_TEXT,
+ VALID_CONTENT_VERSION_LABEL_TEXT,
/** The CPL namespace is not valid.
* note contains the invalid namespace
* file contains the CPL filename
*/
INVALID_CPL_NAMESPACE,
/** A SMPTE CPL does not contain a _<ContentVersion>_ tag
- * note contains the CPL ID
* file contains the CPL filename
*/
MISSING_CPL_CONTENT_VERSION
@@ -545,6 +564,7 @@ private:
ID,
OTHER_ID,
FRAME_RATE,
+ CPL_ID,
CALCULATED_HASH,
REFERENCE_HASH
};
@@ -644,6 +664,15 @@ public:
return data<std::string>(Data::REFERENCE_HASH);
}
+ VerificationNote& set_cpl_id(std::string id) {
+ _data[Data::CPL_ID] = id;
+ return *this;
+ }
+
+ boost::optional<std::string> cpl_id() const {
+ return data<std::string>(Data::CPL_ID);
+ }
+
private:
Type _type;
Code _code;
@@ -661,18 +690,30 @@ struct VerificationOptions
};
-std::vector<VerificationNote> verify (
+struct VerificationResult
+{
+ std::vector<VerificationNote> notes;
+ std::vector<std::shared_ptr<dcp::DCP>> dcps;
+};
+
+
+VerificationResult verify(
std::vector<boost::filesystem::path> directories,
std::vector<dcp::DecryptedKDM> kdms,
- boost::function<void (std::string, boost::optional<boost::filesystem::path>)> stage,
- boost::function<void (float)> progress,
+ std::function<void (std::string, boost::optional<boost::filesystem::path>)> stage,
+ std::function<void (float)> progress,
VerificationOptions options = {},
boost::optional<boost::filesystem::path> xsd_dtd_directory = boost::optional<boost::filesystem::path>()
);
-std::string note_to_string (dcp::VerificationNote note);
+std::string note_to_string(
+ dcp::VerificationNote note,
+ std::function<std::string (std::string)> process_string = [](std::string s) { return s; },
+ std::function<std::string (std::string)> process_filename = [](std::string s) { return s; }
+ );
bool operator== (dcp::VerificationNote const& a, dcp::VerificationNote const& b);
+bool operator!=(dcp::VerificationNote const& a, dcp::VerificationNote const& b);
bool operator< (dcp::VerificationNote const& a, dcp::VerificationNote const& b);
std::ostream& operator<<(std::ostream& s, dcp::VerificationNote const& note);
@@ -687,7 +728,7 @@ struct LinesCharactersResult
extern void verify_text_lines_and_characters(
- std::shared_ptr<const dcp::SubtitleAsset> asset,
+ std::shared_ptr<const dcp::TextAsset> asset,
int warning_length,
int error_length,
dcp::LinesCharactersResult* result
diff --git a/src/verify_j2k.h b/src/verify_j2k.h
index 58c8f4b7..dbfc488b 100644
--- a/src/verify_j2k.h
+++ b/src/verify_j2k.h
@@ -37,8 +37,8 @@
*/
-#ifndef LIBDCP_VERIFY_J2K
-#define LIBDCP_VERIFY_J2K
+#ifndef LIBDCP_VERIFY_J2K_H
+#define LIBDCP_VERIFY_J2K_H
#include "verify.h"
diff --git a/src/verify_report.cc b/src/verify_report.cc
new file mode 100644
index 00000000..bcbda1ff
--- /dev/null
+++ b/src/verify_report.cc
@@ -0,0 +1,151 @@
+/*
+ Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "compose.hpp"
+#include "cpl.h"
+#include "dcp.h"
+#include "file.h"
+#include "reel.h"
+#include "reel_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_text_asset.h"
+#include "verify.h"
+#include "verify_report.h"
+
+
+using std::shared_ptr;
+using std::string;
+using std::vector;
+using boost::optional;
+using namespace dcp;
+
+
+void write_line(File& file, string format)
+{
+ file.puts(string(format + "\n").c_str());
+}
+
+
+template <typename... Args>
+void write_line(File& file, string format, Args... args)
+{
+ file.puts(String::compose(format + "\n", std::forward<Args>(args)...).c_str());
+}
+
+
+void
+dcp::verify_report(dcp::VerificationResult const& result, Formatter& formatter)
+{
+ auto document = formatter.document();
+ auto body = formatter.body();
+
+ formatter.heading("DCP verification report");
+
+ if (result.dcps.size() > 1) {
+ formatter.subheading("DCPs");
+ } else {
+ formatter.subheading("DCP");
+ }
+
+ auto reel_asset_details = [&formatter](shared_ptr<dcp::ReelAsset> asset) {
+ formatter.list_item(String::compose("UUID: %1", asset->id()));
+ formatter.list_item(String::compose("Intrinsic duration: %1", asset->intrinsic_duration()));
+ formatter.list_item(String::compose("Entry point: %1", asset->entry_point().get_value_or(0)));
+ formatter.list_item(String::compose("Duration: %1", asset->duration().get_value_or(0)));
+ if (asset->annotation_text()) {
+ formatter.list_item(String::compose("Annotation text: %1", *asset->annotation_text()));
+ }
+ };
+
+ auto write_notes = [&formatter](dcp::VerificationResult const& result, optional<string> cpl_id) {
+ for (auto note: result.notes) {
+ if (note.cpl_id() == cpl_id) {
+ auto const note_as_string = dcp::note_to_string(note, formatter.process_string(), formatter.process_filename());
+ switch (note.type()) {
+ case dcp::VerificationNote::Type::OK:
+ formatter.list_item(note_as_string, string("ok"));
+ break;
+ case dcp::VerificationNote::Type::WARNING:
+ formatter.list_item(note_as_string, string("warning"));
+ break;
+ case dcp::VerificationNote::Type::ERROR:
+ formatter.list_item(note_as_string, string("error"));
+ break;
+ case dcp::VerificationNote::Type::BV21_ERROR:
+ formatter.list_item(note_as_string, string("bv21-error"));
+ break;
+ }
+ }
+ }
+ };
+
+ for (auto dcp: result.dcps) {
+ auto ul = formatter.unordered_list();
+ for (auto cpl: dcp->cpls()) {
+ formatter.list_item(String::compose("CPL ID: %1", cpl->id()));
+ int reel_index = 1;
+ for (auto reel: cpl->reels()) {
+ formatter.list_item(String::compose("Reel: %1", reel_index++));
+ auto ul2 = formatter.unordered_list();
+ if (auto pic = reel->main_picture()) {
+ formatter.list_item("Main picture");
+ auto ul3 = formatter.unordered_list();
+ reel_asset_details(pic);
+ formatter.list_item(String::compose("Frame rate: %1", pic->frame_rate().numerator));
+ formatter.list_item(String::compose("Screen aspect ratio: %1x%2", pic->screen_aspect_ratio().numerator, pic->screen_aspect_ratio().denominator));
+ }
+ if (auto sound = reel->main_sound()) {
+ formatter.list_item("Main sound");
+ auto ul3 = formatter.unordered_list();
+ reel_asset_details(sound);
+ }
+ if (auto sub = reel->main_subtitle()) {
+ formatter.list_item("Main subtitle");
+ auto ul3 = formatter.unordered_list();
+ reel_asset_details(sub);
+ if (sub->language()) {
+ formatter.list_item(String::compose("Language: %1", *sub->language()));
+ }
+ }
+ }
+ write_notes(result, cpl->id());
+ }
+ }
+
+ if (std::count_if(result.notes.begin(), result.notes.end(), [](VerificationNote const& note) { return !note.cpl_id(); }) > 0) {
+ formatter.subheading("Report");
+ write_notes(result, {});
+ }
+}
+
diff --git a/src/verify_report.h b/src/verify_report.h
new file mode 100644
index 00000000..a8ea4152
--- /dev/null
+++ b/src/verify_report.h
@@ -0,0 +1,240 @@
+/*
+ Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "compose.hpp"
+#include "file.h"
+#include "verify.h"
+#include <boost/filesystem.hpp>
+#include <vector>
+
+
+namespace dcp {
+
+
+class Formatter
+{
+public:
+ Formatter(boost::filesystem::path file)
+ : _file(file, "w")
+ {}
+
+ class Wrap
+ {
+ public:
+ Wrap() = default;
+
+ Wrap(Formatter* formatter, std::string const& close)
+ : _formatter(formatter)
+ , _close(close)
+ {}
+
+ Wrap(Formatter* formatter, std::string const& close, std::function<void ()> closer)
+ : _formatter(formatter)
+ , _close(close)
+ , _closer(closer)
+ {}
+
+ Wrap(Wrap&& other)
+ {
+ std::swap(_formatter, other._formatter);
+ std::swap(_close, other._close);
+ std::swap(_closer, other._closer);
+ }
+
+ ~Wrap()
+ {
+ if (_formatter) {
+ _formatter->file().puts(_close.c_str());
+ }
+ if (_closer) {
+ _closer();
+ }
+ }
+
+ private:
+ Formatter* _formatter = nullptr;
+ std::string _close;
+ std::function<void ()> _closer = nullptr;
+ };
+
+ virtual Wrap document() { return {}; }
+
+ virtual void heading(std::string const& text) = 0;
+ virtual void subheading(std::string const& text) = 0;
+ virtual Wrap body() { return {}; }
+
+ virtual Wrap unordered_list() = 0;
+ virtual void list_item(std::string const& text, boost::optional<std::string> type = {}) = 0;
+
+ virtual std::function<std::string (std::string)> process_string() = 0;
+ virtual std::function<std::string (std::string)> process_filename() = 0;
+
+ dcp::File& file() {
+ return _file;
+ }
+
+protected:
+ dcp::File _file;
+};
+
+
+class TextFormatter : public Formatter
+{
+public:
+ TextFormatter(boost::filesystem::path file)
+ : Formatter(file)
+ {}
+
+ void heading(std::string const& text) override {
+ print(text);
+ }
+
+ void subheading(std::string const& text) override {
+ print("");
+ print(text);
+ }
+
+ Wrap unordered_list() override {
+ _indent++;
+ return Wrap(this, "", [this]() { _indent--; });
+ }
+
+ void list_item(std::string const& text, boost::optional<std::string> type = {}) override {
+ LIBDCP_UNUSED(type);
+ for (int i = 0; i < _indent * 2; ++i) {
+ _file.puts(" ");
+ }
+ _file.puts("* ");
+ print(text);
+ }
+
+ std::function<std::string (std::string)> process_string() override {
+ return [](std::string s) {
+ return s;
+ };
+ }
+
+ std::function<std::string (std::string)> process_filename() override {
+ return [](std::string s) {
+ return s;
+ };
+ }
+
+private:
+ void print(std::string const& text) {
+ _file.puts(text.c_str());
+ _file.puts("\n");
+ }
+
+ int _indent = 0;
+};
+
+
+class HTMLFormatter : public Formatter
+{
+public:
+ HTMLFormatter(boost::filesystem::path file)
+ : Formatter(file)
+ {}
+
+ void heading(std::string const& text) override {
+ tagged("h1", text);
+ }
+
+ void subheading(std::string const& text) override {
+ tagged("h2", text);
+ }
+
+ Wrap document() override {
+ auto html = wrapped("html");
+ auto head = wrapped("head");
+ auto style = wrapped("style");
+ _file.puts("li {\n"
+ " margin: 2px;\n"
+ " padding: 2px 2px 2px 1em;\n"
+ "}\n"
+ );
+ _file.puts("li.ok {\n"
+ " background-color: #00ff00;\n"
+ "}\n"
+ "li.warning {\n"
+ " background-color: #ffa500;\n"
+ "}\n"
+ "li.error {\n"
+ " background-color: #ff0000;\n"
+ "}\n"
+ "li.bv21-error {\n"
+ " background-color: #ff6666;\n"
+ "}\n"
+ "ul {\n"
+ " list-style: none;\n"
+ "}\n"
+ );
+ return html;
+ }
+
+ Wrap body() override {
+ return wrapped("body");
+ }
+
+ Wrap unordered_list() override {
+ return wrapped("ul");
+ }
+
+ void list_item(std::string const& text, boost::optional<std::string> type = {}) override {
+ if (type) {
+ _file.puts(dcp::String::compose("<li class=\"%1\">%2", *type, text).c_str());
+ } else {
+ _file.puts(dcp::String::compose("<li>%1", text).c_str());
+ }
+ }
+
+ std::function<std::string (std::string)> process_string() override {
+ return [](std::string s) {
+ boost::replace_all(s, "<", "&lt;");
+ boost::replace_all(s, ">", "&gt;");
+ return s;
+ };
+ }
+
+ std::function<std::string (std::string)> process_filename() override {
+ return [](std::string s) {
+ return String::compose("<code>%1</code>", s);
+ };
+ }
+
+private:
+ void tagged(std::string tag, std::string content) {
+ _file.puts(String::compose("<%1>%2</%3>\n", tag, content, tag).c_str());
+ };
+
+ Wrap wrapped(std::string const& tag) {
+ _file.puts(String::compose("<%1>", tag).c_str());
+ return Wrap(this, String::compose("</%1>", tag));
+ };
+};
+
+
+extern void verify_report(dcp::VerificationResult const& result, Formatter& formatter);
+
+
+}
+
diff --git a/src/warnings.h b/src/warnings.h
index a3448d9c..7a19b902 100644
--- a/src/warnings.h
+++ b/src/warnings.h
@@ -43,7 +43,7 @@
_Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"") \
_Pragma("GCC diagnostic ignored \"-Wtautological-overlap-compare\"")
#else
-#if __GNUC__ >= 9
+#if __GNUC__ >= 14
#define LIBDCP_DISABLE_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
@@ -54,6 +54,21 @@
_Pragma("GCC diagnostic ignored \"-Wdeprecated-copy\"") \
_Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") \
_Pragma("GCC diagnostic ignored \"-Wunused-function\"") \
+ _Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"") \
+ _Pragma("GCC diagnostic ignored \"-Wignored-qualifiers\"") \
+ _Pragma("GCC diagnostic ignored \"-Wtemplate-id-cdtor\"")
+#elif __GNUC__ >= 9
+#define LIBDCP_DISABLE_WARNINGS \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
+ _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
+ _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ _Pragma("GCC diagnostic ignored \"-Wparentheses\"") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-copy\"") \
+ _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") \
+ _Pragma("GCC diagnostic ignored \"-Wunused-function\"") \
+ _Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"") \
_Pragma("GCC diagnostic ignored \"-Wignored-qualifiers\"")
#elif __GNUC__ >= 5
#define LIBDCP_DISABLE_WARNINGS \
diff --git a/src/wscript b/src/wscript
index c2d499c8..1f0190fc 100644
--- a/src/wscript
+++ b/src/wscript
@@ -36,14 +36,14 @@ def build(bld):
source = """
array_data.cc
asset.cc
- asset_map.cc
asset_factory.cc
+ asset_map.cc
asset_writer.cc
atmos_asset.cc
atmos_asset_writer.cc
bitstream.cc
- certificate_chain.cc
certificate.cc
+ certificate_chain.cc
chromaticity.cc
colour_conversion.cc
combine.cc
@@ -58,13 +58,16 @@ def build(bld):
exceptions.cc
file.cc
filesystem.cc
+ ffmpeg_image.cc
font_asset.cc
fsk.cc
gamma_transfer_function.cc
h_align.cc
identity_transfer_function.cc
interop_load_font_node.cc
- interop_subtitle_asset.cc
+ interop_text_asset.cc
+ j2k_picture_asset.cc
+ j2k_picture_asset_writer.cc
j2k_transcode.cc
key.cc
language_tag.cc
@@ -72,52 +75,54 @@ def build(bld):
locale_convert.cc
metadata.cc
modified_gamma_transfer_function.cc
- mono_picture_asset.cc
- mono_picture_asset_writer.cc
- mono_picture_frame.cc
+ mono_j2k_picture_asset.cc
+ mono_j2k_picture_asset_writer.cc
+ mono_j2k_picture_frame.cc
+ mono_mpeg2_picture_asset.cc
+ mono_mpeg2_picture_asset_writer.cc
+ mono_mpeg2_picture_frame.cc
+ mpeg2_picture_asset.cc
+ mpeg2_picture_asset_writer.cc
+ mpeg2_transcode.cc
mxf.cc
name_format.cc
object.cc
openjpeg_image.cc
picture_asset.cc
- picture_asset_writer.cc
pkl.cc
rating.cc
raw_convert.cc
reel.cc
reel_asset.cc
reel_atmos_asset.cc
- reel_closed_caption_asset.cc
reel_file_asset.cc
- reel_interop_closed_caption_asset.cc
- reel_interop_subtitle_asset.cc
+ reel_interop_text_asset.cc
+ reel_markers_asset.cc
reel_mono_picture_asset.cc
reel_picture_asset.cc
- reel_markers_asset.cc
- reel_smpte_closed_caption_asset.cc
- reel_smpte_subtitle_asset.cc
+ reel_smpte_text_asset.cc
reel_sound_asset.cc
reel_stereo_picture_asset.cc
- reel_subtitle_asset.cc
+ reel_text_asset.cc
ref.cc
rgb_xyz.cc
ruby.cc
s_gamut3_transfer_function.cc
search.cc
smpte_load_font_node.cc
- smpte_subtitle_asset.cc
+ smpte_text_asset.cc
sound_asset.cc
sound_asset_writer.cc
sound_frame.cc
- stereo_picture_asset.cc
- stereo_picture_asset_writer.cc
- stereo_picture_frame.cc
- subtitle.cc
- subtitle_asset.cc
- subtitle_asset_internal.cc
- subtitle_image.cc
+ stereo_j2k_picture_asset.cc
+ stereo_j2k_picture_asset_writer.cc
+ stereo_j2k_picture_frame.cc
+ text_asset.cc
+ text_asset_internal.cc
+ text.cc
+ text_image.cc
subtitle_standard.cc
- subtitle_string.cc
+ text_string.cc
transfer_function.cc
types.cc
utc_offset.cc
@@ -125,6 +130,7 @@ def build(bld):
v_align.cc
verify.cc
verify_j2k.cc
+ verify_report.cc
version.cc
"""
@@ -139,8 +145,9 @@ def build(bld):
atmos_asset_reader.h
atmos_asset_writer.h
atmos_frame.h
- certificate_chain.h
+ behaviour.h
certificate.h
+ certificate_chain.h
chromaticity.h
colour_conversion.h
combine.h
@@ -161,12 +168,16 @@ def build(bld):
filesystem.h
font_asset.h
frame.h
+ frame_info.h
fsk.h
gamma_transfer_function.h
h_align.h
identity_transfer_function.h
interop_load_font_node.h
- interop_subtitle_asset.h
+ interop_text_asset.h
+ ffmpeg_image.h
+ j2k_picture_asset.h
+ j2k_picture_asset_writer.h
j2k_transcode.h
key.h
language_tag.h
@@ -174,57 +185,61 @@ def build(bld):
local_time.h
locale_convert.h
metadata.h
- mono_picture_asset.h
- mono_picture_asset_reader.h
- mono_picture_asset_writer.h
- mono_picture_frame.h
+ mpeg2_picture_asset_writer.h
modified_gamma_transfer_function.h
+ mono_j2k_picture_asset.h
+ mono_j2k_picture_asset_reader.h
+ mono_j2k_picture_asset_writer.h
+ mono_j2k_picture_frame.h
+ mono_mpeg2_picture_asset.h
+ mono_mpeg2_picture_asset_reader.h
+ mono_mpeg2_picture_asset_writer.h
+ mono_mpeg2_picture_frame.h
+ mpeg2_picture_asset.h
+ mpeg2_transcode.h
mxf.h
name_format.h
object.h
openjpeg_image.h
picture_asset.h
- picture_asset_writer.h
piecewise_lut.h
pkl.h
rating.h
raw_convert.h
- rgb_xyz.h
reel.h
reel_asset.h
reel_atmos_asset.h
- reel_closed_caption_asset.h
reel_file_asset.h
- reel_interop_closed_caption_asset.h
- reel_interop_subtitle_asset.h
+ reel_interop_text_asset.h
reel_markers_asset.h
reel_mono_picture_asset.h
reel_picture_asset.h
+ reel_smpte_text_asset.h
reel_sound_asset.h
- reel_smpte_closed_caption_asset.h
- reel_smpte_subtitle_asset.h
reel_stereo_picture_asset.h
- reel_subtitle_asset.h
+ reel_text_asset.h
ref.h
+ rgb_xyz.h
ruby.h
s_gamut3_transfer_function.h
scope_guard.h
search.h
smpte_load_font_node.h
- smpte_subtitle_asset.h
- sound_frame.h
+ smpte_text_asset.h
sound_asset.h
sound_asset_reader.h
sound_asset_writer.h
- stereo_picture_asset.h
- stereo_picture_asset_reader.h
- stereo_picture_asset_writer.h
- stereo_picture_frame.h
- subtitle.h
- subtitle_asset.h
- subtitle_image.h
+ sound_frame.h
+ stereo_j2k_picture_asset.h
+ stereo_j2k_picture_asset_reader.h
+ stereo_j2k_picture_asset_writer.h
+ stereo_j2k_picture_frame.h
+ text.h
+ text_asset.h
+ text_image.h
subtitle_standard.h
- subtitle_string.h
+ text_string.h
+ text_type.h
transfer_function.h
types.h
utc_offset.h
@@ -232,6 +247,7 @@ def build(bld):
v_align.h
verify.h
verify_j2k.h
+ verify_report.h
version.h
warnings.h
"""
@@ -244,7 +260,7 @@ def build(bld):
obj.name = 'libdcp%s' % bld.env.API_VERSION
obj.target = 'dcp%s' % bld.env.API_VERSION
obj.export_includes = ['.']
- obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_CTH XERCES'
+ obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL'
obj.source = source
# Library for gcov
@@ -256,7 +272,7 @@ def build(bld):
obj.name = 'libdcp%s_gcov' % bld.env.API_VERSION
obj.target = 'dcp%s_gcov' % bld.env.API_VERSION
obj.export_includes = ['.']
- obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_CTH XERCES'
+ obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL'
obj.use = 'libkumu-libdcp%s libasdcp-libdcp%s' % (bld.env.API_VERSION, bld.env.API_VERSION)
obj.source = source
obj.cppflags = ['-fprofile-arcs', '-ftest-coverage', '-fno-inline', '-fno-default-inline', '-fno-elide-constructors', '-g', '-O0']