e5cdfa23c1f37a8db2836c63325de9dd06d7dac8
[libdcp.git] / test / smpte_subtitle_test.cc
1 /*
2     Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of portions of this program with the
21     OpenSSL library under certain conditions as described in each
22     individual source file, and distribute linked combinations
23     including the two.
24
25     You must obey the GNU General Public License in all respects
26     for all of the code used other than OpenSSL.  If you modify
27     file(s) with this exception, you may extend this exception to your
28     version of the file(s), but you are not obligated to do so.  If you
29     do not wish to do so, delete this exception statement from your
30     version.  If you delete this exception statement from all source
31     files in the program, then also delete it here.
32 */
33
34
35 #include "smpte_load_font_node.h"
36 #include "smpte_subtitle_asset.h"
37 #include "stream_operators.h"
38 #include "subtitle_image.h"
39 #include "test.h"
40 #include "types.h"
41 #include <boost/optional/optional_io.hpp>
42 #include <boost/test/unit_test.hpp>
43
44
45 using std::dynamic_pointer_cast;
46 using std::shared_ptr;
47 using std::string;
48 using std::vector;
49 using boost::optional;
50
51
52 BOOST_AUTO_TEST_CASE (smpte_subtitle_id_test)
53 {
54         dcp::SMPTESubtitleAsset subs;
55         subs.add(
56                 std::make_shared<dcp::SubtitleString>(
57                         optional<string>(),
58                         false, false, false,
59                         dcp::Colour(),
60                         64,
61                         1,
62                         dcp::Time(0, 1, 2, 3, 24),
63                         dcp::Time(0, 2, 2, 3, 24),
64                         0.5,
65                         dcp::HAlign::CENTER,
66                         0.5,
67                         dcp::VAlign::CENTER,
68                         0,
69                         dcp::Direction::LTR,
70                         "Hello",
71                         dcp::Effect::NONE,
72                         dcp::Colour(),
73                         dcp::Time(0, 0, 0, 0, 24),
74                         dcp::Time(0, 0, 0, 0, 24),
75                         0
76                         )
77                 );
78         subs.write("build/test/smpte_subtitle_id_test.mxf");
79
80         dcp::SMPTESubtitleAsset check("build/test/smpte_subtitle_id_test.mxf");
81         BOOST_CHECK(check.id() != check.xml_id());
82 }
83
84
85 /** Check reading of a SMPTE subtitle file */
86 BOOST_AUTO_TEST_CASE (read_smpte_subtitle_test)
87 {
88         dcp::SMPTESubtitleAsset sc (
89                 private_test /
90                 "data" /
91                 "JourneyToJah_TLR-1_F_EN-DE-FR_CH_51_2K_LOK_20140225_DGL_SMPTE_OV" /
92                 "8b48f6ae-c74b-4b80-b994-a8236bbbad74_sub.mxf"
93                 );
94
95         BOOST_CHECK_EQUAL (sc.id(), "8b48f6ae-c74b-4b80-b994-a8236bbbad74");
96         BOOST_CHECK_EQUAL (sc.content_title_text(), "Journey to Jah");
97         BOOST_REQUIRE (sc.annotation_text());
98         BOOST_CHECK_EQUAL (sc.annotation_text().get(), "Journey to Jah");
99         BOOST_CHECK_EQUAL (sc.issue_date(), dcp::LocalTime ("2014-02-25T11:22:48.000-00:00"));
100         BOOST_REQUIRE (sc.reel_number());
101         BOOST_CHECK_EQUAL (sc.reel_number().get(), 1);
102         BOOST_REQUIRE (sc.language ());
103         BOOST_CHECK_EQUAL (sc.language().get (), "de");
104         BOOST_CHECK_EQUAL (sc.edit_rate(), dcp::Fraction (25, 1));
105         BOOST_CHECK_EQUAL (sc.time_code_rate(), 25);
106         BOOST_CHECK_EQUAL (sc.start_time(), dcp::Time (0, 0, 0, 0, 25));
107         auto lfn = sc.load_font_nodes ();
108         BOOST_REQUIRE_EQUAL (lfn.size(), 1U);
109         shared_ptr<dcp::SMPTELoadFontNode> smpte_lfn = dynamic_pointer_cast<dcp::SMPTELoadFontNode> (lfn.front ());
110         BOOST_REQUIRE (smpte_lfn);
111         BOOST_CHECK_EQUAL (smpte_lfn->id, "theFontId");
112         BOOST_CHECK_EQUAL (smpte_lfn->urn, "9118bbce-4105-4a05-b37c-a5a6f75e1fea");
113         BOOST_REQUIRE_EQUAL (sc.subtitles().size(), 63U);
114         BOOST_REQUIRE (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().front()));
115         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().front())->text(), "Noch mal.");
116         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().front())->space_before(), 0.0f);
117         BOOST_CHECK_EQUAL (sc.subtitles().front()->in(), dcp::Time (0, 0, 25, 12, 25));
118         BOOST_CHECK_EQUAL (sc.subtitles().front()->out(), dcp::Time (0, 0, 26, 4, 25));
119         BOOST_REQUIRE (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back()));
120         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back())->text(), "Prochainement");
121         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back())->space_before(), 0.0f);
122         BOOST_CHECK_EQUAL (sc.subtitles().back()->in(), dcp::Time (0, 1, 57, 17, 25));
123         BOOST_CHECK_EQUAL (sc.subtitles().back()->out(), dcp::Time (0, 1, 58, 12, 25));
124 }
125
126
127 /** And another one featuring <Font> within <Text> and some <Space> */
128 BOOST_AUTO_TEST_CASE (read_smpte_subtitle_test2)
129 {
130         dcp::SMPTESubtitleAsset sc (private_test / "olsson.xml");
131
132         auto subs = sc.subtitles();
133         BOOST_REQUIRE_EQUAL (subs.size(), 6U);
134         auto i = 0;
135         auto is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
136         BOOST_REQUIRE (is);
137         BOOST_CHECK_EQUAL (is->text(), "Testing is ");
138         BOOST_CHECK (!is->italic());
139         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
140         ++i;
141         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
142         BOOST_REQUIRE (is);
143         BOOST_CHECK_EQUAL (is->text(), "really");
144         BOOST_CHECK (is->italic());
145         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
146         ++i;
147         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
148         BOOST_REQUIRE (is);
149         BOOST_CHECK_EQUAL (is->text(), " fun!");
150         BOOST_CHECK (!is->italic());
151         BOOST_CHECK_CLOSE (is->space_before(), 5, 0.1);
152         ++i;
153         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
154         BOOST_REQUIRE (is);
155         BOOST_CHECK_EQUAL (is->text(), "This is the ");
156         BOOST_CHECK (!is->italic());
157         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
158         ++i;
159         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
160         BOOST_REQUIRE (is);
161         BOOST_CHECK_EQUAL (is->text(), "second");
162         BOOST_CHECK (is->italic());
163         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
164         ++i;
165         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
166         BOOST_REQUIRE (is);
167         BOOST_CHECK_EQUAL (is->text(), " line!");
168         BOOST_CHECK (!is->italic());
169         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
170 }
171
172
173 /* Write some subtitle content as SMPTE XML and check that it is right */
174 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
175 {
176         dcp::SMPTESubtitleAsset c;
177         c.set_reel_number (1);
178         c.set_language (dcp::LanguageTag("en"));
179         c.set_content_title_text ("Test");
180         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
181
182         c.add (
183                 std::make_shared<dcp::SubtitleString> (
184                         string ("Frutiger"),
185                         false,
186                         false,
187                         false,
188                         dcp::Colour (255, 255, 255),
189                         48,
190                         1.0,
191                         dcp::Time (0, 4,  9, 22, 24),
192                         dcp::Time (0, 4, 11, 22, 24),
193                         0,
194                         dcp::HAlign::CENTER,
195                         0.8,
196                         dcp::VAlign::TOP,
197                         0.3,
198                         dcp::Direction::LTR,
199                         "Hello world",
200                         dcp::Effect::NONE,
201                         dcp::Colour (0, 0, 0),
202                         dcp::Time (0, 0, 0, 0, 24),
203                         dcp::Time (0, 0, 0, 0, 24),
204                         0
205                         )
206                 );
207
208         c.add (
209                 std::make_shared<dcp::SubtitleString>(
210                         boost::optional<string> (),
211                         true,
212                         true,
213                         true,
214                         dcp::Colour (128, 0, 64),
215                         91,
216                         1.0,
217                         dcp::Time (5, 41,  0, 21, 24),
218                         dcp::Time (6, 12, 15, 21, 24),
219                         0,
220                         dcp::HAlign::CENTER,
221                         0.4,
222                         dcp::VAlign::BOTTOM,
223                         0,
224                         dcp::Direction::RTL,
225                         "What's going ",
226                         dcp::Effect::BORDER,
227                         dcp::Colour (1, 2, 3),
228                         dcp::Time (1, 2, 3, 4, 24),
229                         dcp::Time (5, 6, 7, 8, 24),
230                         0
231                         )
232                 );
233
234         c.add (
235                 std::make_shared<dcp::SubtitleString>(
236                         boost::optional<string> (),
237                         true,
238                         true,
239                         true,
240                         dcp::Colour (128, 0, 64),
241                         91,
242                         1.0,
243                         dcp::Time (5, 41,  0, 21, 24),
244                         dcp::Time (6, 12, 15, 21, 24),
245                         0,
246                         dcp::HAlign::CENTER,
247                         0.4,
248                         dcp::VAlign::BOTTOM,
249                         0,
250                         dcp::Direction::RTL,
251                         "on",
252                         dcp::Effect::BORDER,
253                         dcp::Colour (1, 2, 3),
254                         dcp::Time (1, 2, 3, 4, 24),
255                         dcp::Time (5, 6, 7, 8, 24),
256                         4.2
257                         )
258                 );
259
260         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
261
262         check_xml (
263                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
264                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
265                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
266                 "  <ContentTitleText>Test</ContentTitleText>\n"
267                 "  <IssueDate>2016-04-01T03:52:00</IssueDate>\n"
268                 "  <ReelNumber>1</ReelNumber>\n"
269                 "  <Language>en</Language>\n"
270                 "  <EditRate>24 1</EditRate>\n"
271                 "  <TimeCodeRate>24</TimeCodeRate>\n"
272                 "  <SubtitleList>\n"
273                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Frutiger\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
274                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:22\" TimeOut=\"00:04:11:22\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
275                 "        <Text Valign=\"top\" Vposition=\"80\" Zposition=\"30\">Hello world</Text>\n"
276                 "      </Subtitle>\n"
277                 "    </Font>\n"
278                 "    <Font AspectAdjust=\"1.0\" Color=\"FF800040\" Effect=\"border\" EffectColor=\"FF010203\" Italic=\"yes\" Script=\"normal\" Size=\"91\" Underline=\"yes\" Weight=\"bold\">\n"
279                 "      <Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:21\" TimeOut=\"06:12:15:21\" FadeUpTime=\"01:02:03:04\" FadeDownTime=\"05:06:07:08\">\n"
280                 "        <Text Valign=\"bottom\" Vposition=\"40\" Direction=\"rtl\">What's going <Space Size=\"4.2\"/>on</Text>\n"
281                 "      </Subtitle>\n"
282                 "    </Font>\n"
283                 "  </SubtitleList>\n"
284                 "</SubtitleReel>",
285                 c.xml_as_string (),
286                 vector<string>()
287                 );
288 }
289
290 /* Write some subtitle content as SMPTE XML and check that it is right.
291    This includes in-line font changes.
292 */
293 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
294 {
295         dcp::SMPTESubtitleAsset c;
296         c.set_reel_number (1);
297         c.set_language (dcp::LanguageTag("en"));
298         c.set_content_title_text ("Test");
299         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
300
301         c.add (
302                 std::make_shared<dcp::SubtitleString>(
303                         string ("Arial"),
304                         false,
305                         false,
306                         false,
307                         dcp::Colour (255, 255, 255),
308                         48,
309                         1.0,
310                         dcp::Time (0, 0, 1, 0, 24),
311                         dcp::Time (0, 0, 9, 0, 24),
312                         0,
313                         dcp::HAlign::CENTER,
314                         0.8,
315                         dcp::VAlign::TOP,
316                         0,
317                         dcp::Direction::LTR,
318                         "Testing is ",
319                         dcp::Effect::NONE,
320                         dcp::Colour (0, 0, 0),
321                         dcp::Time (0, 0, 0, 0, 24),
322                         dcp::Time (0, 0, 0, 0, 24),
323                         0
324                         )
325                 );
326
327         c.add (
328                 std::make_shared<dcp::SubtitleString>(
329                         string ("Arial"),
330                         true,
331                         false,
332                         false,
333                         dcp::Colour (255, 255, 255),
334                         48,
335                         1.0,
336                         dcp::Time (0, 0, 1, 0, 24),
337                         dcp::Time (0, 0, 9, 0, 24),
338                         0,
339                         dcp::HAlign::CENTER,
340                         0.8,
341                         dcp::VAlign::TOP,
342                         0,
343                         dcp::Direction::LTR,
344                         "really",
345                         dcp::Effect::NONE,
346                         dcp::Colour (0, 0, 0),
347                         dcp::Time (0, 0, 0, 0, 24),
348                         dcp::Time (0, 0, 0, 0, 24),
349                         0
350                         )
351                 );
352
353         c.add (
354                 std::make_shared<dcp::SubtitleString>(
355                         string ("Arial"),
356                         false,
357                         false,
358                         false,
359                         dcp::Colour (255, 255, 255),
360                         48,
361                         1.0,
362                         dcp::Time (0, 0, 1, 0, 24),
363                         dcp::Time (0, 0, 9, 0, 24),
364                         0,
365                         dcp::HAlign::CENTER,
366                         0.8,
367                         dcp::VAlign::TOP,
368                         0,
369                         dcp::Direction::LTR,
370                         " fun",
371                         dcp::Effect::NONE,
372                         dcp::Colour (0, 0, 0),
373                         dcp::Time (0, 0, 0, 0, 24),
374                         dcp::Time (0, 0, 0, 0, 24),
375                         0
376                         )
377                 );
378
379         c.add (
380                 std::make_shared<dcp::SubtitleString>(
381                         string ("Arial"),
382                         false,
383                         false,
384                         false,
385                         dcp::Colour (255, 255, 255),
386                         48,
387                         1.0,
388                         dcp::Time (0, 0, 1, 0, 24),
389                         dcp::Time (0, 0, 9, 0, 24),
390                         0,
391                         dcp::HAlign::CENTER,
392                         0.9,
393                         dcp::VAlign::TOP,
394                         0,
395                         dcp::Direction::LTR,
396                         "This is the ",
397                         dcp::Effect::NONE,
398                         dcp::Colour (0, 0, 0),
399                         dcp::Time (0, 0, 0, 0, 24),
400                         dcp::Time (0, 0, 0, 0, 24),
401                         0
402                         )
403                 );
404
405         c.add (
406                 std::make_shared<dcp::SubtitleString>(
407                         string ("Arial"),
408                         true,
409                         false,
410                         false,
411                         dcp::Colour (255, 255, 255),
412                         48,
413                         1.0,
414                         dcp::Time (0, 0, 1, 0, 24),
415                         dcp::Time (0, 0, 9, 0, 24),
416                         0,
417                         dcp::HAlign::CENTER,
418                         0.9,
419                         dcp::VAlign::TOP,
420                         0,
421                         dcp::Direction::LTR,
422                         "second",
423                         dcp::Effect::NONE,
424                         dcp::Colour (0, 0, 0),
425                         dcp::Time (0, 0, 0, 0, 24),
426                         dcp::Time (0, 0, 0, 0, 24),
427                         0
428                         )
429                 );
430
431         c.add (
432                 std::make_shared<dcp::SubtitleString>(
433                         string ("Arial"),
434                         false,
435                         false,
436                         false,
437                         dcp::Colour (255, 255, 255),
438                         48,
439                         1.0,
440                         dcp::Time (0, 0, 1, 0, 24),
441                         dcp::Time (0, 0, 9, 0, 24),
442                         0,
443                         dcp::HAlign::CENTER,
444                         0.9,
445                         dcp::VAlign::TOP,
446                         0,
447                         dcp::Direction::LTR,
448                         " line",
449                         dcp::Effect::NONE,
450                         dcp::Colour (0, 0, 0),
451                         dcp::Time (0, 0, 0, 0, 24),
452                         dcp::Time (0, 0, 0, 0, 24),
453                         0
454                         )
455                 );
456
457         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
458
459         check_xml (
460                 c.xml_as_string(),
461                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
462                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
463                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
464                 "  <ContentTitleText>Test</ContentTitleText>\n"
465                 "  <IssueDate>2016-04-01T03:52:00</IssueDate>\n"
466                 "  <ReelNumber>1</ReelNumber>\n"
467                 "  <Language>en</Language>\n"
468                 "  <EditRate>24 1</EditRate>\n"
469                 "  <TimeCodeRate>24</TimeCodeRate>\n"
470                 "  <SubtitleList>\n"
471                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
472                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
473                 "        <Text Valign=\"top\" Vposition=\"80\"><Font Italic=\"no\">Testing is </Font><Font Italic=\"yes\">really</Font><Font Italic=\"no\"> fun</Font></Text>\n"
474                 "        <Text Valign=\"top\" Vposition=\"90\"><Font Italic=\"no\">This is the </Font><Font Italic=\"yes\">second</Font><Font Italic=\"no\"> line</Font></Text>\n"
475                 "      </Subtitle>\n"
476                 "    </Font>\n"
477                 "  </SubtitleList>\n"
478                 "</SubtitleReel>",
479                 vector<string>()
480                 );
481 }
482
483 /* Write some subtitle content as SMPTE using bitmaps and check that it is right */
484 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test3)
485 {
486         dcp::SMPTESubtitleAsset c;
487         c.set_reel_number (1);
488         c.set_language (dcp::LanguageTag("en"));
489         c.set_content_title_text ("Test");
490         c.set_start_time (dcp::Time());
491
492         boost::filesystem::path const sub_image = "test/data/sub.png";
493
494         c.add (
495                 std::make_shared<dcp::SubtitleImage>(
496                         dcp::ArrayData(sub_image),
497                         dcp::Time (0, 4,  9, 22, 24),
498                         dcp::Time (0, 4, 11, 22, 24),
499                         0,
500                         dcp::HAlign::CENTER,
501                         0.8,
502                         dcp::VAlign::TOP,
503                         -88,
504                         dcp::Time (0, 0, 0, 0, 24),
505                         dcp::Time (0, 0, 0, 0, 24)
506                         )
507               );
508
509         c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
510
511         boost::filesystem::path path = "build/test/write_smpte_subtitle_test3";
512         boost::filesystem::create_directories (path);
513         c.write (path / "subs.mxf");
514
515         dcp::SMPTESubtitleAsset read_back (path / "subs.mxf");
516         auto subs = read_back.subtitles ();
517         BOOST_REQUIRE_EQUAL (subs.size(), 1U);
518         auto image = dynamic_pointer_cast<const dcp::SubtitleImage>(subs[0]);
519         BOOST_REQUIRE (image);
520
521         BOOST_CHECK (image->png_image() == dcp::ArrayData(sub_image));
522         BOOST_CHECK (image->in() == dcp::Time(0, 4, 9, 22, 24));
523         BOOST_CHECK (image->out() == dcp::Time(0, 4, 11, 22, 24));
524         BOOST_CHECK_CLOSE (image->h_position(), 0.0, 1);
525         BOOST_CHECK (image->h_align() == dcp::HAlign::CENTER);
526         BOOST_CHECK_CLOSE (image->v_position(), 0.8, 1);
527         BOOST_CHECK (image->v_align() == dcp::VAlign::TOP);
528         BOOST_CHECK_EQUAL(image->z_position(), -88);
529         BOOST_CHECK (image->fade_up_time() == dcp::Time(0, 0, 0, 0, 24));
530         BOOST_CHECK (image->fade_down_time() == dcp::Time(0, 0, 0, 0, 24));
531 }
532
533
534 /* Some closed caption systems require the <Text> elements to be written in order of their
535  * vertical position (see DoM bug #2106).
536  */
537 BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_top_alignment)
538 {
539         dcp::SMPTESubtitleAsset c;
540         c.set_reel_number (1);
541         c.set_language (dcp::LanguageTag("en"));
542         c.set_content_title_text ("Test");
543         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
544
545         c.add (
546                 std::make_shared<dcp::SubtitleString>(
547                         string ("Arial"),
548                         false,
549                         false,
550                         false,
551                         dcp::Colour (255, 255, 255),
552                         48,
553                         1.0,
554                         dcp::Time (0, 0, 1, 0, 24),
555                         dcp::Time (0, 0, 9, 0, 24),
556                         0,
557                         dcp::HAlign::CENTER,
558                         0.8,
559                         dcp::VAlign::TOP,
560                         0,
561                         dcp::Direction::LTR,
562                         "Top line",
563                         dcp::Effect::NONE,
564                         dcp::Colour (0, 0, 0),
565                         dcp::Time (0, 0, 0, 0, 24),
566                         dcp::Time (0, 0, 0, 0, 24),
567                         0
568                         )
569                 );
570
571         c.add (
572                 std::make_shared<dcp::SubtitleString>(
573                         string ("Arial"),
574                         false,
575                         false,
576                         false,
577                         dcp::Colour (255, 255, 255),
578                         48,
579                         1.0,
580                         dcp::Time (0, 0, 1, 0, 24),
581                         dcp::Time (0, 0, 9, 0, 24),
582                         0,
583                         dcp::HAlign::CENTER,
584                         0.9,
585                         dcp::VAlign::TOP,
586                         0,
587                         dcp::Direction::LTR,
588                         "Bottom line",
589                         dcp::Effect::NONE,
590                         dcp::Colour (0, 0, 0),
591                         dcp::Time (0, 0, 0, 0, 24),
592                         dcp::Time (0, 0, 0, 0, 24),
593                         0
594                         )
595                 );
596
597         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
598
599         check_xml (
600                 c.xml_as_string(),
601                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
602                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
603                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
604                 "  <ContentTitleText>Test</ContentTitleText>\n"
605                 "  <IssueDate>2016-04-01T03:52:00</IssueDate>\n"
606                 "  <ReelNumber>1</ReelNumber>\n"
607                 "  <Language>en</Language>\n"
608                 "  <EditRate>24 1</EditRate>\n"
609                 "  <TimeCodeRate>24</TimeCodeRate>\n"
610                 "  <SubtitleList>\n"
611                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
612                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
613                 "        <Text Valign=\"top\" Vposition=\"80\">Top line</Text>\n"
614                 "        <Text Valign=\"top\" Vposition=\"90\">Bottom line</Text>\n"
615                 "      </Subtitle>\n"
616                 "    </Font>\n"
617                 "  </SubtitleList>\n"
618                 "</SubtitleReel>",
619                 {}
620                 );
621 }
622
623
624 /* See the test above */
625 BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_bottom_alignment)
626 {
627         dcp::SMPTESubtitleAsset c;
628         c.set_reel_number (1);
629         c.set_language (dcp::LanguageTag("en"));
630         c.set_content_title_text ("Test");
631         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
632
633         c.add (
634                 std::make_shared<dcp::SubtitleString>(
635                         string ("Arial"),
636                         false,
637                         false,
638                         false,
639                         dcp::Colour (255, 255, 255),
640                         48,
641                         1.0,
642                         dcp::Time (0, 0, 1, 0, 24),
643                         dcp::Time (0, 0, 9, 0, 24),
644                         0,
645                         dcp::HAlign::CENTER,
646                         0.8,
647                         dcp::VAlign::BOTTOM,
648                         0,
649                         dcp::Direction::LTR,
650                         "Top line",
651                         dcp::Effect::NONE,
652                         dcp::Colour (0, 0, 0),
653                         dcp::Time (0, 0, 0, 0, 24),
654                         dcp::Time (0, 0, 0, 0, 24),
655                         0
656                         )
657                 );
658
659         c.add (
660                 std::make_shared<dcp::SubtitleString>(
661                         string ("Arial"),
662                         false,
663                         false,
664                         false,
665                         dcp::Colour (255, 255, 255),
666                         48,
667                         1.0,
668                         dcp::Time (0, 0, 1, 0, 24),
669                         dcp::Time (0, 0, 9, 0, 24),
670                         0,
671                         dcp::HAlign::CENTER,
672                         0.7,
673                         dcp::VAlign::BOTTOM,
674                         0,
675                         dcp::Direction::LTR,
676                         "Bottom line",
677                         dcp::Effect::NONE,
678                         dcp::Colour (0, 0, 0),
679                         dcp::Time (0, 0, 0, 0, 24),
680                         dcp::Time (0, 0, 0, 0, 24),
681                         0
682                         )
683                 );
684
685         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
686
687         check_xml (
688                 c.xml_as_string(),
689                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
690                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
691                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
692                 "  <ContentTitleText>Test</ContentTitleText>\n"
693                 "  <IssueDate>2016-04-01T03:52:00</IssueDate>\n"
694                 "  <ReelNumber>1</ReelNumber>\n"
695                 "  <Language>en</Language>\n"
696                 "  <EditRate>24 1</EditRate>\n"
697                 "  <TimeCodeRate>24</TimeCodeRate>\n"
698                 "  <SubtitleList>\n"
699                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
700                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
701                 "        <Text Valign=\"bottom\" Vposition=\"80\">Top line</Text>\n"
702                 "        <Text Valign=\"bottom\" Vposition=\"70\">Bottom line</Text>\n"
703                 "      </Subtitle>\n"
704                 "    </Font>\n"
705                 "  </SubtitleList>\n"
706                 "</SubtitleReel>",
707                 {}
708                 );
709 }
710
711
712 BOOST_AUTO_TEST_CASE(smpte_subtitle_standard_written_correctly)
713 {
714         RNGFixer fixer;
715
716         boost::filesystem::path const ref = "test/data";
717         boost::filesystem::path const out = "build/test/smpte_subtitle_standard_written_correctly";
718
719         boost::filesystem::remove_all(out);
720         boost::filesystem::create_directories(out);
721
722         dcp::MXFMetadata metadata;
723         /* Pin this so tests don't fail on newer version */
724         metadata.product_version = "1.8.59";
725
726         dcp::SMPTESubtitleAsset test_2014;
727         test_2014.set_metadata(metadata);
728         test_2014.set_issue_date(dcp::LocalTime("2020-01-01T14:00:00"));
729         test_2014.write(out / "2014.mxf");
730         check_file(ref / "2014.mxf", out / "2014.mxf");
731
732         dcp::SMPTESubtitleAsset test_2010(dcp::SubtitleStandard::SMPTE_2010);
733         test_2010.set_metadata(metadata);
734         test_2010.set_issue_date(dcp::LocalTime("2020-01-01T14:00:00"));
735         test_2010.write(out / "2010.mxf");
736         check_file(ref / "2010.mxf", out / "2010.mxf");
737
738         dcp::SMPTESubtitleAsset test_2007(dcp::SubtitleStandard::SMPTE_2007);
739         test_2007.set_metadata(metadata);
740         test_2007.set_issue_date(dcp::LocalTime("2020-01-01T14:00:00"));
741         test_2007.write(out / "2007.mxf");
742         check_file(ref / "2007.mxf", out / "2007.mxf");
743 }
744
745
746 BOOST_AUTO_TEST_CASE(smpte_subtitle_standard_read_correctly)
747 {
748         dcp::SMPTESubtitleAsset test_2007("test/data/2007.mxf");
749         BOOST_CHECK(test_2007.subtitle_standard() == dcp::SubtitleStandard::SMPTE_2007);
750
751         dcp::SMPTESubtitleAsset test_2010("test/data/2010.mxf");
752         BOOST_CHECK(test_2010.subtitle_standard() == dcp::SubtitleStandard::SMPTE_2010);
753
754         dcp::SMPTESubtitleAsset test_2014("test/data/2014.mxf");
755         BOOST_CHECK(test_2014.subtitle_standard() == dcp::SubtitleStandard::SMPTE_2014);
756 }
757