blob: 566a2adc346825d27eed982c1d7d2e09d36b208d [file] [edit]
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre
* Copyright (c) Telecom ParisTech 2000-2023
* All rights reserved
*
* This file is part of GPAC / ISO Media File Format sub-project
*
* GPAC is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GPAC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <gpac/internal/isomedia_dev.h>
#include <gpac/tools.h>
#ifndef GPAC_DISABLE_ISOM
GF_Box *gppc_box_new()
{
//default type is amr but overwritten by box constructor
ISOM_DECL_BOX_ALLOC(GF_3GPPConfigBox, GF_ISOM_BOX_TYPE_DAMR);
return (GF_Box *)tmp;
}
void gppc_box_del(GF_Box *s)
{
GF_3GPPConfigBox *ptr = (GF_3GPPConfigBox *)s;
if (ptr == NULL) return;
gf_free(ptr);
}
GF_Err gppc_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_3GPPConfigBox *ptr = (GF_3GPPConfigBox *)s;
if (ptr == NULL) return GF_BAD_PARAM;
memset(&ptr->cfg, 0, sizeof(GF_3GPConfig));
ISOM_DECREASE_SIZE(s, 5)
ptr->cfg.vendor = gf_bs_read_u32(bs);
ptr->cfg.decoder_version = gf_bs_read_u8(bs);
switch (ptr->type) {
case GF_ISOM_BOX_TYPE_D263:
ISOM_DECREASE_SIZE(s, 2)
ptr->cfg.H263_level = gf_bs_read_u8(bs);
ptr->cfg.H263_profile = gf_bs_read_u8(bs);
break;
case GF_ISOM_BOX_TYPE_DAMR:
ISOM_DECREASE_SIZE(s, 4)
ptr->cfg.AMR_mode_set = gf_bs_read_u16(bs);
ptr->cfg.AMR_mode_change_period = gf_bs_read_u8(bs);
ptr->cfg.frames_per_sample = gf_bs_read_u8(bs);
break;
case GF_ISOM_BOX_TYPE_DEVC:
case GF_ISOM_BOX_TYPE_DQCP:
case GF_ISOM_BOX_TYPE_DSMV:
ISOM_DECREASE_SIZE(s, 1)
ptr->cfg.frames_per_sample = gf_bs_read_u8(bs);
break;
}
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err gppc_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_3GPPConfigBox *ptr = (GF_3GPPConfigBox *)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u32(bs, ptr->cfg.vendor);
gf_bs_write_u8(bs, ptr->cfg.decoder_version);
switch (ptr->cfg.type) {
case GF_ISOM_SUBTYPE_3GP_H263:
gf_bs_write_u8(bs, ptr->cfg.H263_level);
gf_bs_write_u8(bs, ptr->cfg.H263_profile);
break;
case GF_ISOM_SUBTYPE_3GP_AMR:
case GF_ISOM_SUBTYPE_3GP_AMR_WB:
gf_bs_write_u16(bs, ptr->cfg.AMR_mode_set);
gf_bs_write_u8(bs, ptr->cfg.AMR_mode_change_period);
gf_bs_write_u8(bs, ptr->cfg.frames_per_sample);
break;
case GF_ISOM_SUBTYPE_3GP_EVRC:
case GF_ISOM_SUBTYPE_3GP_QCELP:
case GF_ISOM_SUBTYPE_3GP_SMV:
gf_bs_write_u8(bs, ptr->cfg.frames_per_sample);
break;
}
return GF_OK;
}
GF_Err gppc_box_size(GF_Box *s)
{
GF_3GPPConfigBox *ptr = (GF_3GPPConfigBox *)s;
s->size += 5;
if (!ptr->cfg.type) {
switch (ptr->type) {
case GF_ISOM_BOX_TYPE_D263:
ptr->cfg.type = GF_ISOM_SUBTYPE_3GP_H263;
break;
case GF_ISOM_BOX_TYPE_DAMR:
ptr->cfg.type = GF_ISOM_SUBTYPE_3GP_AMR;
break;
case GF_ISOM_BOX_TYPE_DEVC:
ptr->cfg.type = GF_ISOM_SUBTYPE_3GP_EVRC;
break;
case GF_ISOM_BOX_TYPE_DQCP:
ptr->cfg.type = GF_ISOM_SUBTYPE_3GP_QCELP;
break;
case GF_ISOM_BOX_TYPE_DSMV:
ptr->cfg.type = GF_ISOM_SUBTYPE_3GP_SMV;
break;
}
}
switch (ptr->cfg.type) {
case GF_ISOM_SUBTYPE_3GP_H263:
s->size += 2;
break;
case GF_ISOM_SUBTYPE_3GP_AMR:
case GF_ISOM_SUBTYPE_3GP_AMR_WB:
s->size += 4;
break;
case GF_ISOM_SUBTYPE_3GP_EVRC:
case GF_ISOM_SUBTYPE_3GP_QCELP:
case GF_ISOM_SUBTYPE_3GP_SMV:
s->size += 1;
break;
}
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *ftab_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_FontTableBox, GF_ISOM_BOX_TYPE_FTAB);
return (GF_Box *) tmp;
}
void ftab_box_del(GF_Box *s)
{
GF_FontTableBox *ptr = (GF_FontTableBox *)s;
if (ptr->fonts) {
u32 i;
for (i=0; i<ptr->entry_count; i++)
if (ptr->fonts[i].fontName) gf_free(ptr->fonts[i].fontName);
gf_free(ptr->fonts);
}
gf_free(ptr);
}
GF_Err ftab_box_read(GF_Box *s, GF_BitStream *bs)
{
u32 i;
GF_FontTableBox *ptr = (GF_FontTableBox *)s;
ptr->entry_count = gf_bs_read_u16(bs);
ISOM_DECREASE_SIZE(ptr, 2);
if (ptr->size<ptr->entry_count*3) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Corrupted ftap box, skipping\n"));
ptr->entry_count = 0;
return GF_OK;
}
ptr->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord)*ptr->entry_count);
if (!ptr->fonts) return GF_OUT_OF_MEM;
memset(ptr->fonts, 0, sizeof(GF_FontRecord)*ptr->entry_count);
for (i=0; i<ptr->entry_count; i++) {
u32 len;
ISOM_DECREASE_SIZE(ptr, 3);
ptr->fonts[i].fontID = gf_bs_read_u16(bs);
len = gf_bs_read_u8(bs);
if (len) {
ISOM_DECREASE_SIZE(ptr, len);
ptr->fonts[i].fontName = (char *)gf_malloc(sizeof(char)*(len+1));
if (!ptr->fonts[i].fontName) return GF_OUT_OF_MEM;
gf_bs_read_data(bs, ptr->fonts[i].fontName, len);
ptr->fonts[i].fontName[len] = 0;
}
}
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err ftab_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u32 i;
GF_FontTableBox *ptr = (GF_FontTableBox *)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u16(bs, ptr->entry_count);
for (i=0; i<ptr->entry_count; i++) {
gf_bs_write_u16(bs, ptr->fonts[i].fontID);
if (ptr->fonts[i].fontName) {
u32 len = (u32) strlen(ptr->fonts[i].fontName);
gf_bs_write_u8(bs, len);
gf_bs_write_data(bs, ptr->fonts[i].fontName, len);
} else {
gf_bs_write_u8(bs, 0);
}
}
return GF_OK;
}
GF_Err ftab_box_size(GF_Box *s)
{
u32 i;
GF_FontTableBox *ptr = (GF_FontTableBox *)s;
s->size += 2;
for (i=0; i<ptr->entry_count; i++) {
s->size += 3;
if (ptr->fonts[i].fontName) s->size += strlen(ptr->fonts[i].fontName);
}
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *text_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextSampleEntryBox, GF_ISOM_BOX_TYPE_TEXT);
gf_isom_sample_entry_init((GF_SampleEntryBox *)tmp);
return (GF_Box *) tmp;
}
void text_box_del(GF_Box *s)
{
GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s;
gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);
if (ptr->textName)
gf_free(ptr->textName);
gf_free(ptr);
}
GF_Box *tx3g_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_Tx3gSampleEntryBox, GF_ISOM_BOX_TYPE_TX3G);
gf_isom_sample_entry_init((GF_SampleEntryBox *)tmp);
return (GF_Box *) tmp;
}
void tx3g_box_del(GF_Box *s)
{
gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);
gf_free(s);
}
u32 gpp_read_rgba(GF_BitStream *bs)
{
u8 r, g, b, a;
u32 col;
r = gf_bs_read_u8(bs);
g = gf_bs_read_u8(bs);
b = gf_bs_read_u8(bs);
a = gf_bs_read_u8(bs);
col = a;
col<<=8;
col |= r;
col<<=8;
col |= g;
col<<=8;
col |= b;
return col;
}
#define GPP_BOX_SIZE 8
void gpp_read_box(GF_BitStream *bs, GF_BoxRecord *rec)
{
rec->top = gf_bs_read_u16(bs);
rec->left = gf_bs_read_u16(bs);
rec->bottom = gf_bs_read_u16(bs);
rec->right = gf_bs_read_u16(bs);
}
#define GPP_STYLE_SIZE 12
void gpp_read_style(GF_BitStream *bs, GF_StyleRecord *rec)
{
rec->startCharOffset = gf_bs_read_u16(bs);
rec->endCharOffset = gf_bs_read_u16(bs);
rec->fontID = gf_bs_read_u16(bs);
rec->style_flags = gf_bs_read_u8(bs);
rec->font_size = gf_bs_read_u8(bs);
rec->text_color = gpp_read_rgba(bs);
}
GF_Err tx3g_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
GF_Tx3gSampleEntryBox *ptr = (GF_Tx3gSampleEntryBox*)s;
switch (a->type) {
case GF_ISOM_BOX_TYPE_FTAB:
BOX_FIELD_ASSIGN(font_table, GF_FontTableBox)
break;
default:
return GF_OK;
}
return GF_OK;
}
GF_Err tx3g_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_Tx3gSampleEntryBox *ptr = (GF_Tx3gSampleEntryBox*)s;
ISOM_DECREASE_SIZE(ptr, (18 + GPP_BOX_SIZE + GPP_STYLE_SIZE) );
e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
if (e) return e;
ptr->displayFlags = gf_bs_read_u32(bs);
ptr->horizontal_justification = gf_bs_read_u8(bs);
ptr->vertical_justification = gf_bs_read_u8(bs);
ptr->back_color = gpp_read_rgba(bs);
gpp_read_box(bs, &ptr->default_box);
gpp_read_style(bs, &ptr->default_style);
return gf_isom_box_array_read(s, bs);
}
/*this is a quicktime specific box - see apple documentation*/
GF_Err text_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u16 pSize;
GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s;
ISOM_DECREASE_SIZE(ptr, 8);
e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
if (e) return e;
ptr->textJustification = 1;
//some weird text entries are not QT text nor 3gpp, cf issue #1030
if (!ptr->size) {
return GF_OK;
}
if (ptr->size < 43) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Broken text box (%d bytes but min 43 required), skipping parsing.\n", ptr->size));
return GF_OK;
}
ISOM_DECREASE_SIZE(ptr, 43);
ptr->displayFlags = gf_bs_read_u32(bs); /*Display flags*/
ptr->textJustification = gf_bs_read_u32(bs); /*Text justification*/
gf_bs_read_data(bs, ptr->background_color, 6); /*Background color*/
gpp_read_box(bs, &ptr->default_box); /*Default text box*/
gf_bs_read_data(bs, ptr->reserved1, 8); /*Reserved*/
ptr->fontNumber = gf_bs_read_u16(bs); /*Font number*/
ptr->fontFace = gf_bs_read_u16(bs); /*Font face*/
ptr->reserved2 = gf_bs_read_u8(bs); /*Reserved*/
ptr->reserved3 = gf_bs_read_u16(bs); /*Reserved*/
gf_bs_read_data(bs, ptr->foreground_color, 6); /*Foreground color*/
/*ffmpeg compatibility with iPod streams: no pascal string*/
if (!ptr->size)
return GF_OK;
ISOM_DECREASE_SIZE(ptr, 1);
pSize = gf_bs_read_u8(bs); /*a Pascal string begins with its size: get textName size*/
if (ptr->size < pSize) {
u32 b_size = pSize;
size_t i = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] text box doesn't use a Pascal string: trying to decode anyway.\n"));
ptr->textName = (char*)gf_malloc((size_t)ptr->size + 1 + 1);
if (!ptr->textName) return GF_OUT_OF_MEM;
do {
char c = (char)b_size;
if (c == '\0') {
break;
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
ptr->textName[i] = c;
} else {
gf_free(ptr->textName);
ptr->textName = NULL;
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] text box doesn't use a Pascal string and contains non-chars. Abort.\n"));
return GF_ISOM_INVALID_FILE;
}
i++;
if (!ptr->size)
break;
ptr->size--;
b_size = gf_bs_read_u8(bs);
} while (b_size);
ptr->textName[i] = '\0'; /*Font name*/
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] text box doesn't use a Pascal string: \"%s\" detected.\n", ptr->textName));
return GF_OK;
}
if (pSize) {
ptr->textName = (char*) gf_malloc((pSize+1) * sizeof(char));
if (!ptr->textName) return GF_OUT_OF_MEM;
if (gf_bs_read_data(bs, ptr->textName, pSize) != pSize) {
gf_free(ptr->textName);
ptr->textName = NULL;
return GF_ISOM_INVALID_FILE;
}
ptr->textName[pSize] = '\0'; /*Font name*/
}
ISOM_DECREASE_SIZE(ptr, pSize);
if (!ptr->size) return GF_OK;
u32 next_size = gf_bs_peek_bits(bs, 32, 0);
if (next_size > ptr->size) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Broken text box detected, skipping parsing.\n"));
ptr->textJustification = 1;
return GF_OK;
}
return gf_isom_box_array_read(s, bs);
}
void gpp_write_rgba(GF_BitStream *bs, u32 col)
{
gf_bs_write_u8(bs, (col>>16) & 0xFF);
gf_bs_write_u8(bs, (col>>8) & 0xFF);
gf_bs_write_u8(bs, (col) & 0xFF);
gf_bs_write_u8(bs, (col>>24) & 0xFF);
}
void gpp_write_box(GF_BitStream *bs, GF_BoxRecord *rec)
{
gf_bs_write_u16(bs, rec->top);
gf_bs_write_u16(bs, rec->left);
gf_bs_write_u16(bs, rec->bottom);
gf_bs_write_u16(bs, rec->right);
}
#define GPP_STYLE_SIZE 12
void gpp_write_style(GF_BitStream *bs, GF_StyleRecord *rec)
{
gf_bs_write_u16(bs, rec->startCharOffset);
gf_bs_write_u16(bs, rec->endCharOffset);
gf_bs_write_u16(bs, rec->fontID);
gf_bs_write_u8(bs, rec->style_flags);
gf_bs_write_u8(bs, rec->font_size);
gpp_write_rgba(bs, rec->text_color);
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tx3g_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_Tx3gSampleEntryBox *ptr = (GF_Tx3gSampleEntryBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_data(bs, ptr->reserved, 6);
gf_bs_write_u16(bs, ptr->dataReferenceIndex);
gf_bs_write_u32(bs, ptr->displayFlags);
gf_bs_write_u8(bs, ptr->horizontal_justification);
gf_bs_write_u8(bs, ptr->vertical_justification);
gpp_write_rgba(bs, ptr->back_color);
gpp_write_box(bs, &ptr->default_box);
gpp_write_style(bs, &ptr->default_style);
return GF_OK;
}
GF_Err text_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u16 pSize;
GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_data(bs, ptr->reserved, 6);
gf_bs_write_u16(bs, ptr->dataReferenceIndex);
gf_bs_write_u32(bs, ptr->displayFlags); /*Display flags*/
gf_bs_write_u32(bs, ptr->textJustification); /*Text justification*/
gf_bs_write_data(bs, ptr->background_color, 6); /*Background color*/
gpp_write_box(bs, &ptr->default_box); /*Default text box*/
gf_bs_write_data(bs, ptr->reserved1, 8); /*Reserved*/
gf_bs_write_u16(bs, ptr->fontNumber); /*Font number*/
gf_bs_write_u16(bs, ptr->fontFace); /*Font face*/
gf_bs_write_u8(bs, ptr->reserved2); /*Reserved*/
gf_bs_write_u16(bs, ptr->reserved3); /*Reserved*/
gf_bs_write_data(bs, ptr->foreground_color, 6); /*Foreground color*/
//pSize assignment below is not a mistake
if (ptr->textName && (pSize = (u16) strlen(ptr->textName))) {
gf_bs_write_u8(bs, pSize); /*a Pascal string begins with its size*/
gf_bs_write_data(bs, ptr->textName, pSize); /*Font name*/
} else {
gf_bs_write_u8(bs, 0);
}
return GF_OK;
}
GF_Err tx3g_box_size(GF_Box *s)
{
/*base + this + box + style*/
s->size += 18 + GPP_BOX_SIZE + GPP_STYLE_SIZE;
return GF_OK;
}
GF_Err text_box_size(GF_Box *s)
{
GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s;
s->size += 8;
/*base + this + string length*/
s->size += 43 + 1;
if (ptr->textName)
s->size += strlen(ptr->textName);
return GF_OK;
}
#endif
GF_Box *styl_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextStyleBox, GF_ISOM_BOX_TYPE_STYL);
return (GF_Box *) tmp;
}
void styl_box_del(GF_Box *s)
{
GF_TextStyleBox*ptr = (GF_TextStyleBox*)s;
if (ptr->styles) gf_free(ptr->styles);
gf_free(ptr);
}
GF_Err styl_box_read(GF_Box *s, GF_BitStream *bs)
{
u32 i;
GF_TextStyleBox*ptr = (GF_TextStyleBox*)s;
ISOM_DECREASE_SIZE(ptr, 2);
ptr->entry_count = gf_bs_read_u16(bs);
if (ptr->size / GPP_STYLE_SIZE < ptr->entry_count)
return GF_ISOM_INVALID_FILE;
if (ptr->entry_count) {
ptr->styles = (GF_StyleRecord*)gf_malloc(sizeof(GF_StyleRecord)*ptr->entry_count);
if (!ptr->styles) return GF_OUT_OF_MEM;
for (i=0; i<ptr->entry_count; i++) {
ISOM_DECREASE_SIZE(ptr, GPP_STYLE_SIZE);
gpp_read_style(bs, &ptr->styles[i]);
}
}
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err styl_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u32 i;
GF_TextStyleBox*ptr = (GF_TextStyleBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u16(bs, ptr->entry_count);
for (i=0; i<ptr->entry_count; i++) gpp_write_style(bs, &ptr->styles[i]);
return GF_OK;
}
GF_Err styl_box_size(GF_Box *s)
{
GF_TextStyleBox*ptr = (GF_TextStyleBox*)s;
s->size += 2 + ptr->entry_count * GPP_STYLE_SIZE;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *hlit_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextHighlightBox, GF_ISOM_BOX_TYPE_HLIT);
return (GF_Box *) tmp;
}
void hlit_box_del(GF_Box *s)
{
gf_free(s);
}
GF_Err hlit_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextHighlightBox *ptr = (GF_TextHighlightBox *)s;
ISOM_DECREASE_SIZE(ptr, 4)
ptr->startcharoffset = gf_bs_read_u16(bs);
ptr->endcharoffset = gf_bs_read_u16(bs);
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err hlit_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_TextHighlightBox *ptr = (GF_TextHighlightBox *)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u16(bs, ptr->startcharoffset);
gf_bs_write_u16(bs, ptr->endcharoffset);
return GF_OK;
}
GF_Err hlit_box_size(GF_Box *s)
{
s->size += 4;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *hclr_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextHighlightColorBox, GF_ISOM_BOX_TYPE_HCLR);
return (GF_Box *) tmp;
}
void hclr_box_del(GF_Box *s)
{
gf_free(s);
}
GF_Err hclr_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextHighlightColorBox*ptr = (GF_TextHighlightColorBox*)s;
ISOM_DECREASE_SIZE(ptr, 4)
ptr->hil_color = gpp_read_rgba(bs);
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err hclr_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_TextHighlightColorBox*ptr = (GF_TextHighlightColorBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gpp_write_rgba(bs, ptr->hil_color);
return GF_OK;
}
GF_Err hclr_box_size(GF_Box *s)
{
s->size += 4;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *krok_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextKaraokeBox, GF_ISOM_BOX_TYPE_KROK);
return (GF_Box *) tmp;
}
void krok_box_del(GF_Box *s)
{
GF_TextKaraokeBox*ptr = (GF_TextKaraokeBox*)s;
if (ptr->records) gf_free(ptr->records);
gf_free(ptr);
}
GF_Err krok_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextKaraokeBox*ptr = (GF_TextKaraokeBox*)s;
ISOM_DECREASE_SIZE(ptr, 6)
ptr->highlight_starttime = gf_bs_read_u32(bs);
ptr->nb_entries = gf_bs_read_u16(bs);
if (ptr->size / 8 < ptr->nb_entries)
return GF_ISOM_INVALID_FILE;
if (ptr->nb_entries) {
u32 i;
ptr->records = (KaraokeRecord*)gf_malloc(sizeof(KaraokeRecord)*ptr->nb_entries);
if (!ptr->records) return GF_OUT_OF_MEM;
for (i=0; i<ptr->nb_entries; i++) {
ISOM_DECREASE_SIZE(ptr, 8)
ptr->records[i].highlight_endtime = gf_bs_read_u32(bs);
ptr->records[i].start_charoffset = gf_bs_read_u16(bs);
ptr->records[i].end_charoffset = gf_bs_read_u16(bs);
}
}
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err krok_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u32 i;
GF_TextKaraokeBox*ptr = (GF_TextKaraokeBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u32(bs, ptr->highlight_starttime);
gf_bs_write_u16(bs, ptr->nb_entries);
for (i=0; i<ptr->nb_entries; i++) {
gf_bs_write_u32(bs, ptr->records[i].highlight_endtime);
gf_bs_write_u16(bs, ptr->records[i].start_charoffset);
gf_bs_write_u16(bs, ptr->records[i].end_charoffset);
}
return GF_OK;
}
GF_Err krok_box_size(GF_Box *s)
{
GF_TextKaraokeBox*ptr = (GF_TextKaraokeBox*)s;
s->size += 6 + 8*ptr->nb_entries;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *dlay_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextScrollDelayBox, GF_ISOM_BOX_TYPE_DLAY);
return (GF_Box *) tmp;
}
void dlay_box_del(GF_Box *s)
{
gf_free(s);
}
GF_Err dlay_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextScrollDelayBox*ptr = (GF_TextScrollDelayBox*)s;
ISOM_DECREASE_SIZE(ptr, 4)
ptr->scroll_delay = gf_bs_read_u32(bs);
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err dlay_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_TextScrollDelayBox*ptr = (GF_TextScrollDelayBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u32(bs, ptr->scroll_delay);
return GF_OK;
}
GF_Err dlay_box_size(GF_Box *s)
{
s->size += 4;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *href_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextHyperTextBox, GF_ISOM_BOX_TYPE_HREF);
return (GF_Box *) tmp;
}
void href_box_del(GF_Box *s)
{
GF_TextHyperTextBox*ptr = (GF_TextHyperTextBox*)s;
if (ptr->URL) gf_free(ptr->URL);
if (ptr->URL_hint) gf_free(ptr->URL_hint);
gf_free(ptr);
}
GF_Err href_box_read(GF_Box *s, GF_BitStream *bs)
{
u32 len;
GF_TextHyperTextBox*ptr = (GF_TextHyperTextBox*)s;
ISOM_DECREASE_SIZE(ptr, 6) //including 2 length fields
ptr->startcharoffset = gf_bs_read_u16(bs);
ptr->endcharoffset = gf_bs_read_u16(bs);
len = gf_bs_read_u8(bs);
if (len) {
ISOM_DECREASE_SIZE(ptr, len)
ptr->URL = (char *) gf_malloc(sizeof(char) * (len+1));
if (!ptr->URL) return GF_OUT_OF_MEM;
gf_bs_read_data(bs, ptr->URL, len);
ptr->URL[len] = 0;
}
len = gf_bs_read_u8(bs);
if (len) {
ISOM_DECREASE_SIZE(ptr, len)
ptr->URL_hint = (char *) gf_malloc(sizeof(char) * (len+1));
if (!ptr->URL_hint) return GF_OUT_OF_MEM;
gf_bs_read_data(bs, ptr->URL_hint, len);
ptr->URL_hint[len]= 0;
}
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err href_box_write(GF_Box *s, GF_BitStream *bs)
{
u32 len;
GF_Err e;
GF_TextHyperTextBox*ptr = (GF_TextHyperTextBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u16(bs, ptr->startcharoffset);
gf_bs_write_u16(bs, ptr->endcharoffset);
if (ptr->URL) {
len = (u32) strlen(ptr->URL);
gf_bs_write_u8(bs, len);
gf_bs_write_data(bs, ptr->URL, len);
} else {
gf_bs_write_u8(bs, 0);
}
if (ptr->URL_hint) {
len = (u32) strlen(ptr->URL_hint);
gf_bs_write_u8(bs, len);
gf_bs_write_data(bs, ptr->URL_hint, len);
} else {
gf_bs_write_u8(bs, 0);
}
return GF_OK;
}
GF_Err href_box_size(GF_Box *s)
{
GF_TextHyperTextBox*ptr = (GF_TextHyperTextBox*)s;
s->size += 6;
if (ptr->URL) s->size += strlen(ptr->URL);
if (ptr->URL_hint) s->size += strlen(ptr->URL_hint);
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *tbox_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextBoxBox, GF_ISOM_BOX_TYPE_TBOX);
return (GF_Box *) tmp;
}
void tbox_box_del(GF_Box *s)
{
gf_free(s);
}
GF_Err tbox_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextBoxBox*ptr = (GF_TextBoxBox*)s;
ISOM_DECREASE_SIZE(ptr, GPP_BOX_SIZE)
gpp_read_box(bs, &ptr->box);
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tbox_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_TextBoxBox*ptr = (GF_TextBoxBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gpp_write_box(bs, &ptr->box);
return GF_OK;
}
GF_Err tbox_box_size(GF_Box *s)
{
s->size += 8;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *blnk_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextBlinkBox, GF_ISOM_BOX_TYPE_BLNK);
return (GF_Box *) tmp;
}
void blnk_box_del(GF_Box *s)
{
gf_free(s);
}
GF_Err blnk_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextBlinkBox*ptr = (GF_TextBlinkBox*)s;
ISOM_DECREASE_SIZE(ptr, 4)
ptr->startcharoffset = gf_bs_read_u16(bs);
ptr->endcharoffset = gf_bs_read_u16(bs);
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err blnk_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_TextBlinkBox*ptr = (GF_TextBlinkBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u16(bs, ptr->startcharoffset);
gf_bs_write_u16(bs, ptr->endcharoffset);
return GF_OK;
}
GF_Err blnk_box_size(GF_Box *s)
{
s->size += 4;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *twrp_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TextWrapBox, GF_ISOM_BOX_TYPE_TWRP);
return (GF_Box *) tmp;
}
void twrp_box_del(GF_Box *s)
{
gf_free(s);
}
GF_Err twrp_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_TextWrapBox*ptr = (GF_TextWrapBox*)s;
ISOM_DECREASE_SIZE(ptr, 1)
ptr->wrap_flag = gf_bs_read_u8(bs);
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err twrp_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_TextWrapBox*ptr = (GF_TextWrapBox*)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u8(bs, ptr->wrap_flag);
return GF_OK;
}
GF_Err twrp_box_size(GF_Box *s)
{
s->size += 1;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
void tsel_box_del(GF_Box *s)
{
GF_TrackSelectionBox *ptr;
ptr = (GF_TrackSelectionBox *) s;
if (ptr == NULL) return;
if (ptr->attributeList) gf_free(ptr->attributeList);
gf_free(ptr);
}
GF_Err tsel_box_read(GF_Box *s,GF_BitStream *bs)
{
u32 i;
GF_TrackSelectionBox *ptr = (GF_TrackSelectionBox *) s;
ISOM_DECREASE_SIZE(ptr, 4);
ptr->switchGroup = gf_bs_read_u32(bs);
if (ptr->size % 4) return GF_ISOM_INVALID_FILE;
ptr->attributeListCount = (u32)ptr->size/4;
ptr->attributeList = gf_malloc(ptr->attributeListCount*sizeof(u32));
if (ptr->attributeList == NULL) return GF_OUT_OF_MEM;
for (i=0; i< ptr->attributeListCount; i++) {
ptr->attributeList[i] = gf_bs_read_u32(bs);
}
return GF_OK;
}
GF_Box *tsel_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_TrackSelectionBox, GF_ISOM_BOX_TYPE_TSEL);
return (GF_Box *)tmp;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err tsel_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u32 i;
GF_TrackSelectionBox *ptr = (GF_TrackSelectionBox *) s;
e = gf_isom_full_box_write(s, bs);
if (e) return e;
gf_bs_write_u32(bs,ptr->switchGroup);
for (i = 0; i < ptr->attributeListCount; i++ ) {
gf_bs_write_u32(bs, ptr->attributeList[i]);
}
return GF_OK;
}
GF_Err tsel_box_size(GF_Box *s)
{
GF_TrackSelectionBox *ptr = (GF_TrackSelectionBox *) s;
ptr->size += 4 + (4*ptr->attributeListCount);
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *dimC_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_DIMSSceneConfigBox, GF_ISOM_BOX_TYPE_DIMC);
return (GF_Box *)tmp;
}
void dimC_box_del(GF_Box *s)
{
GF_DIMSSceneConfigBox *p = (GF_DIMSSceneConfigBox *)s;
if (p->contentEncoding) gf_free(p->contentEncoding);
if (p->textEncoding) gf_free(p->textEncoding);
gf_free(p);
}
GF_Err dimC_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
u32 i, msize;
GF_DIMSSceneConfigBox *p = (GF_DIMSSceneConfigBox *)s;
ISOM_DECREASE_SIZE(p, 3);
p->profile = gf_bs_read_u8(bs);
p->level = gf_bs_read_u8(bs);
p->pathComponents = gf_bs_read_int(bs, 4);
p->fullRequestHost = gf_bs_read_int(bs, 1);
p->streamType = gf_bs_read_int(bs, 1);
p->containsRedundant = gf_bs_read_int(bs, 2);
if (p->size > GF_UINT_MAX-1) return GF_ISOM_INVALID_FILE;
char *str = gf_malloc( (size_t) (p->size+1));
if (!str) return GF_OUT_OF_MEM;
msize = (u32) p->size;
str[msize] = 0;
i=0;
str[0]=0;
while (i < msize) {
ISOM_DECREASE_SIZE_GOTO_EXIT(p, 1);
str[i] = gf_bs_read_u8(bs);
if (!str[i]) break;
i++;
}
if (i == msize) {
gf_free(str);
return GF_ISOM_INVALID_FILE;
}
p->textEncoding = gf_strdup(str);
i=0;
str[0]=0;
while (i < msize) {
ISOM_DECREASE_SIZE_GOTO_EXIT(p, 1);
str[i] = gf_bs_read_u8(bs);
if (!str[i]) break;
i++;
}
if (i == msize) {
gf_free(str);
return GF_ISOM_INVALID_FILE;
}
p->contentEncoding = gf_strdup(str);
gf_free(str);
if (!p->textEncoding || !p->contentEncoding)
return GF_OUT_OF_MEM;
return GF_OK;
exit:
gf_free(str);
return e;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err dimC_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_DIMSSceneConfigBox *p = (GF_DIMSSceneConfigBox *)s;
GF_Err e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_u8(bs, p->profile);
gf_bs_write_u8(bs, p->level);
gf_bs_write_int(bs, p->pathComponents, 4);
gf_bs_write_int(bs, p->fullRequestHost, 1);
gf_bs_write_int(bs, p->streamType, 1);
gf_bs_write_int(bs, p->containsRedundant, 2);
if (p->textEncoding)
gf_bs_write_data(bs, p->textEncoding, (u32) strlen(p->textEncoding));
gf_bs_write_u8(bs, 0);
if (p->contentEncoding)
gf_bs_write_data(bs, p->contentEncoding, (u32) strlen(p->contentEncoding));
gf_bs_write_u8(bs, 0);
return GF_OK;
}
GF_Err dimC_box_size(GF_Box *s)
{
GF_DIMSSceneConfigBox *p = (GF_DIMSSceneConfigBox *)s;
s->size += 3 + 2;
if (p->textEncoding) s->size += strlen(p->textEncoding);
if (p->contentEncoding) s->size += strlen(p->contentEncoding);
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *diST_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_DIMSScriptTypesBox, GF_ISOM_BOX_TYPE_DIST);
return (GF_Box *)tmp;
}
void diST_box_del(GF_Box *s)
{
GF_DIMSScriptTypesBox *p = (GF_DIMSScriptTypesBox *)s;
if (p->content_script_types) gf_free(p->content_script_types);
gf_free(p);
}
GF_Err diST_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_DIMSScriptTypesBox *p = (GF_DIMSScriptTypesBox *)s;
if (s->size > GF_UINT_MAX-1) return GF_ISOM_INVALID_FILE;
p->content_script_types = gf_malloc(sizeof(u8) * ((u32) s->size + 1));
if (!p->content_script_types) return GF_OUT_OF_MEM;
gf_bs_read_data(bs, p->content_script_types, (u32) s->size);
p->content_script_types[(u32) s->size] = 0;
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err diST_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_DIMSScriptTypesBox *p = (GF_DIMSScriptTypesBox *)s;
GF_Err e = gf_isom_box_write_header(s, bs);
if (e) return e;
if (p->content_script_types)
gf_bs_write_data(bs, p->content_script_types, (u32) strlen(p->content_script_types)+1);
else
gf_bs_write_u8(bs, 0);
return GF_OK;
}
GF_Err diST_box_size(GF_Box *s)
{
GF_DIMSScriptTypesBox *p = (GF_DIMSScriptTypesBox *)s;
s->size += p->content_script_types ? (strlen(p->content_script_types)+1) : 1;
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
GF_Box *dims_box_new()
{
ISOM_DECL_BOX_ALLOC(GF_DIMSSampleEntryBox, GF_ISOM_BOX_TYPE_DIMS);
gf_isom_sample_entry_init((GF_SampleEntryBox *)tmp);
return (GF_Box*)tmp;
}
void dims_box_del(GF_Box *s)
{
gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);
gf_free(s);
}
GF_Err dims_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
GF_DIMSSampleEntryBox *ptr = (GF_DIMSSampleEntryBox *)s;
switch (a->type) {
case GF_ISOM_BOX_TYPE_DIMC:
BOX_FIELD_ASSIGN(config, GF_DIMSSceneConfigBox)
break;
case GF_ISOM_BOX_TYPE_DIST:
BOX_FIELD_ASSIGN(scripts, GF_DIMSScriptTypesBox)
break;
}
return GF_OK;
}
GF_Err dims_box_read(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_DIMSSampleEntryBox *p = (GF_DIMSSampleEntryBox *)s;
e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)p, bs);
if (e) return e;
ISOM_DECREASE_SIZE(p, 8);
return gf_isom_box_array_read(s, bs);
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err dims_box_write(GF_Box *s, GF_BitStream *bs)
{
GF_DIMSSampleEntryBox *p = (GF_DIMSSampleEntryBox *)s;
GF_Err e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_data(bs, p->reserved, 6);
gf_bs_write_u16(bs, p->dataReferenceIndex);
return GF_OK;
}
GF_Err dims_box_size(GF_Box *s)
{
u32 pos = 0;
GF_DIMSSampleEntryBox *p = (GF_DIMSSampleEntryBox *)s;
s->size += 8;
gf_isom_check_position(s, (GF_Box *) p->config, &pos);
gf_isom_check_position(s, (GF_Box *) p->scripts, &pos);
return GF_OK;
}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
#endif /*GPAC_DISABLE_ISOM*/