Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/plugins/encoder_openjpeg.cc
Line
Count
Source
1
/*
2
 * OpenJPEG codec.
3
 * Copyright (c) 2023 Devon Sookhoo
4
 * Copyright (c) 2023 Dirk Farin <dirk.farin@gmail.com>
5
 *
6
 * This file is part of libheif.
7
 *
8
 * libheif is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as
10
 * published by the Free Software Foundation, either version 3 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * libheif is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "libheif/heif.h"
23
#include "libheif/heif_plugin.h"
24
#include "encoder_openjpeg.h"
25
26
#include <openjpeg.h>
27
#include <string.h>
28
29
#include <vector>
30
#include <string>
31
#include <cassert>
32
33
using namespace std;
34
35
36
static const int OPJ_PLUGIN_PRIORITY = 80;
37
38
39
struct encoder_struct_opj
40
{
41
  int quality = 70;
42
  heif_chroma chroma = heif_chroma_undefined;
43
  opj_cparameters_t parameters;
44
45
  // --- output
46
47
  std::vector<uint8_t> codestream; //contains encoded pixel data
48
  bool data_read = false;
49
50
  // --- parameters
51
52
  // std::vector<parameter> parameters;
53
54
  // void add_param(const parameter&);
55
56
  // void add_param(const std::string& name, int value);
57
58
  // void add_param(const std::string& name, bool value);
59
60
  // void add_param(const std::string& name, const std::string& value);
61
62
  // parameter get_param(const std::string& name) const;
63
64
  // std::string preset;
65
  // std::string tune;
66
67
  // int logLevel = X265_LOG_NONE;
68
};
69
70
static const char* kParam_chroma = "chroma";
71
static const char* const kParam_chroma_valid_values[] = {
72
    "420", "422", "444", nullptr
73
};
74
75
76
0
#define MAX_PLUGIN_NAME_LENGTH 80
77
static char plugin_name[MAX_PLUGIN_NAME_LENGTH];
78
79
const char* opj_plugin_name()
80
0
{
81
0
  snprintf(plugin_name, MAX_PLUGIN_NAME_LENGTH, "OpenJPEG %s", opj_version());
82
0
  plugin_name[MAX_PLUGIN_NAME_LENGTH - 1] = 0;
83
84
0
  return plugin_name;
85
0
}
86
87
88
#define MAX_NPARAMETERS 10
89
90
static heif_encoder_parameter opj_encoder_params[MAX_NPARAMETERS];
91
static const heif_encoder_parameter* opj_encoder_parameter_ptrs[MAX_NPARAMETERS + 1];
92
93
static void opj_init_parameters()
94
254
{
95
254
  heif_encoder_parameter* p = opj_encoder_params;
96
254
  const heif_encoder_parameter** d = opj_encoder_parameter_ptrs;
97
254
  int i = 0;
98
99
254
  assert(i < MAX_NPARAMETERS);
100
254
  p->version = 2;
101
254
  p->name = kParam_chroma;
102
254
  p->type = heif_encoder_parameter_type_string;
103
  //p->string.default_value = "420";
104
254
  p->has_default = false;
105
254
  p->string.valid_values = kParam_chroma_valid_values;
106
254
  d[i++] = p++;
107
108
254
  d[i++] = nullptr;
109
254
}
110
111
void opj_init_plugin()
112
254
{
113
254
  opj_init_parameters();
114
254
}
115
116
void opj_cleanup_plugin()
117
0
{
118
0
}
119
120
static void opj_set_default_parameters(void* encoder);
121
122
heif_error opj_new_encoder(void** encoder_out)
123
0
{
124
0
  encoder_struct_opj* encoder = new encoder_struct_opj();
125
0
  *encoder_out = encoder;
126
127
0
  opj_set_default_parameters(encoder);
128
0
  opj_set_default_encoder_parameters(&(encoder->parameters));
129
130
0
  return heif_error_ok;
131
0
}
132
133
void opj_free_encoder(void* encoder_raw)
134
0
{
135
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
136
0
  delete encoder;
137
0
}
138
139
heif_error opj_set_parameter_quality(void* encoder_raw, int quality)
140
0
{
141
0
  auto* encoder = (encoder_struct_opj*) encoder_raw;
142
143
0
  if (quality < 0 || quality > 100) {
144
0
    return heif_error_invalid_parameter_value;
145
0
  }
146
147
0
  encoder->quality = quality;
148
149
0
  return heif_error_ok;
150
0
}
151
152
heif_error opj_get_parameter_quality(void* encoder_raw, int* quality)
153
0
{
154
0
  auto* encoder = (encoder_struct_opj*) encoder_raw;
155
156
0
  *quality = encoder->quality;
157
158
0
  return heif_error_ok;
159
0
}
160
161
heif_error opj_set_parameter_lossless(void* encoder_raw, int lossless)
162
0
{
163
0
  auto* encoder = (encoder_struct_opj*) encoder_raw;
164
0
  encoder->parameters.irreversible = lossless ? 0 : 1;
165
0
  return heif_error_ok;
166
0
}
167
168
heif_error opj_get_parameter_lossless(void* encoder_raw, int* lossless)
169
0
{
170
0
  auto* encoder = (encoder_struct_opj*) encoder_raw;
171
0
  *lossless = (encoder->parameters.irreversible == 0);
172
0
  return heif_error_ok;
173
0
}
174
175
heif_error opj_set_parameter_logging_level(void* encoder, int logging)
176
0
{
177
0
  return heif_error_ok;
178
0
}
179
180
heif_error opj_get_parameter_logging_level(void* encoder, int* logging)
181
0
{
182
0
  return heif_error_ok;
183
0
}
184
185
const heif_encoder_parameter** opj_list_parameters(void* encoder)
186
0
{
187
0
  return opj_encoder_parameter_ptrs;
188
0
}
189
190
heif_error opj_set_parameter_integer(void* encoder_raw, const char* name, int value)
191
0
{
192
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
193
194
0
  if (strcmp(name, heif_encoder_parameter_name_quality) == 0) {
195
0
    return opj_set_parameter_quality(encoder, value);
196
0
  }
197
198
0
  return heif_error_unsupported_parameter;
199
0
}
200
201
heif_error opj_get_parameter_integer(void* encoder_raw, const char* name, int* value)
202
0
{
203
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
204
205
0
  if (strcmp(name, heif_encoder_parameter_name_quality) == 0) {
206
0
    return opj_get_parameter_quality(encoder, value);
207
0
  }
208
209
0
  return heif_error_ok;
210
0
}
211
212
heif_error opj_set_parameter_boolean(void* encoder, const char* name, int value)
213
0
{
214
0
  return heif_error_ok;
215
0
}
216
217
heif_error opj_get_parameter_boolean(void* encoder, const char* name, int* value)
218
0
{
219
0
  return heif_error_ok;
220
0
}
221
222
heif_error opj_set_parameter_string(void* encoder_raw, const char* name, const char* value)
223
0
{
224
0
  auto* encoder = (encoder_struct_opj*) encoder_raw;
225
226
0
  if (strcmp(name, kParam_chroma) == 0) {
227
0
    if (strcmp(value, "420") == 0) {
228
0
      encoder->chroma = heif_chroma_420;
229
0
      return heif_error_ok;
230
0
    }
231
0
    else if (strcmp(value, "422") == 0) {
232
0
      encoder->chroma = heif_chroma_422;
233
0
      return heif_error_ok;
234
0
    }
235
0
    else if (strcmp(value, "444") == 0) {
236
0
      encoder->chroma = heif_chroma_444;
237
0
      return heif_error_ok;
238
0
    }
239
0
    else {
240
0
      return heif_error_invalid_parameter_value;
241
0
    }
242
0
  }
243
244
0
  return heif_error_unsupported_parameter;
245
0
}
246
247
static void save_strcpy(char* dst, int dst_size, const char* src)
248
0
{
249
0
  strncpy(dst, src, dst_size - 1);
250
0
  dst[dst_size - 1] = 0;
251
0
}
252
253
heif_error opj_get_parameter_string(void* encoder_raw, const char* name, char* value, int value_size)
254
0
{
255
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
256
257
0
  if (strcmp(name, kParam_chroma) == 0) {
258
0
    switch (encoder->chroma) {
259
0
      case heif_chroma_420:
260
0
        save_strcpy(value, value_size, "420");
261
0
        break;
262
0
      case heif_chroma_422:
263
0
        save_strcpy(value, value_size, "422");
264
0
        break;
265
0
      case heif_chroma_444:
266
0
        save_strcpy(value, value_size, "444");
267
0
        break;
268
0
      case heif_chroma_undefined:
269
0
        save_strcpy(value, value_size, "undefined");
270
0
        break;
271
0
      default:
272
0
        assert(false);
273
0
        return heif_error_invalid_parameter_value;
274
0
      }
275
0
      return heif_error_ok;
276
0
  }
277
278
0
  return heif_error_unsupported_parameter;
279
0
}
280
281
282
static void opj_set_default_parameters(void* encoder)
283
0
{
284
0
  for (const heif_encoder_parameter** p = opj_encoder_parameter_ptrs; *p; p++) {
285
0
    const heif_encoder_parameter* param = *p;
286
287
0
    if (param->has_default) {
288
0
      switch (param->type) {
289
0
        case heif_encoder_parameter_type_integer:
290
0
          opj_set_parameter_integer(encoder, param->name, param->integer.default_value);
291
0
          break;
292
0
        case heif_encoder_parameter_type_boolean:
293
0
          opj_set_parameter_boolean(encoder, param->name, param->boolean.default_value);
294
0
          break;
295
0
        case heif_encoder_parameter_type_string:
296
0
          opj_set_parameter_string(encoder, param->name, param->string.default_value);
297
0
          break;
298
0
      }
299
0
    }
300
0
  }
301
0
}
302
303
304
void opj_query_input_colorspace(heif_colorspace* inout_colorspace, heif_chroma* inout_chroma)
305
0
{
306
  // Replace the input colorspace/chroma with the one that is supported by the encoder and that
307
  // comes as close to the input colorspace/chroma as possible.
308
309
0
  if (*inout_colorspace == heif_colorspace_monochrome) {
310
0
    *inout_colorspace = heif_colorspace_monochrome;
311
0
    *inout_chroma = heif_chroma_monochrome;
312
0
  }
313
0
  else {
314
0
    *inout_colorspace = heif_colorspace_YCbCr;
315
0
    *inout_chroma = heif_chroma_444;
316
0
  }
317
0
}
318
319
void opj_query_input_colorspace2(void* encoder_raw, heif_colorspace* inout_colorspace, heif_chroma* inout_chroma)
320
0
{
321
0
  auto* encoder = (struct encoder_struct_opj*) encoder_raw;
322
323
0
  if (*inout_colorspace == heif_colorspace_monochrome) {
324
0
    *inout_colorspace = heif_colorspace_monochrome;
325
0
    *inout_chroma = heif_chroma_monochrome;
326
0
  }
327
0
  else {
328
0
    *inout_colorspace = heif_colorspace_YCbCr;
329
330
0
    if (encoder->chroma != heif_chroma_undefined) {
331
0
      *inout_chroma = encoder->chroma;
332
0
    }
333
0
    else {
334
0
      *inout_chroma = heif_chroma_444;
335
0
    }
336
0
  }
337
0
}
338
339
340
// OpenJPEG will encode a portion of the image and then call this function
341
// @param src_data_raw - Newly encoded bytes provided by OpenJPEG
342
// @param nb_bytes - The number of bytes or size of src_data_raw
343
// @param encoder_raw - Out the new
344
// @return - The number of bytes successfully transferred
345
static OPJ_SIZE_T opj_write_from_buffer(void* src_data_raw, OPJ_SIZE_T nb_bytes, void* encoder_raw)
346
0
{
347
0
  uint8_t* src_data = (uint8_t*) src_data_raw;
348
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
349
350
0
  for (size_t i = 0; i < nb_bytes; i++) {
351
0
    encoder->codestream.push_back(src_data[i]);
352
0
  }
353
354
0
  return nb_bytes;
355
0
}
356
357
static void opj_close_from_buffer(void* p_user_data)
358
0
{
359
0
}
360
361
362
// The codestream is defined in ISO/IEC 15444-1. It contains the
363
// compressed image pixel data and very basic metadata. 
364
// @param data - Uncompressed image pixel data
365
// @param encoder - The function will output codestream in encoder->codestream
366
static heif_error generate_codestream(opj_image_t* image, encoder_struct_opj* encoder)
367
0
{
368
0
  heif_error error;
369
0
  OPJ_BOOL success;
370
371
0
  encoder->parameters.cp_disto_alloc = 1;
372
0
  encoder->parameters.tcp_numlayers = 1;
373
0
  if (encoder->parameters.irreversible == 0) {
374
    // Lossless: the reversible wavelet alone is not sufficient, the rate allocation must not
375
    // truncate the codestream either. A rate of 0 means "no rate limit" in OpenJPEG.
376
0
    encoder->parameters.tcp_rates[0] = 0;
377
0
  }
378
0
  else {
379
0
    encoder->parameters.tcp_rates[0] = (float)(1 + (100 - encoder->quality)/2);
380
0
  }
381
382
#if 0
383
  //Insert a human readable comment into the codestream
384
  if (parameters.cp_comment == NULL) {
385
    char buf[80];
386
#ifdef _WIN32
387
    sprintf_s(buf, 80, "Created by OpenJPEG version %s", opj_version());
388
#else
389
    snprintf(buf, 80, "Created by OpenJPEG version %s", opj_version());
390
#endif
391
    parameters.cp_comment = strdup(buf);
392
  }
393
#endif
394
395
  //OPJ_CODEC_J2K - Only generate the codestream
396
  //OPJ_CODEC_JP2 - Generate the entire jp2 file (which contains a codestream)
397
0
  OPJ_CODEC_FORMAT codec_format = OPJ_CODEC_J2K;
398
0
  opj_codec_t* codec = opj_create_compress(codec_format);
399
0
  success = opj_setup_encoder(codec, &(encoder->parameters), image);
400
0
  if (!success) {
401
0
    opj_destroy_codec(codec);
402
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed to setup OpenJPEG encoder"};
403
0
    return error;
404
0
  }
405
406
407
  //Create Stream
408
0
  size_t bufferSize = 64 * 1024; // 64k
409
0
  opj_stream_t* stream = opj_stream_create(bufferSize, false /* read only mode */);
410
0
  if (stream == NULL) {
411
0
    opj_destroy_codec(codec);
412
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed to create opj_stream_t"};
413
0
    return error;
414
0
  }
415
416
417
  // When OpenJPEG encodes the image, it will pass the 'encoder' into the write function
418
0
  opj_stream_set_user_data(stream, encoder, opj_close_from_buffer);
419
420
  // Tell OpenJPEG how and where to write the output data
421
0
  opj_stream_set_write_function(stream, (opj_stream_write_fn) opj_write_from_buffer);
422
423
  // TODO: should we use this function?
424
  // opj_stream_set_user_data_length(stream, 0);
425
426
427
428
0
  success = opj_start_compress(codec, image, stream);
429
0
  if (!success) {
430
0
    opj_stream_destroy(stream);
431
0
    opj_destroy_codec(codec);
432
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed opj_start_compress()"};
433
0
    return error;
434
0
  }
435
436
0
  success = opj_encode(codec, stream);
437
0
  if (!success) {
438
0
    opj_stream_destroy(stream);
439
0
    opj_destroy_codec(codec);
440
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed opj_encode()"};
441
0
    return error;
442
0
  }
443
444
0
  success = opj_end_compress(codec, stream);
445
0
  if (!success) {
446
0
    opj_stream_destroy(stream);
447
0
    opj_destroy_codec(codec);
448
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed opj_end_compress()"};
449
0
    return error;
450
0
  }
451
452
0
  opj_stream_destroy(stream);
453
0
  opj_destroy_codec(codec);
454
455
0
  return heif_error_ok;
456
0
}
457
458
459
heif_error opj_encode_image(void* encoder_raw, const heif_image* image, heif_image_input_class image_class)
460
0
{
461
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
462
0
  heif_error err;
463
464
0
  heif_chroma chroma = heif_image_get_chroma_format(image);
465
0
  heif_colorspace colorspace = heif_image_get_colorspace(image);
466
467
0
  int width = heif_image_get_primary_width(image);
468
0
  int height = heif_image_get_primary_height(image);
469
470
0
  std::vector<heif_channel> channels;
471
0
  OPJ_COLOR_SPACE opj_colorspace;
472
473
0
  switch (colorspace) {
474
0
    case heif_colorspace_YCbCr:
475
0
      channels = {heif_channel_Y, heif_channel_Cb, heif_channel_Cr};
476
0
      opj_colorspace = OPJ_CLRSPC_SYCC;
477
0
      break;
478
0
    case heif_colorspace_RGB:
479
0
      channels = {heif_channel_R, heif_channel_G, heif_channel_B};
480
0
      opj_colorspace = OPJ_CLRSPC_SRGB;
481
0
      break;
482
0
    case heif_colorspace_monochrome:
483
0
      channels = {heif_channel_Y};
484
0
      opj_colorspace = OPJ_CLRSPC_GRAY;
485
0
      break;
486
0
    default:
487
0
      assert(false);
488
0
      return {heif_error_Encoding_error, heif_suberror_Unspecified, "OpenJPEG encoder plugin received image with invalid colorspace."};
489
0
  }
490
491
0
  int band_count = (int) channels.size();
492
493
0
  opj_image_cmptparm_t component_params[4];
494
0
  memset(&component_params, 0, band_count * sizeof(opj_image_cmptparm_t));
495
496
0
  for (int comp = 0; comp < band_count; comp++) {
497
498
0
    int bpp = heif_image_get_bits_per_pixel_range(image, channels[comp]);
499
500
0
    int sub_dx = 1, sub_dy = 1;
501
0
    switch (chroma) {
502
0
      case heif_chroma_420:
503
0
        sub_dx = 2;
504
0
        sub_dy = 2;
505
0
        break;
506
0
      case heif_chroma_422:
507
0
        sub_dx = 2;
508
0
        sub_dy = 1;
509
0
        break;
510
0
      default:
511
0
        break;
512
0
    }
513
514
0
    component_params[comp].prec = bpp;
515
0
    component_params[comp].sgnd = 0;
516
0
    component_params[comp].dx = comp == 0 ? 1 : sub_dx;
517
0
    component_params[comp].dy = comp == 0 ? 1 : sub_dy;
518
0
    component_params[comp].w = comp == 0 ? width : (width + sub_dx / 2) / sub_dx;
519
0
    component_params[comp].h = comp == 0 ? height : (height + sub_dy / 2) / sub_dy;
520
0
  }
521
522
0
  opj_image_t* opj_image = opj_image_create(band_count, &component_params[0], opj_colorspace);
523
0
  if (image == nullptr) {
524
    // Failed to create image
525
0
    err = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed create OpenJPEG image"};
526
0
    return err;
527
0
  }
528
529
0
  opj_image->x0 = 0;
530
0
  opj_image->y0 = 0;
531
0
  opj_image->x1 = width;
532
0
  opj_image->y1 = height;
533
534
0
  for (int comp = 0; comp < band_count; comp++) {
535
0
    int stride;
536
0
    const uint8_t* p = heif_image_get_plane_readonly(image, channels[comp], &stride);
537
0
    int bpp = heif_image_get_bits_per_pixel(image, channels[comp]);
538
539
0
    int cwidth = component_params[comp].w;
540
0
    int cheight = component_params[comp].h;
541
542
    // Note: obj_image data is 32bit integer
543
544
0
    if (bpp <= 8) {
545
0
      for (int y = 0; y < cheight; y++) {
546
0
        for (int x = 0; x < cwidth; x++) {
547
0
          opj_image->comps[comp].data[y * cwidth + x] = p[y * stride + x];
548
0
        }
549
0
      }
550
0
    }
551
0
    else {
552
0
      const uint16_t* p16 = (const uint16_t*)p;
553
554
0
      for (int y = 0; y < cheight; y++) {
555
0
        for (int x = 0; x < cwidth; x++) {
556
0
          opj_image->comps[comp].data[y * cwidth + x] = p16[y * stride/2 + x];
557
0
        }
558
0
      }
559
0
    }
560
0
  }
561
562
0
  encoder->data_read = false;
563
0
  encoder->codestream.clear(); //Fixes issue when encoding multiple images and old data persists.
564
565
  //Encodes the image into a 'codestream' which is stored in the 'encoder' variable
566
0
  err = generate_codestream(opj_image, encoder);
567
568
0
  opj_image_destroy(opj_image);
569
570
0
  return err;
571
0
}
572
573
heif_error opj_get_compressed_data(void* encoder_raw, uint8_t** data, int* size, enum heif_encoded_data_type* type)
574
0
{
575
  // Get a packet of decoded data. The data format depends on the codec.
576
577
0
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
578
579
0
  if (encoder->data_read) {
580
0
    *size = 0;
581
0
    *data = nullptr;
582
0
  }
583
0
  else {
584
0
    *size = (int) encoder->codestream.size();
585
0
    *data = encoder->codestream.data();
586
0
    encoder->data_read = true;
587
0
  }
588
589
0
  return heif_error_ok;
590
0
}
591
592
void opj_query_encoded_size(void* encoder, uint32_t input_width, uint32_t input_height, uint32_t* encoded_width, uint32_t* encoded_height)
593
0
{
594
  // --- version 3 ---
595
596
  // The encoded image size may be different from the input frame size, e.g. because
597
  // of required rounding, or a required minimum size. Use this function to return
598
  // the encoded size for a given input image size.
599
  // You may set this to NULL if no padding is required for any image size.
600
601
0
  *encoded_width = input_width;
602
0
  *encoded_height = input_height;
603
0
}
604
605
606
heif_error opj_start_sequence_encoding(void* encoder, const heif_image* image,
607
                                       enum heif_image_input_class image_class,
608
                                       uint32_t framerate_num, uint32_t framerate_denom,
609
                                       const heif_sequence_encoding_options* options)
610
0
{
611
0
  return heif_error_ok;
612
0
}
613
614
heif_error opj_encode_sequence_frame(void* encoder, const heif_image* image, uintptr_t frame_nr)
615
0
{
616
0
  return opj_encode_image(encoder, image, heif_image_input_class_normal);
617
0
}
618
619
heif_error opj_end_sequence_encoding(void* encoder)
620
0
{
621
0
  return heif_error_ok;
622
0
}
623
624
heif_error opj_get_compressed_data2(void* encoder, uint8_t** data, int* size,
625
                                    uintptr_t* frame_nr,
626
                                    int* is_keyframe, int* more_frame_packets)
627
0
{
628
0
  heif_error err = opj_get_compressed_data(encoder, data, size, nullptr);
629
630
0
  if (is_keyframe) {
631
0
    *is_keyframe = true;
632
0
  }
633
634
0
  if (more_frame_packets) {
635
0
    *more_frame_packets = true;
636
0
  }
637
638
0
  return err;
639
0
}
640
641
static const heif_encoder_plugin encoder_plugin_openjpeg{
642
    /* plugin_api_version */ 4,
643
    /* compression_format */ heif_compression_JPEG2000,
644
    /* id_name */ "openjpeg",
645
    /* priority */ OPJ_PLUGIN_PRIORITY,
646
    /* supports_lossy_compression */ false,
647
    /* supports_lossless_compression */ true,
648
    /* get_plugin_name */ opj_plugin_name,
649
    /* init_plugin */ opj_init_plugin,
650
    /* cleanup_plugin */ opj_cleanup_plugin,
651
    /* new_encoder */ opj_new_encoder,
652
    /* free_encoder */ opj_free_encoder,
653
    /* set_parameter_quality */ opj_set_parameter_quality,
654
    /* get_parameter_quality */ opj_get_parameter_quality,
655
    /* set_parameter_lossless */ opj_set_parameter_lossless,
656
    /* get_parameter_lossless */ opj_get_parameter_lossless,
657
    /* set_parameter_logging_level */ opj_set_parameter_logging_level,
658
    /* get_parameter_logging_level */ opj_get_parameter_logging_level,
659
    /* list_parameters */ opj_list_parameters,
660
    /* set_parameter_integer */ opj_set_parameter_integer,
661
    /* get_parameter_integer */ opj_get_parameter_integer,
662
    /* set_parameter_boolean */ opj_set_parameter_boolean,
663
    /* get_parameter_boolean */ opj_get_parameter_boolean,
664
    /* set_parameter_string */ opj_set_parameter_string,
665
    /* get_parameter_string */ opj_get_parameter_string,
666
    /* query_input_colorspace */ opj_query_input_colorspace,
667
    /* encode_image */ opj_encode_image,
668
    /* get_compressed_data */ opj_get_compressed_data,
669
    /* query_input_colorspace (v2) */ opj_query_input_colorspace2,
670
    /* query_encoded_size (v3) */ opj_query_encoded_size,
671
    /* minimum_required_libheif_version */ LIBHEIF_MAKE_VERSION(1,21,0),
672
    /* start_sequence_encoding (v4) */ opj_start_sequence_encoding,
673
    /* encode_sequence_frame (v4) */ opj_encode_sequence_frame,
674
    /* end_sequence_encoding (v4) */ opj_end_sequence_encoding,
675
    /* get_compressed_data2 (v4) */ opj_get_compressed_data2,
676
    /* does_indicate_keyframes (v4) */ 1
677
};
678
679
const heif_encoder_plugin* get_encoder_plugin_openjpeg()
680
254
{
681
254
  return &encoder_plugin_openjpeg;
682
254
}
683
684
685
#if PLUGIN_OPENJPEG_ENCODER
686
heif_plugin_info plugin_info {
687
  1,
688
  heif_plugin_type_encoder,
689
  &encoder_plugin_openjpeg
690
};
691
#endif