From 3b78e9223c9be784531475acacb88b59b2459f48 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 16 Mar 2021 14:24:48 +0100 Subject: [PATCH 1/1] Split subtitles at reel boundaries (#1918). --- cscript | 4 ++-- src/lib/reel_writer.cc | 11 ++++++----- src/lib/writer.cc | 32 ++++++++++++++++++++++++++++++++ src/lib/writer.h | 12 +++++++++++- test/reels_test.cc | 3 ++- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/cscript b/cscript index 6e9f4da5f..8e9237571 100644 --- a/cscript +++ b/cscript @@ -370,8 +370,8 @@ def dependencies(target, options): # Use distro-provided FFmpeg on Arch deps = [] - deps.append(('libdcp', '8344c1c')) - deps.append(('libsub', '8990c30')) + deps.append(('libdcp', '2c1faeb')) + deps.append(('libsub', '33c9a57')) deps.append(('leqm-nrt', '131f971')) deps.append(('rtaudio', 'f619b76')) # We get our OpenSSL libraries from the environment, but we diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index ad52a1ca1..184707373 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -868,11 +868,12 @@ ReelWriter::write (PlayerText subs, TextType type, optional track, DCPOMATIC_ASSERT (false); } - auto const vfr = film()->video_frame_rate(); + /* timecode rate for subtitles we emit; we might as well stick to ms accuracy here, I think */ + auto const tcr = 1000; for (auto i: subs.string) { - i.set_in (dcp::Time(period.from.seconds() - _period.from.seconds(), vfr)); - i.set_out (dcp::Time(period.to.seconds() - _period.from.seconds(), vfr)); + i.set_in (dcp::Time(period.from.seconds() - _period.from.seconds(), tcr)); + i.set_out (dcp::Time(period.to.seconds() - _period.from.seconds(), tcr)); asset->add (make_shared(i)); } @@ -880,8 +881,8 @@ ReelWriter::write (PlayerText subs, TextType type, optional track, asset->add ( make_shared( i.image->as_png(), - dcp::Time(period.from.seconds() - _period.from.seconds(), vfr), - dcp::Time(period.to.seconds() - _period.from.seconds(), vfr), + dcp::Time(period.from.seconds() - _period.from.seconds(), tcr), + dcp::Time(period.to.seconds() - _period.from.seconds(), tcr), i.rectangle.x, dcp::HAlign::LEFT, i.rectangle.y, dcp::VAlign::TOP, dcp::Time(), dcp::Time() ) diff --git a/src/lib/writer.cc b/src/lib/writer.cc index ad588f0a6..4386b8e26 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -545,6 +545,7 @@ Writer::finish (boost::filesystem::path output_dcp) LOG_GENERAL_NC ("Finishing ReelWriters"); for (auto& i: _reels) { + write_hanging_text (i); i.finish (output_dcp); } @@ -798,6 +799,23 @@ Writer::write (PlayerText text, TextType type, optional track, DCP while ((*reel)->period().to <= period.from) { ++(*reel); DCPOMATIC_ASSERT (*reel != _reels.end()); + write_hanging_text (**reel); + } + + if (period.to > (*reel)->period().to) { + /* This text goes off the end of the reel. Store parts of it that should go into + * other reels. + */ + for (auto i = std::next(*reel); i != _reels.end(); ++i) { + auto overlap = i->period().overlap(period); + if (overlap) { + _hanging_texts.push_back (HangingText{text, type, track, *overlap}); + } + } + /* Back off from the reel boundary by a couple of frames to avoid tripping checks + * for subtitles being too close together. + */ + period.to = (*reel)->period().to - DCPTime::from_frames(2, film()->video_frame_rate()); } (*reel)->write (text, type, track, period); @@ -907,3 +925,17 @@ Writer::calculate_referenced_digests (boost::function set_progress } } + +void +Writer::write_hanging_text (ReelWriter& reel) +{ + vector new_hanging_texts; + for (auto i: _hanging_texts) { + if (i.period.from == reel.period().from) { + reel.write (i.text, i.type, i.track, i.period); + } else { + new_hanging_texts.push_back (i); + } + } + _hanging_texts = new_hanging_texts; +} diff --git a/src/lib/writer.h b/src/lib/writer.h index 14d4b7faa..aab7d5fc7 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2020 Carl Hetherington + Copyright (C) 2012-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -129,6 +129,7 @@ private: void set_digest_progress (Job* job, float progress); void write_cover_sheet (boost::filesystem::path output_dcp); void calculate_referenced_digests (boost::function set_progress); + void write_hanging_text (ReelWriter& reel); std::weak_ptr _job; std::vector _reels; @@ -204,4 +205,13 @@ private: bool _have_subtitles = false; /** all closed caption tracks that we have on any reel */ std::set _have_closed_captions; + + struct HangingText { + PlayerText text; + TextType type; + boost::optional track; + dcpomatic::DCPTimePeriod period; + }; + + std::vector _hanging_texts; }; diff --git a/test/reels_test.cc b/test/reels_test.cc index 47ead7e12..a37e14067 100644 --- a/test/reels_test.cc +++ b/test/reels_test.cc @@ -390,7 +390,8 @@ BOOST_AUTO_TEST_CASE (reels_test10) { dcp::VerificationNote::Code::EXTERNAL_ASSET, dcp::VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, - dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME + dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME, + dcp::VerificationNote::Code::INVALID_SUBTITLE_DURATION, }); } -- 2.30.2