diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-09-09 23:55:49 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2020-09-17 23:07:19 +0200 |
| commit | c19f63dd173e5497070b26528dbac240d5595583 (patch) | |
| tree | 6a2f3760005a1ef8a613ffec5d3df82b1574a61f /test | |
| parent | 62757708dd14df8806eb6482e83afb06a6160f0a (diff) | |
Add dcp::combine().
Diffstat (limited to 'test')
| -rw-r--r-- | test/combine_test.cc | 341 | ||||
| -rw-r--r-- | test/test.cc | 193 | ||||
| -rw-r--r-- | test/test.h | 15 | ||||
| -rw-r--r-- | test/wscript | 1 |
4 files changed, 514 insertions, 36 deletions
diff --git a/test/combine_test.cc b/test/combine_test.cc new file mode 100644 index 00000000..70c55b90 --- /dev/null +++ b/test/combine_test.cc @@ -0,0 +1,341 @@ +/* + Copyright (C) 2020 Carl Hetherington <cth@carlh.net> + + This file is part of libdcp. + + libdcp 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. + + libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>. + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +#include "combine.h" +#include "cpl.h" +#include "dcp.h" +#include "interop_subtitle_asset.h" +#include "reel_subtitle_asset.h" +#include "reel_mono_picture_asset.h" +#include "reel_sound_asset.h" +#include "test.h" +#include "types.h" +#include "verify.h" +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <boost/optional.hpp> +#include <boost/test/unit_test.hpp> +#include <iostream> + + +using std::list; +using std::string; +using std::vector; +using boost::optional; +using boost::shared_ptr; + + +static void +stage (string, optional<boost::filesystem::path>) +{ +} + + +static void +progress (float) +{ +} + + +static +void +dump_notes (list<dcp::VerificationNote> const & notes) +{ + BOOST_FOREACH (dcp::VerificationNote i, notes) { + std::cout << dcp::note_to_string(i) << "\n"; + } +} + + +static +void +check_no_errors (boost::filesystem::path path) +{ + vector<boost::filesystem::path> directories; + directories.push_back (path); + list<dcp::VerificationNote> notes = dcp::verify (directories, &stage, &progress, xsd_test); + dump_notes (notes); + BOOST_CHECK (notes.empty()); +} + + +template <class T> +shared_ptr<T> +pointer_to_id_in_list (shared_ptr<T> needle, list<shared_ptr<T> > haystack) +{ + BOOST_FOREACH (shared_ptr<T> i, haystack) { + if (i->id() == needle->id()) { + return i; + } + } + + return shared_ptr<T>(); +} + + +static +void +note_handler (dcp::NoteType, std::string) +{ + // std::cout << "> " << n << "\n"; +} + + +static +void +check_combined (vector<boost::filesystem::path> inputs, boost::filesystem::path output) +{ + dcp::DCP output_dcp (output); + output_dcp.read (); + + dcp::EqualityOptions options; + options.load_font_nodes_can_differ = true; + + BOOST_FOREACH (boost::filesystem::path i, inputs) + { + dcp::DCP input_dcp (i); + input_dcp.read (); + + BOOST_REQUIRE (input_dcp.cpls().size() == 1); + shared_ptr<dcp::CPL> input_cpl = input_dcp.cpls().front(); + + shared_ptr<dcp::CPL> output_cpl = pointer_to_id_in_list (input_cpl, output_dcp.cpls()); + BOOST_REQUIRE (output_cpl); + + BOOST_FOREACH (shared_ptr<dcp::Asset> i, input_dcp.assets(true)) { + shared_ptr<dcp::Asset> o = pointer_to_id_in_list(i, output_dcp.assets()); + BOOST_REQUIRE_MESSAGE (o, "Could not find " << i->id() << " in combined DCP."); + BOOST_CHECK (i->equals(o, options, note_handler)); + } + } +} + + +BOOST_AUTO_TEST_CASE (combine_single_dcp_test) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_single_dcp_test"; + + remove_all (out); + vector<path> inputs; + inputs.push_back ("test/ref/DCP/dcp_test1"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_dcps_with_same_asset_filenames_test) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_dcps_with_same_asset_filenames_test"; + + shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2"); + second->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("test/ref/DCP/dcp_test1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_subs_test) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_subs_test"; + + shared_ptr<dcp::DCP> first = make_simple_with_interop_subs ("build/test/combine_input1"); + first->write_xml (dcp::INTEROP, dcp::XMLMetadata()); + + shared_ptr<dcp::DCP> second = make_simple_with_interop_subs ("build/test/combine_input2"); + second->write_xml (dcp::INTEROP, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("build/test/combine_input1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_subs_test) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_dcps_with_smpte_subs_test"; + + shared_ptr<dcp::DCP> first = make_simple_with_smpte_subs ("build/test/combine_input1"); + first->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + shared_ptr<dcp::DCP> second = make_simple_with_smpte_subs ("build/test/combine_input2"); + second->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("build/test/combine_input1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_dcps_with_interop_ccaps_test) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test"; + + shared_ptr<dcp::DCP> first = make_simple_with_interop_ccaps ("build/test/combine_input1"); + first->write_xml (dcp::INTEROP, dcp::XMLMetadata()); + + shared_ptr<dcp::DCP> second = make_simple_with_interop_ccaps ("build/test/combine_input2"); + second->write_xml (dcp::INTEROP, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("build/test/combine_input1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_dcps_with_smpte_ccaps_test) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_dcps_with_interop_ccaps_test"; + + shared_ptr<dcp::DCP> first = make_simple_with_smpte_ccaps ("build/test/combine_input1"); + first->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + shared_ptr<dcp::DCP> second = make_simple_with_smpte_ccaps ("build/test/combine_input2"); + second->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("build/test/combine_input1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_multi_reel_dcps) +{ + using namespace boost::algorithm; + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_multi_reel_dcps"; + + shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 4); + first->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + shared_ptr<dcp::DCP> second = make_simple ("build/test/combine_input2", 4); + second->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("build/test/combine_input1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset) +{ + using namespace boost::filesystem; + boost::filesystem::path const out = "build/test/combine_two_dcps_with_shared_asset"; + + shared_ptr<dcp::DCP> first = make_simple ("build/test/combine_input1", 1); + first->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + remove_all ("build/test/combine_input2"); + shared_ptr<dcp::DCP> second(new dcp::DCP("build/test/combine_input2")); + + /* Some known metadata */ + dcp::XMLMetadata xml_meta; + xml_meta.annotation_text = "A Test DCP"; + xml_meta.issuer = "OpenDCP 0.0.25"; + xml_meta.creator = "OpenDCP 0.0.25"; + xml_meta.issue_date = "2012-07-17T04:45:18+00:00"; + dcp::MXFMetadata mxf_meta; + mxf_meta.company_name = "OpenDCP"; + mxf_meta.product_name = "OpenDCP"; + mxf_meta.product_version = "0.0.25"; + + shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::FEATURE)); + cpl->set_content_version_id ("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11"); + cpl->set_content_version_label_text ("content-version-label-text"); + cpl->set_metadata (xml_meta); + + shared_ptr<dcp::ReelMonoPictureAsset> pic(new dcp::ReelMonoPictureAsset(simple_picture("build/test/combine_input2", ""), 0)); + shared_ptr<dcp::ReelSoundAsset> sound(new dcp::ReelSoundAsset(first->cpls().front()->reels().front()->main_sound()->asset(), 0)); + cpl->add (shared_ptr<dcp::Reel>(new dcp::Reel(pic, sound))); + second->add (cpl); + second->write_xml (dcp::SMPTE, dcp::XMLMetadata()); + + remove_all (out); + vector<path> inputs; + inputs.push_back ("build/test/combine_input1"); + inputs.push_back ("build/test/combine_input2"); + dcp::combine (inputs, out); + + check_no_errors (out); + check_combined (inputs, out); +} + + +/* XXX: same CPL names */ +/* XXX: Interop PNG subs */ diff --git a/test/test.cc b/test/test.cc index a53eedc9..60dabcd4 100644 --- a/test/test.cc +++ b/test/test.cc @@ -33,16 +33,21 @@ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE libdcp_test +#include "compose.hpp" #include "cpl.h" #include "dcp.h" #include "file.h" +#include "interop_subtitle_asset.h" #include "mono_picture_asset.h" #include "picture_asset_writer.h" #include "reel.h" #include "reel_mono_picture_asset.h" #include "reel_sound_asset.h" +#include "reel_closed_caption_asset.h" +#include "reel_subtitle_asset.h" #include "sound_asset.h" #include "sound_asset_writer.h" +#include "smpte_subtitle_asset.h" #include "test.h" #include "util.h" #include <asdcp/KM_util.h> @@ -57,6 +62,7 @@ using std::string; using std::min; using std::list; using boost::shared_ptr; +using boost::optional; boost::filesystem::path private_test; boost::filesystem::path xsd_test = "build/test/xsd with spaces"; @@ -202,8 +208,29 @@ RNGFixer::~RNGFixer () } +shared_ptr<dcp::MonoPictureAsset> +simple_picture (boost::filesystem::path path, string suffix) +{ + dcp::MXFMetadata mxf_meta; + mxf_meta.company_name = "OpenDCP"; + mxf_meta.product_name = "OpenDCP"; + mxf_meta.product_version = "0.0.25"; + + shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1), dcp::SMPTE)); + mp->set_metadata (mxf_meta); + shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write (path / dcp::String::compose("video%1.mxf", suffix), false); + dcp::File j2c ("test/data/32x32_red_square.j2c"); + for (int i = 0; i < 24; ++i) { + picture_writer->write (j2c.data (), j2c.size ()); + } + picture_writer->finalize (); + + return mp; +} + + shared_ptr<dcp::DCP> -make_simple (boost::filesystem::path path) +make_simple (boost::filesystem::path path, int reels) { /* Some known metadata */ dcp::XMLMetadata xml_meta; @@ -216,7 +243,6 @@ make_simple (boost::filesystem::path path) mxf_meta.product_name = "OpenDCP"; mxf_meta.product_version = "0.0.25"; - /* We're making build/test/DCP/dcp_test1 */ boost::filesystem::remove_all (path); boost::filesystem::create_directories (path); shared_ptr<dcp::DCP> d (new dcp::DCP (path)); @@ -225,46 +251,143 @@ make_simple (boost::filesystem::path path) cpl->set_content_version_label_text ("content-version-label-text"); cpl->set_metadata (xml_meta); - shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1), dcp::SMPTE)); - mp->set_metadata (mxf_meta); - shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write (path / "video.mxf", false); - dcp::File j2c ("test/data/32x32_red_square.j2c"); - for (int i = 0; i < 24; ++i) { - picture_writer->write (j2c.data (), j2c.size ()); - } - picture_writer->finalize (); - - shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset (dcp::Fraction (24, 1), 48000, 1, dcp::SMPTE)); - ms->set_metadata (mxf_meta); - shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write (path / "audio.mxf"); - - SF_INFO info; - info.format = 0; - SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info); - BOOST_CHECK (sndfile); - float buffer[4096*6]; - float* channels[1]; - channels[0] = buffer; - while (true) { - sf_count_t N = sf_readf_float (sndfile, buffer, 4096); - sound_writer->write (channels, N); - if (N < 4096) { - break; + for (int i = 0; i < reels; ++i) { + string suffix = reels == 1 ? "" : dcp::String::compose("%1", i); + + shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (path, suffix); + + shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset (dcp::Fraction (24, 1), 48000, 1, dcp::SMPTE)); + ms->set_metadata (mxf_meta); + shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write (path / dcp::String::compose("audio%1.mxf", suffix)); + + SF_INFO info; + info.format = 0; + SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info); + BOOST_CHECK (sndfile); + float buffer[4096*6]; + float* channels[1]; + channels[0] = buffer; + while (true) { + sf_count_t N = sf_readf_float (sndfile, buffer, 4096); + sound_writer->write (channels, N); + if (N < 4096) { + break; + } } - } - sound_writer->finalize (); + sound_writer->finalize (); - cpl->add (shared_ptr<dcp::Reel> ( - new dcp::Reel ( - shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)), - shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (ms, 0)) - ) - )); + cpl->add (shared_ptr<dcp::Reel> ( + new dcp::Reel ( + shared_ptr<dcp::ReelMonoPictureAsset>(new dcp::ReelMonoPictureAsset(mp, 0)), + shared_ptr<dcp::ReelSoundAsset>(new dcp::ReelSoundAsset(ms, 0)) + ) + )); + } d->add (cpl); return d; } +shared_ptr<dcp::Subtitle> +simple_subtitle () +{ + return shared_ptr<dcp::Subtitle>( + new dcp::SubtitleString( + optional<string>(), + false, + false, + false, + dcp::Colour(255, 255, 255), + 42, + 1, + dcp::Time(0, 0, 4, 0, 24), + dcp::Time(0, 0, 8, 0, 24), + 0.5, + dcp::HALIGN_CENTER, + 0.8, + dcp::VALIGN_TOP, + dcp::DIRECTION_LTR, + "Hello world", + dcp::NONE, + dcp::Colour(255, 255, 255), + dcp::Time(), + dcp::Time() + ) + ); +} + + +shared_ptr<dcp::DCP> +make_simple_with_interop_subs (boost::filesystem::path path) +{ + shared_ptr<dcp::DCP> dcp = make_simple (path); + + shared_ptr<dcp::InteropSubtitleAsset> subs(new dcp::InteropSubtitleAsset()); + subs->add (simple_subtitle()); + + boost::filesystem::create_directory (path / "subs"); + dcp::Data data(4096); + data.write (path / "subs" / "font.ttf"); + subs->add_font ("afont", path / "subs" / "font.ttf"); + subs->write (path / "subs" / "subs.xml"); + + shared_ptr<dcp::ReelSubtitleAsset> reel_subs(new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 240, 0)); + dcp->cpls().front()->reels().front()->add (reel_subs); + + return dcp; +} + + +shared_ptr<dcp::DCP> +make_simple_with_smpte_subs (boost::filesystem::path path) +{ + shared_ptr<dcp::DCP> dcp = make_simple (path); + + shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset()); + subs->add (simple_subtitle()); + + dcp::Data data(4096); + subs->write (path / "subs.mxf"); + + shared_ptr<dcp::ReelSubtitleAsset> reel_subs(new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 240, 0)); + dcp->cpls().front()->reels().front()->add (reel_subs); + + return dcp; +} + + +shared_ptr<dcp::DCP> +make_simple_with_interop_ccaps (boost::filesystem::path path) +{ + shared_ptr<dcp::DCP> dcp = make_simple (path); + + shared_ptr<dcp::InteropSubtitleAsset> subs(new dcp::InteropSubtitleAsset()); + subs->add (simple_subtitle()); + subs->write (path / "ccap.xml"); + + shared_ptr<dcp::ReelClosedCaptionAsset> reel_caps(new dcp::ReelClosedCaptionAsset(subs, dcp::Fraction(24, 1), 240, 0)); + dcp->cpls().front()->reels().front()->add (reel_caps); + + return dcp; +} + + +shared_ptr<dcp::DCP> +make_simple_with_smpte_ccaps (boost::filesystem::path path) +{ + shared_ptr<dcp::DCP> dcp = make_simple (path); + + shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset()); + subs->add (simple_subtitle()); + subs->write (path / "ccap.mxf"); + + shared_ptr<dcp::ReelClosedCaptionAsset> reel_caps(new dcp::ReelClosedCaptionAsset(subs, dcp::Fraction(24, 1), 240, 0)); + dcp->cpls().front()->reels().front()->add (reel_caps); + + return dcp; +} + + BOOST_GLOBAL_FIXTURE (TestConfig); diff --git a/test/test.h b/test/test.h index 4d53d49f..6fc2067d 100644 --- a/test/test.h +++ b/test/test.h @@ -17,6 +17,13 @@ along with libdcp. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cpl.h" +#include "data.h" +#include "dcp.h" +#include "reel.h" +#include "reel_subtitle_asset.h" +#include "subtitle.h" #include <boost/filesystem.hpp> namespace xmlpp { @@ -25,6 +32,7 @@ namespace xmlpp { namespace dcp { class DCP; + class MonoPictureAsset; } extern boost::filesystem::path private_test; @@ -33,7 +41,12 @@ extern boost::filesystem::path xsd_test; extern void check_xml (xmlpp::Element* ref, xmlpp::Element* test, std::list<std::string> ignore); extern void check_xml (std::string ref, std::string test, std::list<std::string> ignore); extern void check_file (boost::filesystem::path ref, boost::filesystem::path check); -extern boost::shared_ptr<dcp::DCP> make_simple (boost::filesystem::path path); +extern boost::shared_ptr<dcp::MonoPictureAsset> simple_picture (boost::filesystem::path path, std::string suffix); +extern boost::shared_ptr<dcp::DCP> make_simple (boost::filesystem::path path, int reels = 1); +extern boost::shared_ptr<dcp::DCP> make_simple_with_interop_subs (boost::filesystem::path path); +extern boost::shared_ptr<dcp::DCP> make_simple_with_smpte_subs (boost::filesystem::path path); +extern boost::shared_ptr<dcp::DCP> make_simple_with_interop_ccaps (boost::filesystem::path path); +extern boost::shared_ptr<dcp::DCP> make_simple_with_smpte_ccaps (boost::filesystem::path path); /** Creating an object of this class will make asdcplib's random number generation * (more) predictable. diff --git a/test/wscript b/test/wscript index 8ea47108..d6eb078b 100644 --- a/test/wscript +++ b/test/wscript @@ -66,6 +66,7 @@ def build(bld): certificates_test.cc colour_test.cc colour_conversion_test.cc + combine_test.cc cpl_sar_test.cc cpl_ratings_test.cc dcp_font_test.cc |
