Move some tests from write_subtitle_test to smpte_subtitle_test.
[libdcp.git] / test / smpte_subtitle_test.cc
1 /*
2     Copyright (C) 2018 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 "subtitle_image.h"
38 #include "test.h"
39 #include "types.h"
40 #include <boost/optional/optional_io.hpp>
41 #include <boost/test/unit_test.hpp>
42
43
44 using std::list;
45 using std::string;
46 using std::vector;
47 using boost::dynamic_pointer_cast;
48 using boost::optional;
49 using boost::shared_ptr;
50
51
52 BOOST_AUTO_TEST_CASE (smpte_subtitle_id_test)
53 {
54         dcp::SMPTESubtitleAsset subs;
55         subs.add(
56                 shared_ptr<dcp::Subtitle> (
57                         new dcp::SubtitleString(
58                                 optional<string>(),
59                                 false, false, false,
60                                 dcp::Colour(),
61                                 64,
62                                 1,
63                                 dcp::Time(0, 1, 2, 3, 24),
64                                 dcp::Time(0, 2, 2, 3, 24),
65                                 0.5,
66                                 dcp::HALIGN_CENTER,
67                                 0.5,
68                                 dcp::VALIGN_CENTER,
69                                 dcp::DIRECTION_LTR,
70                                 "Hello",
71                                 dcp::NONE,
72                                 dcp::Colour(),
73                                 dcp::Time(0, 0, 0, 0, 24),
74                                 dcp::Time(0, 0, 0, 0, 24)
75                                 )
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(), 1);
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(), 63);
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 (sc.subtitles().front()->in(), dcp::Time (0, 0, 25, 12, 25));
117         BOOST_CHECK_EQUAL (sc.subtitles().front()->out(), dcp::Time (0, 0, 26, 4, 25));
118         BOOST_REQUIRE (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back()));
119         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back())->text(), "Prochainement");
120         BOOST_CHECK_EQUAL (sc.subtitles().back()->in(), dcp::Time (0, 1, 57, 17, 25));
121         BOOST_CHECK_EQUAL (sc.subtitles().back()->out(), dcp::Time (0, 1, 58, 12, 25));
122 }
123
124
125 /** And another one featuring <Font> within <Text> */
126 BOOST_AUTO_TEST_CASE (read_smpte_subtitle_test2)
127 {
128         dcp::SMPTESubtitleAsset sc (private_test / "olsson.xml");
129
130         auto subs = sc.subtitles();
131         BOOST_REQUIRE_EQUAL (subs.size(), 6);
132         auto i = subs.begin();
133         auto is = dynamic_pointer_cast<const dcp::SubtitleString>(*i);
134         BOOST_REQUIRE (is);
135         BOOST_CHECK_EQUAL (is->text(), "Testing is ");
136         BOOST_CHECK (!is->italic());
137         ++i;
138         is = dynamic_pointer_cast<const dcp::SubtitleString>(*i);
139         BOOST_REQUIRE (is);
140         BOOST_CHECK_EQUAL (is->text(), "really");
141         BOOST_CHECK (is->italic());
142         ++i;
143         is = dynamic_pointer_cast<const dcp::SubtitleString>(*i);
144         BOOST_REQUIRE (is);
145         BOOST_CHECK_EQUAL (is->text(), " fun!");
146         BOOST_CHECK (!is->italic());
147         ++i;
148         is = dynamic_pointer_cast<const dcp::SubtitleString>(*i);
149         BOOST_REQUIRE (is);
150         BOOST_CHECK_EQUAL (is->text(), "This is the ");
151         BOOST_CHECK (!is->italic());
152         ++i;
153         is = dynamic_pointer_cast<const dcp::SubtitleString>(*i);
154         BOOST_REQUIRE (is);
155         BOOST_CHECK_EQUAL (is->text(), "second");
156         BOOST_CHECK (is->italic());
157         ++i;
158         is = dynamic_pointer_cast<const dcp::SubtitleString>(*i);
159         BOOST_REQUIRE (is);
160         BOOST_CHECK_EQUAL (is->text(), " line!");
161         BOOST_CHECK (!is->italic());
162 }
163
164
165 /** And another one featuring image subtitles */
166 BOOST_AUTO_TEST_CASE (read_smpte_subtitle_test3)
167 {
168         dcp::SMPTESubtitleAsset subs ("test/data/subs.mxf");
169
170         BOOST_REQUIRE_EQUAL (subs.subtitles().size(), 1);
171         auto si = dynamic_pointer_cast<const dcp::SubtitleImage>(subs.subtitles().front());
172         BOOST_REQUIRE (si);
173         BOOST_CHECK (si->png_image() == dcp::Data("test/data/sub.png"));
174 }
175
176
177 /* Write some subtitle content as SMPTE XML and check that it is right */
178 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
179 {
180         dcp::SMPTESubtitleAsset c;
181         c.set_reel_number (1);
182         c.set_language ("en");
183         c.set_content_title_text ("Test");
184         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
185
186         c.add (
187                 shared_ptr<dcp::SubtitleString> (
188                         new dcp::SubtitleString(
189                                 string ("Frutiger"),
190                                 false,
191                                 false,
192                                 false,
193                                 dcp::Colour (255, 255, 255),
194                                 48,
195                                 1.0,
196                                 dcp::Time (0, 4,  9, 22, 24),
197                                 dcp::Time (0, 4, 11, 22, 24),
198                                 0,
199                                 dcp::HALIGN_CENTER,
200                                 0.8,
201                                 dcp::VALIGN_TOP,
202                                 dcp::DIRECTION_LTR,
203                                 "Hello world",
204                                 dcp::NONE,
205                                 dcp::Colour (0, 0, 0),
206                                 dcp::Time (0, 0, 0, 0, 24),
207                                 dcp::Time (0, 0, 0, 0, 24)
208                                 )
209                         )
210                 );
211
212         c.add (
213                 shared_ptr<dcp::SubtitleString>(
214                         new dcp::SubtitleString(
215                                 boost::optional<string> (),
216                                 true,
217                                 true,
218                                 true,
219                                 dcp::Colour (128, 0, 64),
220                                 91,
221                                 1.0,
222                                 dcp::Time (5, 41,  0, 21, 24),
223                                 dcp::Time (6, 12, 15, 21, 24),
224                                 0,
225                                 dcp::HALIGN_CENTER,
226                                 0.4,
227                                 dcp::VALIGN_BOTTOM,
228                                 dcp::DIRECTION_RTL,
229                                 "What's going on",
230                                 dcp::BORDER,
231                                 dcp::Colour (1, 2, 3),
232                                 dcp::Time (1, 2, 3, 4, 24),
233                                 dcp::Time (5, 6, 7, 8, 24)
234                                 )
235                         )
236                 );
237
238         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
239
240         check_xml (
241                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
242                 "<dcst:SubtitleReel xmlns:dcst=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
243                   "<dcst:Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</dcst:Id>"
244                   "<dcst:ContentTitleText>Test</dcst:ContentTitleText>"
245                   "<dcst:IssueDate>2016-04-01T03:52:00.000+00:00</dcst:IssueDate>"
246                   "<dcst:ReelNumber>1</dcst:ReelNumber>"
247                   "<dcst:Language>en</dcst:Language>"
248                   "<dcst:EditRate>24 1</dcst:EditRate>"
249                   "<dcst:TimeCodeRate>24</dcst:TimeCodeRate>"
250                   "<dcst:SubtitleList>"
251                     "<dcst:Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Frutiger\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">"
252                       "<dcst:Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:22\" TimeOut=\"00:04:11:22\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
253                         "<dcst:Text Valign=\"top\" Vposition=\"80\">Hello world</dcst:Text>"
254                       "</dcst:Subtitle>"
255                     "</dcst:Font>"
256                     "<dcst:Font AspectAdjust=\"1.0\" Color=\"FF800040\" Effect=\"border\" EffectColor=\"FF010203\" Italic=\"yes\" Script=\"normal\" Size=\"91\" Underline=\"yes\" Weight=\"bold\">"
257                       "<dcst:Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:21\" TimeOut=\"06:12:15:21\" FadeUpTime=\"01:02:03:04\" FadeDownTime=\"05:06:07:08\">"
258                         "<dcst:Text Valign=\"bottom\" Vposition=\"40\" Direction=\"rtl\">What's going on</dcst:Text>"
259                       "</dcst:Subtitle>"
260                     "</dcst:Font>"
261                   "</dcst:SubtitleList>"
262                 "</dcst:SubtitleReel>",
263                 c.xml_as_string (),
264                 list<string>()
265                 );
266 }
267
268 /* Write some subtitle content as SMPTE XML and check that it is right.
269    This includes in-line font changes.
270 */
271 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
272 {
273         dcp::SMPTESubtitleAsset c;
274         c.set_reel_number (1);
275         c.set_language ("en");
276         c.set_content_title_text ("Test");
277         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
278
279         c.add (
280                 shared_ptr<dcp::SubtitleString>(
281                         new dcp::SubtitleString(
282                                 string ("Arial"),
283                                 false,
284                                 false,
285                                 false,
286                                 dcp::Colour (255, 255, 255),
287                                 48,
288                                 1.0,
289                                 dcp::Time (0, 0, 1, 0, 24),
290                                 dcp::Time (0, 0, 9, 0, 24),
291                                 0,
292                                 dcp::HALIGN_CENTER,
293                                 0.8,
294                                 dcp::VALIGN_TOP,
295                                 dcp::DIRECTION_LTR,
296                                 "Testing is ",
297                                 dcp::NONE,
298                                 dcp::Colour (0, 0, 0),
299                                 dcp::Time (0, 0, 0, 0, 24),
300                                 dcp::Time (0, 0, 0, 0, 24)
301                                 )
302                         )
303                 );
304
305         c.add (
306                 shared_ptr<dcp::SubtitleString>(
307                         new dcp::SubtitleString(
308                                 string ("Arial"),
309                                 true,
310                                 false,
311                                 false,
312                                 dcp::Colour (255, 255, 255),
313                                 48,
314                                 1.0,
315                                 dcp::Time (0, 0, 1, 0, 24),
316                                 dcp::Time (0, 0, 9, 0, 24),
317                                 0,
318                                 dcp::HALIGN_CENTER,
319                                 0.8,
320                                 dcp::VALIGN_TOP,
321                                 dcp::DIRECTION_LTR,
322                                 "really",
323                                 dcp::NONE,
324                                 dcp::Colour (0, 0, 0),
325                                 dcp::Time (0, 0, 0, 0, 24),
326                                 dcp::Time (0, 0, 0, 0, 24)
327                                 )
328                         )
329                 );
330
331         c.add (
332                 shared_ptr<dcp::SubtitleString>(
333                         new dcp::SubtitleString(
334                                 string ("Arial"),
335                                 false,
336                                 false,
337                                 false,
338                                 dcp::Colour (255, 255, 255),
339                                 48,
340                                 1.0,
341                                 dcp::Time (0, 0, 1, 0, 24),
342                                 dcp::Time (0, 0, 9, 0, 24),
343                                 0,
344                                 dcp::HALIGN_CENTER,
345                                 0.8,
346                                 dcp::VALIGN_TOP,
347                                 dcp::DIRECTION_LTR,
348                                 " fun",
349                                 dcp::NONE,
350                                 dcp::Colour (0, 0, 0),
351                                 dcp::Time (0, 0, 0, 0, 24),
352                                 dcp::Time (0, 0, 0, 0, 24)
353                                 )
354                         )
355                 );
356
357         c.add (
358                 shared_ptr<dcp::SubtitleString>(
359                         new dcp::SubtitleString(
360                                 string ("Arial"),
361                                 false,
362                                 false,
363                                 false,
364                                 dcp::Colour (255, 255, 255),
365                                 48,
366                                 1.0,
367                                 dcp::Time (0, 0, 1, 0, 24),
368                                 dcp::Time (0, 0, 9, 0, 24),
369                                 0,
370                                 dcp::HALIGN_CENTER,
371                                 0.9,
372                                 dcp::VALIGN_TOP,
373                                 dcp::DIRECTION_LTR,
374                                 "This is the ",
375                                 dcp::NONE,
376                                 dcp::Colour (0, 0, 0),
377                                 dcp::Time (0, 0, 0, 0, 24),
378                                 dcp::Time (0, 0, 0, 0, 24)
379                                 )
380                         )
381                 );
382
383         c.add (
384                 shared_ptr<dcp::SubtitleString>(
385                         new dcp::SubtitleString(
386                                 string ("Arial"),
387                                 true,
388                                 false,
389                                 false,
390                                 dcp::Colour (255, 255, 255),
391                                 48,
392                                 1.0,
393                                 dcp::Time (0, 0, 1, 0, 24),
394                                 dcp::Time (0, 0, 9, 0, 24),
395                                 0,
396                                 dcp::HALIGN_CENTER,
397                                 0.9,
398                                 dcp::VALIGN_TOP,
399                                 dcp::DIRECTION_LTR,
400                                 "second",
401                                 dcp::NONE,
402                                 dcp::Colour (0, 0, 0),
403                                 dcp::Time (0, 0, 0, 0, 24),
404                                 dcp::Time (0, 0, 0, 0, 24)
405                                 )
406                         )
407                 );
408
409         c.add (
410                 shared_ptr<dcp::SubtitleString>(
411                         new dcp::SubtitleString(
412                                 string ("Arial"),
413                                 false,
414                                 false,
415                                 false,
416                                 dcp::Colour (255, 255, 255),
417                                 48,
418                                 1.0,
419                                 dcp::Time (0, 0, 1, 0, 24),
420                                 dcp::Time (0, 0, 9, 0, 24),
421                                 0,
422                                 dcp::HALIGN_CENTER,
423                                 0.9,
424                                 dcp::VALIGN_TOP,
425                                 dcp::DIRECTION_LTR,
426                                 " line",
427                                 dcp::NONE,
428                                 dcp::Colour (0, 0, 0),
429                                 dcp::Time (0, 0, 0, 0, 24),
430                                 dcp::Time (0, 0, 0, 0, 24)
431                                 )
432                         )
433                 );
434
435         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
436
437         check_xml (
438                 c.xml_as_string(),
439                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
440                 "<dcst:SubtitleReel xmlns:dcst=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
441                   "<dcst:Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</dcst:Id>"
442                   "<dcst:ContentTitleText>Test</dcst:ContentTitleText>"
443                   "<dcst:IssueDate>2016-04-01T03:52:00.000+00:00</dcst:IssueDate>"
444                   "<dcst:ReelNumber>1</dcst:ReelNumber>"
445                   "<dcst:Language>en</dcst:Language>"
446                   "<dcst:EditRate>24 1</dcst:EditRate>"
447                   "<dcst:TimeCodeRate>24</dcst:TimeCodeRate>"
448                   "<dcst:SubtitleList>"
449                     "<dcst:Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">"
450                       "<dcst:Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
451                         "<dcst:Text Valign=\"top\" Vposition=\"80\">"
452                           "<dcst:Font Italic=\"no\">Testing is </dcst:Font>"
453                           "<dcst:Font Italic=\"yes\">really</dcst:Font>"
454                           "<dcst:Font Italic=\"no\"> fun</dcst:Font>"
455                         "</dcst:Text>"
456                         "<dcst:Text Valign=\"top\" Vposition=\"90\">"
457                           "<dcst:Font Italic=\"no\">This is the </dcst:Font>"
458                           "<dcst:Font Italic=\"yes\">second</dcst:Font>"
459                           "<dcst:Font Italic=\"no\"> line</dcst:Font>"
460                         "</dcst:Text>"
461                       "</dcst:Subtitle>"
462                     "</dcst:Font>"
463                   "</dcst:SubtitleList>"
464                 "</dcst:SubtitleReel>",
465                 list<string>()
466                 );
467 }
468
469 /* Write some subtitle content as SMPTE using bitmaps and check that it is right */
470 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test3)
471 {
472         dcp::SMPTESubtitleAsset c;
473         c.set_reel_number (1);
474         c.set_language ("en");
475         c.set_content_title_text ("Test");
476
477         c.add (
478                 shared_ptr<dcp::SubtitleImage>(
479                         new dcp::SubtitleImage(
480                                 dcp::Data ("test/data/sub.png"),
481                                 dcp::Time (0, 4,  9, 22, 24),
482                                 dcp::Time (0, 4, 11, 22, 24),
483                                 0,
484                                 dcp::HALIGN_CENTER,
485                                 0.8,
486                                 dcp::VALIGN_TOP,
487                                 dcp::Time (0, 0, 0, 0, 24),
488                                 dcp::Time (0, 0, 0, 0, 24)
489                                 )
490                         )
491               );
492
493         c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
494
495         boost::filesystem::create_directories ("build/test/write_smpte_subtitle_test3");
496         c.write ("build/test/write_smpte_subtitle_test3/subs.mxf");
497
498         /* XXX: check this result when we can read them back in again */
499 }
500