FFmpeg
Loading...
Searching...
No Matches
libjxldec.c
Go to the documentation of this file.
1/*
2 * JPEG XL decoding support via libjxl
3 * Copyright (c) 2021 Leo Izen <leo.izen@gmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg 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 GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * JPEG XL decoder using libjxl
25 */
26
27#include "libavutil/avassert.h"
28#include "libavutil/buffer.h"
29#include "libavutil/common.h"
30#include "libavutil/csp.h"
31#include "libavutil/error.h"
33#include "libavutil/mem.h"
34#include "libavutil/pixdesc.h"
35#include "libavutil/pixfmt.h"
36#include "libavutil/frame.h"
37
38#include "avcodec.h"
39#include "codec_internal.h"
40#include "decode.h"
41#include "exif_internal.h"
42#include "internal.h"
43
44#include <jxl/decode.h>
45#include <jxl/thread_parallel_runner.h>
46#include "libjxl.h"
47
48typedef struct LibJxlDecodeContext {
49 void *runner;
50 JxlDecoder *decoder;
51 JxlBasicInfo basic_info;
52 JxlPixelFormat jxl_pixfmt;
53#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0)
54 JxlBitDepth jxl_bit_depth;
55#endif
56 JxlDecoderStatus events;
65 JxlDecoderStatus jret;
67 size_t exif_pos;
70
72{
74
75 ctx->events = JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE
76 | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME
77 | JXL_DEC_BOX;
78 if (JxlDecoderSubscribeEvents(ctx->decoder, ctx->events) != JXL_DEC_SUCCESS) {
79 av_log(avctx, AV_LOG_ERROR, "Error subscribing to JXL events\n");
80 return AVERROR_EXTERNAL;
81 }
82
83 if (JxlDecoderSetDecompressBoxes(ctx->decoder, JXL_TRUE) != JXL_DEC_SUCCESS) {
84 av_log(avctx, AV_LOG_ERROR, "Error setting compress box mode\n");
85 return AVERROR_EXTERNAL;
86 }
87
88 if (JxlDecoderSetParallelRunner(ctx->decoder, JxlThreadParallelRunner, ctx->runner) != JXL_DEC_SUCCESS) {
89 av_log(avctx, AV_LOG_ERROR, "Failed to set JxlThreadParallelRunner\n");
90 return AVERROR_EXTERNAL;
91 }
92
93 av_buffer_unref(&ctx->exif);
94 memset(&ctx->basic_info, 0, sizeof(JxlBasicInfo));
95 memset(&ctx->jxl_pixfmt, 0, sizeof(JxlPixelFormat));
96 ctx->prev_is_last = 1;
97
98 return 0;
99}
100
102{
104 JxlMemoryManager manager;
105
107 ctx->decoder = JxlDecoderCreate(&manager);
108 if (!ctx->decoder) {
109 av_log(avctx, AV_LOG_ERROR, "Failed to create JxlDecoder\n");
110 return AVERROR_EXTERNAL;
111 }
112
113 ctx->runner = JxlThreadParallelRunnerCreate(&manager, ff_libjxl_get_threadcount(avctx->thread_count));
114 if (!ctx->runner) {
115 av_log(avctx, AV_LOG_ERROR, "Failed to create JxlThreadParallelRunner\n");
116 return AVERROR_EXTERNAL;
117 }
118
119 ctx->avpkt = avctx->internal->in_pkt;
120 ctx->frame = av_frame_alloc();
121 if (!ctx->frame)
122 return AVERROR(ENOMEM);
123
124 return libjxl_init_jxl_decoder(avctx);
125}
126
128{
129 const JxlBasicInfo *basic_info = &ctx->basic_info;
130 JxlPixelFormat *format = &ctx->jxl_pixfmt;
131 format->endianness = JXL_NATIVE_ENDIAN;
132 format->num_channels = basic_info->num_color_channels + (basic_info->alpha_bits > 0);
133#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0)
134 ctx->jxl_bit_depth.bits_per_sample = avctx->bits_per_raw_sample = basic_info->bits_per_sample;
135 ctx->jxl_bit_depth.type = JXL_BIT_DEPTH_FROM_PIXEL_FORMAT;
136 ctx->jxl_bit_depth.exponent_bits_per_sample = basic_info->exponent_bits_per_sample;
137#endif
138 /* Gray */
139 if (basic_info->num_color_channels == 1) {
140 if (basic_info->bits_per_sample <= 8) {
141 format->data_type = JXL_TYPE_UINT8;
142 return basic_info->alpha_bits ? AV_PIX_FMT_YA8 : AV_PIX_FMT_GRAY8;
143 }
144 if (basic_info->exponent_bits_per_sample || basic_info->bits_per_sample > 16) {
145 if (!basic_info->alpha_bits) {
146 format->data_type = JXL_TYPE_FLOAT;
147 return AV_PIX_FMT_GRAYF32;
148 }
149 av_log(avctx, AV_LOG_WARNING, "Downsampling gray+alpha float to 16-bit integer via libjxl\n");
150 }
151 format->data_type = JXL_TYPE_UINT16;
152 return basic_info->alpha_bits ? AV_PIX_FMT_YA16 : AV_PIX_FMT_GRAY16;
153 }
154 /* rgb only */
155 /* libjxl only supports packed RGB and gray output at the moment */
156 if (basic_info->num_color_channels == 3) {
157 if (basic_info->bits_per_sample <= 8) {
158 format->data_type = JXL_TYPE_UINT8;
159 return basic_info->alpha_bits ? AV_PIX_FMT_RGBA : AV_PIX_FMT_RGB24;
160 }
161 if (basic_info->exponent_bits_per_sample || basic_info->bits_per_sample > 16) {
162 format->data_type = JXL_TYPE_FLOAT;
163 return basic_info->alpha_bits ? AV_PIX_FMT_RGBAF32 : AV_PIX_FMT_RGBF32;
164 }
165 format->data_type = JXL_TYPE_UINT16;
166 return basic_info->alpha_bits ? AV_PIX_FMT_RGBA64 : AV_PIX_FMT_RGB48;
167 }
168
169 return AV_PIX_FMT_NONE;
170}
171
172static enum AVColorPrimaries libjxl_get_primaries(void *avctx, const JxlColorEncoding *jxl_color)
173{
175 enum AVColorPrimaries prim;
176
177 /* libjxl populates these double values even if it uses an enum space */
178 desc.prim.r.x = av_d2q(jxl_color->primaries_red_xy[0], 300000);
179 desc.prim.r.y = av_d2q(jxl_color->primaries_red_xy[1], 300000);
180 desc.prim.g.x = av_d2q(jxl_color->primaries_green_xy[0], 300000);
181 desc.prim.g.y = av_d2q(jxl_color->primaries_green_xy[1], 300000);
182 desc.prim.b.x = av_d2q(jxl_color->primaries_blue_xy[0], 300000);
183 desc.prim.b.y = av_d2q(jxl_color->primaries_blue_xy[1], 300000);
184 desc.wp.x = av_d2q(jxl_color->white_point_xy[0], 300000);
185 desc.wp.y = av_d2q(jxl_color->white_point_xy[1], 300000);
186
188 if (prim == AVCOL_PRI_UNSPECIFIED) {
189 /* try D65 with the same primaries */
190 /* BT.709 uses D65 white point */
192 av_log(avctx, AV_LOG_WARNING, "Changing unknown white point to D65\n");
194 }
195
196 return prim;
197}
198
199static enum AVColorTransferCharacteristic libjxl_get_trc(void *avctx, const JxlColorEncoding *jxl_color)
200{
201 switch (jxl_color->transfer_function) {
202 case JXL_TRANSFER_FUNCTION_709: return AVCOL_TRC_BT709;
203 case JXL_TRANSFER_FUNCTION_LINEAR: return AVCOL_TRC_LINEAR;
204 case JXL_TRANSFER_FUNCTION_SRGB: return AVCOL_TRC_IEC61966_2_1;
205 case JXL_TRANSFER_FUNCTION_PQ: return AVCOL_TRC_SMPTE2084;
206 case JXL_TRANSFER_FUNCTION_DCI: return AVCOL_TRC_SMPTE428;
207 case JXL_TRANSFER_FUNCTION_HLG: return AVCOL_TRC_ARIB_STD_B67;
208 case JXL_TRANSFER_FUNCTION_GAMMA:
209 if (jxl_color->gamma > 0.45355 && jxl_color->gamma < 0.45555)
210 return AVCOL_TRC_GAMMA22;
211 else if (jxl_color->gamma > 0.35614 && jxl_color->gamma < 0.35814)
212 return AVCOL_TRC_GAMMA28;
213 else
214 av_log(avctx, AV_LOG_WARNING, "Unsupported gamma transfer: %f\n", jxl_color->gamma);
215 break;
216 default:
217 av_log(avctx, AV_LOG_WARNING, "Unknown transfer function: %d\n", jxl_color->transfer_function);
218 }
219
221}
222
224{
226 size_t icc_len;
227 JxlDecoderStatus jret;
228 /* an ICC profile is present, and we can meaningfully get it,
229 * because the pixel data is not XYB-encoded */
230#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
231 jret = JxlDecoderGetICCProfileSize(ctx->decoder, &ctx->jxl_pixfmt, JXL_COLOR_PROFILE_TARGET_DATA, &icc_len);
232#else
233 jret = JxlDecoderGetICCProfileSize(ctx->decoder, JXL_COLOR_PROFILE_TARGET_DATA, &icc_len);
234#endif
235 if (jret == JXL_DEC_SUCCESS && icc_len > 0) {
236 av_buffer_unref(&ctx->iccp);
237 ctx->iccp = av_buffer_alloc(icc_len);
238 if (!ctx->iccp)
239 return AVERROR(ENOMEM);
240#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
241 jret = JxlDecoderGetColorAsICCProfile(ctx->decoder, &ctx->jxl_pixfmt, JXL_COLOR_PROFILE_TARGET_DATA,
242 ctx->iccp->data, icc_len);
243#else
244 jret = JxlDecoderGetColorAsICCProfile(ctx->decoder, JXL_COLOR_PROFILE_TARGET_DATA, ctx->iccp->data, icc_len);
245#endif
246 if (jret != JXL_DEC_SUCCESS) {
247 av_log(avctx, AV_LOG_WARNING, "Unable to obtain ICC Profile\n");
248 av_buffer_unref(&ctx->iccp);
249 }
250 }
251
252 return 0;
253}
254
255/*
256 * There's generally four cases when it comes to decoding a libjxl image
257 * with regard to color encoding:
258 * (a) There is an embedded ICC profile in the image, and the image is XYB-encoded.
259 * (b) There is an embedded ICC profile in the image, and the image is not XYB-encoded.
260 * (c) There is no embedded ICC profile, and FFmpeg supports the tagged colorspace.
261 * (d) There is no embedded ICC profile, and FFmpeg does not support the tagged colorspace.
262 *
263 * In case (b), we forward the pixel data as is and forward the ICC Profile as-is.
264 * In case (c), we request the pixel data in the space it's tagged as,
265 * and tag the space accordingly.
266 * In case (a), libjxl does not support getting the pixel data in the space described by the ICC
267 * profile, so instead we request the pixel data in BT.2020/PQ as it is the widest
268 * space that FFmpeg supports.
269 * In case (d), we also request wide-gamut pixel data as a fallback since FFmpeg doesn't support
270 * the custom primaries tagged in the space.
271 */
273{
275 JxlDecoderStatus jret;
276 int ret;
277 JxlColorEncoding jxl_color;
278 /* set this flag if we need to fall back on wide gamut */
279 int fallback = 0;
280
281#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
282 jret = JxlDecoderGetColorAsEncodedProfile(ctx->decoder, NULL, JXL_COLOR_PROFILE_TARGET_ORIGINAL, &jxl_color);
283#else
284 jret = JxlDecoderGetColorAsEncodedProfile(ctx->decoder, JXL_COLOR_PROFILE_TARGET_ORIGINAL, &jxl_color);
285#endif
286 if (jret == JXL_DEC_SUCCESS) {
287 /* enum values describe the colors of this image */
288 jret = JxlDecoderSetPreferredColorProfile(ctx->decoder, &jxl_color);
289 if (jret == JXL_DEC_SUCCESS)
290#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
291 jret = JxlDecoderGetColorAsEncodedProfile(ctx->decoder, &ctx->jxl_pixfmt,
292 JXL_COLOR_PROFILE_TARGET_DATA, &jxl_color);
293#else
294 jret = JxlDecoderGetColorAsEncodedProfile(ctx->decoder, JXL_COLOR_PROFILE_TARGET_DATA, &jxl_color);
295#endif
296 /* if we couldn't successfully request the pixel data space, we fall back on wide gamut */
297 /* this code path is very unlikely to happen in practice */
298 if (jret != JXL_DEC_SUCCESS)
299 fallback = 1;
300 } else {
301 /* an ICC Profile is present in the stream */
302 if (ctx->basic_info.uses_original_profile) {
303 /* uses_original_profile is the same as !xyb_encoded */
304 av_log(avctx, AV_LOG_VERBOSE, "Using embedded ICC Profile\n");
305 if ((ret = libjxl_get_icc(avctx)) < 0)
306 return ret;
307 } else {
308 /*
309 * an XYB-encoded image with an embedded ICC profile can't always have the
310 * pixel data requested in the original space, so libjxl has no feature
311 * to allow this to happen, so we fall back on wide gamut
312 */
313 fallback = 1;
314 }
315 }
316
317 avctx->color_range = frame->color_range = AVCOL_RANGE_JPEG;
318 if (ctx->basic_info.num_color_channels > 1)
319 avctx->colorspace = AVCOL_SPC_RGB;
322
323 if (!ctx->iccp) {
324 /* checking enum values */
325 if (!fallback) {
326 if (avctx->colorspace == AVCOL_SPC_RGB)
327 avctx->color_primaries = libjxl_get_primaries(avctx, &jxl_color);
328 avctx->color_trc = libjxl_get_trc(avctx, &jxl_color);
329 }
330 /* fall back on wide gamut if enum values fail */
332 if (avctx->colorspace == AVCOL_SPC_RGB) {
333 av_log(avctx, AV_LOG_WARNING, "Falling back on wide gamut output\n");
334 jxl_color.primaries = JXL_PRIMARIES_2100;
336 }
337 /* libjxl requires this set even for grayscale */
338 jxl_color.white_point = JXL_WHITE_POINT_D65;
339 }
340 if (avctx->color_trc == AVCOL_TRC_UNSPECIFIED) {
341 if (ctx->jxl_pixfmt.data_type == JXL_TYPE_FLOAT
342 || ctx->jxl_pixfmt.data_type == JXL_TYPE_FLOAT16) {
343 av_log(avctx, AV_LOG_WARNING, "Falling back on Linear Light transfer\n");
344 jxl_color.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
346 } else {
347 av_log(avctx, AV_LOG_WARNING, "Falling back on iec61966-2-1/sRGB transfer\n");
348 jxl_color.transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
350 }
351 }
352 /* all colors will be in-gamut so we want accurate colors */
353 jxl_color.rendering_intent = JXL_RENDERING_INTENT_RELATIVE;
354 jxl_color.color_space = ctx->basic_info.num_color_channels > 1 ? JXL_COLOR_SPACE_RGB : JXL_COLOR_SPACE_GRAY;
355 jret = JxlDecoderSetPreferredColorProfile(ctx->decoder, &jxl_color);
356 if (jret != JXL_DEC_SUCCESS) {
357 av_log(avctx, AV_LOG_WARNING, "Unable to set fallback color encoding\n");
358 /*
359 * This should only happen if there's a non-XYB encoded image with custom primaries
360 * embedded as enums and no embedded ICC Profile.
361 * In this case, libjxl will synthesize an ICC Profile for us.
362 */
365 if ((ret = libjxl_get_icc(avctx)) < 0)
366 return ret;
367 }
368 }
369
370 frame->color_trc = avctx->color_trc;
371 frame->color_primaries = avctx->color_primaries;
372 frame->colorspace = avctx->colorspace;
373
374 return 0;
375}
376
378{
380 int ret = 0;
381
382 if (ctx->iccp) {
384 if (ret < 0)
385 return ret;
386 }
387
388 if (ctx->exif) {
389 AVExifMetadata ifd = { 0 };
390 /* size may be larger than exif_pos due to the realloc loop */
391 ret = av_exif_parse_buffer(avctx, ctx->exif->data, ctx->exif_pos, &ifd, AV_EXIF_T_OFF);
392 av_buffer_unref(&ctx->exif);
393 if (ret < 0) {
394 av_log(avctx, AV_LOG_ERROR, "Unable to parse EXIF buffer: %s\n", av_err2str(ret));
395 return ret;
396 }
397 /*
398 * JPEG XL Codestream orientation overrides EXIF orientation in all cases.
399 * As a result, we remove the EXIF Orientation tag rather than just zeroing it
400 * in order to prevent any ambiguity. libjxl autorotates the image for us so we
401 * do not need to worry about that.
402 */
403 ret = av_exif_remove_entry(avctx, &ifd, av_exif_get_tag_id("Orientation"), 0);
404 if (ret < 0)
405 av_log(avctx, AV_LOG_WARNING, "Unable to remove orientation from EXIF buffer: %s\n", av_err2str(ret));
406 ret = ff_decode_exif_attach_ifd(avctx, ctx->frame, &ifd);
407 if (ret < 0)
408 av_log(avctx, AV_LOG_ERROR, "Unable to attach EXIF ifd: %s\n", av_err2str(ret));
409 av_exif_free(&ifd);
410 }
411
412 return ret;
413}
414
416{
418 if (ctx->exif_box) {
419 /* last box was Exif */
420 size_t remainder = JxlDecoderReleaseBoxBuffer(ctx->decoder);
421 ctx->exif_pos = ctx->exif->size - remainder;
422 ctx->exif_box = 0;
423 }
424 int ret = libjxl_attach_sidedata(avctx);
426 ctx->frame_complete = 0;
427 return ret;
428}
429
431{
433 int ret;
434 AVPacket *pkt = ctx->avpkt;
435
436 while (1) {
437 size_t remaining;
438 JxlFrameHeader header;
439
440 if (!pkt->size) {
442 ret = ff_decode_get_packet(avctx, pkt);
443 if (ret < 0 && ret != AVERROR_EOF)
444 return ret;
445 ctx->accumulated_pts = 0;
446 ctx->frame_duration = 0;
447 if (!pkt->size) {
448 /* jret set by the last iteration of the loop */
449 if (ctx->jret == JXL_DEC_NEED_MORE_INPUT && !ctx->frame_complete) {
450 av_log(avctx, AV_LOG_ERROR, "Unexpected end of JXL codestream\n");
451 return AVERROR_INVALIDDATA;
452 } else if (ctx->frame_complete) {
453 ctx->jret = JXL_DEC_SUCCESS;
454 goto success;
455 }
456 return AVERROR_EOF;
457 }
458 }
459
460 ctx->jret = JxlDecoderSetInput(ctx->decoder, pkt->data, pkt->size);
461 if (ctx->jret == JXL_DEC_ERROR) {
462 /* this should never happen here unless there's a bug in libjxl */
463 av_log(avctx, AV_LOG_ERROR, "Unknown libjxl decode error\n");
464 return AVERROR_EXTERNAL;
465 }
466
467 ctx->jret = JxlDecoderProcessInput(ctx->decoder);
468 /*
469 * JxlDecoderReleaseInput returns the number
470 * of bytes remaining to be read, rather than
471 * the number of bytes that it did read
472 */
473 remaining = JxlDecoderReleaseInput(ctx->decoder);
474 size_t consumed = pkt->size - remaining;
475 pkt->data += consumed;
476 pkt->size = remaining;
477
478 switch(ctx->jret) {
479 case JXL_DEC_ERROR:
480 av_log(avctx, AV_LOG_ERROR, "Unknown libjxl decode error\n");
481 /*
482 * we consume all remaining input on error, if nothing was consumed
483 * this prevents libjxl from consuming nothing forever
484 * and just dumping the last error over and over
485 */
486 if (!consumed)
488 return AVERROR_INVALIDDATA;
489 case JXL_DEC_NEED_MORE_INPUT:
490 av_log(avctx, AV_LOG_DEBUG, "NEED_MORE_INPUT event emitted\n");
491 continue;
492 case JXL_DEC_BASIC_INFO:
493 av_log(avctx, AV_LOG_DEBUG, "BASIC_INFO event emitted\n");
494 if (JxlDecoderGetBasicInfo(ctx->decoder, &ctx->basic_info) != JXL_DEC_SUCCESS) {
495 /*
496 * this should never happen
497 * if it does it is likely a libjxl decoder bug
498 */
499 av_log(avctx, AV_LOG_ERROR, "Bad libjxl basic info event\n");
500 return AVERROR_EXTERNAL;
501 }
502 avctx->pix_fmt = libjxl_get_pix_fmt(avctx, ctx);
503 if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
504 av_log(avctx, AV_LOG_ERROR, "Bad libjxl pixel format\n");
505 return AVERROR_EXTERNAL;
506 }
507 if ((ret = ff_set_dimensions(avctx, ctx->basic_info.xsize, ctx->basic_info.ysize)) < 0)
508 return ret;
509 if (ctx->basic_info.have_animation)
510 ctx->anim_timebase = av_make_q(ctx->basic_info.animation.tps_denominator,
511 ctx->basic_info.animation.tps_numerator);
512 if (ctx->basic_info.alpha_bits) {
513 if (ctx->basic_info.alpha_premultiplied)
515 else
517 }
518 continue;
519 case JXL_DEC_COLOR_ENCODING:
520 av_log(avctx, AV_LOG_DEBUG, "COLOR_ENCODING event emitted\n");
521 ret = libjxl_color_encoding_event(avctx, ctx->frame);
522 if (ret < 0)
523 return ret;
524 continue;
525 case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
526 av_log(avctx, AV_LOG_DEBUG, "NEED_IMAGE_OUT_BUFFER event emitted\n");
527 ret = ff_get_buffer(avctx, ctx->frame, 0);
528 if (ret < 0)
529 return ret;
530 ctx->jxl_pixfmt.align = ctx->frame->linesize[0];
531 if (JxlDecoderSetImageOutBuffer(ctx->decoder, &ctx->jxl_pixfmt,
532 ctx->frame->data[0], ctx->frame->buf[0]->size)
533 != JXL_DEC_SUCCESS) {
534 av_log(avctx, AV_LOG_ERROR, "Bad libjxl dec need image out buffer event\n");
535 return AVERROR_EXTERNAL;
536 }
537#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 8, 0)
538 if (JxlDecoderSetImageOutBitDepth(ctx->decoder, &ctx->jxl_bit_depth) != JXL_DEC_SUCCESS) {
539 av_log(avctx, AV_LOG_ERROR, "Error setting output bit depth\n");
540 return AVERROR_EXTERNAL;
541 }
542#endif
543 continue;
544 case JXL_DEC_FRAME:
545 /* Frame here refers to the Frame bundle, not a decoded picture */
546 av_log(avctx, AV_LOG_DEBUG, "FRAME event emitted\n");
547 if (ctx->prev_is_last) {
548 /*
549 * The last frame sent was tagged as "is_last" which
550 * means this is a new image file altogether.
551 */
552 ctx->frame->pict_type = AV_PICTURE_TYPE_I;
553 ctx->frame->flags |= AV_FRAME_FLAG_KEY;
554 }
555 if (JxlDecoderGetFrameHeader(ctx->decoder, &header) != JXL_DEC_SUCCESS) {
556 av_log(avctx, AV_LOG_ERROR, "Bad libjxl dec frame event\n");
557 return AVERROR_EXTERNAL;
558 }
559 ctx->prev_is_last = header.is_last;
560 /* zero duration for animation means the frame is not presented */
561 if (ctx->basic_info.have_animation && header.duration)
562 ctx->frame_duration = header.duration;
563 continue;
564 case JXL_DEC_FULL_IMAGE:
565 /* full image is one frame, even if animated */
566 av_log(avctx, AV_LOG_DEBUG, "FULL_IMAGE event emitted\n");
567 if (ctx->basic_info.have_animation) {
568 ctx->frame->pts = av_rescale_q(ctx->accumulated_pts, ctx->anim_timebase, avctx->pkt_timebase);
569 ctx->frame->duration = av_rescale_q(ctx->frame_duration, ctx->anim_timebase, avctx->pkt_timebase);
570 } else {
571 ctx->frame->pts = 0;
572 ctx->frame->duration = pkt->duration;
573 }
574 if (pkt->pts != AV_NOPTS_VALUE)
575 ctx->frame->pts += pkt->pts;
576 ctx->accumulated_pts += ctx->frame_duration;
577 ctx->frame->pkt_dts = pkt->dts;
578 if (ctx->basic_info.have_animation && !ctx->prev_is_last) {
579 libjxl_finalize_frame(avctx, frame, ctx->frame);
580 return 0;
581 } else {
582 ctx->frame_complete = 1;
583 continue;
584 }
585 case JXL_DEC_SUCCESS:
586 av_log(avctx, AV_LOG_DEBUG, "SUCCESS event emitted\n");
587 /*
588 * this event will be fired when the zero-length EOF
589 * packet is sent to the decoder by the client,
590 * but it will also be fired when the next image of
591 * an image2pipe sequence is loaded up
592 */
593success:
594 libjxl_finalize_frame(avctx, frame, ctx->frame);
595 JxlDecoderReset(ctx->decoder);
597 return 0;
598 case JXL_DEC_BOX: {
599 char type[4];
600 av_log(avctx, AV_LOG_DEBUG, "BOX event emitted\n");
601 if (ctx->exif_box) {
602 /* last box was Exif */
603 size_t remainder = JxlDecoderReleaseBoxBuffer(ctx->decoder);
604 ctx->exif_pos = ctx->exif->size - remainder;
605 }
606 if (JxlDecoderGetBoxType(ctx->decoder, type, JXL_TRUE) != JXL_DEC_SUCCESS) {
607 av_log(avctx, AV_LOG_ERROR, "Error getting box type\n");
608 return AVERROR_EXTERNAL;
609 }
610 if (AV_RL32(type) != MKTAG('E','x','i','f')) {
611 ctx->exif_box = 0;
612 continue;
613 }
614 ctx->exif_box = 1;
615 av_buffer_unref(&ctx->exif);
616 ctx->exif_pos = 0;
617 // 4k buffer should usually be enough
618 ret = av_buffer_realloc(&ctx->exif, 4096);
619 if (ret < 0)
620 return AVERROR(ENOMEM);
621 if (JxlDecoderSetBoxBuffer(ctx->decoder, ctx->exif->data, ctx->exif->size) != JXL_DEC_SUCCESS) {
622 av_log(avctx, AV_LOG_ERROR, "Error setting box buffer\n");
623 return AVERROR_EXTERNAL;
624 }
625 continue;
626 }
627 case JXL_DEC_BOX_NEED_MORE_OUTPUT: {
628 av_log(avctx, AV_LOG_DEBUG, "BOX_NEED_MORE_OUTPUT event emitted\n");
629 size_t remainder = JxlDecoderReleaseBoxBuffer(ctx->decoder);
630 ctx->exif_pos = ctx->exif->size - remainder;
631 size_t new_size = ctx->exif->size << 1;
632 ret = av_buffer_realloc(&ctx->exif, new_size);
633 if (ret < 0)
634 return AVERROR(ENOMEM);
635 if (JxlDecoderSetBoxBuffer(ctx->decoder, ctx->exif->data + ctx->exif_pos,
636 ctx->exif->size - ctx->exif_pos) != JXL_DEC_SUCCESS) {
637 av_log(avctx, AV_LOG_ERROR, "Error setting box buffer\n");
638 return AVERROR_EXTERNAL;
639 }
640 continue;
641 }
642 default:
643 av_log(avctx, AV_LOG_ERROR, "Bad libjxl event: %d\n", ctx->jret);
644 return AVERROR_EXTERNAL;
645 }
646 }
647}
648
650{
652
653 if (ctx->runner)
654 JxlThreadParallelRunnerDestroy(ctx->runner);
655 ctx->runner = NULL;
656 if (ctx->decoder)
657 JxlDecoderDestroy(ctx->decoder);
658 ctx->decoder = NULL;
659 av_buffer_unref(&ctx->exif);
660 av_buffer_unref(&ctx->iccp);
661 av_frame_free(&ctx->frame);
662
663 return 0;
664}
665
667 .p.name = "libjxl",
668 CODEC_LONG_NAME("libjxl JPEG XL"),
669 .p.type = AVMEDIA_TYPE_VIDEO,
670 .p.id = AV_CODEC_ID_JPEGXL,
671 .priv_data_size = sizeof(LibJxlDecodeContext),
674 .close = libjxl_decode_close,
676 .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
679 .p.wrapper_name = "libjxl",
680};
681
683 .p.name = "libjxl_anim",
684 CODEC_LONG_NAME("libjxl JPEG XL animated"),
685 .p.type = AVMEDIA_TYPE_VIDEO,
687 .priv_data_size = sizeof(LibJxlDecodeContext),
690 .close = libjxl_decode_close,
692 .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
695 .p.wrapper_name = "libjxl",
696};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static const char *const format[]
Definition af_aiir.c:444
const FFCodec ff_libjxl_decoder
Definition libjxldec.c:666
const FFCodec ff_libjxl_anim_decoder
Definition libjxldec.c:682
simple assert() macros that are a bit more flexible than ISO C assert().
Libavcodec external API header.
refcounted data buffer API
#define FF_CODEC_RECEIVE_FRAME_CB(func)
#define FF_CODEC_CAP_NOT_INIT_THREADSAFE
The codec is not known to be init-threadsafe (i.e.
#define FF_CODEC_CAP_ICC_PROFILES
Codec supports embedded ICC profiles (AV_FRAME_DATA_ICC_PROFILE).
#define CODEC_LONG_NAME(str)
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define FF_CODEC_CAP_AUTO_THREADS
Codec handles avctx->thread_count == 0 (auto) internally.
common internal and external API header
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
Colorspace value utility functions for libavutil.
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition decode.c:1777
int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx, AVFrame *frame, enum AVFrameSideDataType type, AVBufferRef **buf)
Similar to ff_frame_new_side_data, but using an existing buffer ref.
Definition decode.c:2222
int ff_decode_exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMetadata *ifd)
Definition decode.c:2492
int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt)
Called by decoders to get the next packet for decoding.
Definition decode.c:254
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Definition utils.c:91
static AVPacket * pkt
static AVFrame * frame
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
error code definitions
int av_exif_parse_buffer(void *logctx, const uint8_t *buf, size_t size, AVExifMetadata *ifd, enum AVExifHeaderMode header_mode)
Decodes the EXIF data provided in the buffer and writes it into the struct *ifd.
Definition exif.c:882
void av_exif_free(AVExifMetadata *ifd)
Frees all resources associated with the given EXIF metadata struct.
Definition exif.c:659
int32_t av_exif_get_tag_id(const char *name)
Retrieves the tag ID associated with the provided tag string name.
Definition exif.c:244
int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags)
Remove an entry from the provided EXIF metadata struct.
Definition exif.c:1272
@ AV_EXIF_T_OFF
The first four bytes point to the actual start, then it's AV_EXIF_TIFF_HEADER.
Definition exif.h:68
EXIF metadata parser - internal functions.
reference-counted frame API
#define AV_CODEC_CAP_OTHER_THREADS
Codec supports multithreading through a method other than slice- or frame-level multithreading.
Definition codec.h:112
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_JPEGXL_ANIM
Definition codec_id.h:322
@ AV_CODEC_ID_JPEGXL
Definition codec_id.h:308
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition buffer.c:139
int av_buffer_realloc(AVBufferRef **pbuf, size_t size)
Reallocate a given buffer.
Definition buffer.c:183
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition buffer.c:77
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_EOF
End of file.
Definition error.h:57
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition frame.h:687
void av_frame_move_ref(AVFrame *dst, AVFrame *src)
Move everything contained in src to dst and reset src.
Definition frame.c:523
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
@ AV_FRAME_DATA_ICC_PROFILE
The data contains an ICC profile as an opaque octet buffer following the format described by ISO 1507...
Definition frame.h:144
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc *prm)
Detects which enum AVColorPrimaries constant corresponds to the given complete gamut description.
Definition csp.c:115
const AVColorPrimariesDesc * av_csp_primaries_desc_from_id(enum AVColorPrimaries prm)
Retrieves a complete gamut description from an enum constant describing the color primaries.
Definition csp.c:95
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
AVRational av_d2q(double d, int max)
Convert a double precision floating point number to a rational.
Definition rational.c:110
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
@ AV_PICTURE_TYPE_I
Intra.
Definition avutil.h:278
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
cl_device_type type
#define AV_RL32(p)
common internal api header.
#define av_cold
Definition attributes.h:117
size_t ff_libjxl_get_threadcount(int threads)
Transform threadcount in ffmpeg to one used by libjxl.
Definition libjxl.c:33
void ff_libjxl_init_memory_manager(JxlMemoryManager *manager)
Initialize and populate a JxlMemoryManager with av_malloc() and av_free() so libjxl will use these fu...
Definition libjxl.c:65
JPEG XL via libjxl common support header.
static int libjxl_finalize_frame(AVCodecContext *avctx, AVFrame *dst, AVFrame *src)
Definition libjxldec.c:415
static int libjxl_attach_sidedata(AVCodecContext *avctx)
Definition libjxldec.c:377
static av_cold int libjxl_decode_init(AVCodecContext *avctx)
Definition libjxldec.c:101
static enum AVPixelFormat libjxl_get_pix_fmt(AVCodecContext *avctx, LibJxlDecodeContext *ctx)
Definition libjxldec.c:127
static int libjxl_get_icc(AVCodecContext *avctx)
Definition libjxldec.c:223
static av_cold int libjxl_decode_close(AVCodecContext *avctx)
Definition libjxldec.c:649
static int libjxl_color_encoding_event(AVCodecContext *avctx, AVFrame *frame)
Definition libjxldec.c:272
static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame)
Definition libjxldec.c:430
static int libjxl_init_jxl_decoder(AVCodecContext *avctx)
Definition libjxldec.c:71
static enum AVColorPrimaries libjxl_get_primaries(void *avctx, const JxlColorEncoding *jxl_color)
Definition libjxldec.c:172
static enum AVColorTransferCharacteristic libjxl_get_trc(void *avctx, const JxlColorEncoding *jxl_color)
Definition libjxldec.c:199
const char * desc
Definition libsvtav1.c:83
#define MKTAG(a, b, c, d)
Definition macros.h:55
Memory handling functions.
pixel format definitions
#define AV_PIX_FMT_RGBF32
Definition pixfmt.h:632
#define AV_PIX_FMT_RGBAF32
Definition pixfmt.h:633
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
#define AV_PIX_FMT_YA16
Definition pixfmt.h:530
@ AVALPHA_MODE_STRAIGHT
Alpha channel is independent of color values.
Definition pixfmt.h:819
@ AVALPHA_MODE_PREMULTIPLIED
Alpha channel is multiplied into color values.
Definition pixfmt.h:818
#define AV_PIX_FMT_RGBA64
Definition pixfmt.h:535
#define AV_PIX_FMT_RGB48
Definition pixfmt.h:531
#define AV_PIX_FMT_GRAYF32
Definition pixfmt.h:588
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition pixfmt.h:75
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition pixfmt.h:100
@ AV_PIX_FMT_YA8
8 bits gray, 8 bits alpha
Definition pixfmt.h:140
#define AV_PIX_FMT_GRAY16
Definition pixfmt.h:528
AVColorPrimaries
Chromaticity coordinates of the source primaries.
Definition pixfmt.h:642
@ AVCOL_PRI_BT709
also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP 177 Annex B
Definition pixfmt.h:644
@ AVCOL_PRI_UNSPECIFIED
Definition pixfmt.h:645
@ AVCOL_PRI_BT2020
ITU-R BT2020.
Definition pixfmt.h:653
AVColorTransferCharacteristic
Color Transfer Characteristic.
Definition pixfmt.h:672
@ AVCOL_TRC_SMPTE2084
SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems.
Definition pixfmt.h:689
@ AVCOL_TRC_GAMMA22
also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
Definition pixfmt.h:677
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition pixfmt.h:681
@ AVCOL_TRC_GAMMA28
also ITU-R BT470BG
Definition pixfmt.h:678
@ AVCOL_TRC_ARIB_STD_B67
ARIB STD-B67, known as "Hybrid log-gamma".
Definition pixfmt.h:693
@ AVCOL_TRC_SMPTE428
SMPTE ST 428-1.
Definition pixfmt.h:691
@ AVCOL_TRC_IEC61966_2_1
IEC 61966-2-1 (sRGB or sYCC)
Definition pixfmt.h:686
@ AVCOL_TRC_UNSPECIFIED
Definition pixfmt.h:675
@ AVCOL_TRC_BT709
also ITU-R BT1361
Definition pixfmt.h:674
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition pixfmt.h:707
static const uint8_t header[24]
Definition sdr2.c:68
A reference to a data buffer.
Definition buffer.h:82
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition avcodec.h:681
AVRational pkt_timebase
Timebase in which pkt_dts/pts and AVPacket.dts/pts are expressed.
Definition avcodec.h:554
enum AVColorPrimaries color_primaries
Chromaticity coordinates of the source primaries.
Definition avcodec.h:657
int bits_per_raw_sample
Bits per sample/pixel of internal libavcodec pixel/sample format.
Definition avcodec.h:1571
enum AVColorSpace colorspace
YUV colorspace type.
Definition avcodec.h:671
int thread_count
thread count is used to decide how many independent tasks should be passed to execute()
Definition avcodec.h:1579
enum AVColorTransferCharacteristic color_trc
Color Transfer Characteristic.
Definition avcodec.h:664
enum AVAlphaMode alpha_mode
Indicates how the alpha channel of the video is represented.
Definition avcodec.h:1937
struct AVCodecInternal * internal
Private context used for internal data.
Definition avcodec.h:478
void * priv_data
Definition avcodec.h:470
AVPacket * in_pkt
This packet is used to hold the packet given to decoders implementing the .decode API; it is unused b...
Definition internal.h:83
Struct that contains both white point location and primaries location, providing the complete descrip...
Definition csp.h:78
AVWhitepointCoefficients wp
Definition csp.h:79
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
int64_t frame_duration
Definition libjxldec.c:60
AVPacket * avpkt
Definition libjxldec.c:58
JxlBitDepth jxl_bit_depth
Definition libjxldec.c:54
JxlDecoderStatus events
Definition libjxldec.c:56
AVRational anim_timebase
Definition libjxldec.c:62
JxlBasicInfo basic_info
Definition libjxldec.c:51
JxlDecoder * decoder
Definition libjxldec.c:50
AVBufferRef * exif
Definition libjxldec.c:66
JxlDecoderStatus jret
Definition libjxldec.c:65
JxlPixelFormat jxl_pixfmt
Definition libjxldec.c:52
int64_t accumulated_pts
Definition libjxldec.c:59
AVBufferRef * iccp
Definition libjxldec.c:57
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static AVFormatContext * ctx
Definition movenc.c:49