Coverage Report

Created: 2026-06-15 06:24

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
2
{
95
2
  heif_encoder_parameter* p = opj_encoder_params;
96
2
  const heif_encoder_parameter** d = opj_encoder_parameter_ptrs;
97
2
  int i = 0;
98
99
2
  assert(i < MAX_NPARAMETERS);
100
2
  p->version = 2;
101
2
  p->name = kParam_chroma;
102
2
  p->type = heif_encoder_parameter_type_string;
103
  //p->string.default_value = "420";
104
2
  p->has_default = false;
105
2
  p->string.valid_values = kParam_chroma_valid_values;
106
2
  d[i++] = p++;
107
108
2
  d[i++] = nullptr;
109
2
}
110
111
void opj_init_plugin()
112
2
{
113
2
  opj_init_parameters();
114
2
}
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
253
{
124
253
  encoder_struct_opj* encoder = new encoder_struct_opj();
125
253
  *encoder_out = encoder;
126
127
253
  opj_set_default_parameters(encoder);
128
253
  opj_set_default_encoder_parameters(&(encoder->parameters));
129
130
253
  return heif_error_ok;
131
253
}
132
133
void opj_free_encoder(void* encoder_raw)
134
253
{
135
253
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
136
253
  delete encoder;
137
253
}
138
139
heif_error opj_set_parameter_quality(void* encoder_raw, int quality)
140
253
{
141
253
  auto* encoder = (encoder_struct_opj*) encoder_raw;
142
143
253
  if (quality < 0 || quality > 100) {
144
0
    return heif_error_invalid_parameter_value;
145
0
  }
146
147
253
  encoder->quality = quality;
148
149
253
  return heif_error_ok;
150
253
}
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
253
{
163
253
  auto* encoder = (encoder_struct_opj*) encoder_raw;
164
253
  encoder->parameters.irreversible = lossless ? 0 : 1;
165
253
  return heif_error_ok;
166
253
}
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
253
{
284
506
  for (const heif_encoder_parameter** p = opj_encoder_parameter_ptrs; *p; p++) {
285
253
    const heif_encoder_parameter* param = *p;
286
287
253
    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
253
  }
301
253
}
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
246
{
321
246
  auto* encoder = (struct encoder_struct_opj*) encoder_raw;
322
323
246
  if (*inout_colorspace == heif_colorspace_monochrome) {
324
0
    *inout_colorspace = heif_colorspace_monochrome;
325
0
    *inout_chroma = heif_chroma_monochrome;
326
0
  }
327
246
  else {
328
246
    *inout_colorspace = heif_colorspace_YCbCr;
329
330
246
    if (encoder->chroma != heif_chroma_undefined) {
331
0
      *inout_chroma = encoder->chroma;
332
0
    }
333
246
    else {
334
246
      *inout_chroma = heif_chroma_444;
335
246
    }
336
246
  }
337
246
}
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
244
{
347
244
  uint8_t* src_data = (uint8_t*) src_data_raw;
348
244
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
349
350
52.4k
  for (size_t i = 0; i < nb_bytes; i++) {
351
52.1k
    encoder->codestream.push_back(src_data[i]);
352
52.1k
  }
353
354
244
  return nb_bytes;
355
244
}
356
357
static void opj_close_from_buffer(void* p_user_data)
358
246
{
359
246
}
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
246
{
368
246
  heif_error error;
369
246
  OPJ_BOOL success;
370
371
246
  encoder->parameters.cp_disto_alloc = 1;
372
246
  encoder->parameters.tcp_numlayers = 1;
373
246
  encoder->parameters.tcp_rates[0] = (float)(1 + (100 - encoder->quality)/2);
374
375
#if 0
376
  //Insert a human readable comment into the codestream
377
  if (parameters.cp_comment == NULL) {
378
    char buf[80];
379
#ifdef _WIN32
380
    sprintf_s(buf, 80, "Created by OpenJPEG version %s", opj_version());
381
#else
382
    snprintf(buf, 80, "Created by OpenJPEG version %s", opj_version());
383
#endif
384
    parameters.cp_comment = strdup(buf);
385
  }
386
#endif
387
388
  //OPJ_CODEC_J2K - Only generate the codestream
389
  //OPJ_CODEC_JP2 - Generate the entire jp2 file (which contains a codestream)
390
246
  OPJ_CODEC_FORMAT codec_format = OPJ_CODEC_J2K;
391
246
  opj_codec_t* codec = opj_create_compress(codec_format);
392
246
  success = opj_setup_encoder(codec, &(encoder->parameters), image);
393
246
  if (!success) {
394
0
    opj_destroy_codec(codec);
395
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed to setup OpenJPEG encoder"};
396
0
    return error;
397
0
  }
398
399
400
  //Create Stream
401
246
  size_t bufferSize = 64 * 1024; // 64k
402
246
  opj_stream_t* stream = opj_stream_create(bufferSize, false /* read only mode */);
403
246
  if (stream == NULL) {
404
0
    opj_destroy_codec(codec);
405
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed to create opj_stream_t"};
406
0
    return error;
407
0
  }
408
409
410
  // When OpenJPEG encodes the image, it will pass the 'encoder' into the write function
411
246
  opj_stream_set_user_data(stream, encoder, opj_close_from_buffer);
412
413
  // Tell OpenJPEG how and where to write the output data
414
246
  opj_stream_set_write_function(stream, (opj_stream_write_fn) opj_write_from_buffer);
415
416
  // TODO: should we use this function?
417
  // opj_stream_set_user_data_length(stream, 0);
418
419
420
421
246
  success = opj_start_compress(codec, image, stream);
422
246
  if (!success) {
423
2
    opj_stream_destroy(stream);
424
2
    opj_destroy_codec(codec);
425
2
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed opj_start_compress()"};
426
2
    return error;
427
2
  }
428
429
244
  success = opj_encode(codec, stream);
430
244
  if (!success) {
431
0
    opj_stream_destroy(stream);
432
0
    opj_destroy_codec(codec);
433
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed opj_encode()"};
434
0
    return error;
435
0
  }
436
437
244
  success = opj_end_compress(codec, stream);
438
244
  if (!success) {
439
0
    opj_stream_destroy(stream);
440
0
    opj_destroy_codec(codec);
441
0
    error = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed opj_end_compress()"};
442
0
    return error;
443
0
  }
444
445
244
  opj_stream_destroy(stream);
446
244
  opj_destroy_codec(codec);
447
448
244
  return heif_error_ok;
449
244
}
450
451
452
heif_error opj_encode_image(void* encoder_raw, const heif_image* image, heif_image_input_class image_class)
453
246
{
454
246
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
455
246
  heif_error err;
456
457
246
  heif_chroma chroma = heif_image_get_chroma_format(image);
458
246
  heif_colorspace colorspace = heif_image_get_colorspace(image);
459
460
246
  int width = heif_image_get_primary_width(image);
461
246
  int height = heif_image_get_primary_height(image);
462
463
246
  std::vector<heif_channel> channels;
464
246
  OPJ_COLOR_SPACE opj_colorspace;
465
466
246
  switch (colorspace) {
467
246
    case heif_colorspace_YCbCr:
468
246
      channels = {heif_channel_Y, heif_channel_Cb, heif_channel_Cr};
469
246
      opj_colorspace = OPJ_CLRSPC_SYCC;
470
246
      break;
471
0
    case heif_colorspace_RGB:
472
0
      channels = {heif_channel_R, heif_channel_G, heif_channel_B};
473
0
      opj_colorspace = OPJ_CLRSPC_SRGB;
474
0
      break;
475
0
    case heif_colorspace_monochrome:
476
0
      channels = {heif_channel_Y};
477
0
      opj_colorspace = OPJ_CLRSPC_GRAY;
478
0
      break;
479
0
    default:
480
0
      assert(false);
481
0
      return {heif_error_Encoding_error, heif_suberror_Unspecified, "OpenJPEG encoder plugin received image with invalid colorspace."};
482
246
  }
483
484
246
  int band_count = (int) channels.size();
485
486
246
  opj_image_cmptparm_t component_params[4];
487
246
  memset(&component_params, 0, band_count * sizeof(opj_image_cmptparm_t));
488
489
984
  for (int comp = 0; comp < band_count; comp++) {
490
491
738
    int bpp = heif_image_get_bits_per_pixel_range(image, channels[comp]);
492
493
738
    int sub_dx = 1, sub_dy = 1;
494
738
    switch (chroma) {
495
0
      case heif_chroma_420:
496
0
        sub_dx = 2;
497
0
        sub_dy = 2;
498
0
        break;
499
0
      case heif_chroma_422:
500
0
        sub_dx = 2;
501
0
        sub_dy = 1;
502
0
        break;
503
738
      default:
504
738
        break;
505
738
    }
506
507
738
    component_params[comp].prec = bpp;
508
738
    component_params[comp].sgnd = 0;
509
738
    component_params[comp].dx = comp == 0 ? 1 : sub_dx;
510
738
    component_params[comp].dy = comp == 0 ? 1 : sub_dy;
511
738
    component_params[comp].w = comp == 0 ? width : (width + sub_dx / 2) / sub_dx;
512
738
    component_params[comp].h = comp == 0 ? height : (height + sub_dy / 2) / sub_dy;
513
738
  }
514
515
246
  opj_image_t* opj_image = opj_image_create(band_count, &component_params[0], opj_colorspace);
516
246
  if (image == nullptr) {
517
    // Failed to create image
518
0
    err = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed create OpenJPEG image"};
519
0
    return err;
520
0
  }
521
522
246
  opj_image->x0 = 0;
523
246
  opj_image->y0 = 0;
524
246
  opj_image->x1 = width;
525
246
  opj_image->y1 = height;
526
527
984
  for (int comp = 0; comp < band_count; comp++) {
528
738
    int stride;
529
738
    const uint8_t* p = heif_image_get_plane_readonly(image, channels[comp], &stride);
530
738
    int bpp = heif_image_get_bits_per_pixel(image, channels[comp]);
531
532
738
    int cwidth = component_params[comp].w;
533
738
    int cheight = component_params[comp].h;
534
535
    // Note: obj_image data is 32bit integer
536
537
738
    if (bpp <= 8) {
538
110k
      for (int y = 0; y < cheight; y++) {
539
16.9M
        for (int x = 0; x < cwidth; x++) {
540
16.8M
          opj_image->comps[comp].data[y * cwidth + x] = p[y * stride + x];
541
16.8M
        }
542
109k
      }
543
738
    }
544
0
    else {
545
0
      const uint16_t* p16 = (const uint16_t*)p;
546
547
0
      for (int y = 0; y < cheight; y++) {
548
0
        for (int x = 0; x < cwidth; x++) {
549
0
          opj_image->comps[comp].data[y * cwidth + x] = p16[y * stride/2 + x];
550
0
        }
551
0
      }
552
0
    }
553
738
  }
554
555
246
  encoder->data_read = false;
556
246
  encoder->codestream.clear(); //Fixes issue when encoding multiple images and old data persists.
557
558
  //Encodes the image into a 'codestream' which is stored in the 'encoder' variable
559
246
  err = generate_codestream(opj_image, encoder);
560
561
246
  opj_image_destroy(opj_image);
562
563
246
  return err;
564
246
}
565
566
heif_error opj_get_compressed_data(void* encoder_raw, uint8_t** data, int* size, enum heif_encoded_data_type* type)
567
488
{
568
  // Get a packet of decoded data. The data format depends on the codec.
569
570
488
  encoder_struct_opj* encoder = (encoder_struct_opj*) encoder_raw;
571
572
488
  if (encoder->data_read) {
573
244
    *size = 0;
574
244
    *data = nullptr;
575
244
  }
576
244
  else {
577
244
    *size = (int) encoder->codestream.size();
578
244
    *data = encoder->codestream.data();
579
244
    encoder->data_read = true;
580
244
  }
581
582
488
  return heif_error_ok;
583
488
}
584
585
void opj_query_encoded_size(void* encoder, uint32_t input_width, uint32_t input_height, uint32_t* encoded_width, uint32_t* encoded_height)
586
244
{
587
  // --- version 3 ---
588
589
  // The encoded image size may be different from the input frame size, e.g. because
590
  // of required rounding, or a required minimum size. Use this function to return
591
  // the encoded size for a given input image size.
592
  // You may set this to NULL if no padding is required for any image size.
593
594
244
  *encoded_width = input_width;
595
244
  *encoded_height = input_height;
596
244
}
597
598
599
heif_error opj_start_sequence_encoding(void* encoder, const heif_image* image,
600
                                       enum heif_image_input_class image_class,
601
                                       uint32_t framerate_num, uint32_t framerate_denom,
602
                                       const heif_sequence_encoding_options* options)
603
0
{
604
0
  return heif_error_ok;
605
0
}
606
607
heif_error opj_encode_sequence_frame(void* encoder, const heif_image* image, uintptr_t frame_nr)
608
0
{
609
0
  return opj_encode_image(encoder, image, heif_image_input_class_normal);
610
0
}
611
612
heif_error opj_end_sequence_encoding(void* encoder)
613
0
{
614
0
  return heif_error_ok;
615
0
}
616
617
heif_error opj_get_compressed_data2(void* encoder, uint8_t** data, int* size,
618
                                    uintptr_t* frame_nr,
619
                                    int* is_keyframe, int* more_frame_packets)
620
0
{
621
0
  heif_error err = opj_get_compressed_data(encoder, data, size, nullptr);
622
623
0
  if (is_keyframe) {
624
0
    *is_keyframe = true;
625
0
  }
626
627
0
  if (more_frame_packets) {
628
0
    *more_frame_packets = true;
629
0
  }
630
631
0
  return err;
632
0
}
633
634
static const heif_encoder_plugin encoder_plugin_openjpeg{
635
    /* plugin_api_version */ 4,
636
    /* compression_format */ heif_compression_JPEG2000,
637
    /* id_name */ "openjpeg",
638
    /* priority */ OPJ_PLUGIN_PRIORITY,
639
    /* supports_lossy_compression */ false,
640
    /* supports_lossless_compression */ true,
641
    /* get_plugin_name */ opj_plugin_name,
642
    /* init_plugin */ opj_init_plugin,
643
    /* cleanup_plugin */ opj_cleanup_plugin,
644
    /* new_encoder */ opj_new_encoder,
645
    /* free_encoder */ opj_free_encoder,
646
    /* set_parameter_quality */ opj_set_parameter_quality,
647
    /* get_parameter_quality */ opj_get_parameter_quality,
648
    /* set_parameter_lossless */ opj_set_parameter_lossless,
649
    /* get_parameter_lossless */ opj_get_parameter_lossless,
650
    /* set_parameter_logging_level */ opj_set_parameter_logging_level,
651
    /* get_parameter_logging_level */ opj_get_parameter_logging_level,
652
    /* list_parameters */ opj_list_parameters,
653
    /* set_parameter_integer */ opj_set_parameter_integer,
654
    /* get_parameter_integer */ opj_get_parameter_integer,
655
    /* set_parameter_boolean */ opj_set_parameter_boolean,
656
    /* get_parameter_boolean */ opj_get_parameter_boolean,
657
    /* set_parameter_string */ opj_set_parameter_string,
658
    /* get_parameter_string */ opj_get_parameter_string,
659
    /* query_input_colorspace */ opj_query_input_colorspace,
660
    /* encode_image */ opj_encode_image,
661
    /* get_compressed_data */ opj_get_compressed_data,
662
    /* query_input_colorspace (v2) */ opj_query_input_colorspace2,
663
    /* query_encoded_size (v3) */ opj_query_encoded_size,
664
    /* minimum_required_libheif_version */ LIBHEIF_MAKE_VERSION(1,21,0),
665
    /* start_sequence_encoding (v4) */ opj_start_sequence_encoding,
666
    /* encode_sequence_frame (v4) */ opj_encode_sequence_frame,
667
    /* end_sequence_encoding (v4) */ opj_end_sequence_encoding,
668
    /* get_compressed_data2 (v4) */ opj_get_compressed_data2,
669
    /* does_indicate_keyframes (v4) */ 1
670
};
671
672
const heif_encoder_plugin* get_encoder_plugin_openjpeg()
673
2
{
674
2
  return &encoder_plugin_openjpeg;
675
2
}
676
677
678
#if PLUGIN_OPENJPEG_ENCODER
679
heif_plugin_info plugin_info {
680
  1,
681
  heif_plugin_type_encoder,
682
  &encoder_plugin_openjpeg
683
};
684
#endif