From c8128908da7db78a920452f43b531383bb14c115 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 6 Aug 2024 23:56:38 +0200 Subject: Support open captions and closed subtitles. --- src/reel.cc | 113 ++++++++++++++++++++++++++++++----------- src/reel.h | 10 ++++ src/reel_interop_text_asset.cc | 6 +++ src/reel_smpte_text_asset.cc | 6 +++ src/text_type.h | 2 + 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 node, dcp::Standard standard) if (auto main_subtitle = asset_list->optional_node_child("MainSubtitle")) { switch (standard) { - case Standard::INTEROP: - _main_subtitle = make_shared(main_subtitle); - break; - case Standard::SMPTE: - _main_subtitle = make_shared(main_subtitle); - break; + case Standard::INTEROP: + _main_subtitle = make_shared(main_subtitle); + break; + case Standard::SMPTE: + _main_subtitle = make_shared(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(main_caption); + break; } } @@ -103,6 +114,18 @@ Reel::Reel (std::shared_ptr node, dcp::Standard standard) _main_markers = make_shared(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(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 node, dcp::Standard standard) } for (auto i: closed_captions) { switch (standard) { - case Standard::INTEROP: - _closed_captions.push_back (make_shared(i)); - break; - case Standard::SMPTE: - _closed_captions.push_back (make_shared(i)); - break; + case Standard::INTEROP: + _closed_captions.push_back(make_shared(i)); + break; + case Standard::SMPTE: + _closed_captions.push_back(make_shared(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 asset) } else if (auto so = dynamic_pointer_cast(asset)) { _main_sound = so; } else if (auto te = dynamic_pointer_cast(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(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> assets) _main_sound->asset_ref().resolve(assets); } - if (_main_subtitle) { - _main_subtitle->asset_ref().resolve(assets); - + auto resolve_interop_fonts = [&assets](shared_ptr(asset)) { /* Interop subtitle handling is all special cases */ - if (_main_subtitle->asset_ref().resolved()) { - auto iop = dynamic_pointer_cast(_main_subtitle->asset_ref().asset()); - if (iop) { - iop->resolve_fonts (assets); + if (asset->asset_ref().resolved()) { + if (auto iop = dynamic_pointer_cast(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(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 main_caption() const { + return _main_caption; + } + std::shared_ptr main_markers () const { return _main_markers; } + std::vector> closed_subtitles() const { + return _closed_subtitles; + } + std::vector> closed_captions () const { return _closed_captions; } @@ -146,7 +154,9 @@ private: std::shared_ptr _main_picture; std::shared_ptr _main_sound; std::shared_ptr _main_subtitle; + std::shared_ptr _main_caption; std::shared_ptr _main_markers; + std::vector> _closed_subtitles; std::vector> _closed_captions; std::shared_ptr _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 }; -- cgit v1.2.3