Coverage Report

Created: 2026-07-25 07:52

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