diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/audio_analysis_test.cc | 36 | ||||
| -rw-r--r-- | test/audio_mapping_test.cc | 64 | ||||
| -rw-r--r-- | test/create_cli_test.cc | 16 | ||||
| m--------- | test/data | 0 | ||||
| -rw-r--r-- | test/film_test.cc | 21 | ||||
| -rw-r--r-- | test/hints_test.cc | 33 | ||||
| -rw-r--r-- | test/image_test.cc | 347 | ||||
| -rw-r--r-- | test/kdm_cli_test.cc | 58 | ||||
| -rw-r--r-- | test/memory_util_test.cc | 72 | ||||
| -rw-r--r-- | test/packet_queue_test.cc | 116 | ||||
| -rw-r--r-- | test/render_subtitles_test.cc | 7 | ||||
| -rw-r--r-- | test/test.cc | 7 | ||||
| -rw-r--r-- | test/test.h | 1 | ||||
| -rw-r--r-- | test/util_test.cc | 18 | ||||
| -rw-r--r-- | test/vf_test.cc | 96 | ||||
| -rw-r--r-- | test/wscript | 2 |
16 files changed, 678 insertions, 216 deletions
diff --git a/test/audio_analysis_test.cc b/test/audio_analysis_test.cc index 8e04945ac..578250b2c 100644 --- a/test/audio_analysis_test.cc +++ b/test/audio_analysis_test.cc @@ -40,6 +40,7 @@ #include "lib/playlist.h" #include "lib/ratio.h" #include "test.h" +#include <dcp/scope_guard.h> #include <boost/test/unit_test.hpp> #include <numeric> @@ -315,3 +316,38 @@ BOOST_AUTO_TEST_CASE(ebur128_test) } #endif + +static bool saw_ffmpeg_error = false; + +static +void +test_log_callback(void*, int level, const char*, va_list) +{ + if (level <= AV_LOG_WARNING) { + saw_ffmpeg_error = true; + } +} + + +/* The file in this test has the audio stream as index 0, video as 1, + * with both streams having the same ID. This triggered a bug where + * on analysis (with video disabled) the video packets would be fed + * to the audio decoder, causing chaos manifesting as many audio decoder + * errors. + */ +BOOST_AUTO_TEST_CASE(analysis_stream_confusion_test) +{ + auto sound = content_factory(TestPaths::private_data() / "ge.mkv")[0]; + auto film = new_test_film("analysis_stream_confusion_test", { sound }); + + av_log_set_callback(test_log_callback); + dcp::ScopeGuard sg = []() { + capture_ffmpeg_logs(); + }; + + auto job = make_shared<AnalyseAudioJob>(film, film->playlist(), true); + JobManager::instance()->add(job); + BOOST_REQUIRE(!wait_for_jobs()); + + BOOST_CHECK(!saw_ffmpeg_error); +} diff --git a/test/audio_mapping_test.cc b/test/audio_mapping_test.cc index dfde022a0..9bc5bcf5f 100644 --- a/test/audio_mapping_test.cc +++ b/test/audio_mapping_test.cc @@ -36,71 +36,71 @@ using std::string; using boost::optional; -BOOST_AUTO_TEST_CASE (audio_mapping_test) +BOOST_AUTO_TEST_CASE(audio_mapping_test) { AudioMapping none; - BOOST_CHECK_EQUAL (none.input_channels(), 0); + BOOST_CHECK_EQUAL(none.input_channels(), 0); - AudioMapping four (4, MAX_DCP_AUDIO_CHANNELS); - BOOST_CHECK_EQUAL (four.input_channels(), 4); + AudioMapping four(4, MAX_DCP_AUDIO_CHANNELS); + BOOST_CHECK_EQUAL(four.input_channels(), 4); - four.set (0, 1, 1); + four.set(0, 1, 1); for (int i = 0; i < 4; ++i) { for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) { - BOOST_CHECK_EQUAL (four.get(i, j), (i == 0 && j == 1) ? 1 : 0); + BOOST_CHECK_EQUAL(four.get(i, j), (i == 0 && j == 1) ? 1 : 0); } } - auto mapped = four.mapped_output_channels (); - BOOST_CHECK_EQUAL (mapped.size(), 1U); - BOOST_CHECK_EQUAL (mapped.front(), 1); + auto mapped = four.mapped_output_channels(); + BOOST_CHECK_EQUAL(mapped.size(), 1U); + BOOST_CHECK_EQUAL(mapped.front(), 1); - four.make_zero (); + four.make_zero(); for (int i = 0; i < 4; ++i) { for (int j = 0; j < MAX_DCP_AUDIO_CHANNELS; ++j) { - BOOST_CHECK_EQUAL (four.get (i, j), 0); + BOOST_CHECK_EQUAL(four.get(i, j), 0); } } } static void -guess_check (boost::filesystem::path filename, int output_channel) +guess_check(boost::filesystem::path filename, dcp::Channel output_channel) { - AudioMapping m (1, 8); - m.make_default (0, filename); - for (int i = 0; i < 8; ++i) { + AudioMapping m(1, 12); + m.make_default(0, filename); + for (int i = 0; i < 12; ++i) { BOOST_TEST_INFO(fmt::format("{} channel {}", filename.string(), i)); - BOOST_CHECK_CLOSE (m.get(0, i), i == output_channel ? 1 : 0, 0.01); + BOOST_CHECK_CLOSE(m.get(0, i), i == static_cast<int>(output_channel) ? 1 : 0, 0.01); } } -BOOST_AUTO_TEST_CASE (audio_mapping_guess_test) +BOOST_AUTO_TEST_CASE(audio_mapping_guess_test) { - guess_check ("stuff_L_nonsense.wav", 0); - guess_check ("stuff_nonsense.wav", 2); - guess_check ("fred_R.wav", 1); - guess_check ("jim_C_sheila.aiff", 2); - guess_check ("things_Lfe_and.wav", 3); - guess_check ("weeee_Ls.aiff", 4); - guess_check ("try_Rs-it.wav", 5); + guess_check("stuff_L_nonsense.wav", dcp::Channel::LEFT); + guess_check("stuff_nonsense.wav", dcp::Channel::CENTRE); + guess_check("fred_R.wav", dcp::Channel::RIGHT); + guess_check("jim_C_sheila.aiff", dcp::Channel::CENTRE); + guess_check("things_Lfe_and.wav", dcp::Channel::LFE); + guess_check("weeee_Ls.aiff", dcp::Channel::LS); + guess_check("try_Rs-it.wav", dcp::Channel::RS); /* PT-style */ - guess_check ("things_LFE.wav", 3); - guess_check ("ptish_Lsr_abc.wav", 6); - guess_check ("ptish_Rsr_abc.wav", 7); - guess_check ("more_Lss_s.wav", 4); - guess_check ("other_Rss.aiff", 5); + guess_check("things_LFE.wav", dcp::Channel::LFE); + guess_check("ptish_Lsr_abc.wav", dcp::Channel::BSL); + guess_check("ptish_Rsr_abc.wav", dcp::Channel::BSR); + guess_check("more_Lss_s.wav", dcp::Channel::LS); + guess_check("other_Rss.aiff", dcp::Channel::RS); /* Only the filename should be taken into account */ - guess_check ("-Lfe-/foo_L.wav", 0); + guess_check("-Lfe-/foo_L.wav", dcp::Channel::LEFT); /* Dolby-style */ - guess_check ("jake-Lrs-good.wav", 6); - guess_check ("elwood-Rrs-good.wav", 7); + guess_check("jake-Lrs-good.wav", dcp::Channel::BSL); + guess_check("elwood-Rrs-good.wav", dcp::Channel::BSR); } diff --git a/test/create_cli_test.cc b/test/create_cli_test.cc index c71031fbc..0f127c018 100644 --- a/test/create_cli_test.cc +++ b/test/create_cli_test.cc @@ -322,6 +322,22 @@ BOOST_AUTO_TEST_CASE (create_cli_test) BOOST_CHECK(film->content()[0]->video->fade_in() == 24); BOOST_CHECK(film->content()[0]->video->fade_out() == 0); BOOST_CHECK(collected_error.empty()); + + /* Extract a 1.85 frame from a 320x240 source */ + cc = run("dcpomatic2_create --container-ratio 185 --fill-crop test/data/red_24.mp4"); + BOOST_CHECK(!cc.error); + film = cc.make_film(error); + BOOST_REQUIRE_EQUAL(film->content().size(), 1U); + BOOST_REQUIRE(film->content()[0]->video); + BOOST_CHECK(film->content()[0]->video->requested_crop() == Crop(0, 0, 33, 33)); + + /* Extract a 1.85 frame from a 2048x858 source */ + cc = run("dcpomatic2_create --container-ratio 185 --fill-crop test/data/scope_dcp"); + BOOST_CHECK(!cc.error); + film = cc.make_film(error); + BOOST_REQUIRE_EQUAL(film->content().size(), 1U); + BOOST_REQUIRE(film->content()[0]->video); + BOOST_CHECK(film->content()[0]->video->requested_crop() == Crop(230, 230, 0, 0)); } diff --git a/test/data b/test/data -Subproject fe6973d73602cff710f5ea2396a47074b21686d +Subproject cec02cb60028b76800357604f8331b903388d77 diff --git a/test/film_test.cc b/test/film_test.cc index 5ce195637..9949fd7d6 100644 --- a/test/film_test.cc +++ b/test/film_test.cc @@ -86,3 +86,24 @@ BOOST_AUTO_TEST_CASE(film_possible_reel_types_test2) BOOST_CHECK_EQUAL(film->possible_reel_types().size(), 2U); } + +BOOST_AUTO_TEST_CASE(film_copy_remembered_assets_test) +{ + dcp::filesystem::remove_all("build/test/film_copy_remembered_assets_test2"); + + auto content = content_factory("test/data/flat_red.png")[0]; + auto film = new_test_film("film_copy_remembered_assets_test", { content }); + make_and_verify_dcp(film); + + auto copy = make_shared<Film>(boost::filesystem::path("build/test/film_copy_remembered_assets_test2")); + copy->copy_from(film, [](float) {}); + + auto remembered = copy->read_remembered_assets(); + BOOST_REQUIRE_EQUAL(remembered.size(), 1U); + auto path = find_asset(remembered, *copy->directory(), dcpomatic::DCPTimePeriod({}, dcpomatic::DCPTime::from_seconds(10)), film->video_identifier()); + BOOST_CHECK(path.has_value()); + + for (auto path: dcp::filesystem::directory_iterator(film->dir("info"))) { + check_file(path.path(), copy->dir("info") / path.path().filename()); + } +} diff --git a/test/hints_test.cc b/test/hints_test.cc index 073415018..7cb9d676b 100644 --- a/test/hints_test.cc +++ b/test/hints_test.cc @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE (hint_subtitle_mxf_too_big) BOOST_CHECK_EQUAL ( hints[0], "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. " - "You should divide the DCP into shorter reels." + "The largest file is 134MB. You should divide the DCP into shorter reels." ); } @@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE (hint_closed_caption_xml_too_big) BOOST_CHECK_EQUAL ( hints[0], "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT ". " - "You should divide the DCP into shorter reels." + "The largest XML part is 482KB. You should divide the DCP into shorter reels." ); } @@ -326,3 +326,32 @@ BOOST_AUTO_TEST_CASE(hints_120fps) BOOST_CHECK(hint.find("There is a large difference between the frame rate of your DCP and that of some of your content.") == std::string::npos); } } + + +BOOST_AUTO_TEST_CASE(hints_ccap_not_too_many_lines_xml) +{ + auto content = content_factory(TestPaths::private_data() / "ccap_not_too_many_lines.xml")[0]; + auto film = new_test_film("hints_ccap_not_too_many_lines", { content }); + content->text[0]->set_type(TextType::CLOSED_CAPTION); + auto hints = get_hints(film); + + BOOST_CHECK( + std::none_of(hints.begin(), hints.end(), [](string const& hint) { + return hint.find("Some of your closed captions span more than 3 lines") != std::string::npos; + }) + ); +} + + +BOOST_AUTO_TEST_CASE(hints_ccap_too_many_lines_xml) +{ + auto content = content_factory(TestPaths::private_data() / "ccap_too_many_lines.xml")[0]; + auto film = new_test_film("hints_ccap_too_many_lines", { content }); + content->text[0]->set_type(TextType::CLOSED_CAPTION); + auto hints = get_hints(film); + BOOST_CHECK( + std::any_of(hints.begin(), hints.end(), [](string const& hint) { + return hint.find("Some of your closed captions span more than 3 lines") != std::string::npos; + }) + ); +} diff --git a/test/image_test.cc b/test/image_test.cc index aa3baeb4f..6d566aac7 100644 --- a/test/image_test.cc +++ b/test/image_test.cc @@ -43,50 +43,50 @@ using std::make_shared; using std::string; -BOOST_AUTO_TEST_CASE (aligned_image_test) +BOOST_AUTO_TEST_CASE(aligned_image_test) { - auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), Image::Alignment::PADDED); - BOOST_CHECK_EQUAL (s->planes(), 1); + auto s = new Image(AV_PIX_FMT_RGB24, dcp::Size(50, 50), Image::Alignment::PADDED); + BOOST_CHECK_EQUAL(s->planes(), 1); /* 192 is 150 aligned to the nearest 64 bytes */ - BOOST_CHECK_EQUAL (s->stride()[0], 192); - BOOST_CHECK_EQUAL (s->line_size()[0], 150); - BOOST_CHECK (s->data()[0]); - BOOST_CHECK (!s->data()[1]); - BOOST_CHECK (!s->data()[2]); - BOOST_CHECK (!s->data()[3]); + BOOST_CHECK_EQUAL(s->stride()[0], 192); + BOOST_CHECK_EQUAL(s->line_size()[0], 150); + BOOST_CHECK(s->data()[0]); + BOOST_CHECK(!s->data()[1]); + BOOST_CHECK(!s->data()[2]); + BOOST_CHECK(!s->data()[3]); /* copy constructor */ - auto t = new Image (*s); - BOOST_CHECK_EQUAL (t->planes(), 1); - BOOST_CHECK_EQUAL (t->stride()[0], 192); - BOOST_CHECK_EQUAL (t->line_size()[0], 150); - BOOST_CHECK (t->data()[0]); - BOOST_CHECK (!t->data()[1]); - BOOST_CHECK (!t->data()[2]); - BOOST_CHECK (!t->data()[3]); - BOOST_CHECK (t->data() != s->data()); - BOOST_CHECK (t->data()[0] != s->data()[0]); - BOOST_CHECK (t->line_size() != s->line_size()); - BOOST_CHECK_EQUAL (t->line_size()[0], s->line_size()[0]); - BOOST_CHECK (t->stride() != s->stride()); - BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]); + auto t = new Image(*s); + BOOST_CHECK_EQUAL(t->planes(), 1); + BOOST_CHECK_EQUAL(t->stride()[0], 192); + BOOST_CHECK_EQUAL(t->line_size()[0], 150); + BOOST_CHECK(t->data()[0]); + BOOST_CHECK(!t->data()[1]); + BOOST_CHECK(!t->data()[2]); + BOOST_CHECK(!t->data()[3]); + BOOST_CHECK(t->data() != s->data()); + BOOST_CHECK(t->data()[0] != s->data()[0]); + BOOST_CHECK(t->line_size() != s->line_size()); + BOOST_CHECK_EQUAL(t->line_size()[0], s->line_size()[0]); + BOOST_CHECK(t->stride() != s->stride()); + BOOST_CHECK_EQUAL(t->stride()[0], s->stride()[0]); /* assignment operator */ - auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), Image::Alignment::COMPACT); + auto u = new Image(AV_PIX_FMT_YUV422P, dcp::Size(150, 150), Image::Alignment::COMPACT); *u = *s; - BOOST_CHECK_EQUAL (u->planes(), 1); - BOOST_CHECK_EQUAL (u->stride()[0], 192); - BOOST_CHECK_EQUAL (u->line_size()[0], 150); - BOOST_CHECK (u->data()[0]); - BOOST_CHECK (!u->data()[1]); - BOOST_CHECK (!u->data()[2]); - BOOST_CHECK (!u->data()[3]); - BOOST_CHECK (u->data() != s->data()); - BOOST_CHECK (u->data()[0] != s->data()[0]); - BOOST_CHECK (u->line_size() != s->line_size()); - BOOST_CHECK_EQUAL (u->line_size()[0], s->line_size()[0]); - BOOST_CHECK (u->stride() != s->stride()); - BOOST_CHECK_EQUAL (u->stride()[0], s->stride()[0]); + BOOST_CHECK_EQUAL(u->planes(), 1); + BOOST_CHECK_EQUAL(u->stride()[0], 192); + BOOST_CHECK_EQUAL(u->line_size()[0], 150); + BOOST_CHECK(u->data()[0]); + BOOST_CHECK(!u->data()[1]); + BOOST_CHECK(!u->data()[2]); + BOOST_CHECK(!u->data()[3]); + BOOST_CHECK(u->data() != s->data()); + BOOST_CHECK(u->data()[0] != s->data()[0]); + BOOST_CHECK(u->line_size() != s->line_size()); + BOOST_CHECK_EQUAL(u->line_size()[0], s->line_size()[0]); + BOOST_CHECK(u->stride() != s->stride()); + BOOST_CHECK_EQUAL(u->stride()[0], s->stride()[0]); delete s; delete t; @@ -94,49 +94,49 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) } -BOOST_AUTO_TEST_CASE (compact_image_test) +BOOST_AUTO_TEST_CASE(compact_image_test) { - auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), Image::Alignment::COMPACT); - BOOST_CHECK_EQUAL (s->planes(), 1); - BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3); - BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3); - BOOST_CHECK (s->data()[0]); - BOOST_CHECK (!s->data()[1]); - BOOST_CHECK (!s->data()[2]); - BOOST_CHECK (!s->data()[3]); + auto s = new Image(AV_PIX_FMT_RGB24, dcp::Size(50, 50), Image::Alignment::COMPACT); + BOOST_CHECK_EQUAL(s->planes(), 1); + BOOST_CHECK_EQUAL(s->stride()[0], 50 * 3); + BOOST_CHECK_EQUAL(s->line_size()[0], 50 * 3); + BOOST_CHECK(s->data()[0]); + BOOST_CHECK(!s->data()[1]); + BOOST_CHECK(!s->data()[2]); + BOOST_CHECK(!s->data()[3]); /* copy constructor */ - auto t = new Image (*s); - BOOST_CHECK_EQUAL (t->planes(), 1); - BOOST_CHECK_EQUAL (t->stride()[0], 50 * 3); - BOOST_CHECK_EQUAL (t->line_size()[0], 50 * 3); - BOOST_CHECK (t->data()[0]); - BOOST_CHECK (!t->data()[1]); - BOOST_CHECK (!t->data()[2]); - BOOST_CHECK (!t->data()[3]); - BOOST_CHECK (t->data() != s->data()); - BOOST_CHECK (t->data()[0] != s->data()[0]); - BOOST_CHECK (t->line_size() != s->line_size()); - BOOST_CHECK_EQUAL (t->line_size()[0], s->line_size()[0]); - BOOST_CHECK (t->stride() != s->stride()); - BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]); + auto t = new Image(*s); + BOOST_CHECK_EQUAL(t->planes(), 1); + BOOST_CHECK_EQUAL(t->stride()[0], 50 * 3); + BOOST_CHECK_EQUAL(t->line_size()[0], 50 * 3); + BOOST_CHECK(t->data()[0]); + BOOST_CHECK(!t->data()[1]); + BOOST_CHECK(!t->data()[2]); + BOOST_CHECK(!t->data()[3]); + BOOST_CHECK(t->data() != s->data()); + BOOST_CHECK(t->data()[0] != s->data()[0]); + BOOST_CHECK(t->line_size() != s->line_size()); + BOOST_CHECK_EQUAL(t->line_size()[0], s->line_size()[0]); + BOOST_CHECK(t->stride() != s->stride()); + BOOST_CHECK_EQUAL(t->stride()[0], s->stride()[0]); /* assignment operator */ - auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), Image::Alignment::PADDED); + auto u = new Image(AV_PIX_FMT_YUV422P, dcp::Size(150, 150), Image::Alignment::PADDED); *u = *s; - BOOST_CHECK_EQUAL (u->planes(), 1); - BOOST_CHECK_EQUAL (u->stride()[0], 50 * 3); - BOOST_CHECK_EQUAL (u->line_size()[0], 50 * 3); - BOOST_CHECK (u->data()[0]); - BOOST_CHECK (!u->data()[1]); - BOOST_CHECK (!u->data()[2]); - BOOST_CHECK (!u->data()[3]); - BOOST_CHECK (u->data() != s->data()); - BOOST_CHECK (u->data()[0] != s->data()[0]); - BOOST_CHECK (u->line_size() != s->line_size()); - BOOST_CHECK_EQUAL (u->line_size()[0], s->line_size()[0]); - BOOST_CHECK (u->stride() != s->stride()); - BOOST_CHECK_EQUAL (u->stride()[0], s->stride()[0]); + BOOST_CHECK_EQUAL(u->planes(), 1); + BOOST_CHECK_EQUAL(u->stride()[0], 50 * 3); + BOOST_CHECK_EQUAL(u->line_size()[0], 50 * 3); + BOOST_CHECK(u->data()[0]); + BOOST_CHECK(!u->data()[1]); + BOOST_CHECK(!u->data()[2]); + BOOST_CHECK(!u->data()[3]); + BOOST_CHECK(u->data() != s->data()); + BOOST_CHECK(u->data()[0] != s->data()[0]); + BOOST_CHECK(u->line_size() != s->line_size()); + BOOST_CHECK_EQUAL(u->line_size()[0], s->line_size()[0]); + BOOST_CHECK(u->stride() != s->stride()); + BOOST_CHECK_EQUAL(u->stride()[0], s->stride()[0]); delete s; delete t; @@ -150,10 +150,10 @@ alpha_blend_test_bgra_onto(AVPixelFormat format, string suffix) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "prophet_frame.tiff"); auto raw = proxy->image(Image::Alignment::PADDED).image; - auto background = raw->convert_pixel_format (dcp::YUVToRGB::REC709, format, Image::Alignment::PADDED, false); + auto background = raw->convert_pixel_format(dcp::YUVToRGB::REC709, format, Image::Alignment::PADDED, false); auto overlay = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size(431, 891), Image::Alignment::PADDED); - overlay->make_transparent (); + overlay->make_transparent(); for (int y = 0; y < 128; ++y) { auto p = overlay->data()[0] + y * overlay->stride()[0]; @@ -179,9 +179,9 @@ alpha_blend_test_bgra_onto(AVPixelFormat format, string suffix) } } - background->alpha_blend (overlay, Position<int> (13, 17)); + background->alpha_blend(overlay, Position<int>(13, 17)); - auto save = background->convert_pixel_format (dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false); + auto save = background->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false); write_image(save, "build/test/image_test_bgra_" + suffix + ".png"); check_image("build/test/image_test_bgra_" + suffix + ".png", TestPaths::private_data() / ("image_test_bgra_" + suffix + ".png")); @@ -194,7 +194,7 @@ alpha_blend_test_rgba64be_onto(AVPixelFormat format, string suffix) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "prophet_frame.tiff"); auto raw = proxy->image(Image::Alignment::PADDED).image; - auto background = raw->convert_pixel_format (dcp::YUVToRGB::REC709, format, Image::Alignment::PADDED, false); + auto background = raw->convert_pixel_format(dcp::YUVToRGB::REC709, format, Image::Alignment::PADDED, false); auto overlay = make_shared<Image>(AV_PIX_FMT_RGBA64BE, dcp::Size(431, 891), Image::Alignment::PADDED); overlay->make_transparent(); @@ -233,7 +233,7 @@ alpha_blend_test_rgba64be_onto(AVPixelFormat format, string suffix) /** Test Image::alpha_blend */ -BOOST_AUTO_TEST_CASE (alpha_blend_test) +BOOST_AUTO_TEST_CASE(alpha_blend_test) { alpha_blend_test_bgra_onto(AV_PIX_FMT_RGB24, "rgb24"); alpha_blend_test_bgra_onto(AV_PIX_FMT_BGRA, "bgra"); @@ -348,12 +348,12 @@ BOOST_AUTO_TEST_CASE(alpha_blend_text) /** Test merge (list<PositionImage>) with a single image */ -BOOST_AUTO_TEST_CASE (merge_test1) +BOOST_AUTO_TEST_CASE(merge_test1) { int const stride = 48 * 4; - auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 48), Image::Alignment::COMPACT); - A->make_transparent (); + auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size(48, 48), Image::Alignment::COMPACT); + A->make_transparent(); auto a = A->data()[0]; for (int y = 0; y < 48; ++y) { @@ -367,19 +367,19 @@ BOOST_AUTO_TEST_CASE (merge_test1) } list<PositionImage> all; - all.push_back (PositionImage (A, Position<int>(0, 0))); - auto merged = merge (all, Image::Alignment::COMPACT); + all.push_back(PositionImage(A, Position<int>(0, 0))); + auto merged = merge(all, Image::Alignment::COMPACT); - BOOST_CHECK (merged.position == Position<int>(0, 0)); - BOOST_CHECK_EQUAL (memcmp (merged.image->data()[0], A->data()[0], stride * 48), 0); + BOOST_CHECK(merged.position == Position<int>(0, 0)); + BOOST_CHECK_EQUAL(memcmp(merged.image->data()[0], A->data()[0], stride * 48), 0); } /** Test merge (list<PositionImage>) with two images */ -BOOST_AUTO_TEST_CASE (merge_test2) +BOOST_AUTO_TEST_CASE(merge_test2) { - auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 1), Image::Alignment::COMPACT); - A->make_transparent (); + auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size(48, 1), Image::Alignment::COMPACT); + A->make_transparent(); auto a = A->data()[0]; for (int x = 0; x < 16; ++x) { /* blue */ @@ -388,8 +388,8 @@ BOOST_AUTO_TEST_CASE (merge_test2) a[x * 4 + 3] = 255; } - auto B = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 1), Image::Alignment::COMPACT); - B->make_transparent (); + auto B = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size(48, 1), Image::Alignment::COMPACT); + B->make_transparent(); auto b = B->data()[0]; for (int x = 0; x < 16; ++x) { /* red */ @@ -399,26 +399,26 @@ BOOST_AUTO_TEST_CASE (merge_test2) } list<PositionImage> all; - all.push_back (PositionImage(A, Position<int>(0, 0))); - all.push_back (PositionImage(B, Position<int>(0, 0))); - auto merged = merge (all, Image::Alignment::COMPACT); + all.push_back(PositionImage(A, Position<int>(0, 0))); + all.push_back(PositionImage(B, Position<int>(0, 0))); + auto merged = merge(all, Image::Alignment::COMPACT); - BOOST_CHECK (merged.position == Position<int>(0, 0)); + BOOST_CHECK(merged.position == Position<int>(0, 0)); auto m = merged.image->data()[0]; for (int x = 0; x < 16; ++x) { - BOOST_CHECK_EQUAL (m[x * 4], 255); - BOOST_CHECK_EQUAL (m[x * 4 + 3], 255); - BOOST_CHECK_EQUAL (m[(x + 16) * 4 + 3], 0); - BOOST_CHECK_EQUAL (m[(x + 32) * 4 + 2], 255); - BOOST_CHECK_EQUAL (m[(x + 32) * 4 + 3], 255); + BOOST_CHECK_EQUAL(m[x * 4], 255); + BOOST_CHECK_EQUAL(m[x * 4 + 3], 255); + BOOST_CHECK_EQUAL(m[(x + 16) * 4 + 3], 0); + BOOST_CHECK_EQUAL(m[(x + 32) * 4 + 2], 255); + BOOST_CHECK_EQUAL(m[(x + 32) * 4 + 3], 255); } } /** Test Image::crop_scale_window with YUV420P and some windowing */ -BOOST_AUTO_TEST_CASE (crop_scale_window_test) +BOOST_AUTO_TEST_CASE(crop_scale_window_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/flat_red.png"); auto raw = proxy->image(Image::Alignment::PADDED).image; @@ -432,19 +432,19 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test) /** Special cases of Image::crop_scale_window which triggered some valgrind warnings */ -BOOST_AUTO_TEST_CASE (crop_scale_window_test2) +BOOST_AUTO_TEST_CASE(crop_scale_window_test2) { auto image = make_shared<Image>(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), Image::Alignment::PADDED); - image->crop_scale_window ( + image->crop_scale_window( Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); - image->crop_scale_window ( + image->crop_scale_window( Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); } -BOOST_AUTO_TEST_CASE (crop_scale_window_test3) +BOOST_AUTO_TEST_CASE(crop_scale_window_test3) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); @@ -456,7 +456,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test3) } -BOOST_AUTO_TEST_CASE (crop_scale_window_test4) +BOOST_AUTO_TEST_CASE(crop_scale_window_test4) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); @@ -472,7 +472,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test4) } -BOOST_AUTO_TEST_CASE (crop_scale_window_test5) +BOOST_AUTO_TEST_CASE(crop_scale_window_test5) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, Image::Alignment::PADDED, false); @@ -484,7 +484,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test5) } -BOOST_AUTO_TEST_CASE (crop_scale_window_test6) +BOOST_AUTO_TEST_CASE(crop_scale_window_test6) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, Image::Alignment::PADDED, false); @@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test6) /** Test some small crops with an image that shows up errors in registration of the YUV planes (#1872) */ -BOOST_AUTO_TEST_CASE (crop_scale_window_test7) +BOOST_AUTO_TEST_CASE(crop_scale_window_test7) { using namespace boost::filesystem; for (int left_crop = 0; left_crop < 8; ++left_crop) { @@ -526,7 +526,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) } -BOOST_AUTO_TEST_CASE (crop_scale_window_test8) +BOOST_AUTO_TEST_CASE(crop_scale_window_test8) { using namespace boost::filesystem; @@ -543,20 +543,20 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test8) } -BOOST_AUTO_TEST_CASE (as_png_test) +BOOST_AUTO_TEST_CASE(as_png_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/3d_test/000001.png"); auto image_rgb = proxy->image(Image::Alignment::PADDED).image; auto image_bgr = image_rgb->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_BGRA, Image::Alignment::PADDED, false); - image_as_png(image_rgb).write ("build/test/as_png_rgb.png"); - image_as_png(image_bgr).write ("build/test/as_png_bgr.png"); + image_as_png(image_rgb).write("build/test/as_png_rgb.png"); + image_as_png(image_bgr).write("build/test/as_png_bgr.png"); - check_image ("test/data/3d_test/000001.png", "build/test/as_png_rgb.png"); - check_image ("test/data/3d_test/000001.png", "build/test/as_png_bgr.png"); + check_image("test/data/3d_test/000001.png", "build/test/as_png_rgb.png"); + check_image("test/data/3d_test/000001.png", "build/test/as_png_bgr.png"); } -BOOST_AUTO_TEST_CASE (as_jpeg_test) +BOOST_AUTO_TEST_CASE(as_jpeg_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/3d_test/000001.png"); auto image_rgb = proxy->image(Image::Alignment::PADDED).image; @@ -564,67 +564,67 @@ BOOST_AUTO_TEST_CASE (as_jpeg_test) image_as_jpeg(image_rgb, 60).write("build/test/as_jpeg_rgb.jpeg"); image_as_jpeg(image_bgr, 60).write("build/test/as_jpeg_bgr.jpeg"); - check_image ("test/data/as_jpeg_rgb.jpeg", "build/test/as_jpeg_rgb.jpeg"); - check_image ("test/data/as_jpeg_bgr.jpeg", "build/test/as_jpeg_bgr.jpeg"); + check_image("test/data/as_jpeg_rgb.jpeg", "build/test/as_jpeg_rgb.jpeg"); + check_image("test/data/as_jpeg_bgr.jpeg", "build/test/as_jpeg_bgr.jpeg"); } /* Very dumb test to fade black to make sure it stays black */ static void -fade_test_format_black (AVPixelFormat f, string name) +fade_test_format_black(AVPixelFormat f, string name) { - Image yuv (f, dcp::Size(640, 480), Image::Alignment::PADDED); - yuv.make_black (); - yuv.fade (0); + Image yuv(f, dcp::Size(640, 480), Image::Alignment::PADDED); + yuv.make_black(); + yuv.fade(0); string const filename = "fade_test_black_" + name + ".png"; image_as_png(yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)).write("build/test/" + filename); - check_image ("test/data/" + filename, "build/test/" + filename); + check_image("test/data/" + filename, "build/test/" + filename); } /* Fade red to make sure it stays red */ static void -fade_test_format_red (AVPixelFormat f, float amount, string name) +fade_test_format_red(AVPixelFormat f, float amount, string name) { auto proxy = make_shared<FFmpegImageProxy>("test/data/flat_red.png"); auto red = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, f, Image::Alignment::PADDED, false); - red->fade (amount); + red->fade(amount); string const filename = "fade_test_red_" + name + ".png"; image_as_png(red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)).write("build/test/" + filename); - check_image ("test/data/" + filename, "build/test/" + filename); + check_image("test/data/" + filename, "build/test/" + filename); } -BOOST_AUTO_TEST_CASE (fade_test) +BOOST_AUTO_TEST_CASE(fade_test) { - fade_test_format_black (AV_PIX_FMT_YUV420P, "yuv420p"); - fade_test_format_black (AV_PIX_FMT_YUV422P10, "yuv422p10"); - fade_test_format_black (AV_PIX_FMT_RGB24, "rgb24"); - fade_test_format_black (AV_PIX_FMT_XYZ12LE, "xyz12le"); - fade_test_format_black (AV_PIX_FMT_RGB48LE, "rgb48le"); - - fade_test_format_red (AV_PIX_FMT_YUV420P, 0, "yuv420p_0"); - fade_test_format_red (AV_PIX_FMT_YUV420P, 0.5, "yuv420p_50"); - fade_test_format_red (AV_PIX_FMT_YUV420P, 1, "yuv420p_100"); - fade_test_format_red (AV_PIX_FMT_YUV422P10, 0, "yuv422p10_0"); - fade_test_format_red (AV_PIX_FMT_YUV422P10, 0.5, "yuv422p10_50"); - fade_test_format_red (AV_PIX_FMT_YUV422P10, 1, "yuv422p10_100"); - fade_test_format_red (AV_PIX_FMT_RGB24, 0, "rgb24_0"); - fade_test_format_red (AV_PIX_FMT_RGB24, 0.5, "rgb24_50"); - fade_test_format_red (AV_PIX_FMT_RGB24, 1, "rgb24_100"); - fade_test_format_red (AV_PIX_FMT_XYZ12LE, 0, "xyz12le_0"); - fade_test_format_red (AV_PIX_FMT_XYZ12LE, 0.5, "xyz12le_50"); - fade_test_format_red (AV_PIX_FMT_XYZ12LE, 1, "xyz12le_100"); - fade_test_format_red (AV_PIX_FMT_RGB48LE, 0, "rgb48le_0"); - fade_test_format_red (AV_PIX_FMT_RGB48LE, 0.5, "rgb48le_50"); - fade_test_format_red (AV_PIX_FMT_RGB48LE, 1, "rgb48le_100"); + fade_test_format_black(AV_PIX_FMT_YUV420P, "yuv420p"); + fade_test_format_black(AV_PIX_FMT_YUV422P10, "yuv422p10"); + fade_test_format_black(AV_PIX_FMT_RGB24, "rgb24"); + fade_test_format_black(AV_PIX_FMT_XYZ12LE, "xyz12le"); + fade_test_format_black(AV_PIX_FMT_RGB48LE, "rgb48le"); + + fade_test_format_red (AV_PIX_FMT_YUV420P, 0, "yuv420p_0"); + fade_test_format_red (AV_PIX_FMT_YUV420P, 0.5, "yuv420p_50"); + fade_test_format_red (AV_PIX_FMT_YUV420P, 1, "yuv420p_100"); + fade_test_format_red (AV_PIX_FMT_YUV422P10, 0, "yuv422p10_0"); + fade_test_format_red (AV_PIX_FMT_YUV422P10, 0.5, "yuv422p10_50"); + fade_test_format_red (AV_PIX_FMT_YUV422P10, 1, "yuv422p10_100"); + fade_test_format_red (AV_PIX_FMT_RGB24, 0, "rgb24_0"); + fade_test_format_red (AV_PIX_FMT_RGB24, 0.5, "rgb24_50"); + fade_test_format_red (AV_PIX_FMT_RGB24, 1, "rgb24_100"); + fade_test_format_red (AV_PIX_FMT_XYZ12LE, 0, "xyz12le_0"); + fade_test_format_red (AV_PIX_FMT_XYZ12LE, 0.5, "xyz12le_50"); + fade_test_format_red (AV_PIX_FMT_XYZ12LE, 1, "xyz12le_100"); + fade_test_format_red (AV_PIX_FMT_RGB48LE, 0, "rgb48le_0"); + fade_test_format_red (AV_PIX_FMT_RGB48LE, 0.5, "rgb48le_50"); + fade_test_format_red (AV_PIX_FMT_RGB48LE, 1, "rgb48le_100"); } -BOOST_AUTO_TEST_CASE (make_black_test) +BOOST_AUTO_TEST_CASE(make_black_test) { - dcp::Size in_size (512, 512); - dcp::Size out_size (1024, 1024); + dcp::Size in_size(512, 512); + dcp::Size out_size(1024, 1024); list<AVPixelFormat> pix_fmts = { AV_PIX_FMT_RGB24, // 2 @@ -667,8 +667,8 @@ BOOST_AUTO_TEST_CASE (make_black_test) for (auto i: pix_fmts) { auto foo = make_shared<Image>(i, in_size, Image::Alignment::PADDED); - foo->make_black (); - auto bar = foo->scale (out_size, dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); + foo->make_black(); + auto bar = foo->scale(out_size, dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); uint8_t* p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { @@ -677,7 +677,7 @@ BOOST_AUTO_TEST_CASE (make_black_test) if (*q != 0) { std::cerr << "x=" << x << ", (x % 3)=" << (x % 3) << "\n"; } - BOOST_CHECK_EQUAL (*q++, 0); + BOOST_CHECK_EQUAL(*q++, 0); } p += bar->stride()[0]; } @@ -685,7 +685,7 @@ BOOST_AUTO_TEST_CASE (make_black_test) } -BOOST_AUTO_TEST_CASE (make_part_black_test) +BOOST_AUTO_TEST_CASE(make_part_black_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/flat_red.png"); auto original = proxy->image(Image::Alignment::PADDED).image; @@ -709,8 +709,8 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) for (auto i: pix_fmts) { for (auto j: positions) { auto foo = original->convert_pixel_format(dcp::YUVToRGB::REC601, i, Image::Alignment::PADDED, false); - foo->make_part_black (j.first, j.second); - auto bar = foo->convert_pixel_format (dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); + foo->make_part_black(j.first, j.second); + auto bar = foo->convert_pixel_format(dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { @@ -720,19 +720,19 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) int g = *q++; int b = *q++; if (x >= j.first && x < (j.first + j.second)) { - BOOST_CHECK_MESSAGE ( + BOOST_CHECK_MESSAGE( r < 3, "red=" << static_cast<int>(r) << " at (" << x << "," << y << ") format " << i << " from " << j.first << " width " << j.second ); } else { - BOOST_CHECK_MESSAGE ( + BOOST_CHECK_MESSAGE( r >= 252, "red=" << static_cast<int>(r) << " at (" << x << "," << y << ") format " << i << " from " << j.first << " width " << j.second ); } - BOOST_CHECK_MESSAGE ( + BOOST_CHECK_MESSAGE( g == 0, "green=" << static_cast<int>(g) << " at (" << x << "," << y << ") format " << i << " from " << j.first << " width " << j.second ); - BOOST_CHECK_MESSAGE ( + BOOST_CHECK_MESSAGE( b == 0, "blue=" << static_cast<int>(b) << " at (" << x << "," << y << ") format " << i << " from " << j.first << " width " << j.second ); } @@ -747,14 +747,27 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) * filler 128x128 black frame is emitted from the FFmpegDecoder and the overall crop in either direction * is greater than 128 pixels. */ -BOOST_AUTO_TEST_CASE (over_crop_test) +BOOST_AUTO_TEST_CASE(over_crop_test) { auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(128, 128), Image::Alignment::PADDED); - image->make_black (); - auto scaled = image->crop_scale_window ( + image->make_black(); + auto scaled = image->crop_scale_window( Crop(0, 0, 128, 128), dcp::Size(1323, 565), dcp::Size(1349, 565), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::PADDED, true ); string const filename = "over_crop_test.png"; - write_image (scaled, "build/test/" + filename); - check_image ("test/data/" + filename, "build/test/" + filename); + write_image(scaled, "build/test/" + filename); + check_image("test/data/" + filename, "build/test/" + filename); } + + +BOOST_AUTO_TEST_CASE(rgb0_image_test) +{ + auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "rgb0.tif"); + write_image( + proxy->image(Image::Alignment::PADDED).image->convert_pixel_format( + dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false + ), "build/test/rgb0.png" + ); + check_image(TestPaths::private_data() / "rgb0.png", "build/test/rgb0.png"); +} + diff --git a/test/kdm_cli_test.cc b/test/kdm_cli_test.cc index 4bc3ddf46..4913986f3 100644 --- a/test/kdm_cli_test.cc +++ b/test/kdm_cli_test.cc @@ -364,3 +364,61 @@ BOOST_AUTO_TEST_CASE(kdm_cli_add_dkdm) BOOST_CHECK_EQUAL(dkdm->dkdm().as_xml(), dcp::file_to_string("test/data/dkdm.xml")); } + +BOOST_AUTO_TEST_CASE(kdm_cli_formulation_warning) +{ + vector<string> args = { + "kdm_cli", + "--valid-from", "now", + "--valid-duration", "2 weeks", + "--trusted-device-chain", "test/data/decryption_chain", + "--projector-certificate", "test/data/cert.pem", + "-S", "my great screen", + "-o", "build/test", + "test/data/dkdm.xml" + }; + + boost::filesystem::path const kdm_filename = "build/test/KDM_Test_FTR-1_F-133_XX-XX_MOS_2K_20220109_SMPTE_OV__my_great_screen.xml"; + boost::system::error_code ec; + boost::filesystem::remove(kdm_filename, ec); + + vector<string> output; + auto error = run(args, output); + BOOST_CHECK(!error); + BOOST_REQUIRE_EQUAL(output.size(), 1U); + BOOST_CHECK(output[0].find("the KDM formulation you specified will not write them to the KDM") != std::string::npos); + + BOOST_CHECK(boost::filesystem::exists(kdm_filename)); +} + + +BOOST_AUTO_TEST_CASE(kdm_cli_trusted_device_chain) +{ + vector<string> args = { + "kdm_cli", + "--valid-from", "now", + "--valid-duration", "2 weeks", + "--trusted-device-chain", "test/data/decryption_chain", + "--projector-certificate", "test/data/cert.pem", + "-S", "my great screen", + "-o", "build/test", + "-F", "multiple-modified-transitional-1", + "test/data/dkdm.xml" + }; + + boost::filesystem::path const kdm_filename = "build/test/KDM_Test_FTR-1_F-133_XX-XX_MOS_2K_20220109_SMPTE_OV__my_great_screen.xml"; + boost::system::error_code ec; + boost::filesystem::remove(kdm_filename, ec); + + vector<string> output; + auto error = run(args, output); + BOOST_CHECK(!error); + BOOST_CHECK(output.empty()); + + BOOST_CHECK(boost::filesystem::exists(kdm_filename)); + + dcp::EncryptedKDM kdm(dcp::file_to_string(kdm_filename)); + BOOST_REQUIRE_EQUAL(kdm.trusted_devices().size(), 1U); + BOOST_CHECK_EQUAL(kdm.trusted_devices()[0], "KTEVkrCuEsqjXQSPy/H/lpVC9ys="); +} + diff --git a/test/memory_util_test.cc b/test/memory_util_test.cc new file mode 100644 index 000000000..43dedb5ce --- /dev/null +++ b/test/memory_util_test.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2026 Carl Hetherington <cth@carlh.net> + + 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 <http://www.gnu.org/licenses/>. + +*/ + + +#include "lib/memory_util.h" +#include <boost/test/unit_test.hpp> + + +void check(void* p, int size, uint64_t value) +{ + uint8_t* up = reinterpret_cast<uint8_t*>(p); + for (int i = 0; i < size; ++i) { + BOOST_CHECK_EQUAL(*up++, (value >> (i * 8)) & 0xff); + } +} + + +/** Aligned, multiple of 64 size */ +BOOST_AUTO_TEST_CASE(fill_memory_test1) +{ + int constexpr size = 256; + auto memory = wrapped_av_malloc(size); + BOOST_REQUIRE_EQUAL(reinterpret_cast<uintptr_t>(memory) % 8, 0); + + fill_memory(memory, size, 0x1928374654abdfea); + check(memory, size, 0x1928374654abdfea); +} + + +/** Aligned, extra bytes at the end */ +BOOST_AUTO_TEST_CASE(fill_memory_test2) +{ + int constexpr size = 259; + + auto memory = wrapped_av_malloc(size); + BOOST_REQUIRE_EQUAL(reinterpret_cast<uintptr_t>(memory) % 8, 0); + + fill_memory(memory, size, 0x1928374654abdfea); + check(memory, size, 0x1928374654abdfea); +} + + +/** Non-aligned, extra bytes at start and end */ +BOOST_AUTO_TEST_CASE(fill_memory_test3) +{ + int constexpr size = 265; + + auto memory = wrapped_av_malloc(size + 512); + BOOST_REQUIRE_EQUAL(reinterpret_cast<uintptr_t>(memory) % 8, 0); + memory = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + 3); + + fill_memory(memory, size, 0x1928374654abdfea); + check(memory, size, 0x1928374654abdfea); +} + diff --git a/test/packet_queue_test.cc b/test/packet_queue_test.cc new file mode 100644 index 000000000..ae1cc5b22 --- /dev/null +++ b/test/packet_queue_test.cc @@ -0,0 +1,116 @@ +/* + Copyright (C) 2026 Carl Hetherington <cth@carlh.net> + + 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 <http://www.gnu.org/licenses/>. + +*/ + + +#include "lib/subtitle_sync_packet_queue.h" +extern "C" { +#include <libavcodec/packet.h> +} +#include <boost/test/unit_test.hpp> + + +BOOST_AUTO_TEST_CASE(subtitle_sync_packet_queue_test) +{ + SubtitleSyncPacketQueue queue; + std::vector<std::pair<AVPacket*, PacketQueue::Type>> expected; + + auto add_video = [&queue, &expected]() { + auto packet = av_packet_alloc(); + queue.add(packet, PacketQueue::Type::VIDEO); + expected.push_back(std::make_pair(packet, PacketQueue::Type::VIDEO)); + return packet; + }; + + auto add_audio = [&queue, &expected]() { + auto packet = av_packet_alloc(); + queue.add(packet, PacketQueue::Type::AUDIO); + expected.push_back(std::make_pair(packet, PacketQueue::Type::AUDIO)); + return packet; + }; + + auto add_subtitle = [&queue]() { + auto packet = av_packet_alloc(); + queue.add(packet, PacketQueue::Type::SUBTITLE); + return packet; + }; + + auto check = [&queue](bool flush, std::pair<AVPacket*, PacketQueue::Type> ref) { + auto check = queue.get(flush); + BOOST_CHECK(check.has_value()); + BOOST_CHECK(boost::get<AVPacket*>(check->first) == ref.first); + BOOST_CHECK(check->second == ref.second); + }; + + for (int i = 0; i < 24; ++i) { + add_video(); + add_audio(); + add_audio(); + } + + BOOST_CHECK(queue.get(false) == boost::none); + + for (int i = 0; i < 23; ++i) { + add_video(); + add_audio(); + add_audio(); + } + + BOOST_CHECK(queue.get(false) == boost::none); + + auto iter = expected.begin(); + + add_video(); + check(false, *iter); + ++iter; + + auto sub1 = add_subtitle(); + auto sub2 = add_subtitle(); + + for (int i = 0; i < 24; ++i) { + add_video(); + add_audio(); + add_audio(); + } + + check(false, { sub1, PacketQueue::Type::SUBTITLE }); + check(false, { sub2, PacketQueue::Type::SUBTITLE }); + + for (int i = 0; i < 24; ++i) { + check(false, *iter); + ++iter; + check(false, *iter); + ++iter; + check(false, *iter); + ++iter; + } + + for (int i = 0; i < 47; ++i) { + check(true, *iter); + BOOST_REQUIRE(iter != expected.end()); + ++iter; + check(true, *iter); + BOOST_REQUIRE(iter != expected.end()); + ++iter; + check(true, *iter); + BOOST_REQUIRE(iter != expected.end()); + ++iter; + } +} + diff --git a/test/render_subtitles_test.cc b/test/render_subtitles_test.cc index 4e87abde0..4fc98cb56 100644 --- a/test/render_subtitles_test.cc +++ b/test/render_subtitles_test.cc @@ -176,8 +176,11 @@ BOOST_AUTO_TEST_CASE(render_text_with_newline_test) #elif defined(DCPOMATIC_WINDOWS) check_image("test/data/windows/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png"); #elif PANGO_VERSION_CHECK(1, 57, 0) - /* This pango version is the one on Arch, which renders slightly differently */ - check_image("test/data/arch/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png"); + /* This pango version is the one on Arch and Ubuntu 26.04, both of which render slightly differently */ + BOOST_REQUIRE( + check_image_and_report("test/data/arch/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png") + || check_image_and_report("test/data/ubuntu-26.04/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png") + ); #elif PANGO_VERSION_CHECK(1, 52, 1) /* This pango version is the one on Ubuntu 24.04, which renders slightly differently */ check_image("test/data/ubuntu-24.04/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png"); diff --git a/test/test.cc b/test/test.cc index 641ee4085..27b00b9d3 100644 --- a/test/test.cc +++ b/test/test.cc @@ -473,6 +473,13 @@ check_image (boost::filesystem::path ref, boost::filesystem::path check, double } +bool +check_image_and_report(boost::filesystem::path ref, boost::filesystem::path check, double threshold) +{ + return rms_error(ref, check) < threshold; +} + + void check_file (boost::filesystem::path ref, boost::filesystem::path check) { diff --git a/test/test.h b/test/test.h index 172edcf71..cd40c7872 100644 --- a/test/test.h +++ b/test/test.h @@ -69,6 +69,7 @@ extern bool mxf_atmos_files_same (boost::filesystem::path ref, boost::filesystem extern void check_xml(boost::filesystem::path, boost::filesystem::path, std::list<Glib::ustring>); extern void check_ffmpeg(boost::filesystem::path, boost::filesystem::path, float audio_tolerance); extern void check_image(boost::filesystem::path ref, boost::filesystem::path check, double threshold = 4); +extern bool check_image_and_report(boost::filesystem::path ref, boost::filesystem::path check, double threshold = 4); extern boost::filesystem::path test_film_dir (std::string); extern void write_image (std::shared_ptr<const Image> image, boost::filesystem::path file); boost::filesystem::path dcp_file (std::shared_ptr<const Film> film, std::string prefix); diff --git a/test/util_test.cc b/test/util_test.cc index defc7f907..ee26cc18c 100644 --- a/test/util_test.cc +++ b/test/util_test.cc @@ -93,11 +93,11 @@ BOOST_AUTO_TEST_CASE(seconds_to_approximate_hms_test) BOOST_AUTO_TEST_CASE(time_to_hmsf_test) { - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(12, 24), 24), "00:00:00.12"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(24, 24), 24), "00:00:01.00"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(32, 24), 24), "00:00:01.08"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(92), 24), "00:01:32.00"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(2 * 60 * 60 + 92), 24), "02:01:32.00"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(12, 24), 24), "00:00:00:12"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(24, 24), 24), "00:00:01:00"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(32, 24), 24), "00:00:01:08"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(92), 24), "00:01:32:00"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(2 * 60 * 60 + 92), 24), "02:01:32:00"); } @@ -110,14 +110,6 @@ BOOST_AUTO_TEST_CASE(tidy_for_filename_test) } -BOOST_AUTO_TEST_CASE(utf8_strlen_test) -{ - BOOST_CHECK_EQUAL(utf8_strlen("hello world"), 11U); - BOOST_CHECK_EQUAL(utf8_strlen("hëllo world"), 11U); - BOOST_CHECK_EQUAL(utf8_strlen("hëłlo wørld"), 11U); -} - - BOOST_AUTO_TEST_CASE(careful_string_filter_test) { BOOST_CHECK_EQUAL("hello_world", careful_string_filter("hello_world")); diff --git a/test/vf_test.cc b/test/vf_test.cc index 9c7ff65be..29b9913fd 100644 --- a/test/vf_test.cc +++ b/test/vf_test.cc @@ -592,3 +592,99 @@ BOOST_AUTO_TEST_CASE(vf_subs_get_font_from_ov) auto vf_font = find_file(*font_dir, "font"); check_file("test/data/Inconsolata-VF.ttf", vf_font); } + + +/** CCAPs in OVs would not correctly be referred to as we'd incorrectly create an + * empty filler CCAP asset. + */ +BOOST_AUTO_TEST_CASE(vf_referring_to_ov_ccap_test) +{ + auto picture = content_factory("test/data/flat_red.png")[0]; + auto ccap = content_factory("test/data/short.srt")[0]; + auto ov = new_test_film("vf_referring_to_ov_ccap_test_ov", { picture, ccap }); + ccap->only_text()->set_use(true); + ccap->only_text()->set_type(TextType::CLOSED_CAPTION); + ccap->only_text()->set_dcp_track(DCPTextTrack("First track", dcp::LanguageTag("fr"))); + make_and_verify_dcp(ov, { dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME }); + + auto ov_dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name())); + auto subs = content_factory("test/data/short.srt")[0]; + auto vf = new_test_film("vf_referring_to_ov_ccap_test_vf", { ov_dcp, subs }); + vf->set_reel_type(ReelType::BY_VIDEO_CONTENT); + ov_dcp->set_reference_video(true); + ov_dcp->set_reference_audio(true); + ov_dcp->set_reference_text(TextType::CLOSED_CAPTION, true); + subs->only_text()->set_use(true); + subs->only_text()->set_type(TextType::OPEN_SUBTITLE); + subs->set_position(vf, dcpomatic::DCPTime()); + vf->write_metadata(); + make_dcp(vf, TranscodeJob::ChangedBehaviour::IGNORE); + BOOST_REQUIRE(!wait_for_jobs()); + + dcp::DCP ov_check(ov->dir(ov->dcp_name())); + ov_check.read(); + dcp::DCP vf_check(vf->dir(vf->dcp_name())); + vf_check.read(); + + BOOST_REQUIRE_EQUAL(ov_check.cpls().size(), 1U); + BOOST_REQUIRE_EQUAL(vf_check.cpls().size(), 1U); + BOOST_REQUIRE_EQUAL(ov_check.cpls()[0]->reels().size(), 1U); + BOOST_REQUIRE_EQUAL(vf_check.cpls()[0]->reels().size(), 1U); + BOOST_REQUIRE_EQUAL(ov_check.cpls()[0]->reels()[0]->closed_captions().size(), 1U); + BOOST_REQUIRE_EQUAL(vf_check.cpls()[0]->reels()[0]->closed_captions().size(), 1U); + + BOOST_CHECK_EQUAL( + ov_check.cpls()[0]->reels()[0]->closed_captions()[0]->id(), + vf_check.cpls()[0]->reels()[0]->closed_captions()[0]->id() + ); +} + + +/** Check that in a VF we can have a CCAP reel which refers to the OV and another + * which is an auto-created filler. + */ +BOOST_AUTO_TEST_CASE(ccaps_can_be_referred_and_filled_test) +{ + auto picture = content_factory("test/data/flat_red.png")[0]; + auto ccap = content_factory("test/data/short.srt")[0]; + auto ov = new_test_film("ccaps_can_be_referred_and_filled_test_ov", { picture, ccap }); + ccap->only_text()->set_use(true); + ccap->only_text()->set_type(TextType::CLOSED_CAPTION); + ccap->only_text()->set_dcp_track(DCPTextTrack("First track", dcp::LanguageTag("fr"))); + make_and_verify_dcp(ov, { dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME }); + + auto ov_dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name())); + auto subs = content_factory("test/data/short.srt")[0]; + auto vf = new_test_film("ccaps_can_be_referred_and_filled_test_vf", { ov_dcp, subs, picture }); + vf->set_reel_type(ReelType::BY_VIDEO_CONTENT); + ov_dcp->set_reference_video(true); + ov_dcp->set_reference_audio(true); + ov_dcp->set_reference_text(TextType::CLOSED_CAPTION, true); + subs->only_text()->set_use(true); + subs->only_text()->set_type(TextType::OPEN_SUBTITLE); + subs->set_position(vf, dcpomatic::DCPTime()); + vf->write_metadata(); + make_dcp(vf, TranscodeJob::ChangedBehaviour::IGNORE); + BOOST_REQUIRE(!wait_for_jobs()); + + dcp::DCP ov_check(ov->dir(ov->dcp_name())); + ov_check.read(); + dcp::DCP vf_check(vf->dir(vf->dcp_name())); + vf_check.read(); + + BOOST_REQUIRE_EQUAL(ov_check.cpls().size(), 1U); + BOOST_REQUIRE_EQUAL(vf_check.cpls().size(), 1U); + BOOST_REQUIRE_EQUAL(ov_check.cpls()[0]->reels().size(), 1U); + BOOST_REQUIRE_EQUAL(vf_check.cpls()[0]->reels().size(), 2U); + + BOOST_REQUIRE_EQUAL(ov_check.cpls()[0]->reels()[0]->closed_captions().size(), 1U); + BOOST_REQUIRE_EQUAL(vf_check.cpls()[0]->reels()[0]->closed_captions().size(), 1U); + + BOOST_CHECK_EQUAL( + ov_check.cpls()[0]->reels()[0]->closed_captions()[0]->id(), + vf_check.cpls()[0]->reels()[0]->closed_captions()[0]->id() + ); + + BOOST_REQUIRE_EQUAL(vf_check.cpls()[0]->reels()[1]->closed_captions().size(), 1U); +} + diff --git a/test/wscript b/test/wscript index 1390beebb..3c8e2229a 100644 --- a/test/wscript +++ b/test/wscript @@ -136,11 +136,13 @@ def build(bld): markers_test.cc map_cli_test.cc mca_subdescriptors_test.cc + memory_util_test.cc mpeg2_dcp_test.cc no_use_video_test.cc open_caption_test.cc optimise_stills_test.cc overlap_video_test.cc + packet_queue_test.cc pixel_formats_test.cc player_test.cc playlist_test.cc |
