diff options
| author | Carl Hetherington <cth@carlh.net> | 2026-02-08 00:52:27 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2026-02-12 21:01:59 +0100 |
| commit | 7b19d27983cb8078e8b35407a25e62da4ec687fe (patch) | |
| tree | 1d038a938e81eb452dc3c8c970d3e54edd307734 /src/lib | |
| parent | 55c53dd8621a30d3c39858216da6b5d2e6445fb0 (diff) | |
Re-use assets verbatim if they do not need to change (#448).
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/dcp_decoder.cc | 17 | ||||
| -rw-r--r-- | src/lib/dcp_decoder.h | 4 | ||||
| -rw-r--r-- | src/lib/player.cc | 4 | ||||
| -rw-r--r-- | src/lib/reel_writer.cc | 15 | ||||
| -rw-r--r-- | src/lib/reusable_reel_asset.cc | 31 |
5 files changed, 49 insertions, 22 deletions
diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index 27d0f3a94..59dd7c008 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -28,6 +28,7 @@ #include "dcp_decoder.h" #include "dcpomatic_log.h" #include "digester.h" +#include "film.h" #include "ffmpeg_image_proxy.h" #include "frame_interval_checker.h" #include "image.h" @@ -146,6 +147,12 @@ DCPDecoder::DCPDecoder(shared_ptr<const Film> film, shared_ptr<const DCPContent> _font_id_allocator.add_fonts_from_reels(_reels); _font_id_allocator.allocate(); + + _can_reuse_video = _dcp_content->can_reuse_video(film) && !film->reencode_j2k(); + _can_reuse_audio = _dcp_content->can_reuse_audio(film); + for (int i = 0; i < static_cast<int>(TextType::COUNT); ++i) { + _can_reuse_text[i] = _dcp_content->can_reuse_text(film, static_cast<TextType>(i)); + } } @@ -176,7 +183,7 @@ DCPDecoder::pass() */ pass_texts(_next, picture_asset->size()); - if ((_j2k_mono_reader || _j2k_stereo_reader || _mpeg2_mono_reader) && (_decode_reusable || !_dcp_content->reference_video())) { + if ((_j2k_mono_reader || _j2k_stereo_reader || _mpeg2_mono_reader) && (_decode_reusable || !_can_reuse_video)) { auto const entry_point = (*_reel)->main_picture()->entry_point().get_value_or(0); if (_j2k_mono_reader) { video->emit( @@ -233,7 +240,7 @@ DCPDecoder::pass() } } - if (_sound_reader && (_decode_reusable || !_dcp_content->reference_audio())) { + if (_sound_reader && (_decode_reusable || !_can_reuse_audio)) { auto const entry_point = (*_reel)->main_sound()->entry_point().get_value_or(0); auto sf = _sound_reader->get_frame(entry_point + frame); auto from = sf->data(); @@ -331,7 +338,7 @@ DCPDecoder::pass_texts( auto const asset = reel_asset->asset(); auto const entry_point = reel_asset->entry_point().get_value_or(0); - if (_decode_reusable || !_dcp_content->reference_text(type)) { + if (_decode_reusable || !_can_reuse_text[type]) { auto subs = asset->texts_during( dcp::Time(entry_point + frame, vfr, vfr), dcp::Time(entry_point + frame + 1, vfr, vfr), @@ -522,10 +529,10 @@ DCPDecoder::set_decode_reusable(bool r) _decode_reusable = r; if (video) { - video->set_ignore(_dcp_content->reference_video() && !_decode_reusable); + video->set_ignore(_can_reuse_video && !_decode_reusable); } if (audio) { - audio->set_ignore(_dcp_content->reference_audio() && !_decode_reusable); + audio->set_ignore(_can_reuse_audio && !_decode_reusable); } } diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h index dc30526ff..01b85b8d1 100644 --- a/src/lib/dcp_decoder.h +++ b/src/lib/dcp_decoder.h @@ -116,4 +116,8 @@ private: std::string _lazy_digest; FontIDAllocator _font_id_allocator; + + bool _can_reuse_video; + bool _can_reuse_audio; + EnumIndexedVector<bool, TextType> _can_reuse_text; }; diff --git a/src/lib/player.cc b/src/lib/player.cc index 86f6e1082..316cf7e2b 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -758,10 +758,10 @@ Player::pass() earliest_content->done = earliest_content->decoder->pass(); auto dcp = dynamic_pointer_cast<DCPContent>(earliest_content->content); if (dcp && !_play_reusable) { - if (dcp->reference_video()) { + if (dcp->can_reuse_video(film)) { _next_video_time = dcp->end(film); } - if (dcp->reference_audio()) { + if (dcp->can_reuse_audio(film)) { /* We are skipping some referenced DCP audio content, so we need to update _next_audio_time to `hide' the fact that no audio was emitted during the referenced DCP (though we need to behave as though it was). diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 67e707d52..2c4fac6e0 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -411,7 +411,7 @@ ReelWriter::finish(boost::filesystem::path output_dcp) template <class Asset> shared_ptr<Asset> -maybe_reuse_asset(char const* log_name, list<ReusableReelAsset> const& refs, DCPTimePeriod period) +maybe_reuse_asset(char const* log_name, list<ReusableReelAsset> const& refs, DCPTimePeriod period, boost::filesystem::path output_dir) { shared_ptr<Asset> reusable; @@ -423,6 +423,13 @@ maybe_reuse_asset(char const* log_name, list<ReusableReelAsset> const& refs, DCP } if (asset && ref.period == period) { reusable = asset; + if (ref.use == ReusableReelAsset::Use::COPY) { + auto mxf = reusable->asset_ref().asset(); + DCPOMATIC_ASSERT(mxf->file()); + auto const destination = output_dir / mxf->file()->filename(); + copy_file(*mxf->file(), destination); + mxf->set_file(destination); + } /* If we have a hash for this asset in the CPL, assume that it is correct */ if (reusable->hash()) { reusable->asset_ref()->set_hash(reusable->hash().get()); @@ -484,7 +491,7 @@ ReelWriter::maybe_add_text( } else { /* We don't have a subtitle asset of our own; hopefully we have one to reuse */ - reel_asset = maybe_reuse_asset<dcp::ReelTextAsset>("subtitle", refs, _period); + reel_asset = maybe_reuse_asset<dcp::ReelTextAsset>("subtitle", refs, _period, _output_dir); } if (reel_asset) { @@ -519,7 +526,7 @@ ReelWriter::create_reel_picture(shared_ptr<dcp::Reel> reel, list<ReusableReelAss reel_asset = make_shared<dcp::ReelMonoPictureAsset>(_mpeg2_picture_asset, 0); } else { /* We don't have a picture asset of our own; hopefully we have one to reuse */ - reel_asset = maybe_reuse_asset<dcp::ReelPictureAsset>("picture", refs, _period); + reel_asset = maybe_reuse_asset<dcp::ReelPictureAsset>("picture", refs, _period, _output_dir); } Frame const period_duration = _period.duration().frames_round(film()->video_frame_rate()); @@ -552,7 +559,7 @@ ReelWriter::create_reel_sound(shared_ptr<dcp::Reel> reel, list<ReusableReelAsset reel_asset = make_shared<dcp::ReelSoundAsset>(_sound_asset, 0); } else { /* We don't have a sound asset of our own; hopefully we have one to reuse */ - reel_asset = maybe_reuse_asset<dcp::ReelSoundAsset>("sound", refs, _period); + reel_asset = maybe_reuse_asset<dcp::ReelSoundAsset>("sound", refs, _period, _output_dir); } auto const period_duration = _period.duration().frames_round(film()->video_frame_rate()); diff --git a/src/lib/reusable_reel_asset.cc b/src/lib/reusable_reel_asset.cc index ab14460e0..3894cc4e0 100644 --- a/src/lib/reusable_reel_asset.cc +++ b/src/lib/reusable_reel_asset.cc @@ -50,8 +50,12 @@ maybe_add_asset(list<ReusableReelAsset>& a, shared_ptr<dcp::ReelFileAsset> r, Fr r->set_duration (r->actual_duration() - reel_trim_start - reel_trim_end); if (r->actual_duration() > 0) { a.push_back ( - ReusableReelAsset(r, DCPTimePeriod(from, from + DCPTime::from_frames(r->actual_duration(), ffr)), ReusableReelAsset::Use::REFERENCE) - ); + ReusableReelAsset( + r, + DCPTimePeriod(from, from + DCPTime::from_frames(r->actual_duration(), ffr)), + reference ? ReusableReelAsset::Use::REFERENCE : ReusableReelAsset::Use::COPY + ) + ); } } @@ -69,7 +73,12 @@ get_reusable_reel_assets(shared_ptr<const Film> film, shared_ptr<const Playlist> continue; } - if (!dcp->reference_video() && !dcp->reference_audio() && !dcp->reference_text(TextType::OPEN_SUBTITLE) && !dcp->reference_text(TextType::CLOSED_CAPTION)) { + if ( + !dcp->can_reuse_video(film) && + !dcp->can_reuse_audio(film) && + !dcp->can_reuse_text(film, TextType::OPEN_SUBTITLE) && + !dcp->can_reuse_text(film, TextType::CLOSED_CAPTION) + ) { continue; } @@ -107,21 +116,21 @@ get_reusable_reel_assets(shared_ptr<const Film> film, shared_ptr<const Playlist> Frame const reel_trim_end = min(reel_duration, max(int64_t(0), reel_duration - (offset_from_end - trim_end))); auto const from = content->position() + std::max(DCPTime(), DCPTime::from_frames(offset_from_start - trim_start, frame_rate)); - if (dcp->reference_video()) { - maybe_add_asset (reel_assets, reel->main_picture(), reel_trim_start, reel_trim_end, from, frame_rate); + if (dcp->can_reuse_video(film)) { + maybe_add_asset(reel_assets, reel->main_picture(), reel_trim_start, reel_trim_end, from, frame_rate, dcp->reference_video()); } - if (dcp->reference_audio()) { - maybe_add_asset (reel_assets, reel->main_sound(), reel_trim_start, reel_trim_end, from, frame_rate); + if (dcp->can_reuse_audio(film)) { + maybe_add_asset(reel_assets, reel->main_sound(), reel_trim_start, reel_trim_end, from, frame_rate, dcp->reference_audio()); } - if (dcp->reference_text(TextType::OPEN_SUBTITLE) && reel->main_subtitle()) { - maybe_add_asset (reel_assets, reel->main_subtitle(), reel_trim_start, reel_trim_end, from, frame_rate); + if (dcp->can_reuse_text(film, TextType::OPEN_SUBTITLE) && reel->main_subtitle()) { + maybe_add_asset(reel_assets, reel->main_subtitle(), reel_trim_start, reel_trim_end, from, frame_rate, dcp->reference_text(TextType::OPEN_SUBTITLE)); } - if (dcp->reference_text(TextType::CLOSED_CAPTION)) { + if (dcp->can_reuse_text(film, TextType::CLOSED_CAPTION)) { for (auto caption: reel->closed_captions()) { - maybe_add_asset (reel_assets, caption, reel_trim_start, reel_trim_end, from, frame_rate); + maybe_add_asset(reel_assets, caption, reel_trim_start, reel_trim_end, from, frame_rate, dcp->reference_text(TextType::CLOSED_CAPTION)); } } |
