From 5b2e3126602d508498a99bce256f5f465f095d43 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 30 Nov 2023 00:46:00 +0100 Subject: [PATCH] Support playback of MPEG2 DCPs. --- cscript | 14 +------------- src/lib/dcp_decoder.cc | 31 +++++++++++++++++++++++++++++-- src/lib/dcp_decoder.h | 6 ++++++ src/lib/dcp_examiner.cc | 8 ++++++++ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/cscript b/cscript index 2b1c57c95..b971ff2ea 100644 --- a/cscript +++ b/cscript @@ -533,19 +533,7 @@ def make_spec(filename, version, target, options, requires=None): print('/usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :', file=f) def dependencies(target, options): - - if target.platform == 'linux': - ffmpeg_options = { 'shared': False } - else: - ffmpeg_options = {} - - if target.platform != 'linux' or target.distro != 'arch': - deps = [('ffmpeg', '0b73d2f5e70a04a67aa902902c42e3025ef3bb77', ffmpeg_options)] - else: - # Use distro-provided FFmpeg on Arch - deps = [] - - deps.append(('libdcp', '816365d20e0c6ef37b6bf499a42a0d3ecad22c05', {'c++17': target.platform == 'osx'})) + deps = [('libdcp', 'v1.9.6', {'c++17': target.platform == 'osx'})] deps.append(('libsub', 'v1.6.47')) deps.append(('leqm-nrt', '30dcaea1373ac62fba050e02ce5b0c1085797a23')) deps.append(('rtaudio', 'f619b76')) diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index ce471202f..e471a237f 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -26,11 +26,13 @@ #include "constants.h" #include "dcp_content.h" #include "dcp_decoder.h" +#include "dcpomatic_log.h" #include "digester.h" #include "ffmpeg_image_proxy.h" #include "frame_interval_checker.h" #include "image.h" #include "j2k_image_proxy.h" +#include "raw_image_proxy.h" #include "text_decoder.h" #include "util.h" #include "video_decoder.h" @@ -40,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -170,7 +173,7 @@ DCPDecoder::pass () */ pass_texts (_next, picture_asset->size()); - if ((_j2k_mono_reader || _j2k_stereo_reader) && (_decode_referenced || !_dcp_content->reference_video())) { + if ((_j2k_mono_reader || _j2k_stereo_reader || _mpeg2_mono_reader) && (_decode_referenced || !_dcp_content->reference_video())) { auto const entry_point = (*_reel)->main_picture()->entry_point().get_value_or(0); if (_j2k_mono_reader) { video->emit ( @@ -207,6 +210,23 @@ DCPDecoder::pass () ), ContentTime::from_frames(_offset + frame, vfr) ); + } else if (_mpeg2_mono_reader) { + /* XXX: got to flush this at some point */ + try { + for (auto const& image: _mpeg2_decompressor->decompress_frame(_mpeg2_mono_reader->get_frame(entry_point + frame))) { + video->emit( + film(), + /* XXX: should this be PADDED? */ + std::make_shared(std::make_shared(image.frame(), Image::Alignment::COMPACT)), + /* XXX: this will be wrong */ + ContentTime::from_frames(_offset + frame, vfr) + ); + } + } catch (dcp::MPEG2DecompressionError& e) { + LOG_ERROR("Failed to decompress MPEG video frame %1 (%2)", entry_point + frame, e.what()); + } catch (dcp::ReadError& e) { + LOG_ERROR("Failed to read MPEG2 video frame %1 (%2)", entry_point + frame, e.what()); + } } } @@ -370,8 +390,10 @@ DCPDecoder::get_readers () { _j2k_mono_reader.reset(); _j2k_stereo_reader.reset(); + _mpeg2_mono_reader.reset(); _sound_reader.reset(); _atmos_reader.reset(); + _mpeg2_decompressor.reset(); _atmos_metadata = boost::none; if (_reel == _reels.end() || !_dcp_content->can_be_played ()) { @@ -382,13 +404,18 @@ DCPDecoder::get_readers () auto asset = (*_reel)->main_picture()->asset (); auto j2k_mono = dynamic_pointer_cast(asset); auto j2k_stereo = dynamic_pointer_cast(asset); - DCPOMATIC_ASSERT(j2k_mono || j2k_stereo) + auto mpeg2_mono = dynamic_pointer_cast(asset); + DCPOMATIC_ASSERT(j2k_mono || j2k_stereo || mpeg2_mono) if (j2k_mono) { _j2k_mono_reader = j2k_mono->start_read(); _j2k_mono_reader->set_check_hmac(false); } else if (j2k_stereo) { _j2k_stereo_reader = j2k_stereo->start_read(); _j2k_stereo_reader->set_check_hmac(false); + } else { + _mpeg2_mono_reader = mpeg2_mono->start_read(); + _mpeg2_mono_reader->set_check_hmac(false); + _mpeg2_decompressor = std::make_shared(); } } diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h index 0143ef881..ee0f30694 100644 --- a/src/lib/dcp_decoder.h +++ b/src/lib/dcp_decoder.h @@ -29,6 +29,8 @@ #include "font_id_allocator.h" #include #include +#include +#include #include #include @@ -98,11 +100,15 @@ private: std::shared_ptr _j2k_mono_reader; /** Reader for current J2K stereo picture asset, if applicable */ std::shared_ptr _j2k_stereo_reader; + /** Reader for current MPEG2 mono picture asset, if applicable */ + std::shared_ptr _mpeg2_mono_reader; /** Reader for current sound asset, if applicable */ std::shared_ptr _sound_reader; std::shared_ptr _atmos_reader; boost::optional _atmos_metadata; + std::shared_ptr _mpeg2_decompressor; + bool _decode_referenced = false; boost::optional _forced_reduction; diff --git a/src/lib/dcp_examiner.cc b/src/lib/dcp_examiner.cc index 584ba4116..92491947c 100644 --- a/src/lib/dcp_examiner.cc +++ b/src/lib/dcp_examiner.cc @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -295,6 +297,7 @@ DCPExaminer::DCPExaminer (shared_ptr content, bool tolerant) } auto j2k_mono = dynamic_pointer_cast(pic); auto j2k_stereo = dynamic_pointer_cast(pic); + auto mpeg2_mono = dynamic_pointer_cast(pic); if (j2k_mono) { auto reader = j2k_mono->start_read(); @@ -304,6 +307,11 @@ DCPExaminer::DCPExaminer (shared_ptr content, bool tolerant) auto reader = j2k_stereo->start_read(); reader->set_check_hmac (false); reader->get_frame(0)->xyz_image(dcp::Eye::LEFT); + } else if (mpeg2_mono) { + auto reader = mpeg2_mono->start_read(); + reader->set_check_hmac(false); + dcp::MPEG2Decompressor decompressor; + decompressor.decompress_frame(reader->get_frame(0)); } } -- 2.30.2