FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/dovi_rpudec.c
Date: 2024-07-16 12:46:59
Exec Total Coverage
Lines: 190 417 45.6%
Functions: 5 9 55.6%
Branches: 104 265 39.2%

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