Coverage Report

Created: 2026-05-16 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Globals/metadata_handle.c
Line
Count
Source
1
/*
2
* Copyright (c) 2021, Alliance for Open Media. All rights reserved
3
*
4
* This source code is subject to the terms of the BSD 2 Clause License and
5
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
* was not distributed with this source code in the LICENSE file, you can
7
* obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8
* Media Patent License 1.0 was not distributed with this source code in the
9
* PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10
*/
11
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <math.h>
15
#include <string.h>
16
17
#include "EbSvtAv1Metadata.h"
18
#include "EbSvtAv1Enc.h"
19
#include "svt_log.h"
20
#include "svt_malloc.h"
21
22
0
EB_API SvtMetadataT* svt_metadata_alloc(const uint32_t type, const uint8_t* data, const size_t sz) {
23
0
    if (!data || sz == 0) {
24
0
        return NULL;
25
0
    }
26
0
    SvtMetadataT* metadata;
27
0
    EB_MALLOC_OBJECT_NO_CHECK(metadata);
28
0
    if (!metadata) {
29
0
        return NULL;
30
0
    }
31
0
    metadata->type = type;
32
0
    EB_MALLOC_ARRAY_NO_CHECK(metadata->payload, sz);
33
0
    if (!metadata->payload) {
34
0
        EB_FREE(metadata);
35
0
        return NULL;
36
0
    }
37
0
    memcpy(metadata->payload, data, sz);
38
0
    metadata->sz = sz;
39
0
    return metadata;
40
0
}
41
42
0
EB_API void svt_metadata_free(void* ptr) {
43
0
    SvtMetadataT** metadata = (SvtMetadataT**)ptr;
44
0
    if (*metadata) {
45
0
        if ((*metadata)->payload) {
46
0
            EB_FREE_ARRAY((*metadata)->payload);
47
0
            (*metadata)->payload = NULL;
48
0
        }
49
0
        EB_FREE(*metadata);
50
0
        *metadata = NULL;
51
0
    }
52
0
}
53
54
0
EB_API SvtMetadataArrayT* svt_metadata_array_alloc(const size_t sz) {
55
0
    SvtMetadataArrayT* arr;
56
0
    EB_CALLOC_ARRAY_NO_CHECK(arr, 1);
57
0
    if (!arr) {
58
0
        return NULL;
59
0
    }
60
0
    if (sz > 0) {
61
0
        EB_CALLOC_ARRAY_NO_CHECK(arr->metadata_array, sz);
62
0
        if (!arr->metadata_array) {
63
0
            svt_metadata_array_free(&arr);
64
0
            return NULL;
65
0
        }
66
0
        arr->sz = sz;
67
0
    }
68
0
    return arr;
69
0
}
70
71
474
EB_API void svt_metadata_array_free(void* arr) {
72
474
    SvtMetadataArrayT** metadata = (SvtMetadataArrayT**)arr;
73
474
    if (*metadata) {
74
0
        if ((*metadata)->metadata_array) {
75
0
            for (size_t i = 0; i < (*metadata)->sz; i++) {
76
0
                svt_metadata_free(&((*metadata)->metadata_array[i]));
77
0
            }
78
0
            EB_FREE((*metadata)->metadata_array);
79
0
        }
80
0
        EB_FREE(*metadata);
81
0
    }
82
474
    *metadata = NULL;
83
474
}
84
85
0
EB_API int svt_add_metadata(EbBufferHeaderType* buffer, const uint32_t type, const uint8_t* data, const size_t sz) {
86
0
    if (!buffer) {
87
0
        return -1;
88
0
    }
89
0
    if (!buffer->metadata) {
90
0
        buffer->metadata = svt_metadata_array_alloc(0);
91
0
        if (!buffer->metadata) {
92
0
            return -1;
93
0
        }
94
0
    }
95
0
    SvtMetadataT* metadata = svt_metadata_alloc(type, data, sz);
96
0
    if (!metadata) {
97
0
        return -1;
98
0
    }
99
0
    EB_REALLOC_ARRAY_NO_CHECK(buffer->metadata->metadata_array, buffer->metadata->sz + 1);
100
0
    if (!buffer->metadata->metadata_array) {
101
0
        svt_metadata_free(&metadata);
102
0
        return -1;
103
0
    }
104
0
    buffer->metadata->metadata_array[buffer->metadata->sz] = metadata;
105
0
    buffer->metadata->sz++;
106
0
    return 0;
107
0
}
108
109
474
EbErrorType svt_aom_copy_metadata_buffer(EbBufferHeaderType* dst, const SvtMetadataArrayT* const src) {
110
474
    if (!dst || !src) {
111
474
        return EB_ErrorBadParameter;
112
474
    }
113
0
    EbErrorType return_error = EB_ErrorNone;
114
0
    for (size_t i = 0; i < src->sz; ++i) {
115
0
        SvtMetadataT*  current_metadata = src->metadata_array[i];
116
0
        const uint32_t type             = current_metadata->type;
117
0
        const uint8_t* payload          = current_metadata->payload;
118
0
        const size_t   sz               = current_metadata->sz;
119
120
0
        if (svt_add_metadata(dst, type, payload, sz)) {
121
0
            return_error = EB_ErrorInsufficientResources;
122
0
            SVT_ERROR("Metadata of type %d could not be added to the buffer.\n", type);
123
0
        }
124
0
    }
125
0
    return return_error;
126
474
}
127
128
0
EB_API size_t svt_metadata_size(SvtMetadataArrayT* metadata, const EbAv1MetadataType type) {
129
0
    size_t sz = 0;
130
0
    if (!metadata || !metadata->metadata_array || metadata->sz == 0) {
131
0
        return 0;
132
0
    } else {
133
0
        for (size_t i = 0; i < metadata->sz; i++) {
134
0
            SvtMetadataT* current_metadata = metadata->metadata_array[i];
135
0
            if (current_metadata && current_metadata->payload && current_metadata->type == type) {
136
0
                sz += current_metadata->sz + 1 //obu type
137
0
                    + 1 //trailing byte
138
0
                    + 1 //header size
139
0
                    + 1; //length field size
140
0
            }
141
0
        }
142
0
    }
143
0
    return sz;
144
0
}
145
146
0
static inline uint16_t intswap16(uint16_t x) {
147
0
    return x << 8 | x >> 8;
148
0
}
149
150
0
static inline uint32_t intswap32(uint32_t x) {
151
0
    return x >> 24 | (x >> 8 & 0xff00) | (x << 8 & 0xff0000) | x << 24;
152
0
}
153
154
0
static inline uint16_t clip16be(double x) {
155
0
    return intswap16(x > 65535 ? 65535 : (uint16_t)x);
156
0
}
157
158
// Parses "(d1,d2)" into two double values and returns the pointer to after the closing parenthesis.
159
// returns NULL if it fails
160
0
static inline char* parse_double(const char* p, double* d1, double* d2) {
161
0
    char* endptr;
162
0
    if (*p != '(') {
163
0
        return NULL;
164
0
    }
165
0
    *d1 = strtod(p + 1, &endptr);
166
0
    if (*endptr != ',') {
167
0
        return NULL;
168
0
    }
169
0
    *d2 = strtod(endptr + 1, &endptr);
170
0
    return *endptr == ')' ? endptr + 1 : NULL;
171
0
}
172
173
0
EB_API int svt_aom_parse_mastering_display(struct EbSvtAv1MasteringDisplayInfo* mdi, const char* md_str) {
174
0
    if (!mdi || !md_str) {
175
0
        return 0;
176
0
    }
177
0
    double gx = 0, gy = 0, bx = 0, by = 0, rx = 0, ry = 0, wx = 0, wy = 0, max_luma = 0, min_luma = 0;
178
0
    while (md_str && *md_str) {
179
0
        switch (*md_str) {
180
0
        case 'G':
181
0
        case 'g':
182
0
            md_str = parse_double(md_str + 1, &gx, &gy);
183
0
            break;
184
0
        case 'B':
185
0
        case 'b':
186
0
            md_str = parse_double(md_str + 1, &bx, &by);
187
0
            break;
188
0
        case 'R':
189
0
        case 'r':
190
0
            md_str = parse_double(md_str + 1, &rx, &ry);
191
0
            break;
192
0
        case 'W':
193
0
        case 'w':
194
0
            md_str = parse_double(md_str + 2, &wx, &wy);
195
0
            break;
196
0
        case 'L':
197
0
        case 'l':
198
0
            md_str = parse_double(md_str + 1, &max_luma, &min_luma);
199
0
            break;
200
0
        default:
201
0
            break;
202
0
        }
203
0
    }
204
0
#define between1(x) (x >= 0.0 && x <= 1.0)
205
0
    if (!between1(gx) || !between1(gy) || !between1(bx) || !between1(by) || !between1(rx) || !between1(ry) ||
206
0
        !between1(wx) || !between1(wy)) {
207
0
        SVT_WARN("Invalid mastering display info will be clipped to 0.0 to 1.0\n");
208
0
    }
209
0
#undef between1
210
0
    memset(mdi, 0, sizeof(*mdi));
211
0
    rx       = round(rx * (1 << 16));
212
0
    ry       = round(ry * (1 << 16));
213
0
    gx       = round(gx * (1 << 16));
214
0
    gy       = round(gy * (1 << 16));
215
0
    bx       = round(bx * (1 << 16));
216
0
    by       = round(by * (1 << 16));
217
0
    wx       = round(wx * (1 << 16));
218
0
    wy       = round(wy * (1 << 16));
219
0
    max_luma = round(max_luma * (1 << 8));
220
0
    min_luma = round(min_luma * (1 << 14));
221
222
0
    mdi->r = (struct EbSvtAv1ChromaPoints){
223
0
        .x = clip16be(rx),
224
0
        .y = clip16be(ry),
225
0
    };
226
0
    mdi->g = (struct EbSvtAv1ChromaPoints){
227
0
        .x = clip16be(gx),
228
0
        .y = clip16be(gy),
229
0
    };
230
0
    mdi->b = (struct EbSvtAv1ChromaPoints){
231
0
        .x = clip16be(bx),
232
0
        .y = clip16be(by),
233
0
    };
234
0
    mdi->white_point = (struct EbSvtAv1ChromaPoints){
235
0
        .x = clip16be(wx),
236
0
        .y = clip16be(wy),
237
0
    };
238
0
    mdi->max_luma = intswap32((uint32_t)max_luma);
239
0
    mdi->min_luma = intswap32((uint32_t)min_luma);
240
0
    return 1;
241
0
}
242
243
0
EB_API int svt_aom_parse_content_light_level(struct EbContentLightLevel* cll, const char* cll_str) {
244
0
    if (!cll || !cll_str) {
245
0
        return 0;
246
0
    }
247
0
    char*  endptr;
248
0
    double max_cll = strtod(cll_str, &endptr);
249
0
    if (*endptr != ',') {
250
0
        goto fail;
251
0
    }
252
0
    double max_fall = strtod(endptr + 1, &endptr);
253
0
    if (*endptr) {
254
0
        goto fail;
255
0
    }
256
0
    cll->max_cll  = clip16be(max_cll);
257
0
    cll->max_fall = clip16be(max_fall);
258
0
    return 1;
259
260
0
fail:
261
0
    SVT_WARN("Invalid cll provided\n");
262
0
    return 0;
263
0
}