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