FFmpeg coverage


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