/src/libheif/libheif/plugins/decoder_libde265.cc
Line | Count | Source |
1 | | /* |
2 | | * HEIF codec. |
3 | | * Copyright (c) 2017 Dirk Farin <dirk.farin@gmail.com> |
4 | | * |
5 | | * This file is part of libheif. |
6 | | * |
7 | | * libheif is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libheif is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libheif. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include "libheif/heif.h" |
22 | | #include "libheif/heif_plugin.h" |
23 | | #include "decoder_libde265.h" |
24 | | #include <cassert> |
25 | | #include <memory> |
26 | | #include <cstring> |
27 | | #include <limits> |
28 | | #include <string> |
29 | | |
30 | | #include <libde265/de265.h> |
31 | | |
32 | | |
33 | | |
34 | | struct libde265_decoder |
35 | | { |
36 | | de265_decoder_context* ctx; |
37 | | bool strict_decoding = false; |
38 | | std::string error_message; |
39 | | }; |
40 | | |
41 | | static const char kEmptyString[] = ""; |
42 | | static const char kSuccess[] = "Success"; |
43 | | |
44 | | static const int LIBDE265_PLUGIN_PRIORITY = 100; |
45 | | |
46 | 0 | #define MAX_PLUGIN_NAME_LENGTH 80 |
47 | | |
48 | | static char plugin_name[MAX_PLUGIN_NAME_LENGTH]; |
49 | | static constexpr char version_prefix[] = ", version "; |
50 | | |
51 | | static const char* libde265_plugin_name() |
52 | 0 | { |
53 | 0 | strcpy(plugin_name, "libde265 HEVC decoder"); |
54 | |
|
55 | 0 | const char* libde265_version = de265_get_version(); |
56 | |
|
57 | 0 | if (strlen(plugin_name) + strlen(libde265_version) + (sizeof(version_prefix) - 1) < MAX_PLUGIN_NAME_LENGTH) { |
58 | 0 | strcat(plugin_name, version_prefix); |
59 | 0 | strcat(plugin_name, libde265_version); |
60 | 0 | } |
61 | |
|
62 | 0 | return plugin_name; |
63 | 0 | } |
64 | | |
65 | | |
66 | | static void libde265_init_plugin() |
67 | 22.8k | { |
68 | 22.8k | de265_init(); |
69 | 22.8k | } |
70 | | |
71 | | |
72 | | static void libde265_deinit_plugin() |
73 | 22.8k | { |
74 | 22.8k | de265_free(); |
75 | 22.8k | } |
76 | | |
77 | | |
78 | | static int libde265_does_support_format(heif_compression_format format) |
79 | 39.7k | { |
80 | 39.7k | if (format == heif_compression_HEVC) { |
81 | 27.0k | return LIBDE265_PLUGIN_PRIORITY; |
82 | 27.0k | } |
83 | 12.6k | else { |
84 | 12.6k | return 0; |
85 | 12.6k | } |
86 | 39.7k | } |
87 | | |
88 | | |
89 | | [[maybe_unused]] |
90 | | static int libde265_does_support_format2(const heif_decoder_plugin_compressed_format_description* format) |
91 | 0 | { |
92 | 0 | return libde265_does_support_format(format->format); |
93 | 0 | } |
94 | | |
95 | | |
96 | | |
97 | | static heif_error convert_libde265_image_to_heif_image(libde265_decoder* decoder, |
98 | | const de265_image* de265img, |
99 | | heif_image** image, |
100 | | const heif_security_limits* limits) |
101 | 8.20k | { |
102 | 8.20k | bool is_mono = (de265_get_chroma_format(de265img) == de265_chroma_mono); |
103 | | |
104 | 8.20k | heif_error err; |
105 | 8.20k | err = heif_image_create(de265_get_image_width(de265img, 0), |
106 | 8.20k | de265_get_image_height(de265img, 0), |
107 | 8.20k | is_mono ? heif_colorspace_monochrome : heif_colorspace_YCbCr, |
108 | 8.20k | (heif_chroma) de265_get_chroma_format(de265img), |
109 | 8.20k | image); |
110 | 8.20k | if (err.code) { |
111 | 0 | return err; |
112 | 0 | } |
113 | | |
114 | | // --- transfer data from de265_image to HeifPixelImage |
115 | | |
116 | 8.20k | heif_channel channel2plane[3] = { |
117 | 8.20k | heif_channel_Y, |
118 | 8.20k | heif_channel_Cb, |
119 | 8.20k | heif_channel_Cr |
120 | 8.20k | }; |
121 | | |
122 | | |
123 | 8.20k | int bpp = de265_get_bits_per_pixel(de265img, 0); |
124 | | |
125 | 8.20k | int num_planes = (is_mono ? 1 : 3); |
126 | | |
127 | 30.2k | for (int c = 0; c < num_planes; c++) { |
128 | 22.8k | if (de265_get_bits_per_pixel(de265img, c) != bpp) { |
129 | 731 | heif_image_release(*image); |
130 | 731 | err = {heif_error_Unsupported_feature, |
131 | 731 | heif_suberror_Unsupported_color_conversion, |
132 | 731 | "Channels with different number of bits per pixel are not supported"}; |
133 | 731 | return err; |
134 | 731 | } |
135 | | |
136 | 22.0k | int stride; |
137 | 22.0k | const uint8_t* data = de265_get_image_plane(de265img, c, &stride); |
138 | | |
139 | 22.0k | int w = de265_get_image_width(de265img, c); |
140 | 22.0k | int h = de265_get_image_height(de265img, c); |
141 | 22.0k | if (w <= 0 || h <= 0) { |
142 | 0 | heif_image_release(*image); |
143 | 0 | err = {heif_error_Decoder_plugin_error, |
144 | 0 | heif_suberror_Invalid_image_size, |
145 | 0 | kEmptyString}; |
146 | 0 | return err; |
147 | 0 | } |
148 | | |
149 | 22.0k | err = heif_image_add_plane_safe(*image, channel2plane[c], w,h, bpp, limits); |
150 | 22.0k | if (err.code) { |
151 | | // copy error message to decoder object because heif_image will be released |
152 | 0 | decoder->error_message = err.message; |
153 | 0 | err.message = decoder->error_message.c_str(); |
154 | |
|
155 | 0 | heif_image_release(*image); |
156 | 0 | return err; |
157 | 0 | } |
158 | | |
159 | 22.0k | size_t dst_stride; |
160 | 22.0k | uint8_t* dst_mem = heif_image_get_plane2(*image, channel2plane[c], &dst_stride); |
161 | | |
162 | 22.0k | int bytes_per_pixel = (bpp + 7) / 8; |
163 | | |
164 | 6.63M | for (int y = 0; y < h; y++) { |
165 | 6.60M | memcpy(dst_mem + y * dst_stride, data + static_cast<size_t>(y) * stride, static_cast<size_t>(w) * bytes_per_pixel); |
166 | 6.60M | } |
167 | 22.0k | } |
168 | | |
169 | | |
170 | 7.47k | return {heif_error_Ok, heif_suberror_Unspecified, kSuccess}; |
171 | 8.20k | } |
172 | | |
173 | | |
174 | | |
175 | | // Create a new decoder context for decoding an image |
176 | | heif_error libde265_new_decoder2(void** dec, const heif_decoder_plugin_options* options) |
177 | 9.07k | { |
178 | 9.07k | libde265_decoder* decoder = new libde265_decoder(); |
179 | 9.07k | heif_error err = {heif_error_Ok, heif_suberror_Unspecified, kSuccess}; |
180 | | |
181 | 9.07k | decoder->ctx = de265_new_decoder(); |
182 | | |
183 | 9.07k | #if LIBDE265_NUMERIC_VERSION >= 0x01010000 |
184 | | // Pass libheif's max_image_size_pixels through to libde265 so the decoder |
185 | | // rejects bitstreams whose SPS declares an image far larger than what the |
186 | | // surrounding HEIF file claims. libheif tightens this limit per-decode to |
187 | | // ispe + one coding-unit margin (see tighten_image_size_limit_for_ispe), |
188 | | // so the padding margin is already baked into the value we see here. |
189 | 9.07k | { |
190 | 18.4E | const heif_security_limits* limits = options->limits ? options->limits : heif_get_global_security_limits(); |
191 | 9.07k | de265_security_limits* de265_limits = de265_get_security_limits(decoder->ctx); |
192 | 9.07k | if (limits->max_image_size_pixels > std::numeric_limits<uint32_t>::max()) { |
193 | 22 | de265_limits->max_image_size_pixels = 0; |
194 | 22 | } |
195 | 9.05k | else { |
196 | 9.05k | de265_limits->max_image_size_pixels = static_cast<uint32_t>(limits->max_image_size_pixels); |
197 | 9.05k | } |
198 | | |
199 | | // libde265 rejects NAL units larger than 16 MiB by default. libheif has already |
200 | | // read the whole item into memory under max_memory_block_size, so use that |
201 | | // limit for the NAL size too. Otherwise, large images (e.g. lossless) that |
202 | | // libheif can write could not be decoded, even with the limits disabled. |
203 | 9.07k | if (limits->max_memory_block_size > std::numeric_limits<uint32_t>::max()) { |
204 | 0 | de265_limits->max_NAL_size_bytes = 0; |
205 | 0 | } |
206 | 9.07k | else { |
207 | 9.07k | de265_limits->max_NAL_size_bytes = static_cast<uint32_t>(limits->max_memory_block_size); |
208 | 9.07k | } |
209 | 9.07k | } |
210 | 9.07k | #endif |
211 | | |
212 | | #if defined(__EMSCRIPTEN__) |
213 | | // Speed up decoding from JavaScript. |
214 | | de265_set_parameter_bool(decoder->ctx, DE265_DECODER_PARAM_DISABLE_DEBLOCKING, 1); |
215 | | de265_set_parameter_bool(decoder->ctx, DE265_DECODER_PARAM_DISABLE_SAO, 1); |
216 | | #else |
217 | 9.07k | int nThreads = (options->num_threads ? options->num_threads : 1); |
218 | | |
219 | | // Worker threads are not supported when running on Emscripten. |
220 | 9.07k | de265_start_worker_threads(decoder->ctx, nThreads); |
221 | 9.07k | #endif |
222 | | |
223 | 9.07k | decoder->strict_decoding = options->strict_decoding; |
224 | | |
225 | 9.07k | *dec = decoder; |
226 | 9.07k | return err; |
227 | 9.07k | } |
228 | | |
229 | | |
230 | | static heif_error libde265_new_decoder(void** dec) |
231 | 0 | { |
232 | 0 | heif_decoder_plugin_options options{}; |
233 | 0 | options.format = heif_compression_HEVC; |
234 | 0 | options.num_threads = 0; |
235 | 0 | options.strict_decoding = false; |
236 | |
|
237 | 0 | return libde265_new_decoder2(dec, &options); |
238 | 0 | } |
239 | | |
240 | | static void libde265_free_decoder(void* decoder_raw) |
241 | 9.07k | { |
242 | 9.07k | libde265_decoder* decoder = (libde265_decoder*) decoder_raw; |
243 | | |
244 | 9.07k | de265_error err = de265_free_decoder(decoder->ctx); |
245 | 9.07k | (void) err; |
246 | | |
247 | 9.07k | delete decoder; |
248 | 9.07k | } |
249 | | |
250 | | |
251 | | void libde265_set_strict_decoding(void* decoder_raw, int flag) |
252 | 0 | { |
253 | 0 | libde265_decoder* decoder = (libde265_decoder*) decoder_raw; |
254 | |
|
255 | 0 | decoder->strict_decoding = flag; |
256 | 0 | } |
257 | | |
258 | | |
259 | | #if LIBDE265_NUMERIC_VERSION >= 0x02000000 |
260 | | |
261 | | static heif_error libde265_v2_push_data(void* decoder_raw, const void* data, size_t size) |
262 | | { |
263 | | libde265_decoder* decoder = (libde265_decoder*)decoder_raw; |
264 | | |
265 | | const uint8_t* cdata = (const uint8_t*)data; |
266 | | |
267 | | size_t ptr=0; |
268 | | while (ptr < size) { |
269 | | if (4 > size - ptr) { |
270 | | return { heif_error_Decoder_plugin_error, |
271 | | heif_suberror_End_of_data, |
272 | | kEmptyString }; |
273 | | } |
274 | | |
275 | | // TODO: the size of the NAL unit length variable is defined in the hvcC header. |
276 | | // We should not assume that it is always 4 bytes. |
277 | | uint32_t nal_size = (uint32_t)((cdata[ptr]<<24) | (cdata[ptr+1]<<16) | (cdata[ptr+2]<<8) | (cdata[ptr+3])); |
278 | | ptr+=4; |
279 | | |
280 | | if (nal_size > size - ptr) { |
281 | | //sstr << "NAL size (" << size32 << ") exceeds available data in file (" |
282 | | //<< data_bytes_left_to_read << ")"; |
283 | | |
284 | | return { heif_error_Decoder_plugin_error, |
285 | | heif_suberror_End_of_data, |
286 | | kEmptyString }; |
287 | | } |
288 | | |
289 | | de265_push_NAL(decoder->ctx, cdata+ptr, nal_size, 0, nullptr); |
290 | | ptr += nal_size; |
291 | | } |
292 | | |
293 | | |
294 | | return { heif_error_Ok, heif_suberror_Unspecified, kSuccess }; |
295 | | } |
296 | | |
297 | | |
298 | | static heif_error libde265_v2_decode_next_image(void* decoder_raw, |
299 | | heif_image** out_img, |
300 | | const heif_security_limits* limits) |
301 | | { |
302 | | libde265_decoder* decoder = (libde265_decoder*)decoder_raw; |
303 | | |
304 | | de265_push_end_of_stream(decoder->ctx); |
305 | | |
306 | | int action = de265_get_action(decoder->ctx, 1); |
307 | | |
308 | | // TODO: read NCLX from h265 bitstream |
309 | | |
310 | | // TODO(farindk): Set "err" if no image was decoded. |
311 | | if (action==de265_action_get_image) { |
312 | | const de265_image* img = de265_get_next_picture(decoder->ctx); |
313 | | if (img) { |
314 | | heif_error err = convert_libde265_image_to_heif_image(decoder, img, |
315 | | out_img, limits); |
316 | | de265_release_picture(img); |
317 | | |
318 | | return err; |
319 | | } |
320 | | } |
321 | | |
322 | | return { heif_error_Decoder_plugin_error, heif_suberror_Unspecified, kEmptyString }; |
323 | | } |
324 | | |
325 | | static heif_error libde265_v2_decode_image(void* decoder_raw, |
326 | | heif_image** out_img) |
327 | | { |
328 | | auto* limits = heif_get_global_security_limits(); |
329 | | return libde265_v2_decode_next_image(decoder_raw, out_img, limits); |
330 | | } |
331 | | #else |
332 | | |
333 | | static heif_error libde265_v1_push_data2(void* decoder_raw, const void* data, size_t size, uintptr_t user_data) |
334 | 9.07k | { |
335 | 9.07k | libde265_decoder* decoder = (libde265_decoder*) decoder_raw; |
336 | | |
337 | 9.07k | const uint8_t* cdata = (const uint8_t*) data; |
338 | | |
339 | 9.07k | size_t ptr = 0; |
340 | 61.6k | while (ptr < size) { |
341 | 52.5k | if (4 > size - ptr) { |
342 | 0 | return { |
343 | 0 | heif_error_Decoder_plugin_error, |
344 | 0 | heif_suberror_End_of_data, |
345 | 0 | kEmptyString |
346 | 0 | }; |
347 | 0 | } |
348 | | |
349 | 52.5k | uint32_t nal_size = static_cast<uint32_t>((cdata[ptr] << 24) | (cdata[ptr + 1] << 16) | (cdata[ptr + 2] << 8) | (cdata[ptr + 3])); |
350 | 52.5k | ptr += 4; |
351 | | |
352 | 52.5k | if (nal_size > size - ptr) { |
353 | 0 | return { |
354 | 0 | heif_error_Decoder_plugin_error, |
355 | 0 | heif_suberror_End_of_data, |
356 | 0 | kEmptyString |
357 | 0 | }; |
358 | 0 | } |
359 | | |
360 | | // de265_push_NAL() takes the length as 'int'. Larger sizes would turn negative, |
361 | | // which libde265 < 1.1.3 does not reject before copying the data. |
362 | 52.5k | if (nal_size > static_cast<uint32_t>(std::numeric_limits<int>::max())) { |
363 | 0 | return { |
364 | 0 | heif_error_Decoder_plugin_error, |
365 | 0 | heif_suberror_Unspecified, |
366 | 0 | "NAL unit size exceeds 2 GB" |
367 | 0 | }; |
368 | 0 | } |
369 | | |
370 | | #if 0 |
371 | | FILE* fh = fopen("data.h265", "a"); |
372 | | fputc(0, fh); |
373 | | fputc(0, fh); |
374 | | fputc(1, fh); |
375 | | fwrite(cdata + ptr, nal_size, 1, fh); |
376 | | fclose(fh); |
377 | | |
378 | | printf("put nal with size %d %x\n", nal_size, *(cdata+ptr)); |
379 | | #endif |
380 | | |
381 | | // The codec hands this opaque pointer back unchanged; it carries an integer, not an address. |
382 | 52.5k | de265_error push_err = de265_push_NAL(decoder->ctx, cdata + ptr, nal_size, 0, (void*)user_data); // NOLINT(performance-no-int-to-ptr) |
383 | 52.5k | if (!de265_isOK(push_err)) { |
384 | 0 | return { |
385 | 0 | heif_error_Decoder_plugin_error, |
386 | 0 | heif_suberror_Unspecified, |
387 | 0 | de265_get_error_text(push_err) |
388 | 0 | }; |
389 | 0 | } |
390 | | |
391 | 52.5k | ptr += nal_size; |
392 | 52.5k | } |
393 | | |
394 | | //de265_push_data(decoder->ctx, data, size, 0, nullptr); |
395 | | |
396 | 9.07k | return {heif_error_Ok, heif_suberror_Unspecified, kSuccess}; |
397 | 9.07k | } |
398 | | |
399 | | static heif_error libde265_v1_push_data(void* decoder_raw, const void* data, size_t size) |
400 | 0 | { |
401 | 0 | return libde265_v1_push_data2(decoder_raw, data, size, 0); |
402 | 0 | } |
403 | | |
404 | | static heif_error libde265_flush_data(void* decoder_raw) |
405 | 9.07k | { |
406 | 9.07k | libde265_decoder* decoder = (libde265_decoder*) decoder_raw; |
407 | | |
408 | 9.07k | de265_flush_data(decoder->ctx); |
409 | | |
410 | 9.07k | return heif_error_ok; |
411 | 9.07k | } |
412 | | |
413 | | |
414 | | |
415 | | static heif_error libde265_v1_decode_next_image2(void* decoder_raw, |
416 | | heif_image** out_img, |
417 | | uintptr_t* out_user_data, |
418 | | const heif_security_limits* limits) |
419 | 54.7k | { |
420 | 54.7k | libde265_decoder* decoder = (libde265_decoder*) decoder_raw; |
421 | 54.7k | heif_error err = {heif_error_Ok, heif_suberror_Unspecified, kSuccess}; |
422 | | |
423 | | // TODO(251119) : de265_flush_data(decoder->ctx); |
424 | | |
425 | | // TODO(farindk): Set "err" if no image was decoded. |
426 | 54.7k | int more; |
427 | 54.7k | de265_error decode_err; |
428 | 54.7k | *out_img = nullptr; |
429 | 95.2k | do { |
430 | 95.2k | more = 0; |
431 | 95.2k | decode_err = de265_decode(decoder->ctx, &more); |
432 | 95.2k | if (decode_err != DE265_OK) { |
433 | | // printf("Error decoding: %s (%d)\n", de265_get_error_text(decode_err), decode_err); |
434 | 4.55k | break; |
435 | 4.55k | } |
436 | | |
437 | | // TODO: read NCLX from h265 bitstream |
438 | | |
439 | 90.7k | const de265_image* image = de265_get_next_picture(decoder->ctx); |
440 | 90.7k | if (image) { |
441 | | // TODO(farindk): Should we return the first image instead? |
442 | 8.20k | if (*out_img) { |
443 | 0 | heif_image_release(*out_img); |
444 | 0 | } |
445 | | |
446 | 8.20k | if (out_user_data) { |
447 | 0 | *out_user_data = (uintptr_t)de265_get_image_user_data(image); |
448 | 0 | } |
449 | | |
450 | 8.20k | err = convert_libde265_image_to_heif_image(decoder, image, out_img, limits); |
451 | 8.20k | if (err.code != heif_error_Ok) { |
452 | 731 | return err; |
453 | 731 | } |
454 | | |
455 | 7.47k | heif_color_profile_nclx* nclx = heif_nclx_color_profile_alloc(); |
456 | 7.47k | #if LIBDE265_NUMERIC_VERSION >= 0x01000700 |
457 | 7.47k | HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_color_primaries(nclx, static_cast<uint16_t>(de265_get_image_colour_primaries(image))), |
458 | 7.47k | { |
459 | 7.47k | heif_nclx_color_profile_free(nclx); |
460 | 7.47k | heif_image_release(*out_img); |
461 | 7.47k | *out_img = nullptr; |
462 | 7.47k | }); |
463 | 7.47k | HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_transfer_characteristics(nclx, static_cast<uint16_t>(de265_get_image_transfer_characteristics(image))), |
464 | 7.47k | { |
465 | 7.47k | heif_nclx_color_profile_free(nclx); |
466 | 7.47k | heif_image_release(*out_img); |
467 | 7.47k | *out_img = nullptr; |
468 | 7.47k | }); |
469 | 7.47k | HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_matrix_coefficients(nclx, static_cast<uint16_t>(de265_get_image_matrix_coefficients(image))), |
470 | 7.47k | { |
471 | 7.47k | heif_nclx_color_profile_free(nclx); |
472 | 7.47k | heif_image_release(*out_img); |
473 | 7.47k | *out_img = nullptr; |
474 | 7.47k | }); |
475 | 6.08k | nclx->full_range_flag = (bool) de265_get_image_full_range_flag(image); |
476 | 6.08k | #endif |
477 | 6.08k | heif_image_set_nclx_color_profile(*out_img, nclx); |
478 | 6.08k | heif_nclx_color_profile_free(nclx); |
479 | | |
480 | 6.08k | de265_release_next_picture(decoder->ctx); |
481 | 6.08k | return heif_error_ok; |
482 | 7.47k | } |
483 | 90.7k | } while (more); |
484 | | |
485 | 46.5k | return err; |
486 | 54.7k | } |
487 | | |
488 | | |
489 | | static heif_error libde265_v1_decode_next_image(void* decoder_raw, |
490 | | heif_image** out_img, |
491 | | const heif_security_limits* limits) |
492 | 0 | { |
493 | 0 | return libde265_v1_decode_next_image2(decoder_raw, out_img, nullptr, limits); |
494 | 0 | } |
495 | | |
496 | | static heif_error libde265_v1_decode_image(void* decoder_raw, |
497 | | heif_image** out_img) |
498 | 0 | { |
499 | 0 | auto* limits = heif_get_global_security_limits(); |
500 | 0 | return libde265_v1_decode_next_image(decoder_raw, out_img, limits); |
501 | 0 | } |
502 | | |
503 | | #endif |
504 | | |
505 | | |
506 | | #if LIBDE265_NUMERIC_VERSION >= 0x02000000 |
507 | | |
508 | | static const heif_decoder_plugin decoder_libde265 |
509 | | { |
510 | | 1, |
511 | | libde265_plugin_name, |
512 | | libde265_init_plugin, |
513 | | libde265_deinit_plugin, |
514 | | libde265_does_support_format, |
515 | | libde265_new_decoder, |
516 | | libde265_free_decoder, |
517 | | libde265_v2_push_data, |
518 | | libde265_v2_decode_image, |
519 | | libde265_set_strict_decoding, |
520 | | "libde265", |
521 | | libde265_v2_decode_next_image |
522 | | }; |
523 | | |
524 | | #else |
525 | | |
526 | | static const heif_decoder_plugin decoder_libde265 |
527 | | { |
528 | | 5, |
529 | | libde265_plugin_name, |
530 | | libde265_init_plugin, |
531 | | libde265_deinit_plugin, |
532 | | libde265_does_support_format, |
533 | | libde265_new_decoder, |
534 | | libde265_free_decoder, |
535 | | libde265_v1_push_data, |
536 | | libde265_v1_decode_image, |
537 | | libde265_set_strict_decoding, |
538 | | "libde265", |
539 | | libde265_v1_decode_next_image, |
540 | | /* minimum_required_libheif_version */ LIBHEIF_MAKE_VERSION(1,21,0), |
541 | | libde265_does_support_format2, |
542 | | libde265_new_decoder2, |
543 | | libde265_v1_push_data2, |
544 | | libde265_flush_data, |
545 | | libde265_v1_decode_next_image2 |
546 | | }; |
547 | | |
548 | | #endif |
549 | | |
550 | | const heif_decoder_plugin* get_decoder_plugin_libde265() |
551 | 22.8k | { |
552 | 22.8k | return &decoder_libde265; |
553 | 22.8k | } |
554 | | |
555 | | |
556 | | |
557 | | #if PLUGIN_LIBDE265 |
558 | | heif_plugin_info plugin_info { |
559 | | 1, |
560 | | heif_plugin_type_decoder, |
561 | | &decoder_libde265 |
562 | | }; |
563 | | #endif |