+void
+DCPDecoder::pass_texts (ContentTime next, dcp::Size size)
+{
+ auto decoder = text.begin ();
+ if (decoder == text.end()) {
+ /* It's possible that there is now a main subtitle but no TextDecoders, for example if
+ the CPL has just changed but the TextContent's texts have not been recreated yet.
+ */
+ return;
+ }
+
+ if ((*_reel)->main_subtitle()) {
+ pass_texts (
+ next,
+ (*_reel)->main_subtitle()->asset(),
+ _dcp_content->reference_text(TextType::OPEN_SUBTITLE),
+ (*_reel)->main_subtitle()->entry_point().get_value_or(0),
+ *decoder,
+ size
+ );
+ ++decoder;
+ }
+
+ for (auto i: (*_reel)->closed_captions()) {
+ pass_texts (
+ next, i->asset(), _dcp_content->reference_text(TextType::CLOSED_CAPTION), i->entry_point().get_value_or(0), *decoder, size
+ );
+ ++decoder;
+ }
+}
+
+void
+DCPDecoder::pass_texts (
+ ContentTime next, shared_ptr<dcp::SubtitleAsset> asset, bool reference, int64_t entry_point, shared_ptr<TextDecoder> decoder, dcp::Size size
+ )
+{
+ double const vfr = _dcp_content->active_video_frame_rate (film());
+ /* Frame within the (played part of the) reel that is coming up next */
+ int64_t const frame = next.frames_round (vfr);
+
+ if (_decode_referenced || !reference) {
+ auto subs = asset->subtitles_during (
+ dcp::Time (entry_point + frame, vfr, vfr),
+ dcp::Time (entry_point + frame + 1, vfr, vfr),
+ true
+ );
+
+ list<dcp::SubtitleString> strings;
+
+ for (auto i: subs) {
+ auto is = dynamic_pointer_cast<const dcp::SubtitleString>(i);
+ if (is) {
+ if (!strings.empty() && (strings.back().in() != is->in() || strings.back().out() != is->out())) {
+ auto b = strings.back();
+ decoder->emit_plain (
+ ContentTimePeriod (
+ ContentTime::from_frames(_offset - entry_point, vfr) + ContentTime::from_seconds(b.in().as_seconds()),
+ ContentTime::from_frames(_offset - entry_point, vfr) + ContentTime::from_seconds(b.out().as_seconds())
+ ),
+ strings
+ );
+ strings.clear ();
+ }
+
+ strings.push_back (*is);
+ }
+
+ /* XXX: perhaps these image subs should also be collected together like the string ones are;
+ this would need to be done both here and in DCPSubtitleDecoder.
+ */
+
+ auto ii = dynamic_pointer_cast<const dcp::SubtitleImage>(i);
+ if (ii) {
+ emit_subtitle_image (
+ ContentTimePeriod (
+ ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->in().as_seconds ()),
+ ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->out().as_seconds ())
+ ),
+ *ii,
+ size,
+ decoder
+ );
+ }
+ }
+
+ if (!strings.empty()) {
+ auto b = strings.back();
+ decoder->emit_plain (
+ ContentTimePeriod (
+ ContentTime::from_frames(_offset - entry_point, vfr) + ContentTime::from_seconds(b.in().as_seconds()),
+ ContentTime::from_frames(_offset - entry_point, vfr) + ContentTime::from_seconds(b.out().as_seconds())
+ ),
+ strings
+ );
+ strings.clear ();
+ }
+ }
+}
+
+void
+DCPDecoder::next_reel ()
+{
+ _offset += (*_reel)->main_picture()->actual_duration();
+ ++_reel;
+ get_readers ();
+}
+
+void
+DCPDecoder::get_readers ()
+{
+ if (_reel == _reels.end() || !_dcp_content->can_be_played ()) {
+ _mono_reader.reset ();
+ _stereo_reader.reset ();
+ _sound_reader.reset ();
+ _atmos_reader.reset ();
+ return;
+ }
+
+ if ((*_reel)->main_picture()) {
+ shared_ptr<dcp::PictureAsset> asset = (*_reel)->main_picture()->asset ();
+ shared_ptr<dcp::MonoPictureAsset> mono = dynamic_pointer_cast<dcp::MonoPictureAsset> (asset);
+ shared_ptr<dcp::StereoPictureAsset> stereo = dynamic_pointer_cast<dcp::StereoPictureAsset> (asset);
+ DCPOMATIC_ASSERT (mono || stereo);
+ if (mono) {
+ _mono_reader = mono->start_read ();
+ _mono_reader->set_check_hmac (false);
+ _stereo_reader.reset ();
+ } else {
+ _stereo_reader = stereo->start_read ();
+ _stereo_reader->set_check_hmac (false);
+ _mono_reader.reset ();
+ }
+ } else {
+ _mono_reader.reset ();
+ _stereo_reader.reset ();
+ }
+
+ if ((*_reel)->main_sound()) {
+ _sound_reader = (*_reel)->main_sound()->asset()->start_read ();
+ _sound_reader->set_check_hmac (false);
+ } else {
+ _sound_reader.reset ();
+ }
+
+ if ((*_reel)->atmos()) {
+ shared_ptr<dcp::AtmosAsset> asset = (*_reel)->atmos()->asset();
+ _atmos_reader = asset->start_read();
+ _atmos_reader->set_check_hmac (false);
+ _atmos_metadata = AtmosMetadata (asset);
+ } else {
+ _atmos_reader.reset ();
+ _atmos_metadata = boost::none;
+ }
+}
+