Add support for obtaining a frame as RGBA.
[libdcp.git] / src / picture_frame.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <openjpeg.h>
21 #include "AS_DCP.h"
22 #include "KM_fileio.h"
23 #include "picture_frame.h"
24 #include "exceptions.h"
25 #include "rgba_frame.h"
26 #include "lut.h"
27
28 using namespace std;
29 using namespace boost;
30 using namespace libdcp;
31
32 PictureFrame::PictureFrame (string mxf_path, int n)
33 {
34         ASDCP::JP2K::MXFReader reader;
35         if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) {
36                 throw FileError ("could not open MXF file for reading", mxf_path);
37         }
38
39         /* XXX: unfortunate guesswork on this buffer size */
40         _buffer = new ASDCP::JP2K::FrameBuffer (4 * Kumu::Megabyte);
41
42         if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer))) {
43                 throw DCPReadError ("could not read video frame");
44         }
45 }
46
47 PictureFrame::~PictureFrame ()
48 {
49         delete _buffer;
50 }
51
52 uint8_t const *
53 PictureFrame::data () const
54 {
55         return _buffer->RoData();
56 }
57
58 int
59 PictureFrame::size () const
60 {
61         return _buffer->Size ();
62 }
63
64 shared_ptr<RGBAFrame>
65 PictureFrame::rgba_frame () const
66 {
67         /* JPEG2000 -> decompressed XYZ */
68         
69         opj_dinfo_t* decoder = opj_create_decompress (CODEC_J2K);
70         opj_dparameters_t parameters;
71         opj_set_default_decoder_parameters (&parameters);
72         opj_setup_decoder (decoder, &parameters);
73         opj_cio_t* cio = opj_cio_open ((opj_common_ptr) decoder, const_cast<unsigned char *> (data()), size());
74         opj_image_t* xyz_frame = opj_decode (decoder, cio);
75         if (!xyz_frame) {
76                 opj_destroy_decompress (decoder);
77                 opj_cio_close (cio);
78                 throw DCPReadError ("could not decode JPEG2000 codestream");
79         }
80         
81         assert (xyz_frame->numcomps == 3);
82         
83         /* XYZ -> RGB */
84         
85         struct {
86                 double x, y, z;
87         } s;
88         
89         struct {
90                 double r, g, b;
91         } d;
92         
93         int* xyz_x = xyz_frame->comps[0].data;
94         int* xyz_y = xyz_frame->comps[1].data;
95         int* xyz_z = xyz_frame->comps[2].data;
96
97         shared_ptr<RGBAFrame> rgba_frame (new RGBAFrame (xyz_frame->x1, xyz_frame->y1));
98         
99         uint8_t* rgba = rgba_frame->data ();
100         
101         for (int y = 0; y < xyz_frame->y1; ++y) {
102                 uint8_t* rgba_line = rgba;
103                 for (int x = 0; x < xyz_frame->x1; ++x) {
104                         
105                         assert (*xyz_x >= 0 && *xyz_y >= 0 && *xyz_z >= 0 && *xyz_x < 4096 && *xyz_x < 4096 && *xyz_z < 4096);
106                         
107                         /* In gamma LUT */
108                         s.x = lut_in[*xyz_x++];
109                         s.y = lut_in[*xyz_y++];
110                         s.z = lut_in[*xyz_z++];
111                         
112                         /* DCI companding */
113                         s.x /= DCI_COEFFICIENT;
114                         s.y /= DCI_COEFFICIENT;
115                         s.z /= DCI_COEFFICIENT;
116                         
117                         /* XYZ to RGB */
118                         d.r = ((s.x * color_matrix[0][0]) + (s.y * color_matrix[0][1]) + (s.z * color_matrix[0][2]));
119                         d.g = ((s.x * color_matrix[1][0]) + (s.y * color_matrix[1][1]) + (s.z * color_matrix[1][2]));
120                         d.b = ((s.x * color_matrix[2][0]) + (s.y * color_matrix[2][1]) + (s.z * color_matrix[2][2]));
121                         
122                         d.r = min (d.r, 1.0);
123                         d.r = max (d.r, 0.0);
124                         
125                         d.g = min (d.g, 1.0);
126                         d.g = max (d.g, 0.0);
127                         
128                         d.b = min (d.b, 1.0);
129                         d.b = max (d.b, 0.0);
130                         
131                         /* Out gamma LUT */
132                         *rgba_line++ = lut_out[(int) (d.r * COLOR_DEPTH)];
133                         *rgba_line++ = lut_out[(int) (d.g * COLOR_DEPTH)];
134                         *rgba_line++ = lut_out[(int) (d.b * COLOR_DEPTH)];
135                         *rgba_line++ = 0xff;
136                 }
137                 
138                 rgba += rgba_frame->stride ();
139         }
140         
141         opj_cio_close (cio);
142         opj_image_destroy (xyz_frame);
143
144         return rgba_frame;
145 }