FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/prores_raw.c
Date: 2026-01-23 19:11:46
Exec Total Coverage
Lines: 0 281 0.0%
Functions: 0 9 0.0%
Branches: 0 118 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/intreadwrite.h"
24 #include "libavutil/mem_internal.h"
25 #include "libavutil/mem.h"
26
27 #define CACHED_BITSTREAM_READER !ARCH_X86_32
28
29 #include "config_components.h"
30 #include "avcodec.h"
31 #include "bytestream.h"
32 #include "codec_internal.h"
33 #include "decode.h"
34 #include "get_bits.h"
35 #include "idctdsp.h"
36 #include "proresdata.h"
37 #include "thread.h"
38 #include "hwconfig.h"
39 #include "hwaccel_internal.h"
40
41 #include "prores_raw.h"
42
43 static av_cold int decode_init(AVCodecContext *avctx)
44 {
45 ProResRAWContext *s = avctx->priv_data;
46
47 avctx->bits_per_raw_sample = 12;
48 avctx->color_primaries = AVCOL_PRI_UNSPECIFIED;
49 avctx->color_trc = AVCOL_TRC_UNSPECIFIED;
50 avctx->colorspace = AVCOL_SPC_UNSPECIFIED;
51
52 s->pix_fmt = AV_PIX_FMT_NONE;
53
54 ff_blockdsp_init(&s->bdsp);
55 ff_proresdsp_init(&s->prodsp, avctx->bits_per_raw_sample);
56
57 ff_permute_scantable(s->scan, ff_prores_interlaced_scan, s->prodsp.idct_permutation);
58
59 return 0;
60 }
61
62 static uint16_t get_value(GetBitContext *gb, int16_t codebook)
63 {
64 const int16_t switch_bits = codebook >> 8;
65 const int16_t rice_order = codebook & 0xf;
66 const int16_t exp_order = (codebook >> 4) & 0xf;
67 int16_t q, bits;
68
69 uint32_t b = show_bits_long(gb, 32);
70 if (!b)
71 return 0;
72 q = ff_clz(b);
73
74 if (b & 0x80000000) {
75 skip_bits_long(gb, 1 + rice_order);
76 return (b & 0x7FFFFFFF) >> (31 - rice_order);
77 }
78
79 if (q <= switch_bits) {
80 skip_bits_long(gb, 1 + rice_order + q);
81 return (q << rice_order) +
82 (((b << (q + 1)) >> 1) >> (31 - rice_order));
83 }
84
85 bits = exp_order + (q << 1) - switch_bits;
86 if (bits > 32)
87 return 0; // we do not return a negative error code so that we dont produce out of range values on errors
88 skip_bits_long(gb, bits);
89 return (b >> (32 - bits)) +
90 ((switch_bits + 1) << rice_order) -
91 (1 << exp_order);
92 }
93
94 #define TODCCODEBOOK(x) ((x + 1) >> 1)
95
96 #define DC_CB_MAX 12
97 const uint8_t ff_prores_raw_dc_cb[DC_CB_MAX + 1] = {
98 0x010, 0x021, 0x032, 0x033, 0x033, 0x033, 0x044, 0x044, 0x044, 0x044, 0x044, 0x044, 0x076,
99 };
100
101 #define AC_CB_MAX 94
102 const int16_t ff_prores_raw_ac_cb[AC_CB_MAX + 1] = {
103 0x000, 0x211, 0x111, 0x111, 0x222, 0x222, 0x222, 0x122, 0x122, 0x122,
104 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x133, 0x133,
105 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244,
106 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244, 0x244,
107 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355,
108 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355,
109 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355,
110 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x355, 0x166,
111 };
112
113 #define RN_CB_MAX 27
114 const int16_t ff_prores_raw_rn_cb[RN_CB_MAX + 1] = {
115 0x200, 0x100, 0x000, 0x000, 0x211, 0x211, 0x111, 0x111, 0x011, 0x011, 0x021, 0x021, 0x222, 0x022,
116 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x022, 0x032, 0x032, 0x044
117 };
118
119 #define LN_CB_MAX 14
120 const int16_t ff_prores_raw_ln_cb[LN_CB_MAX + 1] = {
121 0x100, 0x111, 0x222, 0x222, 0x122, 0x122, 0x433, 0x433, 0x233, 0x233, 0x233, 0x233, 0x233, 0x233, 0x033,
122 };
123
124 static int decode_comp(AVCodecContext *avctx, TileContext *tile,
125 AVFrame *frame, const uint8_t *data, int size,
126 int component, int16_t *qmat)
127 {
128 int ret;
129 ProResRAWContext *s = avctx->priv_data;
130 const ptrdiff_t linesize = frame->linesize[0] >> 1;
131 uint16_t *dst = (uint16_t *)(frame->data[0] + tile->y*frame->linesize[0] + 2*tile->x);
132
133 int idx;
134 const int w = FFMIN(s->tw, avctx->width - tile->x) / 2;
135 const int nb_blocks = w / 8;
136 const int log2_nb_blocks = 31 - ff_clz(nb_blocks);
137 const int block_mask = (1 << log2_nb_blocks) - 1;
138 const int nb_codes = 64 * nb_blocks;
139
140 LOCAL_ALIGNED_32(int16_t, block, [64*16]);
141
142 int16_t sign = 0;
143 int16_t dc_add = 0;
144 int16_t dc_codebook;
145
146 uint16_t ac, rn, ln;
147 int16_t ac_codebook = 49;
148 int16_t rn_codebook = 0;
149 int16_t ln_codebook = 66;
150
151 const uint8_t *scan = s->scan;
152 GetBitContext gb;
153
154 if (component > 1)
155 dst += linesize;
156 dst += component & 1;
157
158 if ((ret = init_get_bits8(&gb, data, size)) < 0)
159 return ret;
160
161 for (int n = 0; n < nb_blocks; n++)
162 s->bdsp.clear_block(block + n*64);
163
164 /* Special handling for first block */
165 int dc = get_value(&gb, 700);
166 int prev_dc = (dc >> 1) ^ -(dc & 1);
167 block[0] = (((dc&1) + (dc>>1) ^ -(int)(dc & 1)) + (dc & 1)) + 1;
168
169 for (int n = 1; n < nb_blocks; n++) {
170 if (get_bits_left(&gb) <= 0)
171 break;
172
173 if ((n & 15) == 1)
174 dc_codebook = 100;
175 else
176 dc_codebook = ff_prores_raw_dc_cb[FFMIN(TODCCODEBOOK(dc), DC_CB_MAX)];
177
178 dc = get_value(&gb, dc_codebook);
179
180 sign = sign ^ dc & 1;
181 dc_add = (-sign ^ TODCCODEBOOK(dc)) + sign;
182 sign = dc_add < 0;
183 prev_dc += dc_add;
184
185 block[n*64] = prev_dc + 1;
186 }
187
188 for (int n = nb_blocks; n <= nb_codes;) {
189 if (get_bits_left(&gb) <= 0)
190 break;
191
192 ln = get_value(&gb, ln_codebook);
193
194 for (int i = 0; i < ln; i++) {
195 if (get_bits_left(&gb) <= 0)
196 break;
197
198 if ((n + i) >= nb_codes)
199 break;
200
201 ac = get_value(&gb, ac_codebook);
202 ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
203 sign = -get_bits1(&gb);
204
205 idx = scan[(n + i) >> log2_nb_blocks] + (((n + i) & block_mask) << 6);
206 block[idx] = ((ac + 1) ^ sign) - sign;
207 }
208
209 n += ln;
210 if (n >= nb_codes)
211 break;
212
213 rn = get_value(&gb, rn_codebook);
214 rn_codebook = ff_prores_raw_rn_cb[FFMIN(rn, RN_CB_MAX)];
215
216 n += rn + 1;
217 if (n >= nb_codes)
218 break;
219
220 if (get_bits_left(&gb) <= 0)
221 break;
222
223 ac = get_value(&gb, ac_codebook);
224 sign = -get_bits1(&gb);
225
226 idx = scan[n >> log2_nb_blocks] + ((n & block_mask) << 6);
227 block[idx] = ((ac + 1) ^ sign) - sign;
228
229 ac_codebook = ff_prores_raw_ac_cb[FFMIN(ac, AC_CB_MAX)];
230 ln_codebook = ff_prores_raw_ln_cb[FFMIN(ac, LN_CB_MAX)];
231
232 n++;
233 }
234
235 for (int n = 0; n < nb_blocks; n++) {
236 uint16_t *ptr = dst + n*16;
237 s->prodsp.idct_put_bayer(ptr, linesize, block + n*64, qmat);
238 }
239
240 return 0;
241 }
242
243 static int decode_tile(AVCodecContext *avctx, TileContext *tile,
244 AVFrame *frame)
245 {
246 int ret;
247 ProResRAWContext *s = avctx->priv_data;
248
249 GetByteContext *gb = &tile->gb;
250 LOCAL_ALIGNED_32(int16_t, qmat, [64]);
251
252 if (tile->x >= avctx->width)
253 return 0;
254
255 /* Tile header */
256 int header_len = bytestream2_get_byteu(gb) >> 3;
257 int16_t scale = bytestream2_get_byteu(gb);
258
259 int size[4];
260 size[0] = bytestream2_get_be16(gb);
261 size[1] = bytestream2_get_be16(gb);
262 size[2] = bytestream2_get_be16(gb);
263 size[3] = bytestream2_size(gb) - size[0] - size[1] - size[2] - header_len;
264 if (size[3] < 0)
265 return AVERROR_INVALIDDATA;
266
267 for (int i = 0; i < 64; i++)
268 qmat[i] = s->qmat[i] * scale >> 1;
269
270 const uint8_t *comp_start = gb->buffer_start + header_len;
271
272 ret = decode_comp(avctx, tile, frame, comp_start,
273 size[0], 2, qmat);
274 if (ret < 0)
275 goto fail;
276
277 ret = decode_comp(avctx, tile, frame, comp_start + size[0],
278 size[1], 1, qmat);
279 if (ret < 0)
280 goto fail;
281
282 ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1],
283 size[2], 3, qmat);
284 if (ret < 0)
285 goto fail;
286
287 ret = decode_comp(avctx, tile, frame, comp_start + size[0] + size[1] + size[2],
288 size[3], 0, qmat);
289 if (ret < 0)
290 goto fail;
291
292 return 0;
293 fail:
294 av_log(avctx, AV_LOG_ERROR, "tile %d/%d decoding error\n", tile->x, tile->y);
295 return ret;
296 }
297
298 static int decode_tiles(AVCodecContext *avctx, void *arg,
299 int n, int thread_nb)
300 {
301 ProResRAWContext *s = avctx->priv_data;
302 TileContext *tile = &s->tiles[n];
303 AVFrame *frame = arg;
304
305 return decode_tile(avctx, tile, frame);
306 }
307
308 static enum AVPixelFormat get_pixel_format(AVCodecContext *avctx,
309 enum AVPixelFormat pix_fmt)
310 {
311 enum AVPixelFormat pix_fmts[] = {
312 #if CONFIG_PRORES_RAW_VULKAN_HWACCEL
313 AV_PIX_FMT_VULKAN,
314 #endif
315 pix_fmt,
316 AV_PIX_FMT_NONE,
317 };
318
319 return ff_get_format(avctx, pix_fmts);
320 }
321
322 static int decode_frame(AVCodecContext *avctx,
323 AVFrame *frame, int *got_frame_ptr,
324 AVPacket *avpkt)
325 {
326 ProResRAWContext *s = avctx->priv_data;
327 int ret, dimensions_changed = 0, old_version = s->version;
328 DECLARE_ALIGNED(32, uint8_t, qmat)[64];
329 memset(qmat, 1, 64);
330
331 if (avctx->skip_frame >= AVDISCARD_ALL)
332 return avpkt->size;
333
334 switch (avctx->codec_tag) {
335 case 0:
336 break;
337 case MKTAG('a','p','r','n'):
338 avctx->profile = AV_PROFILE_PRORES_RAW;
339 break;
340 case MKTAG('a','p','r','h'):
341 avctx->profile = AV_PROFILE_PRORES_RAW_HQ;
342 break;
343 default:
344 avpriv_request_sample(avctx, "Profile %d", avctx->codec_tag);
345 return AVERROR_PATCHWELCOME;
346 break;
347 }
348
349 GetByteContext gb;
350 bytestream2_init(&gb, avpkt->data, avpkt->size);
351 if (bytestream2_get_be32(&gb) != avpkt->size)
352 return AVERROR_INVALIDDATA;
353
354 /* ProRes RAW frame */
355 if (bytestream2_get_be32(&gb) != MKBETAG('p','r','r','f'))
356 return AVERROR_INVALIDDATA;
357
358 int header_len = bytestream2_get_be16(&gb);
359 if (header_len < 62 || bytestream2_get_bytes_left(&gb) < header_len - 2)
360 return AVERROR_INVALIDDATA;
361
362 GetByteContext gb_hdr;
363 bytestream2_init(&gb_hdr, gb.buffer, header_len - 2);
364 bytestream2_skip(&gb, header_len - 2);
365
366 bytestream2_skip(&gb_hdr, 1);
367 s->version = bytestream2_get_byte(&gb_hdr);
368 if (s->version > 1) {
369 avpriv_request_sample(avctx, "Version %d", s->version);
370 return AVERROR_PATCHWELCOME;
371 }
372
373 /* Vendor header (e.g. "peac" for Panasonic or "atm0" for Atmos) */
374 bytestream2_skip(&gb_hdr, 4);
375
376 /* Width and height must always be even */
377 int w = bytestream2_get_be16(&gb_hdr);
378 int h = bytestream2_get_be16(&gb_hdr);
379 if ((w & 1) || (h & 1))
380 return AVERROR_INVALIDDATA;
381
382 if (w != avctx->width || h != avctx->height) {
383 av_log(avctx, AV_LOG_WARNING, "picture resolution change: %ix%i -> %ix%i\n",
384 avctx->width, avctx->height, w, h);
385 if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
386 return ret;
387 dimensions_changed = 1;
388 }
389
390 avctx->coded_width = FFALIGN(w, 16);
391 avctx->coded_height = FFALIGN(h, 16);
392
393 enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16;
394 if (pix_fmt != s->pix_fmt || dimensions_changed ||
395 s->version != old_version) {
396 s->pix_fmt = pix_fmt;
397
398 ret = get_pixel_format(avctx, pix_fmt);
399 if (ret < 0)
400 return ret;
401
402 avctx->pix_fmt = ret;
403 }
404
405 bytestream2_skip(&gb_hdr, 1 * 4);
406 bytestream2_skip(&gb_hdr, 2); /* & 0x3 */
407 bytestream2_skip(&gb_hdr, 2);
408 bytestream2_skip(&gb_hdr, 4);
409 bytestream2_skip(&gb_hdr, 4);
410 bytestream2_skip(&gb_hdr, 4 * 3 * 3);
411 bytestream2_skip(&gb_hdr, 4);
412 bytestream2_skip(&gb_hdr, 2);
413
414 /* Flags */
415 int flags = bytestream2_get_be16(&gb_hdr);
416 int align = (flags >> 1) & 0x7;
417
418 /* Quantization matrix */
419 if (flags & 1)
420 bytestream2_get_buffer(&gb_hdr, qmat, 64);
421
422 if ((flags >> 4) & 1) {
423 bytestream2_skip(&gb_hdr, 2);
424 bytestream2_skip(&gb_hdr, 2 * 7);
425 }
426
427 ff_permute_scantable(s->qmat, s->prodsp.idct_permutation, qmat);
428
429 s->nb_tw = (w + 15) >> 4;
430 s->nb_th = (h + 15) >> 4;
431 s->nb_tw = (s->nb_tw >> align) + av_popcount(~(-1 * (1 << align)) & s->nb_tw);
432 s->nb_tiles = s->nb_tw * s->nb_th;
433 av_log(avctx, AV_LOG_DEBUG, "%dx%d | nb_tiles: %d\n", s->nb_tw, s->nb_th, s->nb_tiles);
434
435 s->tw = s->version == 0 ? 128 : 256;
436 s->th = 16;
437 av_log(avctx, AV_LOG_DEBUG, "tile_size: %dx%d\n", s->tw, s->th);
438
439 av_fast_mallocz(&s->tiles, &s->tiles_size, s->nb_tiles * sizeof(*s->tiles));
440 if (!s->tiles)
441 return AVERROR(ENOMEM);
442
443 if (bytestream2_get_bytes_left(&gb) < s->nb_tiles * 2)
444 return AVERROR_INVALIDDATA;
445
446 /* Read tile data offsets */
447 int offset = bytestream2_tell(&gb) + s->nb_tiles * 2;
448 for (int n = 0; n < s->nb_tiles; n++) {
449 TileContext *tile = &s->tiles[n];
450
451 int size = bytestream2_get_be16(&gb);
452 if (offset >= avpkt->size)
453 return AVERROR_INVALIDDATA;
454 if (size >= avpkt->size)
455 return AVERROR_INVALIDDATA;
456 if (offset > avpkt->size - size)
457 return AVERROR_INVALIDDATA;
458
459 bytestream2_init(&tile->gb, avpkt->data + offset, size);
460
461 tile->y = (n / s->nb_tw) * s->th;
462 tile->x = (n % s->nb_tw) * s->tw;
463
464 offset += size;
465 }
466
467 ret = ff_thread_get_buffer(avctx, frame, 0);
468 if (ret < 0)
469 return ret;
470
471 s->frame = frame;
472
473 /* Start */
474 if (avctx->hwaccel) {
475 const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
476
477 ret = ff_hwaccel_frame_priv_alloc(avctx, &s->hwaccel_picture_private);
478 if (ret < 0)
479 return ret;
480
481 ret = hwaccel->start_frame(avctx, avpkt->buf, avpkt->data, avpkt->size);
482 if (ret < 0)
483 return ret;
484
485 for (int n = 0; n < s->nb_tiles; n++) {
486 TileContext *tile = &s->tiles[n];
487 ret = hwaccel->decode_slice(avctx, tile->gb.buffer,
488 tile->gb.buffer_end - tile->gb.buffer);
489 if (ret < 0)
490 return ret;
491 }
492
493 ret = hwaccel->end_frame(avctx);
494 if (ret < 0)
495 return ret;
496
497 av_refstruct_unref(&s->hwaccel_picture_private);
498 } else {
499 avctx->execute2(avctx, decode_tiles, frame, NULL, s->nb_tiles);
500 }
501
502 frame->pict_type = AV_PICTURE_TYPE_I;
503 frame->flags |= AV_FRAME_FLAG_KEY;
504
505 *got_frame_ptr = 1;
506
507 return avpkt->size;
508 }
509
510 static av_cold int decode_end(AVCodecContext *avctx)
511 {
512 ProResRAWContext *s = avctx->priv_data;
513 av_refstruct_unref(&s->hwaccel_picture_private);
514 av_freep(&s->tiles);
515 return 0;
516 }
517
518 #if HAVE_THREADS
519 static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
520 {
521 ProResRAWContext *rsrc = src->priv_data;
522 ProResRAWContext *rdst = dst->priv_data;
523
524 rdst->pix_fmt = rsrc->pix_fmt;
525 rdst->version = rsrc->version;
526
527 return 0;
528 }
529 #endif
530
531 const FFCodec ff_prores_raw_decoder = {
532 .p.name = "prores_raw",
533 CODEC_LONG_NAME("Apple ProRes RAW"),
534 .p.type = AVMEDIA_TYPE_VIDEO,
535 .p.id = AV_CODEC_ID_PRORES_RAW,
536 .priv_data_size = sizeof(ProResRAWContext),
537 .init = decode_init,
538 .close = decode_end,
539 FF_CODEC_DECODE_CB(decode_frame),
540 UPDATE_THREAD_CONTEXT(update_thread_context),
541 .p.capabilities = AV_CODEC_CAP_DR1 |
542 AV_CODEC_CAP_FRAME_THREADS |
543 AV_CODEC_CAP_SLICE_THREADS,
544 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
545 FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
546 .hw_configs = (const AVCodecHWConfigInternal *const []) {
547 #if CONFIG_PRORES_RAW_VULKAN_HWACCEL
548 HWACCEL_VULKAN(prores_raw),
549 #endif
550 NULL
551 },
552 };
553