wip: encoding; crashes on startup.
[dcpomatic.git] / test / client_server_test.cc
1 /*
2     Copyright (C) 2012-2018 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 /** @file  test/client_server_test.cc
22  *  @brief Test the server class.
23  *  @ingroup specific
24  *
25  *  Create a test image and then encode it using the standard mechanism
26  *  and also using a EncodeServer object running on localhost.  Compare the resulting
27  *  encoded data to check that they are the same.
28  */
29
30 #include "lib/encode_server.h"
31 #include "lib/image.h"
32 #include "lib/cross.h"
33 #include "lib/dcp_video.h"
34 #include "lib/player_video.h"
35 #include "lib/raw_image_proxy.h"
36 #include "lib/j2k_image_proxy.h"
37 #include "lib/encode_server_description.h"
38 #include "lib/file_log.h"
39 #include "lib/dcpomatic_log.h"
40 #include "lib/j2k_encoder_cpu_backend.h"
41 #include "lib/j2k_encoder_remote_backend.h"
42 #include "test.h"
43 #include <boost/test/unit_test.hpp>
44 #include <boost/thread.hpp>
45
46 using std::list;
47 using std::vector;
48 using boost::shared_ptr;
49 using boost::thread;
50 using boost::optional;
51 using boost::weak_ptr;
52 using dcp::Data;
53 using namespace dcpomatic;
54
55
56 void
57 do_remote_encode (shared_ptr<DCPVideo> frame, shared_ptr<J2KEncoderBackend> backend, Data locally_encoded)
58 {
59         Data remotely_encoded;
60         vector<shared_ptr<DCPVideo> > frames;
61         frames.push_back (frame);
62         BOOST_REQUIRE_NO_THROW (remotely_encoded = backend->encode(frames).front());
63
64         BOOST_REQUIRE_EQUAL (locally_encoded.size(), remotely_encoded.size());
65         BOOST_CHECK_EQUAL (memcmp (locally_encoded.data().get(), remotely_encoded.data().get(), locally_encoded.size()), 0);
66 }
67
68
69 BOOST_AUTO_TEST_CASE (client_server_test_rgb)
70 {
71         shared_ptr<Image> image (new Image (AV_PIX_FMT_RGB24, dcp::Size (1998, 1080), true));
72         uint8_t* p = image->data()[0];
73
74         for (int y = 0; y < 1080; ++y) {
75                 uint8_t* q = p;
76                 for (int x = 0; x < 1998; ++x) {
77                         *q++ = x % 256;
78                         *q++ = y % 256;
79                         *q++ = (x + y) % 256;
80                 }
81                 p += image->stride()[0];
82         }
83
84         shared_ptr<Image> sub_image (new Image (AV_PIX_FMT_BGRA, dcp::Size (100, 200), true));
85         p = sub_image->data()[0];
86         for (int y = 0; y < 200; ++y) {
87                 uint8_t* q = p;
88                 for (int x = 0; x < 100; ++x) {
89                         *q++ = y % 256;
90                         *q++ = x % 256;
91                         *q++ = (x + y) % 256;
92                         *q++ = 1;
93                 }
94                 p += sub_image->stride()[0];
95         }
96
97         LogSwitcher ls (shared_ptr<Log>(new FileLog("build/test/client_server_test_rgb.log")));
98
99         shared_ptr<PlayerVideo> pvf (
100                 new PlayerVideo (
101                         shared_ptr<ImageProxy> (new RawImageProxy (image)),
102                         Crop (),
103                         optional<double> (),
104                         dcp::Size (1998, 1080),
105                         dcp::Size (1998, 1080),
106                         EYES_BOTH,
107                         PART_WHOLE,
108                         ColourConversion(),
109                         VIDEO_RANGE_FULL,
110                         weak_ptr<Content>(),
111                         optional<Frame>(),
112                         false
113                         )
114                 );
115
116         pvf->set_text (PositionImage (sub_image, Position<int> (50, 60)));
117
118         shared_ptr<DCPVideo> frame (
119                 new DCPVideo (
120                         pvf,
121                         0,
122                         24,
123                         200000000,
124                         RESOLUTION_2K
125                         )
126                 );
127
128         vector<shared_ptr<DCPVideo> > frames;
129         frames.push_back (frame);
130
131         J2KEncoderCPUBackend cpu;
132         Data locally_encoded = cpu.encode(frames).front();
133
134         EncodeServer* server = new EncodeServer (true, 2);
135
136         thread* server_thread = new thread (boost::bind (&EncodeServer::run, server));
137
138         /* Let the server get itself ready */
139         dcpomatic_sleep_seconds (1);
140
141         /* "localhost" rather than "127.0.0.1" here fails on docker; go figure */
142         EncodeServerDescription description ("127.0.0.1", 1, SERVER_LINK_VERSION);
143
144         list<thread*> threads;
145         for (int i = 0; i < 8; ++i) {
146                 shared_ptr<J2KEncoderRemoteBackend> backend (new J2KEncoderRemoteBackend(description));
147                 threads.push_back (new thread (boost::bind (do_remote_encode, frame, backend, locally_encoded)));
148         }
149
150         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
151                 (*i)->join ();
152         }
153
154         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
155                 delete *i;
156         }
157
158         server->stop ();
159         server_thread->join ();
160         delete server_thread;
161         delete server;
162 }
163
164 BOOST_AUTO_TEST_CASE (client_server_test_yuv)
165 {
166         shared_ptr<Image> image (new Image (AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), true));
167
168         for (int i = 0; i < image->planes(); ++i) {
169                 uint8_t* p = image->data()[i];
170                 for (int j = 0; j < image->line_size()[i]; ++j) {
171                         *p++ = j % 256;
172                 }
173         }
174
175         shared_ptr<Image> sub_image (new Image (AV_PIX_FMT_BGRA, dcp::Size (100, 200), true));
176         uint8_t* p = sub_image->data()[0];
177         for (int y = 0; y < 200; ++y) {
178                 uint8_t* q = p;
179                 for (int x = 0; x < 100; ++x) {
180                         *q++ = y % 256;
181                         *q++ = x % 256;
182                         *q++ = (x + y) % 256;
183                         *q++ = 1;
184                 }
185                 p += sub_image->stride()[0];
186         }
187
188         LogSwitcher ls (shared_ptr<Log>(new FileLog("build/test/client_server_test_yuv.log")));
189
190         shared_ptr<PlayerVideo> pvf (
191                 new PlayerVideo (
192                         shared_ptr<ImageProxy> (new RawImageProxy (image)),
193                         Crop (),
194                         optional<double> (),
195                         dcp::Size (1998, 1080),
196                         dcp::Size (1998, 1080),
197                         EYES_BOTH,
198                         PART_WHOLE,
199                         ColourConversion(),
200                         VIDEO_RANGE_FULL,
201                         weak_ptr<Content>(),
202                         optional<Frame>(),
203                         false
204                         )
205                 );
206
207         pvf->set_text (PositionImage (sub_image, Position<int> (50, 60)));
208
209         shared_ptr<DCPVideo> frame (
210                 new DCPVideo (
211                         pvf,
212                         0,
213                         24,
214                         200000000,
215                         RESOLUTION_2K
216                         )
217                 );
218
219         vector<shared_ptr<DCPVideo> > frames;
220         frames.push_back (frame);
221
222         J2KEncoderCPUBackend cpu;
223         Data locally_encoded = cpu.encode(frames).front();
224
225         EncodeServer* server = new EncodeServer (true, 2);
226
227         thread* server_thread = new thread (boost::bind (&EncodeServer::run, server));
228
229         /* Let the server get itself ready */
230         dcpomatic_sleep_seconds (1);
231
232         /* "localhost" rather than "127.0.0.1" here fails on docker; go figure */
233         EncodeServerDescription description ("127.0.0.1", 2, SERVER_LINK_VERSION);
234
235         list<thread*> threads;
236         for (int i = 0; i < 8; ++i) {
237                 shared_ptr<J2KEncoderRemoteBackend> backend (new J2KEncoderRemoteBackend(description));
238                 threads.push_back (new thread (boost::bind (do_remote_encode, frame, backend, locally_encoded)));
239         }
240
241         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
242                 (*i)->join ();
243         }
244
245         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
246                 delete *i;
247         }
248
249         server->stop ();
250         server_thread->join ();
251         delete server_thread;
252         delete server;
253 }
254
255 BOOST_AUTO_TEST_CASE (client_server_test_j2k)
256 {
257         shared_ptr<Image> image (new Image (AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), true));
258
259         for (int i = 0; i < image->planes(); ++i) {
260                 uint8_t* p = image->data()[i];
261                 for (int j = 0; j < image->line_size()[i]; ++j) {
262                         *p++ = j % 256;
263                 }
264         }
265
266         LogSwitcher ls (shared_ptr<Log>(new FileLog("build/test/client_server_test_j2k.log")));
267
268         shared_ptr<PlayerVideo> raw_pvf (
269                 new PlayerVideo (
270                         shared_ptr<ImageProxy> (new RawImageProxy (image)),
271                         Crop (),
272                         optional<double> (),
273                         dcp::Size (1998, 1080),
274                         dcp::Size (1998, 1080),
275                         EYES_BOTH,
276                         PART_WHOLE,
277                         ColourConversion(),
278                         VIDEO_RANGE_FULL,
279                         weak_ptr<Content>(),
280                         optional<Frame>(),
281                         false
282                         )
283                 );
284
285         shared_ptr<DCPVideo> raw_frame (
286                 new DCPVideo (
287                         raw_pvf,
288                         0,
289                         24,
290                         200000000,
291                         RESOLUTION_2K
292                         )
293                 );
294
295         vector<shared_ptr<DCPVideo> > raw_frames;
296         raw_frames.push_back (raw_frame);
297
298         J2KEncoderCPUBackend cpu;
299         Data raw_locally_encoded = cpu.encode(raw_frames).front();
300
301         shared_ptr<PlayerVideo> j2k_pvf (
302                 new PlayerVideo (
303                         shared_ptr<ImageProxy> (new J2KImageProxy (raw_locally_encoded, dcp::Size (1998, 1080), AV_PIX_FMT_XYZ12LE)),
304                         Crop (),
305                         optional<double> (),
306                         dcp::Size (1998, 1080),
307                         dcp::Size (1998, 1080),
308                         EYES_BOTH,
309                         PART_WHOLE,
310                         PresetColourConversion::all().front().conversion,
311                         VIDEO_RANGE_FULL,
312                         weak_ptr<Content>(),
313                         optional<Frame>(),
314                         false
315                         )
316                 );
317
318         shared_ptr<DCPVideo> j2k_frame (
319                 new DCPVideo (
320                         j2k_pvf,
321                         0,
322                         24,
323                         200000000,
324                         RESOLUTION_2K
325                         )
326                 );
327
328         vector<shared_ptr<DCPVideo> > j2k_frames;
329         j2k_frames.push_back (j2k_frame);
330
331         Data j2k_locally_encoded = cpu.encode(j2k_frames).front();
332
333         EncodeServer* server = new EncodeServer (true, 2);
334
335         thread* server_thread = new thread (boost::bind (&EncodeServer::run, server));
336
337         /* Let the server get itself ready */
338         dcpomatic_sleep_seconds (1);
339
340         /* "localhost" rather than "127.0.0.1" here fails on docker; go figure */
341         EncodeServerDescription description ("127.0.0.1", 2, SERVER_LINK_VERSION);
342
343         list<thread*> threads;
344         for (int i = 0; i < 8; ++i) {
345                 shared_ptr<J2KEncoderRemoteBackend> backend (new J2KEncoderRemoteBackend(description));
346                 threads.push_back (new thread (boost::bind (do_remote_encode, j2k_frame, backend, j2k_locally_encoded)));
347         }
348
349         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
350                 (*i)->join ();
351         }
352
353         for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
354                 delete *i;
355         }
356
357         server->stop ();
358         server_thread->join ();
359         delete server_thread;
360         delete server;
361 }