From d3b5b533ebba1a1534eb37cc41032876a48a3d82 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 30 Nov 2023 00:29:16 +0100 Subject: Rename classes to follow preparatory renames in libdcp. --- src/lib/dcp_decoder.cc | 62 ++++++++++++++++++------------------------ src/lib/dcp_decoder.h | 12 ++++---- src/lib/dcp_examiner.cc | 26 +++++++++--------- src/lib/j2k_image_proxy.cc | 8 +++--- src/lib/j2k_image_proxy.h | 8 +++--- src/lib/map_cli.cc | 4 +-- src/lib/reel_writer.cc | 18 ++++++------ src/lib/reel_writer.h | 18 ++++++------ src/lib/video_mxf_content.cc | 8 +++--- src/lib/video_mxf_decoder.cc | 12 ++++---- src/lib/video_mxf_decoder.h | 8 +++--- src/lib/video_mxf_examiner.cc | 8 +++--- test/burnt_subtitle_test.cc | 6 ++-- test/dcp_subtitle_test.cc | 4 +-- test/overlap_video_test.cc | 4 +-- test/recover_test.cc | 16 +++++------ test/remake_video_test.cc | 4 +-- test/test.cc | 8 +++--- test/threed_test.cc | 8 +++--- test/torture_test.cc | 6 ++-- test/vf_test.cc | 8 +++--- test/video_level_test.cc | 6 ++-- test/video_mxf_content_test.cc | 6 ++-- 23 files changed, 130 insertions(+), 138 deletions(-) diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index 303126caa..d473476a0 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -36,9 +36,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -48,9 +48,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -169,24 +169,24 @@ DCPDecoder::pass () */ pass_texts (_next, picture_asset->size()); - if ((_mono_reader || _stereo_reader) && (_decode_referenced || !_dcp_content->reference_video())) { + if ((_j2k_mono_reader || _j2k_stereo_reader) && (_decode_referenced || !_dcp_content->reference_video())) { auto const entry_point = (*_reel)->main_picture()->entry_point().get_value_or(0); - if (_mono_reader) { + if (_j2k_mono_reader) { video->emit ( film(), std::make_shared( - _mono_reader->get_frame (entry_point + frame), + _j2k_mono_reader->get_frame(entry_point + frame), picture_asset->size(), AV_PIX_FMT_XYZ12LE, _forced_reduction ), ContentTime::from_frames(_offset + frame, vfr) ); - } else { + } else if (_j2k_stereo_reader) { video->emit ( film(), std::make_shared( - _stereo_reader->get_frame (entry_point + frame), + _j2k_stereo_reader->get_frame (entry_point + frame), picture_asset->size(), dcp::Eye::LEFT, AV_PIX_FMT_XYZ12LE, @@ -198,7 +198,7 @@ DCPDecoder::pass () video->emit ( film(), std::make_shared( - _stereo_reader->get_frame (entry_point + frame), + _j2k_stereo_reader->get_frame (entry_point + frame), picture_asset->size(), dcp::Eye::RIGHT, AV_PIX_FMT_XYZ12LE, @@ -367,38 +367,33 @@ DCPDecoder::next_reel () void DCPDecoder::get_readers () { + _j2k_mono_reader.reset(); + _j2k_stereo_reader.reset(); + _sound_reader.reset(); + _atmos_reader.reset(); + _atmos_metadata = boost::none; + if (_reel == _reels.end() || !_dcp_content->can_be_played ()) { - _mono_reader.reset (); - _stereo_reader.reset (); - _sound_reader.reset (); - _atmos_reader.reset (); return; } if (video && !video->ignore() && (*_reel)->main_picture()) { auto asset = (*_reel)->main_picture()->asset (); - auto mono = dynamic_pointer_cast (asset); - auto stereo = dynamic_pointer_cast (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 (); + auto j2k_mono = dynamic_pointer_cast(asset); + auto j2k_stereo = dynamic_pointer_cast(asset); + DCPOMATIC_ASSERT(j2k_mono || j2k_stereo) + 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 { - _mono_reader.reset (); - _stereo_reader.reset (); } if (audio && !audio->ignore() && (*_reel)->main_sound()) { _sound_reader = (*_reel)->main_sound()->asset()->start_read (); _sound_reader->set_check_hmac (false); - } else { - _sound_reader.reset (); } if ((*_reel)->atmos()) { @@ -406,9 +401,6 @@ DCPDecoder::get_readers () _atmos_reader = asset->start_read(); _atmos_reader->set_check_hmac (false); _atmos_metadata = AtmosMetadata (asset); - } else { - _atmos_reader.reset (); - _atmos_metadata = boost::none; } } diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h index 2c0cd8f41..0143ef881 100644 --- a/src/lib/dcp_decoder.h +++ b/src/lib/dcp_decoder.h @@ -27,8 +27,8 @@ #include "atmos_metadata.h" #include "decoder.h" #include "font_id_allocator.h" -#include -#include +#include +#include #include #include @@ -94,10 +94,10 @@ private: std::vector>::iterator _reel; /** Offset of _reel from the start of the content in frames */ int64_t _offset = 0; - /** Reader for current mono picture asset, if applicable */ - std::shared_ptr _mono_reader; - /** Reader for current stereo picture asset, if applicable */ - std::shared_ptr _stereo_reader; + /** Reader for current J2K mono picture asset, if applicable */ + std::shared_ptr _j2k_mono_reader; + /** Reader for current J2K stereo picture asset, if applicable */ + std::shared_ptr _j2k_stereo_reader; /** Reader for current sound asset, if applicable */ std::shared_ptr _sound_reader; std::shared_ptr _atmos_reader; diff --git a/src/lib/dcp_examiner.cc b/src/lib/dcp_examiner.cc index 3515f34c2..584ba4116 100644 --- a/src/lib/dcp_examiner.cc +++ b/src/lib/dcp_examiner.cc @@ -32,9 +32,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -46,9 +46,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -293,15 +293,15 @@ DCPExaminer::DCPExaminer (shared_ptr content, bool tolerant) LOG_GENERAL_NC ("Picture has no key"); break; } - auto mono = dynamic_pointer_cast(pic); - auto stereo = dynamic_pointer_cast(pic); + auto j2k_mono = dynamic_pointer_cast(pic); + auto j2k_stereo = dynamic_pointer_cast(pic); - if (mono) { - auto reader = mono->start_read(); + if (j2k_mono) { + auto reader = j2k_mono->start_read(); reader->set_check_hmac (false); reader->get_frame(0)->xyz_image(); - } else { - auto reader = stereo->start_read(); + } else if (j2k_stereo) { + auto reader = j2k_stereo->start_read(); reader->set_check_hmac (false); reader->get_frame(0)->xyz_image(dcp::Eye::LEFT); } @@ -354,7 +354,7 @@ DCPExaminer::DCPExaminer (shared_ptr content, bool tolerant) _standard = selected_cpl->standard(); if (!selected_cpl->reels().empty()) { auto first_reel = selected_cpl->reels()[0]; - _three_d = first_reel->main_picture() && first_reel->main_picture()->asset_ref().resolved() && dynamic_pointer_cast(first_reel->main_picture()->asset()); + _three_d = first_reel->main_picture() && first_reel->main_picture()->asset_ref().resolved() && dynamic_pointer_cast(first_reel->main_picture()->asset()); } _ratings = selected_cpl->ratings(); for (auto version: selected_cpl->content_versions()) { diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 869e96967..023723c8b 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -25,11 +25,11 @@ #include "j2k_image_proxy.h" #include #include -#include +#include #include #include #include -#include +#include #include #include LIBDCP_DISABLE_WARNINGS @@ -64,7 +64,7 @@ J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPi J2KImageProxy::J2KImageProxy ( - shared_ptr frame, + shared_ptr frame, dcp::Size size, AVPixelFormat pixel_format, optional forced_reduction @@ -81,7 +81,7 @@ J2KImageProxy::J2KImageProxy ( J2KImageProxy::J2KImageProxy ( - shared_ptr frame, + shared_ptr frame, dcp::Size size, dcp::Eye eye, AVPixelFormat pixel_format, diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index 3346fff08..1d2d5cc21 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -26,8 +26,8 @@ namespace dcp { - class MonoPictureFrame; - class StereoPictureFrame; + class MonoJ2KPictureFrame; + class StereoJ2KPictureFrame; } @@ -37,14 +37,14 @@ public: J2KImageProxy (boost::filesystem::path path, dcp::Size, AVPixelFormat pixel_format); J2KImageProxy ( - std::shared_ptr frame, + std::shared_ptr frame, dcp::Size, AVPixelFormat pixel_format, boost::optional forced_reduction ); J2KImageProxy ( - std::shared_ptr frame, + std::shared_ptr frame, dcp::Size, dcp::Eye, AVPixelFormat pixel_format, diff --git a/src/lib/map_cli.cc b/src/lib/map_cli.cc index b158499a8..be3841deb 100644 --- a/src/lib/map_cli.cc +++ b/src/lib/map_cli.cc @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 1b33cae85..1cca3fd17 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include #include "i18n.h" @@ -150,9 +150,9 @@ ReelWriter::ReelWriter ( if (film()->three_d()) { - _picture_asset.reset (new dcp::StereoPictureAsset(dcp::Fraction(film()->video_frame_rate(), 1), standard)); + _picture_asset = std::make_shared(dcp::Fraction(film()->video_frame_rate(), 1), standard); } else { - _picture_asset.reset (new dcp::MonoPictureAsset(dcp::Fraction(film()->video_frame_rate(), 1), standard)); + _picture_asset = std::make_shared(dcp::Fraction(film()->video_frame_rate(), 1), standard); } _picture_asset->set_size (film()->frame_size()); @@ -164,14 +164,14 @@ ReelWriter::ReelWriter ( } _picture_asset->set_file (asset); - _picture_asset_writer = _picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::PictureAsset::Behaviour::OVERWRITE_EXISTING : dcp::PictureAsset::Behaviour::MAKE_NEW); + _picture_asset_writer = _picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW); } else if (!text_only) { /* We already have a complete picture asset that we can just re-use */ /* XXX: what about if the encryption key changes? */ if (film()->three_d()) { - _picture_asset = make_shared(asset); + _picture_asset = make_shared(asset); } else { - _picture_asset = make_shared(asset); + _picture_asset = make_shared(asset); } } @@ -546,12 +546,12 @@ ReelWriter::create_reel_picture (shared_ptr reel, list (_picture_asset); + auto mono = dynamic_pointer_cast(_picture_asset); if (mono) { reel_asset = make_shared(mono, 0); } - auto stereo = dynamic_pointer_cast (_picture_asset); + auto stereo = dynamic_pointer_cast(_picture_asset); if (stereo) { reel_asset = make_shared(stereo, 0); } diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index c9052c832..0886482a8 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -30,7 +30,7 @@ #include "weak_film.h" #include #include -#include +#include class AudioBuffers; @@ -41,17 +41,17 @@ struct write_frame_info_test; namespace dcp { class AtmosAsset; - class MonoPictureAsset; - class MonoPictureAssetWriter; - class PictureAsset; - class PictureAssetWriter; + class MonoJ2KPictureAsset; + class MonoJ2KPictureAssetWriter; + class J2KPictureAsset; + class J2KPictureAssetWriter; class Reel; class ReelAsset; class ReelPictureAsset; class SoundAsset; class SoundAssetWriter; - class StereoPictureAsset; - class StereoPictureAssetWriter; + class StereoJ2KPictureAsset; + class StereoJ2KPictureAssetWriter; class SubtitleAsset; } @@ -134,9 +134,9 @@ private: dcp::ArrayData _default_font; - std::shared_ptr _picture_asset; + std::shared_ptr _picture_asset; /** picture asset writer, or 0 if we are not writing any picture because we already have one */ - std::shared_ptr _picture_asset_writer; + std::shared_ptr _picture_asset_writer; std::shared_ptr _sound_asset; std::shared_ptr _sound_asset_writer; std::shared_ptr _subtitle_asset; diff --git a/src/lib/video_mxf_content.cc b/src/lib/video_mxf_content.cc index 546e1445b..eeee6222c 100644 --- a/src/lib/video_mxf_content.cc +++ b/src/lib/video_mxf_content.cc @@ -26,8 +26,8 @@ #include "film.h" #include "compose.hpp" #include -#include -#include +#include +#include #include #include @@ -61,7 +61,7 @@ VideoMXFContent::valid_mxf (boost::filesystem::path path) Kumu::DefaultLogSink().UnsetFilterFlag(Kumu::LOG_ALLOW_ALL); try { - dcp::MonoPictureAsset mp (path); + dcp::MonoJ2KPictureAsset mp(path); return true; } catch (dcp::MXFFileError& e) { @@ -71,7 +71,7 @@ VideoMXFContent::valid_mxf (boost::filesystem::path path) try { Kumu::DefaultLogSink().SetFilterFlag(0); - dcp::StereoPictureAsset sp (path); + dcp::StereoJ2KPictureAsset sp (path); return true; } catch (dcp::MXFFileError& e) { diff --git a/src/lib/video_mxf_decoder.cc b/src/lib/video_mxf_decoder.cc index 9f451297b..3d1ed7f4e 100644 --- a/src/lib/video_mxf_decoder.cc +++ b/src/lib/video_mxf_decoder.cc @@ -24,10 +24,10 @@ #include "video_mxf_content.h" #include "j2k_image_proxy.h" #include "frame_interval_checker.h" -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -44,7 +44,7 @@ VideoMXFDecoder::VideoMXFDecoder (shared_ptr film, shared_ptr(this, content); try { - auto mono = make_shared(_content->path(0)); + auto mono = make_shared(_content->path(0)); _mono_reader = mono->start_read (); _mono_reader->set_check_hmac (false); _size = mono->size (); @@ -55,7 +55,7 @@ VideoMXFDecoder::VideoMXFDecoder (shared_ptr film, shared_ptr(_content->path(0)); + auto stereo = make_shared(_content->path(0)); _stereo_reader = stereo->start_read (); _stereo_reader->set_check_hmac (false); _size = stereo->size (); diff --git a/src/lib/video_mxf_decoder.h b/src/lib/video_mxf_decoder.h index 774e269c6..16d8b112e 100644 --- a/src/lib/video_mxf_decoder.h +++ b/src/lib/video_mxf_decoder.h @@ -20,8 +20,8 @@ #include "decoder.h" -#include -#include +#include +#include class VideoMXFContent; @@ -42,7 +42,7 @@ private: /** Time of next thing to return from pass */ dcpomatic::ContentTime _next; - std::shared_ptr _mono_reader; - std::shared_ptr _stereo_reader; + std::shared_ptr _mono_reader; + std::shared_ptr _stereo_reader; dcp::Size _size; }; diff --git a/src/lib/video_mxf_examiner.cc b/src/lib/video_mxf_examiner.cc index 7a05f3369..276664a14 100644 --- a/src/lib/video_mxf_examiner.cc +++ b/src/lib/video_mxf_examiner.cc @@ -21,8 +21,8 @@ #include "video_mxf_content.h" #include "video_mxf_examiner.h" #include -#include -#include +#include +#include using std::shared_ptr; using boost::optional; @@ -30,7 +30,7 @@ using boost::optional; VideoMXFExaminer::VideoMXFExaminer (shared_ptr content) { try { - _asset.reset (new dcp::MonoPictureAsset (content->path(0))); + _asset = std::make_shared(content->path(0)); } catch (dcp::MXFFileError& e) { /* maybe it's stereo */ } catch (dcp::ReadError& e) { @@ -38,7 +38,7 @@ VideoMXFExaminer::VideoMXFExaminer (shared_ptr content) } if (!_asset) { - _asset.reset (new dcp::StereoPictureAsset (content->path(0))); + _asset = std::make_shared(content->path(0)); } } diff --git a/test/burnt_subtitle_test.cc b/test/burnt_subtitle_test.cc index 8d7dcd143..9d25287b2 100644 --- a/test/burnt_subtitle_test.cc +++ b/test/burnt_subtitle_test.cc @@ -39,9 +39,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/test/dcp_subtitle_test.cc b/test/dcp_subtitle_test.cc index 837362e84..e62bd70ba 100644 --- a/test/dcp_subtitle_test.cc +++ b/test/dcp_subtitle_test.cc @@ -37,7 +37,7 @@ #include "lib/text_content.h" #include "lib/text_decoder.h" #include "test.h" -#include +#include #include #include #include @@ -327,7 +327,7 @@ BOOST_AUTO_TEST_CASE(entity_from_dcp_source) dcp::VerificationNote::Code::INVALID_SUBTITLE_SPACING, }); - dcp::MonoPictureAsset burnt(dcp_file(film, "j2c_")); + dcp::MonoJ2KPictureAsset burnt(dcp_file(film, "j2c_")); auto frame = burnt.start_read()->get_frame(12)->xyz_image(); auto const size = frame->size(); int max_X = 0; diff --git a/test/overlap_video_test.cc b/test/overlap_video_test.cc index cb5fcb430..9bef93d67 100644 --- a/test/overlap_video_test.cc +++ b/test/overlap_video_test.cc @@ -30,8 +30,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/test/recover_test.cc b/test/recover_test.cc index 63c611831..01b71a05e 100644 --- a/test/recover_test.cc +++ b/test/recover_test.cc @@ -33,8 +33,8 @@ #include "lib/video_content.h" #include "lib/ratio.h" #include -#include -#include +#include +#include #include #include @@ -94,8 +94,8 @@ BOOST_AUTO_TEST_CASE (recover_test_2d) false ); - auto A = make_shared("build/test/recover_test_2d/original.mxf"); - auto B = make_shared(video); + auto A = make_shared("build/test/recover_test_2d/original.mxf"); + auto B = make_shared(video); dcp::EqualityOptions eq; BOOST_CHECK (A->equals (B, eq, boost::bind (¬e, _1, _2))); @@ -137,8 +137,8 @@ BOOST_AUTO_TEST_CASE (recover_test_3d, * boost::unit_test::depends_on("recover_t false ); - auto A = make_shared("build/test/recover_test_3d/original.mxf"); - auto B = make_shared(video); + auto A = make_shared("build/test/recover_test_3d/original.mxf"); + auto B = make_shared(video); dcp::EqualityOptions eq; BOOST_CHECK (A->equals (B, eq, boost::bind (¬e, _1, _2))); @@ -181,9 +181,9 @@ BOOST_AUTO_TEST_CASE (recover_test_2d_encrypted, * boost::unit_test::depends_on( false ); - auto A = make_shared("build/test/recover_test_2d_encrypted/original.mxf"); + auto A = make_shared("build/test/recover_test_2d_encrypted/original.mxf"); A->set_key (film->key ()); - auto B = make_shared(video); + auto B = make_shared(video); B->set_key (film->key ()); dcp::EqualityOptions eq; diff --git a/test/remake_video_test.cc b/test/remake_video_test.cc index a07659844..2afe90b63 100644 --- a/test/remake_video_test.cc +++ b/test/remake_video_test.cc @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(remake_video_after_yub_rgb_matrix_changed) BOOST_REQUIRE(!cpl->reels().empty()); auto reel = cpl->reels()[0]; BOOST_REQUIRE(reel->main_picture()); - auto mono = dynamic_pointer_cast(reel->main_picture()->asset()); + auto mono = dynamic_pointer_cast(reel->main_picture()->asset()); BOOST_REQUIRE(mono); auto reader = mono->start_read(); diff --git a/test/test.cc b/test/test.cc index 4064f9b0e..64a48b714 100644 --- a/test/test.cc +++ b/test/test.cc @@ -47,8 +47,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -829,10 +829,10 @@ check_one_frame (boost::filesystem::path dcp_dir, int64_t index, boost::filesyst { dcp::DCP dcp (dcp_dir); dcp.read (); - auto asset = dynamic_pointer_cast (dcp.cpls().front()->reels().front()->main_picture()->asset()); + auto asset = dynamic_pointer_cast(dcp.cpls().front()->reels().front()->main_picture()->asset()); BOOST_REQUIRE (asset); auto frame = asset->start_read()->get_frame(index); - dcp::MonoPictureFrame ref_frame(ref); + dcp::MonoJ2KPictureFrame ref_frame(ref); auto image = frame->xyz_image (); auto ref_image = ref_frame.xyz_image(); diff --git a/test/threed_test.cc b/test/threed_test.cc index 78d74add4..38b8f36d4 100644 --- a/test/threed_test.cc +++ b/test/threed_test.cc @@ -42,8 +42,8 @@ #include "lib/util.h" #include "lib/video_content.h" #include "test.h" -#include -#include +#include +#include #include #include @@ -330,10 +330,10 @@ BOOST_AUTO_TEST_CASE(threed_passthrough_test, * boost::unit_test::depends_on("th BOOST_REQUIRE_EQUAL(matches.size(), 1U); - auto stereo = dcp::StereoPictureAsset(matches[0]); + auto stereo = dcp::StereoJ2KPictureAsset(matches[0]); auto stereo_reader = stereo.start_read(); - auto mono = dcp::MonoPictureAsset(dcp_file(film, "j2c")); + auto mono = dcp::MonoJ2KPictureAsset(dcp_file(film, "j2c")); auto mono_reader = mono.start_read(); BOOST_REQUIRE_EQUAL(stereo.intrinsic_duration(), mono.intrinsic_duration()); diff --git a/test/torture_test.cc b/test/torture_test.cc index 8e6a516bd..e5ce694ce 100644 --- a/test/torture_test.cc +++ b/test/torture_test.cc @@ -35,8 +35,8 @@ #include "lib/video_content.h" #include "test.h" #include -#include -#include +#include +#include #include #include #include @@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE (torture_test1) auto reel_picture = reels.front()->main_picture(); BOOST_REQUIRE (reel_picture); - auto picture = dynamic_pointer_cast (reel_picture->asset()); + auto picture = dynamic_pointer_cast(reel_picture->asset()); BOOST_REQUIRE (picture); BOOST_CHECK_EQUAL (picture->intrinsic_duration(), 144); diff --git a/test/vf_test.cc b/test/vf_test.cc index ca987b22d..051712deb 100644 --- a/test/vf_test.cc +++ b/test/vf_test.cc @@ -40,8 +40,8 @@ #include "lib/video_content.h" #include "test.h" #include -#include -#include +#include +#include #include #include #include @@ -492,8 +492,8 @@ BOOST_AUTO_TEST_CASE(test_referencing_ov_with_missing_subtitle_in_some_reels) dcp::DCP ov(path / "ov"); auto make_picture = [path](string filename) { - auto pic = make_shared(dcp::Fraction(24, 1), dcp::Standard::SMPTE); - auto writer = pic->start_write(path / "ov" / filename, dcp::PictureAsset::Behaviour::MAKE_NEW); + auto pic = make_shared(dcp::Fraction(24, 1), dcp::Standard::SMPTE); + auto writer = pic->start_write(path / "ov" / filename, dcp::Behaviour::MAKE_NEW); auto frame = dcp::ArrayData("test/data/picture.j2c"); for (int i = 0; i < 240; ++i) { writer->write(frame); diff --git a/test/video_level_test.cc b/test/video_level_test.cc index 0ff2c4732..c8e939861 100644 --- a/test/video_level_test.cc +++ b/test/video_level_test.cc @@ -45,8 +45,8 @@ #include "test.h" #include #include -#include -#include +#include +#include #include #include #include @@ -275,7 +275,7 @@ pixel_range (boost::filesystem::path dcp_path) dcp::DCP dcp (dcp_path); dcp.read (); - auto picture = dynamic_pointer_cast(dcp.cpls().front()->reels().front()->main_picture()->asset()); + auto picture = dynamic_pointer_cast(dcp.cpls().front()->reels().front()->main_picture()->asset()); BOOST_REQUIRE (picture); auto frame = picture->start_read()->get_frame(0)->xyz_image(); diff --git a/test/video_mxf_content_test.cc b/test/video_mxf_content_test.cc index f3766e4af..819706803 100644 --- a/test/video_mxf_content_test.cc +++ b/test/video_mxf_content_test.cc @@ -33,7 +33,7 @@ #include "lib/video_mxf_content.h" #include "test.h" #include -#include +#include #include @@ -70,9 +70,9 @@ BOOST_AUTO_TEST_CASE (video_mxf_content_test) dcp::VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K }); - auto ref = make_shared(ref_mxf); + auto ref = make_shared(ref_mxf); boost::filesystem::directory_iterator i ("build/test/video_mxf_content_test/video"); - auto comp = make_shared(*i); + auto comp = make_shared(*i); dcp::EqualityOptions op; BOOST_CHECK (ref->equals (comp, op, note)); } -- cgit v1.2.3 From 1fc8c0c6d045404732497ba70bd2eccfbe4cc6f6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 19 Mar 2024 16:29:13 +0100 Subject: Rename Encoder -> FilmEncoder, and subclasses. --- src/lib/dcp_decoder.cc | 1 + src/lib/dcp_encoder.cc | 180 ---------------------- src/lib/dcp_encoder.h | 79 ---------- src/lib/dcp_film_encoder.cc | 180 ++++++++++++++++++++++ src/lib/dcp_film_encoder.h | 79 ++++++++++ src/lib/encode_server.cc | 1 + src/lib/encode_server_finder.cc | 1 + src/lib/encoder.cc | 47 ------ src/lib/encoder.h | 71 --------- src/lib/ffmpeg_encoder.cc | 315 -------------------------------------- src/lib/ffmpeg_encoder.h | 98 ------------ src/lib/ffmpeg_file_encoder.cc | 2 +- src/lib/ffmpeg_file_encoder.h | 4 +- src/lib/ffmpeg_film_encoder.cc | 315 ++++++++++++++++++++++++++++++++++++++ src/lib/ffmpeg_film_encoder.h | 98 ++++++++++++ src/lib/film.cc | 2 +- src/lib/film_encoder.cc | 47 ++++++ src/lib/film_encoder.h | 70 +++++++++ src/lib/hints.h | 9 +- src/lib/make_dcp.cc | 4 +- src/lib/reel_writer.h | 1 + src/lib/subtitle_encoder.cc | 204 ------------------------ src/lib/subtitle_encoder.h | 64 -------- src/lib/subtitle_film_encoder.cc | 204 ++++++++++++++++++++++++ src/lib/subtitle_film_encoder.h | 64 ++++++++ src/lib/transcode_job.cc | 8 +- src/lib/transcode_job.h | 6 +- src/lib/wscript | 8 +- src/tools/dcpomatic.cc | 8 +- src/tools/dcpomatic_cli.cc | 4 +- src/tools/dcpomatic_combiner.cc | 1 + src/tools/dcpomatic_editor.cc | 1 + src/tools/dcpomatic_kdm.cc | 1 + src/wx/config_dialog.cc | 1 + src/wx/dcp_timeline.h | 2 + src/wx/export_video_file_dialog.h | 2 +- src/wx/film_viewer.h | 2 + src/wx/kdm_cpl_panel.cc | 1 + src/wx/timeline_content_view.cc | 1 + test/burnt_subtitle_test.cc | 4 +- test/ffmpeg_encoder_test.cc | 42 ++--- test/j2k_encode_threading_test.cc | 4 +- test/optimise_stills_test.cc | 1 - test/video_level_test.cc | 4 +- test/writer_test.cc | 4 +- 45 files changed, 1130 insertions(+), 1115 deletions(-) delete mode 100644 src/lib/dcp_encoder.cc delete mode 100644 src/lib/dcp_encoder.h create mode 100644 src/lib/dcp_film_encoder.cc create mode 100644 src/lib/dcp_film_encoder.h delete mode 100644 src/lib/encoder.cc delete mode 100644 src/lib/encoder.h delete mode 100644 src/lib/ffmpeg_encoder.cc delete mode 100644 src/lib/ffmpeg_encoder.h create mode 100644 src/lib/ffmpeg_film_encoder.cc create mode 100644 src/lib/ffmpeg_film_encoder.h create mode 100644 src/lib/film_encoder.cc create mode 100644 src/lib/film_encoder.h delete mode 100644 src/lib/subtitle_encoder.cc delete mode 100644 src/lib/subtitle_encoder.h create mode 100644 src/lib/subtitle_film_encoder.cc create mode 100644 src/lib/subtitle_film_encoder.h diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index d473476a0..ce471202f 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -32,6 +32,7 @@ #include "image.h" #include "j2k_image_proxy.h" #include "text_decoder.h" +#include "util.h" #include "video_decoder.h" #include #include diff --git a/src/lib/dcp_encoder.cc b/src/lib/dcp_encoder.cc deleted file mode 100644 index bd78312fa..000000000 --- a/src/lib/dcp_encoder.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright (C) 2012-2020 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -/** @file src/dcp_encoder.cc - * @brief A class which takes a Film and some Options, then uses those to encode the film into a DCP. - * - * A decoder is selected according to the content type, and the encoder can be specified - * as a parameter to the constructor. - */ - - -#include "audio_decoder.h" -#include "compose.hpp" -#include "dcp_encoder.h" -#include "film.h" -#include "j2k_encoder.h" -#include "job.h" -#include "player.h" -#include "player_video.h" -#include "referenced_reel_asset.h" -#include "text_content.h" -#include "video_decoder.h" -#include "writer.h" -#include -#include - -#include "i18n.h" - - -using std::cout; -using std::dynamic_pointer_cast; -using std::list; -using std::make_shared; -using std::shared_ptr; -using std::string; -using std::vector; -using std::weak_ptr; -using boost::optional; -#if BOOST_VERSION >= 106100 -using namespace boost::placeholders; -#endif -using namespace dcpomatic; - - -/** Construct a DCP encoder. - * @param film Film that we are encoding. - * @param job Job that this encoder is being used in. - */ -DCPEncoder::DCPEncoder (shared_ptr film, weak_ptr job) - : Encoder (film, job) - , _writer(film, job) - , _j2k_encoder(film, _writer) - , _finishing (false) - , _non_burnt_subtitles (false) -{ - _player_video_connection = _player.Video.connect(bind(&DCPEncoder::video, this, _1, _2)); - _player_audio_connection = _player.Audio.connect(bind(&DCPEncoder::audio, this, _1, _2)); - _player_text_connection = _player.Text.connect(bind(&DCPEncoder::text, this, _1, _2, _3, _4)); - _player_atmos_connection = _player.Atmos.connect(bind(&DCPEncoder::atmos, this, _1, _2, _3)); - - for (auto c: film->content ()) { - for (auto i: c->text) { - if (i->use() && !i->burn()) { - _non_burnt_subtitles = true; - } - } - } -} - -DCPEncoder::~DCPEncoder () -{ - /* We must stop receiving more video data before we die */ - _player_video_connection.release (); - _player_audio_connection.release (); - _player_text_connection.release (); - _player_atmos_connection.release (); -} - -void -DCPEncoder::go () -{ - _writer.start(); - _j2k_encoder.begin(); - - { - auto job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->sub (_("Encoding")); - } - - if (_non_burnt_subtitles) { - _writer.write(_player.get_subtitle_fonts()); - } - - while (!_player.pass()) {} - - for (auto i: get_referenced_reel_assets(_film, _film->playlist())) { - _writer.write(i); - } - - _finishing = true; - _j2k_encoder.end(); - _writer.finish(_film->dir(_film->dcp_name())); -} - - -void -DCPEncoder::pause() -{ - _j2k_encoder.pause(); -} - - -void -DCPEncoder::resume() -{ - _j2k_encoder.resume(); -} - -void -DCPEncoder::video (shared_ptr data, DCPTime time) -{ - _j2k_encoder.encode(data, time); -} - -void -DCPEncoder::audio (shared_ptr data, DCPTime time) -{ - _writer.write(data, time); - - auto job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->set_progress (float(time.get()) / _film->length().get()); -} - -void -DCPEncoder::text (PlayerText data, TextType type, optional track, DCPTimePeriod period) -{ - if (type == TextType::CLOSED_CAPTION || _non_burnt_subtitles) { - _writer.write(data, type, track, period); - } -} - - -void -DCPEncoder::atmos (shared_ptr data, DCPTime time, AtmosMetadata metadata) -{ - _writer.write(data, time, metadata); -} - - -optional -DCPEncoder::current_rate () const -{ - return _j2k_encoder.current_encoding_rate(); -} - -Frame -DCPEncoder::frames_done () const -{ - return _j2k_encoder.video_frames_enqueued(); -} diff --git a/src/lib/dcp_encoder.h b/src/lib/dcp_encoder.h deleted file mode 100644 index ce0b72204..000000000 --- a/src/lib/dcp_encoder.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright (C) 2012-2020 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -#include "atmos_metadata.h" -#include "dcp_text_track.h" -#include "dcpomatic_time.h" -#include "encoder.h" -#include "player_text.h" -#include "j2k_encoder.h" -#include "writer.h" -#include - - -class AudioBuffers; -class Film; -class Job; -class Player; -class PlayerVideo; - -struct frames_not_lost_when_threads_disappear; - - -/** @class DCPEncoder */ -class DCPEncoder : public Encoder -{ -public: - DCPEncoder (std::shared_ptr film, std::weak_ptr job); - ~DCPEncoder (); - - void go () override; - - boost::optional current_rate () const override; - Frame frames_done () const override; - - /** @return true if we are in the process of calling Encoder::process_end */ - bool finishing () const override { - return _finishing; - } - - void pause() override; - void resume() override; - -private: - - friend struct ::frames_not_lost_when_threads_disappear; - - void video (std::shared_ptr, dcpomatic::DCPTime); - void audio (std::shared_ptr, dcpomatic::DCPTime); - void text (PlayerText, TextType, boost::optional, dcpomatic::DCPTimePeriod); - void atmos (std::shared_ptr, dcpomatic::DCPTime, AtmosMetadata metadata); - - Writer _writer; - J2KEncoder _j2k_encoder; - bool _finishing; - bool _non_burnt_subtitles; - - boost::signals2::scoped_connection _player_video_connection; - boost::signals2::scoped_connection _player_audio_connection; - boost::signals2::scoped_connection _player_text_connection; - boost::signals2::scoped_connection _player_atmos_connection; -}; diff --git a/src/lib/dcp_film_encoder.cc b/src/lib/dcp_film_encoder.cc new file mode 100644 index 000000000..0403b2d90 --- /dev/null +++ b/src/lib/dcp_film_encoder.cc @@ -0,0 +1,180 @@ +/* + Copyright (C) 2012-2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +/** @file src/dcp_film_encoder.cc + * @brief A class which takes a Film and some Options, then uses those to encode the film into a DCP. + * + * A decoder is selected according to the content type, and the encoder can be specified + * as a parameter to the constructor. + */ + + +#include "audio_decoder.h" +#include "compose.hpp" +#include "dcp_film_encoder.h" +#include "film.h" +#include "j2k_encoder.h" +#include "job.h" +#include "player.h" +#include "player_video.h" +#include "referenced_reel_asset.h" +#include "text_content.h" +#include "video_decoder.h" +#include "writer.h" +#include +#include + +#include "i18n.h" + + +using std::cout; +using std::dynamic_pointer_cast; +using std::list; +using std::make_shared; +using std::shared_ptr; +using std::string; +using std::vector; +using std::weak_ptr; +using boost::optional; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif +using namespace dcpomatic; + + +/** Construct a DCP encoder. + * @param film Film that we are encoding. + * @param job Job that this encoder is being used in. + */ +DCPFilmEncoder::DCPFilmEncoder(shared_ptr film, weak_ptr job) + : FilmEncoder(film, job) + , _writer(film, job) + , _j2k_encoder(film, _writer) + , _finishing (false) + , _non_burnt_subtitles (false) +{ + _player_video_connection = _player.Video.connect(bind(&DCPFilmEncoder::video, this, _1, _2)); + _player_audio_connection = _player.Audio.connect(bind(&DCPFilmEncoder::audio, this, _1, _2)); + _player_text_connection = _player.Text.connect(bind(&DCPFilmEncoder::text, this, _1, _2, _3, _4)); + _player_atmos_connection = _player.Atmos.connect(bind(&DCPFilmEncoder::atmos, this, _1, _2, _3)); + + for (auto c: film->content ()) { + for (auto i: c->text) { + if (i->use() && !i->burn()) { + _non_burnt_subtitles = true; + } + } + } +} + +DCPFilmEncoder::~DCPFilmEncoder() +{ + /* We must stop receiving more video data before we die */ + _player_video_connection.release (); + _player_audio_connection.release (); + _player_text_connection.release (); + _player_atmos_connection.release (); +} + +void +DCPFilmEncoder::go() +{ + _writer.start(); + _j2k_encoder.begin(); + + { + auto job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->sub (_("Encoding")); + } + + if (_non_burnt_subtitles) { + _writer.write(_player.get_subtitle_fonts()); + } + + while (!_player.pass()) {} + + for (auto i: get_referenced_reel_assets(_film, _film->playlist())) { + _writer.write(i); + } + + _finishing = true; + _j2k_encoder.end(); + _writer.finish(_film->dir(_film->dcp_name())); +} + + +void +DCPFilmEncoder::pause() +{ + _j2k_encoder.pause(); +} + + +void +DCPFilmEncoder::resume() +{ + _j2k_encoder.resume(); +} + +void +DCPFilmEncoder::video(shared_ptr data, DCPTime time) +{ + _j2k_encoder.encode(data, time); +} + +void +DCPFilmEncoder::audio(shared_ptr data, DCPTime time) +{ + _writer.write(data, time); + + auto job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->set_progress (float(time.get()) / _film->length().get()); +} + +void +DCPFilmEncoder::text(PlayerText data, TextType type, optional track, DCPTimePeriod period) +{ + if (type == TextType::CLOSED_CAPTION || _non_burnt_subtitles) { + _writer.write(data, type, track, period); + } +} + + +void +DCPFilmEncoder::atmos(shared_ptr data, DCPTime time, AtmosMetadata metadata) +{ + _writer.write(data, time, metadata); +} + + +optional +DCPFilmEncoder::current_rate() const +{ + return _j2k_encoder.current_encoding_rate(); +} + +Frame +DCPFilmEncoder::frames_done() const +{ + return _j2k_encoder.video_frames_enqueued(); +} diff --git a/src/lib/dcp_film_encoder.h b/src/lib/dcp_film_encoder.h new file mode 100644 index 000000000..fbc0aeb13 --- /dev/null +++ b/src/lib/dcp_film_encoder.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2012-2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "atmos_metadata.h" +#include "dcp_text_track.h" +#include "dcpomatic_time.h" +#include "film_encoder.h" +#include "player_text.h" +#include "j2k_encoder.h" +#include "writer.h" +#include + + +class AudioBuffers; +class Film; +class Job; +class Player; +class PlayerVideo; + +struct frames_not_lost_when_threads_disappear; + + +/** @class DCPFilmEncoder */ +class DCPFilmEncoder : public FilmEncoder +{ +public: + DCPFilmEncoder(std::shared_ptr film, std::weak_ptr job); + ~DCPFilmEncoder(); + + void go () override; + + boost::optional current_rate () const override; + Frame frames_done () const override; + + /** @return true if we are in the process of calling Encoder::process_end */ + bool finishing () const override { + return _finishing; + } + + void pause() override; + void resume() override; + +private: + + friend struct ::frames_not_lost_when_threads_disappear; + + void video (std::shared_ptr, dcpomatic::DCPTime); + void audio (std::shared_ptr, dcpomatic::DCPTime); + void text (PlayerText, TextType, boost::optional, dcpomatic::DCPTimePeriod); + void atmos (std::shared_ptr, dcpomatic::DCPTime, AtmosMetadata metadata); + + Writer _writer; + J2KEncoder _j2k_encoder; + bool _finishing; + bool _non_burnt_subtitles; + + boost::signals2::scoped_connection _player_video_connection; + boost::signals2::scoped_connection _player_audio_connection; + boost::signals2::scoped_connection _player_text_connection; + boost::signals2::scoped_connection _player_atmos_connection; +}; diff --git a/src/lib/encode_server.cc b/src/lib/encode_server.cc index da5c7270e..68ee871f8 100644 --- a/src/lib/encode_server.cc +++ b/src/lib/encode_server.cc @@ -37,6 +37,7 @@ #include "image.h" #include "log.h" #include "player_video.h" +#include "util.h" #include "variant.h" #include "version.h" #include diff --git a/src/lib/encode_server_finder.cc b/src/lib/encode_server_finder.cc index 9ce9e1691..143569e16 100644 --- a/src/lib/encode_server_finder.cc +++ b/src/lib/encode_server_finder.cc @@ -26,6 +26,7 @@ #include "encode_server_description.h" #include "encode_server_finder.h" #include "exceptions.h" +#include "util.h" #include "variant.h" #include #include diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc deleted file mode 100644 index 5268d8620..000000000 --- a/src/lib/encoder.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (C) 2012-2017 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -/** @file src/encoder.cc - * @brief A class which takes a Film and some Options, then uses those to encode the film - * into some output format. - * - * A decoder is selected according to the content type, and the encoder can be specified - * as a parameter to the constructor. - */ - - -#include "encoder.h" -#include "player.h" - -#include "i18n.h" - - -/** Construct an encoder. - * @param film Film that we are encoding. - * @param job Job that this encoder is being used in. - */ -Encoder::Encoder (std::shared_ptr film, std::weak_ptr job) - : _film (film) - , _job (job) - , _player(film, Image::Alignment::PADDED) -{ - -} diff --git a/src/lib/encoder.h b/src/lib/encoder.h deleted file mode 100644 index aeaf7f620..000000000 --- a/src/lib/encoder.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - Copyright (C) 2012-2021 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -#ifndef DCPOMATIC_ENCODER_H -#define DCPOMATIC_ENCODER_H - - -#include "player.h" -#include "player_text.h" -#include - - -class Film; -class Encoder; -class Player; -class Job; -class PlayerVideo; -class AudioBuffers; - - -/** @class Encoder - * @brief Parent class for something that can encode a film into some format - */ -class Encoder -{ -public: - Encoder (std::shared_ptr film, std::weak_ptr job); - virtual ~Encoder () {} - - Encoder (Encoder const&) = delete; - Encoder& operator= (Encoder const&) = delete; - - virtual void go () = 0; - - /** @return the current frame rate over the last short while */ - virtual boost::optional current_rate () const { - return {}; - } - - /** @return the number of frames that are done */ - virtual Frame frames_done () const = 0; - virtual bool finishing () const = 0; - virtual void pause() {} - virtual void resume() {} - -protected: - std::shared_ptr _film; - std::weak_ptr _job; - Player _player; -}; - - -#endif diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc deleted file mode 100644 index 60241b233..000000000 --- a/src/lib/ffmpeg_encoder.cc +++ /dev/null @@ -1,315 +0,0 @@ -/* - Copyright (C) 2017-2018 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -#include "butler.h" -#include "cross.h" -#include "ffmpeg_encoder.h" -#include "film.h" -#include "image.h" -#include "job.h" -#include "log.h" -#include "player.h" -#include "player_video.h" -#include "compose.hpp" -#include - -#include "i18n.h" - - -using std::cout; -using std::list; -using std::make_shared; -using std::shared_ptr; -using std::string; -using std::weak_ptr; -using boost::bind; -using boost::optional; -using namespace dcpomatic; -#if BOOST_VERSION >= 106100 -using namespace boost::placeholders; -#endif - - -FFmpegEncoder::FFmpegEncoder ( - shared_ptr film, - weak_ptr job, - boost::filesystem::path output, - ExportFormat format, - bool mixdown_to_stereo, - bool split_reels, - bool audio_stream_per_channel, - int x264_crf - ) - : Encoder (film, job) - , _output_audio_channels(mixdown_to_stereo ? 2 : (_film->audio_channels() > 8 ? 16 : _film->audio_channels())) - , _history (200) - , _output (output) - , _format (format) - , _split_reels (split_reels) - , _audio_stream_per_channel (audio_stream_per_channel) - , _x264_crf (x264_crf) - , _butler( - _film, - _player, - mixdown_to_stereo ? stereo_map() : many_channel_map(), - _output_audio_channels, - boost::bind(&PlayerVideo::force, FFmpegFileEncoder::pixel_format(format)), - VideoRange::VIDEO, - Image::Alignment::PADDED, - false, - false, - Butler::Audio::ENABLED - ) -{ - _player.set_always_burn_open_subtitles(); - _player.set_play_referenced(); -} - - -AudioMapping -FFmpegEncoder::stereo_map() const -{ - auto map = AudioMapping(_film->audio_channels(), 2); - float const overall_gain = 2 / (4 + sqrt(2)); - float const minus_3dB = 1 / sqrt(2); - switch (_film->audio_channels()) { - case 2: - map.set(dcp::Channel::LEFT, 0, 1); - map.set(dcp::Channel::RIGHT, 1, 1); - break; - case 4: - map.set(dcp::Channel::LEFT, 0, overall_gain); - map.set(dcp::Channel::RIGHT, 1, overall_gain); - map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); - map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); - map.set(dcp::Channel::LS, 0, overall_gain); - break; - case 6: - map.set(dcp::Channel::LEFT, 0, overall_gain); - map.set(dcp::Channel::RIGHT, 1, overall_gain); - map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); - map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); - map.set(dcp::Channel::LS, 0, overall_gain); - map.set(dcp::Channel::RS, 1, overall_gain); - break; - } - /* XXX: maybe we should do something better for >6 channel DCPs */ - return map; -} - - -AudioMapping -FFmpegEncoder::many_channel_map() const -{ - auto map = AudioMapping(_film->audio_channels(), _output_audio_channels); - for (int i = 0; i < _film->audio_channels(); ++i) { - map.set(i, i, 1); - } - return map; -} - - -void -FFmpegEncoder::go () -{ - { - auto job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->sub (_("Encoding")); - } - - Waker waker; - - list file_encoders; - - int const files = _split_reels ? _film->reels().size() : 1; - for (int i = 0; i < files; ++i) { - - boost::filesystem::path filename = _output; - auto extension = dcp::filesystem::extension(filename); - filename = dcp::filesystem::change_extension(filename, ""); - - if (files > 1) { - /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate - /// which reel it is. Preserve the %1; it will be replaced with the reel number. - filename = filename.string() + String::compose(_("_reel%1"), i + 1); - } - - file_encoders.push_back ( - FileEncoderSet ( - _film->frame_size(), - _film->video_frame_rate(), - _film->audio_frame_rate(), - _output_audio_channels, - _format, - _audio_stream_per_channel, - _x264_crf, - _film->three_d(), - filename, - extension - ) - ); - } - - auto reel_periods = _film->reels (); - auto reel = reel_periods.begin (); - auto encoder = file_encoders.begin (); - - auto const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ()); - int const audio_frames = video_frame.frames_round(_film->audio_frame_rate()); - std::vector interleaved(_output_audio_channels * audio_frames); - auto deinterleaved = make_shared(_output_audio_channels, audio_frames); - int const gets_per_frame = _film->three_d() ? 2 : 1; - for (DCPTime time; time < _film->length(); time += video_frame) { - - if (file_encoders.size() > 1 && !reel->contains(time)) { - /* Next reel and file */ - ++reel; - ++encoder; - DCPOMATIC_ASSERT (reel != reel_periods.end()); - DCPOMATIC_ASSERT (encoder != file_encoders.end()); - } - - for (int j = 0; j < gets_per_frame; ++j) { - Butler::Error e; - auto video = _butler.get_video(Butler::Behaviour::BLOCKING, &e); - _butler.rethrow(); - if (video.first) { - auto fe = encoder->get(video.first->eyes()); - if (fe) { - fe->video(video.first, video.second - reel->from); - } - } else { - if (e.code != Butler::Error::Code::FINISHED) { - throw DecodeError(String::compose("Error during decoding: %1", e.summary())); - } - } - } - - _history.event (); - - { - boost::mutex::scoped_lock lm (_mutex); - _last_time = time; - } - - auto job = _job.lock (); - if (job) { - job->set_progress(float(time.get()) / _film->length().get()); - } - - waker.nudge (); - - _butler.get_audio(Butler::Behaviour::BLOCKING, interleaved.data(), audio_frames); - /* XXX: inefficient; butler interleaves and we deinterleave again */ - float* p = interleaved.data(); - for (int j = 0; j < audio_frames; ++j) { - for (int k = 0; k < _output_audio_channels; ++k) { - deinterleaved->data(k)[j] = *p++; - } - } - encoder->audio (deinterleaved); - } - - for (auto i: file_encoders) { - i.flush (); - } -} - -optional -FFmpegEncoder::current_rate () const -{ - return _history.rate (); -} - -Frame -FFmpegEncoder::frames_done () const -{ - boost::mutex::scoped_lock lm (_mutex); - return _last_time.frames_round (_film->video_frame_rate ()); -} - -FFmpegEncoder::FileEncoderSet::FileEncoderSet ( - dcp::Size video_frame_size, - int video_frame_rate, - int audio_frame_rate, - int channels, - ExportFormat format, - bool audio_stream_per_channel, - int x264_crf, - bool three_d, - boost::filesystem::path output, - string extension - ) -{ - if (three_d) { - _encoders[Eyes::LEFT] = make_shared( - video_frame_size, video_frame_rate, audio_frame_rate, channels, format, - // TRANSLATORS: L here is an abbreviation for "left", to indicate the left-eye part of a 3D export - audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension) - ); - _encoders[Eyes::RIGHT] = make_shared( - video_frame_size, video_frame_rate, audio_frame_rate, channels, format, - // TRANSLATORS: R here is an abbreviation for "right", to indicate the right-eye part of a 3D export - audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension) - ); - } else { - _encoders[Eyes::BOTH] = make_shared( - video_frame_size, video_frame_rate, audio_frame_rate, channels, format, - audio_stream_per_channel, x264_crf, String::compose("%1%2", output.string(), extension) - ); - } -} - -shared_ptr -FFmpegEncoder::FileEncoderSet::get (Eyes eyes) const -{ - if (_encoders.size() == 1) { - /* We are doing a 2D export... */ - if (eyes == Eyes::LEFT) { - /* ...but we got some 3D data; put the left eye into the output... */ - eyes = Eyes::BOTH; - } else if (eyes == Eyes::RIGHT) { - /* ...and ignore the right eye.*/ - return {}; - } - } - - auto i = _encoders.find (eyes); - DCPOMATIC_ASSERT (i != _encoders.end()); - return i->second; -} - -void -FFmpegEncoder::FileEncoderSet::flush () -{ - for (auto& i: _encoders) { - i.second->flush (); - } -} - -void -FFmpegEncoder::FileEncoderSet::audio (shared_ptr a) -{ - for (auto& i: _encoders) { - i.second->audio (a); - } -} diff --git a/src/lib/ffmpeg_encoder.h b/src/lib/ffmpeg_encoder.h deleted file mode 100644 index 2d5c6af87..000000000 --- a/src/lib/ffmpeg_encoder.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - Copyright (C) 2017-2018 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - -#ifndef DCPOMATIC_FFMPEG_ENCODER_H -#define DCPOMATIC_FFMPEG_ENCODER_H - -#include "audio_mapping.h" -#include "butler.h" -#include "encoder.h" -#include "event_history.h" -#include "ffmpeg_file_encoder.h" - - -class FFmpegEncoder : public Encoder -{ -public: - FFmpegEncoder ( - std::shared_ptr film, - std::weak_ptr job, - boost::filesystem::path output, - ExportFormat format, - bool mixdown_to_stereo, - bool split_reels, - bool audio_stream_per_channel, - int x264_crf - ); - - void go () override; - - boost::optional current_rate () const override; - Frame frames_done () const override; - bool finishing () const override { - return false; - } - -private: - - class FileEncoderSet - { - public: - FileEncoderSet ( - dcp::Size video_frame_size, - int video_frame_rate, - int audio_frame_rate, - int channels, - ExportFormat, - bool audio_stream_per_channel, - int x264_crf, - bool three_d, - boost::filesystem::path output, - std::string extension - ); - - std::shared_ptr get (Eyes eyes) const; - void flush (); - void audio (std::shared_ptr); - - private: - std::map> _encoders; - }; - - AudioMapping stereo_map() const; - AudioMapping many_channel_map() const; - - int _output_audio_channels; - - mutable boost::mutex _mutex; - dcpomatic::DCPTime _last_time; - - EventHistory _history; - - boost::filesystem::path _output; - ExportFormat _format; - bool _split_reels; - bool _audio_stream_per_channel; - int _x264_crf; - - Butler _butler; -}; - -#endif diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc index d7833265d..4547a8e8e 100644 --- a/src/lib/ffmpeg_file_encoder.cc +++ b/src/lib/ffmpeg_file_encoder.cc @@ -21,7 +21,7 @@ #include "compose.hpp" #include "cross.h" -#include "ffmpeg_encoder.h" +#include "ffmpeg_file_encoder.h" #include "ffmpeg_wrapper.h" #include "film.h" #include "image.h" diff --git a/src/lib/ffmpeg_file_encoder.h b/src/lib/ffmpeg_file_encoder.h index 78840d6a8..907eca53d 100644 --- a/src/lib/ffmpeg_file_encoder.h +++ b/src/lib/ffmpeg_file_encoder.h @@ -23,12 +23,14 @@ #define DCPOMATIC_FFMPEG_FILE_ENCODER_H +#include "audio_buffers.h" #include "audio_mapping.h" #include "dcpomatic_time.h" -#include "encoder.h" #include "event_history.h" #include "image_store.h" #include "log.h" +#include "player_text.h" +#include "player_video.h" #include #include LIBDCP_DISABLE_WARNINGS diff --git a/src/lib/ffmpeg_film_encoder.cc b/src/lib/ffmpeg_film_encoder.cc new file mode 100644 index 000000000..2d100f7bc --- /dev/null +++ b/src/lib/ffmpeg_film_encoder.cc @@ -0,0 +1,315 @@ +/* + Copyright (C) 2017-2018 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "butler.h" +#include "cross.h" +#include "ffmpeg_film_encoder.h" +#include "film.h" +#include "image.h" +#include "job.h" +#include "log.h" +#include "player.h" +#include "player_video.h" +#include "compose.hpp" +#include + +#include "i18n.h" + + +using std::cout; +using std::list; +using std::make_shared; +using std::shared_ptr; +using std::string; +using std::weak_ptr; +using boost::bind; +using boost::optional; +using namespace dcpomatic; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif + + +FFmpegFilmEncoder::FFmpegFilmEncoder( + shared_ptr film, + weak_ptr job, + boost::filesystem::path output, + ExportFormat format, + bool mixdown_to_stereo, + bool split_reels, + bool audio_stream_per_channel, + int x264_crf + ) + : FilmEncoder(film, job) + , _output_audio_channels(mixdown_to_stereo ? 2 : (_film->audio_channels() > 8 ? 16 : _film->audio_channels())) + , _history (200) + , _output (output) + , _format (format) + , _split_reels (split_reels) + , _audio_stream_per_channel (audio_stream_per_channel) + , _x264_crf (x264_crf) + , _butler( + _film, + _player, + mixdown_to_stereo ? stereo_map() : many_channel_map(), + _output_audio_channels, + boost::bind(&PlayerVideo::force, FFmpegFileEncoder::pixel_format(format)), + VideoRange::VIDEO, + Image::Alignment::PADDED, + false, + false, + Butler::Audio::ENABLED + ) +{ + _player.set_always_burn_open_subtitles(); + _player.set_play_referenced(); +} + + +AudioMapping +FFmpegFilmEncoder::stereo_map() const +{ + auto map = AudioMapping(_film->audio_channels(), 2); + float const overall_gain = 2 / (4 + sqrt(2)); + float const minus_3dB = 1 / sqrt(2); + switch (_film->audio_channels()) { + case 2: + map.set(dcp::Channel::LEFT, 0, 1); + map.set(dcp::Channel::RIGHT, 1, 1); + break; + case 4: + map.set(dcp::Channel::LEFT, 0, overall_gain); + map.set(dcp::Channel::RIGHT, 1, overall_gain); + map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); + map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); + map.set(dcp::Channel::LS, 0, overall_gain); + break; + case 6: + map.set(dcp::Channel::LEFT, 0, overall_gain); + map.set(dcp::Channel::RIGHT, 1, overall_gain); + map.set(dcp::Channel::CENTRE, 0, overall_gain * minus_3dB); + map.set(dcp::Channel::CENTRE, 1, overall_gain * minus_3dB); + map.set(dcp::Channel::LS, 0, overall_gain); + map.set(dcp::Channel::RS, 1, overall_gain); + break; + } + /* XXX: maybe we should do something better for >6 channel DCPs */ + return map; +} + + +AudioMapping +FFmpegFilmEncoder::many_channel_map() const +{ + auto map = AudioMapping(_film->audio_channels(), _output_audio_channels); + for (int i = 0; i < _film->audio_channels(); ++i) { + map.set(i, i, 1); + } + return map; +} + + +void +FFmpegFilmEncoder::go() +{ + { + auto job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->sub (_("Encoding")); + } + + Waker waker; + + list file_encoders; + + int const files = _split_reels ? _film->reels().size() : 1; + for (int i = 0; i < files; ++i) { + + boost::filesystem::path filename = _output; + auto extension = dcp::filesystem::extension(filename); + filename = dcp::filesystem::change_extension(filename, ""); + + if (files > 1) { + /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate + /// which reel it is. Preserve the %1; it will be replaced with the reel number. + filename = filename.string() + String::compose(_("_reel%1"), i + 1); + } + + file_encoders.push_back ( + FileEncoderSet ( + _film->frame_size(), + _film->video_frame_rate(), + _film->audio_frame_rate(), + _output_audio_channels, + _format, + _audio_stream_per_channel, + _x264_crf, + _film->three_d(), + filename, + extension + ) + ); + } + + auto reel_periods = _film->reels (); + auto reel = reel_periods.begin (); + auto encoder = file_encoders.begin (); + + auto const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ()); + int const audio_frames = video_frame.frames_round(_film->audio_frame_rate()); + std::vector interleaved(_output_audio_channels * audio_frames); + auto deinterleaved = make_shared(_output_audio_channels, audio_frames); + int const gets_per_frame = _film->three_d() ? 2 : 1; + for (DCPTime time; time < _film->length(); time += video_frame) { + + if (file_encoders.size() > 1 && !reel->contains(time)) { + /* Next reel and file */ + ++reel; + ++encoder; + DCPOMATIC_ASSERT (reel != reel_periods.end()); + DCPOMATIC_ASSERT (encoder != file_encoders.end()); + } + + for (int j = 0; j < gets_per_frame; ++j) { + Butler::Error e; + auto video = _butler.get_video(Butler::Behaviour::BLOCKING, &e); + _butler.rethrow(); + if (video.first) { + auto fe = encoder->get(video.first->eyes()); + if (fe) { + fe->video(video.first, video.second - reel->from); + } + } else { + if (e.code != Butler::Error::Code::FINISHED) { + throw DecodeError(String::compose("Error during decoding: %1", e.summary())); + } + } + } + + _history.event (); + + { + boost::mutex::scoped_lock lm (_mutex); + _last_time = time; + } + + auto job = _job.lock (); + if (job) { + job->set_progress(float(time.get()) / _film->length().get()); + } + + waker.nudge (); + + _butler.get_audio(Butler::Behaviour::BLOCKING, interleaved.data(), audio_frames); + /* XXX: inefficient; butler interleaves and we deinterleave again */ + float* p = interleaved.data(); + for (int j = 0; j < audio_frames; ++j) { + for (int k = 0; k < _output_audio_channels; ++k) { + deinterleaved->data(k)[j] = *p++; + } + } + encoder->audio (deinterleaved); + } + + for (auto i: file_encoders) { + i.flush (); + } +} + +optional +FFmpegFilmEncoder::current_rate() const +{ + return _history.rate (); +} + +Frame +FFmpegFilmEncoder::frames_done() const +{ + boost::mutex::scoped_lock lm (_mutex); + return _last_time.frames_round (_film->video_frame_rate ()); +} + +FFmpegFilmEncoder::FileEncoderSet::FileEncoderSet( + dcp::Size video_frame_size, + int video_frame_rate, + int audio_frame_rate, + int channels, + ExportFormat format, + bool audio_stream_per_channel, + int x264_crf, + bool three_d, + boost::filesystem::path output, + string extension + ) +{ + if (three_d) { + _encoders[Eyes::LEFT] = make_shared( + video_frame_size, video_frame_rate, audio_frame_rate, channels, format, + // TRANSLATORS: L here is an abbreviation for "left", to indicate the left-eye part of a 3D export + audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension) + ); + _encoders[Eyes::RIGHT] = make_shared( + video_frame_size, video_frame_rate, audio_frame_rate, channels, format, + // TRANSLATORS: R here is an abbreviation for "right", to indicate the right-eye part of a 3D export + audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension) + ); + } else { + _encoders[Eyes::BOTH] = make_shared( + video_frame_size, video_frame_rate, audio_frame_rate, channels, format, + audio_stream_per_channel, x264_crf, String::compose("%1%2", output.string(), extension) + ); + } +} + +shared_ptr +FFmpegFilmEncoder::FileEncoderSet::get(Eyes eyes) const +{ + if (_encoders.size() == 1) { + /* We are doing a 2D export... */ + if (eyes == Eyes::LEFT) { + /* ...but we got some 3D data; put the left eye into the output... */ + eyes = Eyes::BOTH; + } else if (eyes == Eyes::RIGHT) { + /* ...and ignore the right eye.*/ + return {}; + } + } + + auto i = _encoders.find (eyes); + DCPOMATIC_ASSERT (i != _encoders.end()); + return i->second; +} + +void +FFmpegFilmEncoder::FileEncoderSet::flush() +{ + for (auto& i: _encoders) { + i.second->flush (); + } +} + +void +FFmpegFilmEncoder::FileEncoderSet::audio(shared_ptr a) +{ + for (auto& i: _encoders) { + i.second->audio (a); + } +} diff --git a/src/lib/ffmpeg_film_encoder.h b/src/lib/ffmpeg_film_encoder.h new file mode 100644 index 000000000..ec6bb4594 --- /dev/null +++ b/src/lib/ffmpeg_film_encoder.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2017-2018 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + +#ifndef DCPOMATIC_FFMPEG_ENCODER_H +#define DCPOMATIC_FFMPEG_ENCODER_H + +#include "audio_mapping.h" +#include "butler.h" +#include "event_history.h" +#include "ffmpeg_file_encoder.h" +#include "film_encoder.h" + + +class FFmpegFilmEncoder : public FilmEncoder +{ +public: + FFmpegFilmEncoder( + std::shared_ptr film, + std::weak_ptr job, + boost::filesystem::path output, + ExportFormat format, + bool mixdown_to_stereo, + bool split_reels, + bool audio_stream_per_channel, + int x264_crf + ); + + void go () override; + + boost::optional current_rate () const override; + Frame frames_done () const override; + bool finishing () const override { + return false; + } + +private: + + class FileEncoderSet + { + public: + FileEncoderSet ( + dcp::Size video_frame_size, + int video_frame_rate, + int audio_frame_rate, + int channels, + ExportFormat, + bool audio_stream_per_channel, + int x264_crf, + bool three_d, + boost::filesystem::path output, + std::string extension + ); + + std::shared_ptr get (Eyes eyes) const; + void flush (); + void audio (std::shared_ptr); + + private: + std::map> _encoders; + }; + + AudioMapping stereo_map() const; + AudioMapping many_channel_map() const; + + int _output_audio_channels; + + mutable boost::mutex _mutex; + dcpomatic::DCPTime _last_time; + + EventHistory _history; + + boost::filesystem::path _output; + ExportFormat _format; + bool _split_reels; + bool _audio_stream_per_channel; + int _x264_crf; + + Butler _butler; +}; + +#endif diff --git a/src/lib/film.cc b/src/lib/film.cc index 540d0b9b9..fd703a72a 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -36,7 +36,7 @@ #include "cross.h" #include "dcp_content.h" #include "dcp_content_type.h" -#include "dcp_encoder.h" +#include "dcp_film_encoder.h" #include "dcpomatic_log.h" #include "digester.h" #include "environment_info.h" diff --git a/src/lib/film_encoder.cc b/src/lib/film_encoder.cc new file mode 100644 index 000000000..05b911daf --- /dev/null +++ b/src/lib/film_encoder.cc @@ -0,0 +1,47 @@ +/* + Copyright (C) 2012-2017 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +/** @file src/film_encoder.cc + * @brief A class which takes a Film and some Options, then uses those to encode the film + * into some output format. + * + * A decoder is selected according to the content type, and the encoder can be specified + * as a parameter to the constructor. + */ + + +#include "film_encoder.h" +#include "player.h" + +#include "i18n.h" + + +/** Construct a FilmEncoder. + * @param film Film that we are encoding. + * @param job Job that this encoder is being used in. + */ +FilmEncoder::FilmEncoder(std::shared_ptr film, std::weak_ptr job) + : _film (film) + , _job (job) + , _player(film, Image::Alignment::PADDED) +{ + +} diff --git a/src/lib/film_encoder.h b/src/lib/film_encoder.h new file mode 100644 index 000000000..ed7626c68 --- /dev/null +++ b/src/lib/film_encoder.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2012-2021 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#ifndef DCPOMATIC_FILM_ENCODER_H +#define DCPOMATIC_FILM_ENCODER_H + + +#include "player.h" +#include "player_text.h" +#include + + +class Film; +class Player; +class Job; +class PlayerVideo; +class AudioBuffers; + + +/** @class FilmEncoder + * @brief Parent class for something that can encode a film into some format + */ +class FilmEncoder +{ +public: + FilmEncoder(std::shared_ptr film, std::weak_ptr job); + virtual ~FilmEncoder() {} + + FilmEncoder(FilmEncoder const&) = delete; + FilmEncoder& operator=(FilmEncoder const&) = delete; + + virtual void go () = 0; + + /** @return the current frame rate over the last short while */ + virtual boost::optional current_rate () const { + return {}; + } + + /** @return the number of frames that are done */ + virtual Frame frames_done () const = 0; + virtual bool finishing () const = 0; + virtual void pause() {} + virtual void resume() {} + +protected: + std::shared_ptr _film; + std::weak_ptr _job; + Player _player; +}; + + +#endif diff --git a/src/lib/hints.h b/src/lib/hints.h index 0d65edc21..e7a6646ef 100644 --- a/src/lib/hints.h +++ b/src/lib/hints.h @@ -20,15 +20,16 @@ #include "audio_analyser.h" -#include "signaller.h" -#include "player_text.h" #include "dcp_text_track.h" #include "dcpomatic_time.h" +#include "player_text.h" +#include "signaller.h" +#include "text_type.h" #include "weak_film.h" -#include #include -#include +#include #include +#include class Film; diff --git a/src/lib/make_dcp.cc b/src/lib/make_dcp.cc index ddd231243..41c5e8ec5 100644 --- a/src/lib/make_dcp.cc +++ b/src/lib/make_dcp.cc @@ -21,7 +21,7 @@ #include "config.h" #include "dcp_content.h" -#include "dcp_encoder.h" +#include "dcp_film_encoder.h" #include "dcp_transcode_job.h" #include "dcpomatic_log.h" #include "environment_info.h" @@ -94,7 +94,7 @@ make_dcp (shared_ptr film, TranscodeJob::ChangedBehaviour behaviour) LOG_GENERAL ("J2K bandwidth %1", film->j2k_bandwidth()); auto tj = make_shared(film, behaviour); - tj->set_encoder (make_shared(film, tj)); + tj->set_encoder(make_shared(film, tj)); JobManager::instance()->add (tj); return tj; diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index 0886482a8..6f47c6740 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -27,6 +27,7 @@ #include "player_text.h" #include "referenced_reel_asset.h" #include "render_text.h" +#include "text_type.h" #include "weak_film.h" #include #include diff --git a/src/lib/subtitle_encoder.cc b/src/lib/subtitle_encoder.cc deleted file mode 100644 index 8b1d9a15b..000000000 --- a/src/lib/subtitle_encoder.cc +++ /dev/null @@ -1,204 +0,0 @@ -/* - Copyright (C) 2019-2021 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -#include "compose.hpp" -#include "film.h" -#include "job.h" -#include "player.h" -#include "subtitle_encoder.h" -#include -#include -#include -#include -#include -#include - -#include "i18n.h" - - -using std::make_pair; -using std::make_shared; -using std::pair; -using std::shared_ptr; -using std::string; -using std::vector; -using boost::optional; -#if BOOST_VERSION >= 106100 -using namespace boost::placeholders; -#endif -using dcp::raw_convert; - - -/** @param output Directory, if there will be multiple output files, or a filename. - * @param initial_name Hint that may be used to create filenames, if @ref output is a directory. - * @param include_font true to refer to and export any font file (for Interop; ignored for SMPTE). - */ -SubtitleEncoder::SubtitleEncoder (shared_ptr film, shared_ptr job, boost::filesystem::path output, string initial_name, bool split_reels, bool include_font) - : Encoder (film, job) - , _split_reels (split_reels) - , _include_font (include_font) - , _reel_index (0) - , _length (film->length()) -{ - _player.set_play_referenced(); - _player.set_ignore_video(); - _player.set_ignore_audio(); - _player.Text.connect(boost::bind(&SubtitleEncoder::text, this, _1, _2, _3, _4)); - - string const extension = film->interop() ? ".xml" : ".mxf"; - - int const files = split_reels ? film->reels().size() : 1; - for (int i = 0; i < files; ++i) { - - boost::filesystem::path filename = output; - if (dcp::filesystem::is_directory(filename)) { - if (files > 1) { - /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate - /// which reel it is. Preserve the %1; it will be replaced with the reel number. - filename /= String::compose("%1_reel%2", initial_name, i + 1); - } else { - filename /= initial_name; - } - } - - _assets.push_back(make_pair(shared_ptr(), dcp::filesystem::change_extension(filename, extension))); - } - - for (auto i: film->reels()) { - _reels.push_back (i); - } - - _default_font = dcp::ArrayData (default_font_file()); -} - - -void -SubtitleEncoder::go () -{ - { - shared_ptr job = _job.lock (); - DCPOMATIC_ASSERT (job); - job->sub (_("Extracting")); - } - - _reel_index = 0; - - while (!_player.pass()) {} - - int reel = 0; - for (auto& i: _assets) { - if (!i.first) { - /* No subtitles arrived for this asset; make an empty one so we write something to the output */ - if (_film->interop()) { - auto s = make_shared(); - s->set_movie_title (_film->name()); - s->set_reel_number (raw_convert(reel + 1)); - i.first = s; - } else { - auto s = make_shared(); - s->set_content_title_text (_film->name()); - s->set_reel_number (reel + 1); - i.first = s; - } - } - - if (!_film->interop() || _include_font) { - for (auto j: _player.get_subtitle_fonts()) { - i.first->add_font(j->id(), j->data().get_value_or(_default_font)); - } - } - - i.first->write (i.second); - ++reel; - } -} - - -void -SubtitleEncoder::text (PlayerText subs, TextType type, optional track, dcpomatic::DCPTimePeriod period) -{ - if (type != TextType::OPEN_SUBTITLE) { - return; - } - - if (!_assets[_reel_index].first) { - shared_ptr asset; - auto lang = _film->subtitle_languages (); - if (_film->interop ()) { - auto s = make_shared(); - s->set_movie_title (_film->name()); - if (lang.first) { - s->set_language (lang.first->to_string()); - } - s->set_reel_number (raw_convert(_reel_index + 1)); - _assets[_reel_index].first = s; - } else { - auto s = make_shared(); - s->set_content_title_text (_film->name()); - if (lang.first) { - s->set_language (*lang.first); - } else if (track->language) { - s->set_language (track->language.get()); - } - s->set_edit_rate (dcp::Fraction (_film->video_frame_rate(), 1)); - s->set_reel_number (_reel_index + 1); - s->set_time_code_rate (_film->video_frame_rate()); - s->set_start_time (dcp::Time()); - if (_film->encrypted ()) { - s->set_key (_film->key ()); - } - _assets[_reel_index].first = s; - } - } - - for (auto i: subs.string) { - /* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */ - i.set_in (i.in()); - i.set_out (i.out()); - if (_film->interop() && !_include_font) { - i.unset_font (); - } - _assets[_reel_index].first->add (make_shared(i)); - } - - if (_split_reels && (_reel_index < int(_reels.size()) - 1) && period.from > _reels[_reel_index].from) { - ++_reel_index; - } - - _last = period.from; - - auto job = _job.lock (); - if (job) { - job->set_progress (float(period.from.get()) / _length.get()); - } -} - - -Frame -SubtitleEncoder::frames_done () const -{ - if (!_last) { - return 0; - } - - /* XXX: assuming 24fps here but I don't think it matters */ - return _last->seconds() * 24; -} diff --git a/src/lib/subtitle_encoder.h b/src/lib/subtitle_encoder.h deleted file mode 100644 index 0815b1fff..000000000 --- a/src/lib/subtitle_encoder.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2019-2021 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -#include "dcp_text_track.h" -#include "dcpomatic_time.h" -#include "encoder.h" -#include "player_text.h" - - -namespace dcp { - class SubtitleAsset; -} - - -class Film; - - -/** @class SubtitleEncoder. - * @brief An `encoder' which extracts a film's subtitles to DCP XML format. - */ -class SubtitleEncoder : public Encoder -{ -public: - SubtitleEncoder (std::shared_ptr film, std::shared_ptr job, boost::filesystem::path output, std::string initial_name, bool split_reels, bool include_font); - - void go () override; - - /** @return the number of frames that are done */ - Frame frames_done () const override; - - bool finishing () const override { - return false; - } - -private: - void text (PlayerText subs, TextType type, boost::optional track, dcpomatic::DCPTimePeriod period); - - std::vector, boost::filesystem::path>> _assets; - std::vector _reels; - bool _split_reels; - bool _include_font; - int _reel_index; - boost::optional _last; - dcpomatic::DCPTime _length; - dcp::ArrayData _default_font; -}; diff --git a/src/lib/subtitle_film_encoder.cc b/src/lib/subtitle_film_encoder.cc new file mode 100644 index 000000000..93ccc177b --- /dev/null +++ b/src/lib/subtitle_film_encoder.cc @@ -0,0 +1,204 @@ +/* + Copyright (C) 2019-2021 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "compose.hpp" +#include "film.h" +#include "job.h" +#include "player.h" +#include "subtitle_film_encoder.h" +#include +#include +#include +#include +#include +#include + +#include "i18n.h" + + +using std::make_pair; +using std::make_shared; +using std::pair; +using std::shared_ptr; +using std::string; +using std::vector; +using boost::optional; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif +using dcp::raw_convert; + + +/** @param output Directory, if there will be multiple output files, or a filename. + * @param initial_name Hint that may be used to create filenames, if @ref output is a directory. + * @param include_font true to refer to and export any font file (for Interop; ignored for SMPTE). + */ +SubtitleFilmEncoder::SubtitleFilmEncoder(shared_ptr film, shared_ptr job, boost::filesystem::path output, string initial_name, bool split_reels, bool include_font) + : FilmEncoder(film, job) + , _split_reels (split_reels) + , _include_font (include_font) + , _reel_index (0) + , _length (film->length()) +{ + _player.set_play_referenced(); + _player.set_ignore_video(); + _player.set_ignore_audio(); + _player.Text.connect(boost::bind(&SubtitleFilmEncoder::text, this, _1, _2, _3, _4)); + + string const extension = film->interop() ? ".xml" : ".mxf"; + + int const files = split_reels ? film->reels().size() : 1; + for (int i = 0; i < files; ++i) { + + boost::filesystem::path filename = output; + if (dcp::filesystem::is_directory(filename)) { + if (files > 1) { + /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate + /// which reel it is. Preserve the %1; it will be replaced with the reel number. + filename /= String::compose("%1_reel%2", initial_name, i + 1); + } else { + filename /= initial_name; + } + } + + _assets.push_back(make_pair(shared_ptr(), dcp::filesystem::change_extension(filename, extension))); + } + + for (auto i: film->reels()) { + _reels.push_back (i); + } + + _default_font = dcp::ArrayData (default_font_file()); +} + + +void +SubtitleFilmEncoder::go() +{ + { + shared_ptr job = _job.lock (); + DCPOMATIC_ASSERT (job); + job->sub (_("Extracting")); + } + + _reel_index = 0; + + while (!_player.pass()) {} + + int reel = 0; + for (auto& i: _assets) { + if (!i.first) { + /* No subtitles arrived for this asset; make an empty one so we write something to the output */ + if (_film->interop()) { + auto s = make_shared(); + s->set_movie_title (_film->name()); + s->set_reel_number (raw_convert(reel + 1)); + i.first = s; + } else { + auto s = make_shared(); + s->set_content_title_text (_film->name()); + s->set_reel_number (reel + 1); + i.first = s; + } + } + + if (!_film->interop() || _include_font) { + for (auto j: _player.get_subtitle_fonts()) { + i.first->add_font(j->id(), j->data().get_value_or(_default_font)); + } + } + + i.first->write (i.second); + ++reel; + } +} + + +void +SubtitleFilmEncoder::text(PlayerText subs, TextType type, optional track, dcpomatic::DCPTimePeriod period) +{ + if (type != TextType::OPEN_SUBTITLE) { + return; + } + + if (!_assets[_reel_index].first) { + shared_ptr asset; + auto lang = _film->subtitle_languages (); + if (_film->interop ()) { + auto s = make_shared(); + s->set_movie_title (_film->name()); + if (lang.first) { + s->set_language (lang.first->to_string()); + } + s->set_reel_number (raw_convert(_reel_index + 1)); + _assets[_reel_index].first = s; + } else { + auto s = make_shared(); + s->set_content_title_text (_film->name()); + if (lang.first) { + s->set_language (*lang.first); + } else if (track->language) { + s->set_language (track->language.get()); + } + s->set_edit_rate (dcp::Fraction (_film->video_frame_rate(), 1)); + s->set_reel_number (_reel_index + 1); + s->set_time_code_rate (_film->video_frame_rate()); + s->set_start_time (dcp::Time()); + if (_film->encrypted ()) { + s->set_key (_film->key ()); + } + _assets[_reel_index].first = s; + } + } + + for (auto i: subs.string) { + /* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */ + i.set_in (i.in()); + i.set_out (i.out()); + if (_film->interop() && !_include_font) { + i.unset_font (); + } + _assets[_reel_index].first->add (make_shared(i)); + } + + if (_split_reels && (_reel_index < int(_reels.size()) - 1) && period.from > _reels[_reel_index].from) { + ++_reel_index; + } + + _last = period.from; + + auto job = _job.lock (); + if (job) { + job->set_progress (float(period.from.get()) / _length.get()); + } +} + + +Frame +SubtitleFilmEncoder::frames_done() const +{ + if (!_last) { + return 0; + } + + /* XXX: assuming 24fps here but I don't think it matters */ + return _last->seconds() * 24; +} diff --git a/src/lib/subtitle_film_encoder.h b/src/lib/subtitle_film_encoder.h new file mode 100644 index 000000000..54231794d --- /dev/null +++ b/src/lib/subtitle_film_encoder.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2019-2021 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "dcp_text_track.h" +#include "dcpomatic_time.h" +#include "film_encoder.h" +#include "player_text.h" + + +namespace dcp { + class SubtitleAsset; +} + + +class Film; + + +/** @class SubtitleFilmEncoder. + * @brief An `encoder' which extracts a film's subtitles to DCP XML format. + */ +class SubtitleFilmEncoder : public FilmEncoder +{ +public: + SubtitleFilmEncoder(std::shared_ptr film, std::shared_ptr job, boost::filesystem::path output, std::string initial_name, bool split_reels, bool include_font); + + void go () override; + + /** @return the number of frames that are done */ + Frame frames_done () const override; + + bool finishing () const override { + return false; + } + +private: + void text (PlayerText subs, TextType type, boost::optional track, dcpomatic::DCPTimePeriod period); + + std::vector, boost::filesystem::path>> _assets; + std::vector _reels; + bool _split_reels; + bool _include_font; + int _reel_index; + boost::optional _last; + dcpomatic::DCPTime _length; + dcp::ArrayData _default_font; +}; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index ba420ab94..98c6784a9 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -28,11 +28,11 @@ #include "compose.hpp" #include "content.h" #include "config.h" -#include "dcp_encoder.h" +#include "dcp_film_encoder.h" #include "dcpomatic_log.h" -#include "encoder.h" #include "examine_content_job.h" #include "film.h" +#include "film_encoder.h" #include "job_manager.h" #include "log.h" #include "transcode_job.h" @@ -84,7 +84,7 @@ TranscodeJob::json_name () const void -TranscodeJob::set_encoder (shared_ptr e) +TranscodeJob::set_encoder(shared_ptr e) { _encoder = e; } @@ -133,7 +133,7 @@ TranscodeJob::run () LOG_GENERAL(N_("Transcode job completed successfully: %1 fps"), dcp::locale_convert(frames_per_second(), 2, true)); - if (dynamic_pointer_cast(_encoder)) { + if (dynamic_pointer_cast(_encoder)) { try { Analytics::instance()->successful_dcp_encode(); } catch (FileError& e) { diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index 35870231d..720d7f99b 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -35,7 +35,7 @@ #undef IGNORE -class Encoder; +class FilmEncoder; struct frames_not_lost_when_threads_disappear; @@ -65,7 +65,7 @@ public: return true; } - void set_encoder (std::shared_ptr t); + void set_encoder(std::shared_ptr encoder); private: friend struct ::frames_not_lost_when_threads_disappear; @@ -75,7 +75,7 @@ private: int remaining_time () const override; - std::shared_ptr _encoder; + std::shared_ptr _encoder; ChangedBehaviour _changed; }; diff --git a/src/lib/wscript b/src/lib/wscript index 4eeeb578e..5e49b1fbf 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -68,9 +68,9 @@ sources = """ dcp_content.cc dcp_content_type.cc dcp_decoder.cc - dcp_encoder.cc dcp_examiner.cc dcp_digest_file.cc + dcp_film_encoder.cc dcp_subtitle.cc dcp_subtitle_content.cc dcp_subtitle_decoder.cc @@ -89,7 +89,6 @@ sources = """ dolby_cp750.cc email.cc empty.cc - encoder.cc encode_server.cc encode_server_finder.cc encoded_log_entry.cc @@ -107,14 +106,15 @@ sources = """ ffmpeg_audio_stream.cc ffmpeg_content.cc ffmpeg_decoder.cc - ffmpeg_encoder.cc ffmpeg_examiner.cc ffmpeg_file_encoder.cc + ffmpeg_film_encoder.cc ffmpeg_image_proxy.cc ffmpeg_stream.cc ffmpeg_subtitle_stream.cc ffmpeg_wrapper.cc film.cc + film_encoder.cc film_util.cc filter.cc font.cc @@ -187,7 +187,7 @@ sources = """ string_text_file_content.cc string_text_file_decoder.cc subtitle_analysis.cc - subtitle_encoder.cc + subtitle_film_encoder.cc territory_type.cc text_ring_buffers.cc text_type.cc diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 5f723ba0f..de4ddebc2 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -76,7 +76,7 @@ #include "lib/email.h" #include "lib/encode_server_finder.h" #include "lib/exceptions.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/film.h" #include "lib/font_config.h" #ifdef DCPOMATIC_GROK @@ -91,7 +91,7 @@ #include "lib/screen.h" #include "lib/send_kdm_email_job.h" #include "lib/signal_manager.h" -#include "lib/subtitle_encoder.h" +#include "lib/subtitle_film_encoder.h" #include "lib/text_content.h" #include "lib/transcode_job.h" #include "lib/update_checker.h" @@ -1029,7 +1029,7 @@ private: auto job = make_shared(_film, TranscodeJob::ChangedBehaviour::EXAMINE_THEN_STOP); job->set_encoder ( - make_shared ( + make_shared( _film, job, dialog.path(), dialog.format(), dialog.mixdown_to_stereo(), dialog.split_reels(), dialog.split_streams(), dialog.x264_crf()) ); JobManager::instance()->add (job); @@ -1044,7 +1044,7 @@ private: } auto job = make_shared(_film, TranscodeJob::ChangedBehaviour::EXAMINE_THEN_STOP); job->set_encoder( - make_shared(_film, job, dialog.path(), _film->isdcf_name(true), dialog.split_reels(), dialog.include_font()) + make_shared(_film, job, dialog.path(), _film->isdcf_name(true), dialog.split_reels(), dialog.include_font()) ); JobManager::instance()->add(job); } diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index c087f89e7..9eec498f9 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -25,7 +25,7 @@ #include "lib/cross.h" #include "lib/dcpomatic_log.h" #include "lib/encode_server_finder.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/film.h" #include "lib/filter.h" #ifdef DCPOMATIC_GROK @@ -519,7 +519,7 @@ main (int argc, char* argv[]) if (export_format) { auto job = std::make_shared(film, behaviour); job->set_encoder ( - std::make_shared ( + std::make_shared( film, job, *export_filename, *export_format == "mp4" ? ExportFormat::H264_AAC : ExportFormat::PRORES_HQ, false, false, false, 23 ) ); diff --git a/src/tools/dcpomatic_combiner.cc b/src/tools/dcpomatic_combiner.cc index 6588b23b4..a28e063e5 100644 --- a/src/tools/dcpomatic_combiner.cc +++ b/src/tools/dcpomatic_combiner.cc @@ -30,6 +30,7 @@ #include "lib/constants.h" #include "lib/cross.h" #include "lib/job_manager.h" +#include "lib/util.h" #include LIBDCP_DISABLE_WARNINGS #include diff --git a/src/tools/dcpomatic_editor.cc b/src/tools/dcpomatic_editor.cc index e1f541fe8..fc04ce017 100644 --- a/src/tools/dcpomatic_editor.cc +++ b/src/tools/dcpomatic_editor.cc @@ -29,6 +29,7 @@ #include "lib/cross.h" #include "lib/dcpomatic_log.h" #include "lib/null_log.h" +#include "lib/util.h" #include "lib/variant.h" #include #include diff --git a/src/tools/dcpomatic_kdm.cc b/src/tools/dcpomatic_kdm.cc index d6c8b3945..1eda05162 100644 --- a/src/tools/dcpomatic_kdm.cc +++ b/src/tools/dcpomatic_kdm.cc @@ -53,6 +53,7 @@ #include "lib/kdm_with_metadata.h" #include "lib/screen.h" #include "lib/send_kdm_email_job.h" +#include "lib/util.h" #include "lib/variant.h" #include #include diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 04bb26c2e..05c3f281c 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -27,6 +27,7 @@ #include "static_text.h" #include "wx_variant.h" #include "lib/constants.h" +#include "lib/util.h" #include #include #include diff --git a/src/wx/dcp_timeline.h b/src/wx/dcp_timeline.h index 3413c2814..23644c03f 100644 --- a/src/wx/dcp_timeline.h +++ b/src/wx/dcp_timeline.h @@ -25,6 +25,8 @@ #include "timecode.h" #include "timeline.h" +#include "lib/change_signaller.h" +#include "lib/film_property.h" #include "lib/rect.h" #include LIBDCP_DISABLE_WARNINGS diff --git a/src/wx/export_video_file_dialog.h b/src/wx/export_video_file_dialog.h index beb33610b..4e626be6b 100644 --- a/src/wx/export_video_file_dialog.h +++ b/src/wx/export_video_file_dialog.h @@ -20,7 +20,7 @@ #include "table_dialog.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_file_encoder.h" #include LIBDCP_DISABLE_WARNINGS #include diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 5824f8baa..63aa113d1 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -25,8 +25,10 @@ #include "video_view.h" +#include "lib/change_signaller.h" #include "lib/config.h" #include "lib/film_property.h" +#include "lib/player.h" #include "lib/player_text.h" #include "lib/signaller.h" #include "lib/timer.h" diff --git a/src/wx/kdm_cpl_panel.cc b/src/wx/kdm_cpl_panel.cc index 4e1eb8f34..523d0c369 100644 --- a/src/wx/kdm_cpl_panel.cc +++ b/src/wx/kdm_cpl_panel.cc @@ -23,6 +23,7 @@ #include "kdm_cpl_panel.h" #include "static_text.h" #include "wx_util.h" +#include #include LIBDCP_DISABLE_WARNINGS #include diff --git a/src/wx/timeline_content_view.cc b/src/wx/timeline_content_view.cc index cb0d10240..69a675c42 100644 --- a/src/wx/timeline_content_view.cc +++ b/src/wx/timeline_content_view.cc @@ -23,6 +23,7 @@ #include "timeline_content_view.h" #include "wx_util.h" #include "lib/content.h" +#include "lib/util.h" #include LIBDCP_DISABLE_WARNINGS #include diff --git a/test/burnt_subtitle_test.cc b/test/burnt_subtitle_test.cc index 9d25287b2..ac14de2c4 100644 --- a/test/burnt_subtitle_test.cc +++ b/test/burnt_subtitle_test.cc @@ -30,7 +30,7 @@ #include "lib/dcp_content.h" #include "lib/dcp_content_type.h" #include "lib/film.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/log_entry.h" #include "lib/ratio.h" #include "lib/text_content.h" @@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(burn_empty_subtitle_test) auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); auto file = boost::filesystem::path("build") / "test" / "burnt_empty_subtitle_test.mov"; cl.add(file); - FFmpegEncoder encoder(film, job, file, ExportFormat::PRORES_4444, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, file, ExportFormat::PRORES_4444, false, false, false, 23); encoder.go(); cl.run(); diff --git a/test/ffmpeg_encoder_test.cc b/test/ffmpeg_encoder_test.cc index f0133ff66..67bc0ce1e 100644 --- a/test/ffmpeg_encoder_test.cc +++ b/test/ffmpeg_encoder_test.cc @@ -28,8 +28,8 @@ #include "lib/dcp_content.h" #include "lib/dcpomatic_log.h" #include "lib/ffmpeg_content.h" -#include "lib/ffmpeg_encoder.h" #include "lib/ffmpeg_examiner.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/film.h" #include "lib/image_content.h" #include "lib/ratio.h" @@ -84,7 +84,7 @@ ffmpeg_content_test (int number, boost::filesystem::path content, ExportFormat f auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); auto file = boost::filesystem::path("build") / "test" / String::compose("%1.%2", name, extension); cl.add (file); - FFmpegEncoder encoder (film, job, file, format, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, file, format, false, false, false, 23); encoder.go (); cl.run (); @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test5) film->write_metadata (); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test5.mov", ExportFormat::PRORES_HQ, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_prores_test5.mov", ExportFormat::PRORES_HQ, false, false, false, 23); encoder.go (); } @@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test6) film->write_metadata(); auto job = make_shared (film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test6.mov", ExportFormat::PRORES_HQ, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_prores_test6.mov", ExportFormat::PRORES_HQ, false, false, false, 23); encoder.go (); } @@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test7) s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255)); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test7.mov", ExportFormat::PRORES_HQ, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_prores_test7.mov", ExportFormat::PRORES_HQ, false, false, false, 23); encoder.go (); } @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test2) film->write_metadata(); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test2.mp4", ExportFormat::H264_AAC, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test2.mp4", ExportFormat::H264_AAC, false, false, false, 23); encoder.go (); } @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test3) film->write_metadata(); auto job = make_shared (film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test3.mp4", ExportFormat::H264_AAC, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test3.mp4", ExportFormat::H264_AAC, false, false, false, 23); encoder.go (); } @@ -251,7 +251,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test4) film->set_container(Ratio::from_id("185")); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test4.mp4", ExportFormat::H264_AAC, false, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test4.mp4", ExportFormat::H264_AAC, false, false, false, 23); encoder.go(); } @@ -306,7 +306,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test5) Rs->audio->set_mapping (map); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test5.mp4", ExportFormat::H264_AAC, true, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test5.mp4", ExportFormat::H264_AAC, true, false, false, 23); encoder.go (); check_ffmpeg ("build/test/ffmpeg_encoder_h264_test5.mp4", "test/data/ffmpeg_encoder_h264_test5.mp4", 1); @@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test6) } auto job = make_shared(film2, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film2, job, "build/test/ffmpeg_encoder_h264_test6_vf.mp4", ExportFormat::H264_AAC, true, false, false, 23); + FFmpegFilmEncoder encoder(film2, job, "build/test/ffmpeg_encoder_h264_test6_vf.mp4", ExportFormat::H264_AAC, true, false, false, 23); encoder.go (); } @@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_3d_dcp_to_h264) auto film2 = new_test_film2 ("ffmpeg_encoder_3d_dcp_to_h264_export", {dcp}); auto job = make_shared(film2, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film2, job, "build/test/ffmpeg_encoder_3d_dcp_to_h264.mp4", ExportFormat::H264_AAC, true, false, false, 23); + FFmpegFilmEncoder encoder(film2, job, "build/test/ffmpeg_encoder_3d_dcp_to_h264.mp4", ExportFormat::H264_AAC, true, false, false, 23); encoder.go (); } @@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test7) auto film2 = new_test_film2 ("ffmpeg_encoder_h264_test7_export", {dcp}); auto job = make_shared (film2, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film2, job, "build/test/ffmpeg_encoder_h264_test7.mp4", ExportFormat::H264_AAC, true, false, false, 23); + FFmpegFilmEncoder encoder(film2, job, "build/test/ffmpeg_encoder_h264_test7.mp4", ExportFormat::H264_AAC, true, false, false, 23); encoder.go (); } @@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE(ffmpeg_encoder_2d_content_in_3d_project) film->set_three_d(true); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_2d_content_in_3d_project.mp4", ExportFormat::H264_AAC, true, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_2d_content_in_3d_project.mp4", ExportFormat::H264_AAC, true, false, false, 23); encoder.go(); } @@ -394,7 +394,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test8) film->set_audio_channels (2); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test8.mp4", ExportFormat::H264_AAC, true, false, false, 23); + FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test8.mp4", ExportFormat::H264_AAC, true, false, false, 23); encoder.go(); } @@ -415,7 +415,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test9) film->write_metadata (); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test9.mov", ExportFormat::H264_AAC, false, false, false, 23); + FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test9.mov", ExportFormat::H264_AAC, false, false, false, 23); encoder.go (); } @@ -430,7 +430,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_from_dcp_with_crop) film->write_metadata (); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_from_dcp_with_crop.mov", ExportFormat::PRORES_HQ, false, false, false, 23); + FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_from_dcp_with_crop.mov", ExportFormat::PRORES_HQ, false, false, false, 23); encoder.go (); } @@ -445,7 +445,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_from_dcp_with_crop) film->write_metadata (); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_from_dcp_with_crop.mov", ExportFormat::H264_AAC, false, false, false, 23); + FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_from_dcp_with_crop.mov", ExportFormat::H264_AAC, false, false, false, 23); encoder.go (); } @@ -461,7 +461,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_with_reels) content2->video->set_length (240); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_with_reels.mov", ExportFormat::H264_AAC, false, true, false, 23); + FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_with_reels.mov", ExportFormat::H264_AAC, false, true, false, 23); encoder.go (); auto check = [](boost::filesystem::path path) { @@ -485,7 +485,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_regression_1) auto film = new_test_film2 ("ffmpeg_encoder_prores_regression_1", { content }); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_regression_1.mov", ExportFormat::PRORES_HQ, false, true, false, 23); + FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_regression_1.mov", ExportFormat::PRORES_HQ, false, true, false, 23); encoder.go (); cl.add("build/test/ffmpeg_encoder_prores_regression_1.mov"); @@ -505,7 +505,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_regression_2) auto film = new_test_film2 ("ffmpeg_encoder_prores_regression_2", { content }); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_regression_2.mov", ExportFormat::PRORES_HQ, false, true, false, 23); + FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_regression_2.mov", ExportFormat::PRORES_HQ, false, true, false, 23); encoder.go (); dcpomatic_log->set_types(logs); @@ -524,7 +524,7 @@ BOOST_AUTO_TEST_CASE(ffmpeg_encoder_missing_frame_at_end) boost::filesystem::path log("build/test/ffmpeg_encoder_missing_frame_at_end.log"); auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); - FFmpegEncoder encoder(film, job, output, ExportFormat::PRORES_HQ, false, true, false, 23); + FFmpegFilmEncoder encoder(film, job, output, ExportFormat::PRORES_HQ, false, true, false, 23); encoder.go(); run_ffprobe(output, log, false, "-show_frames -show_format -show_streams -select_streams v:0"); diff --git a/test/j2k_encode_threading_test.cc b/test/j2k_encode_threading_test.cc index ff2e7b0dc..5f66df20a 100644 --- a/test/j2k_encode_threading_test.cc +++ b/test/j2k_encode_threading_test.cc @@ -21,7 +21,7 @@ #include "lib/config.h" #include "lib/content_factory.h" -#include "lib/dcp_encoder.h" +#include "lib/dcp_film_encoder.h" #include "lib/dcp_transcode_job.h" #include "lib/encode_server_description.h" #include "lib/film.h" @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(frames_not_lost_when_threads_disappear) auto film = new_test_film2("frames_not_lost", content); film->write_metadata(); auto job = make_dcp(film, TranscodeJob::ChangedBehaviour::IGNORE); - auto& encoder = dynamic_pointer_cast(job->_encoder)->_j2k_encoder; + auto& encoder = dynamic_pointer_cast(job->_encoder)->_j2k_encoder; while (JobManager::instance()->work_to_do()) { encoder.remake_threads(rand() % 8, 0, {}); diff --git a/test/optimise_stills_test.cc b/test/optimise_stills_test.cc index cad7d7d26..50514041b 100644 --- a/test/optimise_stills_test.cc +++ b/test/optimise_stills_test.cc @@ -22,7 +22,6 @@ #include "lib/content.h" #include "lib/content_factory.h" #include "lib/dcp_content_type.h" -#include "lib/dcp_encoder.h" #include "lib/dcpomatic_log.h" #include "lib/film.h" #include "lib/job_manager.h" diff --git a/test/video_level_test.cc b/test/video_level_test.cc index c8e939861..bb2c1b7fa 100644 --- a/test/video_level_test.cc +++ b/test/video_level_test.cc @@ -36,7 +36,7 @@ #include "lib/image.h" #include "lib/image_content.h" #include "lib/image_decoder.h" -#include "lib/ffmpeg_encoder.h" +#include "lib/ffmpeg_film_encoder.h" #include "lib/job_manager.h" #include "lib/player.h" #include "lib/player_video.h" @@ -459,7 +459,7 @@ V_movie_range (shared_ptr film) { auto job = make_shared(film, TranscodeJob::ChangedBehaviour::IGNORE); job->set_encoder ( - make_shared(film, job, film->file("export.mov"), ExportFormat::PRORES_HQ, true, false, false, 23) + make_shared(film, job, film->file("export.mov"), ExportFormat::PRORES_HQ, true, false, false, 23) ); JobManager::instance()->add (job); BOOST_REQUIRE (!wait_for_jobs()); diff --git a/test/writer_test.cc b/test/writer_test.cc index 86b60818f..2d4da570f 100644 --- a/test/writer_test.cc +++ b/test/writer_test.cc @@ -23,7 +23,7 @@ #include "lib/content.h" #include "lib/content_factory.h" #include "lib/cross.h" -#include "lib/dcp_encoder.h" +#include "lib/dcp_film_encoder.h" #include "lib/film.h" #include "lib/job.h" #include "lib/video_content.h" @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(writer_progress_test) last_sub_name = job->sub_name(); }); - DCPEncoder encoder(film, job); + DCPFilmEncoder encoder(film, job); encoder.go(); } -- cgit v1.2.3 From fa15dc1a375e13d2047a857e5aef202179eec0d4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 19 Mar 2024 17:10:27 +0100 Subject: Extract VideoEncoder as a parent of J2KEncoder. --- src/lib/dcp_film_encoder.cc | 16 ++++----- src/lib/dcp_film_encoder.h | 2 +- src/lib/j2k_encoder.cc | 29 ++-------------- src/lib/j2k_encoder.h | 23 ++++--------- src/lib/video_encoder.cc | 64 ++++++++++++++++++++++++++++++++++++ src/lib/video_encoder.h | 69 +++++++++++++++++++++++++++++++++++++++ src/lib/wscript | 1 + test/j2k_encode_threading_test.cc | 4 +-- 8 files changed, 155 insertions(+), 53 deletions(-) create mode 100644 src/lib/video_encoder.cc create mode 100644 src/lib/video_encoder.h diff --git a/src/lib/dcp_film_encoder.cc b/src/lib/dcp_film_encoder.cc index 0403b2d90..b508b66b6 100644 --- a/src/lib/dcp_film_encoder.cc +++ b/src/lib/dcp_film_encoder.cc @@ -67,7 +67,7 @@ using namespace dcpomatic; DCPFilmEncoder::DCPFilmEncoder(shared_ptr film, weak_ptr job) : FilmEncoder(film, job) , _writer(film, job) - , _j2k_encoder(film, _writer) + , _encoder(new J2KEncoder(film, _writer)) , _finishing (false) , _non_burnt_subtitles (false) { @@ -98,7 +98,7 @@ void DCPFilmEncoder::go() { _writer.start(); - _j2k_encoder.begin(); + _encoder->begin(); { auto job = _job.lock (); @@ -117,7 +117,7 @@ DCPFilmEncoder::go() } _finishing = true; - _j2k_encoder.end(); + _encoder->end(); _writer.finish(_film->dir(_film->dcp_name())); } @@ -125,20 +125,20 @@ DCPFilmEncoder::go() void DCPFilmEncoder::pause() { - _j2k_encoder.pause(); + _encoder->pause(); } void DCPFilmEncoder::resume() { - _j2k_encoder.resume(); + _encoder->resume(); } void DCPFilmEncoder::video(shared_ptr data, DCPTime time) { - _j2k_encoder.encode(data, time); + _encoder->encode(data, time); } void @@ -170,11 +170,11 @@ DCPFilmEncoder::atmos(shared_ptr data, DCPTime time, Atmo optional DCPFilmEncoder::current_rate() const { - return _j2k_encoder.current_encoding_rate(); + return _encoder->current_encoding_rate(); } Frame DCPFilmEncoder::frames_done() const { - return _j2k_encoder.video_frames_enqueued(); + return _encoder->video_frames_enqueued(); } diff --git a/src/lib/dcp_film_encoder.h b/src/lib/dcp_film_encoder.h index fbc0aeb13..3c697a115 100644 --- a/src/lib/dcp_film_encoder.h +++ b/src/lib/dcp_film_encoder.h @@ -68,7 +68,7 @@ private: void atmos (std::shared_ptr, dcpomatic::DCPTime, AtmosMetadata metadata); Writer _writer; - J2KEncoder _j2k_encoder; + std::unique_ptr _encoder; bool _finishing; bool _non_burnt_subtitles; diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index de229113b..6154dfb62 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -92,9 +92,7 @@ grk_plugin::IMessengerLogger* getMessengerLogger(void) * @param writer Writer that we are using. */ J2KEncoder::J2KEncoder(shared_ptr film, Writer& writer) - : _film (film) - , _history (200) - , _writer (writer) + : VideoEncoder(film, writer) { #ifdef DCPOMATIC_GROK auto grok = Config::instance()->grok().get_value_or({}); @@ -242,28 +240,6 @@ J2KEncoder::end() } -/** @return an estimate of the current number of frames we are encoding per second, - * if known. - */ -optional -J2KEncoder::current_encoding_rate () const -{ - return _history.rate (); -} - - -/** @return Number of video frames that have been queued for encoding */ -int -J2KEncoder::video_frames_enqueued () const -{ - if (!_last_player_video_time) { - return 0; - } - - return _last_player_video_time->frames_floor (_film->video_frame_rate ()); -} - - /** Should be called when a frame has been encoded successfully */ void J2KEncoder::frame_done () @@ -283,6 +259,8 @@ J2KEncoder::frame_done () void J2KEncoder::encode (shared_ptr pv, DCPTime time) { + VideoEncoder::encode(pv, time); + _waker.nudge (); size_t threads = 0; @@ -344,7 +322,6 @@ J2KEncoder::encode (shared_ptr pv, DCPTime time) } _last_player_video[pv->eyes()] = pv; - _last_player_video_time = time; } diff --git a/src/lib/j2k_encoder.h b/src/lib/j2k_encoder.h index 6bfbaea49..c72a1debe 100644 --- a/src/lib/j2k_encoder.h +++ b/src/lib/j2k_encoder.h @@ -34,6 +34,7 @@ #include "exception_store.h" #include "j2k_encoder_thread.h" #include "writer.h" +#include "video_encoder.h" #include #include #include @@ -65,7 +66,7 @@ struct frames_not_lost_when_threads_disappear; * This class keeps a queue of frames to be encoded and distributes * the work around threads and encoding servers. */ -class J2KEncoder : public ExceptionStore +class J2KEncoder : public VideoEncoder, public ExceptionStore { public: J2KEncoder(std::shared_ptr film, Writer& writer); @@ -75,19 +76,16 @@ public: J2KEncoder& operator= (J2KEncoder const&) = delete; /** Called to indicate that a processing run is about to begin */ - void begin (); + void begin() override; /** Called to pass a bit of video to be encoded as the next DCP frame */ - void encode (std::shared_ptr pv, dcpomatic::DCPTime time); + void encode (std::shared_ptr pv, dcpomatic::DCPTime time) override; - void pause(); - void resume(); + void pause() override; + void resume() override; /** Called when a processing run has finished */ - void end(); - - boost::optional current_encoding_rate () const; - int video_frames_enqueued () const; + void end() override; DCPVideo pop(); void retry(DCPVideo frame); @@ -103,11 +101,6 @@ private: void remake_threads(int cpu, int gpu, std::list servers); void terminate_threads (); - /** Film that we are encoding */ - std::shared_ptr _film; - - EventHistory _history; - boost::mutex _threads_mutex; std::vector> _threads; @@ -118,11 +111,9 @@ private: /** condition to manage thread wakeups when we have too much to do */ boost::condition _full_condition; - Writer& _writer; Waker _waker; EnumIndexedVector, Eyes> _last_player_video; - boost::optional _last_player_video_time; boost::signals2::scoped_connection _server_found_connection; diff --git a/src/lib/video_encoder.cc b/src/lib/video_encoder.cc new file mode 100644 index 000000000..590dc7471 --- /dev/null +++ b/src/lib/video_encoder.cc @@ -0,0 +1,64 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "video_encoder.h" + + +using std::shared_ptr; +using boost::optional; + + +VideoEncoder::VideoEncoder(shared_ptr film, Writer& writer) + : _film(film) + , _writer(writer) + , _history(200) +{ + +} + + +void +VideoEncoder::encode(shared_ptr, dcpomatic::DCPTime time) +{ + _last_player_video_time = time; +} + + +/** @return Number of video frames that have been queued for encoding */ +int +VideoEncoder::video_frames_enqueued() const +{ + if (!_last_player_video_time) { + return 0; + } + + return _last_player_video_time->frames_floor(_film->video_frame_rate()); +} + + +/** @return an estimate of the current number of frames we are encoding per second, + * if known. + */ +optional +VideoEncoder::current_encoding_rate() const +{ + return _history.rate(); +} diff --git a/src/lib/video_encoder.h b/src/lib/video_encoder.h new file mode 100644 index 000000000..8cc33ef8a --- /dev/null +++ b/src/lib/video_encoder.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#ifndef DCPOMATIC_VIDEO_ENCODER_H +#define DCPOMATIC_VIDEO_ENCODER_H + + +#include "dcpomatic_time.h" +#include "event_history.h" +#include "film.h" +#include "player_video.h" + + +class Writer; + + +class VideoEncoder +{ +public: + VideoEncoder(std::shared_ptr film, Writer& writer); + virtual ~VideoEncoder() {} + + VideoEncoder(VideoEncoder const&) = delete; + VideoEncoder& operator=(VideoEncoder const&) = delete; + + /** Called to indicate that a processing run is about to begin */ + virtual void begin() {} + + /** Called to pass a bit of video to be encoded as the next DCP frame */ + virtual void encode(std::shared_ptr pv, dcpomatic::DCPTime time); + + virtual void pause() = 0; + virtual void resume() = 0; + + /** Called when a processing run has finished */ + virtual void end() = 0; + + int video_frames_enqueued() const; + boost::optional current_encoding_rate() const; + +protected: + /** Film that we are encoding */ + std::shared_ptr _film; + Writer& _writer; + EventHistory _history; + boost::optional _last_player_video_time; +}; + + +#endif + diff --git a/src/lib/wscript b/src/lib/wscript index 5e49b1fbf..152d3abaf 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -210,6 +210,7 @@ sources = """ verify_dcp_job.cc video_content.cc video_decoder.cc + video_encoder.cc video_filter_graph.cc video_filter_graph_set.cc video_frame_type.cc diff --git a/test/j2k_encode_threading_test.cc b/test/j2k_encode_threading_test.cc index 5f66df20a..ee219fbe0 100644 --- a/test/j2k_encode_threading_test.cc +++ b/test/j2k_encode_threading_test.cc @@ -99,10 +99,10 @@ BOOST_AUTO_TEST_CASE(frames_not_lost_when_threads_disappear) auto film = new_test_film2("frames_not_lost", content); film->write_metadata(); auto job = make_dcp(film, TranscodeJob::ChangedBehaviour::IGNORE); - auto& encoder = dynamic_pointer_cast(job->_encoder)->_j2k_encoder; + auto encoder = dynamic_cast(dynamic_pointer_cast(job->_encoder)->_encoder.get()); while (JobManager::instance()->work_to_do()) { - encoder.remake_threads(rand() % 8, 0, {}); + encoder->remake_threads(rand() % 8, 0, {}); dcpomatic_sleep_seconds(1); } -- cgit v1.2.3 From f7518583f90a866a07d8069a78bebcea82b2b248 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 26 Mar 2024 22:43:10 +0100 Subject: Extract frame info read/write to new class. --- src/lib/frame_info.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/frame_info.h | 45 ++++++++++++++++++++++++++ src/lib/reel_writer.cc | 65 +++++-------------------------------- src/lib/reel_writer.h | 6 ---- src/lib/writer.cc | 7 ++-- src/lib/wscript | 1 + test/reel_writer_test.cc | 39 +++++++++++----------- 7 files changed, 160 insertions(+), 87 deletions(-) create mode 100644 src/lib/frame_info.cc create mode 100644 src/lib/frame_info.h diff --git a/src/lib/frame_info.cc b/src/lib/frame_info.cc new file mode 100644 index 000000000..f348bca6a --- /dev/null +++ b/src/lib/frame_info.cc @@ -0,0 +1,84 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "frame_info.h" +#include + + +using std::shared_ptr; +using std::string; + + +J2KFrameInfo::J2KFrameInfo(uint64_t offset_, uint64_t size_, string hash_) + : dcp::J2KFrameInfo(offset_, size_, hash_) +{ + +} + + +J2KFrameInfo::J2KFrameInfo(dcp::J2KFrameInfo const& info) + : dcp::J2KFrameInfo(info) +{ + +} + + +J2KFrameInfo::J2KFrameInfo(shared_ptr info_file, Frame frame, Eyes eyes) +{ + info_file->get().seek(position(frame, eyes), SEEK_SET); + info_file->get().checked_read(&offset, sizeof(offset)); + info_file->get().checked_read(&size, sizeof(size)); + + char hash_buffer[33]; + info_file->get().checked_read(hash_buffer, 32); + hash_buffer[32] = '\0'; + hash = hash_buffer; +} + + +long +J2KFrameInfo::position(Frame frame, Eyes eyes) const +{ + switch (eyes) { + case Eyes::BOTH: + return frame * _size_on_disk; + case Eyes::LEFT: + return frame * _size_on_disk * 2; + case Eyes::RIGHT: + return frame * _size_on_disk * 2 + _size_on_disk; + default: + DCPOMATIC_ASSERT(false); + } + + DCPOMATIC_ASSERT(false); +} + + +/** @param frame reel-relative frame */ +void +J2KFrameInfo::write(shared_ptr info_file, Frame frame, Eyes eyes) const +{ + info_file->get().seek(position(frame, eyes), SEEK_SET); + info_file->get().checked_write(&offset, sizeof(offset)); + info_file->get().checked_write(&size, sizeof(size)); + info_file->get().checked_write(hash.c_str(), hash.size()); +} + diff --git a/src/lib/frame_info.h b/src/lib/frame_info.h new file mode 100644 index 000000000..a5a22bd9e --- /dev/null +++ b/src/lib/frame_info.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "film.h" +#include +#include + + +class J2KFrameInfo : public dcp::J2KFrameInfo +{ +public: + J2KFrameInfo(dcp::J2KFrameInfo const& info); + J2KFrameInfo(uint64_t offset_, uint64_t size_, std::string hash_); + J2KFrameInfo(std::shared_ptr info_file, Frame frame, Eyes eyes); + + void write(std::shared_ptr info_file, Frame frame, Eyes eyes) const; + + static int size_on_disk() { + return _size_on_disk; + } + +private: + long position(Frame frame, Eyes eyes) const; + + static constexpr auto _size_on_disk = 32 + sizeof(dcp::J2KFrameInfo::offset) + sizeof(dcp::J2KFrameInfo::size); +}; + diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 1cca3fd17..201c23e71 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -28,6 +28,7 @@ #include "digester.h" #include "film.h" #include "film_util.h" +#include "frame_info.h" #include "image.h" #include "image_png.h" #include "job.h" @@ -81,9 +82,6 @@ using dcp::raw_convert; using namespace dcpomatic; -int const ReelWriter::_info_size = 48; - - static dcp::MXFMetadata mxf_metadata () { @@ -215,53 +213,6 @@ ReelWriter::ReelWriter ( } -/** @param frame reel-relative frame */ -void -ReelWriter::write_frame_info (Frame frame, Eyes eyes, dcp::FrameInfo info) const -{ - auto handle = film()->info_file_handle(_period, false); - handle->get().seek(frame_info_position(frame, eyes), SEEK_SET); - handle->get().checked_write(&info.offset, sizeof(info.offset)); - handle->get().checked_write(&info.size, sizeof(info.size)); - handle->get().checked_write(info.hash.c_str(), info.hash.size()); -} - - -dcp::FrameInfo -ReelWriter::read_frame_info (shared_ptr info, Frame frame, Eyes eyes) const -{ - dcp::FrameInfo frame_info; - info->get().seek(frame_info_position(frame, eyes), SEEK_SET); - info->get().checked_read(&frame_info.offset, sizeof(frame_info.offset)); - info->get().checked_read(&frame_info.size, sizeof(frame_info.size)); - - char hash_buffer[33]; - info->get().checked_read(hash_buffer, 32); - hash_buffer[32] = '\0'; - frame_info.hash = hash_buffer; - - return frame_info; -} - - -long -ReelWriter::frame_info_position (Frame frame, Eyes eyes) const -{ - switch (eyes) { - case Eyes::BOTH: - return frame * _info_size; - case Eyes::LEFT: - return frame * _info_size * 2; - case Eyes::RIGHT: - return frame * _info_size * 2 + _info_size; - default: - DCPOMATIC_ASSERT (false); - } - - DCPOMATIC_ASSERT (false); -} - - Frame ReelWriter::check_existing_picture_asset (boost::filesystem::path asset) { @@ -290,8 +241,8 @@ ReelWriter::check_existing_picture_asset (boost::filesystem::path asset) } /* Offset of the last dcp::FrameInfo in the info file */ - int const n = (dcp::filesystem::file_size(info_file->get().path()) / _info_size) - 1; - LOG_GENERAL ("The last FI is %1; info file is %2, info size %3", n, dcp::filesystem::file_size(info_file->get().path()), _info_size); + int const n = (dcp::filesystem::file_size(info_file->get().path()) / J2KFrameInfo::size_on_disk()) - 1; + LOG_GENERAL("The last FI is %1; info file is %2, info size %3", n, dcp::filesystem::file_size(info_file->get().path()), J2KFrameInfo::size_on_disk()) Frame first_nonexistent_frame; if (film()->three_d()) { @@ -326,8 +277,8 @@ ReelWriter::write (shared_ptr encoded, Frame frame, Eyes eyes) return; } - auto fin = _picture_asset_writer->write (encoded->data(), encoded->size()); - write_frame_info (frame, eyes, fin); + auto fin = J2KFrameInfo(_j2k_picture_asset_writer->write(encoded->data(), encoded->size())); + fin.write(film()->info_file_handle(_period, false), frame, eyes); _last_written[eyes] = encoded; } @@ -368,8 +319,8 @@ ReelWriter::repeat_write (Frame frame, Eyes eyes) return; } - auto fin = _picture_asset_writer->write(_last_written[eyes]->data(), _last_written[eyes]->size()); - write_frame_info (frame, eyes, fin); + auto fin = J2KFrameInfo(_j2k_picture_asset_writer->write(_last_written[eyes]->data(), _last_written[eyes]->size())); + fin.write(film()->info_file_handle(_period, false), frame, eyes); } @@ -1012,7 +963,7 @@ ReelWriter::existing_picture_frame_ok (dcp::File& asset_file, shared_ptrthree_d() ? Eyes::LEFT : Eyes::BOTH); + auto const info = J2KFrameInfo(info_file, frame, film()->three_d() ? Eyes::LEFT : Eyes::BOTH); bool ok = true; diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index 6f47c6740..30abdd563 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -95,14 +95,10 @@ public: return _first_nonexistent_frame; } - dcp::FrameInfo read_frame_info (std::shared_ptr info, Frame frame, Eyes eyes) const; - private: friend struct ::write_frame_info_test; - void write_frame_info (Frame frame, Eyes eyes, dcp::FrameInfo info) const; - long frame_info_position (Frame frame, Eyes eyes) const; Frame check_existing_picture_asset (boost::filesystem::path asset); bool existing_picture_frame_ok (dcp::File& asset_file, std::shared_ptr info_file, Frame frame) const; std::shared_ptr empty_text_asset (TextType type, boost::optional track, bool with_dummy) const; @@ -146,6 +142,4 @@ private: std::shared_ptr _atmos_asset_writer; mutable FontMetrics _font_metrics; - - static int const _info_size; }; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index fbe2d248d..1c04f4065 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -30,6 +30,7 @@ #include "dcpomatic_log.h" #include "film.h" #include "film_util.h" +#include "frame_info.h" #include "job.h" #include "log.h" #include "ratio.h" @@ -229,11 +230,7 @@ Writer::fake_write (Frame frame, Eyes eyes) QueueItem qi; qi.type = QueueItem::Type::FAKE; - - { - shared_ptr info_file = film()->info_file_handle(_reels[reel].period(), true); - qi.size = _reels[reel].read_frame_info(info_file, frame_in_reel, eyes).size; - } + qi.size = J2KFrameInfo(film()->info_file_handle(_reels[reel].period(), true), frame_in_reel, eyes).size; DCPOMATIC_ASSERT((film()->three_d() && eyes != Eyes::BOTH) || (!film()->three_d() && eyes == Eyes::BOTH)); diff --git a/src/lib/wscript b/src/lib/wscript index 152d3abaf..8e839cb49 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -98,6 +98,7 @@ sources = """ examine_ffmpeg_subtitles_job.cc exceptions.cc export_config.cc + frame_info.cc file_group.cc file_log.cc filter_graph.cc diff --git a/test/reel_writer_test.cc b/test/reel_writer_test.cc index ec2469898..f81e8e333 100644 --- a/test/reel_writer_test.cc +++ b/test/reel_writer_test.cc @@ -30,6 +30,7 @@ #include "lib/content_factory.h" #include "lib/cross.h" #include "lib/film.h" +#include "lib/frame_info.h" #include "lib/reel_writer.h" #include "lib/video_content.h" #include "test.h" @@ -46,9 +47,9 @@ using std::string; using boost::optional; -static bool equal (dcp::FrameInfo a, ReelWriter const & writer, shared_ptr file, Frame frame, Eyes eyes) +static bool equal(J2KFrameInfo a, shared_ptr file, Frame frame, Eyes eyes) { - auto b = writer.read_frame_info(file, frame, eyes); + auto b = J2KFrameInfo(file, frame, eyes); return a.offset == b.offset && a.size == b.size && a.hash == b.hash; } @@ -61,44 +62,44 @@ BOOST_AUTO_TEST_CASE (write_frame_info_test) /* Write the first one */ - dcp::FrameInfo info1(0, 123, "12345678901234567890123456789012"); - writer.write_frame_info (0, Eyes::LEFT, info1); + J2KFrameInfo info1(0, 123, "12345678901234567890123456789012"); + info1.write(film->info_file_handle(period, false), 0, Eyes::LEFT); { auto file = film->info_file_handle(period, true); - BOOST_CHECK (equal(info1, writer, file, 0, Eyes::LEFT)); + BOOST_CHECK(equal(info1, file, 0, Eyes::LEFT)); } /* Write some more */ - dcp::FrameInfo info2(596, 14921, "123acb789f1234ae782012n456339522"); - writer.write_frame_info (5, Eyes::RIGHT, info2); + J2KFrameInfo info2(596, 14921, "123acb789f1234ae782012n456339522"); + info2.write(film->info_file_handle(period, false), 5, Eyes::RIGHT); { auto file = film->info_file_handle(period, true); - BOOST_CHECK (equal(info1, writer, file, 0, Eyes::LEFT)); - BOOST_CHECK (equal(info2, writer, file, 5, Eyes::RIGHT)); + BOOST_CHECK(equal(info1, file, 0, Eyes::LEFT)); + BOOST_CHECK(equal(info2, file, 5, Eyes::RIGHT)); } - dcp::FrameInfo info3(12494, 99157123, "xxxxyyyyabc12356ffsfdsf456339522"); - writer.write_frame_info (10, Eyes::LEFT, info3); + J2KFrameInfo info3(12494, 99157123, "xxxxyyyyabc12356ffsfdsf456339522"); + info3.write(film->info_file_handle(period, false), 10, Eyes::LEFT); { auto file = film->info_file_handle(period, true); - BOOST_CHECK (equal(info1, writer, file, 0, Eyes::LEFT)); - BOOST_CHECK (equal(info2, writer, file, 5, Eyes::RIGHT)); - BOOST_CHECK (equal(info3, writer, file, 10, Eyes::LEFT)); + BOOST_CHECK(equal(info1, file, 0, Eyes::LEFT)); + BOOST_CHECK(equal(info2, file, 5, Eyes::RIGHT)); + BOOST_CHECK(equal(info3, file, 10, Eyes::LEFT)); } /* Overwrite one */ - dcp::FrameInfo info4(55512494, 123599157123, "ABCDEFGyabc12356ffsfdsf4563395ZZ"); - writer.write_frame_info (5, Eyes::RIGHT, info4); + J2KFrameInfo info4(55512494, 123599157123, "ABCDEFGyabc12356ffsfdsf4563395ZZ"); + info4.write(film->info_file_handle(period, false), 5, Eyes::RIGHT); { auto file = film->info_file_handle(period, true); - BOOST_CHECK (equal(info1, writer, file, 0, Eyes::LEFT)); - BOOST_CHECK (equal(info4, writer, file, 5, Eyes::RIGHT)); - BOOST_CHECK (equal(info3, writer, file, 10, Eyes::LEFT)); + BOOST_CHECK(equal(info1, file, 0, Eyes::LEFT)); + BOOST_CHECK(equal(info4, file, 5, Eyes::RIGHT)); + BOOST_CHECK(equal(info3, file, 10, Eyes::LEFT)); } } -- cgit v1.2.3 From 45315c3a096fe49ffa50ded1aeb94394f71e3006 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 26 Mar 2024 20:29:11 +0100 Subject: Remove unnecessary library path. --- run/environment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/environment b/run/environment index aa4f77187..a0a2a0782 100644 --- a/run/environment +++ b/run/environment @@ -4,6 +4,6 @@ export LD_LIBRARY_PATH=$build/src/lib:$build/src/wx:/usr/local/lib64:/usr/local/ if [[ $(readlink -f $DIR/..) =~ (.*build/[^/]*) ]]; then export LD_LIBRARY_PATH=${BASH_REMATCH[1]}/lib:$LD_LIBRARY_PATH fi -export DYLD_LIBRARY_PATH=$build/src/lib:$build/src/wx:$build/src/asdcplib/src:/Users/ci/osx-environment/x86_64/10.10/lib:/Users/ci/workspace/lib +export DYLD_LIBRARY_PATH=$build/src/lib:$build/src/wx:/Users/ci/osx-environment/x86_64/10.10/lib:/Users/ci/workspace/lib export DCPOMATIC_GRAPHICS=$DIR/../graphics -- cgit v1.2.3 From 55f1927db0565c74ff7c121645ec397c07f63d51 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 26 Mar 2024 20:29:49 +0100 Subject: Add "build" environment lib to local run script. --- run/environment | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/run/environment b/run/environment index a0a2a0782..ddb642eed 100644 --- a/run/environment +++ b/run/environment @@ -1,6 +1,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" build=$DIR/../build -export LD_LIBRARY_PATH=$build/src/lib:$build/src/wx:/usr/local/lib64:/usr/local/lib:$LD_LIBRARY_PATH +env=$DIR/../../.. +export LD_LIBRARY_PATH=$build/src/lib:$build/src/wx:$env/lib:/usr/local/lib64:/usr/local/lib:$LD_LIBRARY_PATH if [[ $(readlink -f $DIR/..) =~ (.*build/[^/]*) ]]; then export LD_LIBRARY_PATH=${BASH_REMATCH[1]}/lib:$LD_LIBRARY_PATH fi -- cgit v1.2.3 From c98d6fd22da1586ef3c1d64a2f7b1ee602f539e9 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 5 Apr 2024 21:57:03 +0200 Subject: Rename j2k_bandwidth -> video_bit_rate. --- src/lib/config.cc | 24 +++++++---- src/lib/config.h | 22 +++++----- src/lib/create_cli.cc | 16 +++---- src/lib/create_cli.h | 2 +- src/lib/dcp_video.cc | 14 +++--- src/lib/dcp_video.h | 4 +- src/lib/film.cc | 24 ++++++----- src/lib/film.h | 10 ++--- src/lib/film_property.h | 2 +- src/lib/grok/context.h | 2 +- src/lib/hints.cc | 8 ++-- src/lib/hints.h | 2 +- src/lib/j2k_encoder.cc | 2 +- src/lib/make_dcp.cc | 2 +- src/lib/playlist.cc | 6 +-- src/lib/playlist.h | 2 +- src/tools/dcpomatic_cli.cc | 2 +- src/wx/dcp_panel.cc | 28 ++++++------ src/wx/dcp_panel.h | 6 +-- src/wx/full_config_dialog.cc | 34 +++++++-------- test/create_cli_test.cc | 6 +-- test/film_metadata_test.cc | 2 +- test/j2k_bandwidth_test.cc | 92 ---------------------------------------- test/j2k_video_bit_rate_test.cc | 92 ++++++++++++++++++++++++++++++++++++++++ test/reels_test.cc | 4 +- test/required_disk_space_test.cc | 2 +- test/test.cc | 2 +- test/wscript | 2 +- 28 files changed, 213 insertions(+), 201 deletions(-) delete mode 100644 test/j2k_bandwidth_test.cc create mode 100644 test/j2k_video_bit_rate_test.cc diff --git a/src/lib/config.cc b/src/lib/config.cc index fb7a413de..1400b9309 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -108,7 +108,7 @@ Config::set_defaults () _default_still_length = 10; _default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR"); _default_dcp_audio_channels = 8; - _default_j2k_bandwidth = 150000000; + _default_video_bit_rate = 150000000; _default_audio_delay = 0; _default_interop = false; _default_metadata.clear (); @@ -127,7 +127,7 @@ Config::set_defaults () _notification_bcc = ""; _check_for_updates = false; _check_for_test_updates = false; - _maximum_j2k_bandwidth = 250000000; + _maximum_video_bit_rate = 250000000; _log_types = LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR | LogEntry::TYPE_DISK; _analyse_ebur128 = true; _automatic_audio_analysis = false; @@ -375,7 +375,11 @@ try _dcp_j2k_comment = f.optional_string_child("DCPJ2KComment").get_value_or(""); _default_still_length = f.optional_number_child("DefaultStillLength").get_value_or (10); - _default_j2k_bandwidth = f.optional_number_child("DefaultJ2KBandwidth").get_value_or (200000000); + if (auto j2k = f.optional_number_child("DefaultJ2KBandwidth")) { + _default_video_bit_rate = *j2k; + } else { + _default_video_bit_rate = f.optional_number_child("DefaultVideoBitRate").get_value_or(200000000); + } _default_audio_delay = f.optional_number_child("DefaultAudioDelay").get_value_or (0); _default_interop = f.optional_bool_child("DefaultInterop").get_value_or (false); @@ -450,7 +454,11 @@ try _check_for_updates = f.optional_bool_child("CheckForUpdates").get_value_or (false); _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false); - _maximum_j2k_bandwidth = f.optional_number_child ("MaximumJ2KBandwidth").get_value_or (250000000); + if (auto j2k = f.optional_number_child("MaximumJ2KBandwidth")) { + _maximum_video_bit_rate = *j2k; + } else { + _maximum_video_bit_rate = f.optional_number_child("MaximumVideoBitRate").get_value_or(250000000); + } _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate").get_value_or (false); _allow_any_container = f.optional_bool_child ("AllowAnyContainer").get_value_or (false); _allow_96khz_audio = f.optional_bool_child("Allow96kHzAudio").get_value_or(false); @@ -807,8 +815,8 @@ Config::write_config () const /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */ cxml::add_text_child(root, "DefaultStillLength", raw_convert(_default_still_length)); - /* [XML] DefaultJ2KBandwidth Default bitrate (in bits per second) for JPEG2000 data in new films. */ - cxml::add_text_child(root, "DefaultJ2KBandwidth", raw_convert(_default_j2k_bandwidth)); + /* [XML] DefaultVideoBitRate Default bitrate (in bits per second) for JPEG2000 or MPEG2 data in new films. */ + cxml::add_text_child(root, "DefaultVideoBitRate", raw_convert(_default_video_bit_rate)); /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */ cxml::add_text_child(root, "DefaultAudioDelay", raw_convert(_default_audio_delay)); /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */ @@ -888,8 +896,8 @@ Config::write_config () const /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */ cxml::add_text_child(root, "CheckForTestUpdates", _check_for_test_updates ? "1" : "0"); - /* [XML] MaximumJ2KBandwidth Maximum J2K bandwidth (in bits per second) that can be specified in the GUI. */ - cxml::add_text_child(root, "MaximumJ2KBandwidth", raw_convert(_maximum_j2k_bandwidth)); + /* [XML] MaximumVideoBitRate Maximum video bit rate (in bits per second) that can be specified in the GUI. */ + cxml::add_text_child(root, "MaximumVideoBitRate", raw_convert(_maximum_video_bit_rate)); /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */ cxml::add_text_child(root, "AllowAnyDCPFrameRate", _allow_any_dcp_frame_rate ? "1" : "0"); /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */ diff --git a/src/lib/config.h b/src/lib/config.h index ec804c9bf..05421c20a 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -232,8 +232,8 @@ public: return _dcp_j2k_comment; } - int default_j2k_bandwidth () const { - return _default_j2k_bandwidth; + int64_t default_video_bit_rate() const { + return _default_video_bit_rate; } int default_audio_delay () const { @@ -348,8 +348,8 @@ public: return _check_for_test_updates; } - int maximum_j2k_bandwidth () const { - return _maximum_j2k_bandwidth; + int64_t maximum_video_bit_rate() const { + return _maximum_video_bit_rate; } int log_types () const { @@ -810,8 +810,8 @@ public: maybe_set (_dcp_j2k_comment, c); } - void set_default_j2k_bandwidth (int b) { - maybe_set (_default_j2k_bandwidth, b); + void set_default_video_bit_rate(int64_t b) { + maybe_set(_default_video_bit_rate, b); } void set_default_audio_delay (int d) { @@ -933,8 +933,8 @@ public: maybe_set (_check_for_test_updates, c); } - void set_maximum_j2k_bandwidth (int b) { - maybe_set (_maximum_j2k_bandwidth, b); + void set_maximum_video_bit_rate(int64_t b) { + maybe_set(_maximum_video_bit_rate, b); } void set_log_types (int t) { @@ -1380,7 +1380,7 @@ private: std::string _dcp_product_name; std::string _dcp_product_version; std::string _dcp_j2k_comment; - int _default_j2k_bandwidth; + int64_t _default_video_bit_rate; int _default_audio_delay; bool _default_interop; boost::optional _default_audio_language; @@ -1417,8 +1417,8 @@ private: /** true to check for updates on startup */ bool _check_for_updates; bool _check_for_test_updates; - /** maximum allowed J2K bandwidth in bits per second */ - int _maximum_j2k_bandwidth; + /** maximum allowed video bit rate in bits per second */ + int64_t _maximum_video_bit_rate; int _log_types; bool _analyse_ebur128; bool _automatic_audio_analysis; diff --git a/src/lib/create_cli.cc b/src/lib/create_cli.cc index cf903e376..b33537974 100644 --- a/src/lib/create_cli.cc +++ b/src/lib/create_cli.cc @@ -133,7 +133,7 @@ CreateCLI::CreateCLI (int argc, char* argv[]) optional standard_string; int dcp_frame_rate_int = 0; string template_name_string; - int j2k_bandwidth_int = 0; + int64_t video_bit_rate_int = 0; auto next_frame_type = VideoFrameType::TWO_D; optional channel; optional gain; @@ -206,7 +206,7 @@ CreateCLI::CreateCLI (int argc, char* argv[]) argument_option(i, argc, argv, "", "--standard", &claimed, &error, &standard_string, string_to_string); argument_option(i, argc, argv, "", "--config", &claimed, &error, &config_dir, string_to_path); argument_option(i, argc, argv, "-o", "--output", &claimed, &error, &output_dir, string_to_path); - argument_option(i, argc, argv, "", "--j2k-bandwidth", &claimed, &error, &j2k_bandwidth_int); + argument_option(i, argc, argv, "", "--video-bit-rate", &claimed, &error, &video_bit_rate_int); std::function (string)> convert_channel = [](string channel) -> optional{ if (channel == "L") { @@ -272,8 +272,8 @@ CreateCLI::CreateCLI (int argc, char* argv[]) dcp_frame_rate = dcp_frame_rate_int; } - if (j2k_bandwidth_int) { - _j2k_bandwidth = j2k_bandwidth_int * 1000000; + if (video_bit_rate_int) { + _video_bit_rate = video_bit_rate_int * 1000000; } if (dcp_content_type_string) { @@ -320,8 +320,8 @@ CreateCLI::CreateCLI (int argc, char* argv[]) _name = content[0].path.filename().string(); } - if (_j2k_bandwidth && (*_j2k_bandwidth < 10000000 || *_j2k_bandwidth > Config::instance()->maximum_j2k_bandwidth())) { - error = String::compose("%1: j2k-bandwidth must be between 10 and %2 Mbit/s", argv[0], (Config::instance()->maximum_j2k_bandwidth() / 1000000)); + if (_video_bit_rate && (*_video_bit_rate < 10000000 || *_video_bit_rate > Config::instance()->maximum_video_bit_rate())) { + error = String::compose("%1: video-bit-rate must be between 10 and %2 Mbit/s", argv[0], (Config::instance()->maximum_video_bit_rate() / 1000000)); return; } } @@ -372,8 +372,8 @@ CreateCLI::make_film() const if (_fourk) { film->set_resolution(Resolution::FOUR_K); } - if (_j2k_bandwidth) { - film->set_j2k_bandwidth(*_j2k_bandwidth); + if (_video_bit_rate) { + film->set_video_bit_rate(*_video_bit_rate); } int channels = 6; diff --git a/src/lib/create_cli.h b/src/lib/create_cli.h index 782aaf974..850cddea9 100644 --- a/src/lib/create_cli.h +++ b/src/lib/create_cli.h @@ -72,7 +72,7 @@ private: bool _no_use_isdcf_name = false; bool _twok = false; bool _fourk = false; - boost::optional _j2k_bandwidth; + boost::optional _video_bit_rate; static std::string _help; }; diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc index 6580ac448..ec88888dd 100644 --- a/src/lib/dcp_video.cc +++ b/src/lib/dcp_video.cc @@ -74,15 +74,15 @@ using namespace boost::placeholders; /** Construct a DCP video frame. * @param frame Input frame. * @param index Index of the frame within the DCP. - * @param bw J2K bandwidth to use (see Config::j2k_bandwidth ()) + * @param bit_rate Video bit rate to use. */ DCPVideo::DCPVideo ( - shared_ptr frame, int index, int dcp_fps, int bw, Resolution r + shared_ptr frame, int index, int dcp_fps, int64_t bit_rate, Resolution r ) : _frame (frame) , _index (index) , _frames_per_second (dcp_fps) - , _j2k_bandwidth (bw) + , _video_bit_rate(bit_rate) , _resolution (r) { @@ -93,7 +93,7 @@ DCPVideo::DCPVideo (shared_ptr frame, shared_ptrnumber_child ("Index"); _frames_per_second = node->number_child ("FramesPerSecond"); - _j2k_bandwidth = node->number_child ("J2KBandwidth"); + _video_bit_rate = node->number_child("VideoBitRate"); _resolution = Resolution (node->optional_number_child("Resolution").get_value_or(static_cast(Resolution::TWO_K))); } @@ -160,7 +160,7 @@ DCPVideo::encode_locally () const while (true) { enc = dcp::compress_j2k ( xyz, - _j2k_bandwidth, + _video_bit_rate, _frames_per_second, _frame->eyes() == Eyes::LEFT || _frame->eyes() == Eyes::RIGHT, _resolution == Resolution::FOUR_K, @@ -280,7 +280,7 @@ DCPVideo::add_metadata (xmlpp::Element* el) const { cxml::add_text_child(el, "Index", raw_convert(_index)); cxml::add_text_child(el, "FramesPerSecond", raw_convert(_frames_per_second)); - cxml::add_text_child(el, "J2KBandwidth", raw_convert(_j2k_bandwidth)); + cxml::add_text_child(el, "VideoBitRate", raw_convert(_video_bit_rate)); cxml::add_text_child(el, "Resolution", raw_convert(int(_resolution))); _frame->add_metadata (el); } @@ -298,7 +298,7 @@ bool DCPVideo::same (shared_ptr other) const { if (_frames_per_second != other->_frames_per_second || - _j2k_bandwidth != other->_j2k_bandwidth || + _video_bit_rate != other->_video_bit_rate || _resolution != other->_resolution) { return false; } diff --git a/src/lib/dcp_video.h b/src/lib/dcp_video.h index d07c8322b..92c155f0c 100644 --- a/src/lib/dcp_video.h +++ b/src/lib/dcp_video.h @@ -49,7 +49,7 @@ class PlayerVideo; class DCPVideo { public: - DCPVideo (std::shared_ptr, int index, int dcp_fps, int bandwidth, Resolution r); + DCPVideo(std::shared_ptr, int index, int dcp_fps, int64_t bit_rate, Resolution r); DCPVideo (std::shared_ptr, cxml::ConstNodePtr); DCPVideo (DCPVideo const&) = default; @@ -78,7 +78,7 @@ private: std::shared_ptr _frame; int _index; ///< frame index within the DCP's intrinsic duration int _frames_per_second; ///< Frames per second that we will use for the DCP - int _j2k_bandwidth; ///< J2K bandwidth to use + int64_t _video_bit_rate; ///< Video bit rate to use Resolution _resolution; ///< Resolution (2K or 4K) }; diff --git a/src/lib/film.cc b/src/lib/film.cc index fd703a72a..3de536a6d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -163,7 +163,7 @@ Film::Film (optional dir) , _resolution (Resolution::TWO_K) , _encrypted (false) , _context_id (dcp::make_uuid ()) - , _j2k_bandwidth (Config::instance()->default_j2k_bandwidth ()) + , _video_bit_rate(Config::instance()->default_video_bit_rate()) , _video_frame_rate (24) , _audio_channels (Config::instance()->default_dcp_audio_channels ()) , _three_d (false) @@ -240,7 +240,7 @@ Film::video_identifier () const + "_" + resolution_to_string (_resolution) + "_" + _playlist->video_identifier() + "_" + raw_convert(_video_frame_rate) - + "_" + raw_convert(j2k_bandwidth()); + + "_" + raw_convert(video_bit_rate()); if (encrypted ()) { /* This is insecure but hey, the key is in plaintext in metadata.xml */ @@ -397,7 +397,7 @@ Film::metadata (bool with_content_paths) const } cxml::add_text_child(root, "Resolution", resolution_to_string(_resolution)); - cxml::add_text_child(root, "J2KBandwidth", raw_convert(_j2k_bandwidth)); + cxml::add_text_child(root, "VideoBitRate", raw_convert(_video_bit_rate)); cxml::add_text_child(root, "VideoFrameRate", raw_convert(_video_frame_rate)); cxml::add_text_child(root, "AudioFrameRate", raw_convert(_audio_frame_rate)); cxml::add_text_child(root, "ISDCFDate", boost::gregorian::to_iso_string(_isdcf_date)); @@ -569,7 +569,11 @@ Film::read_metadata (optional path) } _resolution = string_to_resolution (f.string_child ("Resolution")); - _j2k_bandwidth = f.number_child ("J2KBandwidth"); + if (auto j2k = f.optional_number_child("J2KBandwidth")) { + _video_bit_rate = *j2k; + } else { + _video_bit_rate = f.number_child("VideoBitRate"); + } _video_frame_rate = f.number_child ("VideoFrameRate"); _audio_frame_rate = f.optional_number_child("AudioFrameRate").get_value_or(48000); _encrypted = f.bool_child ("Encrypted"); @@ -1169,10 +1173,10 @@ Film::set_resolution (Resolution r, bool explicit_user) void -Film::set_j2k_bandwidth (int b) +Film::set_video_bit_rate(int64_t bit_rate) { - FilmChangeSignaller ch(this, FilmProperty::J2K_BANDWIDTH); - _j2k_bandwidth = b; + FilmChangeSignaller ch(this, FilmProperty::VIDEO_BIT_RATE); + _video_bit_rate = bit_rate; } /** @param f New frame rate. @@ -1765,7 +1769,7 @@ Film::make_kdm(boost::filesystem::path cpl_file, dcp::LocalTime from, dcp::Local uint64_t Film::required_disk_space () const { - return _playlist->required_disk_space (shared_from_this(), j2k_bandwidth(), audio_channels(), audio_frame_rate()); + return _playlist->required_disk_space (shared_from_this(), video_bit_rate(), audio_channels(), audio_frame_rate()); } /** This method checks the disk that the Film is on and tries to decide whether or not @@ -1897,7 +1901,7 @@ Film::reels () const /* Integer-divide reel length by the size of one frame to give the number of frames per reel, * making sure we don't go less than 1s long. */ - Frame const reel_in_frames = max(_reel_length / ((j2k_bandwidth() / video_frame_rate()) / 8), static_cast(video_frame_rate())); + Frame const reel_in_frames = max(_reel_length / ((video_bit_rate() / video_frame_rate()) / 8), static_cast(video_frame_rate())); while (current < len) { DCPTime end = min (len, current + DCPTime::from_frames (reel_in_frames, video_frame_rate ())); periods.emplace_back(current, end); @@ -1941,7 +1945,7 @@ Film::use_template (string name) _dcp_content_type = _template_film->_dcp_content_type; _container = _template_film->_container; _resolution = _template_film->_resolution; - _j2k_bandwidth = _template_film->_j2k_bandwidth; + _video_bit_rate = _template_film->_video_bit_rate; _video_frame_rate = _template_film->_video_frame_rate; _encrypted = _template_film->_encrypted; _audio_channels = _template_film->_audio_channels; diff --git a/src/lib/film.h b/src/lib/film.h index 0a0c5a4e1..392f1dc5e 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -250,8 +250,8 @@ public: return _key; } - int j2k_bandwidth () const { - return _j2k_bandwidth; + int video_bit_rate() const { + return _video_bit_rate; } /** @return The frame rate of the DCP */ @@ -401,7 +401,7 @@ public: void set_container (Ratio const *, bool user_explicit = true); void set_resolution (Resolution, bool user_explicit = true); void set_encrypted (bool); - void set_j2k_bandwidth (int); + void set_video_bit_rate(int64_t); void set_video_frame_rate (int rate, bool user_explicit = false); void set_audio_channels (int); void set_three_d (bool); @@ -515,8 +515,8 @@ private: * re-start picture MXF encodes. */ std::string _context_id; - /** bandwidth for J2K files in bits per second */ - int _j2k_bandwidth; + /** bit rate for encoding video using J2K or MPEG2 in bits per second */ + int64_t _video_bit_rate; /** Frames per second to run our DCP at */ int _video_frame_rate; /** The date that we should use in a ISDCF name */ diff --git a/src/lib/film_property.h b/src/lib/film_property.h index 0841caa5c..b755a4887 100644 --- a/src/lib/film_property.h +++ b/src/lib/film_property.h @@ -39,7 +39,7 @@ enum class FilmProperty { CONTAINER, RESOLUTION, ENCRYPTED, - J2K_BANDWIDTH, + VIDEO_BIT_RATE, VIDEO_FRAME_RATE, AUDIO_FRAME_RATE, AUDIO_CHANNELS, diff --git a/src/lib/grok/context.h b/src/lib/grok/context.h index 521faae8d..fc9b74a57 100644 --- a/src/lib/grok/context.h +++ b/src/lib/grok/context.h @@ -226,7 +226,7 @@ public: device, _dcpomatic_context->film->resolution() == Resolution::FOUR_K, _dcpomatic_context->film->video_frame_rate(), - _dcpomatic_context->film->j2k_bandwidth(), + _dcpomatic_context->film->video_bit_rate(), grok.licence_server, grok.licence_port, grok.licence)) { diff --git a/src/lib/hints.cc b/src/lib/hints.cc index 7a6a2a4bf..fc59fa703 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -173,10 +173,10 @@ Hints::check_unusual_container () void -Hints::check_high_j2k_bandwidth () +Hints::check_high_video_bit_rate() { - if (film()->j2k_bandwidth() >= 245000000) { - hint (_("A few projectors have problems playing back very high bit-rate DCPs. It is a good idea to drop the JPEG2000 bandwidth down to about 200Mbit/s; this is unlikely to have any visible effect on the image.")); + if (film()->video_bit_rate() >= 245000000) { + hint (_("A few projectors have problems playing back very high bit-rate DCPs. It is a good idea to drop the video bit rate down to about 200Mbit/s; this is unlikely to have any visible effect on the image.")); } } @@ -468,7 +468,7 @@ try check_upmixers (); check_incorrect_container (); check_unusual_container (); - check_high_j2k_bandwidth (); + check_high_video_bit_rate(); check_frame_rate (); check_4k_3d (); check_speed_up (); diff --git a/src/lib/hints.h b/src/lib/hints.h index e7a6646ef..a46678af8 100644 --- a/src/lib/hints.h +++ b/src/lib/hints.h @@ -74,7 +74,7 @@ private: void check_upmixers (); void check_incorrect_container (); void check_unusual_container (); - void check_high_j2k_bandwidth (); + void check_high_video_bit_rate(); void check_frame_rate (); void check_4k_3d (); void check_speed_up (); diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index 6154dfb62..d5c7b3eed 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -310,7 +310,7 @@ J2KEncoder::encode (shared_ptr pv, DCPTime time) pv, position, _film->video_frame_rate(), - _film->j2k_bandwidth(), + _film->video_bit_rate(), _film->resolution() ); _queue.push_back (dcpv); diff --git a/src/lib/make_dcp.cc b/src/lib/make_dcp.cc index 41c5e8ec5..e4707721c 100644 --- a/src/lib/make_dcp.cc +++ b/src/lib/make_dcp.cc @@ -91,7 +91,7 @@ make_dcp (shared_ptr film, TranscodeJob::ChangedBehaviour behaviour) LOG_GENERAL ("Content: %1", content->technical_summary()); } LOG_GENERAL ("DCP video rate %1 fps", film->video_frame_rate()); - LOG_GENERAL ("J2K bandwidth %1", film->j2k_bandwidth()); + LOG_GENERAL("Video bit rate %1", film->video_bit_rate()); auto tj = make_shared(film, behaviour); tj->set_encoder(make_shared(film, tj)); diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 7f83e9474..d2af000e5 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -645,16 +645,16 @@ Playlist::move_later (shared_ptr film, shared_ptr c) int64_t -Playlist::required_disk_space (shared_ptr film, int j2k_bandwidth, int audio_channels, int audio_frame_rate) const +Playlist::required_disk_space(shared_ptr film, int64_t video_bit_rate, int audio_channels, int audio_frame_rate) const { - int64_t video = uint64_t(j2k_bandwidth / 8) * length(film).seconds(); + int64_t video = uint64_t(video_bit_rate / 8) * length(film).seconds(); int64_t audio = uint64_t(audio_channels) * audio_frame_rate * 3 * length(film).seconds(); for (auto i: content()) { auto d = dynamic_pointer_cast (i); if (d) { if (d->reference_video()) { - video -= uint64_t (j2k_bandwidth / 8) * d->length_after_trim(film).seconds(); + video -= uint64_t(video_bit_rate / 8) * d->length_after_trim(film).seconds(); } if (d->reference_audio()) { audio -= uint64_t(audio_channels) * audio_frame_rate * 3 * d->length_after_trim(film).seconds(); diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 7b9bd19fa..3868c0b51 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -65,7 +65,7 @@ public: dcpomatic::DCPTime length (std::shared_ptr film) const; boost::optional start () const; - int64_t required_disk_space (std::shared_ptr film, int j2k_bandwidth, int audio_channels, int audio_frame_rate) const; + int64_t required_disk_space(std::shared_ptr film, int64_t video_bit_rate, int audio_channels, int audio_frame_rate) const; int best_video_frame_rate () const; dcpomatic::DCPTime video_end (std::shared_ptr film) const; diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index 9eec498f9..b59348908 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -94,7 +94,7 @@ print_dump (shared_ptr film) { cout << film->dcp_name (true) << "\n" << film->container()->container_nickname() << " at " << ((film->resolution() == Resolution::TWO_K) ? "2K" : "4K") << "\n" - << (film->j2k_bandwidth() / 1000000) << "Mbit/s" << "\n" + << (film->video_bit_rate() / 1000000) << "Mbit/s" << "\n" << "Duration " << (film->length().timecode(film->video_frame_rate())) << "\n" << "Output " << film->video_frame_rate() << "fps " << (film->three_d() ? "3D" : "2D") << " " << (film->audio_frame_rate() / 1000) << "kHz\n" << (film->interop() ? "Inter-Op" : "SMPTE") << " " << (film->encrypted() ? "encrypted" : "unencrypted") << "\n"; diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 781c95de7..c2f32fbb9 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -253,13 +253,13 @@ DCPPanel::name_changed () void -DCPPanel::j2k_bandwidth_changed () +DCPPanel::video_bit_rate_changed() { if (!_film) { return; } - _film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000); + _film->set_video_bit_rate(_video_bit_rate->GetValue() * 1000000); } @@ -385,8 +385,8 @@ DCPPanel::film_changed(FilmProperty p) setup_container (); setup_dcp_name (); break; - case FilmProperty::J2K_BANDWIDTH: - checked_set (_j2k_bandwidth, _film->j2k_bandwidth() / 1000000); + case FilmProperty::VIDEO_BIT_RATE: + checked_set(_video_bit_rate, _film->video_bit_rate() / 1000000); break; case FilmProperty::USE_ISDCF_NAME: { @@ -605,7 +605,7 @@ DCPPanel::set_film (shared_ptr film) film_changed(FilmProperty::CONTAINER); film_changed(FilmProperty::RESOLUTION); film_changed(FilmProperty::ENCRYPTED); - film_changed(FilmProperty::J2K_BANDWIDTH); + film_changed(FilmProperty::VIDEO_BIT_RATE); film_changed(FilmProperty::VIDEO_FRAME_RATE); film_changed(FilmProperty::AUDIO_CHANNELS); film_changed(FilmProperty::SEQUENCE); @@ -649,7 +649,7 @@ DCPPanel::setup_sensitivity () _frame_rate_spin->Enable (_generally_sensitive && _film && !_film->references_dcp_video() && !_film->contains_atmos_content()); _audio_channels->Enable (_generally_sensitive && _film && !_film->references_dcp_audio()); _audio_processor->Enable (_generally_sensitive && _film && !_film->references_dcp_audio()); - _j2k_bandwidth->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); + _video_bit_rate->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); _container->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); _best_frame_rate->Enable ( _generally_sensitive && @@ -732,7 +732,7 @@ DCPPanel::reencode_j2k_changed () void DCPPanel::config_changed (Config::Property p) { - _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000); + _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate() / 1000000); setup_frame_rate_widget (); if (p == Config::SHOW_EXPERIMENTAL_AUDIO_PROCESSORS) { @@ -791,8 +791,8 @@ DCPPanel::make_video_panel () _three_d = new CheckBox (panel, _("3D")); - _j2k_bandwidth_label = create_label (panel, _("JPEG2000 bandwidth\nfor newly-encoded data"), true); - _j2k_bandwidth = new SpinCtrl (panel, DCPOMATIC_SPIN_CTRL_WIDTH); + _video_bit_rate_label = create_label(panel, _("Video bit rate\nfor newly-encoded data"), true); + _video_bit_rate = new SpinCtrl(panel, DCPOMATIC_SPIN_CTRL_WIDTH); _mbits_label = create_label (panel, _("Mbit/s"), false); _reencode_j2k = new CheckBox (panel, _("Re-encode JPEG2000 data from input")); @@ -801,9 +801,9 @@ DCPPanel::make_video_panel () _frame_rate_choice->Bind (wxEVT_CHOICE, boost::bind(&DCPPanel::frame_rate_choice_changed, this)); _frame_rate_spin->Bind (wxEVT_SPINCTRL, boost::bind(&DCPPanel::frame_rate_spin_changed, this)); _best_frame_rate->Bind (wxEVT_BUTTON, boost::bind(&DCPPanel::best_frame_rate_clicked, this)); - _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind(&DCPPanel::j2k_bandwidth_changed, this)); + _video_bit_rate->Bind (wxEVT_SPINCTRL, boost::bind(&DCPPanel::video_bit_rate_changed, this)); /* Also listen to wxEVT_TEXT so that typing numbers directly in is always noticed */ - _j2k_bandwidth->Bind (wxEVT_TEXT, boost::bind(&DCPPanel::j2k_bandwidth_changed, this)); + _video_bit_rate->Bind (wxEVT_TEXT, boost::bind(&DCPPanel::video_bit_rate_changed, this)); _resolution->Bind (wxEVT_CHOICE, boost::bind(&DCPPanel::resolution_changed, this)); _three_d->bind(&DCPPanel::three_d_changed, this); _reencode_j2k->bind(&DCPPanel::reencode_j2k_changed, this); @@ -816,7 +816,7 @@ DCPPanel::make_video_panel () _frame_rate_choice->add(boost::lexical_cast(i)); } - _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000); + _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate() / 1000000); _frame_rate_spin->SetRange (1, 480); _resolution->add(_("2K")); @@ -860,9 +860,9 @@ DCPPanel::add_video_panel_to_grid () _video_grid->Add (_three_d, wxGBPosition (r, 0), wxGBSpan (1, 2)); ++r; - add_label_to_sizer (_video_grid, _j2k_bandwidth_label, true, wxGBPosition (r, 0)); + add_label_to_sizer(_video_grid, _video_bit_rate_label, true, wxGBPosition (r, 0)); auto s = new wxBoxSizer (wxHORIZONTAL); - s->Add (_j2k_bandwidth, 0, wxALIGN_CENTER_VERTICAL); + s->Add(_video_bit_rate, 0, wxALIGN_CENTER_VERTICAL); add_label_to_sizer (s, _mbits_label, false, 0, wxLEFT | wxALIGN_CENTER_VERTICAL); _video_grid->Add (s, wxGBPosition(r, 1), wxDefaultSpan); ++r; diff --git a/src/wx/dcp_panel.h b/src/wx/dcp_panel.h index 6c97a41c3..c686a9c55 100644 --- a/src/wx/dcp_panel.h +++ b/src/wx/dcp_panel.h @@ -71,7 +71,7 @@ private: void copy_isdcf_name_button_clicked (); void container_changed (); void dcp_content_type_changed (); - void j2k_bandwidth_changed (); + void video_bit_rate_changed(); void frame_rate_choice_changed (); void frame_rate_spin_changed (); void best_frame_rate_clicked (); @@ -129,9 +129,9 @@ private: Choice* _container; wxStaticText* _container_size; wxButton* _copy_isdcf_name_button; - wxStaticText* _j2k_bandwidth_label; + wxStaticText* _video_bit_rate_label; wxStaticText* _mbits_label; - wxSpinCtrl* _j2k_bandwidth; + wxSpinCtrl* _video_bit_rate; wxStaticText* _dcp_content_type_label; Choice* _dcp_content_type; wxStaticText* _frame_rate_label; diff --git a/src/wx/full_config_dialog.cc b/src/wx/full_config_dialog.cc index 193392f29..c3c194fbc 100644 --- a/src/wx/full_config_dialog.cc +++ b/src/wx/full_config_dialog.cc @@ -322,8 +322,8 @@ private: { add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); auto s = new wxBoxSizer (wxHORIZONTAL); - _j2k_bandwidth = new wxSpinCtrl (_panel); - s->Add (_j2k_bandwidth); + _video_bit_rate = new wxSpinCtrl(_panel); + s->Add(_video_bit_rate); add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); table->Add (s, 1); } @@ -410,8 +410,8 @@ private: _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this)); _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this)); - _j2k_bandwidth->SetRange (50, 250); - _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this)); + _video_bit_rate->SetRange(50, 250); + _video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&DefaultsPage::video_bit_rate_changed, this)); _audio_delay->SetRange (-1000, 1000); _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this)); @@ -451,8 +451,8 @@ private: _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ())); _kdm_type->set (config->default_kdm_type()); checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default()); - checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000); - _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000); + checked_set(_video_bit_rate, config->default_video_bit_rate() / 1000000); + _video_bit_rate->SetRange(50, config->maximum_video_bit_rate() / 1000000); checked_set (_dcp_audio_channels, locale_convert (config->default_dcp_audio_channels())); checked_set (_audio_delay, config->default_audio_delay ()); checked_set (_standard, config->default_interop() ? 1 : 0); @@ -527,9 +527,9 @@ private: config->set_default_kdm_duration (RoughDuration(duration, unit)); } - void j2k_bandwidth_changed () + void video_bit_rate_changed() { - Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000); + Config::instance()->set_default_video_bit_rate(_video_bit_rate->GetValue() * 1000000); } void audio_delay_changed () @@ -634,7 +634,7 @@ private: } } - wxSpinCtrl* _j2k_bandwidth; + wxSpinCtrl* _video_bit_rate; wxSpinCtrl* _audio_delay; wxSpinCtrl* _still_length; #ifdef DCPOMATIC_USE_OWN_PICKER @@ -1543,8 +1543,8 @@ private: { add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); auto s = new wxBoxSizer(wxHORIZONTAL); - _maximum_j2k_bandwidth = new wxSpinCtrl(_panel); - s->Add(_maximum_j2k_bandwidth, 1); + _maximum_video_bit_rate = new wxSpinCtrl(_panel); + s->Add(_maximum_video_bit_rate, 1); add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL); table->Add(s, 1); } @@ -1579,8 +1579,8 @@ private: table->Add(s, 1); } - _maximum_j2k_bandwidth->SetRange(1, 1000); - _maximum_j2k_bandwidth->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_bandwidth_changed, this)); + _maximum_video_bit_rate->SetRange(1, 1000); + _maximum_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_video_bit_rate_changed, this)); _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this); _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this); _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this); @@ -1594,7 +1594,7 @@ private: { auto config = Config::instance(); - checked_set(_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000); + checked_set(_maximum_video_bit_rate, config->maximum_video_bit_rate() / 1000000); checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate()); checked_set(_allow_any_container, config->allow_any_container()); checked_set(_allow_96khz_audio, config->allow_96khz_audio()); @@ -1603,9 +1603,9 @@ private: checked_set(_isdcf_name_part_length, config->isdcf_name_part_length()); } - void maximum_j2k_bandwidth_changed() + void maximum_video_bit_rate_changed() { - Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000); + Config::instance()->set_maximum_video_bit_rate(_maximum_video_bit_rate->GetValue() * 1000000); } void allow_any_dcp_frame_rate_changed() @@ -1638,7 +1638,7 @@ private: Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue()); } - wxSpinCtrl* _maximum_j2k_bandwidth = nullptr; + wxSpinCtrl* _maximum_video_bit_rate = nullptr; CheckBox* _allow_any_dcp_frame_rate = nullptr; CheckBox* _allow_any_container = nullptr; CheckBox* _allow_96khz_audio = nullptr; diff --git a/test/create_cli_test.cc b/test/create_cli_test.cc index aae5fb6de..09f1a4538 100644 --- a/test/create_cli_test.cc +++ b/test/create_cli_test.cc @@ -179,11 +179,11 @@ BOOST_AUTO_TEST_CASE (create_cli_test) BOOST_CHECK_EQUAL(cc._fourk, true); BOOST_CHECK (!cc.error); - cc = run ("dcpomatic2_create --j2k-bandwidth 120 foo.mp4"); + cc = run ("dcpomatic2_create --video-bit-rate 120 foo.mp4"); BOOST_REQUIRE_EQUAL (cc.content.size(), 1U); BOOST_CHECK_EQUAL (cc.content[0].path, "foo.mp4"); - BOOST_REQUIRE(cc._j2k_bandwidth); - BOOST_CHECK_EQUAL(*cc._j2k_bandwidth, 120000000); + BOOST_REQUIRE(cc._video_bit_rate); + BOOST_CHECK_EQUAL(*cc._video_bit_rate, 120000000); BOOST_CHECK (!cc.error); cc = run ("dcpomatic2_create --channel L fred.wav --channel R jim.wav sheila.wav"); diff --git a/test/film_metadata_test.cc b/test/film_metadata_test.cc index 2bd60dc81..2f1346d1d 100644 --- a/test/film_metadata_test.cc +++ b/test/film_metadata_test.cc @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) film->set_name ("fred"); film->set_dcp_content_type (DCPContentType::from_isdcf_name ("SHR")); film->set_container (Ratio::from_id ("185")); - film->set_j2k_bandwidth (200000000); + film->set_video_bit_rate(200000000); film->set_interop (false); film->set_chain (string("")); film->set_distributor (string("")); diff --git a/test/j2k_bandwidth_test.cc b/test/j2k_bandwidth_test.cc deleted file mode 100644 index f9e47c4b9..000000000 --- a/test/j2k_bandwidth_test.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 2016-2021 Carl Hetherington - - This file is part of DCP-o-matic. - - DCP-o-matic is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - DCP-o-matic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DCP-o-matic. If not, see . - -*/ - - -/** @file test/bandwidth_test.cc - * @brief Test whether we output whatever J2K bandwidth is requested. - * @ingroup feature - */ - - -#include "test.h" -#include "lib/dcp_content_type.h" -#include "lib/film.h" -#include "lib/image_content.h" -#include "lib/video_content.h" -#include -#include - - -using std::make_shared; -using std::string; - - -static void -check (int target_bits_per_second) -{ - int const duration = 10; - - string const name = "bandwidth_test_" + dcp::raw_convert (target_bits_per_second); - auto film = new_test_film (name); - film->set_name (name); - film->set_dcp_content_type (DCPContentType::from_isdcf_name ("FTR")); - film->set_j2k_bandwidth (target_bits_per_second); - auto content = make_shared(TestPaths::private_data() / "prophet_frame.tiff"); - film->examine_and_add_content (content); - BOOST_REQUIRE (!wait_for_jobs()); - content->video->set_length (24 * duration); - make_and_verify_dcp ( - film, - { - dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE, - dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE, - dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, - dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, - dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE, - }, - target_bits_per_second <= 250000000, - target_bits_per_second <= 250000000 - ); - - boost::filesystem::directory_iterator i (boost::filesystem::path("build") / "test" / name / "video"); - boost::filesystem::path test = *i++; - BOOST_REQUIRE (i == boost::filesystem::directory_iterator()); - - double actual_bits_per_second = boost::filesystem::file_size(test) * 8.0 / duration; - - /* Check that we're within 85% to 115% of target on average */ - BOOST_CHECK ((actual_bits_per_second / target_bits_per_second) > 0.85); - BOOST_CHECK ((actual_bits_per_second / target_bits_per_second) < 1.15); -} - - -BOOST_AUTO_TEST_CASE (bandwidth_test) -{ - check (50000000); - check (100000000); - check (150000000); - check (200000000); - check (250000000); - check (300000000); - check (350000000); - check (400000000); - check (450000000); - check (500000000); -} diff --git a/test/j2k_video_bit_rate_test.cc b/test/j2k_video_bit_rate_test.cc new file mode 100644 index 000000000..67579a369 --- /dev/null +++ b/test/j2k_video_bit_rate_test.cc @@ -0,0 +1,92 @@ +/* + Copyright (C) 2016-2021 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +/** @file test/bandwidth_test.cc + * @brief Test whether we output whatever J2K bandwidth is requested. + * @ingroup feature + */ + + +#include "test.h" +#include "lib/dcp_content_type.h" +#include "lib/film.h" +#include "lib/image_content.h" +#include "lib/video_content.h" +#include +#include + + +using std::make_shared; +using std::string; + + +static void +check (int target_bits_per_second) +{ + int const duration = 10; + + string const name = "bandwidth_test_" + dcp::raw_convert (target_bits_per_second); + auto film = new_test_film (name); + film->set_name (name); + film->set_dcp_content_type (DCPContentType::from_isdcf_name ("FTR")); + film->set_video_bit_rate(target_bits_per_second); + auto content = make_shared(TestPaths::private_data() / "prophet_frame.tiff"); + film->examine_and_add_content (content); + BOOST_REQUIRE (!wait_for_jobs()); + content->video->set_length (24 * duration); + make_and_verify_dcp ( + film, + { + dcp::VerificationNote::Code::MISSING_FFMC_IN_FEATURE, + dcp::VerificationNote::Code::MISSING_FFEC_IN_FEATURE, + dcp::VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, + dcp::VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, + dcp::VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE, + }, + target_bits_per_second <= 250000000, + target_bits_per_second <= 250000000 + ); + + boost::filesystem::directory_iterator i (boost::filesystem::path("build") / "test" / name / "video"); + boost::filesystem::path test = *i++; + BOOST_REQUIRE (i == boost::filesystem::directory_iterator()); + + double actual_bits_per_second = boost::filesystem::file_size(test) * 8.0 / duration; + + /* Check that we're within 85% to 115% of target on average */ + BOOST_CHECK ((actual_bits_per_second / target_bits_per_second) > 0.85); + BOOST_CHECK ((actual_bits_per_second / target_bits_per_second) < 1.15); +} + + +BOOST_AUTO_TEST_CASE (bandwidth_test) +{ + check (50000000); + check (100000000); + check (150000000); + check (200000000); + check (250000000); + check (300000000); + check (350000000); + check (400000000); + check (450000000); + check (500000000); +} diff --git a/test/reels_test.cc b/test/reels_test.cc index df4bbbbe6..5fcddfe78 100644 --- a/test/reels_test.cc +++ b/test/reels_test.cc @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE (reels_test1) BOOST_CHECK_EQUAL (r.back().from.get(), 288000); BOOST_CHECK_EQUAL (r.back().to.get(), 288000 * 2); - film->set_j2k_bandwidth (100000000); + film->set_video_bit_rate(100000000); film->set_reel_type (ReelType::BY_LENGTH); /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */ film->set_reel_length (31253154); @@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE (reels_test6) auto A = make_shared("test/data/test2.mp4"); auto film = new_test_film2 ("reels_test6", {A}); - film->set_j2k_bandwidth (100000000); + film->set_video_bit_rate(100000000); film->set_reel_type (ReelType::BY_LENGTH); /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */ film->set_reel_length (31253154); diff --git a/test/required_disk_space_test.cc b/test/required_disk_space_test.cc index b704ccef2..bd969bdb2 100644 --- a/test/required_disk_space_test.cc +++ b/test/required_disk_space_test.cc @@ -45,7 +45,7 @@ void check_within_n (int64_t a, int64_t b, int64_t n) BOOST_AUTO_TEST_CASE (required_disk_space_test) { auto film = new_test_film ("required_disk_space_test"); - film->set_j2k_bandwidth (100000000); + film->set_video_bit_rate(100000000); film->set_audio_channels(8); film->set_reel_type (ReelType::BY_VIDEO_CONTENT); auto content_a = content_factory("test/data/flat_blue.png")[0]; diff --git a/test/test.cc b/test/test.cc index 64a48b714..1d5eb9083 100644 --- a/test/test.cc +++ b/test/test.cc @@ -122,7 +122,7 @@ setup_test_config () Config::instance()->set_server_port_base (61921); Config::instance()->set_default_dcp_content_type (static_cast (0)); Config::instance()->set_default_audio_delay (0); - Config::instance()->set_default_j2k_bandwidth (100000000); + Config::instance()->set_default_video_bit_rate(100000000); Config::instance()->set_default_interop (false); Config::instance()->set_default_still_length (10); Config::instance()->set_default_dcp_audio_channels(8); diff --git a/test/wscript b/test/wscript index eb8901338..3acca09e8 100644 --- a/test/wscript +++ b/test/wscript @@ -111,9 +111,9 @@ def build(bld): import_dcp_test.cc interrupt_encoder_test.cc isdcf_name_test.cc - j2k_bandwidth_test.cc j2k_encode_threading_test.cc job_manager_test.cc + j2k_video_bit_rate_test.cc kdm_cli_test.cc kdm_naming_test.cc kdm_util_test.cc -- cgit v1.2.3 From 5b2e3126602d508498a99bce256f5f465f095d43 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 30 Nov 2023 00:46:00 +0100 Subject: 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)); } } -- cgit v1.2.3 From f72a79c93626e773214f1a0318adf2445ac2ee72 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 19 Mar 2024 14:02:47 +0100 Subject: Support encoding of MPEG2 DCPs. --- src/lib/dcp_film_encoder.cc | 11 ++++- src/lib/film.cc | 16 +++++++ src/lib/film.h | 7 +++ src/lib/film_property.h | 1 + src/lib/mpeg2_encoder.cc | 80 +++++++++++++++++++++++++++++++ src/lib/mpeg2_encoder.h | 42 ++++++++++++++++ src/lib/reel_writer.cc | 114 ++++++++++++++++++++++++++++++-------------- src/lib/reel_writer.h | 13 +++-- src/lib/video_encoding.cc | 56 ++++++++++++++++++++++ src/lib/video_encoding.h | 34 +++++++++++++ src/lib/writer.cc | 14 ++++-- src/lib/writer.h | 7 ++- src/lib/wscript | 2 + src/wx/dcp_panel.cc | 16 ++++++- test/burnt_subtitle_test.cc | 2 +- test/data | 2 +- test/overlap_video_test.cc | 2 +- 17 files changed, 369 insertions(+), 50 deletions(-) create mode 100644 src/lib/mpeg2_encoder.cc create mode 100644 src/lib/mpeg2_encoder.h create mode 100644 src/lib/video_encoding.cc create mode 100644 src/lib/video_encoding.h diff --git a/src/lib/dcp_film_encoder.cc b/src/lib/dcp_film_encoder.cc index b508b66b6..17f531693 100644 --- a/src/lib/dcp_film_encoder.cc +++ b/src/lib/dcp_film_encoder.cc @@ -33,6 +33,7 @@ #include "film.h" #include "j2k_encoder.h" #include "job.h" +#include "mpeg2_encoder.h" #include "player.h" #include "player_video.h" #include "referenced_reel_asset.h" @@ -67,10 +68,18 @@ using namespace dcpomatic; DCPFilmEncoder::DCPFilmEncoder(shared_ptr film, weak_ptr job) : FilmEncoder(film, job) , _writer(film, job) - , _encoder(new J2KEncoder(film, _writer)) , _finishing (false) , _non_burnt_subtitles (false) { + switch (_film->video_encoding()) { + case VideoEncoding::JPEG2000: + _encoder.reset(new J2KEncoder(film, _writer)); + break; + case VideoEncoding::MPEG2: + _encoder.reset(new MPEG2Encoder(film, _writer)); + break; + } + _player_video_connection = _player.Video.connect(bind(&DCPFilmEncoder::video, this, _1, _2)); _player_audio_connection = _player.Audio.connect(bind(&DCPFilmEncoder::audio, this, _1, _2)); _player_text_connection = _player.Text.connect(bind(&DCPFilmEncoder::text, this, _1, _2, _3, _4)); diff --git a/src/lib/film.cc b/src/lib/film.cc index 3de536a6d..54c68d756 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -169,6 +169,7 @@ Film::Film (optional dir) , _three_d (false) , _sequence (true) , _interop (Config::instance()->default_interop ()) + , _video_encoding(VideoEncoding::JPEG2000) , _limit_to_smpte_bv20(false) , _audio_processor (0) , _reel_type (ReelType::SINGLE) @@ -251,6 +252,9 @@ Film::video_identifier () const if (_interop) { s += "_I"; + if (_video_encoding == VideoEncoding::MPEG2) { + s += "_M"; + } } else { s += "_S"; if (_limit_to_smpte_bv20) { @@ -405,6 +409,7 @@ Film::metadata (bool with_content_paths) const cxml::add_text_child(root, "ThreeD", _three_d ? "1" : "0"); cxml::add_text_child(root, "Sequence", _sequence ? "1" : "0"); cxml::add_text_child(root, "Interop", _interop ? "1" : "0"); + cxml::add_text_child(root, "VideoEncoding", video_encoding_to_string(_video_encoding)); cxml::add_text_child(root, "LimitToSMPTEBv20", _limit_to_smpte_bv20 ? "1" : "0"); cxml::add_text_child(root, "Encrypted", _encrypted ? "1" : "0"); cxml::add_text_child(root, "Key", _key.hex ()); @@ -595,6 +600,9 @@ Film::read_metadata (optional path) _three_d = f.bool_child ("ThreeD"); _interop = f.bool_child ("Interop"); + if (auto encoding = f.optional_string_child("VideoEncoding")) { + _video_encoding = video_encoding_from_string(*encoding); + } _limit_to_smpte_bv20 = f.optional_bool_child("LimitToSMPTEBv20").get_value_or(false); _key = dcp::Key (f.string_child ("Key")); _context_id = f.optional_string_child("ContextID").get_value_or (dcp::make_uuid ()); @@ -1219,6 +1227,14 @@ Film::set_interop (bool i) } +void +Film::set_video_encoding(VideoEncoding encoding) +{ + FilmChangeSignaller ch(this, FilmProperty::VIDEO_ENCODING); + _video_encoding = encoding; +} + + void Film::set_limit_to_smpte_bv20(bool limit) { diff --git a/src/lib/film.h b/src/lib/film.h index 392f1dc5e..ff3dee6fc 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -41,6 +41,7 @@ #include "transcode_job.h" #include "types.h" #include "util.h" +#include "video_encoding.h" #include #include #include @@ -275,6 +276,10 @@ public: return _interop; } + VideoEncoding video_encoding() const { + return _video_encoding; + } + bool limit_to_smpte_bv20() const { return _limit_to_smpte_bv20; } @@ -408,6 +413,7 @@ public: void set_isdcf_date_today (); void set_sequence (bool); void set_interop (bool); + void set_video_encoding(VideoEncoding encoding); void set_limit_to_smpte_bv20(bool); void set_audio_processor (AudioProcessor const * processor); void set_reel_type (ReelType); @@ -529,6 +535,7 @@ private: bool _three_d; bool _sequence; bool _interop; + VideoEncoding _video_encoding; bool _limit_to_smpte_bv20; AudioProcessor const * _audio_processor; ReelType _reel_type; diff --git a/src/lib/film_property.h b/src/lib/film_property.h index b755a4887..ebda0e807 100644 --- a/src/lib/film_property.h +++ b/src/lib/film_property.h @@ -47,6 +47,7 @@ enum class FilmProperty { THREE_D, SEQUENCE, INTEROP, + VIDEO_ENCODING, LIMIT_TO_SMPTE_BV20, AUDIO_PROCESSOR, REEL_TYPE, diff --git a/src/lib/mpeg2_encoder.cc b/src/lib/mpeg2_encoder.cc new file mode 100644 index 000000000..49bff19d4 --- /dev/null +++ b/src/lib/mpeg2_encoder.cc @@ -0,0 +1,80 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "mpeg2_encoder.h" +#include "writer.h" +#include +extern "C" { +#include +} + + +using std::shared_ptr; + + +MPEG2Encoder::MPEG2Encoder(shared_ptr film, Writer& writer) + : VideoEncoder(film, writer) + , _transcoder(film->frame_size(), film->video_frame_rate(), film->video_bit_rate()) +{ + +} + + +void +MPEG2Encoder::encode(shared_ptr pv, dcpomatic::DCPTime time) +{ + VideoEncoder::encode(pv, time); + + auto image = pv->image( + [](AVPixelFormat) { return AV_PIX_FMT_YUV420P; }, + VideoRange::VIDEO, + false + ); + + dcp::FFmpegImage ffmpeg_image(time.get() * _film->video_frame_rate() / dcpomatic::DCPTime::HZ); + + DCPOMATIC_ASSERT(image->size() == ffmpeg_image.size()); + + auto height = image->size().height; + + for (int y = 0; y < height; ++y) { + memcpy(ffmpeg_image.y() + ffmpeg_image.y_stride() * y, image->data()[0] + image->stride()[0] * y, ffmpeg_image.y_stride()); + } + + for (int y = 0; y < height / 2; ++y) { + memcpy(ffmpeg_image.u() + ffmpeg_image.u_stride() * y, image->data()[1] + image->stride()[1] * y, ffmpeg_image.u_stride()); + memcpy(ffmpeg_image.v() + ffmpeg_image.v_stride() * y, image->data()[2] + image->stride()[2] * y, ffmpeg_image.v_stride()); + } + + if (auto compressed = _transcoder.compress_frame(std::move(ffmpeg_image))) { + _writer.write(compressed->first, compressed->second); + } +} + + +void +MPEG2Encoder::end() +{ + if (auto compressed = _transcoder.flush()) { + _writer.write(compressed->first, compressed->second); + } +} + diff --git a/src/lib/mpeg2_encoder.h b/src/lib/mpeg2_encoder.h new file mode 100644 index 000000000..1b2259d26 --- /dev/null +++ b/src/lib/mpeg2_encoder.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "video_encoder.h" +#include + + +class MPEG2Encoder : public VideoEncoder +{ +public: + MPEG2Encoder(std::shared_ptr film, Writer& writer); + + void encode(std::shared_ptr pv, dcpomatic::DCPTime time) override; + + void pause() override {} + void resume() override {} + + /** Called when a processing run has finished */ + void end() override; + +private: + dcp::MPEG2Compressor _transcoder; +}; + diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 201c23e71..8dc0d7f06 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -146,30 +146,45 @@ ReelWriter::ReelWriter ( dcp::filesystem::rename(asset.string() + ".tmp", asset); } + auto const rate = dcp::Fraction(film()->video_frame_rate(), 1); - if (film()->three_d()) { - _picture_asset = std::make_shared(dcp::Fraction(film()->video_frame_rate(), 1), standard); - } else { - _picture_asset = std::make_shared(dcp::Fraction(film()->video_frame_rate(), 1), standard); - } + auto setup = [this](shared_ptr asset) { + asset->set_size(film()->frame_size()); + asset->set_metadata(mxf_metadata()); - _picture_asset->set_size (film()->frame_size()); - _picture_asset->set_metadata (mxf_metadata()); + if (film()->encrypted()) { + asset->set_key(film()->key()); + asset->set_context_id(film()->context_id()); + } + }; - if (film()->encrypted()) { - _picture_asset->set_key (film()->key()); - _picture_asset->set_context_id (film()->context_id()); + if (film()->video_encoding() == VideoEncoding::JPEG2000) { + if (film()->three_d()) { + _j2k_picture_asset = std::make_shared(rate, standard); + } else { + _j2k_picture_asset = std::make_shared(rate, standard); + } + setup(_j2k_picture_asset); + _j2k_picture_asset->set_file(asset); + _j2k_picture_asset_writer = _j2k_picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW); + } else { + _mpeg2_picture_asset = std::make_shared(rate); + setup(_mpeg2_picture_asset); + _mpeg2_picture_asset->set_file(asset); + _mpeg2_picture_asset_writer = _mpeg2_picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW); } - _picture_asset->set_file (asset); - _picture_asset_writer = _picture_asset->start_write(asset, _first_nonexistent_frame > 0 ? dcp::Behaviour::OVERWRITE_EXISTING : dcp::Behaviour::MAKE_NEW); } else if (!text_only) { /* We already have a complete picture asset that we can just re-use */ /* XXX: what about if the encryption key changes? */ - if (film()->three_d()) { - _picture_asset = make_shared(asset); + if (film()->video_encoding() == VideoEncoding::JPEG2000) { + if (film()->three_d()) { + _j2k_picture_asset = make_shared(asset); + } else { + _j2k_picture_asset = make_shared(asset); + } } else { - _picture_asset = make_shared(asset); + _mpeg2_picture_asset = make_shared(asset); } } @@ -272,7 +287,7 @@ ReelWriter::check_existing_picture_asset (boost::filesystem::path asset) void ReelWriter::write (shared_ptr encoded, Frame frame, Eyes eyes) { - if (!_picture_asset_writer) { + if (!_j2k_picture_asset_writer) { /* We're not writing any data */ return; } @@ -300,21 +315,28 @@ ReelWriter::write (shared_ptr atmos, AtmosMetadata metada void -ReelWriter::fake_write (int size) +ReelWriter::write(shared_ptr image) +{ + _mpeg2_picture_asset_writer->write(image->data(), image->size()); +} + + +void +ReelWriter::fake_write(dcp::J2KFrameInfo const& info) { - if (!_picture_asset_writer) { + if (!_j2k_picture_asset_writer) { /* We're not writing any data */ return; } - _picture_asset_writer->fake_write (size); + _j2k_picture_asset_writer->fake_write(info); } void ReelWriter::repeat_write (Frame frame, Eyes eyes) { - if (!_picture_asset_writer) { + if (!_j2k_picture_asset_writer) { /* We're not writing any data */ return; } @@ -327,10 +349,16 @@ ReelWriter::repeat_write (Frame frame, Eyes eyes) void ReelWriter::finish (boost::filesystem::path output_dcp) { - if (_picture_asset_writer && !_picture_asset_writer->finalize ()) { - /* Nothing was written to the picture asset */ - LOG_GENERAL ("Nothing was written to reel %1 of %2", _reel_index, _reel_count); - _picture_asset.reset (); + if (_j2k_picture_asset_writer && !_j2k_picture_asset_writer->finalize()) { + /* Nothing was written to the J2K picture asset */ + LOG_GENERAL("Nothing was written to J2K asset for reel %1 of %2", _reel_index, _reel_count); + _j2k_picture_asset.reset(); + } + + if (_mpeg2_picture_asset_writer && !_mpeg2_picture_asset_writer->finalize()) { + /* Nothing was written to the MPEG2 picture asset */ + LOG_GENERAL("Nothing was written to MPEG2 asset for reel %1 of %2", _reel_index, _reel_count); + _mpeg2_picture_asset.reset(); } if (_sound_asset_writer && !_sound_asset_writer->finalize ()) { @@ -338,12 +366,21 @@ ReelWriter::finish (boost::filesystem::path output_dcp) _sound_asset.reset (); } + shared_ptr picture_asset; + if (_j2k_picture_asset) { + picture_asset = _j2k_picture_asset; + } else if (_mpeg2_picture_asset) { + picture_asset = _mpeg2_picture_asset; + } + /* Hard-link any video asset file into the DCP */ - if (_picture_asset) { - DCPOMATIC_ASSERT (_picture_asset->file()); - boost::filesystem::path video_from = _picture_asset->file().get(); - boost::filesystem::path video_to = output_dcp; - video_to /= video_asset_filename (_picture_asset, _reel_index, _reel_count, _content_summary); + if (picture_asset) { + auto const file = picture_asset->file(); + DCPOMATIC_ASSERT(file); + + auto video_from = *file; + auto video_to = output_dcp; + video_to /= video_asset_filename(picture_asset, _reel_index, _reel_count, _content_summary); /* There may be an existing "to" file if we are recreating a DCP in the same place without changing any video. */ @@ -371,7 +408,7 @@ ReelWriter::finish (boost::filesystem::path output_dcp) } } - _picture_asset->set_file (video_to); + picture_asset->set_file(video_to); } /* Move the audio asset into the DCP */ @@ -495,17 +532,17 @@ ReelWriter::create_reel_picture (shared_ptr reel, list reel_asset; - if (_picture_asset) { + if (_j2k_picture_asset) { /* We have made a picture asset of our own. Put it into the reel */ - auto mono = dynamic_pointer_cast(_picture_asset); - if (mono) { + if (auto mono = dynamic_pointer_cast(_j2k_picture_asset)) { reel_asset = make_shared(mono, 0); } - auto stereo = dynamic_pointer_cast(_picture_asset); - if (stereo) { + if (auto stereo = dynamic_pointer_cast(_j2k_picture_asset)) { reel_asset = make_shared(stereo, 0); } + } else if (_mpeg2_picture_asset) { + reel_asset = make_shared(_mpeg2_picture_asset, 0); } else { LOG_GENERAL ("no picture asset of our own; look through %1", refs.size()); /* We don't have a picture asset of our own; hopefully we have one to reference */ @@ -734,8 +771,11 @@ try { vector> assets; - if (_picture_asset) { - assets.push_back(_picture_asset); + if (_j2k_picture_asset) { + assets.push_back(_j2k_picture_asset); + } + if (_mpeg2_picture_asset) { + assets.push_back(_mpeg2_picture_asset); } if (_sound_asset) { assets.push_back(_sound_asset); diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h index 30abdd563..f6273f8e9 100644 --- a/src/lib/reel_writer.h +++ b/src/lib/reel_writer.h @@ -31,7 +31,10 @@ #include "weak_film.h" #include #include +#include #include +#include +#include class AudioBuffers; @@ -46,6 +49,7 @@ namespace dcp { class MonoJ2KPictureAssetWriter; class J2KPictureAsset; class J2KPictureAssetWriter; + class MPEG2PictureAsset; class Reel; class ReelAsset; class ReelPictureAsset; @@ -70,11 +74,12 @@ public: ); void write (std::shared_ptr encoded, Frame frame, Eyes eyes); - void fake_write (int size); + void fake_write(dcp::J2KFrameInfo const& info); void repeat_write (Frame frame, Eyes eyes); void write (std::shared_ptr audio); void write(PlayerText text, TextType type, boost::optional track, dcpomatic::DCPTimePeriod period, FontIdMap const& fonts, std::shared_ptr chosen_interop_font); void write (std::shared_ptr atmos, AtmosMetadata metadata); + void write(std::shared_ptr image); void finish (boost::filesystem::path output_dcp); std::shared_ptr create_reel ( @@ -131,9 +136,11 @@ private: dcp::ArrayData _default_font; - std::shared_ptr _picture_asset; + std::shared_ptr _j2k_picture_asset; + std::shared_ptr _mpeg2_picture_asset; /** picture asset writer, or 0 if we are not writing any picture because we already have one */ - std::shared_ptr _picture_asset_writer; + std::shared_ptr _j2k_picture_asset_writer; + std::shared_ptr _mpeg2_picture_asset_writer; std::shared_ptr _sound_asset; std::shared_ptr _sound_asset_writer; std::shared_ptr _subtitle_asset; diff --git a/src/lib/video_encoding.cc b/src/lib/video_encoding.cc new file mode 100644 index 000000000..ead1a2eaf --- /dev/null +++ b/src/lib/video_encoding.cc @@ -0,0 +1,56 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "dcpomatic_assert.h" +#include "video_encoding.h" + + +using std::string; + + +string +video_encoding_to_string(VideoEncoding encoding) +{ + switch (encoding) { + case VideoEncoding::JPEG2000: + return "jpeg2000"; + case VideoEncoding::MPEG2: + return "mpeg2"; + } + + DCPOMATIC_ASSERT(false); +} + + +VideoEncoding +video_encoding_from_string(string const& encoding) +{ + if (encoding == "jpeg2000") { + return VideoEncoding::JPEG2000; + } + + if (encoding == "mpeg2") { + return VideoEncoding::MPEG2; + } + + DCPOMATIC_ASSERT(false); +} + diff --git a/src/lib/video_encoding.h b/src/lib/video_encoding.h new file mode 100644 index 000000000..45ee0b21e --- /dev/null +++ b/src/lib/video_encoding.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2024 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include + + +enum class VideoEncoding +{ + JPEG2000, + MPEG2 +}; + + +std::string video_encoding_to_string(VideoEncoding encoding); +VideoEncoding video_encoding_from_string(std::string const& encoding); + diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 1c04f4065..3dd22718f 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -40,6 +40,7 @@ #include "version.h" #include "writer.h" #include +#include #include #include #include @@ -169,6 +170,13 @@ Writer::write (shared_ptr encoded, Frame frame, Eyes eyes) } +void +Writer::write(shared_ptr image, Frame frame) +{ + _reels[video_reel(frame)].write(image); +} + + bool Writer::can_repeat (Frame frame) const { @@ -230,7 +238,7 @@ Writer::fake_write (Frame frame, Eyes eyes) QueueItem qi; qi.type = QueueItem::Type::FAKE; - qi.size = J2KFrameInfo(film()->info_file_handle(_reels[reel].period(), true), frame_in_reel, eyes).size; + qi.info = J2KFrameInfo(film()->info_file_handle(_reels[reel].period(), true), frame_in_reel, eyes); DCPOMATIC_ASSERT((film()->three_d() && eyes != Eyes::BOTH) || (!film()->three_d() && eyes == Eyes::BOTH)); @@ -401,7 +409,7 @@ try if (i.type == QueueItem::Type::FULL) { LOG_WARNING (N_("- type FULL, frame %1, eyes %2"), i.frame, (int) i.eyes); } else { - LOG_WARNING (N_("- type FAKE, size %1, frame %2, eyes %3"), i.size, i.frame, (int) i.eyes); + LOG_WARNING (N_("- type FAKE, size %1, frame %2, eyes %3"), i.info.size, i.frame, (int) i.eyes); } } } @@ -432,7 +440,7 @@ try break; case QueueItem::Type::FAKE: LOG_DEBUG_ENCODE (N_("Writer FAKE-writes %1"), qi.frame); - reel.fake_write (qi.size); + reel.fake_write(qi.info); ++_fake_written; break; case QueueItem::Type::REPEAT: diff --git a/src/lib/writer.h b/src/lib/writer.h index 1cd278221..1dd88d8a9 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -37,6 +37,8 @@ #include "text_type.h" #include "weak_film.h" #include +#include +#include #include #include #include @@ -74,8 +76,8 @@ public: /** encoded data for FULL */ std::shared_ptr encoded; - /** size of data for FAKE */ - int size = 0; + /** info for FAKE */ + dcp::J2KFrameInfo info; /** reel index */ size_t reel = 0; /** frame index within the reel */ @@ -122,6 +124,7 @@ public: void write (std::vector> fonts); void write (ReferencedReelAsset asset); void write (std::shared_ptr atmos, dcpomatic::DCPTime time, AtmosMetadata metadata); + void write (std::shared_ptr image, Frame frame); void finish (boost::filesystem::path output_dcp); void set_encoder_threads (int threads); diff --git a/src/lib/wscript b/src/lib/wscript index 8e839cb49..86cf2e0b6 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -154,6 +154,7 @@ sources = """ maths_util.cc memory_util.cc mid_side_decoder.cc + mpeg2_encoder.cc named_channel.cc overlaps.cc pixel_quanta.cc @@ -212,6 +213,7 @@ sources = """ video_content.cc video_decoder.cc video_encoder.cc + video_encoding.cc video_filter_graph.cc video_filter_graph_set.cc video_frame_type.cc diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index c2f32fbb9..4ae89d443 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -151,6 +151,7 @@ DCPPanel::add_standards() _standard->add(_("SMPTE (Bv2.0 only)"), N_("smpte-bv20")); } _standard->add(_("Interop"), N_("interop")); + _standard->add(_("MPEG2 Interop"), N_("mpeg2-interop")); _sizer->Layout(); } @@ -162,7 +163,11 @@ DCPPanel::set_standard() DCPOMATIC_ASSERT(!_film->limit_to_smpte_bv20() || _standard->GetCount() == 3); if (_film->interop()) { - checked_set(_standard, "interop"); + if (_film->video_encoding() == VideoEncoding::JPEG2000) { + checked_set(_standard, "interop"); + } else { + checked_set(_standard, "mpeg2-interop"); + } } else { checked_set(_standard, _film->limit_to_smpte_bv20() ? "smpte-bv20" : "smpte"); } @@ -184,12 +189,18 @@ DCPPanel::standard_changed () if (*data == N_("interop")) { _film->set_interop(true); _film->set_limit_to_smpte_bv20(false); + _film->set_video_encoding(VideoEncoding::JPEG2000); } else if (*data == N_("smpte")) { _film->set_interop(false); _film->set_limit_to_smpte_bv20(false); + _film->set_video_encoding(VideoEncoding::JPEG2000); } else if (*data == N_("smpte-bv20")) { _film->set_interop(false); _film->set_limit_to_smpte_bv20(true); + _film->set_video_encoding(VideoEncoding::JPEG2000); + } else if (*data == N_("mpeg2-interop")) { + _film->set_interop(true); + _film->set_video_encoding(VideoEncoding::MPEG2); } } @@ -445,6 +456,9 @@ DCPPanel::film_changed(FilmProperty p) setup_dcp_name (); _markers->Enable (!_film->interop()); break; + case FilmProperty::VIDEO_ENCODING: + set_standard(); + break; case FilmProperty::LIMIT_TO_SMPTE_BV20: set_standard(); break; diff --git a/test/burnt_subtitle_test.cc b/test/burnt_subtitle_test.cc index ac14de2c4..e8ecc0048 100644 --- a/test/burnt_subtitle_test.cc +++ b/test/burnt_subtitle_test.cc @@ -137,7 +137,7 @@ BOOST_AUTO_TEST_CASE (burnt_subtitle_test_onto_dcp) BOOST_REQUIRE (dcp.cpls().front()->reels().front()->main_picture()->asset()); auto pic = dynamic_pointer_cast ( dcp.cpls().front()->reels().front()->main_picture() - )->mono_asset(); + )->mono_j2k_asset(); BOOST_REQUIRE (pic); auto frame = pic->start_read()->get_frame(12); auto xyz = frame->xyz_image (); diff --git a/test/data b/test/data index ddf878730..3ab324522 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit ddf878730354cdec8a802a59543591f6f943f5c0 +Subproject commit 3ab3245220bd2a11cdf2e16a28221e4de063befc diff --git a/test/overlap_video_test.cc b/test/overlap_video_test.cc index 9bef93d67..638f606d3 100644 --- a/test/overlap_video_test.cc +++ b/test/overlap_video_test.cc @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE (overlap_video_test1) BOOST_REQUIRE (reel->main_picture()); auto mono_picture = dynamic_pointer_cast(reel->main_picture()); BOOST_REQUIRE (mono_picture); - auto asset = mono_picture->mono_asset(); + auto asset = mono_picture->mono_j2k_asset(); BOOST_REQUIRE (asset); BOOST_CHECK_EQUAL (asset->intrinsic_duration(), fps * 5); auto reader = asset->start_read (); -- cgit v1.2.3 From b94546264660e266de6828bdd8a3e176c66903a8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2024 23:41:33 +0200 Subject: Use run/environment for paths in run/tests. --- run/tests | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run/tests b/run/tests index bf4c5732e..a750fde10 100755 --- a/run/tests +++ b/run/tests @@ -5,6 +5,9 @@ set -e PRIVATE_GIT="881c48805e352dfe150993814757ca974282be18" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +source $DIR/environment + if [ "$1" == "--check" ]; then shift 1 check=1 @@ -13,7 +16,6 @@ else fi if [ "$(uname)" == "Linux" ]; then - export LD_LIBRARY_PATH=build/src/lib:/usr/local/lib:/usr/local/lib64:$LD_LIBRARY_PATH rm -f build/test/dcpomatic2_openssl # This must be our patched openssl or tests will fail if [ ! -f build/test/dcpomatic2_openssl ]; then @@ -41,8 +43,6 @@ if [ "$(uname)" == "Darwin" ]; then cp ../libdcp/ratings $resources rm -f build/test/openssl ln -s ../../../openssl/apps/openssl build/test/openssl - # SIP stops this being passed in from the caller's environment - export DYLD_LIBRARY_PATH=/Users/ci/osx-environment/x86_64/10.10/lib:/Users/ci/workspace/lib # We need to find ffcmp in here export PATH=$PATH:/Users/ci/workspace/bin fi -- cgit v1.2.3 From 43ac9191b0feb8f5311c3501a5e0a0f80ad1b4b9 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2024 23:42:08 +0200 Subject: Unify indentation at 4 spaces. --- run/tests | 80 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/run/tests b/run/tests index a750fde10..3a991de95 100755 --- a/run/tests +++ b/run/tests @@ -9,56 +9,56 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source $DIR/environment if [ "$1" == "--check" ]; then - shift 1 - check=1 + shift 1 + check=1 else - check=0 + check=0 fi if [ "$(uname)" == "Linux" ]; then - rm -f build/test/dcpomatic2_openssl - # This must be our patched openssl or tests will fail - if [ ! -f build/test/dcpomatic2_openssl ]; then - ln -s ../../../openssl/apps/openssl build/test/dcpomatic2_openssl - fi - export DCPOMATIC_TEST_TOOLS_PATH=/opt/asdcplib/bin - if [ -f /src/backports/dcp_inspect ]; then - export DCPOMATIC_DCP_INSPECT=/src/backports/dcp_inspect - fi - set +e - python3 -m clairmeta.cli --help > /dev/null 2>&1 - if [ "$?" == "0" ]; then - export DCPOMATIC_CLAIRMETA=1 - fi - set -e + rm -f build/test/dcpomatic2_openssl + # This must be our patched openssl or tests will fail + if [ ! -f build/test/dcpomatic2_openssl ]; then + ln -s ../../../openssl/apps/openssl build/test/dcpomatic2_openssl + fi + export DCPOMATIC_TEST_TOOLS_PATH=/opt/asdcplib/bin + if [ -f /src/backports/dcp_inspect ]; then + export DCPOMATIC_DCP_INSPECT=/src/backports/dcp_inspect + fi + set +e + python3 -m clairmeta.cli --help > /dev/null 2>&1 + if [ "$?" == "0" ]; then + export DCPOMATIC_CLAIRMETA=1 + fi + set -e fi if [ "$(uname)" == "Darwin" ]; then - resources=build/Resources - rm -rf $resources - mkdir -p $resources - cp fonts/*.ttf $resources - cp -r ../libdcp/tags $resources - cp -r ../libdcp/xsd $resources - cp ../libdcp/ratings $resources - rm -f build/test/openssl - ln -s ../../../openssl/apps/openssl build/test/openssl - # We need to find ffcmp in here - export PATH=$PATH:/Users/ci/workspace/bin + resources=build/Resources + rm -rf $resources + mkdir -p $resources + cp fonts/*.ttf $resources + cp -r ../libdcp/tags $resources + cp -r ../libdcp/xsd $resources + cp ../libdcp/ratings $resources + rm -f build/test/openssl + ln -s ../../../openssl/apps/openssl build/test/openssl + # We need to find ffcmp in here + export PATH=$PATH:/Users/ci/workspace/bin fi if [ "$check" == "1" ]; then - if [ "$DCPOMATIC_TEST_PRIVATE" == "" ]; then - pushd ../dcpomatic-test-private - else - pushd $DCPOMATIC_TEST_PRIVATE - fi - current=$(git rev-parse HEAD) - if [ "$current" != "$PRIVATE_GIT" ]; then - echo "Unexpected dcpomatic-test-private version" - exit 1 - fi - popd + if [ "$DCPOMATIC_TEST_PRIVATE" == "" ]; then + pushd ../dcpomatic-test-private + else + pushd $DCPOMATIC_TEST_PRIVATE + fi + current=$(git rev-parse HEAD) + if [ "$current" != "$PRIVATE_GIT" ]; then + echo "Unexpected dcpomatic-test-private version" + exit 1 + fi + popd fi if [ "$1" == "--debug" ]; then -- cgit v1.2.3 From 903c33051d45700a8e389b970c857c5339f9f395 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 3 Apr 2024 23:02:41 +0200 Subject: Rename Choice::add to Choice::add_entry. --- src/wx/dcp_panel.cc | 20 ++++++++++---------- src/wx/dcp_timeline.cc | 8 ++++---- src/wx/dcpomatic_choice.cc | 10 +++++----- src/wx/dcpomatic_choice.h | 8 ++++---- src/wx/full_config_dialog.cc | 4 ++-- src/wx/kdm_timing_panel.cc | 2 +- src/wx/metadata_dialog.cc | 10 +++++----- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 4ae89d443..5ad719abc 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -131,7 +131,7 @@ DCPPanel::DCPPanel(wxNotebook* n, shared_ptr film, FilmViewer& viewer) _reels->Bind(wxEVT_BUTTON, boost::bind(&DCPPanel::reels_clicked, this)); for (auto i: DCPContentType::all()) { - _dcp_content_type->add(i->pretty_name()); + _dcp_content_type->add_entry(i->pretty_name()); } add_standards(); @@ -146,12 +146,12 @@ DCPPanel::DCPPanel(wxNotebook* n, shared_ptr film, FilmViewer& viewer) void DCPPanel::add_standards() { - _standard->add(_("SMPTE"), N_("smpte")); + _standard->add_entry(_("SMPTE"), N_("smpte")); if (Config::instance()->allow_smpte_bv20() || (_film && _film->limit_to_smpte_bv20())) { - _standard->add(_("SMPTE (Bv2.0 only)"), N_("smpte-bv20")); + _standard->add_entry(_("SMPTE (Bv2.0 only)"), N_("smpte-bv20")); } - _standard->add(_("Interop"), N_("interop")); - _standard->add(_("MPEG2 Interop"), N_("mpeg2-interop")); + _standard->add_entry(_("Interop"), N_("interop")); + _standard->add_entry(_("MPEG2 Interop"), N_("mpeg2-interop")); _sizer->Layout(); } @@ -827,14 +827,14 @@ DCPPanel::make_video_panel () } for (auto i: Config::instance()->allowed_dcp_frame_rates()) { - _frame_rate_choice->add(boost::lexical_cast(i)); + _frame_rate_choice->add_entry(boost::lexical_cast(i)); } _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate() / 1000000); _frame_rate_spin->SetRange (1, 480); - _resolution->add(_("2K")); - _resolution->add(_("4K")); + _resolution->add_entry(_("2K")); + _resolution->add_entry(_("4K")); add_video_panel_to_grid (); setup_frame_rate_widget(); @@ -1024,9 +1024,9 @@ DCPPanel::show_audio_clicked () void DCPPanel::add_audio_processors () { - _audio_processor->add(_("None"), new wxStringClientData(N_("none"))); + _audio_processor->add_entry(_("None"), new wxStringClientData(N_("none"))); for (auto ap: AudioProcessor::visible()) { - _audio_processor->add(std_to_wx(ap->name()), new wxStringClientData(std_to_wx(ap->id()))); + _audio_processor->add_entry(std_to_wx(ap->name()), new wxStringClientData(std_to_wx(ap->id()))); } _audio_panel_sizer->Layout(); } diff --git a/src/wx/dcp_timeline.cc b/src/wx/dcp_timeline.cc index 6474a8428..7b8e93325 100644 --- a/src/wx/dcp_timeline.cc +++ b/src/wx/dcp_timeline.cc @@ -230,10 +230,10 @@ DCPTimeline::setup_reel_settings() int r = 0; add_label_to_sizer(sizer, _reel_settings, _("Reel mode"), true, wxGBPosition(r, 0)); _reel_type = new Choice(_reel_settings); - _reel_type->add(_("Single reel")); - _reel_type->add(_("Split by video content")); - _reel_type->add(_("Split by maximum reel size")); - _reel_type->add(_("Custom")); + _reel_type->add_entry(_("Single reel")); + _reel_type->add_entry(_("Split by video content")); + _reel_type->add_entry(_("Split by maximum reel size")); + _reel_type->add_entry(_("Custom")); sizer->Add(_reel_type, wxGBPosition(r, 1)); ++r; diff --git a/src/wx/dcpomatic_choice.cc b/src/wx/dcpomatic_choice.cc index 2f1a6f0e9..5e5a1e257 100644 --- a/src/wx/dcpomatic_choice.cc +++ b/src/wx/dcpomatic_choice.cc @@ -40,14 +40,14 @@ Choice::Choice(wxWindow* parent) void -Choice::add(string const& entry) +Choice::add_entry(string const& entry) { - add(std_to_wx(entry)); + add_entry(std_to_wx(entry)); } void -Choice::add(wxString const& entry) +Choice::add_entry(wxString const& entry) { if (_needs_clearing) { Clear(); @@ -59,7 +59,7 @@ Choice::add(wxString const& entry) void -Choice::add(wxString const& entry, wxClientData* data) +Choice::add_entry(wxString const& entry, wxClientData* data) { if (_needs_clearing) { Clear(); @@ -71,7 +71,7 @@ Choice::add(wxString const& entry, wxClientData* data) void -Choice::add(wxString const& entry, wxString const& data) +Choice::add_entry(wxString const& entry, wxString const& data) { if (_needs_clearing) { Clear(); diff --git a/src/wx/dcpomatic_choice.h b/src/wx/dcpomatic_choice.h index dec0a3701..ed59f6a17 100644 --- a/src/wx/dcpomatic_choice.h +++ b/src/wx/dcpomatic_choice.h @@ -32,10 +32,10 @@ class Choice : public wxChoice public: Choice(wxWindow* parent); - void add(wxString const& entry); - void add(wxString const& entry, wxClientData* data); - void add(wxString const& entry, wxString const& data); - void add(std::string const& entry); + void add_entry(wxString const& entry); + void add_entry(wxString const& entry, wxClientData* data); + void add_entry(wxString const& entry, wxString const& data); + void add_entry(std::string const& entry); void set(int index); void set_by_data(wxString const& data); boost::optional get() const; diff --git a/src/wx/full_config_dialog.cc b/src/wx/full_config_dialog.cc index c3c194fbc..2947d98eb 100644 --- a/src/wx/full_config_dialog.cc +++ b/src/wx/full_config_dialog.cc @@ -147,8 +147,8 @@ private: add_update_controls (table, r); - _default_add_file_location->add(_("Same place as last time")); - _default_add_file_location->add(_("Same place as project")); + _default_add_file_location->add_entry(_("Same place as last time")); + _default_add_file_location->add_entry(_("Same place as project")); _default_add_file_location->bind(&FullGeneralPage::default_add_file_location_changed, this); _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this)); diff --git a/src/wx/kdm_timing_panel.cc b/src/wx/kdm_timing_panel.cc index f4112cb08..6e362a3b2 100644 --- a/src/wx/kdm_timing_panel.cc +++ b/src/wx/kdm_timing_panel.cc @@ -124,7 +124,7 @@ KDMTimingPanel::KDMTimingPanel (wxWindow* parent) /* Default to UTC */ size_t sel = get_offsets(_offsets); for (size_t i = 0; i < _offsets.size(); ++i) { - _utc_offset->add(_offsets[i].name); + _utc_offset->add_entry(_offsets[i].name); if (_offsets[i].hour == 0 && _offsets[i].minute == 0) { sel = i; } diff --git a/src/wx/metadata_dialog.cc b/src/wx/metadata_dialog.cc index 347f2fffd..1d0758175 100644 --- a/src/wx/metadata_dialog.cc +++ b/src/wx/metadata_dialog.cc @@ -204,9 +204,9 @@ MetadataDialog::setup_standard (wxPanel* panel, wxSizer* sizer) { add_label_to_sizer(sizer, panel, _("Territory type"), true, 0, wxALIGN_CENTER_VERTICAL); _territory_type = new Choice(panel); - _territory_type->add(_("Specific"), wx_to_std(territory_type_to_string(TerritoryType::SPECIFIC))); - _territory_type->add(_("International texted"), wx_to_std(territory_type_to_string(TerritoryType::INTERNATIONAL_TEXTED))); - _territory_type->add(_("International textless"), wx_to_std(territory_type_to_string(TerritoryType::INTERNATIONAL_TEXTLESS))); + _territory_type->add_entry(_("Specific"), wx_to_std(territory_type_to_string(TerritoryType::SPECIFIC))); + _territory_type->add_entry(_("International texted"), wx_to_std(territory_type_to_string(TerritoryType::INTERNATIONAL_TEXTED))); + _territory_type->add_entry(_("International textless"), wx_to_std(territory_type_to_string(TerritoryType::INTERNATIONAL_TEXTLESS))); sizer->Add(_territory_type); _enable_release_territory = new CheckBox(panel, _("Release territory")); @@ -330,8 +330,8 @@ MetadataDialog::setup_advanced (wxPanel* panel, wxSizer* sizer) sizer->Add (s, 1, wxEXPAND); } - _luminance_unit->add(_("candela per m²")); - _luminance_unit->add(_("foot lambert")); + _luminance_unit->add_entry(_("candela per m²")); + _luminance_unit->add_entry(_("foot lambert")); } -- cgit v1.2.3 From bd9594a3b9958076734c3c6b3e4105d142cde6f4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 3 Apr 2024 23:25:19 +0200 Subject: Add Choice::set_entries(). --- src/wx/dcpomatic_choice.cc | 12 ++++++++++++ src/wx/dcpomatic_choice.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/wx/dcpomatic_choice.cc b/src/wx/dcpomatic_choice.cc index 5e5a1e257..f2e215439 100644 --- a/src/wx/dcpomatic_choice.cc +++ b/src/wx/dcpomatic_choice.cc @@ -82,6 +82,18 @@ Choice::add_entry(wxString const& entry, wxString const& data) } +void +Choice::set_entries(wxArrayString const& entries) +{ + if (GetStrings() == entries) { + return; + } + + Clear(); + Set(entries); +} + + void Choice::set(int index) { diff --git a/src/wx/dcpomatic_choice.h b/src/wx/dcpomatic_choice.h index ed59f6a17..cc8115d20 100644 --- a/src/wx/dcpomatic_choice.h +++ b/src/wx/dcpomatic_choice.h @@ -36,6 +36,8 @@ public: void add_entry(wxString const& entry, wxClientData* data); void add_entry(wxString const& entry, wxString const& data); void add_entry(std::string const& entry); + void set_entries(wxArrayString const& entries); + void set(int index); void set_by_data(wxString const& data); boost::optional get() const; -- cgit v1.2.3 From 32053c222183e17c7c662e6d3f95b9a203461061 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 3 Apr 2024 23:26:50 +0200 Subject: Update available containers whenever they change, always adding the one that the film is currently using. --- src/lib/config.h | 3 ++- src/wx/dcp_panel.cc | 35 ++++++++++++++++++----------------- src/wx/full_config_dialog.cc | 8 +------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/lib/config.h b/src/lib/config.h index 05421c20a..ff71f8a38 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -97,6 +97,7 @@ public: AUTO_CROP_THRESHOLD, ALLOW_SMPTE_BV20, ISDCF_NAME_PART_LENGTH, + ALLOW_ANY_CONTAINER, #ifdef DCPOMATIC_GROK GROK, #endif @@ -742,7 +743,7 @@ public: } void set_allow_any_container (bool a) { - maybe_set (_allow_any_container, a); + maybe_set(_allow_any_container, a, ALLOW_ANY_CONTAINER); } void set_allow_96hhz_audio (bool a) { diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 5ad719abc..2d4e9b3d3 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -458,6 +458,7 @@ DCPPanel::film_changed(FilmProperty p) break; case FilmProperty::VIDEO_ENCODING: set_standard(); + setup_container(); break; case FilmProperty::LIMIT_TO_SMPTE_BV20: set_standard(); @@ -540,24 +541,28 @@ DCPPanel::film_content_changed (int property) void DCPPanel::setup_container () { - int n = 0; - auto ratios = Ratio::containers (); - auto i = ratios.begin (); - while (i != ratios.end() && *i != _film->container()) { - ++i; - ++n; + auto ratios = Ratio::containers(); + if (std::find(ratios.begin(), ratios.end(), _film->container()) == ratios.end()) { + ratios.push_back(_film->container()); } - if (i == ratios.end()) { - checked_set (_container, -1); - checked_set (_container_size, wxT("")); - } else { - checked_set (_container, n); - auto const size = fit_ratio_within (_film->container()->ratio(), _film->full_frame ()); - checked_set (_container_size, wxString::Format("%dx%d", size.width, size.height)); + wxArrayString new_ratios; + for (auto ratio: ratios) { + new_ratios.Add(std_to_wx(ratio->container_nickname())); } + _container->set_entries(new_ratios); + + auto iter = std::find_if(ratios.begin(), ratios.end(), [this](Ratio const* ratio) { return ratio == _film->container(); }); + DCPOMATIC_ASSERT(iter != ratios.end()); + + checked_set(_container, iter - ratios.begin()); + auto const size = fit_ratio_within(_film->container()->ratio(), _film->full_frame ()); + checked_set(_container_size, wxString::Format("%dx%d", size.width, size.height)); + setup_dcp_name (); + + _video_grid->Layout(); } @@ -822,10 +827,6 @@ DCPPanel::make_video_panel () _three_d->bind(&DCPPanel::three_d_changed, this); _reencode_j2k->bind(&DCPPanel::reencode_j2k_changed, this); - for (auto i: Ratio::containers()) { - _container->add(i->container_nickname()); - } - for (auto i: Config::instance()->allowed_dcp_frame_rates()) { _frame_rate_choice->add_entry(boost::lexical_cast(i)); } diff --git a/src/wx/full_config_dialog.cc b/src/wx/full_config_dialog.cc index 2947d98eb..092c9ab26 100644 --- a/src/wx/full_config_dialog.cc +++ b/src/wx/full_config_dialog.cc @@ -1559,13 +1559,7 @@ private: _allow_any_container = new CheckBox(_panel, _("Allow full-frame and non-standard container ratios")); table->Add(_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP); - auto restart = new StaticText(_panel, variant::wx::insert_dcpomatic(_("(restart %s to see all ratios)"))); - auto font = restart->GetFont(); - font.SetStyle(wxFONTSTYLE_ITALIC); - font.SetPointSize(font.GetPointSize() - 1); - restart->SetFont(font); - table->Add(restart, 1, wxALIGN_CENTRE_VERTICAL | wxBOTTOM, DCPOMATIC_CHECKBOX_BOTTOM_PAD); - restart->SetFont(font); + table->AddSpacer(0); checkbox(_("Allow creation of DCPs with 96kHz audio"), _allow_96khz_audio); checkbox(_("Allow mapping to all audio channels"), _use_all_audio_channels); -- cgit v1.2.3 From fb30f7149ffc18494ce38696ab88d5494ca9dfaf Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 3 Apr 2024 23:27:13 +0200 Subject: Desensitise things that can't be adjusted in MPEG2 mode. --- src/wx/dcp_panel.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 2d4e9b3d3..8ee95df18 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -459,6 +459,7 @@ DCPPanel::film_changed(FilmProperty p) case FilmProperty::VIDEO_ENCODING: set_standard(); setup_container(); + setup_sensitivity(); break; case FilmProperty::LIMIT_TO_SMPTE_BV20: set_standard(); @@ -653,6 +654,8 @@ DCPPanel::set_general_sensitivity (bool s) void DCPPanel::setup_sensitivity () { + auto const mpeg2 = _film && _film->video_encoding() == VideoEncoding::MPEG2; + _name->Enable (_generally_sensitive); _use_isdcf_name->Enable (_generally_sensitive); _dcp_content_type->Enable (_generally_sensitive); @@ -669,7 +672,7 @@ DCPPanel::setup_sensitivity () _audio_channels->Enable (_generally_sensitive && _film && !_film->references_dcp_audio()); _audio_processor->Enable (_generally_sensitive && _film && !_film->references_dcp_audio()); _video_bit_rate->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); - _container->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); + _container->Enable (_generally_sensitive && _film && !_film->references_dcp_video() && !mpeg2); _best_frame_rate->Enable ( _generally_sensitive && _film && @@ -677,8 +680,8 @@ DCPPanel::setup_sensitivity () !_film->references_dcp_video() && !_film->contains_atmos_content() ); - _resolution->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); - _three_d->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); + _resolution->Enable (_generally_sensitive && _film && !_film->references_dcp_video() && !mpeg2); + _three_d->Enable (_generally_sensitive && _film && !_film->references_dcp_video() && !mpeg2); _standard->Enable ( _generally_sensitive && @@ -769,6 +772,8 @@ DCPPanel::config_changed (Config::Property p) } } else if (p == Config::ISDCF_NAME_PART_LENGTH) { setup_dcp_name(); + } else if (p == Config::ALLOW_ANY_CONTAINER) { + setup_container(); } } -- cgit v1.2.3 From 4f0d027f1964d0c011f89b5706fbaf654955ba2d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 3 Apr 2024 23:27:41 +0200 Subject: Alert user when fixing settings for MPEG2. --- src/lib/film.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib/film.cc b/src/lib/film.cc index 54c68d756..6dc1b6b6c 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -1232,6 +1232,7 @@ Film::set_video_encoding(VideoEncoding encoding) { FilmChangeSignaller ch(this, FilmProperty::VIDEO_ENCODING); _video_encoding = encoding; + check_settings_consistency(); } @@ -1660,6 +1661,22 @@ Film::check_settings_consistency () set_custom_reel_boundaries(boundaries); } } + + auto const hd = Ratio::from_id("178"); + + if (video_encoding() == VideoEncoding::MPEG2) { + if (container() != hd) { + set_container(hd); + Message(_("DCP-o-matic had to set your container to 1920x1080 as it's the only one that can be used with MPEG2 encoding.")); + } + if (three_d()) { + set_three_d(false); + Message(_("DCP-o-matic had to set your film to 2D as 3D is not yet supported with MPEG2 encoding.")); + } + } else if (container() == hd && !Config::instance()->allow_any_container()) { + set_container(Ratio::from_id("185")); + Message(_("DCP-o-matic set your container to DCI Flat as it was previously 1920x1080 and that is not a standard ratio with JPEG2000 encoding.")); + } } void -- cgit v1.2.3 From 21ebc2365dd7a66c05d130dc87861f7399ae834b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 5 Apr 2024 23:17:03 +0200 Subject: Allow specification of video bit rate separately for J2K and MPEG2. --- src/lib/config.cc | 28 +++++++++------ src/lib/config.h | 22 ++++++------ src/lib/create_cli.cc | 6 ++-- src/lib/dcp_film_encoder.cc | 2 ++ src/lib/film.cc | 27 +++++++++------ src/lib/film.h | 11 +++--- src/lib/grok/context.h | 2 +- src/lib/hints.cc | 2 +- src/lib/j2k_encoder.cc | 2 +- src/lib/make_dcp.cc | 2 +- src/lib/mpeg2_encoder.cc | 2 +- src/lib/video_encoding.cc | 2 ++ src/lib/video_encoding.h | 10 +++++- src/tools/dcpomatic_cli.cc | 2 +- src/wx/dcp_panel.cc | 11 +++--- src/wx/full_config_dialog.cc | 75 ++++++++++++++++++++++++++++++---------- test/data | 2 +- test/film_metadata_test.cc | 2 +- test/j2k_video_bit_rate_test.cc | 2 +- test/reels_test.cc | 4 +-- test/required_disk_space_test.cc | 2 +- test/test.cc | 2 +- 22 files changed, 145 insertions(+), 75 deletions(-) diff --git a/src/lib/config.cc b/src/lib/config.cc index 1400b9309..33b1a8656 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -108,7 +108,8 @@ Config::set_defaults () _default_still_length = 10; _default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR"); _default_dcp_audio_channels = 8; - _default_video_bit_rate = 150000000; + _default_video_bit_rate[VideoEncoding::JPEG2000] = 150000000; + _default_video_bit_rate[VideoEncoding::MPEG2] = 5000000; _default_audio_delay = 0; _default_interop = false; _default_metadata.clear (); @@ -127,7 +128,8 @@ Config::set_defaults () _notification_bcc = ""; _check_for_updates = false; _check_for_test_updates = false; - _maximum_video_bit_rate = 250000000; + _maximum_video_bit_rate[VideoEncoding::JPEG2000] = 250000000; + _maximum_video_bit_rate[VideoEncoding::MPEG2] = 50000000; _log_types = LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR | LogEntry::TYPE_DISK; _analyse_ebur128 = true; _automatic_audio_analysis = false; @@ -376,10 +378,11 @@ try _default_still_length = f.optional_number_child("DefaultStillLength").get_value_or (10); if (auto j2k = f.optional_number_child("DefaultJ2KBandwidth")) { - _default_video_bit_rate = *j2k; + _default_video_bit_rate[VideoEncoding::JPEG2000] = *j2k; } else { - _default_video_bit_rate = f.optional_number_child("DefaultVideoBitRate").get_value_or(200000000); + _default_video_bit_rate[VideoEncoding::JPEG2000] = f.optional_number_child("DefaultJ2KVideoBitRate").get_value_or(200000000); } + _default_video_bit_rate[VideoEncoding::MPEG2] = f.optional_number_child("DefaultMPEG2VideoBitRate").get_value_or(5000000); _default_audio_delay = f.optional_number_child("DefaultAudioDelay").get_value_or (0); _default_interop = f.optional_bool_child("DefaultInterop").get_value_or (false); @@ -455,10 +458,11 @@ try _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false); if (auto j2k = f.optional_number_child("MaximumJ2KBandwidth")) { - _maximum_video_bit_rate = *j2k; + _maximum_video_bit_rate[VideoEncoding::JPEG2000] = *j2k; } else { - _maximum_video_bit_rate = f.optional_number_child("MaximumVideoBitRate").get_value_or(250000000); + _maximum_video_bit_rate[VideoEncoding::JPEG2000] = f.optional_number_child("MaximumJ2KVideoBitRate").get_value_or(250000000); } + _maximum_video_bit_rate[VideoEncoding::MPEG2] = f.optional_number_child("MaximumMPEG2VideoBitRate").get_value_or(50000000); _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate").get_value_or (false); _allow_any_container = f.optional_bool_child ("AllowAnyContainer").get_value_or (false); _allow_96khz_audio = f.optional_bool_child("Allow96kHzAudio").get_value_or(false); @@ -815,8 +819,10 @@ Config::write_config () const /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */ cxml::add_text_child(root, "DefaultStillLength", raw_convert(_default_still_length)); - /* [XML] DefaultVideoBitRate Default bitrate (in bits per second) for JPEG2000 or MPEG2 data in new films. */ - cxml::add_text_child(root, "DefaultVideoBitRate", raw_convert(_default_video_bit_rate)); + /* [XML] DefaultJ2KVideoBitRate Default bitrate (in bits per second) for JPEG2000 data in new films. */ + cxml::add_text_child(root, "DefaultJ2KVideoBitRate", raw_convert(_default_video_bit_rate[VideoEncoding::JPEG2000])); + /* [XML] DefaultMPEG2VideoBitRate Default bitrate (in bits per second) for MPEG2 data in new films. */ + cxml::add_text_child(root, "DefaultMPEG2VideoBitRate", raw_convert(_default_video_bit_rate[VideoEncoding::MPEG2])); /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */ cxml::add_text_child(root, "DefaultAudioDelay", raw_convert(_default_audio_delay)); /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */ @@ -896,8 +902,10 @@ Config::write_config () const /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */ cxml::add_text_child(root, "CheckForTestUpdates", _check_for_test_updates ? "1" : "0"); - /* [XML] MaximumVideoBitRate Maximum video bit rate (in bits per second) that can be specified in the GUI. */ - cxml::add_text_child(root, "MaximumVideoBitRate", raw_convert(_maximum_video_bit_rate)); + /* [XML] MaximumJ2KVideoBitRate Maximum video bit rate (in bits per second) that can be specified in the GUI for JPEG2000 encodes. */ + cxml::add_text_child(root, "MaximumJ2KVideoBitRate", raw_convert(_maximum_video_bit_rate[VideoEncoding::JPEG2000])); + /* [XML] MaximumMPEG2VideoBitRate Maximum video bit rate (in bits per second) that can be specified in the GUI for MPEG2 encodes. */ + cxml::add_text_child(root, "MaximumMPEG2VideoBitRate", raw_convert(_maximum_video_bit_rate[VideoEncoding::MPEG2])); /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */ cxml::add_text_child(root, "AllowAnyDCPFrameRate", _allow_any_dcp_frame_rate ? "1" : "0"); /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */ diff --git a/src/lib/config.h b/src/lib/config.h index ff71f8a38..a7b238c04 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -28,9 +28,11 @@ #include "audio_mapping.h" +#include "enum_indexed_vector.h" #include "export_config.h" #include "rough_duration.h" #include "state.h" +#include "video_encoding.h" #include #include #include @@ -233,8 +235,8 @@ public: return _dcp_j2k_comment; } - int64_t default_video_bit_rate() const { - return _default_video_bit_rate; + int64_t default_video_bit_rate(VideoEncoding encoding) const { + return _default_video_bit_rate[encoding]; } int default_audio_delay () const { @@ -349,8 +351,8 @@ public: return _check_for_test_updates; } - int64_t maximum_video_bit_rate() const { - return _maximum_video_bit_rate; + int64_t maximum_video_bit_rate(VideoEncoding encoding) const { + return _maximum_video_bit_rate[encoding]; } int log_types () const { @@ -811,8 +813,8 @@ public: maybe_set (_dcp_j2k_comment, c); } - void set_default_video_bit_rate(int64_t b) { - maybe_set(_default_video_bit_rate, b); + void set_default_video_bit_rate(VideoEncoding encoding, int64_t b) { + maybe_set(_default_video_bit_rate[encoding], b); } void set_default_audio_delay (int d) { @@ -934,8 +936,8 @@ public: maybe_set (_check_for_test_updates, c); } - void set_maximum_video_bit_rate(int64_t b) { - maybe_set(_maximum_video_bit_rate, b); + void set_maximum_video_bit_rate(VideoEncoding encoding, int64_t b) { + maybe_set(_maximum_video_bit_rate[encoding], b); } void set_log_types (int t) { @@ -1381,7 +1383,7 @@ private: std::string _dcp_product_name; std::string _dcp_product_version; std::string _dcp_j2k_comment; - int64_t _default_video_bit_rate; + EnumIndexedVector _default_video_bit_rate; int _default_audio_delay; bool _default_interop; boost::optional _default_audio_language; @@ -1419,7 +1421,7 @@ private: bool _check_for_updates; bool _check_for_test_updates; /** maximum allowed video bit rate in bits per second */ - int64_t _maximum_video_bit_rate; + EnumIndexedVector _maximum_video_bit_rate; int _log_types; bool _analyse_ebur128; bool _automatic_audio_analysis; diff --git a/src/lib/create_cli.cc b/src/lib/create_cli.cc index b33537974..8fe5a2a14 100644 --- a/src/lib/create_cli.cc +++ b/src/lib/create_cli.cc @@ -320,8 +320,8 @@ CreateCLI::CreateCLI (int argc, char* argv[]) _name = content[0].path.filename().string(); } - if (_video_bit_rate && (*_video_bit_rate < 10000000 || *_video_bit_rate > Config::instance()->maximum_video_bit_rate())) { - error = String::compose("%1: video-bit-rate must be between 10 and %2 Mbit/s", argv[0], (Config::instance()->maximum_video_bit_rate() / 1000000)); + if (_video_bit_rate && (*_video_bit_rate < 10000000 || *_video_bit_rate > Config::instance()->maximum_video_bit_rate(VideoEncoding::JPEG2000))) { + error = String::compose("%1: video-bit-rate must be between 10 and %2 Mbit/s", argv[0], (Config::instance()->maximum_video_bit_rate(VideoEncoding::JPEG2000) / 1000000)); return; } } @@ -373,7 +373,7 @@ CreateCLI::make_film() const film->set_resolution(Resolution::FOUR_K); } if (_video_bit_rate) { - film->set_video_bit_rate(*_video_bit_rate); + film->set_video_bit_rate(VideoEncoding::JPEG2000, *_video_bit_rate); } int channels = 6; diff --git a/src/lib/dcp_film_encoder.cc b/src/lib/dcp_film_encoder.cc index 17f531693..bdcd17f38 100644 --- a/src/lib/dcp_film_encoder.cc +++ b/src/lib/dcp_film_encoder.cc @@ -78,6 +78,8 @@ DCPFilmEncoder::DCPFilmEncoder(shared_ptr film, weak_ptr job) case VideoEncoding::MPEG2: _encoder.reset(new MPEG2Encoder(film, _writer)); break; + case VideoEncoding::COUNT: + DCPOMATIC_ASSERT(false); } _player_video_connection = _player.Video.connect(bind(&DCPFilmEncoder::video, this, _1, _2)); diff --git a/src/lib/film.cc b/src/lib/film.cc index 6dc1b6b6c..a3e78e877 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -163,7 +163,6 @@ Film::Film (optional dir) , _resolution (Resolution::TWO_K) , _encrypted (false) , _context_id (dcp::make_uuid ()) - , _video_bit_rate(Config::instance()->default_video_bit_rate()) , _video_frame_rate (24) , _audio_channels (Config::instance()->default_dcp_audio_channels ()) , _three_d (false) @@ -203,6 +202,10 @@ Film::Film (optional dir) _studio = metadata["studio"]; } + for (auto encoding: {VideoEncoding::JPEG2000, VideoEncoding::MPEG2}) { + _video_bit_rate[encoding] = Config::instance()->default_video_bit_rate(encoding); + } + _playlist_change_connection = _playlist->Change.connect (bind (&Film::playlist_change, this, _1)); _playlist_order_changed_connection = _playlist->OrderChange.connect (bind (&Film::playlist_order_changed, this)); _playlist_content_change_connection = _playlist->ContentChange.connect (bind (&Film::playlist_content_change, this, _1, _2, _3, _4)); @@ -241,7 +244,7 @@ Film::video_identifier () const + "_" + resolution_to_string (_resolution) + "_" + _playlist->video_identifier() + "_" + raw_convert(_video_frame_rate) - + "_" + raw_convert(video_bit_rate()); + + "_" + raw_convert(video_bit_rate(video_encoding())); if (encrypted ()) { /* This is insecure but hey, the key is in plaintext in metadata.xml */ @@ -401,7 +404,8 @@ Film::metadata (bool with_content_paths) const } cxml::add_text_child(root, "Resolution", resolution_to_string(_resolution)); - cxml::add_text_child(root, "VideoBitRate", raw_convert(_video_bit_rate)); + cxml::add_text_child(root, "J2KVideoBitRate", raw_convert(_video_bit_rate[VideoEncoding::JPEG2000])); + cxml::add_text_child(root, "MPEG2VideoBitRate", raw_convert(_video_bit_rate[VideoEncoding::MPEG2])); cxml::add_text_child(root, "VideoFrameRate", raw_convert(_video_frame_rate)); cxml::add_text_child(root, "AudioFrameRate", raw_convert(_audio_frame_rate)); cxml::add_text_child(root, "ISDCFDate", boost::gregorian::to_iso_string(_isdcf_date)); @@ -575,10 +579,11 @@ Film::read_metadata (optional path) _resolution = string_to_resolution (f.string_child ("Resolution")); if (auto j2k = f.optional_number_child("J2KBandwidth")) { - _video_bit_rate = *j2k; + _video_bit_rate[VideoEncoding::JPEG2000] = *j2k; } else { - _video_bit_rate = f.number_child("VideoBitRate"); + _video_bit_rate[VideoEncoding::JPEG2000] = f.number_child("J2KVideoBitRate"); } + _video_bit_rate[VideoEncoding::MPEG2] = f.optional_number_child("MPEG2VideoBitRate").get_value_or(Config::instance()->default_video_bit_rate(VideoEncoding::MPEG2)); _video_frame_rate = f.number_child ("VideoFrameRate"); _audio_frame_rate = f.optional_number_child("AudioFrameRate").get_value_or(48000); _encrypted = f.bool_child ("Encrypted"); @@ -1181,10 +1186,10 @@ Film::set_resolution (Resolution r, bool explicit_user) void -Film::set_video_bit_rate(int64_t bit_rate) +Film::set_video_bit_rate(VideoEncoding encoding, int64_t bit_rate) { FilmChangeSignaller ch(this, FilmProperty::VIDEO_BIT_RATE); - _video_bit_rate = bit_rate; + _video_bit_rate[encoding] = bit_rate; } /** @param f New frame rate. @@ -1802,7 +1807,7 @@ Film::make_kdm(boost::filesystem::path cpl_file, dcp::LocalTime from, dcp::Local uint64_t Film::required_disk_space () const { - return _playlist->required_disk_space (shared_from_this(), video_bit_rate(), audio_channels(), audio_frame_rate()); + return _playlist->required_disk_space (shared_from_this(), video_bit_rate(video_encoding()), audio_channels(), audio_frame_rate()); } /** This method checks the disk that the Film is on and tries to decide whether or not @@ -1934,7 +1939,7 @@ Film::reels () const /* Integer-divide reel length by the size of one frame to give the number of frames per reel, * making sure we don't go less than 1s long. */ - Frame const reel_in_frames = max(_reel_length / ((video_bit_rate() / video_frame_rate()) / 8), static_cast(video_frame_rate())); + Frame const reel_in_frames = max(_reel_length / ((video_bit_rate(video_encoding()) / video_frame_rate()) / 8), static_cast(video_frame_rate())); while (current < len) { DCPTime end = min (len, current + DCPTime::from_frames (reel_in_frames, video_frame_rate ())); periods.emplace_back(current, end); @@ -1978,7 +1983,9 @@ Film::use_template (string name) _dcp_content_type = _template_film->_dcp_content_type; _container = _template_film->_container; _resolution = _template_film->_resolution; - _video_bit_rate = _template_film->_video_bit_rate; + for (auto encoding: { VideoEncoding::JPEG2000, VideoEncoding::MPEG2 }) { + _video_bit_rate[encoding] = _template_film->_video_bit_rate[encoding]; + } _video_frame_rate = _template_film->_video_frame_rate; _encrypted = _template_film->_encrypted; _audio_channels = _template_film->_audio_channels; diff --git a/src/lib/film.h b/src/lib/film.h index ff3dee6fc..e2e88e2c9 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -32,6 +32,7 @@ #include "change_signaller.h" #include "dcp_text_track.h" #include "dcpomatic_time.h" +#include "enum_indexed_vector.h" #include "film_property.h" #include "frame_rate_change.h" #include "named_channel.h" @@ -251,8 +252,8 @@ public: return _key; } - int video_bit_rate() const { - return _video_bit_rate; + int video_bit_rate(VideoEncoding encoding) const { + return _video_bit_rate[encoding]; } /** @return The frame rate of the DCP */ @@ -406,7 +407,7 @@ public: void set_container (Ratio const *, bool user_explicit = true); void set_resolution (Resolution, bool user_explicit = true); void set_encrypted (bool); - void set_video_bit_rate(int64_t); + void set_video_bit_rate(VideoEncoding encoding, int64_t); void set_video_frame_rate (int rate, bool user_explicit = false); void set_audio_channels (int); void set_three_d (bool); @@ -521,8 +522,8 @@ private: * re-start picture MXF encodes. */ std::string _context_id; - /** bit rate for encoding video using J2K or MPEG2 in bits per second */ - int64_t _video_bit_rate; + /** bit rate for encoding video using in bits per second */ + EnumIndexedVector _video_bit_rate; /** Frames per second to run our DCP at */ int _video_frame_rate; /** The date that we should use in a ISDCF name */ diff --git a/src/lib/grok/context.h b/src/lib/grok/context.h index fc9b74a57..81622ad9d 100644 --- a/src/lib/grok/context.h +++ b/src/lib/grok/context.h @@ -226,7 +226,7 @@ public: device, _dcpomatic_context->film->resolution() == Resolution::FOUR_K, _dcpomatic_context->film->video_frame_rate(), - _dcpomatic_context->film->video_bit_rate(), + _dcpomatic_context->film->video_bit_rate(VideoEncoding::JPEG2000), grok.licence_server, grok.licence_port, grok.licence)) { diff --git a/src/lib/hints.cc b/src/lib/hints.cc index fc59fa703..8e678fdf1 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -175,7 +175,7 @@ Hints::check_unusual_container () void Hints::check_high_video_bit_rate() { - if (film()->video_bit_rate() >= 245000000) { + if (film()->video_encoding() == VideoEncoding::JPEG2000 && film()->video_bit_rate(VideoEncoding::JPEG2000) >= 245000000) { hint (_("A few projectors have problems playing back very high bit-rate DCPs. It is a good idea to drop the video bit rate down to about 200Mbit/s; this is unlikely to have any visible effect on the image.")); } } diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index d5c7b3eed..094e104ef 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -310,7 +310,7 @@ J2KEncoder::encode (shared_ptr pv, DCPTime time) pv, position, _film->video_frame_rate(), - _film->video_bit_rate(), + _film->video_bit_rate(VideoEncoding::JPEG2000), _film->resolution() ); _queue.push_back (dcpv); diff --git a/src/lib/make_dcp.cc b/src/lib/make_dcp.cc index e4707721c..b72756194 100644 --- a/src/lib/make_dcp.cc +++ b/src/lib/make_dcp.cc @@ -91,7 +91,7 @@ make_dcp (shared_ptr film, TranscodeJob::ChangedBehaviour behaviour) LOG_GENERAL ("Content: %1", content->technical_summary()); } LOG_GENERAL ("DCP video rate %1 fps", film->video_frame_rate()); - LOG_GENERAL("Video bit rate %1", film->video_bit_rate()); + LOG_GENERAL("Video bit rate %1", film->video_bit_rate(film->video_encoding())); auto tj = make_shared(film, behaviour); tj->set_encoder(make_shared(film, tj)); diff --git a/src/lib/mpeg2_encoder.cc b/src/lib/mpeg2_encoder.cc index 49bff19d4..9b9cdfd09 100644 --- a/src/lib/mpeg2_encoder.cc +++ b/src/lib/mpeg2_encoder.cc @@ -32,7 +32,7 @@ using std::shared_ptr; MPEG2Encoder::MPEG2Encoder(shared_ptr film, Writer& writer) : VideoEncoder(film, writer) - , _transcoder(film->frame_size(), film->video_frame_rate(), film->video_bit_rate()) + , _transcoder(film->frame_size(), film->video_frame_rate(), film->video_bit_rate(VideoEncoding::MPEG2)) { } diff --git a/src/lib/video_encoding.cc b/src/lib/video_encoding.cc index ead1a2eaf..de68c6ae9 100644 --- a/src/lib/video_encoding.cc +++ b/src/lib/video_encoding.cc @@ -34,6 +34,8 @@ video_encoding_to_string(VideoEncoding encoding) return "jpeg2000"; case VideoEncoding::MPEG2: return "mpeg2"; + case VideoEncoding::COUNT: + DCPOMATIC_ASSERT(false); } DCPOMATIC_ASSERT(false); diff --git a/src/lib/video_encoding.h b/src/lib/video_encoding.h index 45ee0b21e..7c240f06f 100644 --- a/src/lib/video_encoding.h +++ b/src/lib/video_encoding.h @@ -19,16 +19,24 @@ */ +#ifndef DCPOMATIC_VIDEO_ENCODING_H +#define DCPOMATIC_VIDEO_ENCODING_H + + #include enum class VideoEncoding { JPEG2000, - MPEG2 + MPEG2, + COUNT }; std::string video_encoding_to_string(VideoEncoding encoding); VideoEncoding video_encoding_from_string(std::string const& encoding); + +#endif + diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index b59348908..49caf5cb2 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -94,7 +94,7 @@ print_dump (shared_ptr film) { cout << film->dcp_name (true) << "\n" << film->container()->container_nickname() << " at " << ((film->resolution() == Resolution::TWO_K) ? "2K" : "4K") << "\n" - << (film->video_bit_rate() / 1000000) << "Mbit/s" << "\n" + << (film->video_bit_rate(film->video_encoding()) / 1000000) << "Mbit/s" << "\n" << "Duration " << (film->length().timecode(film->video_frame_rate())) << "\n" << "Output " << film->video_frame_rate() << "fps " << (film->three_d() ? "3D" : "2D") << " " << (film->audio_frame_rate() / 1000) << "kHz\n" << (film->interop() ? "Inter-Op" : "SMPTE") << " " << (film->encrypted() ? "encrypted" : "unencrypted") << "\n"; diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 8ee95df18..bc8ac859c 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -270,7 +270,7 @@ DCPPanel::video_bit_rate_changed() return; } - _film->set_video_bit_rate(_video_bit_rate->GetValue() * 1000000); + _film->set_video_bit_rate(_film->video_encoding(), _video_bit_rate->GetValue() * 1000000); } @@ -397,7 +397,7 @@ DCPPanel::film_changed(FilmProperty p) setup_dcp_name (); break; case FilmProperty::VIDEO_BIT_RATE: - checked_set(_video_bit_rate, _film->video_bit_rate() / 1000000); + checked_set(_video_bit_rate, _film->video_bit_rate(_film->video_encoding()) / 1000000); break; case FilmProperty::USE_ISDCF_NAME: { @@ -460,6 +460,7 @@ DCPPanel::film_changed(FilmProperty p) set_standard(); setup_container(); setup_sensitivity(); + film_changed(FilmProperty::VIDEO_BIT_RATE); break; case FilmProperty::LIMIT_TO_SMPTE_BV20: set_standard(); @@ -754,7 +755,8 @@ DCPPanel::reencode_j2k_changed () void DCPPanel::config_changed (Config::Property p) { - _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate() / 1000000); + VideoEncoding const encoding = _film ? _film->video_encoding() : VideoEncoding::JPEG2000; + _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate(encoding) / 1000000); setup_frame_rate_widget (); if (p == Config::SHOW_EXPERIMENTAL_AUDIO_PROCESSORS) { @@ -836,7 +838,8 @@ DCPPanel::make_video_panel () _frame_rate_choice->add_entry(boost::lexical_cast(i)); } - _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate() / 1000000); + VideoEncoding const encoding = _film ? _film->video_encoding() : VideoEncoding::JPEG2000; + _video_bit_rate->SetRange(1, Config::instance()->maximum_video_bit_rate(encoding) / 1000000); _frame_rate_spin->SetRange (1, 480); _resolution->add_entry(_("2K")); diff --git a/src/wx/full_config_dialog.cc b/src/wx/full_config_dialog.cc index 092c9ab26..00e5575b1 100644 --- a/src/wx/full_config_dialog.cc +++ b/src/wx/full_config_dialog.cc @@ -320,10 +320,19 @@ private: table->Add (_dcp_audio_channels); { - add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); + add_label_to_sizer(table, _panel, _("Default JPEG2000 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); auto s = new wxBoxSizer (wxHORIZONTAL); - _video_bit_rate = new wxSpinCtrl(_panel); - s->Add(_video_bit_rate); + _j2k_video_bit_rate = new wxSpinCtrl(_panel); + s->Add(_j2k_video_bit_rate); + add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); + table->Add (s, 1); + } + + { + add_label_to_sizer(table, _panel, _("Default MPEG2 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); + auto s = new wxBoxSizer (wxHORIZONTAL); + _mpeg2_video_bit_rate = new wxSpinCtrl(_panel); + s->Add(_mpeg2_video_bit_rate); add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); table->Add (s, 1); } @@ -410,8 +419,10 @@ private: _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this)); _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this)); - _video_bit_rate->SetRange(50, 250); - _video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&DefaultsPage::video_bit_rate_changed, this)); + _j2k_video_bit_rate->SetRange(50, 250); + _j2k_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&DefaultsPage::j2k_video_bit_rate_changed, this)); + _mpeg2_video_bit_rate->SetRange(1, 50); + _mpeg2_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&DefaultsPage::mpeg2_video_bit_rate_changed, this)); _audio_delay->SetRange (-1000, 1000); _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this)); @@ -451,8 +462,10 @@ private: _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ())); _kdm_type->set (config->default_kdm_type()); checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default()); - checked_set(_video_bit_rate, config->default_video_bit_rate() / 1000000); - _video_bit_rate->SetRange(50, config->maximum_video_bit_rate() / 1000000); + checked_set(_j2k_video_bit_rate, config->default_video_bit_rate(VideoEncoding::JPEG2000) / 1000000); + _j2k_video_bit_rate->SetRange(50, config->maximum_video_bit_rate(VideoEncoding::JPEG2000) / 1000000); + checked_set(_mpeg2_video_bit_rate, config->default_video_bit_rate(VideoEncoding::MPEG2) / 1000000); + _mpeg2_video_bit_rate->SetRange(1, config->maximum_video_bit_rate(VideoEncoding::MPEG2) / 1000000); checked_set (_dcp_audio_channels, locale_convert (config->default_dcp_audio_channels())); checked_set (_audio_delay, config->default_audio_delay ()); checked_set (_standard, config->default_interop() ? 1 : 0); @@ -527,9 +540,14 @@ private: config->set_default_kdm_duration (RoughDuration(duration, unit)); } - void video_bit_rate_changed() + void j2k_video_bit_rate_changed() + { + Config::instance()->set_default_video_bit_rate(VideoEncoding::JPEG2000, _j2k_video_bit_rate->GetValue() * 1000000); + } + + void mpeg2_video_bit_rate_changed() { - Config::instance()->set_default_video_bit_rate(_video_bit_rate->GetValue() * 1000000); + Config::instance()->set_default_video_bit_rate(VideoEncoding::MPEG2, _mpeg2_video_bit_rate->GetValue() * 1000000); } void audio_delay_changed () @@ -634,7 +652,8 @@ private: } } - wxSpinCtrl* _video_bit_rate; + wxSpinCtrl* _j2k_video_bit_rate; + wxSpinCtrl* _mpeg2_video_bit_rate; wxSpinCtrl* _audio_delay; wxSpinCtrl* _still_length; #ifdef DCPOMATIC_USE_OWN_PICKER @@ -1541,10 +1560,19 @@ private: _panel->GetSizer()->Add(table, 1, wxALL | wxEXPAND, _border); { - add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); + add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); auto s = new wxBoxSizer(wxHORIZONTAL); - _maximum_video_bit_rate = new wxSpinCtrl(_panel); - s->Add(_maximum_video_bit_rate, 1); + _maximum_j2k_video_bit_rate = new wxSpinCtrl(_panel); + s->Add(_maximum_j2k_video_bit_rate, 1); + add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL); + table->Add(s, 1); + } + + { + add_label_to_sizer(table, _panel, _("Maximum MPEG2 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL); + auto s = new wxBoxSizer(wxHORIZONTAL); + _maximum_mpeg2_video_bit_rate = new wxSpinCtrl(_panel); + s->Add(_maximum_mpeg2_video_bit_rate, 1); add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL); table->Add(s, 1); } @@ -1573,8 +1601,10 @@ private: table->Add(s, 1); } - _maximum_video_bit_rate->SetRange(1, 1000); - _maximum_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_video_bit_rate_changed, this)); + _maximum_j2k_video_bit_rate->SetRange(1, 1000); + _maximum_j2k_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_video_bit_rate_changed, this)); + _maximum_mpeg2_video_bit_rate->SetRange(1, 100); + _maximum_mpeg2_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_mpeg2_video_bit_rate_changed, this)); _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this); _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this); _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this); @@ -1588,7 +1618,8 @@ private: { auto config = Config::instance(); - checked_set(_maximum_video_bit_rate, config->maximum_video_bit_rate() / 1000000); + checked_set(_maximum_j2k_video_bit_rate, config->maximum_video_bit_rate(VideoEncoding::JPEG2000) / 1000000); + checked_set(_maximum_mpeg2_video_bit_rate, config->maximum_video_bit_rate(VideoEncoding::MPEG2) / 1000000); checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate()); checked_set(_allow_any_container, config->allow_any_container()); checked_set(_allow_96khz_audio, config->allow_96khz_audio()); @@ -1597,9 +1628,14 @@ private: checked_set(_isdcf_name_part_length, config->isdcf_name_part_length()); } - void maximum_video_bit_rate_changed() + void maximum_j2k_video_bit_rate_changed() + { + Config::instance()->set_maximum_video_bit_rate(VideoEncoding::JPEG2000, _maximum_j2k_video_bit_rate->GetValue() * 1000000); + } + + void maximum_mpeg2_video_bit_rate_changed() { - Config::instance()->set_maximum_video_bit_rate(_maximum_video_bit_rate->GetValue() * 1000000); + Config::instance()->set_maximum_video_bit_rate(VideoEncoding::MPEG2, _maximum_mpeg2_video_bit_rate->GetValue() * 1000000); } void allow_any_dcp_frame_rate_changed() @@ -1632,7 +1668,8 @@ private: Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue()); } - wxSpinCtrl* _maximum_video_bit_rate = nullptr; + wxSpinCtrl* _maximum_j2k_video_bit_rate = nullptr; + wxSpinCtrl* _maximum_mpeg2_video_bit_rate = nullptr; CheckBox* _allow_any_dcp_frame_rate = nullptr; CheckBox* _allow_any_container = nullptr; CheckBox* _allow_96khz_audio = nullptr; diff --git a/test/data b/test/data index 3ab324522..06f2a187a 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 3ab3245220bd2a11cdf2e16a28221e4de063befc +Subproject commit 06f2a187ab398bc2e26034d4e0b178610315b63e diff --git a/test/film_metadata_test.cc b/test/film_metadata_test.cc index 2f1346d1d..c52df6d72 100644 --- a/test/film_metadata_test.cc +++ b/test/film_metadata_test.cc @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) film->set_name ("fred"); film->set_dcp_content_type (DCPContentType::from_isdcf_name ("SHR")); film->set_container (Ratio::from_id ("185")); - film->set_video_bit_rate(200000000); + film->set_video_bit_rate(VideoEncoding::JPEG2000, 200000000); film->set_interop (false); film->set_chain (string("")); film->set_distributor (string("")); diff --git a/test/j2k_video_bit_rate_test.cc b/test/j2k_video_bit_rate_test.cc index 67579a369..ab4c4271e 100644 --- a/test/j2k_video_bit_rate_test.cc +++ b/test/j2k_video_bit_rate_test.cc @@ -47,7 +47,7 @@ check (int target_bits_per_second) auto film = new_test_film (name); film->set_name (name); film->set_dcp_content_type (DCPContentType::from_isdcf_name ("FTR")); - film->set_video_bit_rate(target_bits_per_second); + film->set_video_bit_rate(VideoEncoding::JPEG2000, target_bits_per_second); auto content = make_shared(TestPaths::private_data() / "prophet_frame.tiff"); film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs()); diff --git a/test/reels_test.cc b/test/reels_test.cc index 5fcddfe78..e6d8cf9c6 100644 --- a/test/reels_test.cc +++ b/test/reels_test.cc @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE (reels_test1) BOOST_CHECK_EQUAL (r.back().from.get(), 288000); BOOST_CHECK_EQUAL (r.back().to.get(), 288000 * 2); - film->set_video_bit_rate(100000000); + film->set_video_bit_rate(VideoEncoding::JPEG2000, 100000000); film->set_reel_type (ReelType::BY_LENGTH); /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */ film->set_reel_length (31253154); @@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE (reels_test6) auto A = make_shared("test/data/test2.mp4"); auto film = new_test_film2 ("reels_test6", {A}); - film->set_video_bit_rate(100000000); + film->set_video_bit_rate(VideoEncoding::JPEG2000, 100000000); film->set_reel_type (ReelType::BY_LENGTH); /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */ film->set_reel_length (31253154); diff --git a/test/required_disk_space_test.cc b/test/required_disk_space_test.cc index bd969bdb2..e26a09169 100644 --- a/test/required_disk_space_test.cc +++ b/test/required_disk_space_test.cc @@ -45,7 +45,7 @@ void check_within_n (int64_t a, int64_t b, int64_t n) BOOST_AUTO_TEST_CASE (required_disk_space_test) { auto film = new_test_film ("required_disk_space_test"); - film->set_video_bit_rate(100000000); + film->set_video_bit_rate(VideoEncoding::JPEG2000, 100000000); film->set_audio_channels(8); film->set_reel_type (ReelType::BY_VIDEO_CONTENT); auto content_a = content_factory("test/data/flat_blue.png")[0]; diff --git a/test/test.cc b/test/test.cc index 1d5eb9083..ddd3d26f0 100644 --- a/test/test.cc +++ b/test/test.cc @@ -122,7 +122,7 @@ setup_test_config () Config::instance()->set_server_port_base (61921); Config::instance()->set_default_dcp_content_type (static_cast (0)); Config::instance()->set_default_audio_delay (0); - Config::instance()->set_default_video_bit_rate(100000000); + Config::instance()->set_default_video_bit_rate(VideoEncoding::JPEG2000, 100000000); Config::instance()->set_default_interop (false); Config::instance()->set_default_still_length (10); Config::instance()->set_default_dcp_audio_channels(8); -- cgit v1.2.3 From f1ab501ede5c421ed9a561774a912e7d4d0d6cd3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 6 Apr 2024 21:16:41 +0200 Subject: Remove unused Windows identifier stuff (removed from cdist). --- cscript | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cscript b/cscript index b971ff2ea..5c3e5e2b1 100644 --- a/cscript +++ b/cscript @@ -717,10 +717,7 @@ def build(target, options, for_package): target.command('./waf install') def package_windows(target): - identifier = '' - if target.version is not None: - identifier = '%s.' % target.version - identifier += '%d' % target.bits + identifier = '%d' % target.bits shutil.copyfile('build/platform/windows/installer.%s.nsi' % identifier, 'build/platform/windows/installer2.%s.nsi' % identifier) target.command('sed -i "s~%%resources%%~%s/platform/windows~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), identifier)) target.command('sed -i "s~%%graphics%%~%s/graphics~g" build/platform/windows/installer2.%s.nsi' % (os.getcwd(), identifier)) -- cgit v1.2.3 From ad222a78a4124ef861ed9bc9528581ddccef3b36 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 7 Apr 2024 20:12:20 +0200 Subject: Disable some hints when encoding to MPEG2. --- src/lib/hints.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/hints.cc b/src/lib/hints.cc index 8e678fdf1..ca69832a9 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -166,7 +166,7 @@ void Hints::check_unusual_container () { auto const film_container = film()->container()->id(); - if (film_container != "185" && film_container != "239") { + if (film()->video_encoding() != VideoEncoding::MPEG2 && film_container != "185" && film_container != "239") { hint (_("Your DCP uses an unusual container ratio. This may cause problems on some projectors. If possible, use Flat or Scope for the DCP container ratio.")); } } @@ -756,7 +756,7 @@ void Hints::check_8_or_16_audio_channels() { auto const channels = film()->audio_channels(); - if (channels != 8 && channels != 16) { + if (film()->video_encoding() != VideoEncoding::MPEG2 && channels != 8 && channels != 16) { hint(String::compose(_("Your DCP has %1 audio channels, rather than 8 or 16. This may cause some distributors to raise QC errors when they check your DCP. To avoid this, set the DCP audio channels to 8 or 16."), channels)); } } -- cgit v1.2.3 From 03a6be002b24e6cbb998d31a5cf4703de6196aa2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 7 Apr 2024 23:44:12 +0200 Subject: Use mpeg2 prefix for MPEG2 video asset filenames. --- src/lib/util.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/util.cc b/src/lib/util.cc index 60117f61d..b727d7b68 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,7 @@ LIBDCP_ENABLE_WARNINGS using std::bad_alloc; using std::cout; +using std::dynamic_pointer_cast; using std::endl; using std::istream; using std::list; @@ -748,9 +750,10 @@ asset_filename (shared_ptr asset, string type, int reel_index, int r string -video_asset_filename (shared_ptr asset, int reel_index, int reel_count, optional summary) +video_asset_filename(shared_ptr asset, int reel_index, int reel_count, optional summary) { - return asset_filename(asset, "j2c", reel_index, reel_count, summary, ".mxf"); + string type = dynamic_pointer_cast(asset) ? "mpeg2" : "j2c"; + return asset_filename(asset, type, reel_index, reel_count, summary, ".mxf"); } -- cgit v1.2.3 From 0af59e8225eae1154e4844711012646681769b00 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 7 Apr 2024 23:44:26 +0200 Subject: Report video range from MPEG2 DCPs correctly. --- src/lib/dcp_examiner.cc | 4 ++++ src/lib/dcp_examiner.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/dcp_examiner.cc b/src/lib/dcp_examiner.cc index 92491947c..229786868 100644 --- a/src/lib/dcp_examiner.cc +++ b/src/lib/dcp_examiner.cc @@ -164,6 +164,10 @@ DCPExaminer::DCPExaminer (shared_ptr content, bool tolerant) } else if (_video_size.get() != asset->size ()) { throw DCPError (_("Mismatched video sizes in DCP")); } + + if (dynamic_pointer_cast(asset)) { + _video_range = VideoRange::VIDEO; + } } } diff --git a/src/lib/dcp_examiner.h b/src/lib/dcp_examiner.h index 425552632..d6baf7d50 100644 --- a/src/lib/dcp_examiner.h +++ b/src/lib/dcp_examiner.h @@ -61,7 +61,7 @@ public: } VideoRange range () const override { - return VideoRange::FULL; + return _video_range; } PixelQuanta pixel_quanta () const override { @@ -211,6 +211,7 @@ private: Frame _atmos_length = 0; dcp::Fraction _atmos_edit_rate; EnumIndexedVector _has_non_zero_entry_point; + VideoRange _video_range = VideoRange::FULL; struct Font { -- cgit v1.2.3 From e530ee820c64828fed7b6fc1b613e57bc0968120 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 8 Apr 2024 23:57:34 +0200 Subject: Fix dcpomatic_player script for macOS. --- run/dcpomatic_player | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/run/dcpomatic_player b/run/dcpomatic_player index 0c565c251..23d2dc3d8 100755 --- a/run/dcpomatic_player +++ b/run/dcpomatic_player @@ -4,6 +4,15 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source $DIR/environment binary=build/src/tools/dcpomatic2_player +if [[ "$(uname -m)" == arm64 ]]; then + env=arm64/11.0 +else + env=x86_64/10.10 +fi + +echo $env +export DYLD_LIBRARY_PATH=/Users/cah/osx-environment/$env/lib:/usr/local/lib + if [ "$1" == "--debug" ]; then shift gdb --args build/src/tools/dcpomatic2_player $* -- cgit v1.2.3 From f762833c3348003df6d0c026582776a6e577cf76 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 8 Apr 2024 23:59:39 +0200 Subject: Don't emit video until film's end if we are seeking. Otherwise if we seek to the frame just before the end of the DCP we'll call emit_video_until() with _next_video unset, causing that method to emit video for the whole film. The point of this emit_video_until() call is only to pad a space between the end of the video content and the end of the film. --- src/lib/player.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/player.cc b/src/lib/player.cc index dba02cfba..913d7392f 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -887,8 +887,10 @@ Player::pass () } if (done) { - LOG_DEBUG_PLAYER("Done: emit video until end of film at %1", to_string(film->length())); - emit_video_until(film->length()); + if (_next_video_time) { + LOG_DEBUG_PLAYER("Done: emit video until end of film at %1", to_string(film->length())); + emit_video_until(film->length()); + } if (_shuffler) { _shuffler->flush (); -- cgit v1.2.3 From b74f594ce1dee47fdb5cbeebdc3d6577cdd1cab8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Apr 2024 10:13:31 +0200 Subject: Clarify a test result when it fails. --- test/kdm_cli_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kdm_cli_test.cc b/test/kdm_cli_test.cc index 6e54f3a6c..2a508d97c 100644 --- a/test/kdm_cli_test.cc +++ b/test/kdm_cli_test.cc @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(kdm_cli_specify_decryption_key_test) output.clear(); error = run(bad_args, output, false); BOOST_REQUIRE(error); - BOOST_CHECK(error->find("Could not decrypt KDM") != string::npos); + BOOST_CHECK_MESSAGE(error->find("Could not decrypt KDM") != string::npos, "Error was " << *error); vector good_args = { "kdm_cli", -- cgit v1.2.3