Add ProRes LT export option (#2834).
[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/audio_content.h"
23 #include "lib/compose.hpp"
24 #include "lib/config.h"
25 #include "lib/constants.h"
26 #include "lib/content_factory.h"
27 #include "lib/cross.h"
28 #include "lib/dcp_content.h"
29 #include "lib/dcpomatic_log.h"
30 #include "lib/ffmpeg_content.h"
31 #include "lib/ffmpeg_examiner.h"
32 #include "lib/ffmpeg_film_encoder.h"
33 #include "lib/film.h"
34 #include "lib/image_content.h"
35 #include "lib/ratio.h"
36 #include "lib/string_text_file_content.h"
37 #include "lib/text_content.h"
38 #include "lib/transcode_job.h"
39 #include "lib/video_content.h"
40 #include "test.h"
41 #include <dcp/file.h>
42 #include <dcp/raw_convert.h>
43 #include <boost/test/unit_test.hpp>
44
45
46 using std::make_shared;
47 using std::string;
48 using std::vector;
49 using namespace dcpomatic;
50
51
52 static void
53 ffmpeg_content_test (int number, boost::filesystem::path content, ExportFormat format)
54 {
55         Cleanup cl;
56
57         string name = "ffmpeg_encoder_";
58         string extension;
59         switch (format) {
60         case ExportFormat::H264_AAC:
61                 name += "h264";
62                 extension = "mp4";
63                 break;
64         case ExportFormat::PRORES_4444:
65                 name += "prores-444";
66                 extension = "mov";
67                 break;
68         case ExportFormat::PRORES_HQ:
69                 name += "prores-hq";
70                 extension = "mov";
71                 break;
72         case ExportFormat::PRORES_LT:
73                 name += "prores-lt";
74                 extension = "mov";
75                 break;
76         case ExportFormat::SUBTITLES_DCP:
77                 BOOST_REQUIRE (false);
78         }
79
80         name = String::compose("%1_test%2", name, number);
81
82         auto c = make_shared<FFmpegContent>(content);
83         auto film = new_test_film(name, {c}, &cl);
84         film->set_name (name);
85         film->set_audio_channels (6);
86
87         film->write_metadata ();
88         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
89         auto file = boost::filesystem::path("build") / "test" / String::compose("%1.%2", name, extension);
90         cl.add (file);
91         FFmpegFilmEncoder encoder(film, job, file, format, false, false, false, 23);
92         encoder.go ();
93
94         cl.run ();
95 }
96
97
98 /** Red / green / blue MP4 -> Prores */
99 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test1)
100 {
101         ffmpeg_content_test (1, "test/data/test.mp4", ExportFormat::PRORES_HQ);
102 }
103
104
105 /** Dolby Aurora trailer VOB -> Prores */
106 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test2)
107 {
108         ffmpeg_content_test (2, TestPaths::private_data() / "dolby_aurora.vob", ExportFormat::PRORES_HQ);
109 }
110
111
112 /** Sintel trailer -> Prores */
113 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test3)
114 {
115         ffmpeg_content_test (3, TestPaths::private_data() / "Sintel_Trailer1.480p.DivX_Plus_HD.mkv", ExportFormat::PRORES_HQ);
116 }
117
118
119 /** Big Buck Bunny trailer -> Prores */
120 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test4)
121 {
122         ffmpeg_content_test (4, TestPaths::private_data() / "big_buck_bunny_trailer_480p.mov", ExportFormat::PRORES_HQ);
123 }
124
125
126 /** Still image -> Prores */
127 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test5)
128 {
129         boost::filesystem::path const output = "build/test/ffmpeg_encoder_prores_test5.mov";
130         Cleanup cl;
131         cl.add(output);
132
133         auto c = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
134         auto film = new_test_film("ffmpeg_encoder_prores_test5", { c });
135         film->set_audio_channels (6);
136
137         c->video->set_length (240);
138
139         film->write_metadata ();
140         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
141         FFmpegFilmEncoder encoder(film, job, output, ExportFormat::PRORES_HQ, false, false, false, 23);
142         encoder.go ();
143
144         cl.run();
145 }
146
147
148 /** Subs -> Prores */
149 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test6)
150 {
151         auto s = make_shared<StringTextFileContent>("test/data/subrip2.srt");
152         auto film = new_test_film("ffmpeg_encoder_prores_test6", { s });
153         film->set_audio_channels (6);
154
155         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
156         s->only_text()->set_effect (dcp::Effect::SHADOW);
157         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
158         film->write_metadata();
159
160         auto job = make_shared<TranscodeJob> (film, TranscodeJob::ChangedBehaviour::IGNORE);
161         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_prores_test6.mov", ExportFormat::PRORES_HQ, false, false, false, 23);
162         encoder.go ();
163 }
164
165
166 /** Video + subs -> Prores */
167 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test7)
168 {
169         boost::filesystem::path const output = "build/test/ffmpeg_encoder_prores_test7.mov";
170         Cleanup cl;
171         cl.add(output);
172
173         auto c = make_shared<FFmpegContent>("test/data/test.mp4");
174         auto s = make_shared<StringTextFileContent>("test/data/subrip.srt");
175         auto film = new_test_film("ffmpeg_encoder_prores_test7", { c, s });
176         film->set_audio_channels (6);
177
178         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
179         s->only_text()->set_effect (dcp::Effect::SHADOW);
180         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
181
182         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
183         FFmpegFilmEncoder encoder(film, job, output, ExportFormat::PRORES_HQ, false, false, false, 23);
184         encoder.go ();
185
186         cl.run();
187 }
188
189
190 /** Red / green / blue MP4 -> H264 */
191 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test1)
192 {
193         ffmpeg_content_test(1, "test/data/test.mp4", ExportFormat::H264_AAC);
194 }
195
196
197 /** Just subtitles -> H264 */
198 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test2)
199 {
200         auto s = make_shared<StringTextFileContent>("test/data/subrip2.srt");
201         auto film = new_test_film("ffmpeg_encoder_h264_test2", { s });
202         film->set_audio_channels (6);
203
204         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
205         s->only_text()->set_effect (dcp::Effect::SHADOW);
206         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
207         film->write_metadata();
208
209         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
210         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test2.mp4", ExportFormat::H264_AAC, false, false, false, 23);
211         encoder.go ();
212 }
213
214
215 /** Video + subs -> H264 */
216 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test3)
217 {
218         auto c = make_shared<FFmpegContent>("test/data/test.mp4");
219         auto s = make_shared<StringTextFileContent>("test/data/subrip.srt");
220         auto film = new_test_film("ffmpeg_encoder_h264_test3", { c, s });
221         film->set_audio_channels (6);
222
223         s->only_text()->set_colour (dcp::Colour (255, 255, 0));
224         s->only_text()->set_effect (dcp::Effect::SHADOW);
225         s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255));
226         film->write_metadata();
227
228         auto job = make_shared<TranscodeJob> (film, TranscodeJob::ChangedBehaviour::IGNORE);
229         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test3.mp4", ExportFormat::H264_AAC, false, false, false, 23);
230         encoder.go ();
231 }
232
233
234 /** Scope-in-flat DCP -> H264 */
235 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test4)
236 {
237         auto film = new_test_film("ffmpeg_encoder_h264_test4", {make_shared<DCPContent>("test/data/scope_dcp")});
238         BOOST_REQUIRE(!wait_for_jobs());
239
240         film->set_container(Ratio::from_id("185"));
241
242         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
243         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test4.mp4", ExportFormat::H264_AAC, false, false, false, 23);
244         encoder.go();
245 }
246
247
248 /** Test mixdown from 5.1 to stereo */
249 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test5)
250 {
251         auto L = make_shared<FFmpegContent>("test/data/L.wav");
252         auto R = make_shared<FFmpegContent>("test/data/R.wav");
253         auto C = make_shared<FFmpegContent>("test/data/C.wav");
254         auto Ls = make_shared<FFmpegContent>("test/data/Ls.wav");
255         auto Rs = make_shared<FFmpegContent>("test/data/Rs.wav");
256         auto Lfe = make_shared<FFmpegContent>("test/data/Lfe.wav");
257
258         auto film = new_test_film("ffmpeg_encoder_h264_test5", { L, R, C, Ls, Rs, Lfe });
259         film->set_audio_channels (6);
260
261         AudioMapping map (1, MAX_DCP_AUDIO_CHANNELS);
262
263         L->set_position (film, DCPTime::from_seconds(0));
264         map.make_zero ();
265         map.set (0, 0, 1);
266         L->audio->set_mapping (map);
267         R->set_position (film, DCPTime::from_seconds(1));
268         map.make_zero ();
269         map.set (0, 1, 1);
270         R->audio->set_mapping (map);
271         C->set_position (film, DCPTime::from_seconds(2));
272         map.make_zero ();
273         map.set (0, 2, 1);
274         C->audio->set_mapping (map);
275         Lfe->set_position (film, DCPTime::from_seconds(3));
276         map.make_zero ();
277         map.set (0, 3, 1);
278         Lfe->audio->set_mapping (map);
279         Ls->set_position (film, DCPTime::from_seconds(4));
280         map.make_zero ();
281         map.set (0, 4, 1);
282         Ls->audio->set_mapping (map);
283         Rs->set_position (film, DCPTime::from_seconds(5));
284         map.make_zero ();
285         map.set (0, 5, 1);
286         Rs->audio->set_mapping (map);
287
288         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
289         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test5.mp4", ExportFormat::H264_AAC, true, false, false, 23);
290         encoder.go ();
291
292         check_ffmpeg ("build/test/ffmpeg_encoder_h264_test5.mp4", "test/data/ffmpeg_encoder_h264_test5.mp4", 1);
293 }
294
295
296 /** Test export of a VF */
297 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test6)
298 {
299         auto film = new_test_film("ffmpeg_encoder_h264_test6_ov");
300         film->examine_and_add_content (make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png"));
301         BOOST_REQUIRE (!wait_for_jobs());
302         make_and_verify_dcp (film);
303
304         auto film2 = new_test_film("ffmpeg_encoder_h264_test6_vf");
305         auto ov = make_shared<DCPContent>("build/test/ffmpeg_encoder_h264_test6_ov/" + film->dcp_name(false));
306         film2->examine_and_add_content (ov);
307         BOOST_REQUIRE (!wait_for_jobs());
308         ov->set_reference_video (true);
309         auto subs = content_factory("test/data/subrip.srt")[0];
310         film2->examine_and_add_content (subs);
311         BOOST_REQUIRE (!wait_for_jobs());
312         for (auto i: subs->text) {
313                 i->set_use (true);
314         }
315
316         auto job = make_shared<TranscodeJob>(film2, TranscodeJob::ChangedBehaviour::IGNORE);
317         FFmpegFilmEncoder encoder(film2, job, "build/test/ffmpeg_encoder_h264_test6_vf.mp4", ExportFormat::H264_AAC, true, false, false, 23);
318         encoder.go ();
319 }
320
321
322 /** Test export of a 3D DCP in a 2D project */
323 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_3d_dcp_to_h264)
324 {
325         boost::filesystem::path const output = "build/test/ffmpeg_encoder_3d_dcp_to_h264.mp4";
326         Cleanup cl;
327         cl.add(output);
328
329         auto dcp = make_shared<DCPContent>(TestPaths::private_data() / "xm");
330         auto film2 = new_test_film("ffmpeg_encoder_3d_dcp_to_h264_export", {dcp});
331
332         auto job = make_shared<TranscodeJob>(film2, TranscodeJob::ChangedBehaviour::IGNORE);
333         FFmpegFilmEncoder encoder(film2, job, output, ExportFormat::H264_AAC, true, false, false, 23);
334         encoder.go ();
335
336         cl.run();
337 }
338
339
340 /** Test export of a 3D DCP in a 2D project */
341 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test7)
342 {
343         auto L = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
344         auto R = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
345         auto film = new_test_film("ffmpeg_encoder_h264_test7_data", {L, R});
346         L->video->set_frame_type (VideoFrameType::THREE_D_LEFT);
347         L->set_position (film, DCPTime());
348         R->video->set_frame_type (VideoFrameType::THREE_D_RIGHT);
349         R->set_position (film, DCPTime());
350         film->set_three_d (true);
351         make_and_verify_dcp (film);
352
353         auto dcp = make_shared<DCPContent>(film->dir(film->dcp_name()));
354         auto film2 = new_test_film("ffmpeg_encoder_h264_test7_export", {dcp});
355
356         auto job = make_shared<TranscodeJob> (film2, TranscodeJob::ChangedBehaviour::IGNORE);
357         FFmpegFilmEncoder encoder(film2, job, "build/test/ffmpeg_encoder_h264_test7.mp4", ExportFormat::H264_AAC, true, false, false, 23);
358         encoder.go ();
359 }
360
361
362 BOOST_AUTO_TEST_CASE(ffmpeg_encoder_2d_content_in_3d_project)
363 {
364         auto content = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
365         auto film = new_test_film("ffmpeg_encoder_2d_content_in_3d_project", { content });
366         film->set_three_d(true);
367
368         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
369         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_2d_content_in_3d_project.mp4", ExportFormat::H264_AAC, true, false, false, 23);
370         encoder.go();
371 }
372
373
374 /** Stereo project with mixdown-to-stereo set */
375 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test8)
376 {
377         auto film = new_test_film("ffmpeg_encoder_h264_test4");
378         film->examine_and_add_content(make_shared<DCPContent>("test/data/scope_dcp"));
379         BOOST_REQUIRE(!wait_for_jobs());
380         film->set_audio_channels (2);
381
382         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
383         FFmpegFilmEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test8.mp4", ExportFormat::H264_AAC, true, false, false, 23);
384         encoder.go();
385 }
386
387
388 /** 7.1/HI/VI (i.e. 12-channel) project */
389 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test9)
390 {
391         auto c = make_shared<ImageContent>(TestPaths::private_data() / "bbc405.png");
392         auto film = new_test_film("ffmpeg_encoder_prores_test9", { c });
393         film->set_name ("ffmpeg_encoder_prores_test9");
394         film->set_container (Ratio::from_id ("185"));
395         film->set_audio_channels (12);
396
397         film->examine_and_add_content (c);
398         BOOST_REQUIRE (!wait_for_jobs ());
399
400         c->video->set_length (240);
401
402         film->write_metadata ();
403         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
404         FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test9.mov", ExportFormat::H264_AAC, false, false, false, 23);
405         encoder.go ();
406 }
407
408
409 /** DCP -> Prores with crop */
410 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_from_dcp_with_crop)
411 {
412         auto dcp = make_shared<DCPContent>("test/data/import_dcp_test2");
413         auto film = new_test_film("ffmpeg_encoder_prores_from_dcp_with_crop", { dcp });
414         dcp->video->set_left_crop (32);
415         dcp->video->set_right_crop (32);
416         film->write_metadata ();
417
418         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
419         FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_from_dcp_with_crop.mov", ExportFormat::PRORES_HQ, false, false, false, 23);
420         encoder.go ();
421 }
422
423
424 /** DCP -> H264 with crop */
425 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_from_dcp_with_crop)
426 {
427         auto dcp = make_shared<DCPContent>("test/data/import_dcp_test2");
428         auto film = new_test_film("ffmpeg_encoder_h264_from_dcp_with_crop", { dcp });
429         dcp->video->set_left_crop (32);
430         dcp->video->set_right_crop (32);
431         film->write_metadata ();
432
433         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
434         FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_from_dcp_with_crop.mov", ExportFormat::H264_AAC, false, false, false, 23);
435         encoder.go ();
436 }
437
438
439 /** Export to H264 with reels */
440 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_with_reels)
441 {
442         auto content1 = content_factory("test/data/flat_red.png")[0];
443         auto content2 = content_factory("test/data/flat_red.png")[0];
444         auto film = new_test_film("ffmpeg_encoder_h264_with_reels", { content1, content2 });
445         film->set_reel_type (ReelType::BY_VIDEO_CONTENT);
446         content1->video->set_length (240);
447         content2->video->set_length (240);
448
449         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
450         FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_with_reels.mov", ExportFormat::H264_AAC, false, true, false, 23);
451         encoder.go ();
452
453         auto check = [](boost::filesystem::path path) {
454                 auto reel = std::dynamic_pointer_cast<FFmpegContent>(content_factory(path)[0]);
455                 BOOST_REQUIRE (reel);
456                 FFmpegExaminer examiner(reel);
457                 BOOST_CHECK_EQUAL (examiner.video_length(), 240U);
458         };
459
460         check ("build/test/ffmpeg_encoder_h264_with_reels_reel1.mov");
461         check ("build/test/ffmpeg_encoder_h264_with_reels_reel2.mov");
462 }
463
464
465 /** Regression test for "Error during decoding: Butler finished" (#2097) */
466 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_regression_1)
467 {
468         Cleanup cl;
469
470         auto content = content_factory(TestPaths::private_data() / "arrietty_JP-EN.mkv")[0];
471         auto film = new_test_film("ffmpeg_encoder_prores_regression_1", { content });
472
473         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
474         FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_regression_1.mov", ExportFormat::PRORES_HQ, false, true, false, 23);
475         encoder.go ();
476
477         cl.add("build/test/ffmpeg_encoder_prores_regression_1.mov");
478         cl.run();
479 }
480
481
482 /** Regression test for Butler video buffers reached 480 frames (audio is 0) (#2101) */
483 BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_regression_2)
484 {
485         Cleanup cl;
486
487         auto logs = dcpomatic_log->types();
488         dcpomatic_log->set_types(logs | LogEntry::TYPE_DEBUG_PLAYER);
489
490         auto content = content_factory(TestPaths::private_data() / "tge_clip.mkv")[0];
491         auto film = new_test_film("ffmpeg_encoder_prores_regression_2", { content });
492
493         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
494         FFmpegFilmEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_regression_2.mov", ExportFormat::PRORES_HQ, false, true, false, 23);
495         encoder.go ();
496
497         dcpomatic_log->set_types(logs);
498
499         cl.add("build/test/ffmpeg_encoder_prores_regression_2.mov");
500         cl.run();
501 }
502
503
504 BOOST_AUTO_TEST_CASE(ffmpeg_encoder_missing_frame_at_end)
505 {
506         auto content = content_factory(TestPaths::private_data() / "1s1f.mov");
507         auto film = new_test_film("ffmpeg_encoder_missing_frame_at_end", content);
508
509         boost::filesystem::path output("build/test/ffmpeg_encoder_missing_frame_at_end.mov");
510         boost::filesystem::path log("build/test/ffmpeg_encoder_missing_frame_at_end.log");
511
512         auto job = make_shared<TranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE);
513         FFmpegFilmEncoder encoder(film, job, output, ExportFormat::PRORES_HQ, false, true, false, 23);
514         encoder.go();
515
516         run_ffprobe(output, log, false, "-show_frames -show_format -show_streams -select_streams v:0");
517
518         dcp::File read_log(log, "r");
519         BOOST_REQUIRE(read_log);
520
521         int nb_read_frames = 0;
522         int nb_frames = 0;
523         char buffer[256];
524
525         while (!read_log.eof()) {
526                 read_log.gets(buffer, sizeof(buffer));
527                 vector<string> parts;
528                 boost::algorithm::split(parts, buffer, boost::is_any_of("="));
529                 if (parts.size() == 2) {
530                         if (parts[0] == "nb_read_frames") {
531                                 nb_read_frames = dcp::raw_convert<int>(parts[1]);
532                         } else if (parts[0] == "nb_frames") {
533                                 nb_frames = dcp::raw_convert<int>(parts[1]);
534                         }
535                 }
536         }
537
538         BOOST_CHECK_EQUAL(nb_frames, 26);
539         BOOST_CHECK_EQUAL(nb_read_frames, 26);
540 }
541