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