Fill test disk partitions with random noise to expose more bugs.
[dcpomatic.git] / test / torture_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 /** @file  test/torture_test.cc
23  *  @brief Tricky arrangements of content whose resulting DCPs are checked programmatically.
24  *  @ingroup completedcp
25  */
26
27
28 #include "lib/audio_content.h"
29 #include "lib/film.h"
30 #include "lib/dcp_content_type.h"
31 #include "lib/ratio.h"
32 #include "lib/content_factory.h"
33 #include "lib/video_content.h"
34 #include "test.h"
35 #include <dcp/cpl.h>
36 #include <dcp/reel.h>
37 #include <dcp/reel_sound_asset.h>
38 #include <dcp/reel_picture_asset.h>
39 #include <dcp/sound_asset.h>
40 #include <dcp/mono_picture_asset.h>
41 #include <dcp/mono_picture_frame.h>
42 #include <dcp/openjpeg_image.h>
43 #include <boost/test/unit_test.hpp>
44 #include <iostream>
45
46
47 using std::list;
48 using std::cout;
49 using std::shared_ptr;
50 using std::dynamic_pointer_cast;
51 using namespace dcpomatic;
52
53
54 /** Test start/end trim and positioning of some audio content */
55 BOOST_AUTO_TEST_CASE (torture_test1)
56 {
57         auto film = new_test_film2 ("torture_test1");
58         film->set_sequence (false);
59
60         /* Staircase at an offset of 2000 samples, trimmed both start and end, with a gain of exactly 2 (linear) */
61         auto staircase = content_factory("test/data/staircase.wav").front();
62         film->examine_and_add_content (staircase);
63         BOOST_REQUIRE (!wait_for_jobs());
64         staircase->set_position (film, DCPTime::from_frames(2000, film->audio_frame_rate()));
65         staircase->set_trim_start (ContentTime::from_frames(12, 48000));
66         staircase->set_trim_end (ContentTime::from_frames (35, 48000));
67         staircase->audio->set_gain (20 * log10(2));
68
69         /* And again at an offset of 50000 samples, trimmed both start and end, with a gain of exactly 2 (linear) */
70         staircase = content_factory("test/data/staircase.wav").front();
71         film->examine_and_add_content (staircase);
72         BOOST_REQUIRE (!wait_for_jobs());
73         staircase->set_position (film, DCPTime::from_frames(50000, film->audio_frame_rate()));
74         staircase->set_trim_start (ContentTime::from_frames(12, 48000));
75         staircase->set_trim_end (ContentTime::from_frames(35, 48000));
76         staircase->audio->set_gain (20 * log10(2));
77
78         /* 1s of red at 5s in */
79         auto red = content_factory("test/data/flat_red.png").front();
80         film->examine_and_add_content (red);
81         BOOST_REQUIRE (!wait_for_jobs());
82         red->set_position (film, DCPTime::from_seconds(5));
83         red->video->set_length (24);
84
85         film->set_video_frame_rate (24);
86         make_and_verify_dcp (film);
87
88         dcp::DCP dcp ("build/test/torture_test1/" + film->dcp_name(false));
89         dcp.read ();
90
91         auto cpls = dcp.cpls ();
92         BOOST_REQUIRE_EQUAL (cpls.size(), 1U);
93         auto reels = cpls.front()->reels ();
94         BOOST_REQUIRE_EQUAL (reels.size(), 1U);
95
96         /* Check sound */
97
98         auto reel_sound = reels.front()->main_sound();
99         BOOST_REQUIRE (reel_sound);
100         auto sound = reel_sound->asset();
101         BOOST_REQUIRE (sound);
102         BOOST_CHECK_EQUAL (sound->intrinsic_duration(), 144);
103
104         auto sound_reader = sound->start_read ();
105
106         /* First frame silent */
107         auto fr = sound_reader->get_frame (0);
108         for (int i = 0; i < fr->samples(); ++i) {
109                 for (int j = 0; j < 6; ++j) {
110                         BOOST_CHECK_EQUAL (fr->get(j, i), 0);
111                 }
112         }
113
114         /* The first staircase is 4800 - 12 - 35 = 4753 samples.  One frame is 2000 samples, so we span 3 frames */
115
116         BOOST_REQUIRE_EQUAL (fr->samples(), 2000);
117
118         int stair = 12;
119
120         BOOST_TEST_CONTEXT("First staircase, frame #1") {
121                 fr = sound_reader->get_frame (1);
122                 for (int i = 0; i < fr->samples(); ++i) {
123                         for (int j = 0; j < 6; ++j) {
124                                 if (j == 2) {
125                                         BOOST_CHECK_EQUAL ((fr->get(j, i) + 128) >> 8, stair * 2);
126                                         ++stair;
127                                 } else {
128                                         BOOST_CHECK_EQUAL (fr->get(j, i), 0);
129                                 }
130                         }
131                 }
132         }
133
134         BOOST_TEST_CONTEXT("First staircase, frame #2") {
135                 fr = sound_reader->get_frame (2);
136                 for (int i = 0; i < fr->samples(); ++i) {
137                         for (int j = 0; j < 6; ++j) {
138                                 if (j == 2) {
139                                         BOOST_CHECK_EQUAL ((fr->get(j, i) + 128) >> 8, stair * 2);
140                                         ++stair;
141                                 } else {
142                                         BOOST_CHECK_EQUAL (fr->get(j, i), 0);
143                                 }
144                         }
145                 }
146         }
147
148         BOOST_TEST_CONTEXT("First staircase, frame #3") {
149                 fr = sound_reader->get_frame (3);
150                 for (int i = 0; i < fr->samples(); ++i) {
151                         for (int j = 0; j < 6; ++j) {
152                                 if (j == 2 && i < (4753 - (2000 * 2))) {
153                                         BOOST_CHECK_EQUAL ((fr->get(j, i) + 128) >> 8, stair * 2);
154                                         ++stair;
155                                 } else {
156                                         BOOST_CHECK_EQUAL (fr->get(j, i), 0);
157                                 }
158                         }
159                 }
160         }
161
162         /* Then some silence */
163
164         BOOST_TEST_CONTEXT("Silence") {
165                 for (int i = 4; i < 24; ++i) {
166                         fr = sound_reader->get_frame (i);
167                         for (int j = 0; j < fr->samples(); ++j) {
168                                 for (int k = 0; k < 6; ++k) {
169                                         BOOST_CHECK_EQUAL (fr->get(k, j), 0);
170                                 }
171                         }
172                 }
173         }
174
175         /* Then the same thing again */
176
177         stair = 12;
178
179         fr = sound_reader->get_frame (25);
180         for (int i = 0; i < fr->samples(); ++i) {
181                 for (int j = 0; j < 6; ++j) {
182                         if (j == 2) {
183                                 BOOST_CHECK_EQUAL ((fr->get(j, i) + 128) >> 8, stair * 2);
184                                 ++stair;
185                         } else {
186                                 BOOST_CHECK_EQUAL (fr->get(j, i), 0);
187                         }
188                 }
189         }
190
191         fr = sound_reader->get_frame (26);
192         for (int i = 0; i < fr->samples(); ++i) {
193                 for (int j = 0; j < 6; ++j) {
194                         if (j == 2) {
195                                 BOOST_CHECK_EQUAL ((fr->get(j, i) + 128) >> 8, stair * 2);
196                                 ++stair;
197                         } else {
198                                 BOOST_CHECK_EQUAL (fr->get(j, i), 0);
199                         }
200                 }
201         }
202
203         fr = sound_reader->get_frame (27);
204         for (int i = 0; i < fr->samples(); ++i) {
205                 for (int j = 0; j < 6; ++j) {
206                         if (j == 2 && i < (4753 - (2000 * 2))) {
207                                 BOOST_CHECK_EQUAL ((fr->get(j, i) + 128) >> 8, stair * 2);
208                                 ++stair;
209                         } else {
210                                 BOOST_CHECK_EQUAL (fr->get(j, i), 0);
211                         }
212                 }
213         }
214
215         /* Then some silence */
216
217         for (int i = 28; i < 144; ++i) {
218                 fr = sound_reader->get_frame (i);
219                 for (int j = 0; j < fr->samples(); ++j) {
220                         for (int k = 0; k < 6; ++k) {
221                                 BOOST_CHECK_EQUAL (fr->get(k, j), 0);
222                         }
223                 }
224         }
225
226         /* Check picture */
227
228         auto reel_picture = reels.front()->main_picture();
229         BOOST_REQUIRE (reel_picture);
230         auto picture = dynamic_pointer_cast<dcp::MonoPictureAsset> (reel_picture->asset());
231         BOOST_REQUIRE (picture);
232         BOOST_CHECK_EQUAL (picture->intrinsic_duration(), 144);
233
234         auto picture_reader = picture->start_read ();
235
236         /* First 5 * 24 = 120 frames should be black, possibly with a little noise to raise the bitrate */
237
238         shared_ptr<dcp::OpenJPEGImage> ref;
239         for (int i = 0; i < 120; ++i) {
240                 auto fr = picture_reader->get_frame (i);
241                 auto image = fr->xyz_image ();
242                 auto const size = image->size ();
243                 if (i == 0) {
244                         /* Check the first frame pixel by pixel... */
245                         for (int c = 0; c < 3; ++c) {
246                                 for (int y = 0; y < size.height; ++y) {
247                                         for (int x = 0; x < size.width; ++x) {
248                                                 BOOST_REQUIRE (image->data(c)[y * size.height + x] <= 3);
249                                         }
250                                 }
251                         }
252                         ref = image;
253                 } else {
254                         /* ... then all the others should be the same */
255                         for (int c = 0; c < 3; ++c) {
256                                 BOOST_REQUIRE_MESSAGE (
257                                         memcmp (image->data(c), ref->data(c), size.width * size.height * sizeof(int)) == 0,
258                                         "failed on frame " << i << " component " << c
259                                         );
260                         }
261                 }
262         }
263
264         /* Then 24 red, perhaps also with some noise */
265
266         for (int i = 120; i < 144; ++i) {
267                 auto fr = picture_reader->get_frame (i);
268                 auto image = fr->xyz_image ();
269                 auto const size = image->size ();
270                 if (i == 120) {
271                         for (int y = 0; y < size.height; ++y) {
272                                 for (int x = 0; x < size.width; ++x) {
273                                         BOOST_REQUIRE_MESSAGE (
274                                                 abs(image->data(0)[y * size.height + x] - 2808) <= 5,
275                                                 "failed on frame " << i << " with image data " << image->data(0)[y * size.height + x]
276                                                 );
277                                         BOOST_REQUIRE_MESSAGE (
278                                                 abs(image->data(1)[y * size.height + x] - 2176) <= 5,
279                                                 "failed on frame " << i << " with image data " << image->data(1)[y * size.height + x]
280                                                 );
281                                         BOOST_REQUIRE_MESSAGE (
282                                                 abs(image->data(2)[y * size.height + x] - 865) <= 5,
283                                                 "failed on frame " << i << " with image data " << image->data(2)[y * size.height + x]
284                                                 );
285                                 }
286                         }
287                         ref = image;
288                 } else {
289                         for (int c = 0; c < 3; ++c) {
290                                 BOOST_REQUIRE_MESSAGE (
291                                         memcmp (image->data(c), ref->data(c), size.width * size.height * sizeof(int)) == 0,
292                                         "failed on frame " << i << " component " << c
293                                         );
294                         }
295                 }
296         }
297
298 }