From d5ab7ecf942405bcaa7fd8d367e09f95d6c0c978 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 18 Oct 2021 08:55:27 +0200 Subject: [PATCH] Order subtitles in the XML according to their vertical position (DoM bug #2106). --- src/smpte_subtitle_asset.h | 4 + src/subtitle_asset.cc | 3 + src/verify.cc | 113 +++++++++++ src/verify.h | 6 +- ...ify_incorrect_closed_caption_ordering3.xml | 20 ++ ...ify_incorrect_closed_caption_ordering4.xml | 20 ++ test/smpte_subtitle_test.cc | 175 ++++++++++++++++++ test/verify_test.cc | 136 ++++++++++++++ 8 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 test/data/verify_incorrect_closed_caption_ordering3.xml create mode 100644 test/data/verify_incorrect_closed_caption_ordering4.xml diff --git a/src/smpte_subtitle_asset.h b/src/smpte_subtitle_asset.h index 4e220d4d..b707da12 100644 --- a/src/smpte_subtitle_asset.h +++ b/src/smpte_subtitle_asset.h @@ -58,6 +58,8 @@ namespace ASDCP { struct verify_invalid_language1; struct verify_invalid_language2; +struct write_subtitles_in_vertical_order_with_top_alignment; +struct write_subtitles_in_vertical_order_with_bottom_alignment; namespace dcp { @@ -204,6 +206,8 @@ private: friend struct ::write_smpte_subtitle_test2; friend struct ::verify_invalid_language1; friend struct ::verify_invalid_language2; + friend struct ::write_subtitles_in_vertical_order_with_top_alignment; + friend struct ::write_subtitles_in_vertical_order_with_bottom_alignment; void read_fonts (std::shared_ptr); void parse_xml (std::shared_ptr xml); diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index 2793772a..22781196 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -579,6 +579,9 @@ struct SubtitleSorter if (a->in() != b->in()) { return a->in() < b->in(); } + if (a->v_align() == VAlign::BOTTOM) { + return a->v_position() > b->v_position(); + } return a->v_position() < b->v_position(); } }; diff --git a/src/verify.cc b/src/verify.cc index 771898da..8a065e68 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -921,6 +921,113 @@ verify_text_details ( } +static +void +verify_closed_caption_details ( + vector> reels, + vector& notes + ) +{ + std::function& text_or_image)> find_text_or_image; + find_text_or_image = [&find_text_or_image](cxml::ConstNodePtr node, std::vector& text_or_image) { + for (auto i: node->node_children()) { + if (i->name() == "Text") { + text_or_image.push_back (i); + } else { + find_text_or_image (i, text_or_image); + } + } + }; + + auto mismatched_valign = false; + auto incorrect_order = false; + + std::function parse; + parse = [&parse, &find_text_or_image, &mismatched_valign, &incorrect_order](cxml::ConstNodePtr node) { + if (node->name() == "Subtitle") { + vector text_or_image; + find_text_or_image (node, text_or_image); + optional last_valign; + optional last_vpos; + for (auto i: text_or_image) { + auto valign = i->optional_string_attribute("VAlign"); + if (!valign) { + valign = i->optional_string_attribute("Valign").get_value_or("center"); + } + auto vpos = i->optional_number_attribute("VPosition"); + if (!vpos) { + vpos = i->optional_number_attribute("Vposition").get_value_or(50); + } + + if (last_valign) { + if (*last_valign != valign) { + mismatched_valign = true; + } + } + last_valign = valign; + + if (!mismatched_valign) { + if (last_vpos) { + if (*last_valign == "top" || *last_valign == "center") { + if (*vpos < *last_vpos) { + incorrect_order = true; + } + } else { + if (*vpos > *last_vpos) { + incorrect_order = true; + } + } + } + last_vpos = vpos; + } + } + } + + for (auto i: node->node_children()) { + parse(i); + } + }; + + for (auto reel: reels) { + 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}); + continue; + } + + /* We need to look at instances in the XML being checked, so we can't use the subtitles + * read in by libdcp's parser. + */ + + shared_ptr doc; + optional tcr; + optional