ba0b2036c4457c2883b7f0c9c8c8288b6b87afc5
[dcpomatic.git] / src / lib / gpu_j2k_encode_worker.cc
1 /*
2     Copyright (C) 2019 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 #include "gpu_j2k_encode_worker.h"
22 #include "dcp_video.h"
23 #include "cross.h"
24 #include "timer.h"
25 #include "dcpomatic_log.h"
26 #include <dcp/openjpeg_image.h>
27 extern "C" {
28 #include <poznanj2k/config/init_device.h>
29 #include <poznanj2k/types/image_types.h>
30 #include <poznanj2k/types/image.h>
31 #include <poznanj2k/preprocessing/mct.h>
32 #include <poznanj2k/dwt/dwt.h>
33 #include <poznanj2k/tier1/quantizer.h>
34 #include <poznanj2k/tier1/coeff_coder/gpu_coder.h>
35 #include <poznanj2k/tier2/codestream.h>
36 #include <poznanj2k/misc/memory_management.cuh>
37 #include <cuda_runtime_api.h>
38 }
39
40 #include "i18n.h"
41
42 using dcp::Data;
43 using boost::optional;
44 using boost::shared_ptr;
45
46 GPUJ2KEncodeWorker::GPUJ2KEncodeWorker ()
47 {
48         init_device (0);
49 }
50
51 optional<Data>
52 GPUJ2KEncodeWorker::encode (shared_ptr<DCPVideo> vf)
53 {
54         shared_ptr<dcp::OpenJPEGImage> image = DCPVideo::convert_to_xyz(vf->frame(), boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
55         int const width = image->size().width;
56         int const height = image->size().height;
57
58         type_image img;
59         img.mct_compression_method = 0;
60         img.width = width;
61         img.height = height;
62         img.num_components = 3;
63         img.depth = 36;
64         img.sign = UNSIGNED;
65         /* XXX: 6 for 4K? */
66         img.num_dlvls = 5;
67         img.wavelet_type = 1;
68         img.num_tiles = 1;
69         img.tile_w = width;
70         img.tile_h = height;
71         img.coding_style = CODING_STYLE_PRECINCTS_DEFINED;
72         img.prog_order = COMP_POS_RES_LY_PROG;
73         img.num_layers = 1;
74         img.num_range_bits = 12;
75         img.use_mct = 1;
76         img.use_part2_mct = 0;
77
78         set_coding_parameters (&img, (vf->j2k_bandwidth() / 8) / vf->frames_per_second());
79
80         init_tiles (&img, width, height, 5, 5);
81         type_tile* tile = &(img.tile[0]);
82
83         PeriodTimer encode("poz-encode");
84
85         // XXX: it's a big shame about this int -> float conversion
86         for (int i = 0; i < 3; ++i) {
87                 type_tile_comp* c = &tile->tile_comp[i];
88                 c->tile_comp_no = i;
89                 int const pixels = c->width * c->height;
90                 for (int j = 0; j < pixels; ++j) {
91                         c->img_data[j] = float (image->data(i)[j]);
92                 }
93                 cuda_memcpy_htd (c->img_data, c->img_data_d, pixels * sizeof(type_data));
94         }
95
96         mct (&img, 10000, 0.000001, 1.0e-7);
97         fwt (tile);
98         quantize_tile (tile);
99         encode_tile (tile);
100
101         type_buffer buffer;
102         init_buffer (&buffer);
103         encode_codestream (&buffer, &img);
104         cudaThreadSynchronize ();
105
106         image_destroy(&img);
107
108         // XXX: remove this memcpy
109         dcp::Data encoded (buffer.bytes_count);
110         memcpy (encoded.data().get(), buffer.data, buffer.bytes_count);
111         free (buffer.data);
112         return encoded;
113 }
114
115 void
116 GPUJ2KEncodeWorker::log_thread_start ()
117 {
118         LOG_TIMING ("start-encoder-thread thread=%1 GPU", thread_id());
119 }