2 Copyright (C) 2015-2018 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
20 #include "interop_subtitle_asset.h"
21 #include "smpte_subtitle_asset.h"
22 #include "subtitle_string.h"
23 #include "subtitle_image.h"
24 #include "subtitle_asset_internal.h"
25 #include "reel_subtitle_asset.h"
31 #include <boost/test/unit_test.hpp>
35 using boost::shared_ptr;
37 /** Test dcp::order::Font::take_intersection */
38 BOOST_AUTO_TEST_CASE (take_intersection_test)
41 A._values["foo"] = "bar";
42 A._values["fred"] = "jim";
45 B._values["foo"] = "bar";
46 B._values["sheila"] = "baz";
48 A.take_intersection (B);
49 BOOST_REQUIRE_EQUAL (A._values.size(), 1);
50 BOOST_CHECK_EQUAL (A._values["foo"], "bar");
55 A._values["foo"] = "bar";
56 A._values["fred"] = "jim";
58 B._values["foo"] = "hello";
59 B._values["sheila"] = "baz";
61 A.take_intersection (B);
62 BOOST_CHECK_EQUAL (A._values.size(), 0);
65 /** Test dcp::order::Font::take_difference */
66 BOOST_AUTO_TEST_CASE (take_difference_test)
69 A._values["foo"] = "bar";
70 A._values["fred"] = "jim";
73 B._values["foo"] = "bar";
74 B._values["sheila"] = "baz";
76 A.take_difference (B);
77 BOOST_REQUIRE_EQUAL (A._values.size(), 1);
78 BOOST_CHECK_EQUAL (A._values["fred"], "jim");
81 /** Test dcp::order::Subtitle::pull_fonts */
82 BOOST_AUTO_TEST_CASE (pull_fonts_test1)
84 shared_ptr<dcp::order::Part> root (new dcp::order::Part (shared_ptr<dcp::order::Part> ()));
85 shared_ptr<dcp::order::Subtitle> sub1 (new dcp::order::Subtitle (root, dcp::Time(), dcp::Time(), dcp::Time(), dcp::Time()));
86 root->children.push_back (sub1);
87 shared_ptr<dcp::order::Text> text1 (new dcp::order::Text (sub1, dcp::HALIGN_CENTER, 0, dcp::VALIGN_TOP, 0, dcp::DIRECTION_LTR));
88 sub1->children.push_back (text1);
89 text1->font._values["font"] = "Inconsolata";
90 text1->font._values["size"] = "42";
92 dcp::SubtitleAsset::pull_fonts (root);
94 BOOST_REQUIRE_EQUAL (sub1->font._values.size(), 2);
95 BOOST_CHECK_EQUAL (sub1->font._values["font"], "Inconsolata");
96 BOOST_CHECK_EQUAL (sub1->font._values["size"], "42");
97 BOOST_CHECK_EQUAL (text1->font._values.size(), 0);
100 /** Test dcp::order::Subtitle::pull_fonts */
101 BOOST_AUTO_TEST_CASE (pull_fonts_test2)
103 shared_ptr<dcp::order::Part> root (new dcp::order::Part (shared_ptr<dcp::order::Part> ()));
104 shared_ptr<dcp::order::Subtitle> sub1 (new dcp::order::Subtitle (root, dcp::Time(), dcp::Time(), dcp::Time(), dcp::Time()));
105 root->children.push_back (sub1);
106 shared_ptr<dcp::order::Text> text1 (new dcp::order::Text (sub1, dcp::HALIGN_CENTER, 0, dcp::VALIGN_TOP, 0, dcp::DIRECTION_LTR));
107 sub1->children.push_back (text1);
108 text1->font._values["font"] = "Inconsolata";
109 text1->font._values["size"] = "42";
110 shared_ptr<dcp::order::Text> text2 (new dcp::order::Text (sub1, dcp::HALIGN_CENTER, 0, dcp::VALIGN_TOP, 0, dcp::DIRECTION_LTR));
111 sub1->children.push_back (text2);
112 text2->font._values["font"] = "Inconsolata";
113 text2->font._values["size"] = "48";
115 dcp::SubtitleAsset::pull_fonts (root);
117 BOOST_REQUIRE_EQUAL (sub1->font._values.size(), 1);
118 BOOST_CHECK_EQUAL (sub1->font._values["font"], "Inconsolata");
119 BOOST_REQUIRE_EQUAL (text1->font._values.size(), 1);
120 BOOST_CHECK_EQUAL (text1->font._values["size"], "42");
121 BOOST_REQUIRE_EQUAL (text2->font._values.size(), 1);
122 BOOST_CHECK_EQUAL (text2->font._values["size"], "48");
125 /** Test dcp::order::Subtitle::pull_fonts */
126 BOOST_AUTO_TEST_CASE (pull_fonts_test3)
128 shared_ptr<dcp::order::Part> root (new dcp::order::Part (shared_ptr<dcp::order::Part> ()));
129 shared_ptr<dcp::order::Subtitle> sub1 (new dcp::order::Subtitle (root, dcp::Time(), dcp::Time(), dcp::Time(), dcp::Time()));
130 root->children.push_back (sub1);
131 shared_ptr<dcp::order::Text> text1 (new dcp::order::Text (sub1, dcp::HALIGN_CENTER, 0, dcp::VALIGN_TOP, 0, dcp::DIRECTION_LTR));
132 sub1->children.push_back (text1);
133 dcp::order::Font font;
134 font._values["font"] = "Inconsolata";
135 font._values["size"] = "42";
136 shared_ptr<dcp::order::String> string1 (new dcp::order::String (text1, font, "Hello world"));
137 text1->children.push_back (string1);
139 dcp::SubtitleAsset::pull_fonts (root);
141 BOOST_REQUIRE_EQUAL (sub1->font._values.size(), 2);
142 BOOST_CHECK_EQUAL (sub1->font._values["font"], "Inconsolata");
143 BOOST_CHECK_EQUAL (sub1->font._values["size"], "42");
146 /** Write some subtitle content as Interop XML and check that it is right */
147 BOOST_AUTO_TEST_CASE (write_interop_subtitle_test)
149 dcp::InteropSubtitleAsset c;
150 c.set_reel_number ("1");
151 c.set_language ("EN");
152 c.set_movie_title ("Test");
155 shared_ptr<dcp::Subtitle> (
156 new dcp::SubtitleString (
161 dcp::Colour (255, 255, 255),
164 dcp::Time (0, 4, 9, 22, 24),
165 dcp::Time (0, 4, 11, 22, 24),
173 dcp::Colour (0, 0, 0),
174 dcp::Time (0, 0, 0, 0, 24),
175 dcp::Time (0, 0, 0, 0, 24)
181 shared_ptr<dcp::Subtitle> (
182 new dcp::SubtitleString (
183 boost::optional<string> (),
187 dcp::Colour (128, 0, 64),
190 dcp::Time (5, 41, 0, 21, 24),
191 dcp::Time (6, 12, 15, 21, 24),
199 dcp::Colour (1, 2, 3),
200 dcp::Time (1, 2, 3, 4, 24),
201 dcp::Time (5, 6, 7, 8, 24)
206 c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
209 "<DCSubtitle Version=\"1.0\">"
210 "<SubtitleID>a6c58cff-3e1e-4b38-acec-a42224475ef6</SubtitleID>"
211 "<MovieTitle>Test</MovieTitle>"
212 "<ReelNumber>1</ReelNumber>"
213 "<Language>EN</Language>"
214 "<Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" Id=\"Frutiger\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underlined=\"no\" Weight=\"normal\">"
215 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:229\" TimeOut=\"00:04:11:229\" FadeUpTime=\"0\" FadeDownTime=\"0\">"
216 "<Text VAlign=\"top\" VPosition=\"80\">Hello world</Text>"
219 "<Font AspectAdjust=\"1.0\" Color=\"FF800040\" Effect=\"border\" EffectColor=\"FF010203\" Italic=\"yes\" Script=\"normal\" Size=\"91\" Underlined=\"yes\" Weight=\"bold\">"
220 "<Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:219\" TimeOut=\"06:12:15:219\" FadeUpTime=\"930792\" FadeDownTime=\"4591834\">"
221 "<Text VAlign=\"bottom\" VPosition=\"40\">What's going on</Text>"
230 /** Write some subtitle content as Interop XML and check that it is right.
231 * This test includes some horizontal alignment.
233 BOOST_AUTO_TEST_CASE (write_interop_subtitle_test2)
235 dcp::InteropSubtitleAsset c;
236 c.set_reel_number ("1");
237 c.set_language ("EN");
238 c.set_movie_title ("Test");
241 shared_ptr<dcp::Subtitle> (
242 new dcp::SubtitleString (
247 dcp::Colour (255, 255, 255),
250 dcp::Time (0, 4, 9, 22, 24),
251 dcp::Time (0, 4, 11, 22, 24),
259 dcp::Colour (0, 0, 0),
260 dcp::Time (0, 0, 0, 0, 24),
261 dcp::Time (0, 0, 0, 0, 24)
267 shared_ptr<dcp::Subtitle> (
268 new dcp::SubtitleString (
269 boost::optional<string> (),
273 dcp::Colour (128, 0, 64),
276 dcp::Time (5, 41, 0, 21, 24),
277 dcp::Time (6, 12, 15, 21, 24),
285 dcp::Colour (1, 2, 3),
286 dcp::Time (1, 2, 3, 4, 24),
287 dcp::Time (5, 6, 7, 8, 24)
292 c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
295 "<DCSubtitle Version=\"1.0\">"
296 "<SubtitleID>a6c58cff-3e1e-4b38-acec-a42224475ef6</SubtitleID>"
297 "<MovieTitle>Test</MovieTitle>"
298 "<ReelNumber>1</ReelNumber>"
299 "<Language>EN</Language>"
300 "<Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" Id=\"Frutiger\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underlined=\"no\" Weight=\"normal\">"
301 "<Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:229\" TimeOut=\"00:04:11:229\" FadeUpTime=\"0\" FadeDownTime=\"0\">"
302 "<Text HPosition=\"-20\" VAlign=\"top\" VPosition=\"80\">Hello world</Text>"
305 "<Font AspectAdjust=\"1.0\" Color=\"FF800040\" Effect=\"border\" EffectColor=\"FF010203\" Italic=\"yes\" Script=\"normal\" Size=\"91\" Underlined=\"yes\" Weight=\"bold\">"
306 "<Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:219\" TimeOut=\"06:12:15:219\" FadeUpTime=\"930792\" FadeDownTime=\"4591834\">"
307 "<Text HPosition=\"-20\" VAlign=\"bottom\" VPosition=\"40\">What's going on</Text>"
316 /* Write some subtitle content as Interop XML using bitmaps and check that it is right */
317 BOOST_AUTO_TEST_CASE (write_interop_subtitle_test3)
319 shared_ptr<dcp::InteropSubtitleAsset> c (new dcp::InteropSubtitleAsset());
320 c->set_reel_number ("1");
321 c->set_language ("EN");
322 c->set_movie_title ("Test");
325 shared_ptr<dcp::Subtitle> (
326 new dcp::SubtitleImage (
327 dcp::Data ("test/data/sub.png"),
328 dcp::Time (0, 4, 9, 22, 24),
329 dcp::Time (0, 4, 11, 22, 24),
334 dcp::Time (0, 0, 0, 0, 24),
335 dcp::Time (0, 0, 0, 0, 24)
340 c->_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
341 boost::filesystem::create_directories ("build/test/write_interop_subtitle_test3");
342 c->write ("build/test/write_interop_subtitle_test3/subs.xml");
344 shared_ptr<dcp::Reel> reel (new dcp::Reel());
345 reel->add(shared_ptr<dcp::ReelSubtitleAsset>(new dcp::ReelSubtitleAsset(c, dcp::Fraction(24, 1), 6046, 0)));
347 dcp::XMLMetadata xml_meta;
348 xml_meta.issue_date = "2018-09-02T04:45:18+00:00";
349 xml_meta.issuer = "libdcp";
350 xml_meta.creator = "libdcp";
351 xml_meta.annotation_text = "Created by libdcp";
353 shared_ptr<dcp::CPL> cpl (new dcp::CPL ("My film", dcp::FEATURE));
355 cpl->set_metadata (xml_meta);
356 cpl->set_content_version_label_text ("foo");
358 dcp::DCP dcp ("build/test/write_interop_subtitle_test3");
360 dcp.write_xml (dcp::INTEROP, xml_meta);
363 dcp::file_to_string("test/ref/write_interop_subtitle_test3/subs.xml"),
364 dcp::file_to_string("build/test/write_interop_subtitle_test3/subs.xml"),
367 check_file ("build/test/write_interop_subtitle_test3/ef5c6baa-be2d-4f86-9f15-b1acc792ee8b.png", "test/data/sub.png");
370 dcp::file_to_string("test/ref/write_interop_subtitle_test3/ASSETMAP"),
371 dcp::file_to_string("build/test/write_interop_subtitle_test3/ASSETMAP"),
376 dcp::file_to_string("test/ref/write_interop_subtitle_test3/pkl.xml"),
377 dcp::file_to_string("build/test/write_interop_subtitle_test3/pkl_f5aab304-8145-44e3-a265-aa8d8812d8a2.xml"),
382 /* Write some subtitle content as SMPTE XML and check that it is right */
383 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
385 dcp::SMPTESubtitleAsset c;
386 c.set_reel_number (1);
387 c.set_language ("EN");
388 c.set_content_title_text ("Test");
389 c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
392 shared_ptr<dcp::Subtitle> (
393 new dcp::SubtitleString (
398 dcp::Colour (255, 255, 255),
401 dcp::Time (0, 4, 9, 22, 24),
402 dcp::Time (0, 4, 11, 22, 24),
410 dcp::Colour (0, 0, 0),
411 dcp::Time (0, 0, 0, 0, 24),
412 dcp::Time (0, 0, 0, 0, 24)
418 shared_ptr<dcp::Subtitle> (
419 new dcp::SubtitleString (
420 boost::optional<string> (),
424 dcp::Colour (128, 0, 64),
427 dcp::Time (5, 41, 0, 21, 24),
428 dcp::Time (6, 12, 15, 21, 24),
436 dcp::Colour (1, 2, 3),
437 dcp::Time (1, 2, 3, 4, 24),
438 dcp::Time (5, 6, 7, 8, 24)
443 c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
446 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
447 "<dcst:SubtitleReel xmlns:dcst=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
448 "<dcst:Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</dcst:Id>"
449 "<dcst:ContentTitleText>Test</dcst:ContentTitleText>"
450 "<dcst:IssueDate>2016-04-01T03:52:00.000+00:00</dcst:IssueDate>"
451 "<dcst:ReelNumber>1</dcst:ReelNumber>"
452 "<dcst:Language>EN</dcst:Language>"
453 "<dcst:EditRate>24 1</dcst:EditRate>"
454 "<dcst:TimeCodeRate>24</dcst:TimeCodeRate>"
455 "<dcst:SubtitleList>"
456 "<dcst:Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Frutiger\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">"
457 "<dcst:Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:22\" TimeOut=\"00:04:11:22\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
458 "<dcst:Text Valign=\"top\" Vposition=\"80\">Hello world</dcst:Text>"
461 "<dcst:Font AspectAdjust=\"1.0\" Color=\"FF800040\" Effect=\"border\" EffectColor=\"FF010203\" Italic=\"yes\" Script=\"normal\" Size=\"91\" Underline=\"yes\" Weight=\"bold\">"
462 "<dcst:Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:21\" TimeOut=\"06:12:15:21\" FadeUpTime=\"01:02:03:04\" FadeDownTime=\"05:06:07:08\">"
463 "<dcst:Text Valign=\"bottom\" Vposition=\"40\" Direction=\"rtl\">What's going on</dcst:Text>"
466 "</dcst:SubtitleList>"
467 "</dcst:SubtitleReel>",
473 /* Write some subtitle content as SMPTE XML and check that it is right.
474 This includes in-line font changes.
476 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
478 dcp::SMPTESubtitleAsset c;
479 c.set_reel_number (1);
480 c.set_language ("EN");
481 c.set_content_title_text ("Test");
482 c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
485 shared_ptr<dcp::Subtitle> (
486 new dcp::SubtitleString (
491 dcp::Colour (255, 255, 255),
494 dcp::Time (0, 0, 1, 0, 24),
495 dcp::Time (0, 0, 9, 0, 24),
503 dcp::Colour (0, 0, 0),
504 dcp::Time (0, 0, 0, 0, 24),
505 dcp::Time (0, 0, 0, 0, 24)
511 shared_ptr<dcp::Subtitle> (
512 new dcp::SubtitleString (
517 dcp::Colour (255, 255, 255),
520 dcp::Time (0, 0, 1, 0, 24),
521 dcp::Time (0, 0, 9, 0, 24),
529 dcp::Colour (0, 0, 0),
530 dcp::Time (0, 0, 0, 0, 24),
531 dcp::Time (0, 0, 0, 0, 24)
537 shared_ptr<dcp::Subtitle> (
538 new dcp::SubtitleString (
543 dcp::Colour (255, 255, 255),
546 dcp::Time (0, 0, 1, 0, 24),
547 dcp::Time (0, 0, 9, 0, 24),
555 dcp::Colour (0, 0, 0),
556 dcp::Time (0, 0, 0, 0, 24),
557 dcp::Time (0, 0, 0, 0, 24)
563 shared_ptr<dcp::Subtitle> (
564 new dcp::SubtitleString (
569 dcp::Colour (255, 255, 255),
572 dcp::Time (0, 0, 1, 0, 24),
573 dcp::Time (0, 0, 9, 0, 24),
581 dcp::Colour (0, 0, 0),
582 dcp::Time (0, 0, 0, 0, 24),
583 dcp::Time (0, 0, 0, 0, 24)
589 shared_ptr<dcp::Subtitle> (
590 new dcp::SubtitleString (
595 dcp::Colour (255, 255, 255),
598 dcp::Time (0, 0, 1, 0, 24),
599 dcp::Time (0, 0, 9, 0, 24),
607 dcp::Colour (0, 0, 0),
608 dcp::Time (0, 0, 0, 0, 24),
609 dcp::Time (0, 0, 0, 0, 24)
615 shared_ptr<dcp::Subtitle> (
616 new dcp::SubtitleString (
621 dcp::Colour (255, 255, 255),
624 dcp::Time (0, 0, 1, 0, 24),
625 dcp::Time (0, 0, 9, 0, 24),
633 dcp::Colour (0, 0, 0),
634 dcp::Time (0, 0, 0, 0, 24),
635 dcp::Time (0, 0, 0, 0, 24)
640 c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
644 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
645 "<dcst:SubtitleReel xmlns:dcst=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
646 "<dcst:Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</dcst:Id>"
647 "<dcst:ContentTitleText>Test</dcst:ContentTitleText>"
648 "<dcst:IssueDate>2016-04-01T03:52:00.000+00:00</dcst:IssueDate>"
649 "<dcst:ReelNumber>1</dcst:ReelNumber>"
650 "<dcst:Language>EN</dcst:Language>"
651 "<dcst:EditRate>24 1</dcst:EditRate>"
652 "<dcst:TimeCodeRate>24</dcst:TimeCodeRate>"
653 "<dcst:SubtitleList>"
654 "<dcst:Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">"
655 "<dcst:Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
656 "<dcst:Text Valign=\"top\" Vposition=\"80\">"
657 "<dcst:Font Italic=\"no\">Testing is </dcst:Font>"
658 "<dcst:Font Italic=\"yes\">really</dcst:Font>"
659 "<dcst:Font Italic=\"no\"> fun</dcst:Font>"
661 "<dcst:Text Valign=\"top\" Vposition=\"90\">"
662 "<dcst:Font Italic=\"no\">This is the </dcst:Font>"
663 "<dcst:Font Italic=\"yes\">second</dcst:Font>"
664 "<dcst:Font Italic=\"no\"> line</dcst:Font>"
668 "</dcst:SubtitleList>"
669 "</dcst:SubtitleReel>",
674 /* Write some subtitle content as SMPTE using bitmaps and check that it is right */
675 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test3)
677 dcp::SMPTESubtitleAsset c;
678 c.set_reel_number (1);
679 c.set_language ("EN");
680 c.set_content_title_text ("Test");
683 shared_ptr<dcp::Subtitle> (
684 new dcp::SubtitleImage (
685 dcp::Data ("test/data/sub.png"),
686 dcp::Time (0, 4, 9, 22, 24),
687 dcp::Time (0, 4, 11, 22, 24),
692 dcp::Time (0, 0, 0, 0, 24),
693 dcp::Time (0, 0, 0, 0, 24)
698 c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
700 boost::filesystem::create_directories ("build/test/write_smpte_subtitle_test3");
701 c.write ("build/test/write_smpte_subtitle_test3/subs.mxf");
703 /* XXX: check this result when we can read them back in again */