blob: 7fda67bb15264faa38982878746a2c7d4bd8cd50 [file] [edit]
#include <gpac/id3.h>
// First 36 bytes of a Nielsen ID3 tag: "ID3\x04\x00 \x00\x00\x02\x05PRIV\x00\x00\x01{\x00\x00www.nielsen.com/"
static const u32 NIELSEN_ID3_TAG_PREFIX_LEN = 36;
static const u8 NIELSEN_ID3_TAG_PREFIX[] = {0x49, 0x44, 0x33, 0x04, 0x00, 0x20,
0x00, 0x00, 0x02, 0x05, 0x50, 0x52,
0x49, 0x56, 0x00, 0x00, 0x01, 0x7B,
0x00, 0x00, 0x77, 0x77, 0x77, 0x2E,
0x6E, 0x69, 0x65, 0x6C, 0x73, 0x65,
0x6E, 0x2E, 0x63, 0x6F, 0x6D, 0x2F};
static const char *ID3_PROP_SCHEME_URI = "https://aomedia.org/emsg/ID3";
static const char *ID3_PROP_VALUE_URI_NIELSEN = "www.nielsen.com:id3:v1";
static const char *ID3_PROP_VALUE_URI_DEFAULT = "https://aomedia.org/emsg/ID3";
GF_EXPORT
GF_Err gf_id3_tag_new(GF_ID3_TAG *tag, u32 timescale, u64 pts, u8 *data, u32 data_length)
{
if (!tag) {
return GF_BAD_PARAM;
}
if (data == NULL || data_length == 0) {
return GF_BAD_PARAM;
}
tag->timescale = timescale;
tag->pts = pts;
tag->scheme_uri = gf_strdup(ID3_PROP_SCHEME_URI);
tag->scheme_uri_length = (u32) strlen(ID3_PROP_SCHEME_URI) + 1; // plus null character
// test if the data is a Nielsen ID3 tag
if ((data_length >= NIELSEN_ID3_TAG_PREFIX_LEN) && !memcmp(data, NIELSEN_ID3_TAG_PREFIX, NIELSEN_ID3_TAG_PREFIX_LEN))
{
tag->value_uri = gf_strdup(ID3_PROP_VALUE_URI_NIELSEN);
}
else
{
tag->value_uri = gf_strdup(ID3_PROP_VALUE_URI_DEFAULT);
}
tag->value_uri_length = (u32) strlen(tag->value_uri) + 1; // plus null character
tag->data_length = data_length;
tag->data = gf_malloc(data_length);
memcpy(tag->data, data, data_length);
return GF_OK;
}
GF_EXPORT
void gf_id3_tag_free(GF_ID3_TAG *tag)
{
if (!tag) {
return;
}
if (tag->scheme_uri) {
gf_free(tag->scheme_uri);
tag->scheme_uri = NULL;
}
if (tag->value_uri) {
gf_free(tag->value_uri);
tag->value_uri = NULL;
}
if (tag->data) {
gf_free(tag->data);
tag->data = NULL;
}
}
GF_EXPORT
GF_Err gf_id3_to_bitstream(GF_ID3_TAG *tag, GF_BitStream *bs)
{
if (!tag || !bs) {
return GF_BAD_PARAM;
}
gf_bs_write_u32(bs, tag->timescale);
gf_bs_write_u64(bs, tag->pts);
gf_bs_write_u32(bs, tag->scheme_uri_length);
u32 bytes_read = gf_bs_write_data(bs, (const u8 *)tag->scheme_uri, tag->scheme_uri_length);
if (bytes_read != tag->scheme_uri_length) {
return GF_IO_ERR;
}
gf_bs_write_u32(bs, tag->value_uri_length);
bytes_read = gf_bs_write_data(bs, (const u8 *)tag->value_uri, tag->value_uri_length);
if (bytes_read != tag->value_uri_length) {
return GF_IO_ERR;
}
gf_bs_write_u32(bs, tag->data_length);
bytes_read = gf_bs_write_data(bs, tag->data, tag->data_length);
if (bytes_read != tag->data_length) {
return GF_IO_ERR;
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_id3_list_to_bitstream(GF_List *tag_list, GF_BitStream *bs) {
GF_Err err = GF_OK;
// first, write the number of tags
u32 id3_count = gf_list_count(tag_list);
gf_bs_write_u32(bs, id3_count);
for (u32 i = 0; i < id3_count; ++i) {
GF_ID3_TAG *tag = gf_list_get(tag_list, i);
err = gf_id3_to_bitstream(tag, bs);
if (err != GF_OK) {
return err;
}
}
return err;
}
GF_EXPORT
GF_Err gf_id3_from_bitstream(GF_ID3_TAG *tag, GF_BitStream *bs)
{
if (!tag || !bs) {
return GF_BAD_PARAM;
}
tag->timescale = gf_bs_read_u32(bs);
tag->pts = gf_bs_read_u64(bs);
tag->scheme_uri_length = gf_bs_read_u32(bs);
tag->scheme_uri = gf_malloc(tag->scheme_uri_length);
u32 bytes_read = gf_bs_read_data(bs, tag->scheme_uri, tag->scheme_uri_length);
if (bytes_read != tag->scheme_uri_length) {
return GF_IO_ERR;
}
tag->value_uri_length = gf_bs_read_u32(bs);
tag->value_uri = gf_malloc(tag->value_uri_length);
bytes_read = gf_bs_read_data(bs, tag->value_uri, tag->value_uri_length);
if (bytes_read != tag->value_uri_length) {
return GF_IO_ERR;
}
tag->data_length = gf_bs_read_u32(bs);
tag->data = gf_malloc(tag->data_length);
bytes_read = gf_bs_read_data(bs, tag->data, tag->data_length);
if (bytes_read != tag->data_length) {
return GF_IO_ERR;
}
return GF_OK;
}