Coverage Report

Created: 2026-01-23 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/media_tools/id3.c
Line
Count
Source
1
#include <gpac/id3.h>
2
3
// First 36 bytes of a Nielsen ID3 tag: "ID3\x04\x00 \x00\x00\x02\x05PRIV\x00\x00\x01{\x00\x00www.nielsen.com/"
4
static const u32 NIELSEN_ID3_TAG_PREFIX_LEN = 36;
5
static const u8 NIELSEN_ID3_TAG_PREFIX[] = {0x49, 0x44, 0x33, 0x04, 0x00, 0x20,
6
                                            0x00, 0x00, 0x02, 0x05, 0x50, 0x52,
7
                                            0x49, 0x56, 0x00, 0x00, 0x01, 0x7B,
8
                                            0x00, 0x00, 0x77, 0x77, 0x77, 0x2E,
9
                                            0x6E, 0x69, 0x65, 0x6C, 0x73, 0x65,
10
                                            0x6E, 0x2E, 0x63, 0x6F, 0x6D, 0x2F};
11
12
static const char *ID3_PROP_SCHEME_URI = "https://aomedia.org/emsg/ID3";
13
static const char *ID3_PROP_VALUE_URI_NIELSEN = "www.nielsen.com:id3:v1";
14
static const char *ID3_PROP_VALUE_URI_DEFAULT = "https://aomedia.org/emsg/ID3";
15
16
GF_EXPORT
17
GF_Err gf_id3_tag_new(GF_ID3_TAG *tag, u32 timescale, u64 pts, u8 *data, u32 data_length)
18
0
{
19
0
    if (!tag) {
20
0
        return GF_BAD_PARAM;
21
0
    }
22
23
0
    if (data == NULL || data_length == 0) {
24
0
        return GF_BAD_PARAM;
25
0
    }
26
27
0
    tag->timescale = timescale;
28
0
    tag->pts = pts;
29
0
    tag->scheme_uri = gf_strdup(ID3_PROP_SCHEME_URI);
30
0
    tag->scheme_uri_length = (u32) strlen(ID3_PROP_SCHEME_URI) + 1; // plus null character
31
32
    // test if the data is a Nielsen ID3 tag
33
0
    if ((data_length >= NIELSEN_ID3_TAG_PREFIX_LEN) && !memcmp(data, NIELSEN_ID3_TAG_PREFIX, NIELSEN_ID3_TAG_PREFIX_LEN))
34
0
    {
35
0
        tag->value_uri = gf_strdup(ID3_PROP_VALUE_URI_NIELSEN);
36
0
    }
37
0
    else
38
0
    {
39
0
        tag->value_uri = gf_strdup(ID3_PROP_VALUE_URI_DEFAULT);
40
0
    }
41
42
0
    tag->value_uri_length = (u32) strlen(tag->value_uri) + 1; // plus null character
43
44
0
    tag->data_length = data_length;
45
0
    tag->data = gf_malloc(data_length);
46
0
    memcpy(tag->data, data, data_length);
47
48
0
    return GF_OK;
49
0
}
50
51
GF_EXPORT
52
void gf_id3_tag_free(GF_ID3_TAG *tag)
53
0
{
54
0
    if (!tag) {
55
0
        return;
56
0
    }
57
58
0
    if (tag->scheme_uri) {
59
0
        gf_free(tag->scheme_uri);
60
0
        tag->scheme_uri = NULL;
61
0
    }
62
63
0
    if (tag->value_uri) {
64
0
        gf_free(tag->value_uri);
65
0
        tag->value_uri = NULL;
66
0
    }
67
68
0
    if (tag->data) {
69
0
        gf_free(tag->data);
70
0
        tag->data = NULL;
71
0
    }
72
0
}
73
74
GF_EXPORT
75
GF_Err gf_id3_to_bitstream(GF_ID3_TAG *tag, GF_BitStream *bs)
76
0
{
77
0
    if (!tag || !bs) {
78
0
        return GF_BAD_PARAM;
79
0
    }
80
81
0
    gf_bs_write_u32(bs, tag->timescale);
82
0
    gf_bs_write_u64(bs, tag->pts);
83
84
0
    gf_bs_write_u32(bs, tag->scheme_uri_length);
85
0
    u32 bytes_read = gf_bs_write_data(bs, (const u8 *)tag->scheme_uri, tag->scheme_uri_length);
86
0
    if (bytes_read != tag->scheme_uri_length) {
87
0
        return GF_IO_ERR;
88
0
    }
89
90
0
    gf_bs_write_u32(bs, tag->value_uri_length);
91
0
    bytes_read = gf_bs_write_data(bs, (const u8 *)tag->value_uri, tag->value_uri_length);
92
0
    if (bytes_read != tag->value_uri_length) {
93
0
        return GF_IO_ERR;
94
0
    }
95
96
0
    gf_bs_write_u32(bs, tag->data_length);
97
0
    bytes_read = gf_bs_write_data(bs, tag->data, tag->data_length);
98
0
    if (bytes_read != tag->data_length) {
99
0
        return GF_IO_ERR;
100
0
    }
101
102
0
    return GF_OK;
103
0
}
104
105
GF_EXPORT
106
0
GF_Err gf_id3_list_to_bitstream(GF_List *tag_list, GF_BitStream *bs) {
107
108
0
    GF_Err err = GF_OK;
109
110
    // first, write the number of tags
111
0
    u32 id3_count = gf_list_count(tag_list);
112
0
    gf_bs_write_u32(bs, id3_count);
113
114
0
    for (u32 i = 0; i < id3_count; ++i) {
115
0
        GF_ID3_TAG *tag = gf_list_get(tag_list, i);
116
0
        err = gf_id3_to_bitstream(tag, bs);
117
0
        if (err != GF_OK) {
118
0
            return err;
119
0
        }
120
0
    }
121
122
0
    return err;
123
0
}
124
125
GF_EXPORT
126
GF_Err gf_id3_from_bitstream(GF_ID3_TAG *tag, GF_BitStream *bs)
127
0
{
128
0
    if (!tag || !bs) {
129
0
        return GF_BAD_PARAM;
130
0
    }
131
132
0
    tag->timescale = gf_bs_read_u32(bs);
133
0
    tag->pts = gf_bs_read_u64(bs);
134
135
0
    tag->scheme_uri_length = gf_bs_read_u32(bs);
136
0
    tag->scheme_uri = gf_malloc(tag->scheme_uri_length);
137
0
    u32 bytes_read = gf_bs_read_data(bs, tag->scheme_uri, tag->scheme_uri_length);
138
0
    if (bytes_read != tag->scheme_uri_length) {
139
0
        return GF_IO_ERR;
140
0
    }
141
142
0
    tag->value_uri_length = gf_bs_read_u32(bs);
143
0
    tag->value_uri = gf_malloc(tag->value_uri_length);
144
0
    bytes_read = gf_bs_read_data(bs, tag->value_uri, tag->value_uri_length);
145
0
    if (bytes_read != tag->value_uri_length) {
146
0
        return GF_IO_ERR;
147
0
    }
148
149
0
    tag->data_length = gf_bs_read_u32(bs);
150
0
    tag->data = gf_malloc(tag->data_length);
151
0
    bytes_read = gf_bs_read_data(bs, tag->data, tag->data_length);
152
0
    if (bytes_read != tag->data_length) {
153
0
        return GF_IO_ERR;
154
0
    }
155
156
0
    return GF_OK;
157
0
}