Fix encoding, perhaps.
[dcpomatic.git] / src / lib / j2k_encoder_fastvideo_backend.cc
1 #include "dcpomatic_assert.h"
2 #include "dcpomatic_log.h"
3 #include "dcp_video.h"
4 #include "exceptions.h"
5 #include "image.h"
6 #include "j2k_encoder_fastvideo_backend.h"
7 #include "player_video.h"
8 #include <dcp/rgb_xyz.h>
9 #include <fastvideo_encoder_j2k.h>
10 #include <fastvideo_sdk.h>
11
12
13 using std::vector;
14 using boost::optional;
15 using boost::shared_ptr;
16 using dcp::Data;
17
18
19
20 J2KEncoderFastvideoBackend::J2KEncoderFastvideoBackend ()
21         : _setup_done (false)
22 {
23         fastSdkParametersHandle_t sdk_parameters;
24         fastStatus_t r = fastGetSdkParametersHandle(&sdk_parameters);
25         if (r != FAST_OK) {
26                 throw FastvideoError ("GetSdkParametersHandle", r);
27         }
28         r = fastEncoderJ2kLibraryInit(sdk_parameters);
29         if (r != FAST_OK) {
30                 throw FastvideoError ("DecoderJ2kLibraryInit", r);
31         }
32         fastTraceCreate("/home/carl/trace.log");
33 }
34
35
36 J2KEncoderFastvideoBackend::~J2KEncoderFastvideoBackend ()
37 {
38         if (_setup_done) {
39                 fastFree (_xyz_buffer);
40                 fastEncoderJ2kDestroy (_encoder);
41                 fastImportFromHostDestroy (_adapter);
42         }
43 }
44
45
46 void
47 J2KEncoderFastvideoBackend::setup (dcp::Size size)
48 {
49         fastStatus_t r = fastImportFromHostCreate(
50                 &_adapter, FAST_RGB12, size.width, size.height, &_src_buffer
51                 );
52         if (r != FAST_OK) {
53                 throw FastvideoError ("ImportFromHostCreate", r);
54         }
55
56         fastEncoderJ2kStaticParameters_t parameters;
57         parameters.lossless = false;
58         parameters.pcrdEnabled = true;
59         parameters.dwtLevels = 6;
60         parameters.codeblockSize = 32;
61         parameters.maxQuality = 0.5;
62         parameters.compressionRatio = 2;
63         parameters.info = false;
64         parameters.tier2Threads = 4;
65         parameters.tileWidth = 0;//size.width;
66         parameters.tileHeight = 0;//size.height;
67         parameters.noMCT = false;
68         parameters.ss1_x = 1;
69         parameters.ss1_y = 1;
70         parameters.ss2_x = 1;
71         parameters.ss2_y = 1;
72         parameters.ss3_x = 1;
73         parameters.ss3_y = 1;
74         parameters.yuvSubsampledFormat = false;
75
76         r = fastEncoderJ2kCreate(
77                 &_encoder, &parameters, FAST_RGB12, size.width, size.height, quantity(), _src_buffer
78                 );
79         if (r != FAST_OK) {
80                 throw FastvideoError ("EncoderJ2kCreate", r);
81         }
82
83         bool success = false;
84
85         r = fastEncoderJ2kIsInitialized(_encoder, &success);
86         if (r != FAST_OK || !success) {
87                 throw FastvideoError ("EncoderJ2kIsInitialized", r);
88         }
89
90         _xyz_buffer_stride = size.width * 6;
91         _xyz_buffer_stride += 4 - (_xyz_buffer_stride % 4);
92         r = fastMalloc(reinterpret_cast<void**>(&_xyz_buffer), _xyz_buffer_stride * size.height);
93         if (r != FAST_OK) {
94                 throw FastvideoError ("Malloc", r);
95         }
96 }
97
98
99 vector<Data>
100 J2KEncoderFastvideoBackend::encode (vector<shared_ptr<DCPVideo> > video)
101 {
102         DCPOMATIC_ASSERT (static_cast<int>(video.size()) == quantity());
103         std::cout << "FV: " << video.size() << " from " << video.front()->index() << "\n";
104
105         if (!_setup_done) {
106                 setup (video.front()->frame()->out_size());
107                 _setup_done = true;
108         }
109
110         BOOST_FOREACH (shared_ptr<DCPVideo> i, video) {
111                 shared_ptr<dcpomatic::Image> image = i->frame()->image(boost::bind(&PlayerVideo::keep_xyz_or_rgb, _1), true, false);
112                 if (i->frame()->colour_conversion()) {
113                         dcp::rgb_to_xyz (
114                                 image->data()[0],
115                                 image->size(),
116                                 image->stride()[0],
117                                 _xyz_buffer,
118                                 _xyz_buffer_stride,
119                                 i->frame()->colour_conversion().get()
120                                 );
121                 } else {
122                         /* XXX */
123                 }
124
125                 fastStatus_t r = fastImportFromHostCopy(
126                         _adapter,
127                         _xyz_buffer,
128                         image->size().width,
129                         _xyz_buffer_stride,
130                         image->size().height
131                         );
132                 if (r != FAST_OK) {
133                         throw FastvideoError ("ImportFromHostCopy", r);
134                 }
135
136                 fastEncoderJ2kDynamicParameters_t dynamic_parameters;
137                 dynamic_parameters.targetStreamSize = _xyz_buffer_stride * image->size().width / 2;
138                 dynamic_parameters.quality = 0.5;
139                 dynamic_parameters.writeHeader = false;
140
141                 r = fastEncoderJ2kAddImageToBatch(
142                         _encoder,
143                         &dynamic_parameters,
144                         image->size().width,
145                         image->size().height
146                 );
147         }
148
149
150         int free_slots = 0;
151         fastEncoderJ2kFreeSlotsInBatch(_encoder, &free_slots);
152         DCPOMATIC_ASSERT (free_slots == 0);
153
154         fastEncoderJ2kReport_t report;
155
156         fastEncoderJ2kOutput_t output;
157         int const max_j2k_size = 1024 * 1024 * 2;
158         output.bufferSize = max_j2k_size;
159         dcp::Data data(output.bufferSize);
160         output.byteStream = data.data().get();
161
162         fastStatus_t r = fastEncoderJ2kTransformBatch(_encoder, &output, &report);
163         if (r != FAST_OK) {
164                 fastTraceClose();
165                 throw FastvideoError ("EncoderJ2KTransformBatch", r);
166         }
167
168         vector<Data> encoded;
169         for (size_t i = 0; i < video.size(); ++i) {
170                 std::cout << "\tframe " << output.streamSize << "\n";
171                 data.set_size (output.streamSize);
172                 encoded.push_back (data);
173                 data = dcp::Data(output.bufferSize);
174                 output.byteStream = data.data().get();
175                 int images_left = 0;
176                 r = fastEncoderJ2kGetNextEncodedImage (_encoder, &output, &report, &images_left);
177         }
178
179         std::cout << "FV returns " << encoded.size() << "\n";
180         return encoded;
181 }
182
183