More verification of DCPs during tests.
[dcpomatic.git] / test / ffmpeg_encoder_test.cc
1 /*
2     Copyright (C) 2017-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic 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     DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "lib/ffmpeg_encoder.h"
23 #include "lib/film.h"
24 #include "lib/ffmpeg_content.h"
25 #include "lib/image_content.h"
26 #include "lib/video_content.h"
27 #include "lib/audio_content.h"
28 #include "lib/string_text_file_content.h"
29 #include "lib/ratio.h"
30 #include "lib/transcode_job.h"
31 #include "lib/dcp_content.h"
32 #include "lib/text_content.h"
33 #include "lib/compose.hpp"
34 #include "lib/content_factory.h"
35 #include "test.h"
36 #include <boost/test/unit_test.hpp>
37
38
39 using std::string;
40 using std::shared_ptr;
41 using std::make_shared;
42 using boost::optional;
43 using namespace dcpomatic;
44
45
46 static void
47 ffmpeg_content_test (int number, boost::filesystem::path content, ExportFormat format)
48 {
49         Cleanup cl;
50
51         string name = "ffmpeg_encoder_";
52         string extension;
53         switch (format) {
54         case ExportFormat::H264_AAC:
55                 name += "h264";
56                 extension = "mp4";
57                 break;
58         case ExportFormat::PRORES:
59                 name += "prores";
60                 extension = "mov";
61                 break;
62         case ExportFormat::H264_PCM:
63         case ExportFormat::SUBTITLES_DCP:
64                 BOOST_REQUIRE (false);
65         }
66
67         name = String::compose("%1_test%2", name, number);
68
69         auto c = make_shared<FFmpegContent>(content);
70         shared_ptr<Film> film = new_test_film2 (name, {c}, &cl);
71         film->set_name (name);
72         film->set_audio_channels (6);
73
74         film->write_metadata ();
75         auto job = make_shared<TranscodeJob>(film);
76         auto file = boost::filesystem::path("build") / "test" / String::compose("%1.%2", name, extension);
77         cl.add (file);
78         FFmpegEncoder encoder (film, job, file, format, false, false, false, 23);
79         encoder.go ();
80
81         cl.run ();
82 }
83
84
85 /** Red / green / blue MP4 -> Prores */
86 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test1)
87 {
88         ffmpeg_content_test (1, "test/data/test.mp4", ExportFormat::PRORES);
89 }
90
91
92 /** Dolby Aurora trailer VOB -> Prores */
93 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test2)
94 {
95         ffmpeg_content_test (2, TestPaths::private_data() / "dolby_aurora.vob", ExportFormat::PRORES);
96 }
97
98
99 /** Sintel trailer -> Prores */
100 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test3)
101 {
102         ffmpeg_content_test (3, TestPaths::private_data() / "Sintel_Trailer1.480p.DivX_Plus_HD.mkv", ExportFormat::PRORES);
103 }
104
105
106 /** Big Buck Bunny trailer -> Prores */
107 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test4)
108 {
109         ffmpeg_content_test (4, TestPaths::private_data() / "big_buck_bunny_trailer_480p.mov", ExportFormat::PRORES);
110 }
111
112
113 /** Still image -> Prores */
114 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test5)
115 {
116         auto film = new_test_film ("ffmpeg_encoder_prores_test5");
117         film->set_name ("ffmpeg_encoder_prores_test5");
118         auto c = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
119         film->set_container (Ratio::from_id ("185"));
120         film->set_audio_channels (6);
121
122         film->examine_and_add_content (c);
123         BOOST_REQUIRE (!wait_for_jobs ());
124
125         c->video->set_length (240);
126
127         film->write_metadata ();
128         auto job = make_shared<TranscodeJob> (film);
129         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test5.mov", ExportFormat::PRORES, false, false, false, 23);
130         encoder.go ();
131 }
132
133
134 /** Subs -> Prores */
135 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test6)
136 {
137         auto film = new_test_film ("ffmpeg_encoder_prores_test6");
138         film->set_name ("ffmpeg_encoder_prores_test6");
139         film->set_container (Ratio::from_id ("185"));
140         film->set_audio_channels (6);
141
142         auto s = make_shared<StringTextFileContent>("test/data/subrip2.srt");
143         film->examine_and_add_content (s);
144         BOOST_REQUIRE (!wait_for_jobs ());
145         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
146         s->only_text()->set_effect (dcp::Effect::SHADOW);
147         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
148         film->write_metadata();
149
150         auto job = make_shared<TranscodeJob> (film);
151         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test6.mov", ExportFormat::PRORES, false, false, false, 23);
152         encoder.go ();
153 }
154
155
156 /** Video + subs -> Prores */
157 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test7)
158 {
159         auto film = new_test_film ("ffmpeg_encoder_prores_test7");
160         film->set_name ("ffmpeg_encoder_prores_test7");
161         film->set_container (Ratio::from_id ("185"));
162         film->set_audio_channels (6);
163
164         auto c = make_shared<FFmpegContent>("test/data/test.mp4");
165         film->examine_and_add_content (c);
166         BOOST_REQUIRE (!wait_for_jobs ());
167
168         auto s = make_shared<StringTextFileContent>("test/data/subrip.srt");
169         film->examine_and_add_content (s);
170         BOOST_REQUIRE (!wait_for_jobs ());
171         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
172         s->only_text()->set_effect (dcp::Effect::SHADOW);
173         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
174
175         auto job = make_shared<TranscodeJob> (film);
176         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test7.mov", ExportFormat::PRORES, false, false, false, 23);
177         encoder.go ();
178 }
179
180
181 /** Red / green / blue MP4 -> H264 */
182 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test1)
183 {
184         ffmpeg_content_test(1, "test/data/test.mp4", ExportFormat::H264_AAC);
185 }
186
187
188 /** Just subtitles -> H264 */
189 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test2)
190 {
191         auto film = new_test_film ("ffmpeg_encoder_h264_test2");
192         film->set_name ("ffmpeg_encoder_h264_test2");
193         film->set_container (Ratio::from_id ("185"));
194         film->set_audio_channels (6);
195
196         auto s = make_shared<StringTextFileContent>("test/data/subrip2.srt");
197         film->examine_and_add_content (s);
198         BOOST_REQUIRE (!wait_for_jobs ());
199         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
200         s->only_text()->set_effect (dcp::Effect::SHADOW);
201         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
202         film->write_metadata();
203
204         auto job = make_shared<TranscodeJob> (film);
205         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test2.mp4", ExportFormat::H264_AAC, false, false, false, 23);
206         encoder.go ();
207 }
208
209
210 /** Video + subs -> H264 */
211 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test3)
212 {
213         auto film = new_test_film ("ffmpeg_encoder_h264_test3");
214         film->set_name ("ffmpeg_encoder_h264_test3");
215         film->set_container (Ratio::from_id ("185"));
216         film->set_audio_channels (6);
217
218         auto c = make_shared<FFmpegContent>("test/data/test.mp4");
219         film->examine_and_add_content (c);
220         BOOST_REQUIRE (!wait_for_jobs());
221
222         auto s = make_shared<StringTextFileContent>("test/data/subrip.srt");
223         film->examine_and_add_content (s);
224         BOOST_REQUIRE (!wait_for_jobs ());
225         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
226         s->only_text()->set_effect (dcp::Effect::SHADOW);
227         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
228         film->write_metadata();
229
230         auto job = make_shared<TranscodeJob> (film);
231         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test3.mp4", ExportFormat::H264_AAC, false, false, false, 23);
232         encoder.go ();
233 }
234
235
236 /** Scope-in-flat DCP -> H264 */
237 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test4)
238 {
239         auto film = new_test_film2("ffmpeg_encoder_h264_test4", {make_shared<DCPContent>("test/data/scope_dcp")});
240         BOOST_REQUIRE(!wait_for_jobs());
241
242         film->set_container(Ratio::from_id("185"));
243
244         auto job = make_shared<TranscodeJob>(film);
245         FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test4.mp4", ExportFormat::H264_AAC, false, false, false, 23);
246         encoder.go();
247 }
248
249
250 /** Test mixdown from 5.1 to stereo */
251 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test5)
252 {
253         auto film = new_test_film ("ffmpeg_transcoder_h264_test5");
254         film->set_name ("ffmpeg_transcoder_h264_test5");
255         film->set_container (Ratio::from_id ("185"));
256         film->set_audio_channels (6);
257
258         auto L = make_shared<FFmpegContent>("test/data/L.wav");
259         film->examine_and_add_content (L);
260         auto R = make_shared<FFmpegContent>("test/data/R.wav");
261         film->examine_and_add_content (R);
262         auto C = make_shared<FFmpegContent>("test/data/C.wav");
263         film->examine_and_add_content (C);
264         auto Ls = make_shared<FFmpegContent>("test/data/Ls.wav");
265         film->examine_and_add_content (Ls);
266         auto Rs = make_shared<FFmpegContent>("test/data/Rs.wav");
267         film->examine_and_add_content (Rs);
268         auto Lfe = make_shared<FFmpegContent>("test/data/Lfe.wav");
269         film->examine_and_add_content (Lfe);
270         BOOST_REQUIRE (!wait_for_jobs ());
271
272         AudioMapping map (1, MAX_DCP_AUDIO_CHANNELS);
273
274         L->set_position (film, DCPTime::from_seconds(0));
275         map.make_zero ();
276         map.set (0, 0, 1);
277         L->audio->set_mapping (map);
278         R->set_position (film, DCPTime::from_seconds(1));
279         map.make_zero ();
280         map.set (0, 1, 1);
281         R->audio->set_mapping (map);
282         C->set_position (film, DCPTime::from_seconds(2));
283         map.make_zero ();
284         map.set (0, 2, 1);
285         C->audio->set_mapping (map);
286         Lfe->set_position (film, DCPTime::from_seconds(3));
287         map.make_zero ();
288         map.set (0, 3, 1);
289         Lfe->audio->set_mapping (map);
290         Ls->set_position (film, DCPTime::from_seconds(4));
291         map.make_zero ();
292         map.set (0, 4, 1);
293         Ls->audio->set_mapping (map);
294         Rs->set_position (film, DCPTime::from_seconds(5));
295         map.make_zero ();
296         map.set (0, 5, 1);
297         Rs->audio->set_mapping (map);
298
299         auto job = make_shared<TranscodeJob> (film);
300         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test5.mp4", ExportFormat::H264_AAC, true, false, false, 23);
301         encoder.go ();
302
303         check_ffmpeg ("build/test/ffmpeg_encoder_h264_test5.mp4", "test/data/ffmpeg_encoder_h264_test5.mp4", 1);
304 }
305
306
307 /** Test export of a VF */
308 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test6)
309 {
310         auto film = new_test_film2 ("ffmpeg_encoder_h264_test6_ov");
311         film->examine_and_add_content (make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png"));
312         BOOST_REQUIRE (!wait_for_jobs());
313         make_and_verify_dcp (film);
314
315         auto film2 = new_test_film2 ("ffmpeg_encoder_h264_test6_vf");
316         auto ov = make_shared<DCPContent>("build/test/ffmpeg_encoder_h264_test6_ov/" + film->dcp_name(false));
317         film2->examine_and_add_content (ov);
318         BOOST_REQUIRE (!wait_for_jobs());
319         ov->set_reference_video (true);
320         auto subs = content_factory("test/data/subrip.srt").front();
321         film2->examine_and_add_content (subs);
322         BOOST_REQUIRE (!wait_for_jobs());
323         for (auto i: subs->text) {
324                 i->set_use (true);
325         }
326
327         auto job = make_shared<TranscodeJob> (film2);
328         FFmpegEncoder encoder (film2, job, "build/test/ffmpeg_encoder_h264_test6_vf.mp4", ExportFormat::H264_AAC, true, false, false, 23);
329         encoder.go ();
330 }
331
332
333 /** Test export of a 3D DCP in a 2D project */
334 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test7)
335 {
336         auto L = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
337         auto R = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
338         auto film = new_test_film2 ("ffmpeg_encoder_h264_test7_data", {L, R});
339         L->video->set_frame_type (VideoFrameType::THREE_D_LEFT);
340         L->set_position (film, DCPTime());
341         R->video->set_frame_type (VideoFrameType::THREE_D_RIGHT);
342         R->set_position (film, DCPTime());
343         film->set_three_d (true);
344         make_and_verify_dcp (film);
345
346         auto dcp = make_shared<DCPContent>(film->dir(film->dcp_name()));
347         auto film2 = new_test_film2 ("ffmpeg_encoder_h264_test7_export", {dcp});
348
349         auto job = make_shared<TranscodeJob> (film2);
350         FFmpegEncoder encoder (film2, job, "build/test/ffmpeg_encoder_h264_test7.mp4", ExportFormat::H264_AAC, true, false, false, 23);
351         encoder.go ();
352 }
353
354
355 /** Stereo project with mixdown-to-stereo set */
356 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test8)
357 {
358         shared_ptr<Film> film = new_test_film2("ffmpeg_encoder_h264_test4");
359         film->examine_and_add_content(shared_ptr<DCPContent>(new DCPContent("test/data/scope_dcp")));
360         BOOST_REQUIRE(!wait_for_jobs());
361         film->set_audio_channels (2);
362
363         shared_ptr<Job> job(new TranscodeJob(film));
364         FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test8.mp4", ExportFormat::H264_AAC, true, false, false, 23);
365         encoder.go();
366 }
367
368
369 /** 7.1/HI/VI (i.e. 12-channel) project */
370 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test9)
371 {
372         shared_ptr<Film> film = new_test_film ("ffmpeg_encoder_prores_test9");
373         film->set_name ("ffmpeg_encoder_prores_test9");
374         shared_ptr<ImageContent> c (new ImageContent(TestPaths::private_data() / "bbc405.png"));
375         film->set_container (Ratio::from_id ("185"));
376         film->set_audio_channels (12);
377
378         film->examine_and_add_content (c);
379         BOOST_REQUIRE (!wait_for_jobs ());
380
381         c->video->set_length (240);
382
383         film->write_metadata ();
384         shared_ptr<Job> job (new TranscodeJob (film));
385         FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test9.mov", ExportFormat::H264_AAC, false, false, false, 23);
386         encoder.go ();
387 }