FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/prores_raw.c
Date: 2026-06-16 12:54:33
Exec Total Coverage
Lines: 0 317 0.0%
Functions: 0 9 0.0%
Branches: 0 134 0.0%

Line Branch Exec Source
1 /*
2 * ProRes RAW decoder
3 * Copyright (c) 2023-2025 Paul B Mahol
4 * Copyright (c) 2025 Lynne
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg 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 GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "libavutil/avassert.h"
24 #include "libavutil/intfloat.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/mem_internal.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/raw_color_params.h"
29 #include "libavutil/rational.h"
30
31 #define CACHED_BITSTREAM_READER !ARCH_X86_32
32
33 #include "config_components.h"
34 #include "avcodec.h"
35 #include "bytestream.h"
36 #include "codec_internal.h"
37 #include "decode.h"
38 #include "get_bits.h"
39 #include "idctdsp.h"
40 #include "proresdata.h"
41 #include "thread.h"
42 #include "hwconfig.h"
43 #include "hwaccel_internal.h"
44
45 #include "prores_raw.h"
46
47 static av_cold int decode_init(AVCodecContext *avctx)
48 {
49 ProResRAWContext *s = avctx->priv_data;
50
51 /* The codec outputs linear data, with the transfer function of the
52 * camera and any adjustments built into an 8-point linearization curve */
53 avctx->bits_per_raw_sample = 16;
54 avctx->color_trc = AVCOL_TRC_LINEAR;
55 avctx->color_primaries = AVCOL_PRI_UNSPECIFIED;
56 avctx->colorspace = AVCOL_SPC_UNSPECIFIED;
57
58 s->pix_fmt = AV_PIX_FMT_NONE;
59
60 ff_blockdsp_init(&s->bdsp);
61 /* Coefficients and the iDCT are 12-bit, the linearization curve then
62 * expands the result to the 16-bit linear output range. */
63 ff_proresdsp_init(&s->prodsp, 12);
64
65 ff_permute_scantable(s->scan, ff_prores_interlaced_scan, s->prodsp.idct_permutation);
66
67 return 0;
68 }
69
70 static uint16_t get_value(GetBitContext *gb, int16_t codebook)
71 {
72 const int16_t switch_bits = codebook >> 8;
73 const int16_t rice_order = codebook & 0xf;
74 const int16_t exp_order = (codebook >> 4) & 0xf;
75 int16_t q, bits;
76
77 uint32_t b = show_bits_long(gb, 32);
78 if (!b)
79 return 0;
80 q = ff_clz(b);
81
82 if (b & 0x80000000) {
83 skip_bits_long(gb, 1 + rice_order);
84 return (b & 0x7FFFFFFF) >> (31 - rice_order);
85 }
86
87 if (q <= switch_bits) {
88 skip_bits_long(gb, 1 + rice_order + q);
89 return (q << rice_order) +
90 (((b << (q + 1)) >> 1) >> (31 - rice_order));
91 }
92
93 bits = exp_order + (q << 1) - switch_bits;
94 if (bits > 32)
95 return 0; // we do not return a negative error code so that we dont produce out of range values on errors
96 skip_bits_long(gb, bits);
97 return (b >> (32 - bits)) +
98 ((switch_bits + 1) << rice_order) -
99 (1 << exp_order);
100 }
101
102 #define TODCCODEBOOK(x) ((x + 1) >> 1)
103
104 #define DC_CB_MAX 12
105 const uint8_t ff_prores_raw_dc_cb[DC_CB_MAX + 1] = {
106 0x010, 0x021, 0x032, 0x033, 0x033, 0x033, 0x044, 0x044, 0x044, 0x044, 0x044, 0x044, 0x076,
107 };
108
109 #define AC_CB_MAX 94
110 const int16_t ff_prores_raw_ac_cb[AC_CB_MAX + 1] = {
111 0x000, 0x211, 0x111, 0x111, 0x222, 0x222, 0x222, 0x122, 0x122, 0x122,
112 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x133, 0x133,
113 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244,
114 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244,
115 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355,
116 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355,
117 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355,
118 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x166,
119 };
120
121 #define RN_CB_MAX 27
122 const int16_t ff_prores_raw_rn_cb[RN_CB_MAX + 1] = {
123 0x200, 0x100, 0x000, 0x000, 0x211, 0x211, 0x111, 0x111, 0x011, 0x011, 0x021, 0x021, 0x222, 0x022,
124 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x032, 0x032, 0x044
125 };
126
127 #define LN_CB_MAX 14
128 const int16_t ff_prores_raw_ln_cb[LN_CB_MAX + 1] = {
129 0x100, 0x111, 0x222, 0x222, 0x122, 0x122, 0x433, 0x433, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x033,
130 };
131
132 static int decode_comp(AVCodecContext *avctx, TileContext *tile,
133 AVFrame *frame, const uint8_t *data, int size,
134 int component, int16_t *qmat)
135 {
136 int ret;
137 ProResRAWContext *s = avctx->priv_data;
138 const ptrdiff_t linesize = frame->linesize[0] >> 1;
139 uint16_t *dst = (uint16_t *)(frame->data[0] + tile->y*frame->linesize[0] + 2*tile->x);
140
141 int idx;
142 const int log2_nb_blocks = tile->log2_nb_blocks;
143 const int nb_blocks = 1 << log2_nb_blocks;
144 const int block_mask = nb_blocks - 1;
145 const int nb_codes = 64 * nb_blocks;
146
147 LOCAL_ALIGNED_32(int32_t, block, [64*16]);
148
149 int16_t sign = 0;
150 int16_t dc_add = 0;
151 int16_t dc_codebook;
152
153 uint16_t ac, rn, ln;
154 int16_t ac_codebook = 49;
155 int16_t rn_codebook = 0;
156 int16_t ln_codebook = 66;
157
158 const uint8_t *scan = s->scan;
159 GetBitContext gb;
160
161 if (component > 1)
162 dst += linesize;
163 dst += component & 1;
164
165 if ((ret = init_get_bits8(&gb, data, size)) < 0)
166 return ret;
167
168 memset(block, 0, nb_blocks * 64 * sizeof(*block));
169
170 /* Special handling for first block */
171 int dc = get_value(&gb, 700);
172 int prev_dc = (dc >> 1) ^ -(dc & 1);
173 block[0] = (((dc&1) + (dc>>1) ^ -(int)(dc & 1)) + (dc & 1)) + 1;
174
175 for (int n = 1; n < nb_blocks; n++) {
176 if (get_bits_left(&gb) <= 0)
177 break;
178
179 if ((n & 15) == 1)
180 dc_codebook = 100;
181 else
182 dc_codebook = ff_prores_raw_dc_cb[FFMIN(TODCCODEBOOK(dc), DC_CB_MAX)];
183
184 dc = get_value(&gb, dc_codebook);
185
186 sign = sign ^ dc & 1;
187 dc_add = (-sign ^ TODCCODEBOOK(dc)) + sign;
188 sign = dc_add < 0;
189 prev_dc += dc_add;
190
191 block[n*64] = prev_dc + 1;
192 }
193
194 for (int n = nb_blocks; n <= nb_codes;) {
195 if (get_bits_left(&gb) <= 0)
196 break;
197
198 ln = get_value(&gb, ln_codebook);
199
200 for (int i = 0; i < ln; i++) {
201 if (get_bits_left(&gb) <= 0)
202 break;
203
204 if ((n + i) >= nb_codes)
205 break;
206
207 ac = get_value(&gb, ac_codebook);
208 ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
209 sign = -get_bits1(&gb);
210
211 idx = scan[(n + i) >> log2_nb_blocks] + (((n + i) & block_mask) << 6);
212 block[idx] = ((ac + 1) ^ sign) - sign;
213 }
214
215 n += ln;
216 if (n >= nb_codes)
217 break;
218
219 rn = get_value(&gb, rn_codebook);
220 rn_codebook = ff_prores_raw_rn_cb[FFMIN(rn, RN_CB_MAX)];
221
222 n += rn + 1;
223 if (n >= nb_codes)
224 break;
225
226 if (get_bits_left(&gb) <= 0)
227 break;
228
229 ac = get_value(&gb, ac_codebook);
230 sign = -get_bits1(&gb);
231
232 idx = scan[n >> log2_nb_blocks] + ((n & block_mask) << 6);
233 block[idx] = ((ac + 1) ^ sign) - sign;
234
235 ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
236 ln_codebook = ff_prores_raw_ln_cb[FFMIN(ac, LN_CB_MAX)];
237
238 n++;
239 }
240
241 for (int n = 0; n < nb_blocks; n++) {
242 uint16_t *ptr = dst + n*16;
243 s->prodsp.idct_put_bayer(ptr, linesize, block + n*64, qmat, s->lin_curve);
244 }
245
246 return 0;
247 }
248
249 static int decode_tile(AVCodecContext *avctx, TileContext *tile,
250 AVFrame *frame)
251 {
252 int ret;
253 ProResRAWContext *s = avctx->priv_data;
254
255 GetByteContext *gb = &tile->gb;
256 LOCAL_ALIGNED_32(int16_t, qmat, [64]);
257
258 if (tile->x >= avctx->width)
259 return 0;
260
261 /* Tile header */
262 int header_len = bytestream2_get_byteu(gb) >> 3;
263 int16_t scale = bytestream2_get_byteu(gb);
264
265 int size[4];
266 size[0] = bytestream2_get_be16(gb);
267 size[1] = bytestream2_get_be16(gb);
268 size[2] = bytestream2_get_be16(gb);
269 size[3] = bytestream2_size(gb) - size[0] - size[1] - size[2] - header_len;
270 if (size[3] < 0)
271 return AVERROR_INVALIDDATA;
272
273 for (int i = 0; i < 64; i++)
274 qmat[i] = s->qmat[i] * scale;
275
276 const uint8_t *comp_start = gb->buffer_start + header_len;
277
278 ret = decode_comp(avctx, tile, frame, comp_start,
279 size[0], 2, qmat);
280 if (ret < 0)
281 goto fail;
282
283 ret = decode_comp(avctx, tile, frame, comp_start + size[0],
284 size[1], 1, qmat);
285 if (ret < 0)
286 goto fail;
287
288 ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1],
289 size[2], 3, qmat);
290 if (ret < 0)
291 goto fail;
292
293 ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1] + size[2],
294 size[3], 0, qmat);
295 if (ret < 0)
296 goto fail;
297
298 return 0;
299 fail:
300 av_log(avctx, AV_LOG_ERROR, "tile %d/%d decoding error\n", tile->x, tile->y);
301 return ret;
302 }
303
304 static int decode_tiles(AVCodecContext *avctx, void *arg,
305 int n, int thread_nb)
306 {
307 ProResRAWContext *s = avctx->priv_data;
308 TileContext *tile = &s->tiles[n];
309 AVFrame *frame = arg;
310
311 return decode_tile(avctx, tile, frame);
312 }
313
314 static enum AVPixelFormat get_pixel_format(AVCodecContext *avctx,
315 enum AVPixelFormat pix_fmt)
316 {
317 enum AVPixelFormat pix_fmts[] = {
318 #if CONFIG_PRORES_RAW_VULKAN_HWACCEL
319 AV_PIX_FMT_VULKAN,
320 #endif
321 #if CONFIG_PRORES_RAW_VIDEOTOOLBOX_HWACCEL
322 AV_PIX_FMT_VIDEOTOOLBOX,
323 #endif
324 pix_fmt,
325 AV_PIX_FMT_NONE,
326 };
327
328 return ff_get_format(avctx, pix_fmts);
329 }
330
331 static int decode_frame(AVCodecContext *avctx,
332 AVFrame *frame, int *got_frame_ptr,
333 AVPacket *avpkt)
334 {
335 ProResRAWContext *s = avctx->priv_data;
336 int ret, dimensions_changed = 0, old_version = s->version;
337 DECLARE_ALIGNED(32, uint8_t, qmat)[64];
338 memset(qmat, 1, 64);
339
340 if (avctx->skip_frame >= AVDISCARD_ALL)
341 return avpkt->size;
342
343 switch (avctx->codec_tag) {
344 case 0:
345 break;
346 case MKTAG('a','p','r','n'):
347 avctx->profile = AV_PROFILE_PRORES_RAW;
348 break;
349 case MKTAG('a','p','r','h'):
350 avctx->profile = AV_PROFILE_PRORES_RAW_HQ;
351 break;
352 default:
353 avpriv_request_sample(avctx, "Profile %d", avctx->codec_tag);
354 return AVERROR_PATCHWELCOME;
355 break;
356 }
357
358 GetByteContext gb;
359 bytestream2_init(&gb, avpkt->data, avpkt->size);
360 if (bytestream2_get_be32(&gb) != avpkt->size)
361 return AVERROR_INVALIDDATA;
362
363 /* ProRes RAW frame */
364 if (bytestream2_get_be32(&gb) != MKBETAG('p','r','r','f'))
365 return AVERROR_INVALIDDATA;
366
367 int header_len = bytestream2_get_be16(&gb);
368 if (header_len < 62 || bytestream2_get_bytes_left(&gb) < header_len - 2)
369 return AVERROR_INVALIDDATA;
370
371 GetByteContext gb_hdr;
372 bytestream2_init(&gb_hdr, gb.buffer, header_len - 2);
373 bytestream2_skip(&gb, header_len - 2);
374
375 bytestream2_skip(&gb_hdr, 1); /* 1 reserved byte */
376 s->version = bytestream2_get_byte(&gb_hdr);
377 if (s->version > 1) {
378 avpriv_request_sample(avctx, "Version %d", s->version);
379 return AVERROR_PATCHWELCOME;
380 }
381
382 /* Vendor header (e.g. "peac" for Panasonic or "atm0" for Atmos) */
383 bytestream2_skip(&gb_hdr, 4);
384
385 /* Width and height must always be even */
386 int w = bytestream2_get_be16(&gb_hdr);
387 int h = bytestream2_get_be16(&gb_hdr);
388 if ((w & 1) || (h & 1))
389 return AVERROR_INVALIDDATA;
390
391 if (w != avctx->width || h != avctx->height) {
392 av_log(avctx, AV_LOG_WARNING, "picture resolution change: %ix%i -> %ix%i\n",
393 avctx->width, avctx->height, w, h);
394 if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
395 return ret;
396 dimensions_changed = 1;
397 }
398
399 avctx->coded_width = FFALIGN(w, 16);
400 avctx->coded_height = FFALIGN(h, 16);
401
402 enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16;
403 if (pix_fmt != s->pix_fmt || dimensions_changed ||
404 s->version != old_version) {
405 s->pix_fmt = pix_fmt;
406
407 ret = get_pixel_format(avctx, pix_fmt);
408 if (ret < 0)
409 return ret;
410
411 avctx->pix_fmt = ret;
412 }
413
414 /* RecommendedCrop: pixel margins to discard after debayer. Order is
415 * left/right/top/bottom */
416 uint8_t crop_l = bytestream2_get_byte(&gb_hdr);
417 uint8_t crop_r = bytestream2_get_byte(&gb_hdr);
418 uint8_t crop_t = bytestream2_get_byte(&gb_hdr);
419 uint8_t crop_b = bytestream2_get_byte(&gb_hdr);
420
421 /* BayerPattern: 0=RGGB, 1/2/3 = alternates */
422 int bayer_pattern = bytestream2_get_be16(&gb_hdr) & 0x3;
423 if (bayer_pattern != 0) {
424 avpriv_request_sample(avctx, "Bayer pattern %d", bayer_pattern);
425 return AVERROR_PATCHWELCOME;
426 }
427
428 /* senselValueRange: black_level is hardcoded to 0x100,
429 * white_level = senselValueRange + 0x100 */
430 uint16_t black_level = 0x100;
431 uint16_t white_level = bytestream2_get_be16(&gb_hdr) + 0x100;
432
433 float wb_red = av_int2float(bytestream2_get_be32(&gb_hdr)); /* WhiteBalanceRedFactor */
434 float wb_blue = av_int2float(bytestream2_get_be32(&gb_hdr)); /* WhiteBalanceBlueFactor */
435
436 /* ColorMatrix (3x3 float, camera RGB -> CIE 1931 XYZ D65, row-major) */
437 float color_matrix[3][3];
438 for (int r = 0; r < 3; r++)
439 for (int c = 0; c < 3; c++)
440 color_matrix[r][c] = av_int2float(bytestream2_get_be32(&gb_hdr));
441
442 float gain = av_int2float(bytestream2_get_be32(&gb_hdr)); /* GainFactor (post-matrix mult) */
443 uint16_t wb_cct = bytestream2_get_be16(&gb_hdr); /* WhiteBalanceCCT (Kelvin, informational) */
444
445 /* Flags */
446 int flags = bytestream2_get_be16(&gb_hdr);
447 int align = (flags >> 1) & 0x7;
448 if (align > 4) {
449 av_log(avctx, AV_LOG_ERROR,
450 "Invalid tile alignment %d (max 4)\n", align);
451 return AVERROR_INVALIDDATA;
452 }
453
454 /* Quantization matrix */
455 if (flags & 1)
456 bytestream2_get_buffer(&gb_hdr, qmat, 64);
457
458 if ((flags >> 4) & 1) {
459 /* 8-poing 16-bit control points, defining the combined linearization
460 * curve (inv. transfer fn + encoder-defined shaping) */
461 for (int i = 0; i < 8; i++)
462 s->lin_curve[i] = bytestream2_get_be16(&gb_hdr);
463 } else {
464 /* default curve: ptwos */
465 static const uint16_t default_lin_curve[8] =
466 { 0, 512, 1024, 2048, 4096, 8192, 16384, 32768 };
467 memcpy(s->lin_curve, default_lin_curve, sizeof(s->lin_curve));
468 }
469
470 ff_permute_scantable(s->qmat, s->prodsp.idct_permutation, qmat);
471
472 int tw16 = (w + 15) >> 4;
473 s->nb_tw = (tw16 >> align) + av_popcount(~(-1 * (1 << align)) & tw16);
474 s->nb_th = (h + 15) >> 4;
475 s->nb_tiles = s->nb_tw * s->nb_th;
476 av_log(avctx, AV_LOG_DEBUG, "%dx%d | nb_tiles: %d\n", s->nb_tw, s->nb_th, s->nb_tiles);
477
478 s->th = 16;
479
480 av_fast_mallocz(&s->tiles, &s->tiles_size, s->nb_tiles * sizeof(*s->tiles));
481 if (!s->tiles)
482 return AVERROR(ENOMEM);
483
484 if (bytestream2_get_bytes_left(&gb) < s->nb_tiles * 2)
485 return AVERROR_INVALIDDATA;
486
487 /* First tile that extends past the right edge gets halved in width,
488 * next one gets quartered, and so on */
489 int offset = bytestream2_tell(&gb) + s->nb_tiles * 2;
490 int n = 0;
491 for (int ty = 0; ty < s->nb_th; ty++) {
492 unsigned tx = 0;
493 int rem = tw16;
494 for (int e = align; rem > 0; e--) {
495 int unit = 1 << e;
496 while (unit <= rem) {
497 TileContext *tile = &s->tiles[n++];
498 int size = bytestream2_get_be16(&gb);
499
500 if (offset >= avpkt->size)
501 return AVERROR_INVALIDDATA;
502 if (size >= avpkt->size)
503 return AVERROR_INVALIDDATA;
504 if (offset > avpkt->size - size)
505 return AVERROR_INVALIDDATA;
506
507 bytestream2_init(&tile->gb, avpkt->data + offset, size);
508 tile->x = tx * 16;
509 tile->y = ty * s->th;
510 tile->log2_nb_blocks = e;
511 offset += size;
512
513 tx += unit;
514 rem -= unit;
515 }
516 }
517 }
518 av_assert1(n == s->nb_tiles);
519
520 /**
521 * Any data between last tile and frame end is vendor-specific metadata:
522 * [psim record] 4 be32 size + "psim" + pascal string + payload
523 * <more records, if any>, or:
524 * [eomd] 4 be32 size=8 + "eomd" fourcc (end of metadata)
525 * [padding] zero-fill to next-frame alignment
526 *
527 * Known records (feel free to extend):
528 * com.panasonic.Semi-Pro.optical_correction (IEEE doubles):
529 * R - radial polynomial? + padding: [ k0, k1, k2, k3, pad0, pad1 ]
530 * G, B: same
531 * Trailer: optical center in normalized frame coords: [ x, y ]
532 */
533
534 ret = ff_thread_get_buffer(avctx, frame, 0);
535 if (ret < 0)
536 return ret;
537
538 s->frame = frame;
539
540 /* Start */
541 if (avctx->hwaccel) {
542 const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
543
544 ret = ff_hwaccel_frame_priv_alloc(avctx, &s->hwaccel_picture_private);
545 if (ret < 0)
546 return ret;
547
548 ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size);
549 if (ret < 0)
550 return ret;
551
552 for (int n = 0; n < s->nb_tiles; n++) {
553 TileContext *tile = &s->tiles[n];
554 ret = hwaccel->decode_slice(avctx, tile->gb.buffer,
555 tile->gb.buffer_end - tile->gb.buffer);
556 if (ret < 0)
557 return ret;
558 }
559
560 ret = hwaccel->end_frame(avctx);
561 if (ret < 0)
562 return ret;
563
564 av_refstruct_unref(&s->hwaccel_picture_private);
565 } else {
566 avctx->execute2(avctx, decode_tiles, frame, NULL, s->nb_tiles);
567 }
568
569 frame->pict_type = AV_PICTURE_TYPE_I;
570 frame->flags |= AV_FRAME_FLAG_KEY;
571 frame->crop_left = crop_l;
572 frame->crop_right = crop_r;
573 frame->crop_top = crop_t;
574 frame->crop_bottom = crop_b;
575
576 AVRawColorParams *rcp = av_raw_color_params_create_side_data(frame);
577 if (!rcp)
578 return AVERROR(ENOMEM);
579 rcp->type = AV_RAW_COLOR_PARAMS_PRORES_RAW;
580 rcp->black_level = av_make_q(black_level, 65535);
581 rcp->white_level = av_make_q(white_level, 65535);
582 rcp->wb_cct = wb_cct;
583
584 AVProResRawColorParams *pr = &rcp->codec.prores_raw;
585 pr->wb_red = av_d2q(wb_red, INT_MAX);
586 pr->wb_blue = av_d2q(wb_blue, INT_MAX);
587 pr->gain = av_d2q(gain, INT_MAX);
588 for (int r = 0; r < 3; r++)
589 for (int c = 0; c < 3; c++)
590 pr->color_matrix[r][c] = av_d2q(color_matrix[r][c], INT_MAX);
591
592 *got_frame_ptr = 1;
593
594 return avpkt->size;
595 }
596
597 static av_cold int decode_end(AVCodecContext *avctx)
598 {
599 ProResRAWContext *s = avctx->priv_data;
600 av_refstruct_unref(&s->hwaccel_picture_private);
601 av_freep(&s->tiles);
602 return 0;
603 }
604
605 #if HAVE_THREADS
606 static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
607 {
608 ProResRAWContext *rsrc = src->priv_data;
609 ProResRAWContext *rdst = dst->priv_data;
610
611 rdst->pix_fmt = rsrc->pix_fmt;
612 rdst->version = rsrc->version;
613
614 return 0;
615 }
616 #endif
617
618 const FFCodec ff_prores_raw_decoder = {
619 .p.name = "prores_raw",
620 CODEC_LONG_NAME("Apple ProRes RAW"),
621 .p.type = AVMEDIA_TYPE_VIDEO,
622 .p.id = AV_CODEC_ID_PRORES_RAW,
623 .priv_data_size = sizeof(ProResRAWContext),
624 .init = decode_init,
625 .close = decode_end,
626 FF_CODEC_DECODE_CB(decode_frame),
627 UPDATE_THREAD_CONTEXT(update_thread_context),
628 .p.capabilities = AV_CODEC_CAP_DR1 |
629 AV_CODEC_CAP_FRAME_THREADS |
630 AV_CODEC_CAP_SLICE_THREADS,
631 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
632 FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
633 .hw_configs = (const AVCodecHWConfigInternal *const []) {
634 #if CONFIG_PRORES_RAW_VULKAN_HWACCEL
635 HWACCEL_VULKAN(prores_raw),
636 #endif
637 #if CONFIG_PRORES_RAW_VIDEOTOOLBOX_HWACCEL
638 HWACCEL_VIDEOTOOLBOX(prores_raw),
639 #endif
640 NULL
641 },
642 };
643