FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/proresenc_kostya_common.c
Date: 2026-10-31 18:41:55
Exec Total Coverage
Lines: 53 131 40.5%
Functions: 1 3 33.3%
Branches: 22 70 31.4%

Line Branch Exec Source
1 /*
2 * Apple ProRes encoder
3 *
4 * Copyright (c) 2011 Anatoliy Wasserman
5 * Copyright (c) 2012 Konstantin Shishkov
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "libavutil/pixdesc.h"
25 #include "avcodec.h"
26 #include "bytestream.h"
27 #include "encode.h"
28 #include "proresdata.h"
29 #include <sys/types.h>
30 #include "proresenc_kostya_common.h"
31
32 static const uint8_t prores_quant_matrices[][64] = {
33 { // proxy
34 4, 7, 9, 11, 13, 14, 15, 63,
35 7, 7, 11, 12, 14, 15, 63, 63,
36 9, 11, 13, 14, 15, 63, 63, 63,
37 11, 11, 13, 14, 63, 63, 63, 63,
38 11, 13, 14, 63, 63, 63, 63, 63,
39 13, 14, 63, 63, 63, 63, 63, 63,
40 13, 63, 63, 63, 63, 63, 63, 63,
41 63, 63, 63, 63, 63, 63, 63, 63,
42 },
43 { // proxy chromas
44 4, 7, 9, 11, 13, 14, 63, 63,
45 7, 7, 11, 12, 14, 63, 63, 63,
46 9, 11, 13, 14, 63, 63, 63, 63,
47 11, 11, 13, 14, 63, 63, 63, 63,
48 11, 13, 14, 63, 63, 63, 63, 63,
49 13, 14, 63, 63, 63, 63, 63, 63,
50 13, 63, 63, 63, 63, 63, 63, 63,
51 63, 63, 63, 63, 63, 63, 63, 63
52 },
53 { // LT
54 4, 5, 6, 7, 9, 11, 13, 15,
55 5, 5, 7, 8, 11, 13, 15, 17,
56 6, 7, 9, 11, 13, 15, 15, 17,
57 7, 7, 9, 11, 13, 15, 17, 19,
58 7, 9, 11, 13, 14, 16, 19, 23,
59 9, 11, 13, 14, 16, 19, 23, 29,
60 9, 11, 13, 15, 17, 21, 28, 35,
61 11, 13, 16, 17, 21, 28, 35, 41,
62 },
63 { // standard
64 4, 4, 5, 5, 6, 7, 7, 9,
65 4, 4, 5, 6, 7, 7, 9, 9,
66 5, 5, 6, 7, 7, 9, 9, 10,
67 5, 5, 6, 7, 7, 9, 9, 10,
68 5, 6, 7, 7, 8, 9, 10, 12,
69 6, 7, 7, 8, 9, 10, 12, 15,
70 6, 7, 7, 9, 10, 11, 14, 17,
71 7, 7, 9, 10, 11, 14, 17, 21,
72 },
73 { // high quality
74 4, 4, 4, 4, 4, 4, 4, 4,
75 4, 4, 4, 4, 4, 4, 4, 4,
76 4, 4, 4, 4, 4, 4, 4, 4,
77 4, 4, 4, 4, 4, 4, 4, 5,
78 4, 4, 4, 4, 4, 4, 5, 5,
79 4, 4, 4, 4, 4, 5, 5, 6,
80 4, 4, 4, 4, 5, 5, 6, 7,
81 4, 4, 4, 4, 5, 6, 7, 7,
82 },
83 { // XQ luma
84 2, 2, 2, 2, 2, 2, 2, 2,
85 2, 2, 2, 2, 2, 2, 2, 2,
86 2, 2, 2, 2, 2, 2, 2, 2,
87 2, 2, 2, 2, 2, 2, 2, 3,
88 2, 2, 2, 2, 2, 2, 3, 3,
89 2, 2, 2, 2, 2, 3, 3, 3,
90 2, 2, 2, 2, 3, 3, 3, 4,
91 2, 2, 2, 2, 3, 3, 4, 4,
92 },
93 { // codec default
94 4, 4, 4, 4, 4, 4, 4, 4,
95 4, 4, 4, 4, 4, 4, 4, 4,
96 4, 4, 4, 4, 4, 4, 4, 4,
97 4, 4, 4, 4, 4, 4, 4, 4,
98 4, 4, 4, 4, 4, 4, 4, 4,
99 4, 4, 4, 4, 4, 4, 4, 4,
100 4, 4, 4, 4, 4, 4, 4, 4,
101 4, 4, 4, 4, 4, 4, 4, 4,
102 },
103 };
104
105 static const int prores_mb_limits[NUM_MB_LIMITS] = {
106 1620, // up to 720x576
107 2700, // up to 960x720
108 6075, // up to 1440x1080
109 9216, // up to 2048x1152
110 };
111
112 static const prores_profile prores_profile_info[6] = {
113 {
114 .full_name = "proxy",
115 .tag = MKTAG('a', 'p', 'c', 'o'),
116 .min_quant = 4,
117 .max_quant = 8,
118 .br_tab = { 300, 242, 220, 194 },
119 .quant = QUANT_MAT_PROXY,
120 .quant_chroma = QUANT_MAT_PROXY_CHROMA,
121 },
122 {
123 .full_name = "LT",
124 .tag = MKTAG('a', 'p', 'c', 's'),
125 .min_quant = 1,
126 .max_quant = 9,
127 .br_tab = { 720, 560, 490, 440 },
128 .quant = QUANT_MAT_LT,
129 .quant_chroma = QUANT_MAT_LT,
130 },
131 {
132 .full_name = "standard",
133 .tag = MKTAG('a', 'p', 'c', 'n'),
134 .min_quant = 1,
135 .max_quant = 6,
136 .br_tab = { 1050, 808, 710, 632 },
137 .quant = QUANT_MAT_STANDARD,
138 .quant_chroma = QUANT_MAT_STANDARD,
139 },
140 {
141 .full_name = "high quality",
142 .tag = MKTAG('a', 'p', 'c', 'h'),
143 .min_quant = 1,
144 .max_quant = 6,
145 .br_tab = { 1566, 1216, 1070, 950 },
146 .quant = QUANT_MAT_HQ,
147 .quant_chroma = QUANT_MAT_HQ,
148 },
149 {
150 .full_name = "4444",
151 .tag = MKTAG('a', 'p', '4', 'h'),
152 .min_quant = 1,
153 .max_quant = 6,
154 .br_tab = { 2350, 1828, 1600, 1425 },
155 .quant = QUANT_MAT_HQ,
156 .quant_chroma = QUANT_MAT_HQ,
157 },
158 {
159 .full_name = "4444XQ",
160 .tag = MKTAG('a', 'p', '4', 'x'),
161 .min_quant = 1,
162 .max_quant = 6,
163 .br_tab = { 3525, 2742, 2400, 2137 },
164 .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */
165 .quant_chroma = QUANT_MAT_HQ,
166 }
167 };
168
169 4 av_cold int ff_prores_kostya_encode_init(AVCodecContext *avctx, ProresContext *ctx,
170 enum AVPixelFormat pix_fmt)
171 {
172 int mps, i, j, min_quant;
173 4 int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT);
174
175 4 avctx->bits_per_raw_sample = 10;
176
177 4 ctx->scantable = interlaced ? ff_prores_interlaced_scan
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 : ff_prores_progressive_scan;
179
180 4 mps = ctx->mbs_per_slice;
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mps & (mps - 1)) {
182 ✗ av_log(avctx, AV_LOG_ERROR,
183 "there should be an integer power of two MBs per slice\n");
184 ✗ return AVERROR(EINVAL);
185 }
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ctx->profile == PRORES_PROFILE_AUTO) {
187 ✗ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
188 ✗ ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA ||
189 ✗ !(desc->log2_chroma_w + desc->log2_chroma_h))
190 ✗ ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ;
191 ✗ av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden "
192 ✗ "through -profile option.\n", ctx->profile == PRORES_PROFILE_4444
193 ? "4:4:4:4 profile because of the used input colorspace"
194 : "HQ profile to keep best quality");
195 }
196
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (av_pix_fmt_desc_get(pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
197 ✗ if (ctx->profile != PRORES_PROFILE_4444 &&
198 ✗ ctx->profile != PRORES_PROFILE_4444XQ) {
199 // force alpha and warn
200 ✗ av_log(avctx, AV_LOG_WARNING, "Profile selected will not "
201 "encode alpha. Override with -profile if needed.\n");
202 ✗ ctx->alpha_bits = 0;
203 }
204 ✗ if (ctx->alpha_bits & 7) {
205 ✗ av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
206 ✗ return AVERROR(EINVAL);
207 }
208 ✗ avctx->bits_per_coded_sample = 32;
209 } else {
210 4 ctx->alpha_bits = 0;
211 }
212
213 4 ctx->chroma_factor = pix_fmt == AV_PIX_FMT_YUV422P10
214 ? CFACTOR_Y422
215
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 : CFACTOR_Y444;
216 4 ctx->profile_info = prores_profile_info + ctx->profile;
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 ctx->num_planes = 3 + !!ctx->alpha_bits;
218
219 4 ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
220
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (interlaced)
222 ✗ ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
223 else
224 4 ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
225
226 4 ctx->slices_width = ctx->mb_width / mps;
227 4 ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
228 4 ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
229 4 ctx->pictures_per_frame = 1 + interlaced;
230
231
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (ctx->quant_sel == -1) {
232 4 ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
233 4 ctx->quant_chroma_mat = prores_quant_matrices[ctx->profile_info->quant_chroma];
234 } else {
235 ✗ ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
236 ✗ ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel];
237 }
238
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (strlen(ctx->vendor) != 4) {
240 ✗ av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
241 ✗ return AVERROR_INVALIDDATA;
242 }
243
244 4 ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
245
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!ctx->force_quant) {
246
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!ctx->bits_per_mb) {
247
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 for (i = 0; i < NUM_MB_LIMITS - 1; i++)
248 4 if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
249
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 ctx->pictures_per_frame)
250 4 break;
251 4 ctx->bits_per_mb = ctx->profile_info->br_tab[i];
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ctx->alpha_bits)
253 ✗ ctx->bits_per_mb *= 20;
254 ✗ } else if (ctx->bits_per_mb < 128) {
255 ✗ av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n");
256 ✗ return AVERROR_INVALIDDATA;
257 }
258
259 4 min_quant = ctx->profile_info->min_quant;
260
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 4 times.
64 for (i = min_quant; i < MAX_STORED_Q; i++) {
261
2/2
✓ Branch 0 taken 3840 times.
✓ Branch 1 taken 60 times.
3900 for (j = 0; j < 64; j++) {
262 3840 ctx->quants[i][j] = ctx->quant_mat[j] * i;
263 3840 ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i;
264 }
265 }
266 } else {
267 ✗ int ls = 0;
268 ✗ int ls_chroma = 0;
269
270 ✗ if (ctx->force_quant > 64) {
271 ✗ av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
272 ✗ return AVERROR_INVALIDDATA;
273 }
274
275 ✗ for (j = 0; j < 64; j++) {
276 ✗ ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
277 ✗ ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] * ctx->force_quant;
278 ✗ ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
279 ✗ ls_chroma += av_log2((1 << 11) / ctx->quants_chroma[0][j]) * 2 + 1;
280 }
281
282 ✗ ctx->bits_per_mb = ls * 4 + ls_chroma * 4;
283 ✗ if (ctx->chroma_factor == CFACTOR_Y444)
284 ✗ ctx->bits_per_mb += ls_chroma * 4;
285 }
286
287 4 int64_t frame_size_upper_bound = (int64_t)(ctx->pictures_per_frame *
288 4 ctx->slices_per_picture + 1) *
289 4 (2 + 2 * ctx->num_planes +
290 4 (mps * ctx->bits_per_mb) / 8)
291 + 200;
292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 ctx->slice_size_upper_bound = mps * (ctx->chroma_factor == CFACTOR_Y444 ? 768 : 512) * 8;
293
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ctx->alpha_bits) {
295 // The alpha plane is run-coded and might exceed the bit budget.
296 ✗ int alpha_slice_size = /* num pixels per slice */ mps * 256 *
297 ✗ /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3;
298 ✗ frame_size_upper_bound += (int64_t)(ctx->pictures_per_frame *
299 ✗ ctx->slices_per_picture + 1) * alpha_slice_size;
300 ✗ ctx->slice_size_upper_bound += alpha_slice_size;
301 }
302
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (frame_size_upper_bound + ctx->slice_size_upper_bound + FF_INPUT_BUFFER_MIN_SIZE > INT_MAX) {
304 ✗ av_log(avctx, AV_LOG_ERROR, "Frame too large to encode\n");
305 ✗ return AVERROR(EINVAL);
306 }
307 4 ctx->frame_size_upper_bound = frame_size_upper_bound;
308
309 4 avctx->codec_tag = ctx->profile_info->tag;
310 4 avctx->profile = ctx->profile;
311
312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 av_log(avctx, AV_LOG_DEBUG,
313 "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
314 4 ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
315 interlaced ? "yes" : "no", ctx->bits_per_mb);
316 4 av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
317 ctx->frame_size_upper_bound);
318
319 4 return 0;
320 }
321
322 ✗ uint8_t *ff_prores_kostya_write_frame_header(AVCodecContext *avctx, ProresContext *ctx,
323 uint8_t **orig_buf, int flags,
324 enum AVColorPrimaries color_primaries,
325 enum AVColorTransferCharacteristic color_trc,
326 enum AVColorSpace colorspace)
327 {
328 uint8_t *buf, *tmp;
329 uint8_t frame_flags;
330
331 // frame atom
332 ✗ *orig_buf += 4; // frame size
333 ✗ bytestream_put_be32 (orig_buf, FRAME_ID); // frame container ID
334 ✗ buf = *orig_buf;
335
336 // frame header
337 ✗ tmp = buf;
338 ✗ buf += 2; // frame header size will be stored here
339 ✗ bytestream_put_be16 (&buf, ctx->chroma_factor != CFACTOR_Y422 || ctx->alpha_bits ? 1 : 0);
340 ✗ bytestream_put_buffer(&buf, (uint8_t*)ctx->vendor, 4);
341 ✗ bytestream_put_be16 (&buf, avctx->width);
342 ✗ bytestream_put_be16 (&buf, avctx->height);
343
344 ✗ frame_flags = ctx->chroma_factor << 6;
345 ✗ if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT)
346 ✗ frame_flags |= (flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 0x04 : 0x08;
347 ✗ bytestream_put_byte (&buf, frame_flags);
348
349 ✗ bytestream_put_byte (&buf, 0); // reserved
350 ✗ bytestream_put_byte (&buf, color_primaries);
351 ✗ bytestream_put_byte (&buf, color_trc);
352 ✗ bytestream_put_byte (&buf, colorspace);
353 ✗ bytestream_put_byte (&buf, ctx->alpha_bits >> 3);
354 ✗ bytestream_put_byte (&buf, 0); // reserved
355 ✗ if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
356 ✗ bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
357 ✗ bytestream_put_buffer(&buf, ctx->quant_mat, 64); // luma quantisation matrix
358 ✗ bytestream_put_buffer(&buf, ctx->quant_chroma_mat, 64); // chroma quantisation matrix
359 } else {
360 ✗ bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used
361 }
362 ✗ bytestream_put_be16 (&tmp, buf - *orig_buf); // write back frame header size
363 ✗ return buf;
364 }
365
366 ✗ uint8_t *ff_prores_kostya_write_picture_header(ProresContext *ctx, uint8_t *buf)
367 {
368 ✗ bytestream_put_byte (&buf, 0x40); // picture header size (in bits)
369 ✗ buf += 4; // picture data size will be stored here
370 ✗ bytestream_put_be16 (&buf, ctx->slices_per_picture);
371 ✗ bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs
372 ✗ return buf;
373 }
374