FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/dovi_rpu.c
Date: 2022-11-28 23:49:43
Exec Total Coverage
Lines: 173 252 68.7%
Branches: 87 177 49.2%

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
26 #include "dovi_rpu.h"
27 #include "golomb.h"
28 #include "get_bits.h"
29
30 enum {
31 RPU_COEFF_FIXED = 0,
32 RPU_COEFF_FLOAT = 1,
33 };
34
35 /**
36 * Private contents of vdr_ref.
37 */
38 typedef struct DOVIVdrRef {
39 AVDOVIDataMapping mapping;
40 AVDOVIColorMetadata color;
41 } DOVIVdrRef;
42
43 389 void ff_dovi_ctx_unref(DOVIContext *s)
44 {
45
2/2
✓ Branch 0 taken 6224 times.
✓ Branch 1 taken 389 times.
6613 for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++)
46 6224 av_buffer_unref(&s->vdr_ref[i]);
47
48 389 *s = (DOVIContext) {
49 389 .logctx = s->logctx,
50 };
51 389 }
52
53 5 void ff_dovi_ctx_flush(DOVIContext *s)
54 {
55
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 5 times.
85 for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++)
56 80 av_buffer_unref(&s->vdr_ref[i]);
57
58 5 *s = (DOVIContext) {
59 5 .logctx = s->logctx,
60 5 .dv_profile = s->dv_profile,
61 };
62 5 }
63
64 32 int ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0)
65 {
66 int ret;
67 32 s->logctx = s0->logctx;
68 32 s->mapping = s0->mapping;
69 32 s->color = s0->color;
70 32 s->dv_profile = s0->dv_profile;
71
2/2
✓ Branch 0 taken 480 times.
✓ Branch 1 taken 32 times.
512 for (int i = 0; i < DOVI_MAX_DM_ID; i++) {
72
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 480 times.
480 if ((ret = av_buffer_replace(&s->vdr_ref[i], s0->vdr_ref[i])) < 0)
73 goto fail;
74 }
75
76 32 return 0;
77
78 fail:
79 ff_dovi_ctx_unref(s);
80 return ret;
81 }
82
83 void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg)
84 {
85 if (!cfg)
86 return;
87
88 s->dv_profile = cfg->dv_profile;
89 }
90
91 9492 int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame)
92 {
93 AVFrameSideData *sd;
94 AVBufferRef *buf;
95 AVDOVIMetadata *dovi;
96 size_t dovi_size;
97
98
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9490 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
9492 if (!s->mapping || !s->color)
99 9490 return 0; /* incomplete dovi metadata */
100
101 2 dovi = av_dovi_metadata_alloc(&dovi_size);
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!dovi)
103 return AVERROR(ENOMEM);
104
105 2 buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0);
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!buf) {
107 av_free(dovi);
108 return AVERROR(ENOMEM);
109 }
110
111 2 sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf);
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!sd) {
113 av_buffer_unref(&buf);
114 return AVERROR(ENOMEM);
115 }
116
117 /* Copy only the parts of these structs known to us at compiler-time. */
118 #define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last))
119 2 COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag);
120 2 COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq[2].linear_deadzone_threshold);
121 2 COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal);
122 2 return 0;
123 }
124
125 2 static int guess_profile(const AVDOVIRpuDataHeader *hdr)
126 {
127
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 switch (hdr->vdr_rpu_profile) {
128 case 0:
129 if (hdr->bl_video_full_range_flag)
130 return 5;
131 break;
132 2 case 1:
133
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (hdr->el_spatial_resampling_filter_flag && !hdr->disable_residual_flag) {
134 if (hdr->vdr_bit_depth == 12) {
135 return 7;
136 } else {
137 return 4;
138 }
139 } else {
140 2 return 8;
141 }
142 }
143
144 return 0; /* unknown */
145 }
146
147 static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
148 {
149 uint64_t ipart;
150 union { uint32_t u32; float f32; } fpart;
151
152 switch (hdr->coef_data_type) {
153 case RPU_COEFF_FIXED:
154 ipart = get_ue_golomb_long(gb);
155 fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom);
156 return (ipart << hdr->coef_log2_denom) + fpart.u32;
157
158 case RPU_COEFF_FLOAT:
159 fpart.u32 = get_bits_long(gb, 32);
160 return fpart.f32 * (1 << hdr->coef_log2_denom);
161 }
162
163 return 0; /* unreachable */
164 }
165
166 136 static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
167 {
168 int64_t ipart;
169 union { uint32_t u32; float f32; } fpart;
170
171
1/3
✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
136 switch (hdr->coef_data_type) {
172 136 case RPU_COEFF_FIXED:
173 136 ipart = get_se_golomb_long(gb);
174 136 fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom);
175 136 return ipart * (1LL << hdr->coef_log2_denom) + fpart.u32;
176
177 case RPU_COEFF_FLOAT:
178 fpart.u32 = get_bits_long(gb, 32);
179 return fpart.f32 * (1 << hdr->coef_log2_denom);
180 }
181
182 return 0; /* unreachable */
183 }
184
185 #define VALIDATE(VAR, MIN, MAX) \
186 do { \
187 if (VAR < MIN || VAR > MAX) { \
188 av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \
189 #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \
190 goto fail; \
191 } \
192 } while (0)
193
194 2 int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size)
195 {
196 2 AVDOVIRpuDataHeader *hdr = &s->header;
197 2 GetBitContext *gb = &(GetBitContext){0};
198 DOVIVdrRef *vdr;
199 int ret;
200
201 uint8_t nal_prefix;
202 uint8_t rpu_type;
203 uint8_t vdr_seq_info_present;
204 uint8_t vdr_dm_metadata_present;
205 uint8_t use_prev_vdr_rpu;
206 uint8_t use_nlq;
207 uint8_t profile;
208
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0)
209 return ret;
210
211 /* RPU header, common values */
212 2 nal_prefix = get_bits(gb, 8);
213
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 VALIDATE(nal_prefix, 25, 25);
214 2 rpu_type = get_bits(gb, 6);
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (rpu_type != 2) {
216 av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type "
217 "%"PRIu8", ignoring\n", rpu_type);
218 return 0;
219 }
220
221 2 hdr->rpu_type = rpu_type;
222 2 hdr->rpu_format = get_bits(gb, 11);
223
224 /* Values specific to RPU type 2 */
225 2 hdr->vdr_rpu_profile = get_bits(gb, 4);
226 2 hdr->vdr_rpu_level = get_bits(gb, 4);
227
228 2 vdr_seq_info_present = get_bits1(gb);
229
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (vdr_seq_info_present) {
230 2 hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb);
231 2 hdr->coef_data_type = get_bits(gb, 2);
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT);
233
1/3
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
2 switch (hdr->coef_data_type) {
234 2 case RPU_COEFF_FIXED:
235 2 hdr->coef_log2_denom = get_ue_golomb(gb);
236
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);
237 2 break;
238 case RPU_COEFF_FLOAT:
239 hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */
240 break;
241 }
242
243 2 hdr->vdr_rpu_normalized_idc = get_bits(gb, 2);
244 2 hdr->bl_video_full_range_flag = get_bits1(gb);
245
246
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ((hdr->rpu_format & 0x700) == 0) {
247 2 int bl_bit_depth_minus8 = get_ue_golomb_31(gb);
248 2 int el_bit_depth_minus8 = get_ue_golomb_31(gb);
249 2 int vdr_bit_depth_minus8 = get_ue_golomb_31(gb);
250
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);
251
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);
252
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);
253 2 hdr->bl_bit_depth = bl_bit_depth_minus8 + 8;
254 2 hdr->el_bit_depth = el_bit_depth_minus8 + 8;
255 2 hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8;
256 2 hdr->spatial_resampling_filter_flag = get_bits1(gb);
257 2 skip_bits(gb, 3); /* reserved_zero_3bits */
258 2 hdr->el_spatial_resampling_filter_flag = get_bits1(gb);
259 2 hdr->disable_residual_flag = get_bits1(gb);
260 }
261 }
262
263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!hdr->bl_bit_depth) {
264 av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n");
265 goto fail;
266 }
267
268 2 vdr_dm_metadata_present = get_bits1(gb);
269 2 use_prev_vdr_rpu = get_bits1(gb);
270
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;
271
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 profile = s->dv_profile ? s->dv_profile : guess_profile(hdr);
273
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) {
274 av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n");
275 goto fail;
276 }
277
278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (use_prev_vdr_rpu) {
279 int prev_vdr_rpu_id = get_ue_golomb_31(gb);
280 VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID);
281 if (!s->vdr_ref[prev_vdr_rpu_id]) {
282 av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n",
283 prev_vdr_rpu_id);
284 goto fail;
285 }
286 vdr = (DOVIVdrRef *) s->vdr_ref[prev_vdr_rpu_id]->data;
287 s->mapping = &vdr->mapping;
288 } else {
289 2 int vdr_rpu_id = get_ue_golomb_31(gb);
290
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);
291
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!s->vdr_ref[vdr_rpu_id]) {
292 1 s->vdr_ref[vdr_rpu_id] = av_buffer_allocz(sizeof(DOVIVdrRef));
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->vdr_ref[vdr_rpu_id])
294 return AVERROR(ENOMEM);
295 }
296
297 2 vdr = (DOVIVdrRef *) s->vdr_ref[vdr_rpu_id]->data;
298 2 s->mapping = &vdr->mapping;
299
300 2 vdr->mapping.vdr_rpu_id = vdr_rpu_id;
301 2 vdr->mapping.mapping_color_space = get_ue_golomb_31(gb);
302 2 vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb);
303
304
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int c = 0; c < 3; c++) {
305 6 AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c];
306 6 int num_pivots_minus_2 = get_ue_golomb_31(gb);
307 6 int pivot = 0;
308
309
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);
310 6 curve->num_pivots = num_pivots_minus_2 + 2;
311
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
32 for (int i = 0; i < curve->num_pivots; i++) {
312 26 pivot += get_bits(gb, hdr->bl_bit_depth);
313 26 curve->pivots[i] = av_clip_uint16(pivot);
314 }
315 }
316
317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (use_nlq) {
318 vdr->mapping.nlq_method_idc = get_bits(gb, 3);
319 /**
320 * The patent mentions another legal value, NLQ_MU_LAW, but it's
321 * not documented anywhere how to parse or apply that type of NLQ.
322 */
323 VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ);
324 } else {
325 2 vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE;
326 }
327
328 2 vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1;
329 2 vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1;
330 /* End of rpu_data_header(), start of vdr_rpu_data_payload() */
331
332
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int c = 0; c < 3; c++) {
333 6 AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c];
334
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 6 times.
26 for (int i = 0; i < curve->num_pivots - 1; i++) {
335 20 int mapping_idc = get_ue_golomb_31(gb);
336
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);
337 20 curve->mapping_idc[i] = mapping_idc;
338
2/3
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
20 switch (mapping_idc) {
339 16 case AV_DOVI_MAPPING_POLYNOMIAL: {
340 16 int poly_order_minus1 = get_ue_golomb_31(gb);
341
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);
342 16 curve->poly_order[i] = poly_order_minus1 + 1;
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (poly_order_minus1 == 0) {
344 int linear_interp_flag = get_bits1(gb);
345 if (linear_interp_flag) {
346 /* lack of documentation/samples */
347 avpriv_request_sample(s->logctx, "Dolby Vision "
348 "linear interpolation");
349 ff_dovi_ctx_unref(s);
350 return AVERROR_PATCHWELCOME;
351 }
352 }
353
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
64 for (int k = 0; k <= curve->poly_order[i]; k++)
354 48 curve->poly_coef[i][k] = get_se_coef(gb, hdr);
355 16 break;
356 }
357 4 case AV_DOVI_MAPPING_MMR: {
358 4 int mmr_order_minus1 = get_bits(gb, 2);
359
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);
360 4 curve->mmr_order[i] = mmr_order_minus1 + 1;
361 4 curve->mmr_constant[i] = get_se_coef(gb, hdr);
362
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 for (int j = 0; j < curve->mmr_order[i]; j++) {
363
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 12 times.
96 for (int k = 0; k < 7; k++)
364 84 curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr);
365 }
366 4 break;
367 }
368 }
369 }
370 }
371
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (use_nlq) {
373 for (int c = 0; c < 3; c++) {
374 AVDOVINLQParams *nlq = &vdr->mapping.nlq[c];
375 nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth);
376 nlq->vdr_in_max = get_ue_coef(gb, hdr);
377 switch (vdr->mapping.nlq_method_idc) {
378 case AV_DOVI_NLQ_LINEAR_DZ:
379 nlq->linear_deadzone_slope = get_ue_coef(gb, hdr);
380 nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr);
381 break;
382 }
383 }
384 }
385 }
386
387
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (vdr_dm_metadata_present) {
388 AVDOVIColorMetadata *color;
389 2 int affected_dm_id = get_ue_golomb_31(gb);
390 2 int current_dm_id = get_ue_golomb_31(gb);
391
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);
392
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);
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->vdr_ref[affected_dm_id]) {
394 s->vdr_ref[affected_dm_id] = av_buffer_allocz(sizeof(DOVIVdrRef));
395 if (!s->vdr_ref[affected_dm_id])
396 return AVERROR(ENOMEM);
397 }
398
399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->vdr_ref[current_dm_id]) {
400 av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n",
401 current_dm_id);
402 goto fail;
403 }
404
405 /* Update current pointer based on current_dm_id */
406 2 vdr = (DOVIVdrRef *) s->vdr_ref[current_dm_id]->data;
407 2 s->color = &vdr->color;
408
409 /* Update values of affected_dm_id */
410 2 vdr = (DOVIVdrRef *) s->vdr_ref[affected_dm_id]->data;
411 2 color = &vdr->color;
412 2 color->dm_metadata_id = affected_dm_id;
413 2 color->scene_refresh_flag = get_ue_golomb_31(gb);
414
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (int i = 0; i < 9; i++)
415 18 color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);
416
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int i = 0; i < 3; i++) {
417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 int denom = profile == 4 ? (1 << 30) : (1 << 28);
418 6 unsigned offset = get_bits_long(gb, 32);
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (offset > INT_MAX) {
420 /* Ensure the result fits inside AVRational */
421 offset >>= 1;
422 denom >>= 1;
423 }
424 6 color->ycc_to_rgb_offset[i] = av_make_q(offset, denom);
425 }
426
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (int i = 0; i < 9; i++)
427 18 color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14);
428
429 2 color->signal_eotf = get_bits(gb, 16);
430 2 color->signal_eotf_param0 = get_bits(gb, 16);
431 2 color->signal_eotf_param1 = get_bits(gb, 16);
432 2 color->signal_eotf_param2 = get_bits_long(gb, 32);
433 2 color->signal_bit_depth = get_bits(gb, 5);
434
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);
435 2 color->signal_color_space = get_bits(gb, 2);
436 2 color->signal_chroma_format = get_bits(gb, 2);
437 2 color->signal_full_range_flag = get_bits(gb, 2);
438 2 color->source_min_pq = get_bits(gb, 12);
439 2 color->source_max_pq = get_bits(gb, 12);
440 2 color->source_diagonal = get_bits(gb, 10);
441 }
442
443 /* FIXME: verify CRC32, requires implementation of AV_CRC_32_MPEG_2 */
444 2 return 0;
445
446 fail:
447 ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */
448 return AVERROR(EINVAL);
449 }
450