diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-12-13 21:23:41 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2021-01-17 20:13:22 +0100 |
| commit | 254fda18939ba1153ea8f45b4a71f687dc28573f (patch) | |
| tree | e12890160d162033105204f4019d2d0272da32c5 | |
| parent | 7701297decde2568e11feddede28177077e164cc (diff) | |
Bv2.1 7.1: Check picture size and frame rate.
| -rw-r--r-- | BRANCH | 2 | ||||
| -rw-r--r-- | src/verify.cc | 72 | ||||
| -rw-r--r-- | src/verify.h | 8 | ||||
| -rw-r--r-- | test/verify_test.cc | 155 |
4 files changed, 234 insertions, 3 deletions
@@ -17,5 +17,5 @@ Mark things with [Bv2.1_paragraph] - CPL metadata ReleaseTerritory 7 [/] -7.1 picture essence encoding; frame size, rate and 2D/3D will be one of the four allowed combinations +7.1 picture essence encoding; frame size, rate and 2D/3D will be one of the four allowed combinations [/] diff --git a/src/verify.cc b/src/verify.cc index d78e6462..78c087da 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -480,7 +480,8 @@ verify_main_picture_asset ( list<VerificationNote>& notes ) { - boost::filesystem::path const file = *reel_asset->asset()->file(); + shared_ptr<const PictureAsset> asset = reel_asset->asset(); + boost::filesystem::path const file = *asset->file(); stage ("Checking picture asset hash", file); VerifyAssetResult const r = verify_asset (dcp, reel_asset, progress); switch (r) { @@ -501,7 +502,7 @@ verify_main_picture_asset ( default: break; } - stage ("Checking picture frame sizes", reel_asset->asset()->file()); + stage ("Checking picture frame sizes", asset->file()); VerifyPictureAssetResult const pr = verify_picture_asset (reel_asset, progress); switch (pr) { case VERIFY_PICTURE_ASSET_RESULT_BAD: @@ -521,6 +522,64 @@ verify_main_picture_asset ( default: break; } + + /* Only flat/scope allowed by Bv2.1 */ + if ( + asset->size() != dcp::Size(2048, 858) && + asset->size() != dcp::Size(1998, 1080) && + asset->size() != dcp::Size(4096, 1716) && + asset->size() != dcp::Size(3996, 2160)) { + notes.push_back( + VerificationNote( + VerificationNote::VERIFY_BV21_ERROR, + VerificationNote::PICTURE_ASSET_INVALID_SIZE_IN_PIXELS, + String::compose("%1x%2", asset->size().width, asset->size().height), + file + ) + ); + } + + /* Only 24, 25, 48fps allowed for 2K */ + if ( + (asset->size() == dcp::Size(2048, 858) || asset->size() == dcp::Size(1998, 1080)) && + (asset->edit_rate() != dcp::Fraction(24, 1) && asset->edit_rate() != dcp::Fraction(25, 1) && asset->edit_rate() != dcp::Fraction(48, 1)) + ) { + notes.push_back( + VerificationNote( + VerificationNote::VERIFY_BV21_ERROR, + VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K, + String::compose("%1/%2", asset->edit_rate().numerator, asset->edit_rate().denominator), + file + ) + ); + } + + if (asset->size() == dcp::Size(4096, 1716) || asset->size() == dcp::Size(3996, 2160)) { + /* Only 24fps allowed for 4K */ + if (asset->edit_rate() != dcp::Fraction(24, 1)) { + notes.push_back( + VerificationNote( + VerificationNote::VERIFY_BV21_ERROR, + VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K, + String::compose("%1/%2", asset->edit_rate().numerator, asset->edit_rate().denominator), + file + ) + ); + } + + /* Only 2D allowed for 4K */ + if (dynamic_pointer_cast<const StereoPictureAsset>(asset)) { + notes.push_back( + VerificationNote( + VerificationNote::VERIFY_BV21_ERROR, + VerificationNote::PICTURE_ASSET_4K_3D, + file + ) + ); + + } + } + } @@ -768,6 +827,15 @@ dcp::note_to_string (dcp::VerificationNote note) return "This DCP does not use the SMPTE standard, which is required for Bv2.1 compliance."; case dcp::VerificationNote::BAD_LANGUAGE: return String::compose("The DCP specifies a language '%1' which does not conform to the RFC 5646 standard.", note.note().get()); + case dcp::VerificationNote::PICTURE_ASSET_INVALID_SIZE_IN_PIXELS: + return String::compose("A picture asset's size (%1) is not one of those allowed by Bv2.1 (2048x858, 1998x1080, 4096x1716 or 3996x2160)", note.note().get()); + case dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K: + return String::compose("A picture asset's frame rate (%1) is not one of those allowed for 2K DCPs by Bv2.1 (24, 25 or 48fps)", note.note().get()); + case dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K: + return String::compose("A picture asset's frame rate (%1) is not 24fps as required for 4K DCPs by Bv2.1", note.note().get()); + case dcp::VerificationNote::PICTURE_ASSET_4K_3D: + return "3D 4K DCPs are not allowed by Bv2.1"; + } return ""; diff --git a/src/verify.h b/src/verify.h index 24a9e671..500918de 100644 --- a/src/verify.h +++ b/src/verify.h @@ -94,6 +94,14 @@ public: NOT_SMPTE, /** A language or territory does not conform to RFC 5646 [Bv2.1_6.2.1] */ BAD_LANGUAGE, + /** A picture asset does not have one of the required Bv2.1 sizes (in pixels) [Bv2.1_7.1] */ + PICTURE_ASSET_INVALID_SIZE_IN_PIXELS, + /** A picture asset is 2K but is not at 24, 25 or 48 fps as required by Bv2.1 [Bv2.1_7.1] */ + PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K, + /** A picture asset is 4K but is not at 24fps as required by Bv2.1 [Bv2.1_7.1] */ + PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K, + /** A picture asset is 4K but is 3D which is not allowed by Bv2.1 [Bv2.1_7.1] */ + PICTURE_ASSET_4K_3D, }; VerificationNote (Type type, Code code) diff --git a/test/verify_test.cc b/test/verify_test.cc index e74a737a..e8396dd1 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -41,10 +41,12 @@ #include "dcp.h" #include "openjpeg_image.h" #include "mono_picture_asset.h" +#include "stereo_picture_asset.h" #include "mono_picture_asset_writer.h" #include "interop_subtitle_asset.h" #include "smpte_subtitle_asset.h" #include "reel_closed_caption_asset.h" +#include "reel_stereo_picture_asset.h" #include "reel_subtitle_asset.h" #include "compose.hpp" #include "test.h" @@ -1002,3 +1004,156 @@ BOOST_AUTO_TEST_CASE (verify_various_invalid_languages) ++i; } + +static +list<dcp::VerificationNote> +check_picture_size (int width, int height, int frame_rate, bool three_d) +{ + using namespace boost::filesystem; + + path dcp_path = "build/test/verify_picture_test"; + remove_all (dcp_path); + create_directories (dcp_path); + + shared_ptr<dcp::PictureAsset> mp; + if (three_d) { + mp.reset (new dcp::StereoPictureAsset(dcp::Fraction(frame_rate, 1), dcp::SMPTE)); + } else { + mp.reset (new dcp::MonoPictureAsset(dcp::Fraction(frame_rate, 1), dcp::SMPTE)); + } + shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write (dcp_path / "video.mxf", false); + + shared_ptr<dcp::OpenJPEGImage> image = black_image (dcp::Size(width, height)); + dcp::ArrayData j2c = dcp::compress_j2k (image, 100000000, frame_rate, three_d, width > 2048); + int const length = three_d ? frame_rate * 2 : frame_rate; + for (int i = 0; i < length; ++i) { + picture_writer->write (j2c.data(), j2c.size()); + } + picture_writer->finalize (); + + shared_ptr<dcp::DCP> d (new dcp::DCP(dcp_path)); + shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::FEATURE)); + cpl->set_annotation_text ("A Test DCP"); + cpl->set_issue_date ("2012-07-17T04:45:18+00:00"); + + shared_ptr<dcp::Reel> reel(new dcp::Reel()); + + if (three_d) { + reel->add ( + shared_ptr<dcp::ReelPictureAsset>( + new dcp::ReelStereoPictureAsset( + std::dynamic_pointer_cast<dcp::StereoPictureAsset>(mp), + 0) + ) + ); + } else { + reel->add ( + shared_ptr<dcp::ReelPictureAsset>( + new dcp::ReelMonoPictureAsset( + std::dynamic_pointer_cast<dcp::MonoPictureAsset>(mp), + 0) + ) + ); + } + + cpl->add (reel); + + d->add (cpl); + d->write_xml (dcp::SMPTE); + + vector<boost::filesystem::path> dirs; + dirs.push_back (dcp_path); + return dcp::verify (dirs, &stage, &progress, xsd_test); +} + + +static +void +check_picture_size_ok (int width, int height, int frame_rate, bool three_d) +{ + list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d); + dump_notes (notes); + BOOST_CHECK_EQUAL (notes.size(), 0U); +} + + +static +void +check_picture_size_bad_frame_size (int width, int height, int frame_rate, bool three_d) +{ + list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d); + BOOST_REQUIRE_EQUAL (notes.size(), 1U); + BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR); + BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_SIZE_IN_PIXELS); +} + + +static +void +check_picture_size_bad_2k_frame_rate (int width, int height, int frame_rate, bool three_d) +{ + list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d); + BOOST_REQUIRE_EQUAL (notes.size(), 2U); + BOOST_CHECK_EQUAL (notes.back().type(), dcp::VerificationNote::VERIFY_BV21_ERROR); + BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K); +} + + +static +void +check_picture_size_bad_4k_frame_rate (int width, int height, int frame_rate, bool three_d) +{ + list<dcp::VerificationNote> notes = check_picture_size(width, height, frame_rate, three_d); + BOOST_REQUIRE_EQUAL (notes.size(), 1U); + BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR); + BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K); +} + + +BOOST_AUTO_TEST_CASE (verify_picture_size) +{ + using namespace boost::filesystem; + + /* 2K scope */ + check_picture_size_ok (2048, 858, 24, false); + check_picture_size_ok (2048, 858, 25, false); + check_picture_size_ok (2048, 858, 48, false); + check_picture_size_ok (2048, 858, 24, true); + check_picture_size_ok (2048, 858, 25, true); + check_picture_size_ok (2048, 858, 48, true); + + /* 2K flat */ + check_picture_size_ok (1998, 1080, 24, false); + check_picture_size_ok (1998, 1080, 25, false); + check_picture_size_ok (1998, 1080, 48, false); + check_picture_size_ok (1998, 1080, 24, true); + check_picture_size_ok (1998, 1080, 25, true); + check_picture_size_ok (1998, 1080, 48, true); + + /* 4K scope */ + check_picture_size_ok (4096, 1716, 24, false); + + /* 4K flat */ + check_picture_size_ok (3996, 2160, 24, false); + + /* Bad frame size */ + check_picture_size_bad_frame_size (2050, 858, 24, false); + check_picture_size_bad_frame_size (2048, 658, 25, false); + check_picture_size_bad_frame_size (1920, 1080, 48, true); + check_picture_size_bad_frame_size (4000, 3000, 24, true); + + /* Bad 2K frame rate */ + check_picture_size_bad_2k_frame_rate (2048, 858, 26, false); + check_picture_size_bad_2k_frame_rate (2048, 858, 31, false); + check_picture_size_bad_2k_frame_rate (1998, 1080, 50, true); + + /* Bad 4K frame rate */ + check_picture_size_bad_4k_frame_rate (3996, 2160, 25, false); + check_picture_size_bad_4k_frame_rate (3996, 2160, 48, false); + + /* No 4K 3D */ + list<dcp::VerificationNote> notes = check_picture_size(3996, 2160, 24, true); + BOOST_REQUIRE_EQUAL (notes.size(), 1U); + BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR); + BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::PICTURE_ASSET_4K_3D); +} |
