c5de41920be00a6cc40ace4ba42b1843e502292d
[dcpomatic.git] / src / lib / poznan_encoder.cc
1 /*
2     Copyright (C) 2015 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 "poznan_encoder.h"
21 #include "exceptions.h"
22 #include "encoded_data.h"
23 #include "raw_convert.h"
24 #include <poznan/tier2/markers.h>
25 #include <dcp/xyz_image.h>
26 #include <dlfcn.h>
27
28 #include "i18n.h"
29
30 using std::string;
31 using std::cout;
32 using boost::shared_ptr;
33
34 PoznanEncoder::PoznanEncoder ()
35 {
36         void* config = open_library ("config");
37         void* preprocessing = open_library ("preprocessing");
38         void* dwt = open_library ("dwt");
39         void* tier1 = open_library ("tier1");
40         void* gpu_coeff_coder = open_library ("gpu_coeff_coder");
41         void* tier2 = open_library ("tier2");
42         void* types = open_library ("types");
43         void* misc = open_library ("misc");
44         
45         _init_device = (void (*)(type_parameters *)) dlsym (config, "init_device");
46         _color_coder_lossy = (void (*)(type_image *)) dlsym (preprocessing, "color_coder_lossy");
47         _fwt = (void (*)(type_tile *)) dlsym (dwt, "fwt");
48         _quantize_tile = (void (*)(type_tile *)) dlsym (tier1, "quantize_tile");
49         _encode_tile = (void (*)(type_tile *)) dlsym (gpu_coeff_coder, "encode_tile");
50         _set_coding_parameters = (void (*)(type_image *, type_parameters *)) dlsym (types, "set_coding_parameters");
51         _init_tiles = (void (*)(type_image **, type_parameters *)) dlsym (types, "init_tiles");
52         _init_buffer = (void (*)(type_buffer *)) dlsym (types, "init_buffer");
53         _encode_codestream = (void (*)(type_buffer *, type_image *)) dlsym (tier2, "encode_codestream");
54         _cuda_h_allocate_mem = (void (*)(void **, uint64_t)) dlsym (misc, "cuda_h_allocate_mem");
55         _cuda_memcpy_htd = (void (*)(void *, void *, uint64_t)) dlsym (misc, "cuda_memcpy_htd");
56         _cuda_h_free = (void (*)(void *)) dlsym (misc, "cuda_h_free");
57         
58         if (
59                 !_init_device || !_color_coder_lossy || !_fwt || !_quantize_tile ||
60                 !_encode_tile || !_set_coding_parameters || !_init_tiles ||
61                 !_init_buffer || !_encode_codestream || !_cuda_h_allocate_mem ||
62                 !_cuda_memcpy_htd || !_cuda_h_free) {
63                 throw JPEG2000EncoderUnavailableException (name(), "missing symbol");
64         }
65 }
66
67 void *
68 PoznanEncoder::open_library (string library_name)
69 {
70         /* XXX: need cross-platform implementation of dlopen etc. */
71
72         library_name = "libdcpomatic-" + library_name + ".so";
73         void* lib = dlopen (library_name.c_str(), RTLD_LAZY | RTLD_GLOBAL);
74         if (!lib) {
75                 throw JPEG2000EncoderUnavailableException (name(), "could not find " + library_name + " (" + dlerror() + ")");
76         }
77         return lib;
78 }
79
80 void
81 PoznanEncoder::parameters_changed ()
82 {
83         /* One tile which covers entire image */
84         _param.param_tile_w = -1;
85         _param.param_tile_h = -1;
86
87         /* Wavelet decomposition levels */
88         _param.param_tile_comp_dlvls = _resolution.get() == RESOLUTION_2K ? 5 : 6;
89
90         /* Power of 2 for maximum codeblock size */
91         _param.param_cblk_exp_w = 5;
92         _param.param_cblk_exp_h = 5;
93
94         /* DWT 9/7 transform */
95         _param.param_wavelet_type = 1;
96
97         /* Use MCT */
98         _param.param_use_mct = 1;
99
100         /* Device to run on */
101         _param.param_device = 0;
102
103         /* Target file size */
104         _param.param_target_size = (_bandwidth.get() / _frame_rate.get()) / 8;
105         if (_threed.get ()) {
106                 _param.param_target_size /= 2;
107         }
108
109         /* Bits per pixel per component */
110         _param.param_bp = 12;
111
112         /* Don't know about these: use the defaults */
113         _param.param_use_part2_mct = 0;
114         _param.param_mct_compression_method = 0;
115         _param.param_mct_klt_iterations = 10000;
116         _param.param_mct_klt_border_eigenvalue = 0.000001;
117         _param.param_mct_klt_err = 1.0e-7;
118         
119         _init_device (&_param);
120 }
121
122 string
123 PoznanEncoder::name () const
124 {
125         return _("CUDA (GPU) encoder (Poznan Supercomputing and Networking Center)");
126 }
127
128 shared_ptr<EncodedData>
129 PoznanEncoder::do_encode (shared_ptr<const dcp::XYZImage> input)
130 {
131         type_image* img = new type_image;
132
133         img->width = input->size().width;
134         img->height = input->size().height;
135         img->depth = 12;
136         img->num_components = 3;
137         img->num_range_bits = 12;
138         img->sign = UNSIGNED;
139         img->num_dlvls = _param.param_tile_comp_dlvls;
140
141         img->wavelet_type = _param.param_wavelet_type;
142         img->use_mct = _param.param_use_mct;
143         img->use_part2_mct = _param.param_use_part2_mct;
144         img->mct_compression_method = _param.param_mct_compression_method;
145
146         img->coding_style = CODING_STYLE;
147         img->prog_order = COMP_POS_RES_LY_PROG;
148         img->num_layers = NUM_LAYERS;
149
150         _set_coding_parameters (img, &_param);
151         _init_tiles (&img, &_param);
152
153         _color_coder_lossy (img);
154
155         type_tile* tile = &(img->tile[0]);
156
157         /* XXX: it's a shame about this int -> float conversion */
158         for (int i = 0; i < 3; ++i) {
159                 type_tile_comp* c = &tile->tile_comp[i];
160                 std::cout << "Tile comp " << i << ": " << c->width << "x" << c->height << "\n";
161                 int const pixels = c->width * c->height;
162                 _cuda_h_allocate_mem ((void **) &c->img_data, pixels * sizeof (type_data));
163                 for (int j = 0; j < pixels; ++j) {
164                         c->img_data[j] = float (input->data(i)[j]) / 4095;
165                         //c->img_data[j] = input->data(i)[j];
166                 }
167                 _cuda_memcpy_htd (c->img_data, c->img_data_d, pixels * sizeof (type_data));
168                 _cuda_h_free (c->img_data);
169         }
170         
171         std::cout << "Tile " << tile->width << "x" << tile->height << "\n";
172         _fwt (tile);
173         _quantize_tile (tile);
174         _encode_tile (tile);
175
176         type_buffer buffer;
177         _init_buffer (&buffer);
178         _encode_codestream (&buffer, img);
179
180         std::cout << img->num_tiles << " tiles.\n";
181         std::cout << "got " << buffer.bytes_count << " bytes.\n";
182         shared_ptr<EncodedData> encoded (new EncodedData (buffer.data, buffer.bytes_count));
183
184         /* XXX! */
185         static int shit = 0;
186         {
187                 string name = raw_convert<string> (shit);
188                 FILE* f = fopen (name.c_str(), "wb");
189                 fwrite (buffer.data, 1, buffer.bytes_count, f);
190                 fclose (f);
191                 ++shit;
192         }
193
194         free (buffer.data);
195         delete img;
196
197         return encoded;
198 }