FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/dovi_rpu.c
Date: 2024-04-20 14:10:07
Exec Total Coverage
Lines: 216 450 48.0%
Functions: 9 14 64.3%
Branches: 105 270 38.9%

Line Branch Exec Source
1 /*
2 * Dolby Vision RPU decoder
3 *
4 * Copyright (C) 2021 Jan Ekström
5 * Copyright (C) 2021 Niklas Haas
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/buffer.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/crc.h"
27
28 #include "avcodec.h"
29 #include "dovi_rpu.h"
30 #include "golomb.h"
31 #include "get_bits.h"
32 #include "refstruct.h"
33
34 enum {
35 RPU_COEFF_FIXED = 0,
36 RPU_COEFF_FLOAT = 1,
37 };
38
39 /**
40 * Private contents of vdr.
41 */
42 typedef struct DOVIVdr {
43 AVDOVIDataMapping mapping;
44 AVDOVIColorMetadata color;
45 } DOVIVdr;
46
47 453 void ff_dovi_ctx_unref(DOVIContext *s)
48 {
49
2/2
✓ Branch 0 taken 7248 times.
✓ Branch 1 taken 453 times.
7701 for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++)
50 7248 ff_refstruct_unref(&s->vdr[i]);
51 453 ff_refstruct_unref(&s->ext_blocks);
52 453 av_free(s->rpu_buf);
53
54 453 *s = (DOVIContext) {
55 453 .logctx = s->logctx,
56 };
57 453 }
58
59 8 void ff_dovi_ctx_flush(DOVIContext *s)
60 {
61
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 8 times.
136 for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++)
62 128 ff_refstruct_unref(&s->vdr[i]);
63 8 ff_refstruct_unref(&s->ext_blocks);
64
65 8 *s = (DOVIContext) {
66 8 .logctx = s->logctx,
67 8 .dv_profile = s->dv_profile,
68 /* preserve temporary buffer */
69 8 .rpu_buf = s->rpu_buf,
70 8 .rpu_buf_sz = s->rpu_buf_sz,
71 };
72 8 }
73
74 32 void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0)
75 {
76 32 s->logctx = s0->logctx;
77 32 s->mapping = s0->mapping;
78 32 s->color = s0->color;
79 32 s->dv_profile = s0->dv_profile;
80
2/2
✓ Branch 0 taken 512 times.
✓ Branch 1 taken 32 times.
544 for (int i = 0; i <= DOVI_MAX_DM_ID; i++)
81 512 ff_refstruct_replace(&s->vdr[i], s0->vdr[i]);
82 32 ff_refstruct_replace(&s->ext_blocks, s0->ext_blocks);
83 32 }
84
85 11 void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg)
86 {
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!cfg)
88 return;
89
90 11 s->dv_profile = cfg->dv_profile;
91 }
92
93 9535 int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame)
94 {
95 AVFrameSideData *sd;
96 AVBufferRef *buf;
97 AVDOVIMetadata *dovi;
98 size_t dovi_size, ext_sz;
99
100
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9533 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
9535 if (!s->mapping || !s->color)
101 9533 return 0; /* incomplete dovi metadata */
102
103 2 dovi = av_dovi_metadata_alloc(&dovi_size);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!dovi)
105 return AVERROR(ENOMEM);
106
107 2 buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!buf) {
109 av_free(dovi);
110 return AVERROR(ENOMEM);
111 }
112
113 2 sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf);
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!sd) {
115 av_buffer_unref(&buf);
116 return AVERROR(ENOMEM);
117 }
118
119 /* Copy only the parts of these structs known to us at compiler-time. */
120 #define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last))
121 2 COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag);
122 2 COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq_pivots);
123 2 COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal);
124 2 ext_sz = FFMIN(sizeof(AVDOVIDmData), dovi->ext_block_size);
125
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (int i = 0; i < s->num_ext_blocks; i++)
126 2 memcpy(av_dovi_get_ext(dovi, i), &s->ext_blocks[i], ext_sz);
127 2 dovi->num_ext_blocks = s->num_ext_blocks;
128 2 return 0;
129 }
130
131 static int guess_profile(const AVDOVIRpuDataHeader *hdr)
132 {
133 switch (hdr->vdr_rpu_profile) {
134 case 0:
135 if (hdr->bl_video_full_range_flag)
136 return 5;
137 break;
138 case 1:
139 if (hdr->el_spatial_resampling_filter_flag && !hdr->disable_residual_flag) {
140 if (hdr->vdr_bit_depth == 12) {
141 return 7;
142 } else {
143 return 4;
144 }
145 } else {
146 return 8;
147 }
148 }
149
150 return 0; /* unknown */
151 }
152
153 static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
154 {
155 uint64_t ipart;
156 union { uint32_t u32; float f32; } fpart;
157
158 switch (hdr->coef_data_type) {
159 case RPU_COEFF_FIXED:
160 ipart = get_ue_golomb_long(gb);
161 fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom);
162 return (ipart << hdr->coef_log2_denom) | fpart.u32;
163
164 case RPU_COEFF_FLOAT:
165 fpart.u32 = get_bits_long(gb, 32);
166 return fpart.f32 * (1LL << hdr->coef_log2_denom);
167 }
168
169 return 0; /* unreachable */
170 }
171
172 136 static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
173 {
174 int64_t ipart;
175 union { uint32_t u32; float f32; } fpart;
176
177
1/3
✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
136 switch (hdr->coef_data_type) {
178 136 case RPU_COEFF_FIXED:
179 136 ipart = get_se_golomb_long(gb);
180 136 fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom);
181 136 return ipart * (1LL << hdr->coef_log2_denom) | fpart.u32;
182
183 case RPU_COEFF_FLOAT:
184 fpart.u32 = get_bits_long(gb, 32);
185 return fpart.f32 * (1LL << hdr->coef_log2_denom);
186 }
187
188 return 0; /* unreachable */
189 }
190
191 static inline unsigned get_variable_bits(GetBitContext *gb, int n)
192 {
193 unsigned int value = get_bits(gb, n);
194 int read_more = get_bits1(gb);
195 while (read_more) {
196 value = (value + 1) << n;
197 value |= get_bits(gb, n);
198 read_more = get_bits1(gb);
199 }
200 return value;
201 }
202
203 #define VALIDATE(VAR, MIN, MAX) \
204 do { \
205 if (VAR < MIN || VAR > MAX) { \
206 av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \
207 #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \
208 goto fail; \
209 } \
210 } while (0)
211
212 2 static void parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm)
213 {
214
1/7
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2 switch (dm->level) {
215 2 case 1:
216 2 dm->l1.min_pq = get_bits(gb, 12);
217 2 dm->l1.max_pq = get_bits(gb, 12);
218 2 dm->l1.avg_pq = get_bits(gb, 12);
219 2 break;
220 case 2:
221 dm->l2.target_max_pq = get_bits(gb, 12);
222 dm->l2.trim_slope = get_bits(gb, 12);
223 dm->l2.trim_offset = get_bits(gb, 12);
224 dm->l2.trim_power = get_bits(gb, 12);
225 dm->l2.trim_chroma_weight = get_bits(gb, 12);
226 dm->l2.trim_saturation_gain = get_bits(gb, 12);
227 dm->l2.ms_weight = get_bits(gb, 13) - 8192;
228 break;
229 case 4:
230 dm->l4.anchor_pq = get_bits(gb, 12);
231 dm->l4.anchor_power = get_bits(gb, 12);
232 break;
233 case 5:
234 dm->l5.left_offset = get_bits(gb, 13);
235 dm->l5.right_offset = get_bits(gb, 13);
236 dm->l5.top_offset = get_bits(gb, 13);
237 dm->l5.bottom_offset = get_bits(gb, 13);
238 break;
239 case 6:
240 dm->l6.max_luminance = get_bits(gb, 16);
241 dm->l6.min_luminance = get_bits(gb, 16);
242 dm->l6.max_cll = get_bits(gb, 16);
243 dm->l6.max_fall = get_bits(gb, 16);
244 break;
245 case 255:
246 dm->l255.dm_run_mode = get_bits(gb, 8);
247 dm->l255.dm_run_version = get_bits(gb, 8);
248 for (int i = 0; i < 4; i++)
249 dm->l255.dm_debug[i] = get_bits(gb, 8);
250 break;
251 default:
252 av_log(s->logctx, AV_LOG_WARNING,
253 "Unknown Dolby Vision DM v1 level: %u\n", dm->level);
254 }
255 2 }
256
257 static AVCIExy get_cie_xy(GetBitContext *gb)
258 {
259 AVCIExy xy;
260 const int denom = 32767;
261 xy.x = av_make_q(get_sbits(gb, 16), denom);
262 xy.y = av_make_q(get_sbits(gb, 16), denom);
263 return xy;
264 }
265
266 static void parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm,
267 int ext_block_length)
268 {
269 switch (dm->level) {
270 case 3:
271 dm->l3.min_pq_offset = get_bits(gb, 12);
272 dm->l3.max_pq_offset = get_bits(gb, 12);
273 dm->l3.avg_pq_offset = get_bits(gb, 12);
274 break;
275 case 8:
276 dm->l8.target_display_index = get_bits(gb, 8);
277 dm->l8.trim_slope = get_bits(gb, 12);
278 dm->l8.trim_offset = get_bits(gb, 12);
279 dm->l8.trim_power = get_bits(gb, 12);
280 dm->l8.trim_chroma_weight = get_bits(gb, 12);
281 dm->l8.trim_saturation_gain = get_bits(gb, 12);
282 dm->l8.ms_weight = get_bits(gb, 12) - 8192;
283 if (ext_block_length < 12)
284 break;
285 dm->l8.target_mid_contrast = get_bits(gb, 12);
286 if (ext_block_length < 13)
287 break;
288 dm->l8.clip_trim = get_bits(gb, 12);
289 if (ext_block_length < 19)
290 break;
291 for (int i = 0; i < 6; i++)
292 dm->l8.saturation_vector_field[i] = get_bits(gb, 8);
293 if (ext_block_length < 25)
294 break;
295 for (int i = 0; i < 6; i++)
296 dm->l8.hue_vector_field[i] = get_bits(gb, 8);
297 break;
298 case 9:
299 dm->l9.source_primary_index = get_bits(gb, 8);
300 if (ext_block_length < 17)
301 break;
302 dm->l9.source_display_primaries.prim.r = get_cie_xy(gb);
303 dm->l9.source_display_primaries.prim.g = get_cie_xy(gb);
304 dm->l9.source_display_primaries.prim.b = get_cie_xy(gb);
305 dm->l9.source_display_primaries.wp = get_cie_xy(gb);
306 break;
307 case 10:
308 dm->l10.target_display_index = get_bits(gb, 8);
309 dm->l10.target_max_pq = get_bits(gb, 12);
310 dm->l10.target_min_pq = get_bits(gb, 12);
311 dm->l10.target_primary_index = get_bits(gb, 8);
312 if (ext_block_length < 21)
313 break;
314 dm->l10.target_display_primaries.prim.r = get_cie_xy(gb);
315 dm->l10.target_display_primaries.prim.g = get_cie_xy(gb);
316 dm->l10.target_display_primaries.prim.b = get_cie_xy(gb);
317 dm->l10.target_display_primaries.wp = get_cie_xy(gb);
318 break;
319 case 11:
320 dm->l11.content_type = get_bits(gb, 8);
321 dm->l11.whitepoint = get_bits(gb, 4);
322 dm->l11.reference_mode_flag = get_bits1(gb);
323 skip_bits(gb, 3); /* reserved */
324 dm->l11.sharpness = get_bits(gb, 2);
325 dm->l11.noise_reduction = get_bits(gb, 2);
326 dm->l11.mpeg_noise_reduction = get_bits(gb, 2);
327 dm->l11.frame_rate_conversion = get_bits(gb, 2);
328 dm->l11.brightness = get_bits(gb, 2);
329 dm->l11.color = get_bits(gb, 2);
330 break;
331 case 254:
332 dm->l254.dm_mode = get_bits(gb, 8);
333 dm->l254.dm_version_index = get_bits(gb, 8);
334 break;
335 default:
336 av_log(s->logctx, AV_LOG_WARNING,
337 "Unknown Dolby Vision DM v2 level: %u\n", dm->level);
338 }
339 }
340
341 2 static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver)
342 {
343 int num_ext_blocks, ext_block_length, start_pos, parsed_bits;
344
345 2 num_ext_blocks = get_ue_golomb_31(gb);
346 2 align_get_bits(gb);
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (s->num_ext_blocks + num_ext_blocks > AV_DOVI_MAX_EXT_BLOCKS)
348 return AVERROR_INVALIDDATA;
349
350
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!s->ext_blocks) {
351 1 s->ext_blocks = ff_refstruct_allocz(sizeof(AVDOVIDmData) * AV_DOVI_MAX_EXT_BLOCKS);
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->ext_blocks)
353 return AVERROR(ENOMEM);
354 }
355
356
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 while (num_ext_blocks--) {
357 2 AVDOVIDmData *dm = &s->ext_blocks[s->num_ext_blocks++];
358 2 ext_block_length = get_ue_golomb_31(gb);
359 2 dm->level = get_bits(gb, 8);
360 2 start_pos = get_bits_count(gb);
361
362
1/3
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
2 switch (ver) {
363 2 case 1: parse_ext_v1(s, gb, dm); break;
364 case 2: parse_ext_v2(s, gb, dm, ext_block_length); break;
365 }
366
367 2 parsed_bits = get_bits_count(gb) - start_pos;
368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (parsed_bits > ext_block_length * 8)
369 return AVERROR_INVALIDDATA;
370 2 skip_bits(gb, ext_block_length * 8 - parsed_bits);
371 }
372
373 2 return 0;
374 }
375
376 2 int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
377 int err_recognition)
378 {
379 2 AVDOVIRpuDataHeader *hdr = &s->header;
380 2 GetBitContext *gb = &(GetBitContext){0};
381 DOVIVdr *vdr;
382 int ret;
383
384 uint8_t rpu_type;
385 uint8_t vdr_seq_info_present;
386 uint8_t vdr_dm_metadata_present;
387 uint8_t use_prev_vdr_rpu;
388 uint8_t use_nlq;
389 uint8_t profile;
390
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (rpu_size < 5)
392 goto fail;
393
394 /* Container */
395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (s->dv_profile == 10 /* dav1.10 */) {
396 /* DV inside AV1 re-uses an EMDF container skeleton, but with fixed
397 * values - so we can effectively treat this as a magic byte sequence.
398 *
399 * The exact fields are, as follows:
400 * emdf_version : f(2) = 0
401 * key_id : f(3) = 6
402 * emdf_payload_id : f(5) = 31
403 * emdf_payload_id_ext : var(5) = 225
404 * smploffste : f(1) = 0
405 * duratione : f(1) = 0
406 * groupide : f(1) = 0
407 * codecdatae : f(1) = 0
408 * discard_unknown_payload : f(1) = 1
409 */
410 const unsigned header_magic = 0x01be6841u;
411 unsigned emdf_header, emdf_payload_size, emdf_protection;
412 if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0)
413 return ret;
414 emdf_header = get_bits_long(gb, 27);
415 VALIDATE(emdf_header, header_magic, header_magic);
416 emdf_payload_size = get_variable_bits(gb, 8);
417 VALIDATE(emdf_payload_size, 6, 512);
418 if (emdf_payload_size * 8 > get_bits_left(gb))
419 return AVERROR_INVALIDDATA;
420
421 /* The payload is not byte-aligned (off by *one* bit, curse Dolby),
422 * so copy into a fresh buffer to preserve byte alignment of the
423 * RPU struct */
424 av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, emdf_payload_size);
425 if (!s->rpu_buf)
426 return AVERROR(ENOMEM);
427 for (int i = 0; i < emdf_payload_size; i++)
428 s->rpu_buf[i] = get_bits(gb, 8);
429 rpu = s->rpu_buf;
430 rpu_size = emdf_payload_size;
431
432 /* Validate EMDF footer */
433 emdf_protection = get_bits(gb, 5 + 12);
434 VALIDATE(emdf_protection, 0x400, 0x400);
435 } else {
436 /* NAL RBSP with prefix and trailing zeroes */
437
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(rpu[0], 25, 25); /* NAL prefix */
438 2 rpu++;
439 2 rpu_size--;
440 /* Strip trailing padding bytes */
441
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 while (rpu_size && rpu[rpu_size - 1] == 0)
442 rpu_size--;
443 }
444
445
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!rpu_size || rpu[rpu_size - 1] != 0x80)
446 goto fail;
447
448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (err_recognition & AV_EF_CRCCHECK) {
449 uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE),
450 -1, rpu, rpu_size - 1)); /* exclude 0x80 */
451 if (crc) {
452 av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc);
453 if (err_recognition & AV_EF_EXPLODE)
454 goto fail;
455 }
456 }
457
458
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0)
459 return ret;
460
461 /* RPU header */
462 2 rpu_type = get_bits(gb, 6);
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (rpu_type != 2) {
464 av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type "
465 "%"PRIu8", ignoring\n", rpu_type);
466 return 0;
467 }
468
469 2 hdr->rpu_type = rpu_type;
470 2 hdr->rpu_format = get_bits(gb, 11);
471
472 /* Values specific to RPU type 2 */
473 2 hdr->vdr_rpu_profile = get_bits(gb, 4);
474 2 hdr->vdr_rpu_level = get_bits(gb, 4);
475
476 2 vdr_seq_info_present = get_bits1(gb);
477
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (vdr_seq_info_present) {
478 2 hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb);
479 2 hdr->coef_data_type = get_bits(gb, 2);
480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT);
481
1/3
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
2 switch (hdr->coef_data_type) {
482 2 case RPU_COEFF_FIXED:
483 2 hdr->coef_log2_denom = get_ue_golomb(gb);
484
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(hdr->coef_log2_denom, 13, 32);
485 2 break;
486 case RPU_COEFF_FLOAT:
487 hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */
488 break;
489 }
490
491 2 hdr->vdr_rpu_normalized_idc = get_bits(gb, 2);
492 2 hdr->bl_video_full_range_flag = get_bits1(gb);
493
494
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ((hdr->rpu_format & 0x700) == 0) {
495 2 int bl_bit_depth_minus8 = get_ue_golomb_31(gb);
496 2 int el_bit_depth_minus8 = get_ue_golomb_31(gb);
497 2 int vdr_bit_depth_minus8 = get_ue_golomb_31(gb);
498
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(bl_bit_depth_minus8, 0, 8);
499
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(el_bit_depth_minus8, 0, 8);
500
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(vdr_bit_depth_minus8, 0, 8);
501 2 hdr->bl_bit_depth = bl_bit_depth_minus8 + 8;
502 2 hdr->el_bit_depth = el_bit_depth_minus8 + 8;
503 2 hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8;
504 2 hdr->spatial_resampling_filter_flag = get_bits1(gb);
505 2 skip_bits(gb, 3); /* reserved_zero_3bits */
506 2 hdr->el_spatial_resampling_filter_flag = get_bits1(gb);
507 2 hdr->disable_residual_flag = get_bits1(gb);
508 }
509 }
510
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!hdr->bl_bit_depth) {
512 av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n");
513 goto fail;
514 }
515
516 2 vdr_dm_metadata_present = get_bits1(gb);
517 2 use_prev_vdr_rpu = get_bits1(gb);
518
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;
519
520
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 profile = s->dv_profile ? s->dv_profile : guess_profile(hdr);
521
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (profile == 5 && use_nlq) {
522 av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n");
523 goto fail;
524 }
525
526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (use_prev_vdr_rpu) {
527 int prev_vdr_rpu_id = get_ue_golomb_31(gb);
528 VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID);
529 if (!s->vdr[prev_vdr_rpu_id]) {
530 av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n",
531 prev_vdr_rpu_id);
532 goto fail;
533 }
534 vdr = s->vdr[prev_vdr_rpu_id];
535 s->mapping = &vdr->mapping;
536 } else {
537 2 int vdr_rpu_id = get_ue_golomb_31(gb);
538
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID);
539
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!s->vdr[vdr_rpu_id]) {
540 1 s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(DOVIVdr));
541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->vdr[vdr_rpu_id])
542 return AVERROR(ENOMEM);
543 }
544
545 2 vdr = s->vdr[vdr_rpu_id];
546 2 s->mapping = &vdr->mapping;
547
548 2 vdr->mapping.vdr_rpu_id = vdr_rpu_id;
549 2 vdr->mapping.mapping_color_space = get_ue_golomb_31(gb);
550 2 vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb);
551
552
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int c = 0; c < 3; c++) {
553 6 AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c];
554 6 int num_pivots_minus_2 = get_ue_golomb_31(gb);
555 6 int pivot = 0;
556
557
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1);
558 6 curve->num_pivots = num_pivots_minus_2 + 2;
559
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
32 for (int i = 0; i < curve->num_pivots; i++) {
560 26 pivot += get_bits(gb, hdr->bl_bit_depth);
561 26 curve->pivots[i] = av_clip_uint16(pivot);
562 }
563 }
564
565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (use_nlq) {
566 int nlq_pivot = 0;
567 vdr->mapping.nlq_method_idc = get_bits(gb, 3);
568
569 for (int i = 0; i < 2; i++) {
570 nlq_pivot += get_bits(gb, hdr->bl_bit_depth);
571 vdr->mapping.nlq_pivots[i] = av_clip_uint16(nlq_pivot);
572 }
573
574 /**
575 * The patent mentions another legal value, NLQ_MU_LAW, but it's
576 * not documented anywhere how to parse or apply that type of NLQ.
577 */
578 VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ);
579 } else {
580 2 vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE;
581 }
582
583 2 vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1;
584 2 vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1;
585 /* End of rpu_data_header(), start of vdr_rpu_data_payload() */
586
587
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int c = 0; c < 3; c++) {
588 6 AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c];
589
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 6 times.
26 for (int i = 0; i < curve->num_pivots - 1; i++) {
590 20 int mapping_idc = get_ue_golomb_31(gb);
591
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 VALIDATE(mapping_idc, 0, 1);
592 20 curve->mapping_idc[i] = mapping_idc;
593
2/3
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
20 switch (mapping_idc) {
594 16 case AV_DOVI_MAPPING_POLYNOMIAL: {
595 16 int poly_order_minus1 = get_ue_golomb_31(gb);
596
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
16 VALIDATE(poly_order_minus1, 0, 1);
597 16 curve->poly_order[i] = poly_order_minus1 + 1;
598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (poly_order_minus1 == 0) {
599 int linear_interp_flag = get_bits1(gb);
600 if (linear_interp_flag) {
601 /* lack of documentation/samples */
602 avpriv_request_sample(s->logctx, "Dolby Vision "
603 "linear interpolation");
604 ff_dovi_ctx_unref(s);
605 return AVERROR_PATCHWELCOME;
606 }
607 }
608
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
64 for (int k = 0; k <= curve->poly_order[i]; k++)
609 48 curve->poly_coef[i][k] = get_se_coef(gb, hdr);
610 16 break;
611 }
612 4 case AV_DOVI_MAPPING_MMR: {
613 4 int mmr_order_minus1 = get_bits(gb, 2);
614
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 VALIDATE(mmr_order_minus1, 0, 2);
615 4 curve->mmr_order[i] = mmr_order_minus1 + 1;
616 4 curve->mmr_constant[i] = get_se_coef(gb, hdr);
617
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 for (int j = 0; j < curve->mmr_order[i]; j++) {
618
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 12 times.
96 for (int k = 0; k < 7; k++)
619 84 curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr);
620 }
621 4 break;
622 }
623 }
624 }
625 }
626
627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (use_nlq) {
628 for (int c = 0; c < 3; c++) {
629 AVDOVINLQParams *nlq = &vdr->mapping.nlq[c];
630 nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth);
631 nlq->vdr_in_max = get_ue_coef(gb, hdr);
632 switch (vdr->mapping.nlq_method_idc) {
633 case AV_DOVI_NLQ_LINEAR_DZ:
634 nlq->linear_deadzone_slope = get_ue_coef(gb, hdr);
635 nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr);
636 break;
637 }
638 }
639 }
640 }
641
642
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (vdr_dm_metadata_present) {
643 AVDOVIColorMetadata *color;
644 2 int affected_dm_id = get_ue_golomb_31(gb);
645 2 int current_dm_id = get_ue_golomb_31(gb);
646
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID);
647
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID);
648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->vdr[affected_dm_id]) {
649 s->vdr[affected_dm_id] = ff_refstruct_allocz(sizeof(DOVIVdr));
650 if (!s->vdr[affected_dm_id])
651 return AVERROR(ENOMEM);
652 }
653
654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->vdr[current_dm_id]) {
655 av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n",
656 current_dm_id);
657 goto fail;
658 }
659
660 /* Update current pointer based on current_dm_id */
661 2 vdr = s->vdr[current_dm_id];
662 2 s->color = &vdr->color;
663
664 /* Update values of affected_dm_id */
665 2 vdr = s->vdr[affected_dm_id];
666 2 color = &vdr->color;
667 2 color->dm_metadata_id = affected_dm_id;
668 2 color->scene_refresh_flag = get_ue_golomb_31(gb);
669
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (int i = 0; i < 9; i++)
670 18 color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);
671
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int i = 0; i < 3; i++) {
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 int denom = profile == 4 ? (1 << 30) : (1 << 28);
673 6 unsigned offset = get_bits_long(gb, 32);
674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (offset > INT_MAX) {
675 /* Ensure the result fits inside AVRational */
676 offset >>= 1;
677 denom >>= 1;
678 }
679 6 color->ycc_to_rgb_offset[i] = av_make_q(offset, denom);
680 }
681
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (int i = 0; i < 9; i++)
682 18 color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14);
683
684 2 color->signal_eotf = get_bits(gb, 16);
685 2 color->signal_eotf_param0 = get_bits(gb, 16);
686 2 color->signal_eotf_param1 = get_bits(gb, 16);
687 2 color->signal_eotf_param2 = get_bits_long(gb, 32);
688 2 color->signal_bit_depth = get_bits(gb, 5);
689
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(color->signal_bit_depth, 8, 16);
690 2 color->signal_color_space = get_bits(gb, 2);
691 2 color->signal_chroma_format = get_bits(gb, 2);
692 2 color->signal_full_range_flag = get_bits(gb, 2);
693 2 color->source_min_pq = get_bits(gb, 12);
694 2 color->source_max_pq = get_bits(gb, 12);
695 2 color->source_diagonal = get_bits(gb, 10);
696 }
697
698 /* Parse extension blocks */
699 2 s->num_ext_blocks = 0;
700
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = parse_ext_blocks(s, gb, 1)) < 0) {
701 ff_dovi_ctx_unref(s);
702 return ret;
703 }
704
705
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) {
706 if ((ret = parse_ext_blocks(s, gb, 2)) < 0) {
707 ff_dovi_ctx_unref(s);
708 return ret;
709 }
710 }
711
712 2 return 0;
713
714 fail:
715 ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */
716 return AVERROR_INVALIDDATA;
717 }
718