summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2024-08-06 23:56:38 +0200
committerCarl Hetherington <cth@carlh.net>2024-08-17 12:57:31 +0200
commitc8128908da7db78a920452f43b531383bb14c115 (patch)
treee06a72e9b38ddbc0de1bc86d28af0fbd96977b6d /src
parentf037f1cc035a1e81b582cfaba6087e693cca9a26 (diff)
Support open captions and closed subtitles.
Diffstat (limited to 'src')
-rw-r--r--src/reel.cc113
-rw-r--r--src/reel.h10
-rw-r--r--src/reel_interop_text_asset.cc6
-rw-r--r--src/reel_smpte_text_asset.cc6
-rw-r--r--src/text_type.h2
5 files changed, 108 insertions, 29 deletions
diff --git a/src/reel.cc b/src/reel.cc
index 6208f3a6..ce654f6f 100644
--- a/src/reel.cc
+++ b/src/reel.cc
@@ -90,12 +90,23 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
if (auto main_subtitle = asset_list->optional_node_child("MainSubtitle")) {
switch (standard) {
- case Standard::INTEROP:
- _main_subtitle = make_shared<ReelInteropTextAsset>(main_subtitle);
- break;
- case Standard::SMPTE:
- _main_subtitle = make_shared<ReelSMPTETextAsset>(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;
+ }
+ }
+
+ 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;
}
}
@@ -103,6 +114,18 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
_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");
@@ -111,12 +134,12 @@ 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<ReelInteropTextAsset>(i));
- break;
- case Standard::SMPTE:
- _closed_captions.push_back (make_shared<ReelSMPTETextAsset>(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;
}
}
@@ -153,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);
}
@@ -350,10 +381,19 @@ Reel::add (shared_ptr<ReelAsset> asset)
} else if (auto so = dynamic_pointer_cast<ReelSoundAsset>(asset)) {
_main_sound = so;
} else if (auto te = dynamic_pointer_cast<ReelTextAsset>(asset)) {
- if (te->type() == TextType::OPEN_SUBTITLE) {
+ switch (te->type()) {
+ case TextType::OPEN_SUBTITLE:
_main_subtitle = te;
- } else {
+ 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;
@@ -378,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);
@@ -397,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<InteropTextAsset>(_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<InteropTextAsset>(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) {
@@ -446,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 28e574ea..347013c3 100644
--- a/src/reel.h
+++ b/src/reel.h
@@ -109,10 +109,18 @@ public:
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<ReelTextAsset>> closed_subtitles() const {
+ return _closed_subtitles;
+ }
+
std::vector<std::shared_ptr<ReelTextAsset>> closed_captions () const {
return _closed_captions;
}
@@ -146,7 +154,9 @@ private:
std::shared_ptr<ReelPictureAsset> _main_picture;
std::shared_ptr<ReelSoundAsset> _main_sound;
std::shared_ptr<ReelTextAsset> _main_subtitle;
+ std::shared_ptr<ReelTextAsset> _main_caption;
std::shared_ptr<ReelMarkersAsset> _main_markers;
+ std::vector<std::shared_ptr<ReelTextAsset>> _closed_subtitles;
std::vector<std::shared_ptr<ReelTextAsset>> _closed_captions;
std::shared_ptr<ReelAtmosAsset> _atmos;
diff --git a/src/reel_interop_text_asset.cc b/src/reel_interop_text_asset.cc
index c43cf37b..0f99b614 100644
--- a/src/reel_interop_text_asset.cc
+++ b/src/reel_interop_text_asset.cc
@@ -72,6 +72,10 @@ ReelInteropTextAsset::cpl_node_name() const
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";
}
@@ -86,7 +90,9 @@ ReelInteropTextAsset::cpl_node_namespace() const
{
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");
}
diff --git a/src/reel_smpte_text_asset.cc b/src/reel_smpte_text_asset.cc
index 7950dfd2..b1ce34cb 100644
--- a/src/reel_smpte_text_asset.cc
+++ b/src/reel_smpte_text_asset.cc
@@ -74,6 +74,10 @@ ReelSMPTETextAsset::cpl_node_name() const
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";
}
@@ -88,7 +92,9 @@ ReelSMPTETextAsset::cpl_node_namespace() const
{
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");
}
diff --git a/src/text_type.h b/src/text_type.h
index 3f4f43c8..60065478 100644
--- a/src/text_type.h
+++ b/src/text_type.h
@@ -38,6 +38,8 @@ namespace dcp {
enum class TextType
{
OPEN_SUBTITLE,
+ OPEN_CAPTION,
+ CLOSED_SUBTITLE,
CLOSED_CAPTION
};