Support the 2014 version of SMPTE 428-7 in render_text.cc and use it
authorCarl Hetherington <cth@carlh.net>
Sun, 11 Dec 2022 23:51:56 +0000 (00:51 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 27 Feb 2023 13:47:25 +0000 (14:47 +0100)
when placing subtitles (e.g. SRT).  Also default to outputting 2014-era
alignment.

src/lib/dcp_decoder.cc
src/lib/dcp_subtitle_decoder.cc
src/lib/dcp_subtitle_decoder.h
src/lib/reel_writer.cc
src/lib/reel_writer.h
src/lib/render_text.cc
src/lib/string_text.h
src/lib/text_decoder.cc
src/lib/text_decoder.h
src/lib/util.cc
test/render_subtitles_test.cc

index 0f4e1afa1fadb2ff535294e3ca014d672466fbd3..e82e9e9584674621dd47480a5a914f758e6f8bd2 100644 (file)
@@ -304,7 +304,7 @@ DCPDecoder::pass_texts (
                                                        ContentTime::from_frames(_offset - entry_point, vfr) + ContentTime::from_seconds(b.out().as_seconds())
                                                        ),
                                                strings,
-                                               _dcp_content->standard()
+                                               asset->subtitle_standard()
                                                );
                                        strings.clear ();
                                }
@@ -340,7 +340,7 @@ DCPDecoder::pass_texts (
                                        ContentTime::from_frames(_offset - entry_point, vfr) + ContentTime::from_seconds(b.out().as_seconds())
                                        ),
                                strings,
-                               _dcp_content->standard()
+                               asset->subtitle_standard()
                                );
                        strings.clear ();
                }
index 617f7ec536530b71e83558f0f871b216cfe84312..fa92193a5a7f384022740a9dbb5fc7ee8e1c1861 100644 (file)
@@ -47,11 +47,7 @@ DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr<const Film> film, shared_ptr<
        _subtitles = asset->subtitles ();
        _next = _subtitles.begin ();
 
-       if (dynamic_pointer_cast<dcp::InteropSubtitleAsset>(asset)) {
-               _standard = dcp::Standard::INTEROP;
-       } else {
-               _standard = dcp::Standard::SMPTE;
-       }
+       _subtitle_standard = asset->subtitle_standard();
 
        text.push_back (make_shared<TextDecoder>(this, content->only_text()));
        update_position();
@@ -109,7 +105,7 @@ DCPSubtitleDecoder::pass ()
                }
        }
 
-       only_text()->emit_plain(p, s, _standard);
+       only_text()->emit_plain(p, s, _subtitle_standard);
 
        update_position();
 
index 3eed4ad24cd5863dddd9197972c3773693c7b7dd..45a4999ddcf769781bd87c8a577264b6511a6e06 100644 (file)
@@ -43,5 +43,5 @@ private:
        std::vector<std::shared_ptr<const dcp::Subtitle>> _subtitles;
        std::vector<std::shared_ptr<const dcp::Subtitle>>::const_iterator _next;
 
-       dcp::Standard _standard;
+       dcp::SubtitleStandard _subtitle_standard;
 };
index e0279725bc79b50a43c4bb95d25a2e1cda504610..47df4feb159ac458dc2556df203d3e9edfdc2b6e 100644 (file)
@@ -892,9 +892,10 @@ ReelWriter::empty_text_asset (TextType type, optional<DCPTextTrack> track, bool
 
 
 float
-ReelWriter::convert_vertical_position(StringText const& subtitle, dcp::Standard to) const
+ReelWriter::convert_vertical_position(StringText const& subtitle, dcp::SubtitleStandard to) const
 {
-       if (subtitle.valign_standard == to) {
+       if (dcp::uses_baseline(subtitle.valign_standard) == dcp::uses_baseline(to)) {
+               /* The from and to standards use the same alignment reference */
                return subtitle.v_position();
        }
 
@@ -914,7 +915,7 @@ ReelWriter::convert_vertical_position(StringText const& subtitle, dcp::Standard
                break;
        }
 
-       return subtitle.v_position() + ((subtitle.valign_standard == dcp::Standard::SMPTE) ? correction : -correction);
+       return subtitle.v_position() + (dcp::uses_bounding_box(subtitle.valign_standard) ? correction : -correction);
 }
 
 
@@ -957,7 +958,7 @@ ReelWriter::write (PlayerText subs, TextType type, optional<DCPTextTrack> track,
        for (auto i: subs.string) {
                i.set_in  (dcp::Time(period.from.seconds() - _period.from.seconds(), tcr));
                i.set_out (dcp::Time(period.to.seconds() - _period.from.seconds(), tcr));
-               i.set_v_position(convert_vertical_position(i, film()->interop() ? dcp::Standard::INTEROP : dcp::Standard::SMPTE));
+               i.set_v_position(convert_vertical_position(i, film()->interop() ? dcp::SubtitleStandard::INTEROP : dcp::SubtitleStandard::SMPTE_2014));
                auto sub = make_shared<dcp::SubtitleString>(i);
                if (type == TextType::OPEN_SUBTITLE) {
                        sub->set_font(fonts.get(i.font));
index 8ceef9f516eb46fc2866c358e72c8993eb581c29..892d803a502f11458fc77308c52365469249c530 100644 (file)
@@ -121,7 +121,7 @@ private:
                std::set<DCPTextTrack> ensure_closed_captions
                ) const;
        void create_reel_markers (std::shared_ptr<dcp::Reel> reel) const;
-       float convert_vertical_position(StringText const& subtitle, dcp::Standard to) const;
+       float convert_vertical_position(StringText const& subtitle, dcp::SubtitleStandard to) const;
 
        dcpomatic::DCPTimePeriod _period;
        /** the first picture frame index that does not already exist in our MXF */
index 702f848ac261d5d6730e319c72850313ec6aae4d..99c4c06a8d1fbfbbf7ec46c7d49a42885254cc0c 100644 (file)
@@ -253,7 +253,8 @@ y_position (StringText const& first, int target_height, int baseline_to_bottom,
 {
        int y = 0;
        switch (first.valign_standard) {
-       case dcp::Standard::INTEROP:
+       case dcp::SubtitleStandard::INTEROP:
+       case dcp::SubtitleStandard::SMPTE_2014:
                switch (first.v_align()) {
                case dcp::VAlign::TOP:
                        /* v_position is distance from top of frame to subtitle baseline */
@@ -269,7 +270,8 @@ y_position (StringText const& first, int target_height, int baseline_to_bottom,
                        break;
                }
                break;
-       case dcp::Standard::SMPTE:
+       case dcp::SubtitleStandard::SMPTE_2007:
+       case dcp::SubtitleStandard::SMPTE_2010:
                switch (first.v_align()) {
                case dcp::VAlign::TOP:
                        /* v_position is distance from top of frame to top of subtitle */
index 4eef7da0562aa79cb6b2a6d507b099ab27a42c6f..787231b8cf2d57b2ed3a8dda65b1ea7e42fb312c 100644 (file)
@@ -24,6 +24,7 @@
 
 
 #include "font.h"
+#include <dcp/subtitle_standard.h>
 #include <dcp/subtitle_string.h>
 
 
@@ -40,7 +41,7 @@
 class StringText : public dcp::SubtitleString
 {
 public:
-       StringText(dcp::SubtitleString dcp_, int outline_width_, std::shared_ptr<dcpomatic::Font> font_, dcp::Standard valign_standard_)
+       StringText(dcp::SubtitleString dcp_, int outline_width_, std::shared_ptr<dcpomatic::Font> font_, dcp::SubtitleStandard valign_standard_)
                : dcp::SubtitleString (dcp_)
                , outline_width (outline_width_)
                , font (font_)
@@ -49,18 +50,24 @@ public:
 
        int outline_width;
        std::shared_ptr<dcpomatic::Font> font;
+
        /** Interop and SMPTE use the same VAlign choices (top, center, bottom) but give them different
-        *  meanings.  This is the standard which should be used to interpret v_align() in this subtitle;
-        *  valign_standard == SMPTE means:
+        *  meanings.  To add some extra confusion, it seems that SMPTE changed their minds on this topic
+        *  between the 2010 and 2014 versions of standard 428-7, so there isn't even one answer for SMPTE.
+        *
+        *  This is the standard which should be used to interpret v_align() in this subtitle.
+         *
+        *  valign_standard == SMPTE_{2007,2010} means:
         *     top - top of screen to top of subtitle
         *     center - centre of screen to center of subtitle
         *     bottom - bottom of screen to bottom of subtitle
-        *  valign_standard == Interop means:
+        *
+        *  valign_standard == {INTEROP,SMPTE_2014} means:
         *     top - top of screen to baseline of subtitle
         *     center - centre of screen to baseline of subtitle
         *     bottom - bottom of screen to baseline of subtitle
         */
-       dcp::Standard valign_standard;
+       dcp::SubtitleStandard valign_standard;
 };
 
 
index 6fd036ae191ad193b5f1813e8eba8c5219e4949f..2541bbc9bfbf25efe1148729f417d98223c00e24 100644 (file)
@@ -88,7 +88,7 @@ set_forced_appearance(shared_ptr<const TextContent> content, StringText& subtitl
 
 
 void
-TextDecoder::emit_plain_start (ContentTime from, vector<dcp::SubtitleString> subtitles, dcp::Standard valign_standard)
+TextDecoder::emit_plain_start(ContentTime from, vector<dcp::SubtitleString> subtitles, dcp::SubtitleStandard valign_standard)
 {
        vector<StringText> string_texts;
 
@@ -265,7 +265,7 @@ TextDecoder::emit_plain_start (ContentTime from, sub::Subtitle const & sub_subti
                                dcp_subtitle,
                                content()->outline_width(),
                                content()->get_font(block.font.get_value_or("")),
-                               dcp::Standard::SMPTE
+                               dcp::SubtitleStandard::SMPTE_2014
                                );
                        set_forced_appearance(content(), string_text);
                        string_texts.push_back(string_text);
@@ -285,7 +285,7 @@ TextDecoder::emit_stop (ContentTime to)
 
 
 void
-TextDecoder::emit_plain (ContentTimePeriod period, vector<dcp::SubtitleString> subtitles, dcp::Standard valign_standard)
+TextDecoder::emit_plain(ContentTimePeriod period, vector<dcp::SubtitleString> subtitles, dcp::SubtitleStandard valign_standard)
 {
        emit_plain_start (period.from, subtitles, valign_standard);
        emit_stop (period.to);
index 5362540c2ed6a78a598dac2693d86ddb11e8ac6a..3b25e54cbe1a6c701d7f6407e77042d51c71eee4 100644 (file)
 #define DCPOMATIC_CAPTION_DECODER_H
 
 
+#include "content_text.h"
 #include "decoder.h"
+#include "decoder_part.h"
 #include "rect.h"
 #include "content_text.h"
-#include "decoder_part.h"
+#include "types.h"
+#include <dcp/subtitle_standard.h>
 #include <dcp/subtitle_string.h>
 #include <boost/signals2.hpp>
 
@@ -49,9 +52,9 @@ public:
 
        void emit_bitmap_start (ContentBitmapText const& bitmap);
        void emit_bitmap (dcpomatic::ContentTimePeriod period, std::shared_ptr<const Image> image, dcpomatic::Rect<double> rect);
-       void emit_plain_start (dcpomatic::ContentTime from, std::vector<dcp::SubtitleString> s, dcp::Standard valign_standard);
+       void emit_plain_start(dcpomatic::ContentTime from, std::vector<dcp::SubtitleString> s, dcp::SubtitleStandard valign_standard);
        void emit_plain_start (dcpomatic::ContentTime from, sub::Subtitle const & subtitle);
-       void emit_plain (dcpomatic::ContentTimePeriod period, std::vector<dcp::SubtitleString> s, dcp::Standard valign_standard);
+       void emit_plain(dcpomatic::ContentTimePeriod period, std::vector<dcp::SubtitleString> s, dcp::SubtitleStandard valign_standard);
        void emit_plain (dcpomatic::ContentTimePeriod period, sub::Subtitle const & subtitle);
        void emit_stop (dcpomatic::ContentTime to);
 
index 086a99f243784439f6877065e8c89953f0114b20..82f31b8f137a8f372d5285a2f677530309cb9f97 100644 (file)
@@ -412,7 +412,7 @@ LIBDCP_ENABLE_WARNINGS
                optional<string>(), false, false, false, dcp::Colour(), 42, 1, dcp::Time(), dcp::Time(), 0, dcp::HAlign::CENTER, 0, dcp::VAlign::CENTER, 0, dcp::Direction::LTR,
                "Hello dolly", dcp::Effect::NONE, dcp::Colour(), dcp::Time(), dcp::Time(), 0
                );
-       subs.push_back (StringText(ss, 0, {}, dcp::Standard::SMPTE));
+       subs.push_back(StringText(ss, 0, {}, dcp::SubtitleStandard::SMPTE_2014));
        render_text (subs, dcp::Size(640, 480), DCPTime(), 24);
 #endif
 
index e5de60c4ec64f719c32eb53fa2a7f4bd1b6d3447..d1c91260254cfbb623be91628ba33d3cd0931fd0 100644 (file)
@@ -66,7 +66,7 @@ add (std::list<StringText>& s, std::string text, bool italic, bool bold, bool un
                                ),
                        2,
                        std::shared_ptr<dcpomatic::Font>(),
-                       dcp::Standard::SMPTE
+                       dcp::SubtitleStandard::SMPTE_2014
                        )
                );
 }