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 | 397 | void ff_dovi_ctx_unref(DOVIContext *s) | |
44 | { | ||
45 |
2/2✓ Branch 0 taken 6352 times.
✓ Branch 1 taken 397 times.
|
6749 | for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++) |
46 | 6352 | av_buffer_unref(&s->vdr_ref[i]); | |
47 | |||
48 | 397 | *s = (DOVIContext) { | |
49 | 397 | .logctx = s->logctx, | |
50 | }; | ||
51 | 397 | } | |
52 | |||
53 | 6 | void ff_dovi_ctx_flush(DOVIContext *s) | |
54 | { | ||
55 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 6 times.
|
102 | for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++) |
56 | 96 | av_buffer_unref(&s->vdr_ref[i]); | |
57 | |||
58 | 6 | *s = (DOVIContext) { | |
59 | 6 | .logctx = s->logctx, | |
60 | 6 | .dv_profile = s->dv_profile, | |
61 | }; | ||
62 | 6 | } | |
63 | |||
64 | 33 | int ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) | |
65 | { | ||
66 | int ret; | ||
67 | 33 | s->logctx = s0->logctx; | |
68 | 33 | s->mapping = s0->mapping; | |
69 | 33 | s->color = s0->color; | |
70 | 33 | s->dv_profile = s0->dv_profile; | |
71 |
2/2✓ Branch 0 taken 495 times.
✓ Branch 1 taken 33 times.
|
528 | for (int i = 0; i < DOVI_MAX_DM_ID; i++) { |
72 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 495 times.
|
495 | if ((ret = av_buffer_replace(&s->vdr_ref[i], s0->vdr_ref[i])) < 0) |
73 | ✗ | goto fail; | |
74 | } | ||
75 | |||
76 | 33 | 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 | 9514 | 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 9512 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
9514 | if (!s->mapping || !s->color) |
99 | 9512 | 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 |