Make sure we use limited ("video") range data when exporting.
[dcpomatic.git] / dunit
1 diff --git a/src/lib/crypto.cc b/src/lib/crypto.cc
2 index c67fc27fa..494924daa 100644
3 --- a/src/lib/crypto.cc
4 +++ b/src/lib/crypto.cc
5 @@ -34,39 +34,39 @@ using namespace dcpomatic;
6  /** The cipher that this code uses */
7  #define CIPHER EVP_aes_256_cbc()
8  
9 -dcp::Data
10 +dcp::ArrayData
11  dcpomatic::random_iv ()
12  {
13         EVP_CIPHER const * cipher = CIPHER;
14 -       dcp::Data iv (EVP_CIPHER_iv_length(cipher));
15 -       RAND_bytes (iv.data().get(), iv.size());
16 +       dcp::ArrayData iv (EVP_CIPHER_iv_length(cipher));
17 +       RAND_bytes (iv.data(), iv.size());
18         return iv;
19  }
20  
21 -dcp::Data
22 -dcpomatic::encrypt (string plaintext, dcp::Data key, dcp::Data iv)
23 +dcp::ArrayData
24 +dcpomatic::encrypt (string plaintext, dcp::ArrayData key, dcp::ArrayData iv)
25  {
26         EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new ();
27         if (!ctx) {
28                 throw CryptoError ("could not create cipher context");
29         }
30  
31 -       int r = EVP_EncryptInit_ex (ctx, CIPHER, 0, key.data().get(), iv.data().get());
32 +       int r = EVP_EncryptInit_ex (ctx, CIPHER, 0, key.data(), iv.data());
33         if (r != 1) {
34                 throw CryptoError ("could not initialise cipher context for encryption");
35         }
36  
37 -       dcp::Data ciphertext (plaintext.size() * 2);
38 +       dcp::ArrayData ciphertext (plaintext.size() * 2);
39  
40         int len;
41 -       r = EVP_EncryptUpdate (ctx, ciphertext.data().get(), &len, (uint8_t const *) plaintext.c_str(), plaintext.size());
42 +       r = EVP_EncryptUpdate (ctx, ciphertext.data(), &len, (uint8_t const *) plaintext.c_str(), plaintext.size());
43         if (r != 1) {
44                 throw CryptoError ("could not encrypt data");
45         }
46  
47         int ciphertext_len = len;
48  
49 -       r = EVP_EncryptFinal_ex (ctx, ciphertext.data().get() + len, &len);
50 +       r = EVP_EncryptFinal_ex (ctx, ciphertext.data() + len, &len);
51         if (r != 1) {
52                 throw CryptoError ("could not finish encryption");
53         }
54 @@ -79,40 +79,40 @@ dcpomatic::encrypt (string plaintext, dcp::Data key, dcp::Data iv)
55  }
56  
57  string
58 -dcpomatic::decrypt (dcp::Data ciphertext, dcp::Data key, dcp::Data iv)
59 +dcpomatic::decrypt (dcp::ArrayData ciphertext, dcp::ArrayData key, dcp::ArrayData iv)
60  {
61         EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new ();
62         if (!ctx) {
63                 throw CryptoError ("could not create cipher context");
64         }
65  
66 -       int r = EVP_DecryptInit_ex (ctx, CIPHER, 0, key.data().get(), iv.data().get());
67 +       int r = EVP_DecryptInit_ex (ctx, CIPHER, 0, key.data(), iv.data());
68         if (r != 1) {
69                 throw CryptoError ("could not initialise cipher context for decryption");
70         }
71  
72 -       dcp::Data plaintext (ciphertext.size() * 2);
73 +       dcp::ArrayData plaintext (ciphertext.size() * 2);
74  
75         int len;
76 -       r = EVP_DecryptUpdate (ctx, plaintext.data().get(), &len, ciphertext.data().get(), ciphertext.size());
77 +       r = EVP_DecryptUpdate (ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size());
78         if (r != 1) {
79                 throw CryptoError ("could not decrypt data");
80         }
81  
82         int plaintext_len = len;
83  
84 -       r = EVP_DecryptFinal_ex (ctx, plaintext.data().get() + len, &len);
85 +       r = EVP_DecryptFinal_ex (ctx, plaintext.data() + len, &len);
86         if (r != 1) {
87                 throw CryptoError ("could not finish decryption");
88         }
89  
90         plaintext_len += len;
91         plaintext.set_size (plaintext_len + 1);
92 -       plaintext.data().get()[plaintext_len] = '\0';
93 +       plaintext.data()[plaintext_len] = '\0';
94  
95         EVP_CIPHER_CTX_free (ctx);
96  
97 -       return string ((char *) plaintext.data().get());
98 +       return string ((char *) plaintext.data());
99  }
100  
101  int
102 diff --git a/src/lib/crypto.h b/src/lib/crypto.h
103 index e450d4db1..ee0ff9b55 100644
104 --- a/src/lib/crypto.h
105 +++ b/src/lib/crypto.h
106 @@ -18,14 +18,14 @@
107  
108  */
109  
110 -#include <dcp/data.h>
111 +#include <dcp/array_data.h>
112  
113  namespace dcpomatic {
114 -       
115 -dcp::Data random_iv ();
116 -dcp::Data encrypt (std::string plaintext, dcp::Data key, dcp::Data iv);
117 -std::string decrypt (dcp::Data ciphertext, dcp::Data key, dcp::Data iv);
118 -int crypto_key_length ();      
119 +
120 +dcp::ArrayData random_iv ();
121 +dcp::ArrayData encrypt (std::string plaintext, dcp::ArrayData key, dcp::ArrayData iv);
122 +std::string decrypt (dcp::ArrayData ciphertext, dcp::ArrayData key, dcp::ArrayData iv);
123 +int crypto_key_length ();
124  
125  }
126  
127 diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc
128 index 36928b3fc..b3461e569 100644
129 --- a/src/lib/dcp_video.cc
130 +++ b/src/lib/dcp_video.cc
131 @@ -60,7 +60,7 @@ using std::string;
132  using std::cout;
133  using boost::shared_ptr;
134  using dcp::Size;
135 -using dcp::Data;
136 +using dcp::ArrayData;
137  using dcp::raw_convert;
138  #if BOOST_VERSION >= 106100
139  using namespace boost::placeholders;
140 @@ -118,12 +118,12 @@ DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler
141  /** J2K-encode this frame on the local host.
142   *  @return Encoded data.
143   */
144 -Data
145 +ArrayData
146  DCPVideo::encode_locally ()
147  {
148         string const comment = Config::instance()->dcp_j2k_comment();
149  
150 -       Data enc = dcp::compress_j2k (
151 +       ArrayData enc = dcp::compress_j2k (
152                 convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2)),
153                 _j2k_bandwidth,
154                 _frames_per_second,
155 @@ -154,7 +154,7 @@ DCPVideo::encode_locally ()
156   *  @param timeout timeout in seconds.
157   *  @return Encoded data.
158   */
159 -Data
160 +ArrayData
161  DCPVideo::encode_remotely (EncodeServerDescription serv, int timeout)
162  {
163         boost::asio::io_service io_service;
164 @@ -192,9 +192,9 @@ DCPVideo::encode_remotely (EncodeServerDescription serv, int timeout)
165         */
166         Socket::ReadDigestScope ds (socket);
167         LOG_TIMING("start-remote-encode thread=%1", thread_id ());
168 -       Data e (socket->read_uint32 ());
169 +       ArrayData e (socket->read_uint32 ());
170         LOG_TIMING("start-remote-receive thread=%1", thread_id ());
171 -       socket->read (e.data().get(), e.size());
172 +       socket->read (e.data(), e.size());
173         LOG_TIMING("finish-remote-receive thread=%1", thread_id ());
174         if (!ds.check()) {
175                 throw NetworkError ("Checksums do not match");
176 diff --git a/src/lib/dcp_video.h b/src/lib/dcp_video.h
177 index 81ddc4470..aa11d7d3c 100644
178 --- a/src/lib/dcp_video.h
179 +++ b/src/lib/dcp_video.h
180 @@ -21,7 +21,7 @@
181  #include "types.h"
182  #include "encode_server_description.h"
183  #include <libcxml/cxml.h>
184 -#include <dcp/data.h>
185 +#include <dcp/array_data.h>
186  
187  /** @file  src/dcp_video_frame.h
188   *  @brief A single frame of video destined for a DCP.
189 @@ -45,8 +45,8 @@ public:
190         DCPVideo (boost::shared_ptr<const PlayerVideo>, int, int, int, Resolution);
191         DCPVideo (boost::shared_ptr<const PlayerVideo>, cxml::ConstNodePtr);
192  
193 -       dcp::Data encode_locally ();
194 -       dcp::Data encode_remotely (EncodeServerDescription, int timeout = 30);
195 +       dcp::ArrayData encode_locally ();
196 +       dcp::ArrayData encode_remotely (EncodeServerDescription, int timeout = 30);
197  
198         int index () const {
199                 return _index;
200 diff --git a/src/lib/emailer.cc b/src/lib/emailer.cc
201 index dc216e90c..6fe537eb1 100644
202 --- a/src/lib/emailer.cc
203 +++ b/src/lib/emailer.cc
204 @@ -35,7 +35,7 @@ using std::list;
205  using std::cout;
206  using std::pair;
207  using boost::shared_ptr;
208 -using dcp::Data;
209 +using dcp::ArrayData;
210  
211  Emailer::Emailer (string from, list<string> to, string subject, string body)
212         : _from (from)
213 @@ -155,8 +155,8 @@ Emailer::send (string server, int port, EmailProtocol protocol, string user, str
214                 BIO* bio = BIO_new (BIO_s_mem());
215                 bio = BIO_push (b64, bio);
216  
217 -               Data data (i.file);
218 -               BIO_write (bio, data.data().get(), data.size());
219 +               ArrayData data (i.file);
220 +               BIO_write (bio, data.data(), data.size());
221                 (void) BIO_flush (bio);
222  
223                 char* out;
224 diff --git a/src/lib/encode_server.cc b/src/lib/encode_server.cc
225 index f4224798b..9e096fdfa 100644
226 --- a/src/lib/encode_server.cc
227 +++ b/src/lib/encode_server.cc
228 @@ -65,8 +65,8 @@ using boost::thread;
229  using boost::bind;
230  using boost::scoped_array;
231  using boost::optional;
232 +using dcp::ArrayData;
233  using dcp::Size;
234 -using dcp::Data;
235  using dcp::raw_convert;
236  
237  EncodeServer::EncodeServer (bool verbose, int num_threads)
238 @@ -145,14 +145,14 @@ EncodeServer::process (shared_ptr<Socket> socket, struct timeval& after_read, st
239  
240         gettimeofday (&after_read, 0);
241  
242 -       Data encoded = dcp_video_frame.encode_locally ();
243 +       ArrayData encoded = dcp_video_frame.encode_locally ();
244  
245         gettimeofday (&after_encode, 0);
246  
247         try {
248                 Socket::WriteDigestScope ds (socket);
249                 socket->write (encoded.size());
250 -               socket->write (encoded.data().get(), encoded.size());
251 +               socket->write (encoded.data(), encoded.size());
252         } catch (std::exception& e) {
253                 cerr << "Send failed; frame " << dcp_video_frame.index() << "\n";
254                 LOG_ERROR ("Send failed; frame %1", dcp_video_frame.index());
255 diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc
256 index f2b72059b..602185bb8 100644
257 --- a/src/lib/ffmpeg_image_proxy.cc
258 +++ b/src/lib/ffmpeg_image_proxy.cc
259 @@ -56,7 +56,7 @@ FFmpegImageProxy::FFmpegImageProxy (boost::filesystem::path path)
260  
261  }
262  
263 -FFmpegImageProxy::FFmpegImageProxy (dcp::Data data)
264 +FFmpegImageProxy::FFmpegImageProxy (dcp::ArrayData data)
265         : _data (data)
266         , _pos (0)
267  {
268 @@ -67,8 +67,8 @@ FFmpegImageProxy::FFmpegImageProxy (shared_ptr<cxml::Node>, shared_ptr<Socket> s
269         : _pos (0)
270  {
271         uint32_t const size = socket->read_uint32 ();
272 -       _data = dcp::Data (size);
273 -       socket->read (_data.data().get(), size);
274 +       _data = dcp::ArrayData (size);
275 +       socket->read (_data.data(), size);
276  }
277  
278  static int
279 @@ -90,7 +90,7 @@ FFmpegImageProxy::avio_read (uint8_t* buffer, int const amount)
280         if (to_do == 0) {
281                 return AVERROR_EOF;
282         }
283 -       memcpy (buffer, _data.data().get() + _pos, to_do);
284 +       memcpy (buffer, _data.data() + _pos, to_do);
285         _pos += to_do;
286         return to_do;
287  }
288 @@ -212,7 +212,7 @@ void
289  FFmpegImageProxy::write_to_socket (shared_ptr<Socket> socket) const
290  {
291         socket->write (_data.size());
292 -       socket->write (_data.data().get(), _data.size());
293 +       socket->write (_data.data(), _data.size());
294  }
295  
296  bool
297 @@ -223,11 +223,7 @@ FFmpegImageProxy::same (shared_ptr<const ImageProxy> other) const
298                 return false;
299         }
300  
301 -       if (_data.size() != mp->_data.size()) {
302 -               return false;
303 -       }
304 -
305 -       return memcmp (_data.data().get(), mp->_data.data().get(), _data.size()) == 0;
306 +       return _data == mp->_data;
307  }
308  
309  size_t
310 diff --git a/src/lib/ffmpeg_image_proxy.h b/src/lib/ffmpeg_image_proxy.h
311 index aa77003a4..62b99d280 100644
312 --- a/src/lib/ffmpeg_image_proxy.h
313 +++ b/src/lib/ffmpeg_image_proxy.h
314 @@ -19,7 +19,7 @@
315  */
316  
317  #include "image_proxy.h"
318 -#include <dcp/data.h>
319 +#include <dcp/array_data.h>
320  #include <boost/thread/mutex.hpp>
321  #include <boost/filesystem.hpp>
322  
323 @@ -27,7 +27,7 @@ class FFmpegImageProxy : public ImageProxy
324  {
325  public:
326         explicit FFmpegImageProxy (boost::filesystem::path);
327 -       explicit FFmpegImageProxy (dcp::Data);
328 +       explicit FFmpegImageProxy (dcp::ArrayData);
329         FFmpegImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
330  
331         Result image (
332 @@ -43,7 +43,7 @@ public:
333         int64_t avio_seek (int64_t const pos, int whence);
334  
335  private:
336 -       dcp::Data _data;
337 +       dcp::ArrayData _data;
338         mutable int64_t _pos;
339         /** Path of a file that this image came from, if applicable; stored so that
340             failed-decode errors can give more detail.
341 diff --git a/src/lib/image.cc b/src/lib/image.cc
342 index 002c7df9a..03f1bf6dc 100644
343 --- a/src/lib/image.cc
344 +++ b/src/lib/image.cc
345 @@ -1278,7 +1278,7 @@ Image::png_error (char const * message)
346         throw EncodeError (String::compose ("Error during PNG write: %1", message));
347  }
348  
349 -dcp::Data
350 +dcp::ArrayData
351  Image::as_png () const
352  {
353         DCPOMATIC_ASSERT (bytes_per_pixel(0) == 4);
354 @@ -1317,5 +1317,5 @@ Image::as_png () const
355         png_destroy_write_struct (&png_ptr, &info_ptr);
356         png_free (png_ptr, row_pointers);
357  
358 -       return dcp::Data (state.data, state.size);
359 +       return dcp::ArrayData (state.data, state.size);
360  }
361 diff --git a/src/lib/image.h b/src/lib/image.h
362 index eab71c2b1..ab9b3c78a 100644
363 --- a/src/lib/image.h
364 +++ b/src/lib/image.h
365 @@ -31,6 +31,7 @@
366  extern "C" {
367  #include <libavutil/pixfmt.h>
368  }
369 +#include <dcp/array_data.h>
370  #include <dcp/colour_conversion.h>
371  #include <boost/shared_ptr.hpp>
372  #include <boost/enable_shared_from_this.hpp>
373 @@ -83,7 +84,7 @@ public:
374  
375         size_t memory_used () const;
376  
377 -       dcp::Data as_png () const;
378 +       dcp::ArrayData as_png () const;
379  
380         void png_error (char const * message);
381  
382 diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc
383 index 64cd38147..18bb27645 100644
384 --- a/src/lib/j2k_encoder.cc
385 +++ b/src/lib/j2k_encoder.cc
386 @@ -127,7 +127,7 @@ J2KEncoder::end ()
387                 LOG_GENERAL (N_("Encode left-over frame %1"), (*i)->index ());
388                 try {
389                         _writer->write (
390 -                               (*i)->encode_locally(),
391 +                               shared_ptr<dcp::Data>(new dcp::ArrayData((*i)->encode_locally())),
392                                 (*i)->index(),
393                                 (*i)->eyes()
394                                 );
395 @@ -296,12 +296,12 @@ try
396  
397                         lock.unlock ();
398  
399 -                       optional<Data> encoded;
400 +                       shared_ptr<Data> encoded;
401  
402                         /* We need to encode this input */
403                         if (server) {
404                                 try {
405 -                                       encoded = vf->encode_remotely (server.get ());
406 +                                       encoded.reset(new dcp::ArrayData(vf->encode_remotely(server.get())));
407  
408                                         if (remote_backoff > 0) {
409                                                 LOG_GENERAL ("%1 was lost, but now she is found; removing backoff", server->host_name ());
410 @@ -324,7 +324,7 @@ try
411                         } else {
412                                 try {
413                                         LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), vf->index());
414 -                                       encoded = vf->encode_locally ();
415 +                                       encoded.reset(new dcp::ArrayData(vf->encode_locally()));
416                                         LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), vf->index());
417                                 } catch (std::exception& e) {
418                                         /* This is very bad, so don't cope with it, just pass it on */
419 @@ -334,7 +334,7 @@ try
420                         }
421  
422                         if (encoded) {
423 -                               _writer->write (encoded.get(), vf->index (), vf->eyes ());
424 +                               _writer->write (encoded, vf->index(), vf->eyes());
425                                 frame_done ();
426                         } else {
427                                 lock.lock ();
428 diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc
429 index 08ebc343c..064bbec7b 100644
430 --- a/src/lib/j2k_image_proxy.cc
431 +++ b/src/lib/j2k_image_proxy.cc
432 @@ -46,12 +46,12 @@ using std::make_pair;
433  using boost::shared_ptr;
434  using boost::optional;
435  using boost::dynamic_pointer_cast;
436 -using dcp::Data;
437 +using dcp::ArrayData;
438  using dcp::raw_convert;
439  
440  /** Construct a J2KImageProxy from a JPEG2000 file */
441  J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format)
442 -       : _data (path)
443 +       : _data (new dcp::ArrayData(path))
444         , _size (size)
445         , _pixel_format (pixel_format)
446         , _error (false)
447 @@ -60,13 +60,14 @@ J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPi
448         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
449  }
450  
451 +
452  J2KImageProxy::J2KImageProxy (
453         shared_ptr<const dcp::MonoPictureFrame> frame,
454         dcp::Size size,
455         AVPixelFormat pixel_format,
456         optional<int> forced_reduction
457         )
458 -       : _data (frame->j2k_size ())
459 +       : _data (frame)
460         , _size (size)
461         , _pixel_format (pixel_format)
462         , _forced_reduction (forced_reduction)
463 @@ -74,9 +75,9 @@ J2KImageProxy::J2KImageProxy (
464  {
465         /* ::image assumes 16bpp */
466         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
467 -       memcpy (_data.data().get(), frame->j2k_data(), _data.size ());
468  }
469  
470 +
471  J2KImageProxy::J2KImageProxy (
472         shared_ptr<const dcp::StereoPictureFrame> frame,
473         dcp::Size size,
474 @@ -84,7 +85,8 @@ J2KImageProxy::J2KImageProxy (
475         AVPixelFormat pixel_format,
476         optional<int> forced_reduction
477         )
478 -       : _size (size)
479 +       : _data (eye ? frame->left() : frame->right())
480 +       , _size (size)
481         , _eye (eye)
482         , _pixel_format (pixel_format)
483         , _forced_reduction (forced_reduction)
484 @@ -92,18 +94,9 @@ J2KImageProxy::J2KImageProxy (
485  {
486         /* ::image assumes 16bpp */
487         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
488 -       switch (eye) {
489 -       case dcp::EYE_LEFT:
490 -               _data = Data (frame->left_j2k_size ());
491 -               memcpy (_data.data().get(), frame->left_j2k_data(), _data.size ());
492 -               break;
493 -       case dcp::EYE_RIGHT:
494 -               _data = Data (frame->right_j2k_size ());
495 -               memcpy (_data.data().get(), frame->right_j2k_data(), _data.size ());
496 -               break;
497 -       }
498  }
499  
500 +
501  J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
502         : _error (false)
503  {
504 @@ -111,13 +104,14 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc
505         if (xml->optional_number_child<int> ("Eye")) {
506                 _eye = static_cast<dcp::Eye> (xml->number_child<int> ("Eye"));
507         }
508 -       _data = Data (xml->number_child<int> ("Size"));
509 +       shared_ptr<ArrayData> data(new ArrayData(xml->number_child<int>("Size")));
510         /* This only matters when we are using J2KImageProxy for the preview, which
511            will never use this constructor (which is only used for passing data to
512            encode servers).  So we can put anything in here.  It's a bit of a hack.
513         */
514         _pixel_format = AV_PIX_FMT_XYZ12LE;
515 -       socket->read (_data.data().get (), _data.size ());
516 +       socket->read (data->data(), data->size());
517 +       _data = data;
518  }
519  
520  int
521 @@ -144,7 +138,8 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const
522         }
523  
524         try {
525 -               shared_ptr<dcp::OpenJPEGImage> decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce);
526 +               /* XXX: should check that potentially trashing _data here doesn't matter */
527 +               shared_ptr<dcp::OpenJPEGImage> decompressed = dcp::decompress_j2k (const_cast<uint8_t*>(_data->data()), _data->size(), reduce);
528                 _image.reset (new Image (_pixel_format, decompressed->size(), true));
529  
530                 int const shift = 16 - decompressed->precision (0);
531 @@ -202,13 +197,13 @@ J2KImageProxy::add_metadata (xmlpp::Node* node) const
532         if (_eye) {
533                 node->add_child("Eye")->add_child_text (raw_convert<string> (static_cast<int> (_eye.get ())));
534         }
535 -       node->add_child("Size")->add_child_text (raw_convert<string> (_data.size ()));
536 +       node->add_child("Size")->add_child_text (raw_convert<string>(_data->size()));
537  }
538  
539  void
540  J2KImageProxy::write_to_socket (shared_ptr<Socket> socket) const
541  {
542 -       socket->write (_data.data().get(), _data.size());
543 +       socket->write (_data->data(), _data->size());
544  }
545  
546  bool
547 @@ -219,15 +214,11 @@ J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
548                 return false;
549         }
550  
551 -       if (_data.size() != jp->_data.size()) {
552 -               return false;
553 -       }
554 -
555 -       return memcmp (_data.data().get(), jp->_data.data().get(), _data.size()) == 0;
556 +       return *_data == *jp->_data;
557  }
558  
559 -J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_format)
560 -       : _data (data)
561 +J2KImageProxy::J2KImageProxy (ArrayData data, dcp::Size size, AVPixelFormat pixel_format)
562 +       : _data (new ArrayData(data))
563         , _size (size)
564         , _pixel_format (pixel_format)
565  {
566 @@ -238,7 +229,7 @@ J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_for
567  size_t
568  J2KImageProxy::memory_used () const
569  {
570 -       size_t m = _data.size();
571 +       size_t m = _data->size();
572         if (_image) {
573                 /* 3 components, 16-bits per pixel */
574                 m += 3 * 2 * _image->size().width * _image->size().height;
575 diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h
576 index 71bcffb2c..3eccc213d 100644
577 --- a/src/lib/j2k_image_proxy.h
578 +++ b/src/lib/j2k_image_proxy.h
579 @@ -19,8 +19,8 @@
580  */
581  
582  #include "image_proxy.h"
583 +#include <dcp/array_data.h>
584  #include <dcp/util.h>
585 -#include <dcp/data.h>
586  #include <boost/thread/mutex.hpp>
587  
588  namespace dcp {
589 @@ -60,7 +60,7 @@ public:
590         bool same (boost::shared_ptr<const ImageProxy>) const;
591         int prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const;
592  
593 -       dcp::Data j2k () const {
594 +       boost::shared_ptr<const dcp::Data> j2k () const {
595                 return _data;
596         }
597  
598 @@ -74,9 +74,9 @@ private:
599         friend struct client_server_test_j2k;
600  
601         /* For tests */
602 -       J2KImageProxy (dcp::Data data, dcp::Size size, AVPixelFormat pixel_format);
603 +       J2KImageProxy (dcp::ArrayData data, dcp::Size size, AVPixelFormat pixel_format);
604  
605 -       dcp::Data _data;
606 +       boost::shared_ptr<const dcp::Data> _data;
607         dcp::Size _size;
608         boost::optional<dcp::Eye> _eye;
609         mutable boost::shared_ptr<Image> _image;
610 diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc
611 index 10e798ed5..620245781 100644
612 --- a/src/lib/player_video.cc
613 +++ b/src/lib/player_video.cc
614 @@ -232,7 +232,7 @@ PlayerVideo::has_j2k () const
615         return _crop == Crop () && _out_size == j2k->size() && !_text && !_fade && !_colour_conversion;
616  }
617  
618 -Data
619 +shared_ptr<const dcp::Data>
620  PlayerVideo::j2k () const
621  {
622         shared_ptr<const J2KImageProxy> j2k = dynamic_pointer_cast<const J2KImageProxy> (_in);
623 diff --git a/src/lib/player_video.h b/src/lib/player_video.h
624 index 1a4a01d58..6043632c2 100644
625 --- a/src/lib/player_video.h
626 +++ b/src/lib/player_video.h
627 @@ -79,7 +79,7 @@ public:
628         bool reset_metadata (boost::shared_ptr<const Film> film, dcp::Size video_container_size, dcp::Size film_frame_size);
629  
630         bool has_j2k () const;
631 -       dcp::Data j2k () const;
632 +       boost::shared_ptr<const dcp::Data> j2k () const;
633  
634         Eyes eyes () const {
635                 return _eyes;
636 diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc
637 index a42c6182a..7ed79d818 100644
638 --- a/src/lib/reel_writer.cc
639 +++ b/src/lib/reel_writer.cc
640 @@ -67,6 +67,7 @@ using boost::dynamic_pointer_cast;
641  #if BOOST_VERSION >= 106100
642  using namespace boost::placeholders;
643  #endif
644 +using dcp::ArrayData;
645  using dcp::Data;
646  using dcp::raw_convert;
647  using namespace dcpomatic;
648 @@ -289,14 +290,14 @@ ReelWriter::check_existing_picture_asset (boost::filesystem::path asset)
649  }
650  
651  void
652 -ReelWriter::write (optional<Data> encoded, Frame frame, Eyes eyes)
653 +ReelWriter::write (shared_ptr<const Data> encoded, Frame frame, Eyes eyes)
654  {
655         if (!_picture_asset_writer) {
656                 /* We're not writing any data */
657                 return;
658         }
659  
660 -       dcp::FrameInfo fin = _picture_asset_writer->write (encoded->data().get (), encoded->size());
661 +       dcp::FrameInfo fin = _picture_asset_writer->write (encoded->data(), encoded->size());
662         write_frame_info (frame, eyes, fin);
663         _last_written[eyes] = encoded;
664  }
665 @@ -338,7 +339,7 @@ ReelWriter::repeat_write (Frame frame, Eyes eyes)
666         }
667  
668         dcp::FrameInfo fin = _picture_asset_writer->write (
669 -               _last_written[eyes]->data().get(),
670 +               _last_written[eyes]->data(),
671                 _last_written[eyes]->size()
672                 );
673         write_frame_info (frame, eyes, fin);
674 @@ -762,15 +763,15 @@ ReelWriter::existing_picture_frame_ok (FILE* asset_file, shared_ptr<InfoFileHand
675  
676         /* Read the data from the asset and hash it */
677         dcpomatic_fseek (asset_file, info.offset, SEEK_SET);
678 -       Data data (info.size);
679 -       size_t const read = fread (data.data().get(), 1, data.size(), asset_file);
680 +       ArrayData data (info.size);
681 +       size_t const read = fread (data.data(), 1, data.size(), asset_file);
682         LOG_GENERAL ("Read %1 bytes of asset data; wanted %2", read, info.size);
683         if (read != static_cast<size_t> (data.size ())) {
684                 LOG_GENERAL ("Existing frame %1 is incomplete", frame);
685                 ok = false;
686         } else {
687                 Digester digester;
688 -               digester.add (data.data().get(), data.size());
689 +               digester.add (data.data(), data.size());
690                 LOG_GENERAL ("Hash %1 vs %2", digester.get(), info.hash);
691                 if (digester.get() != info.hash) {
692                         LOG_GENERAL ("Existing frame %1 failed hash check", frame);
693 diff --git a/src/lib/reel_writer.h b/src/lib/reel_writer.h
694 index 17bfc7ba2..09c29adae 100644
695 --- a/src/lib/reel_writer.h
696 +++ b/src/lib/reel_writer.h
697 @@ -66,7 +66,7 @@ public:
698                 boost::optional<std::string> content_summary
699                 );
700  
701 -       void write (boost::optional<dcp::Data> encoded, Frame frame, Eyes eyes);
702 +       void write (boost::shared_ptr<const dcp::Data> encoded, Frame frame, Eyes eyes);
703         void fake_write (int size);
704         void repeat_write (Frame frame, Eyes eyes);
705         void write (boost::shared_ptr<const AudioBuffers> audio);
706 @@ -104,7 +104,7 @@ private:
707         /** the first picture frame index that does not already exist in our MXF */
708         int _first_nonexistant_frame;
709         /** the data of the last written frame, if there is one */
710 -       boost::optional<dcp::Data> _last_written[EYES_COUNT];
711 +       boost::shared_ptr<const dcp::Data> _last_written[EYES_COUNT];
712         /** index of this reel within the DCP (starting from 0) */
713         int _reel_index;
714         /** number of reels in the DCP */
715 diff --git a/src/lib/string_text_file.cc b/src/lib/string_text_file.cc
716 index d3c56832d..793619003 100644
717 --- a/src/lib/string_text_file.cc
718 +++ b/src/lib/string_text_file.cc
719 @@ -38,7 +38,7 @@ using std::string;
720  using boost::shared_ptr;
721  using boost::scoped_array;
722  using boost::optional;
723 -using dcp::Data;
724 +using dcp::ArrayData;
725  using namespace dcpomatic;
726  
727  StringTextFile::StringTextFile (shared_ptr<const StringTextFileContent> content)
728 @@ -64,11 +64,11 @@ StringTextFile::StringTextFile (shared_ptr<const StringTextFileContent> content)
729         } else {
730                 /* Text-based file; sort out its character encoding before we try to parse it */
731  
732 -               Data in (content->path (0));
733 +               ArrayData in (content->path (0));
734  
735                 UErrorCode status = U_ZERO_ERROR;
736                 UCharsetDetector* detector = ucsdet_open (&status);
737 -               ucsdet_setText (detector, reinterpret_cast<const char *> (in.data().get()), in.size(), &status);
738 +               ucsdet_setText (detector, reinterpret_cast<const char *>(in.data()), in.size(), &status);
739  
740                 UCharsetMatch const * match = ucsdet_detect (detector, &status);
741                 char const * in_charset = ucsdet_getName (match, &status);
742 @@ -78,7 +78,7 @@ StringTextFile::StringTextFile (shared_ptr<const StringTextFileContent> content)
743                 scoped_array<uint16_t> utf16 (new uint16_t[in.size() * 2]);
744                 int const utf16_len = ucnv_toUChars (
745                                 to_utf16, reinterpret_cast<UChar*>(utf16.get()), in.size() * 2,
746 -                               reinterpret_cast<const char *> (in.data().get()), in.size(),
747 +                               reinterpret_cast<const char *>(in.data()), in.size(),
748                                 &status
749                                 );
750  
751 diff --git a/src/lib/writer.cc b/src/lib/writer.cc
752 index d3fdc5128..346cbb0c2 100644
753 --- a/src/lib/writer.cc
754 +++ b/src/lib/writer.cc
755 @@ -66,6 +66,7 @@ using boost::optional;
756  using namespace boost::placeholders;
757  #endif
758  using dcp::Data;
759 +using dcp::ArrayData;
760  using namespace dcpomatic;
761  
762  Writer::Writer (shared_ptr<const Film> film, weak_ptr<Job> j)
763 @@ -130,7 +131,7 @@ Writer::~Writer ()
764   *  @param eyes Eyes that this frame image is for.
765   */
766  void
767 -Writer::write (Data encoded, Frame frame, Eyes eyes)
768 +Writer::write (shared_ptr<const Data> encoded, Frame frame, Eyes eyes)
769  {
770         boost::mutex::scoped_lock lock (_state_mutex);
771  
772 @@ -426,7 +427,7 @@ try
773                         case QueueItem::FULL:
774                                 LOG_DEBUG_ENCODE (N_("Writer FULL-writes %1 (%2)"), qi.frame, (int) qi.eyes);
775                                 if (!qi.encoded) {
776 -                                       qi.encoded = Data (_film->j2c_path (qi.reel, qi.frame, qi.eyes, false));
777 +                                       qi.encoded.reset (new ArrayData(_film->j2c_path(qi.reel, qi.frame, qi.eyes, false)));
778                                 }
779                                 reel.write (qi.encoded, qi.frame, qi.eyes);
780                                 ++_full_written;
781 diff --git a/src/lib/writer.h b/src/lib/writer.h
782 index 71e04df96..fd7db69db 100644
783 --- a/src/lib/writer.h
784 +++ b/src/lib/writer.h
785 @@ -35,7 +35,7 @@
786  #include <list>
787  
788  namespace dcp {
789 -       class Data;
790 +       class ArrayData;
791  }
792  
793  namespace dcpomatic {
794 @@ -70,7 +70,7 @@ public:
795         } type;
796  
797         /** encoded data for FULL */
798 -       boost::optional<dcp::Data> encoded;
799 +       boost::shared_ptr<const dcp::Data> encoded;
800         /** size of data for FAKE */
801         int size;
802         /** reel index */
803 @@ -105,7 +105,7 @@ public:
804  
805         bool can_fake_write (Frame) const;
806  
807 -       void write (dcp::Data, Frame, Eyes);
808 +       void write (boost::shared_ptr<const dcp::Data>, Frame, Eyes);
809         void fake_write (Frame, Eyes);
810         bool can_repeat (Frame) const;
811         void repeat (Frame, Eyes);
812 diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc
813 index 99a6b4caf..b64970f62 100644
814 --- a/src/tools/server_test.cc
815 +++ b/src/tools/server_test.cc
816 @@ -46,7 +46,7 @@ using boost::bind;
817  #if BOOST_VERSION >= 106100
818  using namespace boost::placeholders;
819  #endif
820 -using dcp::Data;
821 +using dcp::ArrayData;
822  
823  static shared_ptr<Film> film;
824  static EncodeServerDescription* server;
825 @@ -63,8 +63,8 @@ process_video (shared_ptr<PlayerVideo> pvf)
826  
827         ++frame_count;
828  
829 -       Data local_encoded = local->encode_locally ();
830 -       Data remote_encoded;
831 +       ArrayData local_encoded = local->encode_locally ();
832 +       ArrayData remote_encoded;
833  
834         string remote_error;
835         try {
836 @@ -83,8 +83,8 @@ process_video (shared_ptr<PlayerVideo> pvf)
837                 return;
838         }
839  
840 -       uint8_t* p = local_encoded.data().get ();
841 -       uint8_t* q = remote_encoded.data().get ();
842 +       uint8_t* p = local_encoded.data();
843 +       uint8_t* q = remote_encoded.data();
844         for (int i = 0; i < local_encoded.size(); ++i) {
845                 if (*p++ != *q++) {
846                         cout << "\033[0;31mdata differ\033[0m at byte " << i << "\n";
847 diff --git a/test/client_server_test.cc b/test/client_server_test.cc
848 index 75cee85b3..22eeedbab 100644
849 --- a/test/client_server_test.cc
850 +++ b/test/client_server_test.cc
851 @@ -46,16 +46,16 @@ using boost::shared_ptr;
852  using boost::thread;
853  using boost::optional;
854  using boost::weak_ptr;
855 -using dcp::Data;
856 +using dcp::ArrayData;
857  
858  void
859 -do_remote_encode (shared_ptr<DCPVideo> frame, EncodeServerDescription description, Data locally_encoded)
860 +do_remote_encode (shared_ptr<DCPVideo> frame, EncodeServerDescription description, ArrayData locally_encoded)
861  {
862 -       Data remotely_encoded;
863 +       ArrayData remotely_encoded;
864         BOOST_REQUIRE_NO_THROW (remotely_encoded = frame->encode_remotely (description, 1200));
865  
866         BOOST_REQUIRE_EQUAL (locally_encoded.size(), remotely_encoded.size());
867 -       BOOST_CHECK_EQUAL (memcmp (locally_encoded.data().get(), remotely_encoded.data().get(), locally_encoded.size()), 0);
868 +       BOOST_CHECK_EQUAL (memcmp (locally_encoded.data(), remotely_encoded.data(), locally_encoded.size()), 0);
869  }
870  
871  BOOST_AUTO_TEST_CASE (client_server_test_rgb)
872 @@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb)
873                         )
874                 );
875  
876 -       Data locally_encoded = frame->encode_locally ();
877 +       ArrayData locally_encoded = frame->encode_locally ();
878  
879         EncodeServer* server = new EncodeServer (true, 2);
880  
881 @@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv)
882                         )
883                 );
884  
885 -       Data locally_encoded = frame->encode_locally ();
886 +       ArrayData locally_encoded = frame->encode_locally ();
887  
888         EncodeServer* server = new EncodeServer (true, 2);
889  
890 @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_j2k)
891                         )
892                 );
893  
894 -       Data raw_locally_encoded = raw_frame->encode_locally ();
895 +       ArrayData raw_locally_encoded = raw_frame->encode_locally ();
896  
897         shared_ptr<PlayerVideo> j2k_pvf (
898                 new PlayerVideo (
899 @@ -303,7 +303,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_j2k)
900                         )
901                 );
902  
903 -       Data j2k_locally_encoded = j2k_frame->encode_locally ();
904 +       ArrayData j2k_locally_encoded = j2k_frame->encode_locally ();
905  
906         EncodeServer* server = new EncodeServer (true, 2);
907  
908 diff --git a/test/crypto_test.cc b/test/crypto_test.cc
909 index e1069b42f..26c6748b8 100644
910 --- a/test/crypto_test.cc
911 +++ b/test/crypto_test.cc
912 @@ -29,12 +29,12 @@ using std::list;
913  
914  BOOST_AUTO_TEST_CASE (crypto_test)
915  {
916 -       dcp::Data key (dcpomatic::crypto_key_length());
917 -       dcp::Data iv = dcpomatic::random_iv ();
918 +       dcp::ArrayData key (dcpomatic::crypto_key_length());
919 +       dcp::ArrayData iv = dcpomatic::random_iv ();
920  
921 -       RAND_bytes (key.data().get(), dcpomatic::crypto_key_length());
922 +       RAND_bytes (key.data(), dcpomatic::crypto_key_length());
923  
924 -       dcp::Data ciphertext = dcpomatic::encrypt ("Can you see any fish?", key, iv);
925 +       dcp::ArrayData ciphertext = dcpomatic::encrypt ("Can you see any fish?", key, iv);
926         BOOST_REQUIRE_EQUAL (dcpomatic::decrypt (ciphertext, key, iv), "Can you see any fish?");
927  
928         key.data()[5]++;
929 diff --git a/test/test.cc b/test/test.cc
930 index 03e8768f4..9ac202b80 100644
931 --- a/test/test.cc
932 +++ b/test/test.cc
933 @@ -687,7 +687,7 @@ write_image (shared_ptr<const Image> image, boost::filesystem::path file)
934         png_destroy_write_struct (&png_ptr, &info_ptr);
935         png_free (png_ptr, row_pointers);
936  
937 -       dcp::Data(state.data, state.size).write(file);
938 +       dcp::ArrayData(state.data, state.size).write(file);
939  }
940  
941