| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2026 | |
| * 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> | |
| #ifndef GPAC_DISABLE_ISOM | |
| void co64_box_del(GF_Box *s) | |
| { | |
| GF_ChunkLargeOffsetBox *ptr; | |
| ptr = (GF_ChunkLargeOffsetBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->offsets) gf_free(ptr->offsets); | |
| gf_free(ptr); | |
| } | |
| GF_Err co64_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 entries; | |
| GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s; | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| if ((u64)ptr->nb_entries > ptr->size / 8 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(u64)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in co64\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->offsets = (u64 *) gf_malloc(ptr->nb_entries * sizeof(u64) ); | |
| if (ptr->offsets == NULL) return GF_OUT_OF_MEM; | |
| ptr->alloc_size = ptr->nb_entries; | |
| for (entries = 0; entries < ptr->nb_entries; entries++) { | |
| ptr->offsets[entries] = gf_bs_read_u64(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *co64_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ChunkLargeOffsetBox, GF_ISOM_BOX_TYPE_CO64); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err co64_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nb_entries); | |
| for (i = 0; i < ptr->nb_entries; i++ ) { | |
| gf_bs_write_u64(bs, ptr->offsets[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err co64_box_size(GF_Box *s) | |
| { | |
| GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s; | |
| ptr->size += 4 + (8 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void cprt_box_del(GF_Box *s) | |
| { | |
| GF_CopyrightBox *ptr = (GF_CopyrightBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->notice) | |
| gf_free(ptr->notice); | |
| gf_free(ptr); | |
| } | |
| GF_Box *chpl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ChapterListBox, GF_ISOM_BOX_TYPE_CHPL); | |
| tmp->list = gf_list_new(); | |
| tmp->version = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| void chpl_box_del(GF_Box *s) | |
| { | |
| GF_ChapterListBox *ptr = (GF_ChapterListBox *) s; | |
| if (ptr == NULL) return; | |
| while (gf_list_count(ptr->list)) { | |
| GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(ptr->list, 0); | |
| if (ce->name) gf_free(ce->name); | |
| gf_free(ce); | |
| gf_list_rem(ptr->list, 0); | |
| } | |
| gf_list_del(ptr->list); | |
| gf_free(ptr); | |
| } | |
| /*this is using chpl format according to some NeroRecode samples*/ | |
| GF_Err chpl_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ChapterEntry *ce=NULL; | |
| u32 nb_chaps, len, i, count; | |
| GF_ChapterListBox *ptr = (GF_ChapterListBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 5) | |
| /*reserved or ???*/ | |
| gf_bs_read_u32(bs); | |
| nb_chaps = gf_bs_read_u8(bs); | |
| count = 0; | |
| while (nb_chaps) { | |
| GF_SAFEALLOC(ce, GF_ChapterEntry); | |
| if (!ce) return GF_OUT_OF_MEM; | |
| ISOM_DECREASE_SIZE_GOTO_EXIT(ptr, 9) | |
| ce->start_time = gf_bs_read_u64(bs); | |
| len = gf_bs_read_u8(bs); | |
| if (ptr->size<len) { | |
| e = GF_ISOM_INVALID_FILE; | |
| goto exit; | |
| } | |
| if (len) { | |
| ce->name = (char *)gf_malloc(sizeof(char)*(len+1)); | |
| if (!ce->name) { | |
| e = GF_OUT_OF_MEM; | |
| goto exit; | |
| } | |
| ISOM_DECREASE_SIZE_GOTO_EXIT(ptr, len) | |
| gf_bs_read_data(bs, ce->name, len); | |
| ce->name[len] = 0; | |
| } else { | |
| ce->name = gf_strdup(""); | |
| } | |
| for (i=0; i<count; i++) { | |
| GF_ChapterEntry *ace = (GF_ChapterEntry *) gf_list_get(ptr->list, i); | |
| if (ace->start_time >= ce->start_time) { | |
| gf_list_insert(ptr->list, ce, i); | |
| ce = NULL; | |
| break; | |
| } | |
| } | |
| if (ce) gf_list_add(ptr->list, ce); | |
| count++; | |
| nb_chaps--; | |
| ce = NULL; | |
| } | |
| return GF_OK; | |
| exit: | |
| if (ce) gf_free(ce); | |
| return e; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err chpl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 count, i; | |
| GF_ChapterListBox *ptr = (GF_ChapterListBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| count = gf_list_count(ptr->list); | |
| gf_bs_write_u32(bs, 0); | |
| gf_bs_write_u8(bs, count); | |
| for (i=0; i<count; i++) { | |
| u32 len; | |
| GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(ptr->list, i); | |
| gf_bs_write_u64(bs, ce->start_time); | |
| if (ce->name) { | |
| len = (u32) strlen(ce->name); | |
| if (len>255) len = 255; | |
| gf_bs_write_u8(bs, len); | |
| gf_bs_write_data(bs, ce->name, len); | |
| } else { | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err chpl_box_size(GF_Box *s) | |
| { | |
| u32 count, i; | |
| GF_ChapterListBox *ptr = (GF_ChapterListBox *)s; | |
| ptr->size += 5; | |
| count = gf_list_count(ptr->list); | |
| for (i=0; i<count; i++) { | |
| GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(ptr->list, i); | |
| ptr->size += 9; /*64bit time stamp + 8bit str len*/ | |
| if (ce->name) ptr->size += strlen(ce->name); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Err cprt_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_CopyrightBox *ptr = (GF_CopyrightBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| gf_bs_read_int(bs, 1); | |
| //the spec is unclear here, just says "the value 0 is interpreted as undetermined" | |
| ptr->packedLanguageCode[0] = gf_bs_read_int(bs, 5); | |
| ptr->packedLanguageCode[1] = gf_bs_read_int(bs, 5); | |
| ptr->packedLanguageCode[2] = gf_bs_read_int(bs, 5); | |
| //but before or after compaction ?? We assume before | |
| if (ptr->packedLanguageCode[0] || ptr->packedLanguageCode[1] || ptr->packedLanguageCode[2]) { | |
| ptr->packedLanguageCode[0] += 0x60; | |
| ptr->packedLanguageCode[1] += 0x60; | |
| ptr->packedLanguageCode[2] += 0x60; | |
| } else { | |
| ptr->packedLanguageCode[0] = 'u'; | |
| ptr->packedLanguageCode[1] = 'n'; | |
| ptr->packedLanguageCode[2] = 'd'; | |
| } | |
| if (ptr->size) { | |
| u32 bytesToRead = (u32) ptr->size; | |
| ptr->notice = (char*)gf_malloc((bytesToRead+1) * sizeof(char)); | |
| if (ptr->notice == NULL) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->notice, bytesToRead); | |
| ptr->notice[bytesToRead] = 0; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *cprt_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_CopyrightBox, GF_ISOM_BOX_TYPE_CPRT); | |
| tmp->packedLanguageCode[0] = 'u'; | |
| tmp->packedLanguageCode[1] = 'n'; | |
| tmp->packedLanguageCode[2] = 'd'; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err cprt_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_CopyrightBox *ptr = (GF_CopyrightBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, 0, 1); | |
| if (ptr->packedLanguageCode[0]) { | |
| gf_bs_write_int(bs, ptr->packedLanguageCode[0] - 0x60, 5); | |
| gf_bs_write_int(bs, ptr->packedLanguageCode[1] - 0x60, 5); | |
| gf_bs_write_int(bs, ptr->packedLanguageCode[2] - 0x60, 5); | |
| } else { | |
| gf_bs_write_int(bs, 0, 15); | |
| } | |
| if (ptr->notice) { | |
| gf_bs_write_data(bs, ptr->notice, (u32) (strlen(ptr->notice) + 1) ); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err cprt_box_size(GF_Box *s) | |
| { | |
| GF_CopyrightBox *ptr = (GF_CopyrightBox *)s; | |
| ptr->size += 2; | |
| if (ptr->notice) | |
| ptr->size += strlen(ptr->notice) + 1; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void kind_box_del(GF_Box *s) | |
| { | |
| GF_KindBox *ptr = (GF_KindBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->schemeURI) gf_free(ptr->schemeURI); | |
| if (ptr->value) gf_free(ptr->value); | |
| gf_free(ptr); | |
| } | |
| GF_Err kind_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_KindBox *ptr = (GF_KindBox *)s; | |
| if (ptr->size) { | |
| u32 bytesToRead = (u32) ptr->size; | |
| char *data; | |
| u32 schemeURIlen; | |
| data = (char*)gf_malloc(bytesToRead * sizeof(char)); | |
| if (!data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, data, bytesToRead); | |
| /*safety check in case the string is not null-terminated*/ | |
| if (data[bytesToRead-1]) { | |
| data = (char*)gf_realloc(data, sizeof(char)*(bytesToRead + 1)); | |
| if (!data) return GF_OUT_OF_MEM; | |
| data[bytesToRead] = 0; | |
| bytesToRead++; | |
| } | |
| ptr->schemeURI = gf_strdup(data); | |
| if (!ptr->schemeURI) return GF_OUT_OF_MEM; | |
| schemeURIlen = (u32) strlen(data); | |
| if (bytesToRead > schemeURIlen+1) { | |
| /* read the value */ | |
| char *data_value = data + schemeURIlen +1; | |
| ptr->value = gf_strdup(data_value); | |
| if (!ptr->value) return GF_OUT_OF_MEM; | |
| } | |
| gf_free(data); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *kind_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_KindBox, GF_ISOM_BOX_TYPE_KIND); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err kind_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_KindBox *ptr = (GF_KindBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->schemeURI) | |
| gf_bs_write_data(bs, ptr->schemeURI, (u32) (strlen(ptr->schemeURI) + 1 )); | |
| else | |
| gf_bs_write_u8(bs, 0); | |
| if (ptr->value) { | |
| gf_bs_write_data(bs, ptr->value, (u32) (strlen(ptr->value) + 1) ); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err kind_box_size(GF_Box *s) | |
| { | |
| GF_KindBox *ptr = (GF_KindBox *)s; | |
| ptr->size += (ptr->schemeURI ? strlen(ptr->schemeURI) : 0) + 1; | |
| if (ptr->value) { | |
| ptr->size += strlen(ptr->value) + 1; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void prsl_box_del(GF_Box *s) | |
| { | |
| GF_PreselectionGroupBox *ptr = (GF_PreselectionGroupBox *) s; | |
| if (ptr == NULL) return; | |
| if (s->child_boxes) gf_isom_box_array_del(s->child_boxes); | |
| if (ptr->entity_id_count && ptr->entity_ids) gf_free(ptr->entity_ids); | |
| if (ptr->preselection_tag) gf_free(ptr->preselection_tag); | |
| if (ptr->interleaving_tag) gf_free(ptr->interleaving_tag); | |
| gf_free(ptr); | |
| } | |
| #define GF_READ_STRING_WITH_0END(bs, ptr, size) \ | |
| { \ | |
| char *x_data; \ | |
| u32 x_i = 0; \ | |
| GF_SAFE_ALLOC_N(x_data, (size) + 1, char); \ | |
| while (gf_bs_available(bs) && x_i < (size)) { \ | |
| x_data[x_i] = (char) gf_bs_read_u8(bs); \ | |
| if (x_data[x_i] == '\0') break; \ | |
| x_i++; \ | |
| } \ | |
| x_data[(size)] = '\0'; \ | |
| ptr = gf_strdup(x_data); \ | |
| gf_free(x_data); \ | |
| if (!ptr) return GF_OUT_OF_MEM; \ | |
| } | |
| GF_Err prsl_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i, size, str_len; | |
| GF_PreselectionGroupBox *ptr = (GF_PreselectionGroupBox *)s; | |
| ptr->version = gf_bs_read_int(bs, 8); | |
| ptr->flags = gf_bs_read_int(bs, 24); | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->group_id = gf_bs_read_u32(bs); | |
| ptr->entity_id_count = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| if ((u64) ptr->entity_id_count > (u64) SIZE_MAX / sizeof(u32)) { | |
| return GF_OUT_OF_MEM; | |
| } | |
| if ((u64) ptr->entity_id_count > ptr->size / 4) { | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (ptr->entity_id_count) { | |
| ptr->entity_ids = (u32 *) gf_malloc(ptr->entity_id_count * sizeof(u32)); | |
| if (!ptr->entity_ids) return GF_OUT_OF_MEM; | |
| } | |
| for (i = 0; i < ptr->entity_id_count; i++) { | |
| ptr->entity_ids[i] = gf_bs_read_u32(bs); | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 4 * ptr->entity_id_count) | |
| size = (u32) ptr->size; | |
| if (ptr->flags & GF_ISOM_PRESELECTION_TAG_PRESENT) { | |
| GF_READ_STRING_WITH_0END(bs, ptr->preselection_tag, size); | |
| str_len = (u32) strlen(ptr->preselection_tag) + 1; | |
| ISOM_DECREASE_SIZE(ptr, str_len) | |
| } | |
| if (ptr->flags & GF_ISOM_SELECTION_PRIORITY_PRESENT) { | |
| ptr->selection_priority = gf_bs_read_u8(bs); | |
| size -= 1; | |
| ISOM_DECREASE_SIZE(ptr, 1) | |
| } | |
| if (ptr->flags & GF_ISOM_INTERLEAVING_TAG_PRESENT) { | |
| GF_READ_STRING_WITH_0END(bs, ptr->interleaving_tag, size); | |
| str_len = (u32) strlen(ptr->interleaving_tag) + 1; | |
| ISOM_DECREASE_SIZE(ptr, str_len) | |
| } | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *prsl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PreselectionGroupBox, GF_ISOM_BOX_TYPE_PRSL); | |
| tmp->child_boxes = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err prsl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_PreselectionGroupBox *ptr = (GF_PreselectionGroupBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->group_id); | |
| gf_bs_write_u32(bs, ptr->entity_id_count); | |
| for (i = 0; i < ptr->entity_id_count; i++) { | |
| gf_bs_write_u32(bs, ptr->entity_ids[i]); | |
| } | |
| if (ptr->flags & GF_ISOM_PRESELECTION_TAG_PRESENT) { | |
| gf_bs_write_data(bs, ptr->preselection_tag, (u32) (strlen(ptr->preselection_tag) + 1 )); | |
| } | |
| if (ptr->flags & GF_ISOM_SELECTION_PRIORITY_PRESENT) { | |
| gf_bs_write_u8(bs, ptr->selection_priority); | |
| } | |
| if (ptr->flags & GF_ISOM_INTERLEAVING_TAG_PRESENT) { | |
| gf_bs_write_data(bs, ptr->interleaving_tag, (u32) (strlen(ptr->interleaving_tag) + 1 )); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err prsl_box_size(GF_Box *s) | |
| { | |
| GF_PreselectionGroupBox *ptr = (GF_PreselectionGroupBox *)s; | |
| ptr->size += 12 + (4 * ptr->entity_id_count); | |
| if (ptr->flags & GF_ISOM_PRESELECTION_TAG_PRESENT) { | |
| ptr->size += strlen(ptr->preselection_tag) + 1; | |
| } | |
| if (ptr->flags & GF_ISOM_SELECTION_PRIORITY_PRESENT) { | |
| ptr->size += 1; | |
| } | |
| if (ptr->flags & GF_ISOM_INTERLEAVING_TAG_PRESENT) { | |
| ptr->size += strlen(ptr->interleaving_tag) + 1; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ardi_box_del(GF_Box *s) | |
| { | |
| GF_AudioRenderingIndicationBox *ptr = (GF_AudioRenderingIndicationBox *) s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err ardi_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_AudioRenderingIndicationBox *ptr = (GF_AudioRenderingIndicationBox *)s; | |
| ptr->version = gf_bs_read_int(bs, 8); | |
| ptr->flags = gf_bs_read_int(bs, 24); | |
| ptr->audio_rendering_indication = gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *ardi_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_AudioRenderingIndicationBox, GF_ISOM_BOX_TYPE_ARDI); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ardi_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_AudioRenderingIndicationBox *ptr = (GF_AudioRenderingIndicationBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->audio_rendering_indication); | |
| return GF_OK; | |
| } | |
| GF_Err ardi_box_size(GF_Box *s) | |
| { | |
| GF_AudioRenderingIndicationBox *ptr = (GF_AudioRenderingIndicationBox *)s; | |
| ptr->size += 5; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void diap_box_del(GF_Box *s) | |
| { | |
| GF_DialogueProcessingBox *ptr = (GF_DialogueProcessingBox *) s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err diap_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_DialogueProcessingBox *ptr = (GF_DialogueProcessingBox *)s; | |
| ptr->version = gf_bs_read_int(bs, 8); | |
| ptr->flags = gf_bs_read_int(bs, 24); | |
| ptr->dialog_gain = (s8) gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *diap_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DialogueProcessingBox, GF_ISOM_BOX_TYPE_DIAP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err diap_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DialogueProcessingBox *ptr = (GF_DialogueProcessingBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, (u8) ptr->dialog_gain); | |
| return GF_OK; | |
| } | |
| GF_Err diap_box_size(GF_Box *s) | |
| { | |
| GF_DialogueProcessingBox *ptr = (GF_DialogueProcessingBox *)s; | |
| ptr->size += 5; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void labl_box_del(GF_Box *s) | |
| { | |
| GF_LabelBox *ptr = (GF_LabelBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->language) gf_free(ptr->language); | |
| if (ptr->label) gf_free(ptr->label); | |
| gf_free(ptr); | |
| } | |
| GF_Err labl_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_LabelBox *ptr = (GF_LabelBox *)s; | |
| u32 size; | |
| ptr->version = gf_bs_read_int(bs, 8); | |
| ptr->flags = gf_bs_read_int(bs, 24); | |
| ptr->label_id = gf_bs_read_u16(bs); | |
| size = (u32) ptr->size - 2; | |
| GF_READ_STRING_WITH_0END(bs, ptr->language, size); | |
| size -= (u32) strlen(ptr->language) + 1; | |
| GF_READ_STRING_WITH_0END(bs, ptr->label, size); | |
| return GF_OK; | |
| } | |
| GF_Box *labl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_LabelBox, GF_ISOM_BOX_TYPE_LABL); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err labl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_LabelBox *ptr = (GF_LabelBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->label_id); | |
| if (ptr->language) { | |
| gf_bs_write_data(bs, ptr->language, (u32) (strlen(ptr->language) + 1 )); | |
| } | |
| if (ptr->label) { | |
| gf_bs_write_data(bs, ptr->label, (u32) (strlen(ptr->label) + 1)); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err labl_box_size(GF_Box *s) | |
| { | |
| GF_LabelBox *ptr = (GF_LabelBox *)s; | |
| ptr->size += 6; | |
| if (ptr->language) { | |
| ptr->size += strlen(ptr->language) + 1; | |
| } | |
| if (ptr->label) { | |
| ptr->size += strlen(ptr->label) + 1; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ctts_box_del(GF_Box *s) | |
| { | |
| GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err ctts_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| u32 sampleCount; | |
| GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->nb_entries > ptr->size / 8 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(GF_DttsEntry) ) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->alloc_size = ptr->nb_entries; | |
| ptr->entries = (GF_DttsEntry *)gf_malloc(sizeof(GF_DttsEntry)*ptr->alloc_size); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| sampleCount = 0; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->entries[i].sampleCount = gf_bs_read_u32(bs); | |
| if (ptr->version) | |
| ptr->entries[i].decodingOffset = gf_bs_read_int(bs, 32); | |
| else { | |
| ptr->entries[i].decodingOffset = (s32) gf_bs_read_u32(bs); | |
| if (ptr->entries[i].decodingOffset <= INT_MIN) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid decodingOffset (%d) in entry #%i - defaulting to 0.\n", ptr->entries[i].decodingOffset, i)); | |
| ptr->entries[i].decodingOffset = 0; | |
| } | |
| if (ptr->entries[i].decodingOffset<ptr->min_neg_cts_offset) | |
| ptr->min_neg_cts_offset = ptr->entries[i].decodingOffset; | |
| } | |
| if (ptr->entries[i].decodingOffset == INT_MIN) { | |
| ptr->max_cts_delta = INT_MAX; | |
| } else if (ptr->max_cts_delta <= ABS(ptr->entries[i].decodingOffset)) { | |
| ptr->max_cts_delta = ABS(ptr->entries[i].decodingOffset); | |
| } | |
| sampleCount += ptr->entries[i].sampleCount; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| ptr->w_LastSampleNumber = sampleCount; | |
| #endif | |
| return GF_OK; | |
| } | |
| GF_Box *ctts_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_CompositionOffsetBox, GF_ISOM_BOX_TYPE_CTTS); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ctts_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->nb_entries && !ptr->entries) | |
| return GF_ISOM_INVALID_MEDIA; | |
| gf_bs_write_u32(bs, ptr->nb_entries); | |
| for (i=0; i<ptr->nb_entries; i++ ) { | |
| gf_bs_write_u32(bs, ptr->entries[i].sampleCount); | |
| if (ptr->version) { | |
| gf_bs_write_int(bs, ptr->entries[i].decodingOffset, 32); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->entries[i].decodingOffset); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err ctts_box_size(GF_Box *s) | |
| { | |
| GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *) s; | |
| ptr->size += 4 + (8 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void cslg_box_del(GF_Box *s) | |
| { | |
| GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| return; | |
| } | |
| GF_Err cslg_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s; | |
| if (s->version == 0) { | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| ptr->compositionToDTSShift = gf_bs_read_int(bs, 32); | |
| ptr->leastDecodeToDisplayDelta = gf_bs_read_int(bs, 32); | |
| ptr->greatestDecodeToDisplayDelta = gf_bs_read_int(bs, 32); | |
| ptr->compositionStartTime = gf_bs_read_int(bs, 32); | |
| ptr->compositionEndTime = gf_bs_read_int(bs, 32); | |
| return GF_OK; | |
| } else if (s->version == 1) { | |
| ISOM_DECREASE_SIZE(ptr, 40); | |
| ptr->compositionToDTSShift = gf_bs_read_int(bs, 64); | |
| ptr->leastDecodeToDisplayDelta = gf_bs_read_int(bs, 64); | |
| ptr->greatestDecodeToDisplayDelta = gf_bs_read_int(bs, 64); | |
| ptr->compositionStartTime = gf_bs_read_int(bs, 64); | |
| ptr->compositionEndTime = gf_bs_read_int(bs, 64); | |
| return GF_OK; | |
| } | |
| return GF_NOT_SUPPORTED; | |
| } | |
| GF_Box *cslg_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_CompositionToDecodeBox, GF_ISOM_BOX_TYPE_CSLG); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err cslg_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (s->version == 0) { | |
| gf_bs_write_int(bs, (s32) ptr->compositionToDTSShift, 32); | |
| gf_bs_write_int(bs, (s32) ptr->leastDecodeToDisplayDelta, 32); | |
| gf_bs_write_int(bs, (s32) ptr->greatestDecodeToDisplayDelta, 32); | |
| gf_bs_write_int(bs, (s32) ptr->compositionStartTime, 32); | |
| gf_bs_write_int(bs, (s32) ptr->compositionEndTime, 32); | |
| return GF_OK; | |
| } else if (s->version == 1) { | |
| gf_bs_write_long_int(bs, ptr->compositionToDTSShift, 64); | |
| gf_bs_write_long_int(bs, ptr->leastDecodeToDisplayDelta, 64); | |
| gf_bs_write_long_int(bs, ptr->greatestDecodeToDisplayDelta, 64); | |
| gf_bs_write_long_int(bs, ptr->compositionStartTime, 64); | |
| gf_bs_write_long_int(bs, ptr->compositionEndTime, 64); | |
| return GF_OK; | |
| } | |
| return GF_NOT_SUPPORTED; | |
| } | |
| GF_Err cslg_box_size(GF_Box *s) | |
| { | |
| GF_CompositionToDecodeBox *ptr = (GF_CompositionToDecodeBox *)s; | |
| if (s->version == 0) { | |
| ptr->size += 20; | |
| return GF_OK; | |
| } else if (s->version == 1) { | |
| ptr->size += 40; | |
| return GF_OK; | |
| } | |
| return GF_NOT_SUPPORTED; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ccst_box_del(GF_Box *s) | |
| { | |
| GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s; | |
| if (ptr) gf_free(ptr); | |
| return; | |
| } | |
| GF_Err ccst_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->all_ref_pics_intra = gf_bs_read_int(bs, 1); | |
| ptr->intra_pred_used = gf_bs_read_int(bs, 1); | |
| ptr->max_ref_per_pic = gf_bs_read_int(bs, 4); | |
| ptr->reserved = gf_bs_read_int(bs, 26); | |
| return GF_OK; | |
| } | |
| GF_Box *ccst_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_CodingConstraintsBox, GF_ISOM_BOX_TYPE_CCST); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ccst_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->all_ref_pics_intra, 1); | |
| gf_bs_write_int(bs, ptr->intra_pred_used, 1); | |
| gf_bs_write_int(bs, ptr->max_ref_per_pic, 4); | |
| gf_bs_write_int(bs, 0, 26); | |
| return GF_OK; | |
| } | |
| GF_Err ccst_box_size(GF_Box *s) | |
| { | |
| GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s; | |
| ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void url_box_del(GF_Box *s) | |
| { | |
| GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->location) gf_free(ptr->location); | |
| gf_free(ptr); | |
| return; | |
| } | |
| GF_Err url_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s; | |
| //imdt case | |
| if (ptr->type == GF_ISOM_BOX_TYPE_IMDT) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->imda_ref_id = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| if (ptr->size) { | |
| u32 location_size = (u32) ptr->size; | |
| if (location_size < 1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in svhd box\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->location = (char*)gf_malloc(location_size); | |
| if (! ptr->location) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->location, location_size); | |
| if (ptr->location[location_size-1]) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] url box location is not 0-terminated\n" )); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *url_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DataEntryURLBox, GF_ISOM_BOX_TYPE_URL); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err url_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| //imdt case | |
| if (ptr->type == GF_ISOM_BOX_TYPE_IMDT) { | |
| gf_bs_write_u32(bs, ptr->imda_ref_id); | |
| return GF_OK; | |
| } | |
| //the flag set indicates we have a string (WE HAVE TO for URLs) | |
| if ( !(ptr->flags & 1)) { | |
| if (ptr->location) { | |
| gf_bs_write_data(bs, ptr->location, (u32)strlen(ptr->location) + 1); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err url_box_size(GF_Box *s) | |
| { | |
| GF_DataEntryURLBox *ptr = (GF_DataEntryURLBox *)s; | |
| //imdt case | |
| if (ptr->type == GF_ISOM_BOX_TYPE_IMDT) { | |
| ptr->size+=4; | |
| return GF_OK; | |
| } | |
| if ( !(ptr->flags & 1)) { | |
| if (ptr->location) ptr->size += 1 + strlen(ptr->location); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void urn_box_del(GF_Box *s) | |
| { | |
| GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->location) gf_free(ptr->location); | |
| if (ptr->nameURN) gf_free(ptr->nameURN); | |
| gf_free(ptr); | |
| } | |
| GF_Err urn_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, to_read; | |
| char *tmpName; | |
| GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s; | |
| if (! ptr->size ) return GF_OK; | |
| //here we have to handle that in a clever way | |
| to_read = (u32) ptr->size; | |
| tmpName = (char*)gf_malloc(sizeof(char) * to_read); | |
| if (!tmpName) return GF_OUT_OF_MEM; | |
| //get the data | |
| gf_bs_read_data(bs, tmpName, to_read); | |
| //then get the break | |
| i = 0; | |
| while ( (i < to_read) && (tmpName[i] != 0) ) { | |
| i++; | |
| } | |
| //check the data is consistent | |
| if (i == to_read) { | |
| gf_free(tmpName); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| //no NULL char, URL is not specified | |
| if (i == to_read - 1) { | |
| ptr->nameURN = tmpName; | |
| ptr->location = NULL; | |
| return GF_OK; | |
| } | |
| //OK, this has both URN and URL | |
| ptr->nameURN = (char*)gf_malloc(sizeof(char) * (i+1)); | |
| if (!ptr->nameURN) { | |
| gf_free(tmpName); | |
| return GF_OUT_OF_MEM; | |
| } | |
| memcpy(ptr->nameURN, tmpName, i + 1); | |
| if (tmpName[to_read - 1] != 0) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] urn box contains invalid location field\n" )); | |
| } | |
| else { | |
| ptr->location = (char*)gf_malloc(sizeof(char) * (to_read - i - 1)); | |
| if (!ptr->location) { | |
| gf_free(tmpName); | |
| gf_free(ptr->nameURN); | |
| ptr->nameURN = NULL; | |
| return GF_OUT_OF_MEM; | |
| } | |
| memcpy(ptr->location, tmpName + i + 1, (to_read - i - 1)); | |
| } | |
| gf_free(tmpName); | |
| return GF_OK; | |
| } | |
| GF_Box *urn_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DataEntryURNBox, GF_ISOM_BOX_TYPE_URN); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err urn_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| //the flag set indicates we have a string (WE HAVE TO for URLs) | |
| if ( !(ptr->flags & 1)) { | |
| //to check, the spec says: First name, then location | |
| if (ptr->nameURN) { | |
| gf_bs_write_data(bs, ptr->nameURN, (u32)strlen(ptr->nameURN) + 1); | |
| } | |
| if (ptr->location) { | |
| gf_bs_write_data(bs, ptr->location, (u32)strlen(ptr->location) + 1); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err urn_box_size(GF_Box *s) | |
| { | |
| GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s; | |
| if ( !(ptr->flags & 1)) { | |
| if (ptr->nameURN) ptr->size += 1 + strlen(ptr->nameURN); | |
| if (ptr->location) ptr->size += 1 + strlen(ptr->location); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void unkn_box_del(GF_Box *s) | |
| { | |
| GF_UnknownBox *ptr = (GF_UnknownBox *) s; | |
| if (!s) return; | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Err unkn_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 bytesToRead, sub_size, sub_a; | |
| GF_BitStream *sub_bs; | |
| GF_UnknownBox *ptr = (GF_UnknownBox *)s; | |
| if (ptr->size > 0xFFFFFFFF) return GF_ISOM_INVALID_FILE; | |
| bytesToRead = (u32) (ptr->size); | |
| if (!bytesToRead) return GF_OK; | |
| if (bytesToRead>1000000) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Unknown box %s (0x%08X) with payload larger than 1 MBytes, ignoring\n", gf_4cc_to_str(ptr->original_4cc), ptr->original_4cc )); | |
| gf_bs_skip_bytes(bs, ptr->dataSize); | |
| return GF_OK; | |
| } | |
| ptr->data = (char*)gf_malloc(bytesToRead); | |
| if (ptr->data == NULL ) return GF_OUT_OF_MEM; | |
| ptr->dataSize = bytesToRead; | |
| gf_bs_read_data(bs, ptr->data, ptr->dataSize); | |
| //don't try to load sub boxes if already in udta child box loading | |
| if (gf_bs_get_cookie(bs) & GF_ISOM_BS_COOKIE_IN_UDTA) { | |
| return GF_OK; | |
| } | |
| //try to parse container boxes, check if next 8 bytes match a subbox | |
| sub_bs = gf_bs_new(ptr->data, ptr->dataSize, GF_BITSTREAM_READ); | |
| sub_size = gf_bs_read_u32(sub_bs); | |
| sub_a = gf_bs_read_u8(sub_bs); | |
| e = (sub_size && (sub_size <= ptr->dataSize)) ? GF_OK : GF_NOT_SUPPORTED; | |
| if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED; | |
| sub_a = gf_bs_read_u8(sub_bs); | |
| if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED; | |
| sub_a = gf_bs_read_u8(sub_bs); | |
| if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED; | |
| sub_a = gf_bs_read_u8(sub_bs); | |
| if (! isalnum(sub_a)) e = GF_NOT_SUPPORTED; | |
| if (e == GF_OK) { | |
| gf_bs_seek(sub_bs, 0); | |
| gf_bs_set_cookie(sub_bs, GF_ISOM_BS_COOKIE_NO_LOGS|GF_ISOM_BS_COOKIE_IN_UDTA); | |
| e = gf_isom_box_array_read(s, sub_bs); | |
| } | |
| gf_bs_del(sub_bs); | |
| if (e==GF_OK) { | |
| gf_free(ptr->data); | |
| ptr->data = NULL; | |
| ptr->dataSize = 0; | |
| } else if (s->child_boxes) { | |
| gf_isom_box_array_del(s->child_boxes); | |
| s->child_boxes=NULL; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *unkn_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_UnknownBox, GF_ISOM_BOX_TYPE_UNKNOWN); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err unkn_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 type; | |
| GF_UnknownBox *ptr = (GF_UnknownBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| if (ptr->original_4cc == GF_ISOM_BOX_TYPE_UUID) return GF_BAD_PARAM; | |
| type = s->type; | |
| ptr->type = ptr->original_4cc; | |
| e = gf_isom_box_write_header(s, bs); | |
| ptr->type = type; | |
| if (e) return e; | |
| if (ptr->sai_type) { | |
| if (ptr->saio_box) { | |
| u64 pos = gf_bs_get_position(bs); | |
| gf_bs_seek(bs, ptr->saio_box->offset_first_offset_field); | |
| if (ptr->saio_box->version) | |
| gf_bs_write_u64(bs, pos); | |
| else | |
| gf_bs_write_u32(bs, (u32) pos); | |
| gf_bs_seek(bs, pos); | |
| } else { | |
| ptr->sai_offset = gf_bs_get_position(bs); | |
| } | |
| } | |
| if (ptr->dataSize && ptr->data) { | |
| gf_bs_write_data(bs, ptr->data, ptr->dataSize); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err unkn_box_size(GF_Box *s) | |
| { | |
| GF_UnknownBox *ptr = (GF_UnknownBox *)s; | |
| if (ptr->dataSize && ptr->data) { | |
| ptr->size += ptr->dataSize; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void def_parent_box_del(GF_Box *s) | |
| { | |
| if (s) gf_free(s); | |
| } | |
| GF_Err def_parent_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *def_parent_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Box, 0); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err def_parent_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err def_parent_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void def_parent_full_box_del(GF_Box *s) | |
| { | |
| if (s) gf_free(s); | |
| } | |
| GF_Err def_parent_full_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *def_parent_full_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Box, 0); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err def_parent_full_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_full_box_write(s, bs); | |
| } | |
| GF_Err def_parent_full_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void uuid_box_del(GF_Box *s) | |
| { | |
| GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox *) s; | |
| if (!s) return; | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Err uuid_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 bytesToRead; | |
| GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox *)s; | |
| if (ptr->size > 0xFFFFFFFF) return GF_ISOM_INVALID_FILE; | |
| bytesToRead = (u32) (ptr->size); | |
| if (bytesToRead) { | |
| ptr->data = (char*)gf_malloc(bytesToRead); | |
| if (ptr->data == NULL ) return GF_OUT_OF_MEM; | |
| ptr->dataSize = bytesToRead; | |
| gf_bs_read_data(bs, ptr->data, ptr->dataSize); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *uuid_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_UnknownUUIDBox, GF_ISOM_BOX_TYPE_UUID); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err uuid_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox*)s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| if (ptr->data) { | |
| gf_bs_write_data(bs, ptr->data, ptr->dataSize); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err uuid_box_size(GF_Box *s) | |
| { | |
| GF_UnknownUUIDBox*ptr = (GF_UnknownUUIDBox*)s; | |
| ptr->size += ptr->dataSize; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void dinf_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err dinf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_DataInformationBox *ptr = (GF_DataInformationBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_DREF: | |
| BOX_FIELD_ASSIGN(dref, GF_DataReferenceBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err dinf_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DataInformationBox *dinf; | |
| GF_Err e = gf_isom_box_array_read(s, bs); | |
| if (e) { | |
| return e; | |
| } | |
| dinf = (GF_DataInformationBox *)s; | |
| if (!dinf->dref) { | |
| if (! (gf_bs_get_cookie(bs) & GF_ISOM_BS_COOKIE_NO_LOGS) ) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing dref box in dinf\n")); | |
| } | |
| dinf->dref = (GF_DataReferenceBox *) gf_isom_box_new_parent(&dinf->child_boxes, GF_ISOM_BOX_TYPE_DREF); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *dinf_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DataInformationBox, GF_ISOM_BOX_TYPE_DINF); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dinf_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err dinf_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void dref_box_del(GF_Box *s) | |
| { | |
| GF_DataReferenceBox *ptr = (GF_DataReferenceBox *) s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err dref_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DataReferenceBox *ptr = (GF_DataReferenceBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| gf_bs_read_u32(bs); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *dref_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DataReferenceBox, GF_ISOM_BOX_TYPE_DREF); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dref_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 count; | |
| GF_DataReferenceBox *ptr = (GF_DataReferenceBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| count = ptr->child_boxes ? gf_list_count(ptr->child_boxes) : 0; | |
| gf_bs_write_u32(bs, count); | |
| return GF_OK; | |
| } | |
| GF_Err dref_box_size(GF_Box *s) | |
| { | |
| GF_DataReferenceBox *ptr = (GF_DataReferenceBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void edts_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err edts_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_EditBox *ptr = (GF_EditBox *)s; | |
| if (a->type == GF_ISOM_BOX_TYPE_ELST) { | |
| BOX_FIELD_ASSIGN(editList, GF_EditListBox) | |
| return GF_OK; | |
| } else { | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err edts_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *edts_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_EditBox, GF_ISOM_BOX_TYPE_EDTS); | |
| return (GF_Box *) tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err edts_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_EditBox *ptr = (GF_EditBox *)s; | |
| //here we have a trick: if editList is empty, skip the box | |
| if (ptr->editList && gf_list_count(ptr->editList->entryList)) { | |
| return gf_isom_box_write_header(s, bs); | |
| } else { | |
| s->size = 0; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err edts_box_size(GF_Box *s) | |
| { | |
| GF_EditBox *ptr = (GF_EditBox *)s; | |
| //here we have a trick: if editList is empty, skip the box | |
| if (!ptr->editList || ! gf_list_count(ptr->editList->entryList)) { | |
| ptr->size = 0; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void elst_box_del(GF_Box *s) | |
| { | |
| GF_EditListBox *ptr; | |
| u32 nb_entries; | |
| u32 i; | |
| ptr = (GF_EditListBox *)s; | |
| if (ptr == NULL) return; | |
| nb_entries = gf_list_count(ptr->entryList); | |
| for (i = 0; i < nb_entries; i++) { | |
| GF_EdtsEntry *p = (GF_EdtsEntry*)gf_list_get(ptr->entryList, i); | |
| if (p) gf_free(p); | |
| } | |
| gf_list_del(ptr->entryList); | |
| gf_free(ptr); | |
| } | |
| GF_Err elst_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 entries; | |
| s32 tr; | |
| u32 nb_entries; | |
| GF_EditListBox *ptr = (GF_EditListBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->version == 1) { | |
| if (nb_entries > ptr->size / 20) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } else { | |
| if (nb_entries > ptr->size / 12) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| for (entries = 0; entries < nb_entries; entries++) { | |
| GF_EdtsEntry *p; | |
| GF_SAFEALLOC(p, GF_EdtsEntry); | |
| if (!p) return GF_OUT_OF_MEM; | |
| if (ptr->version == 1) { | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| p->segmentDuration = gf_bs_read_u64(bs); | |
| p->mediaTime = (s64) gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| p->segmentDuration = gf_bs_read_u32(bs); | |
| tr = gf_bs_read_u32(bs); | |
| p->mediaTime = (s64) tr; | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| p->mediaRate = gf_bs_read_u32(bs); | |
| gf_list_add(ptr->entryList, p); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *elst_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_EditListBox, GF_ISOM_BOX_TYPE_ELST); | |
| tmp->entryList = gf_list_new(); | |
| if (!tmp->entryList) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err elst_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| u32 nb_entries; | |
| GF_EditListBox *ptr = (GF_EditListBox *)s; | |
| if (!ptr) return GF_BAD_PARAM; | |
| nb_entries = gf_list_count(ptr->entryList); | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, nb_entries); | |
| for (i = 0; i < nb_entries; i++ ) { | |
| GF_EdtsEntry *p = (GF_EdtsEntry*)gf_list_get(ptr->entryList, i); | |
| if (ptr->version == 1) { | |
| gf_bs_write_u64(bs, p->segmentDuration); | |
| gf_bs_write_u64(bs, p->mediaTime); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) p->segmentDuration); | |
| gf_bs_write_u32(bs, (s32) p->mediaTime); | |
| } | |
| gf_bs_write_u32(bs, p->mediaRate); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err elst_box_size(GF_Box *s) | |
| { | |
| u32 durtimebytes; | |
| u32 i, nb_entries; | |
| GF_EditListBox *ptr = (GF_EditListBox *)s; | |
| //entry count | |
| ptr->size += 4; | |
| nb_entries = gf_list_count(ptr->entryList); | |
| ptr->version = 0; | |
| for (i=0; i<nb_entries; i++) { | |
| GF_EdtsEntry *p = (GF_EdtsEntry*)gf_list_get(ptr->entryList, i); | |
| if ((p->segmentDuration>0xFFFFFFFF) || (p->mediaTime>0xFFFFFFFF)) { | |
| ptr->version = 1; | |
| break; | |
| } | |
| } | |
| durtimebytes = (ptr->version == 1 ? 16 : 8) + 4; | |
| ptr->size += (nb_entries * durtimebytes); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void esds_box_del(GF_Box *s) | |
| { | |
| GF_ESDBox *ptr = (GF_ESDBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->desc) gf_odf_desc_del((GF_Descriptor *)ptr->desc); | |
| gf_free(ptr); | |
| } | |
| GF_Err esds_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e=GF_OK; | |
| u32 descSize; | |
| GF_ESDBox *ptr = (GF_ESDBox *)s; | |
| descSize = (u32) (ptr->size); | |
| if (descSize) { | |
| char *enc_desc = (char*)gf_malloc(sizeof(char) * descSize); | |
| if (!enc_desc) return GF_OUT_OF_MEM; | |
| //get the payload | |
| gf_bs_read_data(bs, enc_desc, descSize); | |
| //send it to the OD Codec | |
| e = gf_odf_desc_read(enc_desc, descSize, (GF_Descriptor **) &ptr->desc); | |
| //OK, free our desc | |
| gf_free(enc_desc); | |
| if (ptr->desc && (ptr->desc->tag!=GF_ODF_ESD_TAG) ) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid descriptor tag 0x%x in esds\n", ptr->desc->tag)); | |
| gf_odf_desc_del((GF_Descriptor*)ptr->desc); | |
| ptr->desc=NULL; | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (e) { | |
| ptr->desc = NULL; | |
| } else { | |
| /*fix broken files*/ | |
| if (ptr->desc && !ptr->desc->URLString) { | |
| if (!ptr->desc->slConfig) { | |
| ptr->desc->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); | |
| ptr->desc->slConfig->predefined = SLPredef_MP4; | |
| } else if (ptr->desc->slConfig->predefined != SLPredef_MP4) { | |
| ptr->desc->slConfig->predefined = SLPredef_MP4; | |
| gf_odf_slc_set_pref(ptr->desc->slConfig); | |
| } | |
| } | |
| } | |
| } | |
| return e; | |
| } | |
| GF_Box *esds_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ESDBox, GF_ISOM_BOX_TYPE_ESDS); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err esds_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u8 *enc_desc; | |
| u32 descSize = 0; | |
| GF_ESDBox *ptr = (GF_ESDBox *)s; | |
| //make sure we write with no ESID and no OCRESID | |
| if (ptr->desc) { | |
| ptr->desc->ESID = 0; | |
| ptr->desc->OCRESID = 0; | |
| } | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| e = gf_odf_desc_write((GF_Descriptor *)ptr->desc, &enc_desc, &descSize); | |
| if (e) return e; | |
| gf_bs_write_data(bs, enc_desc, descSize); | |
| //free our buffer | |
| gf_free(enc_desc); | |
| return GF_OK; | |
| } | |
| GF_Err esds_box_size(GF_Box *s) | |
| { | |
| u32 descSize = 0; | |
| GF_ESDBox *ptr = (GF_ESDBox *)s; | |
| //make sure we write with no ESID and no OCRESID | |
| if (ptr->desc) { | |
| ptr->desc->ESID = 0; | |
| ptr->desc->OCRESID = 0; | |
| } | |
| descSize = gf_odf_desc_size((GF_Descriptor *)ptr->desc); | |
| ptr->size += descSize; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void free_box_del(GF_Box *s) | |
| { | |
| GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s; | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Err free_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 bytesToRead; | |
| GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s; | |
| if (ptr->size > 0xFFFFFFFF) return GF_IO_ERR; | |
| bytesToRead = (u32) (ptr->size); | |
| if (bytesToRead) { | |
| ptr->data = (char*)gf_malloc(bytesToRead * sizeof(char)); | |
| if (!ptr->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->data, bytesToRead); | |
| ptr->dataSize = bytesToRead; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *free_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_FreeSpaceBox, GF_ISOM_BOX_TYPE_FREE); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err free_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s; | |
| if (ptr->original_4cc) { | |
| u32 t = s->type; | |
| s->type=ptr->original_4cc; | |
| e = gf_isom_box_write_header(s, bs); | |
| s->type=t; | |
| } else { | |
| e = gf_isom_box_write_header(s, bs); | |
| } | |
| if (e) return e; | |
| if (ptr->dataSize) { | |
| if (ptr->data) { | |
| gf_bs_write_data(bs, ptr->data, ptr->dataSize); | |
| } else { | |
| u32 i = 0; | |
| while (i<ptr->dataSize) { | |
| gf_bs_write_u8(bs, 0); | |
| i++; | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err free_box_size(GF_Box *s) | |
| { | |
| GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s; | |
| ptr->size += ptr->dataSize; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ftyp_box_del(GF_Box *s) | |
| { | |
| GF_FileTypeBox *ptr = (GF_FileTypeBox *) s; | |
| if (ptr->altBrand) gf_free(ptr->altBrand); | |
| gf_free(ptr); | |
| } | |
| GF_Box *ftyp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_FileTypeBox, GF_ISOM_BOX_TYPE_FTYP); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err ftyp_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_FileTypeBox *ptr = (GF_FileTypeBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->majorBrand = gf_bs_read_u32(bs); | |
| ptr->minorVersion = gf_bs_read_u32(bs); | |
| if (ptr->size % 4) return GF_ISOM_INVALID_FILE; | |
| ptr->altCount = ( (u32) (ptr->size)) / 4; | |
| if (!ptr->altCount) return GF_OK; | |
| ptr->altBrand = (u32*)gf_malloc(sizeof(u32)*ptr->altCount); | |
| if (!ptr->altBrand) return GF_OUT_OF_MEM; | |
| for (i = 0; i<ptr->altCount; i++) { | |
| ptr->altBrand[i] = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ftyp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_FileTypeBox *ptr = (GF_FileTypeBox *) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->majorBrand); | |
| gf_bs_write_u32(bs, ptr->minorVersion); | |
| for (i=0; i<ptr->altCount; i++) { | |
| gf_bs_write_u32(bs, ptr->altBrand[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err ftyp_box_size(GF_Box *s) | |
| { | |
| GF_FileTypeBox *ptr = (GF_FileTypeBox *)s; | |
| ptr->size += 8 + ptr->altCount * 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void gnrm_box_del(GF_Box *s) | |
| { | |
| GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr); | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Box *gnrm_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_GenericSampleEntryBox, GF_ISOM_BOX_TYPE_GNRM); | |
| gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err gnrm_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s; | |
| GF_Err e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)s, bs); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| if (ptr->size) { | |
| ptr->data_size = (u32) ptr->size; | |
| ptr->data = (char*)gf_malloc(ptr->data_size * sizeof(char)); | |
| if (!ptr->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->data, ptr->data_size); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err gnrm_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s; | |
| //careful we are not writing the box type but the entry type so switch for write | |
| if (ptr->EntryType == GF_ISOM_BOX_TYPE_UUID) return GF_BAD_PARAM; | |
| ptr->type = ptr->EntryType; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| ptr->type = GF_ISOM_BOX_TYPE_GNRM; | |
| gf_bs_write_data(bs, ptr->reserved, 6); | |
| gf_bs_write_u16(bs, ptr->dataReferenceIndex); | |
| gf_bs_write_data(bs, ptr->data, ptr->data_size); | |
| return GF_OK; | |
| } | |
| GF_Err gnrm_box_size(GF_Box *s) | |
| { | |
| GF_GenericSampleEntryBox *ptr = (GF_GenericSampleEntryBox *)s; | |
| s->type = GF_ISOM_BOX_TYPE_GNRM; | |
| ptr->size += 8+ptr->data_size; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void gnrv_box_del(GF_Box *s) | |
| { | |
| GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr); | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Box *gnrv_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_GenericVisualSampleEntryBox, GF_ISOM_BOX_TYPE_GNRV); | |
| gf_isom_video_sample_entry_init((GF_VisualSampleEntryBox*) tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err gnrv_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s; | |
| GF_Err e = gf_isom_video_sample_entry_read((GF_VisualSampleEntryBox *)ptr, bs); | |
| if (e) return e; | |
| if (ptr->size) { | |
| ptr->data_size = (u32) ptr->size; | |
| ptr->data = (char*)gf_malloc(ptr->data_size * sizeof(char)); | |
| if (!ptr->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->data, ptr->data_size); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err gnrv_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s; | |
| //careful we are not writing the box type but the entry type so switch for write | |
| if (ptr->EntryType == GF_ISOM_BOX_TYPE_UUID) return GF_BAD_PARAM; | |
| ptr->type = ptr->EntryType; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| ptr->type = GF_ISOM_BOX_TYPE_GNRV; | |
| gf_isom_video_sample_entry_write((GF_VisualSampleEntryBox *)ptr, bs); | |
| gf_bs_write_data(bs, ptr->data, ptr->data_size); | |
| return GF_OK; | |
| } | |
| GF_Err gnrv_box_size(GF_Box *s) | |
| { | |
| GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s; | |
| s->type = GF_ISOM_BOX_TYPE_GNRV; | |
| gf_isom_video_sample_entry_size((GF_VisualSampleEntryBox *)s); | |
| ptr->size += ptr->data_size; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void gnra_box_del(GF_Box *s) | |
| { | |
| GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr); | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Box *gnra_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_GenericAudioSampleEntryBox, GF_ISOM_BOX_TYPE_GNRA); | |
| gf_isom_audio_sample_entry_init((GF_AudioSampleEntryBox*) tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err gnra_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s; | |
| GF_Err e = gf_isom_audio_sample_entry_read((GF_AudioSampleEntryBox *)ptr, bs); | |
| if (e) return e; | |
| if (ptr->size) { | |
| ptr->data_size = (u32) ptr->size; | |
| ptr->data = (char*)gf_malloc(ptr->data_size * sizeof(char)); | |
| if (!ptr->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->data, ptr->data_size); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err gnra_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s; | |
| //careful we are not writing the box type but the entry type so switch for write | |
| if (ptr->EntryType == GF_ISOM_BOX_TYPE_UUID) return GF_BAD_PARAM; | |
| ptr->type = ptr->EntryType; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| ptr->type = GF_ISOM_BOX_TYPE_GNRA; | |
| gf_isom_audio_sample_entry_write((GF_AudioSampleEntryBox *)ptr, bs); | |
| if (ptr->data) { | |
| gf_bs_write_data(bs, ptr->data, ptr->data_size); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gnra_box_size(GF_Box *s) | |
| { | |
| GF_GenericAudioSampleEntryBox *ptr = (GF_GenericAudioSampleEntryBox *)s; | |
| s->type = GF_ISOM_BOX_TYPE_GNRA; | |
| gf_isom_audio_sample_entry_size((GF_AudioSampleEntryBox *)s); | |
| ptr->size += ptr->data_size; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void hdlr_box_del(GF_Box *s) | |
| { | |
| GF_HandlerBox *ptr = (GF_HandlerBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->nameUTF8) gf_free(ptr->nameUTF8); | |
| gf_free(ptr); | |
| } | |
| GF_Err hdlr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u64 cookie; | |
| GF_HandlerBox *ptr = (GF_HandlerBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| ptr->reserved1 = gf_bs_read_u32(bs); | |
| ptr->handlerType = gf_bs_read_u32(bs); | |
| gf_bs_read_data(bs, (char*)ptr->reserved2, 12); | |
| cookie = gf_bs_get_cookie(bs); | |
| if (ptr->handlerType==GF_ISOM_MEDIA_VISUAL) | |
| cookie |= GF_ISOM_BS_COOKIE_VISUAL_TRACK; | |
| else | |
| cookie &= ~GF_ISOM_BS_COOKIE_VISUAL_TRACK; | |
| gf_bs_set_cookie(bs, cookie); | |
| if (ptr->size) { | |
| u32 name_size = (u32) ptr->size; | |
| if (name_size < 1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in hdlr\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->nameUTF8 = (char*)gf_malloc(name_size); | |
| if (!ptr->nameUTF8) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->nameUTF8, name_size); | |
| //patch for old QT files - we cannot rely on checking if str[0]==len(str+1) since we may have | |
| //cases where the first character of the string decimal value is indeed the same as the string length!! | |
| //we had this issue with encryption_import test | |
| //we therefore only check if last char is null, and if not so assume old QT style | |
| if (ptr->nameUTF8[name_size-1]) { | |
| if (name_size > 1) | |
| memmove(ptr->nameUTF8, ptr->nameUTF8+1, sizeof(char) * (u32) (name_size-1) ); | |
| ptr->nameUTF8[name_size-1] = 0; | |
| ptr->store_counted_string = GF_TRUE; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *hdlr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_HandlerBox, GF_ISOM_BOX_TYPE_HDLR); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err hdlr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_HandlerBox *ptr = (GF_HandlerBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->reserved1); | |
| gf_bs_write_u32(bs, ptr->handlerType); | |
| gf_bs_write_data(bs, (char*)ptr->reserved2, 12); | |
| if (ptr->nameUTF8) { | |
| u32 len = (u32)strlen(ptr->nameUTF8); | |
| if (ptr->store_counted_string) { | |
| gf_bs_write_u8(bs, len); | |
| gf_bs_write_data(bs, ptr->nameUTF8, len); | |
| } else { | |
| gf_bs_write_data(bs, ptr->nameUTF8, len); | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| } else { | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err hdlr_box_size(GF_Box *s) | |
| { | |
| GF_HandlerBox *ptr = (GF_HandlerBox *)s; | |
| ptr->size += 20 + 1; //null term or counted string | |
| if (ptr->nameUTF8) { | |
| ptr->size += strlen(ptr->nameUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void hinf_box_del(GF_Box *s) | |
| { | |
| GF_HintInfoBox *hinf = (GF_HintInfoBox *)s; | |
| gf_free(hinf); | |
| } | |
| GF_Box *hinf_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_HintInfoBox, GF_ISOM_BOX_TYPE_HINF); | |
| tmp->child_boxes = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err hinf_on_child_box(GF_Box *s, GF_Box *_a, Bool is_rem) | |
| { | |
| GF_HintInfoBox *hinf = (GF_HintInfoBox *)s; | |
| switch (_a->type) { | |
| case GF_ISOM_BOX_TYPE_MAXR: | |
| if (!is_rem) { | |
| u32 i=0; | |
| GF_MAXRBox *a = (GF_MAXRBox *)_a; | |
| GF_MAXRBox *maxR; | |
| while ((maxR = (GF_MAXRBox *)gf_list_enum(hinf->child_boxes, &i))) { | |
| if ((maxR != a) && (maxR->type==GF_ISOM_BOX_TYPE_MAXR) && (maxR->granularity == a->granularity)) | |
| ERROR_ON_DUPLICATED_BOX(_a, s) | |
| } | |
| } | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err hinf_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err hinf_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| // GF_HintInfoBox *ptr = (GF_HintInfoBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err hinf_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void hmhd_box_del(GF_Box *s) | |
| { | |
| GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err hmhd_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| ptr->maxPDUSize = gf_bs_read_u16(bs); | |
| ptr->avgPDUSize = gf_bs_read_u16(bs); | |
| ptr->maxBitrate = gf_bs_read_u32(bs); | |
| ptr->avgBitrate = gf_bs_read_u32(bs); | |
| ptr->slidingAverageBitrate = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *hmhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_HintMediaHeaderBox, GF_ISOM_BOX_TYPE_HMHD); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err hmhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->maxPDUSize); | |
| gf_bs_write_u16(bs, ptr->avgPDUSize); | |
| gf_bs_write_u32(bs, ptr->maxBitrate); | |
| gf_bs_write_u32(bs, ptr->avgBitrate); | |
| gf_bs_write_u32(bs, ptr->slidingAverageBitrate); | |
| return GF_OK; | |
| } | |
| GF_Err hmhd_box_size(GF_Box *s) | |
| { | |
| GF_HintMediaHeaderBox *ptr = (GF_HintMediaHeaderBox *)s; | |
| ptr->size += 16; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *hnti_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_HintTrackInfoBox, GF_ISOM_BOX_TYPE_HNTI); | |
| return (GF_Box *)tmp; | |
| } | |
| void hnti_box_del(GF_Box *a) | |
| { | |
| gf_free(a); | |
| } | |
| GF_Err hnti_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_HintTrackInfoBox *ptr = (GF_HintTrackInfoBox *)s; | |
| if (!ptr || !a) return GF_BAD_PARAM; | |
| switch (a->type) { | |
| //this is the value for GF_RTPBox - same as HintSampleEntry for RTP !!! | |
| case GF_ISOM_BOX_TYPE_RTP: | |
| case GF_ISOM_BOX_TYPE_SDP: | |
| BOX_FIELD_ASSIGN(SDP, GF_Box) | |
| break; | |
| default: | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err hnti_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err hnti_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err hnti_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| GF_SDPBox | |
| **********************************************************/ | |
| void sdp_box_del(GF_Box *s) | |
| { | |
| GF_SDPBox *ptr = (GF_SDPBox *)s; | |
| if (ptr->sdpText) gf_free(ptr->sdpText); | |
| gf_free(ptr); | |
| } | |
| GF_Err sdp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 length; | |
| GF_SDPBox *ptr = (GF_SDPBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| length = (u32) (ptr->size); | |
| if (length >= (u32)0xFFFFFFFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid length %lu in sdp box\n", length)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| //sdp text has no delimiter !!! | |
| ptr->sdpText = (char*)gf_malloc(sizeof(char) * (length+1)); | |
| if (!ptr->sdpText) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->sdpText, length); | |
| ptr->sdpText[length] = 0; | |
| return GF_OK; | |
| } | |
| GF_Box *sdp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SDPBox, GF_ISOM_BOX_TYPE_SDP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err sdp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SDPBox *ptr = (GF_SDPBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| //don't write the NULL char!!! | |
| if (ptr->sdpText) | |
| gf_bs_write_data(bs, ptr->sdpText, (u32) strlen(ptr->sdpText)); | |
| return GF_OK; | |
| } | |
| GF_Err sdp_box_size(GF_Box *s) | |
| { | |
| GF_SDPBox *ptr = (GF_SDPBox *)s; | |
| //don't count the NULL char!!! | |
| if (ptr->sdpText) | |
| ptr->size += strlen(ptr->sdpText); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void rtp_hnti_box_del(GF_Box *s) | |
| { | |
| GF_RTPBox *ptr = (GF_RTPBox *)s; | |
| if (ptr->sdpText) gf_free(ptr->sdpText); | |
| gf_free(ptr); | |
| } | |
| GF_Err rtp_hnti_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 length; | |
| GF_RTPBox *ptr = (GF_RTPBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->subType = gf_bs_read_u32(bs); | |
| length = (u32) (ptr->size); | |
| if (length >= (u32)0xFFFFFFFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid length %lu in rtp_hnti box\n", length)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| //sdp text has no delimiter !!! | |
| ptr->sdpText = (char*)gf_malloc(sizeof(char) * (length+1)); | |
| if (!ptr->sdpText) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->sdpText, length); | |
| ptr->sdpText[length] = 0; | |
| return GF_OK; | |
| } | |
| GF_Box *rtp_hnti_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_RTPBox, GF_ISOM_BOX_TYPE_RTP); | |
| tmp->subType = GF_ISOM_BOX_TYPE_SDP; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err rtp_hnti_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_RTPBox *ptr = (GF_RTPBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->subType); | |
| //don't write the NULL char!!! | |
| gf_bs_write_data(bs, ptr->sdpText, (u32) strlen(ptr->sdpText)); | |
| return GF_OK; | |
| } | |
| GF_Err rtp_hnti_box_size(GF_Box *s) | |
| { | |
| GF_RTPBox *ptr = (GF_RTPBox *)s; | |
| ptr->size += 4 + strlen(ptr->sdpText); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| TRPY GF_Box | |
| **********************************************************/ | |
| void trpy_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_TRPYBox *)s); | |
| } | |
| GF_Err trpy_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TRPYBox *ptr = (GF_TRPYBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->nbBytes = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *trpy_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TRPYBox, GF_ISOM_BOX_TYPE_TRPY); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trpy_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TRPYBox *ptr = (GF_TRPYBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err trpy_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| TOTL GF_Box | |
| **********************************************************/ | |
| void totl_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_TRPYBox *)s); | |
| } | |
| GF_Err totl_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TOTLBox *ptr = (GF_TOTLBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nbBytes = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *totl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TOTLBox, GF_ISOM_BOX_TYPE_TOTL); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err totl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TOTLBox *ptr = (GF_TOTLBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err totl_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| NUMP GF_Box | |
| **********************************************************/ | |
| void nump_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_NUMPBox *)s); | |
| } | |
| GF_Err nump_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_NUMPBox *ptr = (GF_NUMPBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->nbPackets = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *nump_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_NUMPBox, GF_ISOM_BOX_TYPE_NUMP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err nump_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_NUMPBox *ptr = (GF_NUMPBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->nbPackets); | |
| return GF_OK; | |
| } | |
| GF_Err nump_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| NPCK GF_Box | |
| **********************************************************/ | |
| void npck_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_NPCKBox *)s); | |
| } | |
| GF_Err npck_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_NPCKBox *ptr = (GF_NPCKBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nbPackets = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *npck_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_NPCKBox, GF_ISOM_BOX_TYPE_NPCK); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err npck_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_NPCKBox *ptr = (GF_NPCKBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nbPackets); | |
| return GF_OK; | |
| } | |
| GF_Err npck_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| TPYL GF_Box | |
| **********************************************************/ | |
| void tpyl_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_NTYLBox *)s); | |
| } | |
| GF_Err tpyl_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_NTYLBox *ptr = (GF_NTYLBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->nbBytes = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tpyl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_NTYLBox, GF_ISOM_BOX_TYPE_TPYL); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tpyl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_NTYLBox *ptr = (GF_NTYLBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err tpyl_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| TPAY GF_Box | |
| **********************************************************/ | |
| void tpay_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_TPAYBox *)s); | |
| } | |
| GF_Err tpay_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TPAYBox *ptr = (GF_TPAYBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nbBytes = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tpay_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TPAYBox, GF_ISOM_BOX_TYPE_TPAY); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tpay_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TPAYBox *ptr = (GF_TPAYBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err tpay_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| MAXR GF_Box | |
| **********************************************************/ | |
| void maxr_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_MAXRBox *)s); | |
| } | |
| GF_Err maxr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MAXRBox *ptr = (GF_MAXRBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->granularity = gf_bs_read_u32(bs); | |
| ptr->maxDataRate = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *maxr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MAXRBox, GF_ISOM_BOX_TYPE_MAXR); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err maxr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MAXRBox *ptr = (GF_MAXRBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->granularity); | |
| gf_bs_write_u32(bs, ptr->maxDataRate); | |
| return GF_OK; | |
| } | |
| GF_Err maxr_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| DMED GF_Box | |
| **********************************************************/ | |
| void dmed_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_DMEDBox *)s); | |
| } | |
| GF_Err dmed_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DMEDBox *ptr = (GF_DMEDBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->nbBytes = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *dmed_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DMEDBox, GF_ISOM_BOX_TYPE_DMED); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dmed_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DMEDBox *ptr = (GF_DMEDBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err dmed_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| DIMM GF_Box | |
| **********************************************************/ | |
| void dimm_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_DIMMBox *)s); | |
| } | |
| GF_Err dimm_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DIMMBox *ptr = (GF_DIMMBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| ptr->nbBytes = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *dimm_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DIMMBox, GF_ISOM_BOX_TYPE_DIMM); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dimm_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DIMMBox *ptr = (GF_DIMMBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err dimm_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| DREP GF_Box | |
| **********************************************************/ | |
| void drep_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_DREPBox *)s); | |
| } | |
| GF_Err drep_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DREPBox *ptr = (GF_DREPBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| ptr->nbBytes = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *drep_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DREPBox, GF_ISOM_BOX_TYPE_DREP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err drep_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DREPBox *ptr = (GF_DREPBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->nbBytes); | |
| return GF_OK; | |
| } | |
| GF_Err drep_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| TMIN GF_Box | |
| **********************************************************/ | |
| void tmin_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_TMINBox *)s); | |
| } | |
| GF_Err tmin_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TMINBox *ptr = (GF_TMINBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->minTime = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tmin_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TMINBox, GF_ISOM_BOX_TYPE_TMIN); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tmin_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TMINBox *ptr = (GF_TMINBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->minTime); | |
| return GF_OK; | |
| } | |
| GF_Err tmin_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| TMAX GF_Box | |
| **********************************************************/ | |
| void tmax_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_TMAXBox *)s); | |
| } | |
| GF_Err tmax_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TMAXBox *ptr = (GF_TMAXBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->maxTime = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tmax_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TMAXBox, GF_ISOM_BOX_TYPE_TMAX); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tmax_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TMAXBox *ptr = (GF_TMAXBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->maxTime); | |
| return GF_OK; | |
| } | |
| GF_Err tmax_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| PMAX GF_Box | |
| **********************************************************/ | |
| void pmax_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_PMAXBox *)s); | |
| } | |
| GF_Err pmax_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_PMAXBox *ptr = (GF_PMAXBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->maxSize = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *pmax_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PMAXBox, GF_ISOM_BOX_TYPE_PMAX); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err pmax_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_PMAXBox *ptr = (GF_PMAXBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->maxSize); | |
| return GF_OK; | |
| } | |
| GF_Err pmax_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| DMAX GF_Box | |
| **********************************************************/ | |
| void dmax_box_del(GF_Box *s) | |
| { | |
| gf_free((GF_DMAXBox *)s); | |
| } | |
| GF_Err dmax_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DMAXBox *ptr = (GF_DMAXBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->maxDur = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *dmax_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DMAXBox, GF_ISOM_BOX_TYPE_DMAX); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dmax_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DMAXBox *ptr = (GF_DMAXBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->maxDur); | |
| return GF_OK; | |
| } | |
| GF_Err dmax_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| PAYT GF_Box | |
| **********************************************************/ | |
| void payt_box_del(GF_Box *s) | |
| { | |
| GF_PAYTBox *payt = (GF_PAYTBox *)s; | |
| if (payt->payloadString) gf_free(payt->payloadString); | |
| gf_free(payt); | |
| } | |
| GF_Err payt_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 length; | |
| GF_PAYTBox *ptr = (GF_PAYTBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 5 ); | |
| ptr->payloadCode = gf_bs_read_u32(bs); | |
| length = gf_bs_read_u8(bs); | |
| ISOM_DECREASE_SIZE(ptr, length); | |
| ptr->payloadString = (char*)gf_malloc(sizeof(char) * (length+1) ); | |
| if (! ptr->payloadString) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->payloadString, length); | |
| ptr->payloadString[length] = 0; | |
| return GF_OK; | |
| } | |
| GF_Box *payt_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PAYTBox, GF_ISOM_BOX_TYPE_PAYT); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err payt_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 len; | |
| GF_Err e; | |
| GF_PAYTBox *ptr = (GF_PAYTBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->payloadCode); | |
| len = ptr->payloadString ? (u32) strlen(ptr->payloadString) : 0; | |
| gf_bs_write_u8(bs, len); | |
| if (len) gf_bs_write_data(bs, ptr->payloadString, len); | |
| return GF_OK; | |
| } | |
| GF_Err payt_box_size(GF_Box *s) | |
| { | |
| GF_PAYTBox *ptr = (GF_PAYTBox *)s; | |
| s->size += 4 + 1; | |
| if (ptr->payloadString) ptr->size += strlen(ptr->payloadString); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /********************************************************** | |
| PAYT GF_Box | |
| **********************************************************/ | |
| void name_box_del(GF_Box *s) | |
| { | |
| GF_NameBox *name = (GF_NameBox *)s; | |
| if (name->string) gf_free(name->string); | |
| gf_free(name); | |
| } | |
| GF_Err name_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 length; | |
| GF_NameBox *ptr = (GF_NameBox *)s; | |
| length = (u32) (ptr->size); | |
| if (length >= (u32)0xFFFFFFFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid length %lu in name box\n", length)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->string = (char*)gf_malloc(sizeof(char) * (length+1)); | |
| if (! ptr->string) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->string, length); | |
| ptr->string[length] = 0; | |
| return GF_OK; | |
| } | |
| GF_Box *name_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_NameBox, GF_QT_BOX_TYPE_NAME); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err name_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_NameBox *ptr = (GF_NameBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| if (gf_isom_box_is_full_box(s)) | |
| e = gf_isom_full_box_write(s, bs); | |
| else | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| if (ptr->string) { | |
| //do not write the terminating 0 | |
| gf_bs_write_data(bs, ptr->string, (u32) strlen(ptr->string)); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err name_box_size(GF_Box *s) | |
| { | |
| GF_NameBox *ptr = (GF_NameBox *)s; | |
| //do not count the terminating 0 | |
| if (ptr->string) ptr->size += strlen(ptr->string); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void tssy_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err tssy_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TimeStampSynchronyBox *ptr = (GF_TimeStampSynchronyBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 1) | |
| gf_bs_read_int(bs, 6); | |
| ptr->timestamp_sync = gf_bs_read_int(bs, 2); | |
| return GF_OK; | |
| } | |
| GF_Box *tssy_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TimeStampSynchronyBox, GF_ISOM_BOX_TYPE_TSSY); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tssy_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TimeStampSynchronyBox *ptr = (GF_TimeStampSynchronyBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, 0, 6); | |
| gf_bs_write_int(bs, ptr->timestamp_sync, 2); | |
| return GF_OK; | |
| } | |
| GF_Err tssy_box_size(GF_Box *s) | |
| { | |
| s->size += 1; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void srpp_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err srpp_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_SCHI: | |
| BOX_FIELD_ASSIGN(info, GF_SchemeInformationBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SCHM: | |
| BOX_FIELD_ASSIGN(scheme_type, GF_SchemeTypeBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err srpp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s; | |
| ISOM_DECREASE_SIZE(s, 16) | |
| ptr->encryption_algorithm_rtp = gf_bs_read_u32(bs); | |
| ptr->encryption_algorithm_rtcp = gf_bs_read_u32(bs); | |
| ptr->integrity_algorithm_rtp = gf_bs_read_u32(bs); | |
| ptr->integrity_algorithm_rtcp = gf_bs_read_u32(bs); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *srpp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SRTPProcessBox, GF_ISOM_BOX_TYPE_SRPP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err srpp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->encryption_algorithm_rtp); | |
| gf_bs_write_u32(bs, ptr->encryption_algorithm_rtcp); | |
| gf_bs_write_u32(bs, ptr->integrity_algorithm_rtp); | |
| gf_bs_write_u32(bs, ptr->integrity_algorithm_rtcp); | |
| return GF_OK; | |
| } | |
| GF_Err srpp_box_size(GF_Box *s) | |
| { | |
| u32 pos = 0; | |
| GF_SRTPProcessBox *ptr = (GF_SRTPProcessBox *)s; | |
| s->size += 16; | |
| gf_isom_check_position(s, (GF_Box*)ptr->info, &pos); | |
| gf_isom_check_position(s, (GF_Box*)ptr->scheme_type, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void rssr_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err rssr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_ReceivedSsrcBox *ptr = (GF_ReceivedSsrcBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->ssrc = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *rssr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ReceivedSsrcBox, GF_ISOM_BOX_TYPE_RSSR); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err rssr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ReceivedSsrcBox *ptr = (GF_ReceivedSsrcBox *)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->ssrc); | |
| return GF_OK; | |
| } | |
| GF_Err rssr_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void iods_box_del(GF_Box *s) | |
| { | |
| GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->descriptor) gf_odf_desc_del(ptr->descriptor); | |
| gf_free(ptr); | |
| } | |
| GF_Err iods_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 descSize; | |
| char *desc; | |
| GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s; | |
| //use the OD codec... | |
| descSize = (u32) (ptr->size); | |
| desc = (char*)gf_malloc(sizeof(char) * descSize); | |
| if (!desc) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, desc, descSize); | |
| e = gf_odf_desc_read(desc, descSize, &ptr->descriptor); | |
| //OK, free our desc | |
| gf_free(desc); | |
| if (e) return e; | |
| switch (ptr->descriptor->tag) { | |
| case GF_ODF_ISOM_OD_TAG: | |
| case GF_ODF_ISOM_IOD_TAG: | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid descriptor in iods, tag %u found but only %u or %u allowed\n", ptr->descriptor->tag, GF_ODF_ISOM_IOD_TAG, GF_ODF_ISOM_OD_TAG )); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *iods_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ObjectDescriptorBox, GF_ISOM_BOX_TYPE_IODS); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err iods_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 descSize; | |
| u8 *desc; | |
| GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| //call our OD codec | |
| e = gf_odf_desc_write(ptr->descriptor, &desc, &descSize); | |
| if (e) return e; | |
| gf_bs_write_data(bs, desc, descSize); | |
| //and free our stuff maybe!! | |
| gf_free(desc); | |
| return GF_OK; | |
| } | |
| GF_Err iods_box_size(GF_Box *s) | |
| { | |
| GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s; | |
| ptr->size += gf_odf_desc_size(ptr->descriptor); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mdat_box_del(GF_Box *s) | |
| { | |
| GF_MediaDataBox *ptr = (GF_MediaDataBox *)s; | |
| if (!s) return; | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Err mdat_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MediaDataBox *ptr = (GF_MediaDataBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_IMDA) { | |
| ptr->type = GF_ISOM_BOX_TYPE_MDAT; | |
| ptr->is_imda = 1; | |
| ISOM_DECREASE_SIZE(s, 4) | |
| ptr->imda_id = gf_bs_read_u32(bs); | |
| } | |
| ptr->dataSize = s->size; | |
| ptr->bsOffset = gf_bs_get_position(bs); | |
| //store idat for rewrite | |
| if (ptr->type==GF_ISOM_BOX_TYPE_IDAT) { | |
| ptr->data = gf_malloc(sizeof(u8) * (size_t)ptr->dataSize); | |
| if (!ptr->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->data, (u32) ptr->dataSize); | |
| ptr->size = 0; | |
| return GF_OK; | |
| } | |
| //then skip these bytes | |
| gf_bs_skip_bytes(bs, ptr->dataSize); | |
| return GF_OK; | |
| } | |
| GF_Box *mdat_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MediaDataBox, GF_ISOM_BOX_TYPE_MDAT); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mdat_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MediaDataBox *ptr = (GF_MediaDataBox *)s; | |
| if (ptr->is_imda) { | |
| s->type = GF_ISOM_BOX_TYPE_IMDA; | |
| e = gf_isom_box_write_header(s, bs); | |
| s->type = GF_ISOM_BOX_TYPE_MDAT; | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->imda_id); | |
| } else { | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| } | |
| //make sure we have some data ... | |
| //if not, we handle that independently (edit files) | |
| if (ptr->data) { | |
| gf_bs_write_data(bs, ptr->data, (u32) ptr->dataSize); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mdat_box_size(GF_Box *s) | |
| { | |
| GF_MediaDataBox *ptr = (GF_MediaDataBox *)s; | |
| ptr->size += ptr->dataSize; | |
| if (ptr->is_imda) | |
| ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mdhd_box_del(GF_Box *s) | |
| { | |
| GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| // Mapping of QuickTime old language codes | |
| // https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34320 | |
| // to 3-letter codes (per ISO/IEC 639-2/T, https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) | |
| // NOTE that Media Info maps them to 2-letter codes, possibly with region codes https://github.com/MediaArea/MediaInfoLib/blob/72213574cbf2ca01c0fbb97d2239b53891ad7b9d/Source/MediaInfo/Multiple/File_Mpeg4.cpp#L754 | |
| // NOTE that FFmpeg mostly maps to ISO/IEC 639-2/B and sometimes 2-letter code | |
| // (see https://ffmpeg.org/doxygen/trunk/isom_8c_source.html) | |
| static const char* qtLanguages[] = { | |
| "eng", // 0 English | |
| "fra", // 1 French | |
| "deu", // 2 German | |
| "ita", // 3 Italian | |
| "nld", // 4 Dutch | |
| "swe", // 5 Swedish | |
| "spa", // 6 Spanish | |
| "dan", // 7 Danish | |
| "por", // 8 Portuguese | |
| "nor", // 9 Norwegian | |
| "heb", // 10 Hebrew | |
| "jpn", // 11 Japanese | |
| "ara", // 12 Arabic | |
| "fin", // 13 Finnish | |
| "ell", // 14 Greek | |
| "isl", // 15 Icelandic | |
| "mlt", // 16 Maltese | |
| "tur", // 17 Turkish | |
| "hrv", // 18 Croatian | |
| "zho", // 19 Traditional Chinese - general 3-letter code, ignoring the "Traditional" part | |
| "urd", // 20 Urdu | |
| "hin", // 21 Hindi | |
| "tha", // 22 Thai | |
| "kor", // 23 Korean | |
| "lit", // 24 Lithuanian | |
| "pol", // 25 Polish | |
| "hun", // 26 Hungarian | |
| "est", // 27 Estonian | |
| "lav", // 28 Lettish or Latvian | |
| "sme", // 29 Saami or Sami | |
| "fao", // 30 Faroese | |
| "fas", // 31 Farsi | |
| "rus", // 32 Russian | |
| "zho", // 33 Simplified Chinese - general 3-letter code, ignoring the "Simplified" part | |
| "nld", // 34 Flemish - using same code as Dutch | |
| "gle", // 35 Irish | |
| "sqi", // 36 Albanian | |
| "ron", // 37 Romanian | |
| "ces", // 38 Czech | |
| "slk", // 39 Slovak | |
| "slv", // 40 Slovenian | |
| "yid", // 41 Yiddish | |
| "srp", // 42 Serbian | |
| "mkd", // 43 Macedonian | |
| "bul", // 44 Bulgarian | |
| "ukr", // 45 Ukrainian | |
| "bel", // 46 Belarusian | |
| "uzb", // 47 Uzbek | |
| "kaz", // 48 Kazakh | |
| "aze", // 49 Azerbaijani | |
| "aze", // 50 AzerbaijanAr (Armenian-Azerbaijani) - using same code as Azerbaijani | |
| "hye", // 51 Armenian | |
| "kat", // 52 Georgian | |
| "ron", // 53 Moldavian | |
| "kir", // 54 Kirghiz | |
| "tgk", // 55 Tajik | |
| "tuk", // 56 Turkmen | |
| "mon", // 57 Mongolian | |
| "mon", // 58 MongolianCyr - using same code as Mongolian | |
| "pus", // 59 Pashto | |
| "kur", // 60 Kurdish | |
| "kas", // 61 Kashmiri | |
| "snd", // 62 Sindhi | |
| "bod", // 63 Tibetan | |
| "nep", // 64 Nepali | |
| "san", // 65 Sanskrit | |
| "mar", // 66 Marathi | |
| "ben", // 67 Bengali | |
| "asm", // 68 Assamese | |
| "guj", // 69 Gujarati | |
| "pan", // 70 Punjabi | |
| "ori", // 71 Oriya | |
| "mal", // 72 Malayalam | |
| "kan", // 73 Kannada | |
| "tam", // 74 Tamil | |
| "tel", // 75 Telugu | |
| "sin", // 76 Sinhala | |
| "mya", // 77 Burmese | |
| "khm", // 78 Khmer | |
| "lao", // 79 Lao | |
| "vie", // 80 Vietnamese | |
| "ind", // 81 Indonesian | |
| "tgl", // 82 Tagalog | |
| "msa", // 83 MalayRoman | |
| "msa", // 84 MalayArabic | |
| "amh", // 85 Amharic | |
| " ", // 86 Empty | |
| "orm", // 87 Oromo | |
| "som", // 88 Somali | |
| "swa", // 89 Swahili | |
| "kin", // 90 Kinyarwanda | |
| "run", // 91 Rundi | |
| "nya", // 92 Nyanja | |
| "mlg", // 93 Malagasy | |
| "epo", // 94 Esperanto | |
| // Gap 95-127 | |
| "cym", // 128 Welsh | |
| "eus", // 129 Basque | |
| "cat", // 130 Catalan | |
| "lat", // 131 Latin | |
| "que", // 132 Quechua | |
| "grn", // 133 Guarani | |
| "aym", // 134 Aymara | |
| "tat", // 135 Tatar | |
| "uig", // 136 Uighur | |
| "dzo", // 127 Dzongkha | |
| "jav" // 138 Javanese | |
| }; | |
| //static const u8 qtLanguagesSize = GF_ARRAY_LENGTH(qtLanguages); | |
| GF_Err set_quicktime_lang(char lang[4], u8 code) { | |
| if (code > 138 || (code > 94 && code < 128) || code == 86) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid QuickTime Language Code %d\n", code)); | |
| return GF_BAD_PARAM; | |
| } | |
| if (code > 94) | |
| code -=(128-94); // Gap in the list | |
| lang[0] = qtLanguages[code][0]; | |
| lang[1] = qtLanguages[code][1]; | |
| lang[2] = qtLanguages[code][2]; | |
| lang[3] = qtLanguages[code][3]; | |
| return GF_OK; | |
| } | |
| GF_Err mdhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s; | |
| if (ptr->version == 1) { | |
| ISOM_DECREASE_SIZE(ptr, 28) | |
| ptr->creationTime = gf_bs_read_u64(bs); | |
| ptr->modificationTime = gf_bs_read_u64(bs); | |
| ptr->timeScale = gf_bs_read_u32(bs); | |
| ptr->duration = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 16) | |
| ptr->creationTime = gf_bs_read_u32(bs); | |
| ptr->modificationTime = gf_bs_read_u32(bs); | |
| ptr->timeScale = gf_bs_read_u32(bs); | |
| ptr->duration = gf_bs_read_u32(bs); | |
| } | |
| if (!ptr->timeScale) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Media header timescale is 0 - defaulting to 90000\n" )); | |
| ptr->timeScale = 90000; | |
| } | |
| ptr->original_duration = ptr->duration; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| u16 lang_code = gf_bs_read_u16(bs); | |
| ptr->packedLanguage[0] = (lang_code>>10) & 0x1F; | |
| ptr->packedLanguage[1] = (lang_code>>5) & 0x1F; | |
| ptr->packedLanguage[2] = (lang_code) & 0x1F; | |
| // QuickTime Language Codes | |
| if (lang_code < 0x400) { | |
| u8 code = (ptr->packedLanguage[0] << 16) | (ptr->packedLanguage[1] << 8) | ptr->packedLanguage[2]; | |
| set_quicktime_lang(ptr->packedLanguage, code); | |
| } else { | |
| ptr->packedLanguage[0] += 0x60; | |
| ptr->packedLanguage[1] += 0x60; | |
| ptr->packedLanguage[2] += 0x60; | |
| } | |
| if (!ptr->packedLanguage[0] || !ptr->packedLanguage[1] || !ptr->packedLanguage[2]) { | |
| ptr->packedLanguage[0] = 'u'; | |
| ptr->packedLanguage[1] = 'n'; | |
| ptr->packedLanguage[2] = 'd'; | |
| } | |
| ptr->reserved = gf_bs_read_u16(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *mdhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MediaHeaderBox, GF_ISOM_BOX_TYPE_MDHD); | |
| tmp->packedLanguage[0] = 'u'; | |
| tmp->packedLanguage[1] = 'n'; | |
| tmp->packedLanguage[2] = 'd'; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mdhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version == 1) { | |
| gf_bs_write_u64(bs, ptr->creationTime); | |
| gf_bs_write_u64(bs, ptr->modificationTime); | |
| gf_bs_write_u32(bs, ptr->timeScale); | |
| gf_bs_write_u64(bs, ptr->duration); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->creationTime); | |
| gf_bs_write_u32(bs, (u32) ptr->modificationTime); | |
| gf_bs_write_u32(bs, ptr->timeScale); | |
| gf_bs_write_u32(bs, (u32) ptr->duration); | |
| } | |
| //SPECS: BIT(1) of padding | |
| gf_bs_write_int(bs, 0, 1); | |
| gf_bs_write_int(bs, ptr->packedLanguage[0] - 0x60, 5); | |
| gf_bs_write_int(bs, ptr->packedLanguage[1] - 0x60, 5); | |
| gf_bs_write_int(bs, ptr->packedLanguage[2] - 0x60, 5); | |
| gf_bs_write_u16(bs, ptr->reserved); | |
| return GF_OK; | |
| } | |
| GF_Err mdhd_box_size(GF_Box *s) | |
| { | |
| GF_MediaHeaderBox *ptr = (GF_MediaHeaderBox *)s; | |
| ptr->version = 0; | |
| if (ptr->duration!=(u64)-1 && (ptr->duration>0xFFFFFFFF)) ptr->version = 1; | |
| if (ptr->creationTime!=(u64)-1 && (ptr->creationTime>0xFFFFFFFF)) ptr->version = 1; | |
| if (ptr->modificationTime!=(u64)-1 && (ptr->modificationTime>0xFFFFFFFF)) ptr->version = 1; | |
| ptr->size += 4; | |
| ptr->size += (ptr->version == 1) ? 28 : 16; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mdia_box_del(GF_Box *s) | |
| { | |
| GF_MediaBox *ptr = (GF_MediaBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->nalu_parser) gf_bs_del(ptr->nalu_parser); | |
| if (ptr->nalu_out_bs) gf_bs_del(ptr->nalu_out_bs); | |
| if (ptr->nalu_ps_bs) gf_bs_del(ptr->nalu_ps_bs); | |
| if (ptr->extracted_bs) gf_bs_del(ptr->extracted_bs); | |
| if (ptr->extracted_samp) gf_isom_sample_del(&ptr->extracted_samp); | |
| if (ptr->in_sample_buffer) gf_free(ptr->in_sample_buffer); | |
| if (ptr->tmp_nal_copy_buffer) gf_free(ptr->tmp_nal_copy_buffer); | |
| if (ptr->information && ptr->information->dataHandler) { | |
| gf_isom_datamap_del(ptr->information->dataHandler); | |
| ptr->information->dataHandler = NULL; | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err mdia_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MediaBox *ptr = (GF_MediaBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_MDHD: | |
| BOX_FIELD_ASSIGN(mediaHeader, GF_MediaHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_HDLR: | |
| BOX_FIELD_ASSIGN(handler, GF_HandlerBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_MINF: | |
| BOX_FIELD_ASSIGN(information, GF_MediaInformationBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mdia_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u64 cookie = gf_bs_get_cookie(bs); | |
| cookie &= ~GF_ISOM_BS_COOKIE_VISUAL_TRACK; | |
| gf_bs_set_cookie(bs, cookie); | |
| e = gf_isom_box_array_read(s, bs); | |
| gf_bs_set_cookie(bs, cookie); | |
| if (e) return e; | |
| if (!((GF_MediaBox *)s)->information) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MediaInformationBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (!((GF_MediaBox *)s)->handler) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing HandlerBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (!((GF_MediaBox *)s)->mediaHeader) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MediaHeaderBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *mdia_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MediaBox, GF_ISOM_BOX_TYPE_MDIA); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mdia_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err mdia_box_size(GF_Box *s) | |
| { | |
| u32 pos = 0; | |
| GF_MediaBox *ptr = (GF_MediaBox *)s; | |
| //Header first | |
| gf_isom_check_position(s, (GF_Box*)ptr->mediaHeader, &pos); | |
| //then handler | |
| gf_isom_check_position(s, (GF_Box*)ptr->handler, &pos); | |
| #if 0 | |
| //elng before info for CMAF info - we deactiveate for now, no specific errors raised and CMAF should not impose any order | |
| GF_Box *elng = gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_ELNG); | |
| if (elng) | |
| gf_isom_check_position(s, elng, &pos); | |
| #endif | |
| //then info | |
| gf_isom_check_position(s, (GF_Box*)ptr->information, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mfra_box_del(GF_Box *s) | |
| { | |
| GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s; | |
| if (ptr == NULL) return; | |
| gf_list_del(ptr->tfra_list); | |
| gf_free(ptr); | |
| } | |
| GF_Box *mfra_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieFragmentRandomAccessBox, GF_ISOM_BOX_TYPE_MFRA); | |
| tmp->tfra_list = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err mfra_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_TFRA: | |
| BOX_FIELD_LIST_ASSIGN(tfra_list); | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_MFRO: | |
| BOX_FIELD_ASSIGN(mfro, GF_MovieFragmentRandomAccessOffsetBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mfra_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mfra_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err mfra_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s; | |
| gf_isom_check_position_list(s, ptr->tfra_list, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->mfro, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void tfra_box_del(GF_Box *s) | |
| { | |
| GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Box *tfra_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackFragmentRandomAccessBox, GF_ISOM_BOX_TYPE_TFRA); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err tfra_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_RandomAccessEntry *p = 0; | |
| GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 12); | |
| ptr->track_id = gf_bs_read_u32(bs); | |
| if (gf_bs_read_int(bs, 26) != 0) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->traf_bits = (gf_bs_read_int(bs, 2) + 1) * 8; | |
| ptr->trun_bits = (gf_bs_read_int(bs, 2) + 1) * 8; | |
| ptr->sample_bits = (gf_bs_read_int(bs, 2) + 1) * 8; | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->version == 1) { | |
| if (ptr->nb_entries > ptr->size / (16+(ptr->traf_bits+ptr->trun_bits+ptr->sample_bits)/8)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in traf\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } else { | |
| if (ptr->nb_entries > ptr->size / (8+(ptr->traf_bits+ptr->trun_bits+ptr->sample_bits)/8)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in traf\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| if (ptr->nb_entries) { | |
| if ((u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(GF_RandomAccessEntry)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in traf\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| p = (GF_RandomAccessEntry *) gf_malloc(sizeof(GF_RandomAccessEntry) * ptr->nb_entries); | |
| if (!p) return GF_OUT_OF_MEM; | |
| } | |
| ptr->entries = p; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| memset(p, 0, sizeof(GF_RandomAccessEntry)); | |
| if (ptr->version == 1) { | |
| p->time = gf_bs_read_u64(bs); | |
| p->moof_offset = gf_bs_read_u64(bs); | |
| } else { | |
| p->time = gf_bs_read_u32(bs); | |
| p->moof_offset = gf_bs_read_u32(bs); | |
| } | |
| p->traf_number = gf_bs_read_int(bs, ptr->traf_bits); | |
| p->trun_number = gf_bs_read_int(bs, ptr->trun_bits); | |
| p->sample_number = gf_bs_read_int(bs, ptr->sample_bits); | |
| ++p; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tfra_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i, sap_nb_entries; | |
| GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->track_id); | |
| gf_bs_write_int(bs, 0, 26); | |
| gf_bs_write_int(bs, ptr->traf_bits/8 - 1, 2); | |
| gf_bs_write_int(bs, ptr->trun_bits/8 - 1, 2); | |
| gf_bs_write_int(bs, ptr->sample_bits/8 - 1, 2); | |
| sap_nb_entries = 0; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| GF_RandomAccessEntry *p = &ptr->entries[i]; | |
| //no sap found, do not store | |
| if (p->trun_number) sap_nb_entries++; | |
| } | |
| gf_bs_write_u32(bs, sap_nb_entries); | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| GF_RandomAccessEntry *p = &ptr->entries[i]; | |
| //no sap found, do not store | |
| if (!p->trun_number) continue; | |
| if (ptr->version==1) { | |
| gf_bs_write_u64(bs, p->time); | |
| gf_bs_write_u64(bs, p->moof_offset); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) p->time); | |
| gf_bs_write_u32(bs, (u32) p->moof_offset); | |
| } | |
| gf_bs_write_int(bs, p->traf_number, ptr->traf_bits); | |
| gf_bs_write_int(bs, p->trun_number, ptr->trun_bits); | |
| gf_bs_write_int(bs, p->sample_number, ptr->sample_bits); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err tfra_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_TrackFragmentRandomAccessBox *ptr = (GF_TrackFragmentRandomAccessBox *)s; | |
| ptr->size += 12; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| GF_RandomAccessEntry *p = &ptr->entries[i]; | |
| //no sap found, do not store | |
| if (!p->trun_number) continue; | |
| ptr->size += ((ptr->version==1) ? 16 : 8 ) + ptr->traf_bits/8 + ptr->trun_bits/8 + ptr->sample_bits/8; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mfro_box_del(GF_Box *s) | |
| { | |
| GF_MovieFragmentRandomAccessOffsetBox *ptr = (GF_MovieFragmentRandomAccessOffsetBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Box *mfro_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieFragmentRandomAccessOffsetBox, GF_ISOM_BOX_TYPE_MFRO); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err mfro_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MovieFragmentRandomAccessOffsetBox *ptr = (GF_MovieFragmentRandomAccessOffsetBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->container_size = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mfro_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MovieFragmentRandomAccessOffsetBox *ptr = (GF_MovieFragmentRandomAccessOffsetBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->container_size); | |
| return GF_OK; | |
| } | |
| GF_Err mfro_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void elng_box_del(GF_Box *s) | |
| { | |
| GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->extended_language) gf_free(ptr->extended_language); | |
| gf_free(ptr); | |
| } | |
| GF_Err elng_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; | |
| if (ptr && ptr->size > GF_UINT_MAX) | |
| return GF_ISOM_INVALID_FILE; | |
| if (ptr->size) { | |
| ptr->extended_language = (char*)gf_malloc((u32) ptr->size); | |
| if (ptr->extended_language == NULL) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->extended_language, (u32) ptr->size); | |
| /*safety check in case the string is not null-terminated*/ | |
| if (ptr->extended_language[ptr->size-1]) { | |
| char *str = (char*)gf_malloc((u32) ptr->size + 1); | |
| if (!str) return GF_OUT_OF_MEM; | |
| memcpy(str, ptr->extended_language, (u32) ptr->size); | |
| str[ptr->size] = 0; | |
| gf_free(ptr->extended_language); | |
| ptr->extended_language = str; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *elng_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MediaBox, GF_ISOM_BOX_TYPE_ELNG); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err elng_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->extended_language) { | |
| gf_bs_write_data(bs, ptr->extended_language, (u32)(strlen(ptr->extended_language)+1)); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err elng_box_size(GF_Box *s) | |
| { | |
| GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; | |
| if (ptr->extended_language) { | |
| ptr->size += strlen(ptr->extended_language)+1; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void mfhd_box_del(GF_Box *s) | |
| { | |
| GF_MovieFragmentHeaderBox *ptr = (GF_MovieFragmentHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err mfhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MovieFragmentHeaderBox *ptr = (GF_MovieFragmentHeaderBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->sequence_number = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *mfhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieFragmentHeaderBox, GF_ISOM_BOX_TYPE_MFHD); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mfhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MovieFragmentHeaderBox *ptr = (GF_MovieFragmentHeaderBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->sequence_number); | |
| return GF_OK; | |
| } | |
| GF_Err mfhd_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| void minf_box_del(GF_Box *s) | |
| { | |
| GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s; | |
| if (ptr == NULL) return; | |
| //if we have a Handler not self-contained, delete it (the self-contained belongs to the movie) | |
| if (ptr->dataHandler) { | |
| gf_isom_datamap_close(ptr); | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err minf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_NMHD: | |
| case GF_ISOM_BOX_TYPE_STHD: | |
| case GF_ISOM_BOX_TYPE_VMHD: | |
| case GF_ISOM_BOX_TYPE_SMHD: | |
| case GF_ISOM_BOX_TYPE_HMHD: | |
| case GF_ISOM_BOX_TYPE_GMHD: | |
| BOX_FIELD_ASSIGN(InfoHeader, GF_Box) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_DINF: | |
| BOX_FIELD_ASSIGN(dataInformation, GF_DataInformationBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_STBL: | |
| BOX_FIELD_ASSIGN(sampleTable, GF_SampleTableBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err minf_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s; | |
| GF_Err e; | |
| e = gf_isom_box_array_read(s, bs); | |
| if (!e && ! ptr->dataInformation) { | |
| GF_Box *url; | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing DataInformationBox\n")); | |
| //commented on purpose, we are still able to handle the file, we only throw an error but keep processing | |
| // e = GF_ISOM_INVALID_FILE; | |
| //add a dinf box to avoid any access to a null dinf | |
| ptr->dataInformation = (GF_DataInformationBox *) gf_isom_box_new_parent(&ptr->child_boxes, GF_ISOM_BOX_TYPE_DINF); | |
| if (!ptr->dataInformation) return GF_OUT_OF_MEM; | |
| ptr->dataInformation->dref = (GF_DataReferenceBox *) gf_isom_box_new_parent(&ptr->dataInformation->child_boxes, GF_ISOM_BOX_TYPE_DREF); | |
| if (!ptr->dataInformation->dref) return GF_OUT_OF_MEM; | |
| url = gf_isom_box_new_parent(&ptr->dataInformation->dref->child_boxes, GF_ISOM_BOX_TYPE_URL); | |
| if (!url) return GF_OUT_OF_MEM; | |
| ((GF_FullBox*)url)->flags = 1; | |
| } | |
| return e; | |
| } | |
| GF_Box *minf_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MediaInformationBox, GF_ISOM_BOX_TYPE_MINF); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err minf_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err minf_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s; | |
| //Header first | |
| gf_isom_check_position(s, (GF_Box *)ptr->InfoHeader, &pos); | |
| //then dataInfo | |
| gf_isom_check_position(s, (GF_Box *)ptr->dataInformation, &pos); | |
| gf_isom_check_position(s, gf_isom_box_find_child(s->child_boxes, GF_ISOM_BOX_TYPE_MVCI), &pos); | |
| //then sampleTable | |
| gf_isom_check_position(s, (GF_Box *)ptr->sampleTable, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void moof_box_del(GF_Box *s) | |
| { | |
| GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *)s; | |
| if (ptr == NULL) return; | |
| gf_list_del(ptr->TrackList); | |
| if (ptr->PSSHs) gf_list_del(ptr->PSSHs); | |
| if (ptr->mdat) gf_free(ptr->mdat); | |
| //happens if error while fragmenting, the emsg boxes are not part of the moof hierarchy ! | |
| if (ptr->emsgs) { | |
| while (1) { | |
| GF_Box *emsg = gf_list_pop_front(ptr->emsgs); | |
| if (!emsg) break; | |
| gf_isom_box_del(emsg); | |
| } | |
| gf_list_del(ptr->emsgs); | |
| } | |
| gf_list_del(ptr->trun_list); | |
| gf_free(ptr); | |
| } | |
| GF_Err moof_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_MFHD: | |
| BOX_FIELD_ASSIGN(mfhd, GF_MovieFragmentHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TRAF: | |
| BOX_FIELD_LIST_ASSIGN(TrackList) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_PSSH: | |
| BOX_FIELD_LIST_ASSIGN(PSSHs) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err moof_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *moof_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieFragmentBox, GF_ISOM_BOX_TYPE_MOOF); | |
| tmp->TrackList = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err moof_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err moof_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| //Header First | |
| gf_isom_check_position(s, (GF_Box *)ptr->mfhd, &pos); | |
| //then PSSH | |
| gf_isom_check_position_list(s, ptr->PSSHs, &pos); | |
| //then the track list | |
| gf_isom_check_position_list(s, ptr->TrackList, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| void moov_box_del(GF_Box *s) | |
| { | |
| GF_MovieBox *ptr = (GF_MovieBox *)s; | |
| if (ptr == NULL) return; | |
| gf_list_del(ptr->trackList); | |
| gf_free(ptr); | |
| } | |
| GF_Err moov_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MovieBox *ptr = (GF_MovieBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_IODS: | |
| BOX_FIELD_ASSIGN(iods, GF_ObjectDescriptorBox) | |
| //if no IOD, delete the box | |
| if (ptr->iods && !ptr->iods->descriptor) { | |
| ptr->iods = NULL; | |
| gf_isom_box_del_parent(&s->child_boxes, a); | |
| } | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_MVHD: | |
| BOX_FIELD_ASSIGN(mvhd, GF_MovieHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_UDTA: | |
| BOX_FIELD_ASSIGN(udta, GF_UserDataBox) | |
| return GF_OK; | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| case GF_ISOM_BOX_TYPE_MVEX: | |
| BOX_FIELD_ASSIGN(mvex, GF_MovieExtendsBox) | |
| if (ptr->mvex) | |
| ptr->mvex->mov = ptr->mov; | |
| return GF_OK; | |
| #endif | |
| case GF_ISOM_BOX_TYPE_META: | |
| BOX_FIELD_ASSIGN(meta, GF_MetaBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TRAK: | |
| case GF_ISOM_BOX_TYPE_EXTK: | |
| if (is_rem) { | |
| gf_list_del_item(ptr->trackList, a); | |
| return GF_OK; | |
| } | |
| { | |
| GF_TrackBox *tk = (GF_TrackBox *)a; | |
| //set our pointer to this obj | |
| tk->moov = ptr; | |
| if (tk->References) { | |
| GF_TrackReferenceTypeBox *dpnd=NULL; | |
| Track_FindRef(tk, GF_ISOM_REF_BASE, &dpnd); | |
| if (dpnd) | |
| tk->nb_base_refs = dpnd->trackIDCount; | |
| } | |
| } | |
| return gf_list_add(ptr->trackList, a); | |
| case GF_QT_BOX_TYPE_CMVD: | |
| ptr->has_cmvd = 1; | |
| break; | |
| case GF_ISOM_BOX_TYPE_UNKNOWN: | |
| if (((GF_UnknownBox*)a)->original_4cc == GF_QT_BOX_TYPE_CMOV) { | |
| ptr->has_cmvd = 2; | |
| break; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err moov_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *moov_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieBox, GF_ISOM_BOX_TYPE_MOOV); | |
| tmp->trackList = gf_list_new(); | |
| if (!tmp->trackList) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err moov_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| static void moov_check_tracks_position(GF_MovieBox *s, GF_List *childlist, u32 *pos) | |
| { | |
| u32 i, k, count; | |
| if (!s || (s->internal_flags & GF_ISOM_ORDER_FREEZE)) | |
| return; | |
| if (!s->mov) { | |
| gf_isom_check_position_list((GF_Box*)s, childlist, pos); | |
| return; | |
| } | |
| if (!s->mov->auto_reorder_tracks) { | |
| //no specific mux index set | |
| if (!s->mov->tracks_use_mux_index) { | |
| gf_isom_check_position_list((GF_Box*)s, childlist, pos); | |
| return; | |
| } | |
| GF_List *all_tracks = gf_list_new(); | |
| count = gf_list_count(childlist); | |
| for (i=0; i<count; i++) { | |
| GF_TrackBox *tk = (GF_TrackBox*)gf_list_get(childlist, i); | |
| u32 mux_index = tk->mux_index; | |
| //mux index not set on this track , use list index | |
| if (!mux_index) mux_index = i+1; | |
| //resort by mux index | |
| for (k=0; k<gf_list_count(all_tracks); k++) { | |
| GF_TrackBox *a_tk = (GF_TrackBox*)gf_list_get(all_tracks, k); | |
| u32 atk_mux_index = a_tk->mux_index; | |
| if (!atk_mux_index) atk_mux_index = k+1; | |
| if ((atk_mux_index > mux_index) | |
| //if we have a mux index on current track but not on target insertion track, we insert before | |
| || (!a_tk->mux_index && tk->mux_index && (atk_mux_index == mux_index)) | |
| ) { | |
| gf_list_insert(all_tracks, tk, k); | |
| tk = NULL; | |
| break; | |
| } | |
| } | |
| if (tk) gf_list_add(all_tracks, tk); | |
| } | |
| gf_isom_check_position_list((GF_Box*)s, all_tracks, pos); | |
| gf_list_del(all_tracks); | |
| return; | |
| } | |
| count = gf_list_count(childlist); | |
| GF_List *v_tracks=gf_list_new(); | |
| GF_List *a_tracks=gf_list_new(); | |
| GF_List *t_tracks=gf_list_new(); | |
| GF_List *o_tracks=gf_list_new(); | |
| for (i=0; i<count; i++) { | |
| GF_TrackBox *tk = (GF_TrackBox*)gf_list_get(childlist, i); | |
| switch (tk->Media->handler->handlerType) { | |
| case GF_ISOM_MEDIA_VISUAL: | |
| case GF_ISOM_MEDIA_AUXV: | |
| case GF_ISOM_MEDIA_PICT: | |
| gf_list_add(v_tracks, tk); | |
| break; | |
| case GF_ISOM_MEDIA_AUDIO: | |
| gf_list_add(a_tracks, tk); | |
| break; | |
| case GF_ISOM_MEDIA_TEXT: | |
| case GF_ISOM_MEDIA_SUBT: | |
| case GF_ISOM_MEDIA_SUBPIC: | |
| case GF_ISOM_MEDIA_MPEG_SUBT: | |
| case GF_ISOM_MEDIA_CLOSED_CAPTION: | |
| gf_list_add(t_tracks, tk); | |
| break; | |
| default: | |
| gf_list_add(o_tracks, tk); | |
| break; | |
| } | |
| } | |
| for (k=0; k<4;k++) { | |
| GF_List *src = NULL; | |
| switch (k) { | |
| case 0: src = v_tracks; break; | |
| case 1: src = a_tracks; break; | |
| case 2: src = t_tracks; break; | |
| case 3: src = o_tracks; break; | |
| } | |
| count = gf_list_count(src); | |
| for (i=0; i<count; i++) { | |
| GF_Box *child = gf_list_get(src, i); | |
| gf_isom_check_position((GF_Box*)s, child, pos); | |
| } | |
| gf_list_del(src); | |
| } | |
| } | |
| GF_Err moov_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MovieBox *ptr = (GF_MovieBox *)s; | |
| gf_isom_check_position(s, (GF_Box *) ptr->mvhd, &pos); | |
| gf_isom_check_position(s, (GF_Box *) ptr->iods, &pos); | |
| gf_isom_check_position(s, (GF_Box *) ptr->meta, &pos); | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| if (ptr->mvex && !ptr->mvex_after_traks) { | |
| gf_isom_check_position(s, (GF_Box *) ptr->mvex, &pos); | |
| } | |
| #endif | |
| moov_check_tracks_position(ptr, ptr->trackList, &pos); | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| if (ptr->mvex && ptr->mvex_after_traks) { | |
| gf_isom_check_position(s, (GF_Box *) ptr->mvex, &pos); | |
| } | |
| #endif | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void audio_sample_entry_box_del(GF_Box *s) | |
| { | |
| GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s; | |
| if (ptr == NULL) return; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); | |
| if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc); | |
| gf_free(ptr); | |
| } | |
| GF_Err audio_sample_entry_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_UnknownBox *wave = NULL; | |
| Bool drop_wave=GF_FALSE; | |
| GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_ESDS: | |
| BOX_FIELD_ASSIGN(esd, GF_ESDBox) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_DAMR: | |
| case GF_ISOM_BOX_TYPE_DEVC: | |
| case GF_ISOM_BOX_TYPE_DQCP: | |
| case GF_ISOM_BOX_TYPE_DSMV: | |
| BOX_FIELD_ASSIGN(cfg_3gpp, GF_3GPPConfigBox) | |
| /*for 3GP config, remember sample entry type in config*/ | |
| ptr->cfg_3gpp->cfg.type = ptr->type; | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_DOPS: | |
| BOX_FIELD_ASSIGN(cfg_opus, GF_OpusSpecificBox) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_IACB: | |
| BOX_FIELD_ASSIGN(cfg_iamf, GF_IAConfigurationBox) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_DAC3: | |
| BOX_FIELD_ASSIGN(cfg_ac3, GF_AC3ConfigBox) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_DEC3: | |
| BOX_FIELD_ASSIGN(cfg_ac3, GF_AC3ConfigBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_DAC4: | |
| BOX_FIELD_ASSIGN(cfg_ac4, GF_AC4ConfigBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_DMLP: | |
| BOX_FIELD_ASSIGN(cfg_mlp, GF_TrueHDConfigBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_MHAC: | |
| BOX_FIELD_ASSIGN(cfg_mha, GF_MHAConfigBox) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_DFLA: | |
| BOX_FIELD_ASSIGN(cfg_flac, GF_FLACConfigBox) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| break; | |
| case GF_ISOM_BOX_TYPE_UNKNOWN: | |
| wave = (GF_UnknownBox *)a; | |
| /*HACK for QT files: get the esds box from the track*/ | |
| if (s->type == GF_ISOM_BOX_TYPE_MP4A) { | |
| if (is_rem) { | |
| return GF_OK; | |
| } | |
| if (ptr->esd) ERROR_ON_DUPLICATED_BOX(a, ptr) | |
| //wave subboxes may have been properly parsed | |
| if ((wave->original_4cc == GF_QT_BOX_TYPE_WAVE) && gf_list_count(wave->child_boxes)) { | |
| u32 i; | |
| for (i =0; i<gf_list_count(wave->child_boxes); i++) { | |
| GF_Box *inner_box = (GF_Box *)gf_list_get(wave->child_boxes, i); | |
| if (inner_box->type == GF_ISOM_BOX_TYPE_ESDS) { | |
| ptr->esd = (GF_ESDBox *)inner_box; | |
| if (ptr->qtff_mode & GF_ISOM_AUDIO_QTFF_CONVERT_FLAG) { | |
| gf_list_rem(a->child_boxes, i); | |
| drop_wave=GF_TRUE; | |
| ptr->compression_id = 0; | |
| gf_list_add(ptr->child_boxes, inner_box); | |
| } | |
| } | |
| } | |
| if (drop_wave) { | |
| gf_isom_box_del_parent(&ptr->child_boxes, a); | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| ptr->version = 0; | |
| return GF_OK; | |
| } | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_EXT_VALID; | |
| return GF_OK; | |
| } | |
| gf_isom_box_del_parent(&ptr->child_boxes, a); | |
| return GF_ISOM_INVALID_MEDIA; | |
| } | |
| ptr->qtff_mode &= ~GF_ISOM_AUDIO_QTFF_CONVERT_FLAG; | |
| if ((wave->original_4cc == GF_QT_BOX_TYPE_WAVE) && gf_list_count(wave->child_boxes)) { | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_NOEXT; | |
| } | |
| return GF_OK; | |
| case GF_QT_BOX_TYPE_WAVE: | |
| { | |
| u32 subtype = 0; | |
| GF_Box **cfg_ptr = NULL; | |
| if (s->type == GF_ISOM_BOX_TYPE_MP4A) { | |
| cfg_ptr = (GF_Box **) &ptr->esd; | |
| subtype = GF_ISOM_BOX_TYPE_ESDS; | |
| } | |
| else if (s->type == GF_ISOM_BOX_TYPE_AC3) { | |
| cfg_ptr = (GF_Box **) &ptr->cfg_ac3; | |
| subtype = GF_ISOM_BOX_TYPE_DAC3; | |
| } | |
| else if (s->type == GF_ISOM_BOX_TYPE_EC3) { | |
| cfg_ptr = (GF_Box **) &ptr->cfg_ac3; | |
| subtype = GF_ISOM_BOX_TYPE_DEC3; | |
| } | |
| else if (s->type == GF_ISOM_BOX_TYPE_AC4) { | |
| cfg_ptr = (GF_Box **) &ptr->cfg_ac4; | |
| subtype = GF_ISOM_BOX_TYPE_DAC4; | |
| } | |
| else if (s->type == GF_ISOM_BOX_TYPE_OPUS) { | |
| cfg_ptr = (GF_Box **) &ptr->cfg_opus; | |
| subtype = GF_ISOM_BOX_TYPE_DOPS; | |
| } | |
| else if ((s->type == GF_ISOM_BOX_TYPE_MHA1) | |
| || (s->type == GF_ISOM_BOX_TYPE_MHA2) | |
| || (s->type == GF_ISOM_BOX_TYPE_MHM1) | |
| || (s->type == GF_ISOM_BOX_TYPE_MHM2) | |
| ) { | |
| cfg_ptr = (GF_Box **) &ptr->cfg_mha; | |
| subtype = GF_ISOM_BOX_TYPE_MHAC; | |
| } | |
| else if (s->type == GF_ISOM_BOX_TYPE_MLPA) { | |
| cfg_ptr = (GF_Box **) &ptr->cfg_mlp; | |
| subtype = GF_ISOM_BOX_TYPE_DMLP; | |
| } | |
| if (cfg_ptr) { | |
| if (is_rem) { | |
| *cfg_ptr = NULL; | |
| return GF_OK; | |
| } | |
| if (*cfg_ptr) ERROR_ON_DUPLICATED_BOX(a, ptr) | |
| //wave subboxes may have been properly parsed | |
| if (gf_list_count(a->child_boxes)) { | |
| u32 i; | |
| for (i =0; i<gf_list_count(a->child_boxes); i++) { | |
| GF_Box *inner_box = (GF_Box *)gf_list_get(a->child_boxes, i); | |
| if (inner_box->type == subtype) { | |
| *cfg_ptr = inner_box; | |
| if (ptr->qtff_mode & GF_ISOM_AUDIO_QTFF_CONVERT_FLAG) { | |
| gf_list_rem(a->child_boxes, i); | |
| drop_wave=GF_TRUE; | |
| gf_list_add(ptr->child_boxes, inner_box); | |
| } | |
| break; | |
| } | |
| } | |
| if (drop_wave) { | |
| gf_isom_box_del_parent(&ptr->child_boxes, a); | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| ptr->compression_id = 0; | |
| ptr->version = 0; | |
| return GF_OK; | |
| } | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_EXT_VALID; | |
| return GF_OK; | |
| } | |
| } | |
| } | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_EXT_VALID; | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err audio_sample_entry_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MPEGAudioSampleEntryBox *ptr; | |
| char *data; | |
| u8 a, b, c, d; | |
| u32 i, size, v, nb_alnum; | |
| GF_Err e; | |
| u64 pos, start; | |
| ptr = (GF_MPEGAudioSampleEntryBox *)s; | |
| start = gf_bs_get_position(bs); | |
| v = gf_bs_peek_bits(bs, 16, 8); | |
| if (v) | |
| ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_NOEXT; | |
| //try to disambiguate QTFF v1 and MP4 v1 audio sample entries ... | |
| if (v==1) { | |
| //go to end of ISOM audio sample entry, skip 4 byte (box size field), read 4 bytes (box type) and check if this looks like a box | |
| gf_bs_skip_bytes(bs, 8 + 20 + 4); | |
| a = gf_bs_read_u8(bs); | |
| b = gf_bs_read_u8(bs); | |
| c = gf_bs_read_u8(bs); | |
| d = gf_bs_read_u8(bs); | |
| nb_alnum = 0; | |
| if (isalnum(a)) nb_alnum++; | |
| if (isalnum(b)) nb_alnum++; | |
| if (isalnum(c)) nb_alnum++; | |
| if (isalnum(d)) nb_alnum++; | |
| if (nb_alnum>2) ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE; | |
| gf_bs_seek(bs, start); | |
| } | |
| e = gf_isom_audio_sample_entry_read((GF_AudioSampleEntryBox*)s, bs); | |
| if (e) return e; | |
| pos = gf_bs_get_position(bs); | |
| size = (u32) s->size; | |
| //when cookie is set on bs, always convert qtff-style mp4a to isobmff-style | |
| //since the conversion is done in addBox and we don't have the bitstream there (arg...), flag the box | |
| if (gf_bs_get_cookie(bs) & GF_ISOM_BS_COOKIE_QT_CONV) { | |
| ptr->qtff_mode |= GF_ISOM_AUDIO_QTFF_CONVERT_FLAG; | |
| } | |
| e = gf_isom_box_array_read(s, bs); | |
| if (!e) { | |
| if (s->type==GF_ISOM_BOX_TYPE_ENCA) { | |
| GF_ProtectionSchemeInfoBox *sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(s->child_boxes, GF_ISOM_BOX_TYPE_SINF); | |
| if (sinf && sinf->original_format) { | |
| u32 type = sinf->original_format->data_format; | |
| switch (type) { | |
| case GF_ISOM_SUBTYPE_3GP_AMR: | |
| case GF_ISOM_SUBTYPE_3GP_AMR_WB: | |
| case GF_ISOM_SUBTYPE_3GP_EVRC: | |
| case GF_ISOM_SUBTYPE_3GP_QCELP: | |
| case GF_ISOM_SUBTYPE_3GP_SMV: | |
| if (ptr->cfg_3gpp) ptr->cfg_3gpp->cfg.type = type; | |
| break; | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| if (size<8) return GF_ISOM_INVALID_FILE; | |
| /*hack for some weird files (possibly recorded with live.com tools, needs further investigations)*/ | |
| gf_bs_seek(bs, pos); | |
| data = (char*)gf_malloc(sizeof(char) * size); | |
| if (!data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, data, size); | |
| for (i=0; i<size-8; i++) { | |
| if (GF_4CC((u32)data[i+4], (u8)data[i+5], (u8)data[i+6], (u8)data[i+7]) == GF_ISOM_BOX_TYPE_ESDS) { | |
| GF_BitStream *mybs = gf_bs_new(data + i, size - i, GF_BITSTREAM_READ); | |
| gf_bs_set_cookie(mybs, GF_ISOM_BS_COOKIE_NO_LOGS); | |
| if (ptr->esd) { | |
| gf_list_del_item(ptr->child_boxes, (GF_Box *)ptr->esd); | |
| for (u32 i=0; i<gf_list_count(ptr->child_boxes); i++) { | |
| GF_Box *inner_box = (GF_Box *)gf_list_get(ptr->child_boxes, i); | |
| if (inner_box->child_boxes) { | |
| gf_list_del_item(inner_box->child_boxes, (GF_Box *)ptr->esd); | |
| } | |
| } | |
| gf_isom_box_del((GF_Box *)ptr->esd); | |
| } | |
| ptr->esd = NULL; | |
| e = gf_isom_box_parse((GF_Box **)&ptr->esd, mybs); | |
| gf_bs_del(mybs); | |
| if ((e==GF_OK) && ptr->esd && (ptr->esd->type == GF_ISOM_BOX_TYPE_ESDS)) { | |
| if (!ptr->child_boxes) ptr->child_boxes = gf_list_new(); | |
| gf_list_add(ptr->child_boxes, ptr->esd); | |
| } else if (ptr->esd) { | |
| gf_isom_box_del((GF_Box *)ptr->esd); | |
| ptr->esd = NULL; | |
| } | |
| e = GF_OK; | |
| break; | |
| } | |
| } | |
| gf_free(data); | |
| return e; | |
| } | |
| GF_Box *audio_sample_entry_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MPEGAudioSampleEntryBox, GF_ISOM_BOX_TYPE_MP4A); | |
| gf_isom_audio_sample_entry_init((GF_AudioSampleEntryBox*)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Box *enca_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MPEGAudioSampleEntryBox, GF_ISOM_BOX_TYPE_ENCA); | |
| gf_isom_audio_sample_entry_init((GF_AudioSampleEntryBox*)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err audio_sample_entry_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_isom_audio_sample_entry_write((GF_AudioSampleEntryBox*)s, bs); | |
| return GF_OK; | |
| } | |
| GF_Err audio_sample_entry_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s; | |
| gf_isom_audio_sample_entry_size((GF_AudioSampleEntryBox*)s); | |
| if (ptr->qtff_mode) | |
| return GF_OK; | |
| if (ptr->version) { | |
| gf_isom_check_position(s, gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_SRAT), &pos); | |
| gf_isom_check_position(s, gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_CHNL), &pos); | |
| } | |
| gf_isom_check_position(s, (GF_Box *)ptr->esd, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_mha, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_3gpp, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_opus, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_ac3, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_flac, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_mlp, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_iamf, &pos); | |
| if (!ptr->version) { | |
| gf_isom_check_position(s, gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_SRAT), &pos); | |
| gf_isom_check_position(s, gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_CHNL), &pos); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void gen_sample_entry_box_del(GF_Box *s) | |
| { | |
| GF_SampleEntryBox *ptr = (GF_SampleEntryBox *)s; | |
| if (ptr == NULL) return; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); | |
| gf_free(ptr); | |
| } | |
| GF_Err gen_sample_entry_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)s, bs); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(s, 8); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *gen_sample_entry_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleEntryBox, GF_QT_SUBTYPE_C608);//type will be overwritten | |
| gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err gen_sample_entry_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SampleEntryBox *ptr = (GF_SampleEntryBox *)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); | |
| return GF_OK; | |
| } | |
| GF_Err gen_sample_entry_box_size(GF_Box *s) | |
| { | |
| GF_SampleEntryBox *ptr = (GF_SampleEntryBox *)s; | |
| ptr->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mp4s_box_del(GF_Box *s) | |
| { | |
| GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s; | |
| if (ptr == NULL) return; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); | |
| if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc); | |
| gf_free(ptr); | |
| } | |
| GF_Err mp4s_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_ESDS: | |
| BOX_FIELD_ASSIGN(esd, GF_ESDBox) | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mp4s_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s; | |
| e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *mp4s_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MPEGSampleEntryBox, GF_ISOM_BOX_TYPE_MP4S); | |
| gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); | |
| tmp->internal_type = GF_ISOM_SAMPLE_ENTRY_MP4S; | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Box *encs_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MPEGSampleEntryBox, GF_ISOM_BOX_TYPE_ENCS); | |
| gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); | |
| tmp->internal_type = GF_ISOM_SAMPLE_ENTRY_MP4S; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mp4s_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)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); | |
| return GF_OK; | |
| } | |
| GF_Err mp4s_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s; | |
| s->size += 8; | |
| gf_isom_check_position(s, (GF_Box *)ptr->esd, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void video_sample_entry_box_del(GF_Box *s) | |
| { | |
| GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s; | |
| if (ptr == NULL) return; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); | |
| if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc); | |
| /*for publishing*/ | |
| if (ptr->emul_esd) gf_odf_desc_del((GF_Descriptor *)ptr->emul_esd); | |
| gf_free(ptr); | |
| } | |
| GF_Err video_sample_entry_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_ESDS: | |
| BOX_FIELD_ASSIGN(esd, GF_ESDBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_RINF: | |
| BOX_FIELD_ASSIGN(rinf, GF_RestrictedSchemeInfoBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_AVCC: | |
| BOX_FIELD_ASSIGN(avc_config, GF_AVCConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_HVCC: | |
| BOX_FIELD_ASSIGN(hevc_config, GF_HEVCConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_VVCC: | |
| BOX_FIELD_ASSIGN(vvc_config, GF_VVCConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_SVCC: | |
| BOX_FIELD_ASSIGN(svc_config, GF_AVCConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_MVCC: | |
| BOX_FIELD_ASSIGN(mvc_config, GF_AVCConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_LHVC: | |
| BOX_FIELD_ASSIGN(lhvc_config, GF_HEVCConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_AV1C: | |
| BOX_FIELD_ASSIGN(av1_config, GF_AV1ConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_VPCC: | |
| BOX_FIELD_ASSIGN(vp_config, GF_VPConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_AV3C: | |
| BOX_FIELD_ASSIGN(avs3v_config, GF_AVS3VConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_DVCC: | |
| case GF_ISOM_BOX_TYPE_DVVC: | |
| BOX_FIELD_ASSIGN(dovi_config, GF_DOVIConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_UUID: | |
| if (! memcmp(((GF_UnknownUUIDBox*)a)->uuid, GF_ISOM_IPOD_EXT, 16)) { | |
| BOX_FIELD_ASSIGN(ipod_ext, GF_UnknownUUIDBox) | |
| } else { | |
| return GF_OK; | |
| } | |
| break; | |
| case GF_ISOM_BOX_TYPE_D263: | |
| BOX_FIELD_ASSIGN(cfg_3gpp, GF_3GPPConfigBox) | |
| /*for 3GP config, remember sample entry type in config*/ | |
| if (ptr->cfg_3gpp) | |
| ptr->cfg_3gpp->cfg.type = ptr->type; | |
| break; | |
| case GF_ISOM_BOX_TYPE_JP2H: | |
| BOX_FIELD_ASSIGN(jp2h, GF_J2KHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_PASP: | |
| case GF_ISOM_BOX_TYPE_CLAP: | |
| case GF_ISOM_BOX_TYPE_COLR: | |
| case GF_ISOM_BOX_TYPE_MDCV: | |
| case GF_ISOM_BOX_TYPE_CLLI: | |
| case GF_ISOM_BOX_TYPE_CCST: | |
| case GF_ISOM_BOX_TYPE_AUXI: | |
| case GF_ISOM_BOX_TYPE_RVCC: | |
| case GF_ISOM_BOX_TYPE_M4DS: | |
| case GF_ISOM_BOX_TYPE_VEXU: | |
| if (!is_rem && !gf_isom_box_check_unique(s->child_boxes, a)) { | |
| ERROR_ON_DUPLICATED_BOX(a, ptr) | |
| } | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err video_sample_entry_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MPEGVisualSampleEntryBox *mp4v = (GF_MPEGVisualSampleEntryBox*)s; | |
| GF_Err e; | |
| e = gf_isom_video_sample_entry_read((GF_VisualSampleEntryBox *)s, bs); | |
| if (e) return e; | |
| e = gf_isom_box_array_read(s, bs); | |
| if (e) return e; | |
| /*this is an AVC sample desc*/ | |
| if (mp4v->avc_config || mp4v->svc_config || mp4v->mvc_config) | |
| AVC_RewriteESDescriptor(mp4v); | |
| /*this is an HEVC sample desc*/ | |
| if (mp4v->hevc_config || mp4v->lhvc_config || (mp4v->type==GF_ISOM_BOX_TYPE_HVT1)) | |
| HEVC_RewriteESDescriptor(mp4v); | |
| /*this is an AV1 sample desc*/ | |
| if (mp4v->av1_config) | |
| AV1_RewriteESDescriptor(mp4v); | |
| /*this is a VP8-9 sample desc*/ | |
| if (mp4v->vp_config) | |
| VP9_RewriteESDescriptor(mp4v); | |
| if (s->type==GF_ISOM_BOX_TYPE_ENCV) { | |
| GF_ProtectionSchemeInfoBox *sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(s->child_boxes, GF_ISOM_BOX_TYPE_SINF); | |
| if (sinf && sinf->original_format) { | |
| u32 type = sinf->original_format->data_format; | |
| switch (type) { | |
| case GF_ISOM_SUBTYPE_3GP_H263: | |
| if (mp4v->cfg_3gpp) mp4v->cfg_3gpp->cfg.type = type; | |
| break; | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *video_sample_entry_box_new() | |
| { | |
| GF_MPEGVisualSampleEntryBox *tmp; | |
| GF_SAFEALLOC(tmp, GF_MPEGVisualSampleEntryBox); | |
| if (tmp == NULL) return NULL; | |
| gf_isom_video_sample_entry_init((GF_VisualSampleEntryBox *)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err video_sample_entry_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_isom_video_sample_entry_write((GF_VisualSampleEntryBox *)s, bs); | |
| return GF_OK; | |
| } | |
| GF_Err video_sample_entry_box_size(GF_Box *s) | |
| { | |
| GF_Box *b; | |
| u32 pos=0; | |
| GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s; | |
| gf_isom_video_sample_entry_size((GF_VisualSampleEntryBox *)s); | |
| /*make sure we write the config box first, we don't care about the rest*/ | |
| /*mp4v*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->esd, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->cfg_3gpp, &pos); | |
| /*avc / SVC + MVC*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->avc_config, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->svc_config, &pos); | |
| if (ptr->mvc_config) { | |
| gf_isom_check_position(s, gf_isom_box_find_child(s->child_boxes, GF_ISOM_BOX_TYPE_VWID), &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->mvc_config, &pos); | |
| } | |
| /*HEVC*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->hevc_config, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->lhvc_config, &pos); | |
| /*VVC*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->vvc_config, &pos); | |
| /*AV1*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->av1_config, &pos); | |
| /*VPx*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->vp_config, &pos); | |
| /*JP2H*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->jp2h, &pos); | |
| /*DolbyVision*/ | |
| gf_isom_check_position(s, (GF_Box *)ptr->dovi_config, &pos); | |
| b = gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_ST3D); | |
| if (b) gf_isom_check_position(s, b, &pos); | |
| b = gf_isom_box_find_child(ptr->child_boxes, GF_ISOM_BOX_TYPE_SV3D); | |
| if (b) gf_isom_check_position(s, b, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void mvex_box_del(GF_Box *s) | |
| { | |
| GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s; | |
| if (ptr == NULL) return; | |
| gf_list_del(ptr->TrackExList); | |
| gf_list_del(ptr->TrackExPropList); | |
| gf_free(ptr); | |
| } | |
| GF_Err mvex_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_TREX: | |
| BOX_FIELD_LIST_ASSIGN(TrackExList) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TREP: | |
| BOX_FIELD_LIST_ASSIGN(TrackExPropList) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_MEHD: | |
| BOX_FIELD_ASSIGN(mehd, GF_MovieExtendsHeaderBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mvex_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *mvex_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieExtendsBox, GF_ISOM_BOX_TYPE_MVEX); | |
| tmp->TrackExList = gf_list_new(); | |
| if (!tmp->TrackExList) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| tmp->TrackExPropList = gf_list_new(); | |
| if (!tmp->TrackExPropList) { | |
| gf_list_del(tmp->TrackExList); | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mvex_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err mvex_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *) s; | |
| gf_isom_check_position(s, (GF_Box *)ptr->mehd, &pos); | |
| gf_isom_check_position_list(s, ptr->TrackExList, &pos); | |
| gf_isom_check_position_list(s, ptr->TrackExPropList, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *mehd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieExtendsHeaderBox, GF_ISOM_BOX_TYPE_MEHD); | |
| return (GF_Box *)tmp; | |
| } | |
| void mehd_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err mehd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MovieExtendsHeaderBox *ptr = (GF_MovieExtendsHeaderBox *)s; | |
| if (ptr->version==1) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->fragment_duration = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->fragment_duration = (u64) gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mehd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MovieExtendsHeaderBox *ptr = (GF_MovieExtendsHeaderBox *)s; | |
| GF_Err e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version == 1) { | |
| gf_bs_write_u64(bs, ptr->fragment_duration); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->fragment_duration); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mehd_box_size(GF_Box *s) | |
| { | |
| GF_MovieExtendsHeaderBox *ptr = (GF_MovieExtendsHeaderBox *)s; | |
| ptr->version = (ptr->fragment_duration>0xFFFFFFFF) ? 1 : 0; | |
| s->size += (ptr->version == 1) ? 8 : 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| void mvhd_box_del(GF_Box *s) | |
| { | |
| GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err mvhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| if (ptr->version == 1) { | |
| ISOM_DECREASE_SIZE(ptr, 28); | |
| ptr->creationTime = gf_bs_read_u64(bs); | |
| ptr->modificationTime = gf_bs_read_u64(bs); | |
| ptr->timeScale = gf_bs_read_u32(bs); | |
| ptr->duration = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| ptr->creationTime = gf_bs_read_u32(bs); | |
| ptr->modificationTime = gf_bs_read_u32(bs); | |
| ptr->timeScale = gf_bs_read_u32(bs); | |
| ptr->duration = gf_bs_read_u32(bs); | |
| } | |
| if (!ptr->timeScale) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Movie header timescale is invalid (0) - defaulting to 600\n" )); | |
| ptr->timeScale = 600; | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 80); | |
| ptr->preferredRate = gf_bs_read_u32(bs); | |
| ptr->preferredVolume = gf_bs_read_u16(bs); | |
| gf_bs_read_data(bs, ptr->reserved, 10); | |
| ptr->matrixA = gf_bs_read_u32(bs); | |
| ptr->matrixB = gf_bs_read_u32(bs); | |
| ptr->matrixU = gf_bs_read_u32(bs); | |
| ptr->matrixC = gf_bs_read_u32(bs); | |
| ptr->matrixD = gf_bs_read_u32(bs); | |
| ptr->matrixV = gf_bs_read_u32(bs); | |
| ptr->matrixX = gf_bs_read_u32(bs); | |
| ptr->matrixY = gf_bs_read_u32(bs); | |
| ptr->matrixW = gf_bs_read_u32(bs); | |
| ptr->previewTime = gf_bs_read_u32(bs); | |
| ptr->previewDuration = gf_bs_read_u32(bs); | |
| ptr->posterTime = gf_bs_read_u32(bs); | |
| ptr->selectionTime = gf_bs_read_u32(bs); | |
| ptr->selectionDuration = gf_bs_read_u32(bs); | |
| ptr->currentTime = gf_bs_read_u32(bs); | |
| ptr->nextTrackID = gf_bs_read_u32(bs); | |
| ptr->original_duration = ptr->duration; | |
| return GF_OK; | |
| } | |
| GF_Box *mvhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MovieHeaderBox, GF_ISOM_BOX_TYPE_MVHD); | |
| tmp->preferredRate = (1<<16); | |
| tmp->preferredVolume = (1<<8); | |
| tmp->matrixA = (1<<16); | |
| tmp->matrixD = (1<<16); | |
| tmp->matrixW = (1<<30); | |
| tmp->nextTrackID = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mvhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version == 1) { | |
| gf_bs_write_u64(bs, ptr->creationTime); | |
| gf_bs_write_u64(bs, ptr->modificationTime); | |
| gf_bs_write_u32(bs, ptr->timeScale); | |
| gf_bs_write_u64(bs, ptr->duration); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->creationTime); | |
| gf_bs_write_u32(bs, (u32) ptr->modificationTime); | |
| gf_bs_write_u32(bs, ptr->timeScale); | |
| gf_bs_write_u32(bs, (u32) ptr->duration); | |
| } | |
| gf_bs_write_u32(bs, ptr->preferredRate); | |
| gf_bs_write_u16(bs, ptr->preferredVolume); | |
| gf_bs_write_data(bs, ptr->reserved, 10); | |
| gf_bs_write_u32(bs, ptr->matrixA); | |
| gf_bs_write_u32(bs, ptr->matrixB); | |
| gf_bs_write_u32(bs, ptr->matrixU); | |
| gf_bs_write_u32(bs, ptr->matrixC); | |
| gf_bs_write_u32(bs, ptr->matrixD); | |
| gf_bs_write_u32(bs, ptr->matrixV); | |
| gf_bs_write_u32(bs, ptr->matrixX); | |
| gf_bs_write_u32(bs, ptr->matrixY); | |
| gf_bs_write_u32(bs, ptr->matrixW); | |
| gf_bs_write_u32(bs, ptr->previewTime); | |
| gf_bs_write_u32(bs, ptr->previewDuration); | |
| gf_bs_write_u32(bs, ptr->posterTime); | |
| gf_bs_write_u32(bs, ptr->selectionTime); | |
| gf_bs_write_u32(bs, ptr->selectionDuration); | |
| gf_bs_write_u32(bs, ptr->currentTime); | |
| gf_bs_write_u32(bs, ptr->nextTrackID); | |
| return GF_OK; | |
| } | |
| GF_Err mvhd_box_size(GF_Box *s) | |
| { | |
| GF_MovieHeaderBox *ptr = (GF_MovieHeaderBox *)s; | |
| ptr->version = 0; | |
| if (ptr->duration!=(u64)-1 && (ptr->duration>0xFFFFFFFF)) ptr->version = 1; | |
| if (ptr->creationTime!=(u64)-1 && (ptr->creationTime>0xFFFFFFFF)) ptr->version = 1; | |
| if (ptr->modificationTime!=(u64)-1 && (ptr->modificationTime>0xFFFFFFFF)) ptr->version = 1; | |
| ptr->size += (ptr->version == 1) ? 28 : 16; | |
| ptr->size += 80; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void nmhd_box_del(GF_Box *s) | |
| { | |
| GF_MPEGMediaHeaderBox *ptr = (GF_MPEGMediaHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err nmhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return GF_OK; | |
| } | |
| GF_Box *nmhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MPEGMediaHeaderBox, GF_ISOM_BOX_TYPE_NMHD); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err nmhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_full_box_write(s, bs); | |
| } | |
| GF_Err nmhd_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void padb_box_del(GF_Box *s) | |
| { | |
| GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->padbits) gf_free(ptr->padbits); | |
| gf_free(ptr); | |
| } | |
| GF_Err padb_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->SampleCount = gf_bs_read_u32(bs); | |
| if (ptr->size < ptr->SampleCount/2) //half byte per sample | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->padbits = (u8 *)gf_malloc(sizeof(u8)*ptr->SampleCount); | |
| if (!ptr->padbits) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->SampleCount; i += 2) { | |
| gf_bs_read_int(bs, 1); | |
| if (i+1 < ptr->SampleCount) { | |
| ptr->padbits[i+1] = gf_bs_read_int(bs, 3); | |
| } else { | |
| gf_bs_read_int(bs, 3); | |
| } | |
| gf_bs_read_int(bs, 1); | |
| ptr->padbits[i] = gf_bs_read_int(bs, 3); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *padb_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PaddingBitsBox, GF_ISOM_BOX_TYPE_PADB); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err padb_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_Err e; | |
| GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->SampleCount, 32); | |
| for (i=0 ; i<ptr->SampleCount; i += 2) { | |
| gf_bs_write_int(bs, 0, 1); | |
| if (i+1 < ptr->SampleCount) { | |
| gf_bs_write_int(bs, ptr->padbits[i+1], 3); | |
| } else { | |
| gf_bs_write_int(bs, 0, 3); | |
| } | |
| gf_bs_write_int(bs, 0, 1); | |
| gf_bs_write_int(bs, ptr->padbits[i], 3); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err padb_box_size(GF_Box *s) | |
| { | |
| GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *)s; | |
| ptr->size += 4; | |
| if (ptr->SampleCount) ptr->size += (ptr->SampleCount + 1) / 2; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void rely_box_del(GF_Box *s) | |
| { | |
| GF_RelyHintBox *rely = (GF_RelyHintBox *)s; | |
| gf_free(rely); | |
| } | |
| GF_Err rely_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_RelyHintBox *ptr = (GF_RelyHintBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 1); | |
| ptr->reserved = gf_bs_read_int(bs, 6); | |
| ptr->preferred = gf_bs_read_int(bs, 1); | |
| ptr->required = gf_bs_read_int(bs, 1); | |
| return GF_OK; | |
| } | |
| GF_Box *rely_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_RelyHintBox, GF_ISOM_BOX_TYPE_RELY); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err rely_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_RelyHintBox *ptr = (GF_RelyHintBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->reserved, 6); | |
| gf_bs_write_int(bs, ptr->preferred, 1); | |
| gf_bs_write_int(bs, ptr->required, 1); | |
| return GF_OK; | |
| } | |
| GF_Err rely_box_size(GF_Box *s) | |
| { | |
| s->size += 1; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void rtpo_box_del(GF_Box *s) | |
| { | |
| GF_RTPOBox *rtpo = (GF_RTPOBox *)s; | |
| gf_free(rtpo); | |
| } | |
| GF_Err rtpo_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_RTPOBox *ptr = (GF_RTPOBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->timeOffset = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *rtpo_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_RTPOBox, GF_ISOM_BOX_TYPE_RTPO); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err rtpo_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_RTPOBox *ptr = (GF_RTPOBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| //here we have no pb, just remembed that some entries will have to | |
| //be 4-bytes aligned ... | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->timeOffset); | |
| return GF_OK; | |
| } | |
| GF_Err rtpo_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void smhd_box_del(GF_Box *s) | |
| { | |
| GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s; | |
| if (ptr == NULL ) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err smhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->balance = gf_bs_read_u16(bs); | |
| ptr->reserved = gf_bs_read_u16(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *smhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SoundMediaHeaderBox, GF_ISOM_BOX_TYPE_SMHD); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err smhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->balance); | |
| gf_bs_write_u16(bs, ptr->reserved); | |
| return GF_OK; | |
| } | |
| GF_Err smhd_box_size(GF_Box *s) | |
| { | |
| GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s; | |
| ptr->reserved = 0; | |
| ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void snro_box_del(GF_Box *s) | |
| { | |
| GF_SeqOffHintEntryBox *snro = (GF_SeqOffHintEntryBox *)s; | |
| gf_free(snro); | |
| } | |
| GF_Err snro_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SeqOffHintEntryBox *ptr = (GF_SeqOffHintEntryBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->SeqOffset = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *snro_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SeqOffHintEntryBox, GF_ISOM_BOX_TYPE_SNRO); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err snro_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SeqOffHintEntryBox *ptr = (GF_SeqOffHintEntryBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->SeqOffset); | |
| return GF_OK; | |
| } | |
| GF_Err snro_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stbl_box_del(GF_Box *s) | |
| { | |
| GF_SampleTableBox *ptr = (GF_SampleTableBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->sub_samples) gf_list_del(ptr->sub_samples); | |
| if (ptr->sampleGroups) gf_list_del(ptr->sampleGroups); | |
| if (ptr->sampleGroupsDescription) gf_list_del(ptr->sampleGroupsDescription); | |
| if (ptr->sai_sizes) gf_list_del(ptr->sai_sizes); | |
| if (ptr->sai_offsets) gf_list_del(ptr->sai_offsets); | |
| if (ptr->traf_map) { | |
| if (ptr->traf_map->frag_starts) { | |
| u32 i; | |
| for (i=0; i<ptr->traf_map->nb_entries; i++) { | |
| if (ptr->traf_map->frag_starts[i].moof_template) | |
| gf_free(ptr->traf_map->frag_starts[i].moof_template); | |
| } | |
| gf_free(ptr->traf_map->frag_starts); | |
| } | |
| gf_free(ptr->traf_map); | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err stbl_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_SampleTableBox *ptr = (GF_SampleTableBox *)s; | |
| if (!a) return GF_OK; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_STTS: | |
| BOX_FIELD_ASSIGN(TimeToSample, GF_TimeToSampleBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_CTTS: | |
| BOX_FIELD_ASSIGN(CompositionOffset, GF_CompositionOffsetBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_CSLG: | |
| BOX_FIELD_ASSIGN(CompositionToDecode, GF_CompositionToDecodeBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_STSS: | |
| BOX_FIELD_ASSIGN(SyncSample, GF_SyncSampleBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_STSD: | |
| BOX_FIELD_ASSIGN(SampleDescription, GF_SampleDescriptionBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_STZ2: | |
| case GF_ISOM_BOX_TYPE_STSZ: | |
| BOX_FIELD_ASSIGN(SampleSize, GF_SampleSizeBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_STSC: | |
| BOX_FIELD_ASSIGN(SampleToChunk, GF_SampleToChunkBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_PADB: | |
| BOX_FIELD_ASSIGN(PaddingBits, GF_PaddingBitsBox) | |
| break; | |
| //WARNING: AS THIS MAY CHANGE DYNAMICALLY DURING EDIT, | |
| case GF_ISOM_BOX_TYPE_CO64: | |
| case GF_ISOM_BOX_TYPE_STCO: | |
| BOX_FIELD_ASSIGN(ChunkOffset, GF_Box) | |
| break; | |
| case GF_ISOM_BOX_TYPE_STSH: | |
| BOX_FIELD_ASSIGN(ShadowSync, GF_ShadowSyncBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_STDP: | |
| BOX_FIELD_ASSIGN(DegradationPriority, GF_DegradationPriorityBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_SDTP: | |
| BOX_FIELD_ASSIGN(SampleDep, GF_SampleDependencyTypeBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_SUBS: | |
| BOX_FIELD_LIST_ASSIGN(sub_samples) | |
| //check subsample box | |
| if (!is_rem) { | |
| GF_SubSampleInformationBox *subs = (GF_SubSampleInformationBox *)a; | |
| GF_SubSampleInfoEntry *ent = gf_list_get(subs->Samples, 0); | |
| if (!ent) { | |
| gf_list_rem(subs->Samples, 0); | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] first entry in SubSample in track SampleTable is invalid\n")); | |
| } | |
| else if (ent->sample_delta==0) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] first entry in SubSample in track SampleTable has sample_delta of 0, should be one. Fixing\n")); | |
| ent->sample_delta = 1; | |
| } | |
| } | |
| break; | |
| case GF_ISOM_BOX_TYPE_SBGP: | |
| case GF_ISOM_BOX_TYPE_CSGP: | |
| BOX_FIELD_LIST_ASSIGN(sampleGroups) | |
| break; | |
| case GF_ISOM_BOX_TYPE_SGPD: | |
| BOX_FIELD_LIST_ASSIGN(sampleGroupsDescription) | |
| break; | |
| case GF_ISOM_BOX_TYPE_SAIZ: | |
| BOX_FIELD_LIST_ASSIGN(sai_sizes) | |
| break; | |
| case GF_ISOM_BOX_TYPE_SAIO: | |
| BOX_FIELD_LIST_ASSIGN(sai_offsets) | |
| break; | |
| case GF_GPAC_BOX_TYPE_SREF: | |
| case GF_ISOM_BOX_TYPE_CDRF: | |
| BOX_FIELD_ASSIGN(SampleRefs, GF_SampleReferences) | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stbl_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| //we need to parse DegPrior in a special way | |
| GF_SampleTableBox *ptr = (GF_SampleTableBox *)s; | |
| e = gf_isom_box_array_read(s, bs); | |
| if (e) return e; | |
| if (!ptr->SyncSample) | |
| ptr->no_sync_found = 1; | |
| ptr->nb_sgpd_in_stbl = gf_list_count(ptr->sampleGroupsDescription); | |
| ptr->nb_stbl_boxes = gf_list_count(ptr->child_boxes); | |
| if (gf_bs_get_cookie(bs) & GF_ISOM_BS_COOKIE_CLONE_TRACK) | |
| return GF_OK; | |
| // return GF_OK; | |
| #define CHECK_BOX(_name) \ | |
| if (!ptr->_name) {\ | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Mandatory box %s is missing\n", #_name)); \ | |
| return GF_ISOM_INVALID_FILE; \ | |
| } | |
| CHECK_BOX(SampleToChunk) | |
| CHECK_BOX(SampleSize) | |
| CHECK_BOX(ChunkOffset) | |
| CHECK_BOX(TimeToSample) | |
| //sanity check | |
| if (ptr->SampleSize->sampleCount) { | |
| if (!ptr->TimeToSample->nb_entries || !ptr->SampleToChunk->nb_entries) | |
| return GF_ISOM_INVALID_FILE; | |
| //safety check : get info for last sample, if error consider file is invalid | |
| u64 sample_offset; | |
| u32 di, chunk; | |
| e = stbl_GetSampleInfos(ptr, ptr->SampleSize->sampleCount, &sample_offset, &chunk, &di, NULL); | |
| if (e) return e; | |
| e = stbl_GetSampleDTS(ptr->TimeToSample, ptr->SampleSize->sampleCount, &sample_offset); | |
| if (e) return e; | |
| } | |
| u32 i, max_chunks=0; | |
| if (ptr->ChunkOffset->type == GF_ISOM_BOX_TYPE_STCO) { | |
| max_chunks = ((GF_ChunkOffsetBox *)ptr->ChunkOffset)->nb_entries; | |
| } | |
| else if (ptr->ChunkOffset->type == GF_ISOM_BOX_TYPE_CO64) { | |
| max_chunks = ((GF_ChunkOffsetBox *)ptr->ChunkOffset)->nb_entries; | |
| } | |
| //sanity check on stsc vs chunk offset tables | |
| for (i=0; i<ptr->SampleToChunk->nb_entries; i++) { | |
| GF_StscEntry *ent = &ptr->SampleToChunk->entries[i]; | |
| if (!i && (ent->firstChunk!=1)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] first_chunk of first entry shall be 1 but is %u\n", ent->firstChunk)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (ptr->SampleToChunk->entries[i].firstChunk > max_chunks) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] first_chunk is %u but number of chunks defined %u\n", ptr->SampleToChunk->entries[i].firstChunk, max_chunks)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (i+1 == ptr->SampleToChunk->nb_entries) break; | |
| GF_StscEntry *next_ent = &ptr->SampleToChunk->entries[i+1]; | |
| if (next_ent->firstChunk < ent->firstChunk) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] first_chunk (%u) for entry %u is greater than first_chunk (%u) for entry %u\n", i+1, ent->firstChunk, i+2, next_ent->firstChunk)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stbl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleTableBox, GF_ISOM_BOX_TYPE_STBL); | |
| //maxSamplePer chunk is 10 by default | |
| tmp->MaxSamplePerChunk = 10; | |
| tmp->groupID = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stbl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err stbl_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_SampleTableBox *ptr = (GF_SampleTableBox *)s; | |
| gf_isom_check_position(s, (GF_Box *)ptr->SampleDescription, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->TimeToSample, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->CompositionOffset, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->CompositionToDecode, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->SyncSample, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->ShadowSync, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->SampleToChunk, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->SampleSize, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->ChunkOffset, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->DegradationPriority, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->SampleDep, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->PaddingBits, &pos); | |
| if (ptr->sub_samples) { | |
| gf_isom_check_position_list(s, ptr->sub_samples, &pos); | |
| } | |
| if (ptr->sampleGroupsDescription) { | |
| gf_isom_check_position_list(s, ptr->sampleGroupsDescription, &pos); | |
| } | |
| if (ptr->sampleGroups) { | |
| gf_isom_check_position_list(s, ptr->sampleGroups, &pos); | |
| } | |
| if (ptr->sai_sizes) { | |
| gf_isom_check_position_list(s, ptr->sai_sizes, &pos); | |
| } | |
| if (ptr->sai_offsets) { | |
| gf_isom_check_position_list(s, ptr->sai_offsets, &pos); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stco_box_del(GF_Box *s) | |
| { | |
| GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->offsets) gf_free(ptr->offsets); | |
| gf_free(ptr); | |
| } | |
| GF_Err stco_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 entries; | |
| GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->nb_entries > ptr->size / 4 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(u32)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stco\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (ptr->nb_entries) { | |
| ptr->offsets = (u32 *) gf_malloc(ptr->nb_entries * sizeof(u32) ); | |
| if (ptr->offsets == NULL) return GF_OUT_OF_MEM; | |
| ptr->alloc_size = ptr->nb_entries; | |
| for (entries = 0; entries < ptr->nb_entries; entries++) { | |
| ptr->offsets[entries] = gf_bs_read_u32(bs); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stco_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ChunkOffsetBox, GF_ISOM_BOX_TYPE_STCO); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stco_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nb_entries); | |
| for (i = 0; i < ptr->nb_entries; i++) { | |
| gf_bs_write_u32(bs, ptr->offsets[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stco_box_size(GF_Box *s) | |
| { | |
| GF_ChunkOffsetBox *ptr = (GF_ChunkOffsetBox *)s; | |
| ptr->size += 4 + (4 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stdp_box_del(GF_Box *s) | |
| { | |
| GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s; | |
| if (ptr == NULL ) return; | |
| if (ptr->priorities) gf_free(ptr->priorities); | |
| gf_free(ptr); | |
| } | |
| //this is called through stbl_read... | |
| GF_Err stdp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 entry; | |
| GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s; | |
| /*out-of-order stdp, assume no padding at the end and take the entire remaining data for entries*/ | |
| if (!ptr->nb_entries) ptr->nb_entries = (u32) ptr->size / 2; | |
| else if (ptr->nb_entries > ptr->size / 2) return GF_ISOM_INVALID_FILE; | |
| ptr->priorities = (u16 *) gf_malloc(ptr->nb_entries * sizeof(u16)); | |
| if (ptr->priorities == NULL) return GF_OUT_OF_MEM; | |
| for (entry = 0; entry < ptr->nb_entries; entry++) { | |
| ptr->priorities[entry] = gf_bs_read_u16(bs); | |
| } | |
| ISOM_DECREASE_SIZE(ptr, (2*ptr->nb_entries) ); | |
| return GF_OK; | |
| } | |
| GF_Box *stdp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DegradationPriorityBox, GF_ISOM_BOX_TYPE_STDP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stdp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| for (i = 0; i < ptr->nb_entries; i++) { | |
| gf_bs_write_u16(bs, ptr->priorities[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stdp_box_size(GF_Box *s) | |
| { | |
| GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s; | |
| ptr->size += (2 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stsc_box_del(GF_Box *s) | |
| { | |
| GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err stsc_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->nb_entries > ptr->size / 12 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(GF_StscEntry)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsc\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->alloc_size = ptr->nb_entries; | |
| ptr->entries = NULL; | |
| if (ptr->nb_entries) { | |
| ptr->entries = gf_malloc(sizeof(GF_StscEntry)*ptr->alloc_size); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| } | |
| for (i = 0; i < ptr->nb_entries; i++) { | |
| ptr->entries[i].firstChunk = gf_bs_read_u32(bs); | |
| ptr->entries[i].samplesPerChunk = gf_bs_read_u32(bs); | |
| ptr->entries[i].sampleDescriptionIndex = gf_bs_read_u32(bs); | |
| ptr->entries[i].isEdited = 0; | |
| ptr->entries[i].nextChunk = 0; | |
| if (!ptr->entries[i].firstChunk) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] invalid first chunk 0 in stsc entry\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| //update the next chunk in the previous entry | |
| if (i) ptr->entries[i-1].nextChunk = ptr->entries[i].firstChunk; | |
| } | |
| ptr->currentIndex = 0; | |
| ptr->firstSampleInCurrentChunk = 0; | |
| ptr->currentChunk = 0; | |
| ptr->ghostNumber = 0; | |
| return GF_OK; | |
| } | |
| GF_Box *stsc_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleToChunkBox, GF_ISOM_BOX_TYPE_STSC); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stsc_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nb_entries); | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| gf_bs_write_u32(bs, ptr->entries[i].firstChunk); | |
| gf_bs_write_u32(bs, ptr->entries[i].samplesPerChunk); | |
| gf_bs_write_u32(bs, ptr->entries[i].sampleDescriptionIndex); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stsc_box_size(GF_Box *s) | |
| { | |
| GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s; | |
| ptr->size += 4 + (12 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stsd_box_del(GF_Box *s) | |
| { | |
| GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err stsd_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_UnknownBox *def; | |
| if (!a) return GF_OK; | |
| if (is_rem || gf_box_valid_in_parent(a, "stsd")) { | |
| return GF_OK; | |
| } | |
| switch (a->type) { | |
| //unknown sample description: we need a specific box to handle the data ref index | |
| //rather than a default box ... | |
| case GF_ISOM_BOX_TYPE_UNKNOWN: | |
| def = (GF_UnknownBox *)a; | |
| /*we need at least 8 bytes for unknown sample entries*/ | |
| if (def->dataSize < 8) { | |
| gf_isom_box_del_parent(&s->child_boxes, a); | |
| return GF_ISOM_INVALID_MEDIA; | |
| } | |
| return GF_OK; | |
| default: | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Cannot process box of type %s\n", gf_4cc_to_str(a->type))); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| GF_Err stsd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| ISOM_DECREASE_SIZE(s, 4) | |
| gf_bs_read_u32(bs); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *stsd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleDescriptionBox, GF_ISOM_BOX_TYPE_STSD); | |
| tmp->child_boxes = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stsd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 nb_entries; | |
| GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| nb_entries = gf_list_count(ptr->child_boxes); | |
| gf_bs_write_u32(bs, nb_entries); | |
| return GF_OK; | |
| } | |
| GF_Err stsd_box_size(GF_Box *s) | |
| { | |
| GF_SampleDescriptionBox *ptr = (GF_SampleDescriptionBox *)s; | |
| ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stsh_box_del(GF_Box *s) | |
| { | |
| u32 i = 0; | |
| GF_StshEntry *ent; | |
| GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s; | |
| if (ptr == NULL) return; | |
| while ( (ent = (GF_StshEntry *)gf_list_enum(ptr->entries, &i)) ) { | |
| gf_free(ent); | |
| } | |
| gf_list_del(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err stsh_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 count, i; | |
| GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s; | |
| ISOM_DECREASE_SIZE(s, 4) | |
| count = gf_bs_read_u32(bs); | |
| if (ptr->size / 8 < count) | |
| return GF_ISOM_INVALID_FILE; | |
| for (i = 0; i < count; i++) { | |
| GF_StshEntry *ent = (GF_StshEntry *) gf_malloc(sizeof(GF_StshEntry)); | |
| if (!ent) return GF_OUT_OF_MEM; | |
| ent->shadowedSampleNumber = gf_bs_read_u32(bs); | |
| ent->syncSampleNumber = gf_bs_read_u32(bs); | |
| e = gf_list_add(ptr->entries, ent); | |
| if (e) return e; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stsh_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ShadowSyncBox, GF_ISOM_BOX_TYPE_STSH); | |
| tmp->entries = gf_list_new(); | |
| if (!tmp->entries) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stsh_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_StshEntry *ent; | |
| GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, gf_list_count(ptr->entries)); | |
| i=0; | |
| while ((ent = (GF_StshEntry *)gf_list_enum(ptr->entries, &i))) { | |
| gf_bs_write_u32(bs, ent->shadowedSampleNumber); | |
| gf_bs_write_u32(bs, ent->syncSampleNumber); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stsh_box_size(GF_Box *s) | |
| { | |
| GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s; | |
| ptr->size += 4 + (8 * gf_list_count(ptr->entries)); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stss_box_del(GF_Box *s) | |
| { | |
| GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->sampleNumbers) gf_free(ptr->sampleNumbers); | |
| gf_free(ptr); | |
| } | |
| GF_Err stss_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->size / 4 < ptr->nb_entries || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(u32)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stss\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->alloc_size = ptr->nb_entries; | |
| ptr->sampleNumbers = (u32 *) gf_malloc( ptr->alloc_size * sizeof(u32)); | |
| if (ptr->sampleNumbers == NULL) return GF_OUT_OF_MEM; | |
| for (i = 0; i < ptr->nb_entries; i++) { | |
| ptr->sampleNumbers[i] = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stss_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SyncSampleBox, GF_ISOM_BOX_TYPE_STSS); | |
| return (GF_Box*)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stss_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nb_entries); | |
| for (i = 0; i < ptr->nb_entries; i++) { | |
| gf_bs_write_u32(bs, ptr->sampleNumbers[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stss_box_size(GF_Box *s) | |
| { | |
| GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s; | |
| ptr->size += 4 + (4 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stsz_box_del(GF_Box *s) | |
| { | |
| GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->sizes) gf_free(ptr->sizes); | |
| gf_free(ptr); | |
| } | |
| GF_Err stsz_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, estSize; | |
| GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| //support for CompactSizes | |
| if (s->type == GF_ISOM_BOX_TYPE_STSZ) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->sampleSize = gf_bs_read_u32(bs); | |
| ptr->sampleCount = gf_bs_read_u32(bs); | |
| } else { | |
| //24-reserved | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| gf_bs_read_int(bs, 24); | |
| i = gf_bs_read_u8(bs); | |
| ptr->sampleCount = gf_bs_read_u32(bs); | |
| switch (i) { | |
| case 4: | |
| case 8: | |
| case 16: | |
| ptr->sampleSize = i; | |
| break; | |
| default: | |
| //try to fix the file | |
| //no samples, no parsing pb | |
| if (!ptr->sampleCount) { | |
| ptr->sampleSize = 16; | |
| return GF_OK; | |
| } | |
| estSize = (u32) (ptr->size) / ptr->sampleCount; | |
| if (!estSize && ((ptr->sampleCount+1)/2 == (ptr->size)) ) { | |
| ptr->sampleSize = 4; | |
| break; | |
| } else if (estSize == 1 || estSize == 2) { | |
| ptr->sampleSize = 8 * estSize; | |
| } else { | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| } | |
| if (ptr->sampleCount && (u64)ptr->sampleCount > (u64)SIZE_MAX/sizeof(u32)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (s->type == GF_ISOM_BOX_TYPE_STSZ) { | |
| if (! ptr->sampleSize && ptr->sampleCount) { | |
| if (ptr->sampleCount > ptr->size / 4) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->sizes = (u32 *) gf_malloc(ptr->sampleCount * sizeof(u32)); | |
| if (! ptr->sizes) return GF_OUT_OF_MEM; | |
| ptr->alloc_size = ptr->sampleCount; | |
| for (i = 0; i < ptr->sampleCount; i++) { | |
| ptr->sizes[i] = gf_bs_read_u32(bs); | |
| if (ptr->max_size < ptr->sizes[i]) | |
| ptr->max_size = ptr->sizes[i]; | |
| ptr->total_size += ptr->sizes[i]; | |
| ptr->total_samples++; | |
| } | |
| } | |
| } else { | |
| if (ptr->sampleSize==4) { | |
| if (ptr->sampleCount / 2 > ptr->size) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } else { | |
| if (ptr->sampleCount > ptr->size / (ptr->sampleSize/8)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stsz\n", ptr->sampleCount)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| } | |
| //note we could optimize the mem usage by keeping the table compact | |
| //in memory. But that would complicate both caching and editing | |
| //we therefore keep all sizes as u32 and uncompress the table | |
| ptr->sizes = (u32 *) gf_malloc(ptr->sampleCount * sizeof(u32)); | |
| if (! ptr->sizes) return GF_OUT_OF_MEM; | |
| ptr->alloc_size = ptr->sampleCount; | |
| for (i = 0; i < ptr->sampleCount; ) { | |
| u32 s_size; | |
| switch (ptr->sampleSize) { | |
| case 4: | |
| s_size = ptr->sizes[i] = gf_bs_read_int(bs, 4); | |
| if (ptr->max_size < s_size) | |
| ptr->max_size = s_size; | |
| ptr->total_size += s_size; | |
| ptr->total_samples++; | |
| if (i+1 < ptr->sampleCount) { | |
| s_size = ptr->sizes[i+1] = gf_bs_read_int(bs, 4); | |
| if (ptr->max_size < s_size) | |
| ptr->max_size = s_size; | |
| ptr->total_size += s_size; | |
| ptr->total_samples++; | |
| } else { | |
| //0 padding in odd sample count | |
| gf_bs_read_int(bs, 4); | |
| } | |
| i += 2; | |
| break; | |
| default: | |
| s_size = ptr->sizes[i] = gf_bs_read_int(bs, ptr->sampleSize); | |
| if (ptr->max_size < s_size) | |
| ptr->max_size = s_size; | |
| ptr->total_size += s_size; | |
| ptr->total_samples++; | |
| i += 1; | |
| break; | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stsz_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleSizeBox, 0); | |
| //type is unknown here, can be regular or compact table | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stsz_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| //in both versions this is still valid | |
| if (ptr->type == GF_ISOM_BOX_TYPE_STSZ) { | |
| gf_bs_write_u32(bs, ptr->sampleSize); | |
| } else { | |
| gf_bs_write_u24(bs, 0); | |
| gf_bs_write_u8(bs, ptr->sampleSize); | |
| } | |
| gf_bs_write_u32(bs, ptr->sampleCount); | |
| if (ptr->type == GF_ISOM_BOX_TYPE_STSZ) { | |
| if (ptr->sampleSize) return GF_OK; | |
| for (i = 0; i < ptr->sampleCount; i++) { | |
| gf_bs_write_u32(bs, ptr->sizes ? ptr->sizes[i] : 0); | |
| } | |
| } else { | |
| if (!ptr->sizes) return GF_ISOM_INVALID_FILE; | |
| for (i = 0; i < ptr->sampleCount; ) { | |
| switch (ptr->sampleSize) { | |
| case 4: | |
| gf_bs_write_int(bs, ptr->sizes[i], 4); | |
| if (i+1 < ptr->sampleCount) { | |
| gf_bs_write_int(bs, ptr->sizes[i+1], 4); | |
| } else { | |
| //0 padding in odd sample count | |
| gf_bs_write_int(bs, 0, 4); | |
| } | |
| i += 2; | |
| break; | |
| default: | |
| gf_bs_write_int(bs, ptr->sizes[i], ptr->sampleSize); | |
| i += 1; | |
| break; | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stsz_box_size(GF_Box *s) | |
| { | |
| u32 i, fieldSize, size; | |
| GF_SampleSizeBox *ptr = (GF_SampleSizeBox *)s; | |
| ptr->size += 8; | |
| if (!ptr->sampleCount) return GF_OK; | |
| //regular table | |
| if (ptr->type == GF_ISOM_BOX_TYPE_STSZ) { | |
| if (ptr->sampleSize) return GF_OK; | |
| ptr->size += (4 * ptr->sampleCount); | |
| return GF_OK; | |
| } | |
| if (!ptr->sizes) return GF_ISOM_INVALID_FILE; | |
| //compact size table | |
| fieldSize = 4; | |
| size = ptr->sizes[0]; | |
| for (i=0; i < ptr->sampleCount; i++) { | |
| if (ptr->sizes[i] <= 0xF) { | |
| } | |
| //switch to 8-bit table | |
| else if (ptr->sizes[i] <= 0xFF) { | |
| fieldSize = 8; | |
| } | |
| //switch to 16-bit table | |
| else if (ptr->sizes[i] <= 0xFFFF) { | |
| fieldSize = 16; | |
| } | |
| //switch to 32-bit table | |
| else { | |
| fieldSize = 32; | |
| } | |
| //check the size | |
| if (size != ptr->sizes[i]) size = 0; | |
| } | |
| //if all samples are of the same size, switch to regular (more compact) | |
| if (size) { | |
| ptr->type = GF_ISOM_BOX_TYPE_STSZ; | |
| ptr->sampleSize = size; | |
| gf_free(ptr->sizes); | |
| ptr->sizes = NULL; | |
| return GF_OK; | |
| } | |
| if (fieldSize == 32) { | |
| //oops, doesn't fit in a compact table | |
| ptr->type = GF_ISOM_BOX_TYPE_STSZ; | |
| ptr->size += (4 * ptr->sampleCount); | |
| return GF_OK; | |
| } | |
| //make sure we are a compact table (no need to change the mem representation) | |
| ptr->type = GF_ISOM_BOX_TYPE_STZ2; | |
| ptr->sampleSize = fieldSize; | |
| if (fieldSize == 4) { | |
| //do not forget the 0 padding field for odd count | |
| ptr->size += (ptr->sampleCount + 1) / 2; | |
| } else { | |
| ptr->size += (ptr->sampleCount) * (fieldSize/8); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stts_box_del(GF_Box *s) | |
| { | |
| GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err stts_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| u32 nb_patches=0, needs_patch = 0; | |
| GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s; | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| ptr->w_LastDTS = 0; | |
| #endif | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->nb_entries = gf_bs_read_u32(bs); | |
| if (ptr->size / 8 < ptr->nb_entries || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(GF_SttsEntry)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in stts\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->alloc_size = ptr->nb_entries; | |
| ptr->entries = gf_malloc(sizeof(GF_SttsEntry)*ptr->alloc_size); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| ptr->entries[i].sampleCount = gf_bs_read_u32(bs); | |
| ptr->entries[i].sampleDelta = gf_bs_read_u32(bs); | |
| //check for 0-duration | |
| if (!ptr->entries[i].sampleDelta | |
| //forbiden if not last sample | |
| && ((i+1 < ptr->nb_entries) || (ptr->entries[i].sampleCount>1)) | |
| ) { | |
| needs_patch += ptr->entries[i].sampleCount; | |
| if (i + 1 == ptr->nb_entries) needs_patch --; | |
| ptr->entries[i].sampleDelta = 1; | |
| nb_patches++; | |
| } | |
| //cf issue 1644: some media streams may have sample duration > 2^31 (ttml mostly), we cannot patch this | |
| //for now we disable the check, one opt could be to have the check only for some media types, or only for the first entry | |
| #if 0 | |
| else if ((s32) ptr->entries[i].sampleDelta < 0) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] stts entry %d has negative duration %d - forbidden ! Fixing to 1, sync may get lost (consider re-importing raw media)\n", i, (s32) ptr->entries[i].sampleDelta )); | |
| ptr->entries[i].sampleDelta = 1; | |
| } | |
| #endif | |
| //we patch exitsing sample_delta=0 to sample_delta=1 but we want to avoid breaking the timing of following samples | |
| //accumulate the ticks added due to patching and remove them from previous entries - cf #3319 | |
| if (needs_patch) { | |
| s64 k; | |
| //walk down the previous samples and try to shorten the duration | |
| for (k=i; k>=0; k--) { | |
| if (ptr->entries[k].sampleDelta == 1) continue; | |
| //we only try to locate entries with a delta larger than the accumulated number of patches | |
| if (ptr->entries[k].sampleDelta <= needs_patch) continue; | |
| if (ptr->entries[k].sampleCount == 1) { | |
| ptr->entries[k].sampleDelta -= needs_patch; | |
| needs_patch = 0; | |
| break; | |
| } | |
| //split entry in two | |
| if (ptr->nb_entries>=ptr->alloc_size) { | |
| ptr->alloc_size += 1; | |
| ptr->entries = gf_realloc(ptr->entries, sizeof(GF_SttsEntry) * ptr->alloc_size); | |
| } | |
| memmove(&ptr->entries[k+2], &ptr->entries[k+1], sizeof(GF_SttsEntry) * (ptr->nb_entries - k - 1) ); | |
| ptr->entries[k].sampleCount -= 1; | |
| ptr->entries[k+1].sampleCount = 1; | |
| ptr->entries[k+1].sampleDelta = ptr->entries[k].sampleDelta - needs_patch; | |
| i++; | |
| ptr->nb_entries++; | |
| needs_patch = 0; | |
| break; | |
| } | |
| } | |
| //needs_patch may still be non-0 if we couldn't find an entry, we'll adjust ts of next entries | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| ptr->w_currentSampleNum += ptr->entries[i].sampleCount; | |
| ptr->w_LastDTS += (u64)ptr->entries[i].sampleCount * ptr->entries[i].sampleDelta; | |
| #endif | |
| if (ptr->max_ts_delta<ptr->entries[i].sampleDelta) | |
| ptr->max_ts_delta = ptr->entries[i].sampleDelta; | |
| } | |
| ISOM_DECREASE_SIZE(ptr, ptr->nb_entries*8); | |
| if (nb_patches) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Found %u stts entries with forbidden sample_delta=0 - patching to 1\n", nb_patches)); | |
| if (needs_patch) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] %u stts patches failed\n", needs_patch)); | |
| } | |
| } | |
| //remove the last sample delta. | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| if (ptr->nb_entries) ptr->w_LastDTS -= ptr->entries[ptr->nb_entries-1].sampleDelta; | |
| #endif | |
| return GF_OK; | |
| } | |
| GF_Box *stts_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TimeToSampleBox, GF_ISOM_BOX_TYPE_STTS); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stts_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->nb_entries); | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| gf_bs_write_u32(bs, ptr->entries[i].sampleCount); | |
| gf_bs_write_u32(bs, ptr->entries[i].sampleDelta); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stts_box_size(GF_Box *s) | |
| { | |
| GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s; | |
| ptr->size += 4 + (8 * ptr->nb_entries); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void tfhd_box_del(GF_Box *s) | |
| { | |
| GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err tfhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->trackID = gf_bs_read_u32(bs); | |
| //The rest depends on the flags | |
| if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->base_data_offset = gf_bs_read_u64(bs); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->sample_desc_index = gf_bs_read_u32(bs); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->def_sample_duration = gf_bs_read_u32(bs); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->def_sample_size = gf_bs_read_u32(bs); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->def_sample_flags = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *tfhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackFragmentHeaderBox, GF_ISOM_BOX_TYPE_TFHD); | |
| //NO FLAGS SET BY DEFAULT | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tfhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->trackID); | |
| //The rest depends on the flags | |
| if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) { | |
| gf_bs_write_u64(bs, ptr->base_data_offset); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) { | |
| gf_bs_write_u32(bs, ptr->sample_desc_index); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) { | |
| gf_bs_write_u32(bs, ptr->def_sample_duration); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) { | |
| gf_bs_write_u32(bs, ptr->def_sample_size); | |
| } | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) { | |
| gf_bs_write_u32(bs, ptr->def_sample_flags); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err tfhd_box_size(GF_Box *s) | |
| { | |
| GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s; | |
| ptr->size += 4; | |
| //The rest depends on the flags | |
| if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) ptr->size += 8; | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) ptr->size += 4; | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) ptr->size += 4; | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) ptr->size += 4; | |
| if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| void tims_box_del(GF_Box *s) | |
| { | |
| GF_TSHintEntryBox *tims = (GF_TSHintEntryBox *)s; | |
| gf_free(tims); | |
| } | |
| GF_Err tims_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TSHintEntryBox *ptr = (GF_TSHintEntryBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->timeScale = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tims_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TSHintEntryBox, GF_ISOM_BOX_TYPE_TIMS); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tims_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TSHintEntryBox *ptr = (GF_TSHintEntryBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->timeScale); | |
| return GF_OK; | |
| } | |
| GF_Err tims_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void tkhd_box_del(GF_Box *s) | |
| { | |
| GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| return; | |
| } | |
| GF_Err tkhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s; | |
| if (ptr->version == 1) { | |
| ISOM_DECREASE_SIZE(ptr, 32); | |
| ptr->creationTime = gf_bs_read_u64(bs); | |
| ptr->modificationTime = gf_bs_read_u64(bs); | |
| ptr->trackID = gf_bs_read_u32(bs); | |
| ptr->reserved1 = gf_bs_read_u32(bs); | |
| ptr->duration = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| ptr->creationTime = gf_bs_read_u32(bs); | |
| ptr->modificationTime = gf_bs_read_u32(bs); | |
| ptr->trackID = gf_bs_read_u32(bs); | |
| ptr->reserved1 = gf_bs_read_u32(bs); | |
| ptr->duration = gf_bs_read_u32(bs); | |
| } | |
| ptr->initial_duration = ptr->duration; | |
| ISOM_DECREASE_SIZE(ptr, 60); | |
| ptr->reserved2[0] = gf_bs_read_u32(bs); | |
| ptr->reserved2[1] = gf_bs_read_u32(bs); | |
| ptr->layer = gf_bs_read_u16(bs); | |
| ptr->alternate_group = gf_bs_read_u16(bs); | |
| ptr->volume = gf_bs_read_u16(bs); | |
| ptr->reserved3 = gf_bs_read_u16(bs); | |
| ptr->matrix[0] = gf_bs_read_u32(bs); | |
| ptr->matrix[1] = gf_bs_read_u32(bs); | |
| ptr->matrix[2] = gf_bs_read_u32(bs); | |
| ptr->matrix[3] = gf_bs_read_u32(bs); | |
| ptr->matrix[4] = gf_bs_read_u32(bs); | |
| ptr->matrix[5] = gf_bs_read_u32(bs); | |
| ptr->matrix[6] = gf_bs_read_u32(bs); | |
| ptr->matrix[7] = gf_bs_read_u32(bs); | |
| ptr->matrix[8] = gf_bs_read_u32(bs); | |
| ptr->width = gf_bs_read_u32(bs); | |
| ptr->height = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tkhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackHeaderBox, GF_ISOM_BOX_TYPE_TKHD); | |
| tmp->matrix[0] = 0x00010000; | |
| tmp->matrix[4] = 0x00010000; | |
| tmp->matrix[8] = 0x40000000; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tkhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version == 1) { | |
| gf_bs_write_u64(bs, ptr->creationTime); | |
| gf_bs_write_u64(bs, ptr->modificationTime); | |
| gf_bs_write_u32(bs, ptr->trackID); | |
| gf_bs_write_u32(bs, ptr->reserved1); | |
| gf_bs_write_u64(bs, ptr->duration); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->creationTime); | |
| gf_bs_write_u32(bs, (u32) ptr->modificationTime); | |
| gf_bs_write_u32(bs, ptr->trackID); | |
| gf_bs_write_u32(bs, ptr->reserved1); | |
| gf_bs_write_u32(bs, (u32) ptr->duration); | |
| } | |
| gf_bs_write_u32(bs, ptr->reserved2[0]); | |
| gf_bs_write_u32(bs, ptr->reserved2[1]); | |
| gf_bs_write_u16(bs, ptr->layer); | |
| gf_bs_write_u16(bs, ptr->alternate_group); | |
| gf_bs_write_u16(bs, ptr->volume); | |
| gf_bs_write_u16(bs, ptr->reserved3); | |
| gf_bs_write_u32(bs, ptr->matrix[0]); | |
| gf_bs_write_u32(bs, ptr->matrix[1]); | |
| gf_bs_write_u32(bs, ptr->matrix[2]); | |
| gf_bs_write_u32(bs, ptr->matrix[3]); | |
| gf_bs_write_u32(bs, ptr->matrix[4]); | |
| gf_bs_write_u32(bs, ptr->matrix[5]); | |
| gf_bs_write_u32(bs, ptr->matrix[6]); | |
| gf_bs_write_u32(bs, ptr->matrix[7]); | |
| gf_bs_write_u32(bs, ptr->matrix[8]); | |
| gf_bs_write_u32(bs, ptr->width); | |
| gf_bs_write_u32(bs, ptr->height); | |
| return GF_OK; | |
| } | |
| GF_Err tkhd_box_size(GF_Box *s) | |
| { | |
| GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s; | |
| ptr->version = 0; | |
| if (ptr->duration!=(u64)-1 && (ptr->duration>0xFFFFFFFF)) ptr->version = 1; | |
| if (ptr->creationTime!=(u64)-1 && (ptr->creationTime>0xFFFFFFFF)) ptr->version = 1; | |
| if (ptr->modificationTime!=(u64)-1 && (ptr->modificationTime>0xFFFFFFFF)) ptr->version = 1; | |
| ptr->size += (ptr->version == 1) ? 32 : 20; | |
| ptr->size += 60; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void traf_box_del(GF_Box *s) | |
| { | |
| GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->sub_samples) gf_list_del(ptr->sub_samples); | |
| gf_list_del(ptr->TrackRuns); | |
| if (ptr->sampleGroups) gf_list_del(ptr->sampleGroups); | |
| if (ptr->sampleGroupsDescription) gf_list_del(ptr->sampleGroupsDescription); | |
| if (ptr->sai_sizes) gf_list_del(ptr->sai_sizes); | |
| if (ptr->sai_offsets) gf_list_del(ptr->sai_offsets); | |
| gf_free(ptr); | |
| } | |
| GF_Err traf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_TFHD: | |
| BOX_FIELD_ASSIGN(tfhd, GF_TrackFragmentHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TRUN: | |
| BOX_FIELD_LIST_ASSIGN(TrackRuns) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SDTP: | |
| BOX_FIELD_ASSIGN(sdtp, GF_SampleDependencyTypeBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TFDT: | |
| BOX_FIELD_ASSIGN(tfdt, GF_TFBaseMediaDecodeTimeBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_RSOT: | |
| BOX_FIELD_ASSIGN(rsot, GF_TFOriginalDurationBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SUBS: | |
| BOX_FIELD_LIST_ASSIGN(sub_samples) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SBGP: | |
| case GF_ISOM_BOX_TYPE_CSGP: | |
| BOX_FIELD_LIST_ASSIGN(sampleGroups) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SGPD: | |
| BOX_FIELD_LIST_ASSIGN(sampleGroupsDescription) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SAIZ: | |
| BOX_FIELD_LIST_ASSIGN(sai_sizes) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SAIO: | |
| BOX_FIELD_LIST_ASSIGN(sai_offsets) | |
| return GF_OK; | |
| //we will throw an error if both PIFF_PSEC and SENC are found. Not such files seen yet | |
| case GF_ISOM_BOX_TYPE_UUID: | |
| if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_PSEC) { | |
| BOX_FIELD_ASSIGN(sample_encryption, GF_SampleEncryptionBox) | |
| if (!is_rem) | |
| ptr->sample_encryption->traf = ptr; | |
| return GF_OK; | |
| } else if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_TFXD) { | |
| BOX_FIELD_ASSIGN(tfxd, GF_MSSTimeExtBox) | |
| return GF_OK; | |
| } else if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_TFRF) { | |
| BOX_FIELD_ASSIGN(tfrf, GF_MSSTimeRefBox) | |
| return GF_OK; | |
| } else { | |
| return GF_OK; | |
| } | |
| case GF_ISOM_BOX_TYPE_SENC: | |
| BOX_FIELD_ASSIGN(sample_encryption, GF_SampleEncryptionBox) | |
| if (!is_rem) | |
| ptr->sample_encryption->traf = ptr; | |
| return GF_OK; | |
| case GF_GPAC_BOX_TYPE_SREF: | |
| case GF_ISOM_BOX_TYPE_CDRF: | |
| BOX_FIELD_ASSIGN(SampleRefs, GF_SampleReferences) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err traf_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s; | |
| GF_Err e = gf_isom_box_array_read(s, bs); | |
| if (e) return e; | |
| if (!ptr->tfhd) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing TrackFragmentHeaderBox \n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *traf_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackFragmentBox, GF_ISOM_BOX_TYPE_TRAF); | |
| tmp->TrackRuns = gf_list_new(); | |
| if (gf_sys_old_arch_compat()) | |
| tmp->no_sdtp_first_flags = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err traf_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err traf_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *) s; | |
| //Header first | |
| gf_isom_check_position(s, (GF_Box *)ptr->tfhd, &pos); | |
| gf_isom_check_position_list(s, ptr->sub_samples, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->tfdt, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->rsot, &pos); | |
| //cmaf-like | |
| if (ptr->truns_first) { | |
| gf_isom_check_position_list(s, ptr->TrackRuns, &pos); | |
| gf_isom_check_position_list(s, ptr->sai_sizes, &pos); | |
| gf_isom_check_position_list(s, ptr->sai_offsets, &pos); | |
| //senc MUST be after saio in GPAC, as senc writing uses info from saio writing | |
| gf_isom_check_position(s, (GF_Box *)ptr->sample_encryption, &pos); | |
| gf_isom_check_position_list(s, ptr->sampleGroupsDescription, &pos); | |
| gf_isom_check_position_list(s, ptr->sampleGroups, &pos); | |
| //subsamples will be last | |
| } else { | |
| gf_isom_check_position_list(s, ptr->sampleGroupsDescription, &pos); | |
| gf_isom_check_position_list(s, ptr->sampleGroups, &pos); | |
| gf_isom_check_position_list(s, ptr->sai_sizes, &pos); | |
| gf_isom_check_position_list(s, ptr->sai_offsets, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->sample_encryption, &pos); | |
| gf_isom_check_position_list(s, ptr->TrackRuns, &pos); | |
| } | |
| //when sdtp is present (smooth-like) write it after the trun box | |
| gf_isom_check_position(s, (GF_Box *)ptr->sdtp, &pos); | |
| //tfxd should be last ... | |
| if (ptr->tfxd) | |
| gf_isom_check_position(s, (GF_Box *)ptr->tfxd, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *tfxd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MSSTimeExtBox, GF_ISOM_BOX_TYPE_UUID); | |
| tmp->internal_4cc = GF_ISOM_BOX_UUID_TFXD; | |
| tmp->version = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| void tfxd_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err tfxd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MSSTimeExtBox *ptr = (GF_MSSTimeExtBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->version = gf_bs_read_u8(bs); | |
| ptr->flags = gf_bs_read_u24(bs); | |
| if (ptr->version == 0x01) { | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| ptr->absolute_time_in_track_timescale = gf_bs_read_u64(bs); | |
| ptr->fragment_duration_in_track_timescale = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->absolute_time_in_track_timescale = gf_bs_read_u32(bs); | |
| ptr->fragment_duration_in_track_timescale = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tfxd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MSSTimeExtBox *ptr = (GF_MSSTimeExtBox*)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->version); | |
| gf_bs_write_u24(bs, 0); | |
| if (ptr->version) { | |
| gf_bs_write_u64(bs, ptr->absolute_time_in_track_timescale); | |
| gf_bs_write_u64(bs, ptr->fragment_duration_in_track_timescale); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->absolute_time_in_track_timescale); | |
| gf_bs_write_u32(bs, (u32) ptr->fragment_duration_in_track_timescale); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err tfxd_box_size(GF_Box *s) | |
| { | |
| GF_MSSTimeExtBox *ptr = (GF_MSSTimeExtBox*)s; | |
| s->size += 4 + (ptr->version ? 16 : 8); | |
| return GF_OK; | |
| } | |
| #endif //GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *tfrf_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MSSTimeRefBox, GF_ISOM_BOX_TYPE_UUID); | |
| tmp->internal_4cc = GF_ISOM_BOX_UUID_TFRF; | |
| return (GF_Box *)tmp; | |
| } | |
| void tfrf_box_del(GF_Box *s) | |
| { | |
| GF_MSSTimeRefBox *ptr = (GF_MSSTimeRefBox *)s; | |
| if (ptr->frags) gf_free(ptr->frags); | |
| gf_free(s); | |
| } | |
| GF_Err tfrf_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_MSSTimeRefBox *ptr = (GF_MSSTimeRefBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 5); | |
| ptr->version = gf_bs_read_u8(bs); | |
| ptr->flags = gf_bs_read_u24(bs); | |
| ptr->frags_count = gf_bs_read_u8(bs); | |
| ptr->frags = gf_malloc(sizeof(GF_MSSTimeEntry) * ptr->frags_count); | |
| if (!ptr->frags) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->frags_count; i++) { | |
| if (ptr->version == 0x01) { | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| ptr->frags[i].absolute_time_in_track_timescale = gf_bs_read_u64(bs); | |
| ptr->frags[i].fragment_duration_in_track_timescale = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->frags[i].absolute_time_in_track_timescale = gf_bs_read_u32(bs); | |
| ptr->frags[i].fragment_duration_in_track_timescale = gf_bs_read_u32(bs); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tfrf_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_MSSTimeRefBox *ptr = (GF_MSSTimeRefBox*)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->version); | |
| gf_bs_write_u24(bs, 0); | |
| gf_bs_write_u8(bs, ptr->frags_count); | |
| for (i=0; i<ptr->frags_count; i++) { | |
| if (ptr->version==0x01) { | |
| gf_bs_write_u64(bs, ptr->frags[i].absolute_time_in_track_timescale); | |
| gf_bs_write_u64(bs, ptr->frags[i].fragment_duration_in_track_timescale); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->frags[i].absolute_time_in_track_timescale); | |
| gf_bs_write_u32(bs, (u32) ptr->frags[i].fragment_duration_in_track_timescale); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err tfrf_box_size(GF_Box *s) | |
| { | |
| GF_MSSTimeRefBox *ptr = (GF_MSSTimeRefBox*)s; | |
| s->size += 5; | |
| if (ptr->version) s->size += 16 * ptr->frags_count; | |
| else s->size += 8 * ptr->frags_count; | |
| return GF_OK; | |
| } | |
| #endif //GPAC_DISABLE_ISOM_WRITE | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| void trak_box_del(GF_Box *s) | |
| { | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_TrackBox *ptr = (GF_TrackBox *)s; | |
| if (ptr->chunk_cache) | |
| gf_bs_del(ptr->chunk_cache); | |
| #endif | |
| gf_free(s); | |
| } | |
| static void stsd_switch_box(GF_BitStream *bs, GF_Box *box, GF_UnknownBox *a, u8 **data, u32 *data_size, u32 *EntryType, GF_SampleDescriptionBox *stsd, u32 stsd_idx) | |
| { | |
| if (gf_bs_available(bs)) { | |
| GF_Err e; | |
| u32 count_subb; | |
| gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_NO_LOGS); | |
| e = gf_isom_box_array_read(box, bs); | |
| count_subb = box->child_boxes ? gf_list_count(box->child_boxes) : 0; | |
| if (count_subb && !e) { | |
| u32 i; | |
| GF_BitStream *new_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); | |
| //serialize all unknown boxes | |
| for (i=0; i<count_subb; i++) { | |
| GF_UnknownBox *priv = gf_list_get(box->child_boxes, i); | |
| if (priv->type != GF_ISOM_BOX_TYPE_UNKNOWN) continue; | |
| gf_bs_write_u32(new_dsi, 8 + priv->dataSize); | |
| gf_bs_write_u32(new_dsi, priv->original_4cc); | |
| gf_bs_write_data(new_dsi, priv->data, priv->dataSize); | |
| gf_list_rem(box->child_boxes, i); | |
| gf_isom_box_del((GF_Box*)priv); | |
| count_subb--; | |
| i--; | |
| } | |
| if (*data) gf_free(*data); | |
| gf_bs_get_content(new_dsi, data, data_size); | |
| gf_bs_del(new_dsi); | |
| } else { | |
| *data_size = 0; | |
| } | |
| } | |
| gf_bs_del(bs); | |
| if (!*data_size && *data) { | |
| gf_free(*data); | |
| *data = NULL; | |
| } | |
| box->size = 0; | |
| *EntryType = a->original_4cc; | |
| gf_list_rem(stsd->child_boxes, stsd_idx); | |
| gf_isom_box_del((GF_Box *)a); | |
| gf_list_insert(stsd->child_boxes, box, stsd_idx); | |
| } | |
| static GF_Err gf_isom_check_sample_desc(GF_TrackBox *trak) | |
| { | |
| GF_BitStream *bs; | |
| GF_UnknownBox *a; | |
| u32 i; | |
| GF_Err e; | |
| GF_SampleTableBox *stbl; | |
| if (!trak->Media || !trak->Media->information) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no media box !\n" )); | |
| return GF_OK; | |
| } | |
| if (!trak->Media->information->sampleTable) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no sample table !\n" )); | |
| trak->Media->information->sampleTable = (GF_SampleTableBox *) gf_isom_box_new_parent(&trak->Media->information->child_boxes, GF_ISOM_BOX_TYPE_STBL); | |
| } | |
| stbl = trak->Media->information->sampleTable; | |
| if (!stbl->SampleDescription) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no sample description box !\n" )); | |
| stbl->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSD); | |
| return GF_OK; | |
| } | |
| i=0; | |
| while ((a = (GF_UnknownBox*)gf_list_enum(stbl->SampleDescription->child_boxes, &i))) { | |
| GF_ProtectionSchemeInfoBox *sinf; | |
| u32 base_ent_type = 0; | |
| u32 type = a->type; | |
| u32 sinf_type = GF_ISOM_BOX_TYPE_SINF; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_RESV: | |
| sinf_type = GF_ISOM_BOX_TYPE_RINF; | |
| case GF_ISOM_BOX_TYPE_ENCS: | |
| case GF_ISOM_BOX_TYPE_ENCA: | |
| case GF_ISOM_BOX_TYPE_ENCV: | |
| case GF_ISOM_BOX_TYPE_ENCT: | |
| sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(a->child_boxes, sinf_type); | |
| if (!sinf || !sinf->original_format) return GF_ISOM_INVALID_FILE; | |
| type = sinf->original_format->data_format; | |
| base_ent_type = ((GF_SampleEntryBox *)a)->internal_type; | |
| break; | |
| } | |
| switch (type) { | |
| case GF_ISOM_BOX_TYPE_MP4S: | |
| if (base_ent_type && (base_ent_type != GF_ISOM_SAMPLE_ENTRY_MP4S)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Protected sample entry %s uses incompatible sample description %s\n", gf_4cc_to_str(a->type), gf_4cc_to_str(type) )); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| continue; | |
| case GF_ISOM_SUBTYPE_3GP_AMR: | |
| case GF_ISOM_SUBTYPE_3GP_AMR_WB: | |
| case GF_ISOM_SUBTYPE_3GP_EVRC: | |
| case GF_ISOM_SUBTYPE_3GP_QCELP: | |
| case GF_ISOM_SUBTYPE_3GP_SMV: | |
| case GF_ISOM_BOX_TYPE_MP4A: | |
| case GF_ISOM_BOX_TYPE_MP3: | |
| case GF_ISOM_BOX_TYPE_MHA1: | |
| case GF_ISOM_BOX_TYPE_MHA2: | |
| case GF_ISOM_BOX_TYPE_MHM1: | |
| case GF_ISOM_BOX_TYPE_MHM2: | |
| case GF_ISOM_BOX_TYPE_OPUS: | |
| case GF_ISOM_BOX_TYPE_AC3: | |
| case GF_ISOM_BOX_TYPE_EC3: | |
| case GF_ISOM_BOX_TYPE_AC4: | |
| case GF_QT_SUBTYPE_RAW_AUD: | |
| case GF_QT_SUBTYPE_TWOS: | |
| case GF_QT_SUBTYPE_SOWT: | |
| case GF_QT_SUBTYPE_FL32: | |
| case GF_QT_SUBTYPE_FL64: | |
| case GF_QT_SUBTYPE_IN24: | |
| case GF_QT_SUBTYPE_IN32: | |
| case GF_QT_SUBTYPE_ULAW: | |
| case GF_QT_SUBTYPE_ALAW: | |
| case GF_QT_SUBTYPE_ADPCM: | |
| case GF_QT_SUBTYPE_IMA_ADPCM: | |
| case GF_QT_SUBTYPE_DVCA: | |
| case GF_QT_SUBTYPE_QDMC: | |
| case GF_QT_SUBTYPE_QDMC2: | |
| case GF_QT_SUBTYPE_QCELP: | |
| case GF_QT_SUBTYPE_kMP3: | |
| case GF_ISOM_BOX_TYPE_IPCM: | |
| case GF_ISOM_BOX_TYPE_FPCM: | |
| if (base_ent_type && (base_ent_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)) | |
| return GF_ISOM_INVALID_FILE; | |
| continue; | |
| case GF_ISOM_BOX_TYPE_MP4V: | |
| case GF_ISOM_SUBTYPE_3GP_H263: | |
| case GF_ISOM_BOX_TYPE_AVC1: | |
| case GF_ISOM_BOX_TYPE_AVC2: | |
| case GF_ISOM_BOX_TYPE_AVC3: | |
| case GF_ISOM_BOX_TYPE_AVC4: | |
| case GF_ISOM_BOX_TYPE_SVC1: | |
| case GF_ISOM_BOX_TYPE_MVC1: | |
| case GF_ISOM_BOX_TYPE_HVC1: | |
| case GF_ISOM_BOX_TYPE_HEV1: | |
| case GF_ISOM_BOX_TYPE_HVC2: | |
| case GF_ISOM_BOX_TYPE_HEV2: | |
| case GF_ISOM_BOX_TYPE_HVT1: | |
| case GF_ISOM_BOX_TYPE_LHV1: | |
| case GF_ISOM_BOX_TYPE_LHE1: | |
| case GF_ISOM_BOX_TYPE_AV01: | |
| case GF_ISOM_BOX_TYPE_VP08: | |
| case GF_ISOM_BOX_TYPE_VP09: | |
| case GF_ISOM_BOX_TYPE_VP10: | |
| case GF_ISOM_BOX_TYPE_AV1C: | |
| case GF_ISOM_BOX_TYPE_AV3C: | |
| case GF_ISOM_BOX_TYPE_AVS3: | |
| case GF_ISOM_BOX_TYPE_JPEG: | |
| case GF_ISOM_BOX_TYPE_PNG: | |
| case GF_ISOM_BOX_TYPE_JP2K: | |
| case GF_ISOM_BOX_TYPE_MJP2: | |
| case GF_QT_SUBTYPE_APCH: | |
| case GF_QT_SUBTYPE_APCO: | |
| case GF_QT_SUBTYPE_APCN: | |
| case GF_QT_SUBTYPE_APCS: | |
| case GF_QT_SUBTYPE_AP4X: | |
| case GF_QT_SUBTYPE_AP4H: | |
| case GF_ISOM_BOX_TYPE_VVC1: | |
| case GF_ISOM_BOX_TYPE_VVI1: | |
| case GF_QT_SUBTYPE_RAW_VID: | |
| case GF_QT_SUBTYPE_YUYV: | |
| case GF_QT_SUBTYPE_UYVY: | |
| case GF_QT_SUBTYPE_YUV444: | |
| case GF_QT_SUBTYPE_YUVA444: | |
| case GF_QT_SUBTYPE_YUV422_10: | |
| case GF_QT_SUBTYPE_YUV444_10: | |
| case GF_QT_SUBTYPE_YUV422_16: | |
| case GF_QT_SUBTYPE_YUV420: | |
| case GF_QT_SUBTYPE_I420: | |
| case GF_QT_SUBTYPE_IYUV: | |
| case GF_QT_SUBTYPE_YV12: | |
| case GF_QT_SUBTYPE_YVYU: | |
| case GF_QT_SUBTYPE_RGBA: | |
| case GF_QT_SUBTYPE_ABGR: | |
| case GF_ISOM_BOX_TYPE_DVHE: | |
| case GF_ISOM_BOX_TYPE_DVH1: | |
| case GF_ISOM_BOX_TYPE_DVA1: | |
| case GF_ISOM_BOX_TYPE_DVAV: | |
| case GF_ISOM_BOX_TYPE_DAV1: | |
| if (base_ent_type && (base_ent_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)) | |
| return GF_ISOM_INVALID_FILE; | |
| continue; | |
| case GF_ISOM_BOX_TYPE_METX: | |
| case GF_ISOM_BOX_TYPE_METT: | |
| case GF_ISOM_BOX_TYPE_STXT: | |
| case GF_ISOM_BOX_TYPE_TX3G: | |
| case GF_ISOM_BOX_TYPE_TEXT: | |
| case GF_ISOM_BOX_TYPE_GHNT: | |
| case GF_ISOM_BOX_TYPE_RTP_STSD: | |
| case GF_ISOM_BOX_TYPE_SRTP_STSD: | |
| case GF_ISOM_BOX_TYPE_FDP_STSD: | |
| case GF_ISOM_BOX_TYPE_RRTP_STSD: | |
| case GF_ISOM_BOX_TYPE_RTCP_STSD: | |
| case GF_ISOM_BOX_TYPE_DIMS: | |
| case GF_ISOM_BOX_TYPE_LSR1: | |
| case GF_ISOM_BOX_TYPE_WVTT: | |
| case GF_ISOM_BOX_TYPE_STPP: | |
| case GF_ISOM_BOX_TYPE_SBTT: | |
| if (base_ent_type && (base_ent_type != GF_ISOM_SAMPLE_ENTRY_GENERIC)) | |
| return GF_ISOM_INVALID_FILE; | |
| continue; | |
| case GF_ISOM_BOX_TYPE_UNKNOWN: | |
| break; | |
| default: | |
| if (gf_box_valid_in_parent((GF_Box *) a, "stsd")) { | |
| continue; | |
| } | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Unexpected box %s in stsd!\n", gf_4cc_to_str(a->type))); | |
| continue; | |
| } | |
| //we are sure to have an unknown box here | |
| if (a->type!=GF_ISOM_BOX_TYPE_UNKNOWN) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Sample description %s not supported\n", gf_4cc_to_str(a->type) )); | |
| continue; | |
| } | |
| if (!a->data || (a->dataSize<8) ) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Sample description %s does not have at least 8 bytes!\n", gf_4cc_to_str(a->original_4cc) )); | |
| continue; | |
| } | |
| else if (a->dataSize > a->size) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Sample description %s has wrong data size %d!\n", gf_4cc_to_str(a->original_4cc), a->dataSize)); | |
| continue; | |
| } | |
| /*only process visual or audio | |
| note: no need for new_box_parent here since we always store sample descriptions in child_boxes*/ | |
| switch (trak->Media->handler->handlerType) { | |
| case GF_ISOM_MEDIA_VISUAL: | |
| case GF_ISOM_MEDIA_AUXV: | |
| case GF_ISOM_MEDIA_PICT: | |
| { | |
| GF_GenericVisualSampleEntryBox *genv = (GF_GenericVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRV); | |
| bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); | |
| genv->size = a->size-8; | |
| e = gnrv_box_read((GF_Box *) genv, bs); | |
| if (e) { | |
| gf_bs_del(bs); | |
| gnrv_box_del((GF_Box *)genv); | |
| return e; | |
| } | |
| stsd_switch_box(bs, (GF_Box *) genv, a, &genv->data, &genv->data_size, &genv->EntryType, trak->Media->information->sampleTable->SampleDescription, i-1); | |
| } | |
| break; | |
| case GF_ISOM_MEDIA_AUDIO: | |
| { | |
| GF_GenericAudioSampleEntryBox *gena = (GF_GenericAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRA); | |
| gena->size = a->size-8; | |
| bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); | |
| e = gnra_box_read((GF_Box *) gena, bs); | |
| if (e) { | |
| gf_bs_del(bs); | |
| gnra_box_del((GF_Box *)gena); | |
| return e; | |
| } | |
| stsd_switch_box(bs, (GF_Box *) gena, a, &gena->data, &gena->data_size, &gena->EntryType, trak->Media->information->sampleTable->SampleDescription, i-1); | |
| } | |
| break; | |
| default: | |
| { | |
| GF_GenericSampleEntryBox *genm = (GF_GenericSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM); | |
| genm->size = a->size-8; | |
| bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); | |
| e = gnrm_box_read((GF_Box *)genm, bs); | |
| if (e) { | |
| gf_bs_del(bs); | |
| gnrm_box_del((GF_Box *)genm); | |
| return e; | |
| } | |
| stsd_switch_box(bs, (GF_Box *) genm, a, &genm->data, &genm->data_size, &genm->EntryType, trak->Media->information->sampleTable->SampleDescription, i-1); | |
| } | |
| break; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err trak_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_TrackBox *ptr = (GF_TrackBox *)s; | |
| if (!a) return GF_OK; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_TKHD: | |
| BOX_FIELD_ASSIGN(Header, GF_TrackHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_EXTL: | |
| BOX_FIELD_ASSIGN(extl, GF_ExternalTrackLocationBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_EDTS: | |
| BOX_FIELD_ASSIGN(editBox, GF_EditBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_UDTA: | |
| BOX_FIELD_ASSIGN(udta, GF_UserDataBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_META: | |
| BOX_FIELD_ASSIGN(meta, GF_MetaBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TREF: | |
| BOX_FIELD_ASSIGN(References, GF_TrackReferenceBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_MDIA: | |
| BOX_FIELD_ASSIGN(Media, GF_MediaBox) | |
| if (!is_rem) | |
| ((GF_MediaBox *)a)->mediaTrack = ptr; | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_TRGR: | |
| BOX_FIELD_ASSIGN(groups, GF_TrackGroupBox) | |
| return GF_OK; | |
| case GF_QT_BOX_TYPE_TAPT: | |
| BOX_FIELD_ASSIGN(Aperture, GF_Box) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SENC: | |
| BOX_FIELD_ASSIGN(sample_encryption, GF_SampleEncryptionBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_UUID: | |
| if (((GF_UnknownUUIDBox *)a)->internal_4cc == GF_ISOM_BOX_UUID_PSEC) { | |
| BOX_FIELD_ASSIGN(sample_encryption, GF_SampleEncryptionBox) | |
| return GF_OK; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err trak_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_TrackBox *ptr = (GF_TrackBox *)s; | |
| e = gf_isom_box_array_read(s, bs); | |
| if (e) return e; | |
| if (!ptr->Header) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing TrackHeaderBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (ptr->extl) return GF_OK; | |
| e = gf_isom_check_sample_desc(ptr); | |
| if (e) return e; | |
| if (!ptr->Media) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MediaBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (!ptr->Media->information || !ptr->Media->information->sampleTable) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid MediaBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (!ptr->Media->information->sampleTable->SampleSize || (ptr->Media->information->sampleTable->SampleSize->sampleCount==0)) { | |
| if (ptr->Header->initial_duration) { | |
| GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Track with no samples but duration defined, ignoring duration\n")); | |
| ptr->Header->initial_duration = 0; | |
| } | |
| } | |
| for (i=0; i<gf_list_count(ptr->Media->information->sampleTable->child_boxes); i++) { | |
| GF_Box *a = gf_list_get(ptr->Media->information->sampleTable->child_boxes, i); | |
| if ((a->type ==GF_ISOM_BOX_TYPE_UUID) && (((GF_UUIDBox *)a)->internal_4cc == GF_ISOM_BOX_UUID_PSEC)) { | |
| ptr->sample_encryption = (struct __sample_encryption_box *) a; | |
| break; | |
| } | |
| else if (a->type == GF_ISOM_BOX_TYPE_SENC) { | |
| ptr->sample_encryption = (struct __sample_encryption_box *)a; | |
| break; | |
| } | |
| } | |
| return e; | |
| } | |
| GF_Box *trak_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackBox, GF_ISOM_BOX_TYPE_TRAK); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trak_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err trak_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_TrackBox *ptr = (GF_TrackBox *)s; | |
| if (ptr->sample_encryption && ptr->sample_encryption->load_needed) { | |
| if (!ptr->moov || !ptr->moov->mov || !ptr->moov->mov->movieFileMap) | |
| return GF_ISOM_INVALID_FILE; | |
| GF_Err e = senc_Parse(ptr->moov->mov->movieFileMap->bs, ptr, NULL, ptr->sample_encryption, 0); | |
| if (e) return e; | |
| } | |
| gf_isom_check_position(s, (GF_Box *)ptr->extl, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->Header, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->Aperture, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->References, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->editBox, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->Media, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->meta, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->groups, &pos); | |
| gf_isom_check_position(s, (GF_Box *)ptr->udta, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stri_box_del(GF_Box *s) | |
| { | |
| GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->attribute_list) gf_free(ptr->attribute_list); | |
| gf_free(ptr); | |
| } | |
| GF_Err stri_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| size_t i; | |
| GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| ptr->switch_group = gf_bs_read_u16(bs); | |
| ptr->alternate_group = gf_bs_read_u16(bs); | |
| ptr->sub_track_id = gf_bs_read_u32(bs); | |
| ptr->attribute_count = ptr->size / 4; | |
| if ((u64)ptr->attribute_count > (u64)SIZE_MAX/sizeof(u32)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in stri\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| GF_SAFE_ALLOC_N(ptr->attribute_list, (size_t)ptr->attribute_count, u32); | |
| if (!ptr->attribute_list) return GF_OUT_OF_MEM; | |
| for (i = 0; i < ptr->attribute_count; i++) { | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->attribute_list[i] = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stri_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SubTrackInformationBox, GF_ISOM_BOX_TYPE_STRI); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stri_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->switch_group); | |
| gf_bs_write_u16(bs, ptr->alternate_group); | |
| gf_bs_write_u32(bs, ptr->sub_track_id); | |
| for (i = 0; i < ptr->attribute_count; i++) { | |
| gf_bs_write_u32(bs, ptr->attribute_list[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stri_box_size(GF_Box *s) | |
| { | |
| GF_SubTrackInformationBox *ptr = (GF_SubTrackInformationBox *)s; | |
| ptr->size += 8 + 4 * ptr->attribute_count; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void stsg_box_del(GF_Box *s) | |
| { | |
| GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->group_description_index) gf_free(ptr->group_description_index); | |
| gf_free(ptr); | |
| } | |
| GF_Err stsg_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s; | |
| ISOM_DECREASE_SIZE(s, 6); | |
| ptr->grouping_type = gf_bs_read_u32(bs); | |
| ptr->nb_groups = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(s, ptr->nb_groups*4); | |
| GF_SAFE_ALLOC_N(ptr->group_description_index, ptr->nb_groups, u32); | |
| if (!ptr->group_description_index) return GF_OUT_OF_MEM; | |
| for (i = 0; i < ptr->nb_groups; i++) { | |
| ptr->group_description_index[i] = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *stsg_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SubTrackSampleGroupBox, GF_ISOM_BOX_TYPE_STSG); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stsg_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->grouping_type); | |
| gf_bs_write_u16(bs, ptr->nb_groups); | |
| for (i = 0; i < ptr->nb_groups; i++) { | |
| gf_bs_write_u32(bs, ptr->group_description_index[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err stsg_box_size(GF_Box *s) | |
| { | |
| GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s; | |
| ptr->size += 6 + 4 * ptr->nb_groups; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void strk_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err strk_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_SubTrackBox *ptr = (GF_SubTrackBox *)s; | |
| if (!a) return GF_OK; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_STRI: | |
| BOX_FIELD_ASSIGN(info, GF_SubTrackInformationBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_STRD: | |
| BOX_FIELD_ASSIGN(strd, GF_Box) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err strk_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SubTrackBox *ptr = (GF_SubTrackBox *)s; | |
| e = gf_isom_box_array_read(s, bs); | |
| if (e) return e; | |
| if (!ptr->info) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing SubTrackInformationBox\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *strk_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SubTrackBox, GF_ISOM_BOX_TYPE_STRK); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err strk_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err strk_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void tref_box_del(GF_Box *s) | |
| { | |
| GF_TrackReferenceBox *ptr = (GF_TrackReferenceBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err tref_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *tref_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackReferenceBox, GF_ISOM_BOX_TYPE_TREF); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tref_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| // GF_TrackReferenceBox *ptr = (GF_TrackReferenceBox *)s; | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err tref_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void reftype_box_del(GF_Box *s) | |
| { | |
| GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s; | |
| if (!ptr) return; | |
| if (ptr->trackIDs) gf_free(ptr->trackIDs); | |
| gf_free(ptr); | |
| } | |
| GF_Err reftype_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 bytesToRead; | |
| u32 i; | |
| GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s; | |
| bytesToRead = (u32) (ptr->size); | |
| if (!bytesToRead) return GF_OK; | |
| ptr->trackIDCount = (u32) (bytesToRead) / sizeof(u32); | |
| ptr->trackIDs = (GF_ISOTrackID *) gf_malloc(ptr->trackIDCount * sizeof(GF_ISOTrackID)); | |
| if (!ptr->trackIDs) return GF_OUT_OF_MEM; | |
| for (i = 0; i < ptr->trackIDCount; i++) { | |
| ptr->trackIDs[i] = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *reftype_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackReferenceTypeBox, GF_ISOM_BOX_TYPE_REFT); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Err reftype_AddRefTrack(GF_TrackReferenceTypeBox *ref, GF_ISOTrackID trackID, u16 *outRefIndex) | |
| { | |
| u32 i; | |
| if (!ref || !trackID) return GF_BAD_PARAM; | |
| if (outRefIndex) *outRefIndex = 0; | |
| //don't add a dep if already here !! | |
| for (i = 0; i < ref->trackIDCount; i++) { | |
| if (ref->trackIDs[i] == trackID) { | |
| if (outRefIndex) *outRefIndex = i+1; | |
| return GF_OK; | |
| } | |
| } | |
| ref->trackIDs = (GF_ISOTrackID *) gf_realloc(ref->trackIDs, (ref->trackIDCount + 1) * sizeof(GF_ISOTrackID) ); | |
| if (!ref->trackIDs) return GF_OUT_OF_MEM; | |
| ref->trackIDs[ref->trackIDCount] = trackID; | |
| ref->trackIDCount++; | |
| if (outRefIndex) *outRefIndex = ref->trackIDCount; | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err reftype_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s; | |
| if (ptr->reference_type == GF_ISOM_BOX_TYPE_UUID) return GF_BAD_PARAM; | |
| ptr->type = ptr->reference_type; | |
| e = gf_isom_box_write_header(s, bs); | |
| ptr->type = GF_ISOM_BOX_TYPE_REFT; | |
| if (e) return e; | |
| for (i = 0; i < ptr->trackIDCount; i++) { | |
| gf_bs_write_u32(bs, ptr->trackIDs[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err reftype_box_size(GF_Box *s) | |
| { | |
| GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s; | |
| if (ptr->trackIDCount) | |
| ptr->size += (ptr->trackIDCount * sizeof(u32)); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void trex_box_del(GF_Box *s) | |
| { | |
| GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err trex_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| ptr->trackID = gf_bs_read_u32(bs); | |
| ptr->def_sample_desc_index = gf_bs_read_u32(bs); | |
| ptr->def_sample_duration = gf_bs_read_u32(bs); | |
| ptr->def_sample_size = gf_bs_read_u32(bs); | |
| ptr->def_sample_flags = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *trex_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackExtendsBox, GF_ISOM_BOX_TYPE_TREX); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trex_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->trackID); | |
| //we always write 1 in trex default sample desc as using 0 breaks chrome/opera/... | |
| gf_bs_write_u32(bs, ptr->def_sample_desc_index ? ptr->def_sample_desc_index : 1); | |
| gf_bs_write_u32(bs, ptr->def_sample_duration); | |
| gf_bs_write_u32(bs, ptr->def_sample_size); | |
| gf_bs_write_u32(bs, ptr->def_sample_flags); | |
| return GF_OK; | |
| } | |
| GF_Err trex_box_size(GF_Box *s) | |
| { | |
| GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s; | |
| ptr->size += 20; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void trep_box_del(GF_Box *s) | |
| { | |
| GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err trep_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->trackID = gf_bs_read_u32(bs); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *trep_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackExtensionPropertiesBox, GF_ISOM_BOX_TYPE_TREP); | |
| tmp->child_boxes = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trep_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->trackID); | |
| return GF_OK; | |
| } | |
| GF_Err trep_box_size(GF_Box *s) | |
| { | |
| GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s; | |
| ptr->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| void trun_box_del(GF_Box *s) | |
| { | |
| GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->samples) gf_free(ptr->samples); | |
| if (ptr->cache) gf_bs_del(ptr->cache); | |
| if (ptr->sample_order) gf_free(ptr->sample_order); | |
| if (ptr->sample_refs) { | |
| while (gf_list_count(ptr->sample_refs)) { | |
| GF_TrafSampleRef *sref = gf_list_pop_back(ptr->sample_refs); | |
| if (!sref->ref) gf_free(sref->data); | |
| gf_free(sref); | |
| } | |
| gf_list_del(ptr->sample_refs); | |
| } | |
| gf_free(ptr); | |
| } | |
| #ifdef GF_ENABLE_CTRN | |
| static u32 ctrn_field_size(u32 field_idx) | |
| { | |
| if (field_idx==3) return 4; | |
| return field_idx; | |
| } | |
| u32 gf_isom_ctrn_field_size_bits(u32 field_idx) | |
| { | |
| if (field_idx==3) return 32; | |
| return field_idx*8; | |
| } | |
| static u32 ctrn_read_flags(GF_BitStream *bs, u32 nbbits) | |
| { | |
| u32 val = gf_bs_read_int(bs, nbbits); | |
| if (nbbits==16) val <<= 16; | |
| else if (nbbits==8) val <<= 24; | |
| return val; | |
| } | |
| static GF_Err ctrn_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, count, flags, first_idx=0; | |
| Bool inherit_dur, inherit_size, inherit_flags, inherit_ctso; | |
| GF_TrunEntry *ent; | |
| GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s; | |
| flags = ptr->flags; | |
| ptr->ctrn_flags = flags; | |
| ptr->flags = 0; | |
| ptr->sample_count = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| if (flags & GF_ISOM_TRUN_DATA_OFFSET) { | |
| if (flags & GF_ISOM_CTRN_DATAOFFSET_16) { | |
| ptr->data_offset = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| } else { | |
| ptr->data_offset = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| } | |
| ptr->flags |= GF_ISOM_TRUN_DATA_OFFSET; | |
| } | |
| if (flags & GF_ISOM_CTRN_CTSO_MULTIPLIER) { | |
| ptr->ctso_multiplier = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| } | |
| /*no sample dur/sample_flag/size/ctso for first or following, create a pack sample */ | |
| if (! (flags & 0x00FFFF00)) { | |
| GF_SAFEALLOC(ent, GF_TrunEntry); | |
| if (!ent) return GF_OUT_OF_MEM; | |
| ent->nb_pack = ptr->sample_count; | |
| gf_list_add(ptr->entries, ent); | |
| return GF_OK; | |
| } | |
| /*allocate all entries*/ | |
| for (i=0; i<ptr->sample_count; i++) { | |
| GF_SAFEALLOC(ent, GF_TrunEntry); | |
| if (!ent) return GF_OUT_OF_MEM; | |
| gf_list_add(ptr->entries, ent); | |
| } | |
| //unpack flags | |
| ptr->ctrn_first_dur = (flags>>22) & 0x3; | |
| ptr->ctrn_first_size = (flags>>20) & 0x3; | |
| ptr->ctrn_first_sample_flags = (flags>>18) & 0x3; | |
| ptr->ctrn_first_ctts = (flags>>16) & 0x3; | |
| ptr->ctrn_dur = (flags>>14) & 0x3; | |
| ptr->ctrn_size = (flags>>12) & 0x3; | |
| ptr->ctrn_sample_flags = (flags>>10) & 0x3; | |
| ptr->ctrn_ctts = (flags>>8) & 0x3; | |
| inherit_dur = flags & GF_ISOM_CTRN_INHERIT_DUR; | |
| inherit_size = flags & GF_ISOM_CTRN_INHERIT_SIZE; | |
| inherit_flags = flags & GF_ISOM_CTRN_INHERIT_FLAGS; | |
| inherit_ctso = flags & GF_ISOM_CTRN_INHERIT_CTSO; | |
| if (flags & GF_ISOM_CTRN_FIRST_SAMPLE) { | |
| ent = gf_list_get(ptr->entries, 0); | |
| first_idx = 1; | |
| if (!inherit_dur && ptr->ctrn_first_dur) { | |
| ent->Duration = gf_bs_read_int(bs, gf_isom_ctrn_field_size_bits(ptr->ctrn_first_dur) ); | |
| ISOM_DECREASE_SIZE(ptr, ctrn_field_size(ptr->ctrn_first_dur) ); | |
| } | |
| if (!inherit_size && ptr->ctrn_first_size) { | |
| ent->size = gf_bs_read_int(bs, gf_isom_ctrn_field_size_bits(ptr->ctrn_first_size) ); | |
| ISOM_DECREASE_SIZE(ptr, ctrn_field_size(ptr->ctrn_first_size) ); | |
| } | |
| if (!inherit_flags && ptr->ctrn_first_sample_flags) { | |
| ent->flags = ctrn_read_flags(bs, gf_isom_ctrn_field_size_bits(ptr->ctrn_first_sample_flags) ); | |
| ISOM_DECREASE_SIZE(ptr, ctrn_field_size(ptr->ctrn_first_sample_flags) ); | |
| } | |
| if (!inherit_ctso && ptr->ctrn_first_ctts) { | |
| ent->CTS_Offset = gf_bs_read_int(bs, gf_isom_ctrn_field_size_bits(ptr->ctrn_first_ctts) ); | |
| ISOM_DECREASE_SIZE(ptr, ctrn_field_size(ptr->ctrn_first_ctts) ); | |
| if (ptr->ctso_multiplier) | |
| ent->CTS_Offset *= (s32) ptr->ctso_multiplier; | |
| } | |
| } | |
| count = ptr->sample_count - first_idx; | |
| if (!inherit_dur && ptr->ctrn_dur) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ptr->ctrn_dur); | |
| ISOM_DECREASE_SIZE(ptr, count * nbbits / 8); | |
| for (i=first_idx; i<ptr->sample_count; i++) { | |
| ent = gf_list_get(ptr->entries, i); | |
| ent->Duration = gf_bs_read_int(bs, nbbits); | |
| } | |
| } | |
| if (!inherit_size && ptr->ctrn_size) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ptr->ctrn_size); | |
| ISOM_DECREASE_SIZE(ptr, count * nbbits / 8); | |
| for (i=first_idx; i<ptr->sample_count; i++) { | |
| ent = gf_list_get(ptr->entries, i); | |
| ent->size = gf_bs_read_int(bs, nbbits); | |
| } | |
| } | |
| if (!inherit_flags && ptr->ctrn_sample_flags) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ptr->ctrn_sample_flags); | |
| ISOM_DECREASE_SIZE(ptr, count * nbbits / 8); | |
| for (i=first_idx; i<ptr->sample_count; i++) { | |
| ent = gf_list_get(ptr->entries, i); | |
| ent->flags = ctrn_read_flags(bs, nbbits); | |
| } | |
| } | |
| if (!inherit_ctso && ptr->ctrn_ctts) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ptr->ctrn_ctts); | |
| ISOM_DECREASE_SIZE(ptr, count * nbbits / 8); | |
| for (i=first_idx; i<ptr->sample_count; i++) { | |
| ent = gf_list_get(ptr->entries, i); | |
| ent->CTS_Offset = gf_bs_read_int(bs, nbbits); | |
| if (ptr->ctso_multiplier) | |
| ent->CTS_Offset *= (s32) ptr->ctso_multiplier; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| GF_Err trun_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s; | |
| #ifdef GF_ENABLE_CTRN | |
| if (ptr->type == GF_ISOM_BOX_TYPE_CTRN) { | |
| ptr->type = GF_ISOM_BOX_TYPE_TRUN; | |
| ptr->use_ctrn = GF_TRUE; | |
| return ctrn_box_read(s, bs); | |
| } | |
| #endif | |
| //check this is a good file | |
| if ((ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) && (ptr->flags & GF_ISOM_TRUN_FLAGS)) | |
| return GF_ISOM_INVALID_FILE; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->sample_count = gf_bs_read_u32(bs); | |
| //The rest depends on the flags | |
| if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->data_offset = gf_bs_read_u32(bs); | |
| } | |
| if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->first_sample_flags = gf_bs_read_u32(bs); | |
| } | |
| if (! (ptr->flags & (GF_ISOM_TRUN_DURATION | GF_ISOM_TRUN_SIZE | GF_ISOM_TRUN_FLAGS | GF_ISOM_TRUN_CTS_OFFSET) ) ) { | |
| ptr->samples = gf_malloc(sizeof(GF_TrunEntry)); | |
| if (!ptr->samples) return GF_OUT_OF_MEM; | |
| //memset to 0 !! | |
| memset(ptr->samples, 0, sizeof(GF_TrunEntry)); | |
| ptr->sample_alloc = ptr->nb_samples = 1; | |
| ptr->samples[0].nb_pack = ptr->sample_count; | |
| } else { | |
| u32 base_size=0; | |
| //check size | |
| if (ptr->flags & GF_ISOM_TRUN_DURATION) base_size+=4; | |
| if (ptr->flags & GF_ISOM_TRUN_SIZE) base_size+=4; | |
| if (ptr->flags & GF_ISOM_TRUN_FLAGS) base_size+=4; | |
| if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) base_size+=4; | |
| if ((u64) ptr->sample_count * base_size > ptr->size) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of samples %u in trun for box size %u\n", ptr->sample_count, ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if ((u64)ptr->sample_count > (u64)SIZE_MAX/sizeof(GF_TrunEntry)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of samples %u in trun\n", ptr->sample_count)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->samples = gf_malloc(sizeof(GF_TrunEntry) * ptr->sample_count); | |
| if (!ptr->samples) return GF_OUT_OF_MEM; | |
| ptr->sample_alloc = ptr->nb_samples = ptr->sample_count; | |
| //memset to 0 upfront | |
| memset(ptr->samples, 0, ptr->sample_count * sizeof(GF_TrunEntry)); | |
| //read each entry (even though nothing may be written) | |
| for (i=0; i<ptr->sample_count; i++) { | |
| u32 trun_size = 0; | |
| GF_TrunEntry *p = &ptr->samples[i]; | |
| if (ptr->flags & GF_ISOM_TRUN_DURATION) { | |
| p->Duration = gf_bs_read_u32(bs); | |
| trun_size += 4; | |
| if (!ptr->min_duration || (ptr->min_duration>p->Duration)) | |
| ptr->min_duration = p->Duration; | |
| } | |
| if (ptr->flags & GF_ISOM_TRUN_SIZE) { | |
| p->size = gf_bs_read_u32(bs); | |
| trun_size += 4; | |
| } | |
| //SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED | |
| if (ptr->flags & GF_ISOM_TRUN_FLAGS) { | |
| p->flags = gf_bs_read_u32(bs); | |
| trun_size += 4; | |
| } | |
| if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) { | |
| if (ptr->version==0) { | |
| p->CTS_Offset = (u32) gf_bs_read_u32(bs); | |
| } else { | |
| p->CTS_Offset = (s32) gf_bs_read_u32(bs); | |
| } | |
| trun_size += 4; | |
| } | |
| ISOM_DECREASE_SIZE(ptr, trun_size); | |
| } | |
| } | |
| /*todo parse sample reorder*/ | |
| if (ptr->size) { | |
| gf_bs_skip_bytes(bs, ptr->size); | |
| ptr->size = 0; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *trun_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackFragmentRunBox, GF_ISOM_BOX_TYPE_TRUN); | |
| //NO FLAGS SET BY DEFAULT | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| #ifdef GF_ENABLE_CTRN | |
| static void ctrn_write_sample_flags(GF_BitStream *bs, u32 flags, u32 field_size) | |
| { | |
| if (!field_size) return; | |
| if (field_size==8) flags = flags>>24; | |
| else if (field_size==16) flags = flags>>16; | |
| gf_bs_write_int(bs, flags, field_size); | |
| } | |
| static void ctrn_write_ctso(GF_TrackFragmentRunBox *ctrn, GF_BitStream *bs, u32 ctso, u32 field_size) | |
| { | |
| if (!field_size) return; | |
| if (ctrn->ctso_multiplier) { | |
| gf_bs_write_int(bs, ctso / ctrn->ctso_multiplier, field_size); | |
| } else { | |
| gf_bs_write_int(bs, ctso, field_size); | |
| } | |
| } | |
| GF_Err ctrn_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i, count, flags; | |
| GF_TrunEntry *ent; | |
| GF_TrackFragmentRunBox *ctrn = (GF_TrackFragmentRunBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| flags = ctrn->flags; | |
| ctrn->flags = ctrn->ctrn_flags; | |
| ctrn->type = GF_ISOM_BOX_TYPE_CTRN; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| ctrn->flags = flags; | |
| ctrn->type = GF_ISOM_BOX_TYPE_TRUN; | |
| gf_bs_write_u16(bs, ctrn->sample_count); | |
| if (ctrn->flags & GF_ISOM_TRUN_DATA_OFFSET) { | |
| if (ctrn->ctrn_flags & GF_ISOM_CTRN_DATAOFFSET_16) { | |
| gf_bs_write_u16(bs, ctrn->data_offset); | |
| } else { | |
| gf_bs_write_u32(bs, ctrn->data_offset); | |
| } | |
| } | |
| if (ctrn->ctso_multiplier) { | |
| gf_bs_write_u16(bs, ctrn->ctso_multiplier); | |
| } | |
| /*we always write first sample using first flags*/ | |
| ent = gf_list_get(ctrn->entries, 0); | |
| gf_bs_write_int(bs, ent->Duration, gf_isom_ctrn_field_size_bits(ctrn->ctrn_first_dur) ); | |
| gf_bs_write_int(bs, ent->size, gf_isom_ctrn_field_size_bits(ctrn->ctrn_first_size) ); | |
| ctrn_write_sample_flags(bs, ent->flags, gf_isom_ctrn_field_size_bits(ctrn->ctrn_first_sample_flags) ); | |
| ctrn_write_ctso(ctrn,bs, ent->CTS_Offset, gf_isom_ctrn_field_size_bits(ctrn->ctrn_first_ctts) ); | |
| count = gf_list_count(ctrn->entries); | |
| if (ctrn->ctrn_dur) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ctrn->ctrn_dur); | |
| for (i=1; i<count; i++) { | |
| GF_TrunEntry *a_ent = gf_list_get(ctrn->entries, i); | |
| gf_bs_write_int(bs, a_ent->Duration, nbbits); | |
| } | |
| } | |
| if (ctrn->ctrn_size) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ctrn->ctrn_size); | |
| for (i=1; i<count; i++) { | |
| GF_TrunEntry *a_ent = gf_list_get(ctrn->entries, i); | |
| gf_bs_write_int(bs, a_ent->size, nbbits); | |
| } | |
| } | |
| if (ctrn->ctrn_sample_flags) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ctrn->ctrn_sample_flags); | |
| for (i=1; i<count; i++) { | |
| GF_TrunEntry *a_ent = gf_list_get(ctrn->entries, i); | |
| ctrn_write_sample_flags(bs, a_ent->flags, nbbits); | |
| } | |
| } | |
| if (ctrn->ctrn_ctts) { | |
| u32 nbbits = gf_isom_ctrn_field_size_bits(ctrn->ctrn_ctts); | |
| for (i=1; i<count; i++) { | |
| GF_TrunEntry *a_ent = gf_list_get(ctrn->entries, i); | |
| ctrn_write_ctso(ctrn, bs, a_ent->CTS_Offset, nbbits); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| GF_Err trun_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| #ifdef GF_ENABLE_CTRN | |
| if (ptr->use_ctrn) | |
| return ctrn_box_write(s, bs); | |
| #endif | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->sample_count); | |
| //The rest depends on the flags | |
| if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) { | |
| gf_bs_write_u32(bs, ptr->data_offset); | |
| } | |
| if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) { | |
| gf_bs_write_u32(bs, ptr->first_sample_flags); | |
| } | |
| if (ptr->flags & (GF_ISOM_TRUN_DURATION | GF_ISOM_TRUN_SIZE | GF_ISOM_TRUN_FLAGS | GF_ISOM_TRUN_CTS_OFFSET) ) { | |
| for (i=0; i<ptr->nb_samples; i++) { | |
| GF_TrunEntry *p = &ptr->samples[i]; | |
| if (ptr->flags & GF_ISOM_TRUN_DURATION) { | |
| gf_bs_write_u32(bs, p->Duration); | |
| } | |
| if (ptr->flags & GF_ISOM_TRUN_SIZE) { | |
| gf_bs_write_u32(bs, p->size); | |
| } | |
| //SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED | |
| if (ptr->flags & GF_ISOM_TRUN_FLAGS) { | |
| gf_bs_write_u32(bs, p->flags); | |
| } | |
| if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) { | |
| if (ptr->version==0) { | |
| gf_bs_write_u32(bs, p->CTS_Offset); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) p->CTS_Offset); | |
| } | |
| } | |
| } | |
| } | |
| if (ptr->sample_order) { | |
| u32 nb_bits = 8; | |
| if (ptr->sample_count>0xFFFFFF) nb_bits = 32; | |
| else if (ptr->sample_count>0xFFFF) nb_bits = 24; | |
| else if (ptr->sample_count>0xFF) nb_bits = 16; | |
| for (i=0; i<ptr->sample_count; i++) { | |
| gf_bs_write_int(bs, ptr->sample_order[i], nb_bits); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #ifdef GF_ENABLE_CTRN | |
| static u32 ctrn_sample_flags_to_index(u32 val) | |
| { | |
| if (!val) return 0; | |
| if (val & 0x0000FFFF) | |
| return 3; | |
| if (val & 0x00FF0000) | |
| return 2; | |
| return 1; | |
| } | |
| static u32 ctrn_u32_to_index(u32 val) | |
| { | |
| if (!val) return 0; | |
| if (val<=255) return 1; | |
| if (val<=65535) return 2; | |
| return 3; | |
| } | |
| static u32 ctrn_s32_to_index(s32 val) | |
| { | |
| if (!val) return 0; | |
| if (ABS(val)<=127) return 1; | |
| if (ABS(val)<=32767) return 2; | |
| return 3; | |
| } | |
| static u32 ctrn_ctts_to_index(GF_TrackFragmentRunBox *ctrn, s32 ctts) | |
| { | |
| if (!(ctrn->flags & GF_ISOM_TRUN_CTS_OFFSET)) | |
| return 0; | |
| if (!ctts) return 0; | |
| if (ctrn->version) { | |
| if (ctrn->ctso_multiplier) return ctrn_s32_to_index(ctts / ctrn->ctso_multiplier); | |
| return ctrn_s32_to_index(ctts); | |
| } | |
| gf_assert(ctts>0); | |
| if (ctrn->ctso_multiplier) return ctrn_u32_to_index((u32)ctts / ctrn->ctso_multiplier); | |
| return ctrn_s32_to_index((u32)ctts); | |
| } | |
| static GF_Err ctrn_box_size(GF_TrackFragmentRunBox *ctrn) | |
| { | |
| Bool use_ctso_multi = GF_TRUE; | |
| u32 i, count; | |
| GF_TrunEntry *ent; | |
| ctrn->ctrn_flags = 0; | |
| ctrn->ctrn_first_dur = ctrn->ctrn_first_size = ctrn->ctrn_first_sample_flags = ctrn->ctrn_first_ctts = 0; | |
| ctrn->ctrn_dur = ctrn->ctrn_size = ctrn->ctrn_sample_flags = ctrn->ctrn_ctts = 0; | |
| ctrn->size += 2; //16 bits for sample count | |
| if (ctrn->flags & GF_ISOM_TRUN_DATA_OFFSET) { | |
| ctrn->ctrn_flags |= GF_ISOM_TRUN_DATA_OFFSET; | |
| if (ABS(ctrn->data_offset) < 32767) { | |
| ctrn->size += 2; | |
| ctrn->ctrn_flags |= GF_ISOM_CTRN_DATAOFFSET_16; | |
| } else | |
| ctrn->size += 4; | |
| } | |
| count = gf_list_count(ctrn->entries); | |
| if (ctrn->ctso_multiplier && (ctrn->flags & GF_ISOM_TRUN_CTS_OFFSET) && (ctrn->ctso_multiplier<=0xFFFF) ) { | |
| for (i=0; i<count; i++) { | |
| GF_TrunEntry *a_ent = gf_list_get(ctrn->entries, i); | |
| if (a_ent->CTS_Offset % ctrn->ctso_multiplier) { | |
| use_ctso_multi = GF_FALSE; | |
| break; | |
| } | |
| } | |
| } else { | |
| use_ctso_multi = GF_FALSE; | |
| } | |
| if (ctrn->use_inherit) { | |
| use_ctso_multi = GF_FALSE; | |
| ctrn->ctrn_flags |= 0xB0; //duration=1,size=0,flags=1,cts=1 << 4 | |
| } | |
| if (use_ctso_multi) { | |
| ctrn->size += 2; | |
| ctrn->ctrn_flags |= GF_ISOM_CTRN_CTSO_MULTIPLIER; | |
| } else { | |
| ctrn->ctso_multiplier = 0; | |
| } | |
| /*we always write first sample using first flags*/ | |
| ent = gf_list_get(ctrn->entries, 0); | |
| ctrn->ctrn_flags |= GF_ISOM_CTRN_FIRST_SAMPLE; | |
| if (!ctrn->use_inherit && (ctrn->flags & GF_ISOM_TRUN_DURATION)) { | |
| ctrn->ctrn_first_dur = ctrn_u32_to_index(ent->Duration); | |
| if (ctrn->ctrn_first_dur) { | |
| ctrn->size += ctrn_field_size(ctrn->ctrn_first_dur); | |
| ctrn->ctrn_flags |= ctrn->ctrn_first_dur<<22; | |
| } | |
| } | |
| if (ctrn->flags & GF_ISOM_TRUN_SIZE) { | |
| ctrn->ctrn_first_size = ctrn_u32_to_index(ent->size); | |
| if (ctrn->ctrn_first_size) { | |
| ctrn->size += ctrn_field_size(ctrn->ctrn_first_size); | |
| ctrn->ctrn_flags |= ctrn->ctrn_first_size<<20; | |
| } | |
| } | |
| if (!ctrn->use_inherit && (ctrn->flags & GF_ISOM_TRUN_FLAGS)) { | |
| ctrn->ctrn_first_sample_flags = ctrn_sample_flags_to_index(ent->flags); | |
| if (ctrn->ctrn_first_sample_flags) { | |
| ctrn->size += ctrn_field_size(ctrn->ctrn_first_sample_flags); | |
| ctrn->ctrn_flags |= ctrn->ctrn_first_sample_flags<<18; | |
| } | |
| } | |
| if (!ctrn->use_inherit && (ctrn->flags & GF_ISOM_TRUN_CTS_OFFSET)) { | |
| ctrn->ctrn_first_ctts = ctrn_ctts_to_index(ctrn, ent->CTS_Offset); | |
| if (ctrn->ctrn_first_ctts) { | |
| ctrn->size += ctrn_field_size(ctrn->ctrn_first_ctts); | |
| ctrn->ctrn_flags |= ctrn->ctrn_first_ctts<<16; | |
| } | |
| } | |
| for (i=1; i<count; i++) { | |
| u8 field_idx; | |
| GF_TrunEntry *a_ent = gf_list_get(ctrn->entries, i); | |
| if (!ctrn->use_inherit && (ctrn->flags & GF_ISOM_TRUN_DURATION)) { | |
| field_idx = ctrn_u32_to_index(a_ent->Duration); | |
| if (ctrn->ctrn_dur < field_idx) | |
| ctrn->ctrn_dur = field_idx; | |
| } | |
| if (ctrn->flags & GF_ISOM_TRUN_SIZE) { | |
| field_idx = ctrn_u32_to_index(a_ent->size); | |
| if (ctrn->ctrn_size < field_idx) | |
| ctrn->ctrn_size = field_idx; | |
| } | |
| if (!ctrn->use_inherit && (ctrn->flags & GF_ISOM_TRUN_FLAGS)) { | |
| field_idx = ctrn_sample_flags_to_index(a_ent->flags); | |
| if (ctrn->ctrn_sample_flags < field_idx) | |
| ctrn->ctrn_sample_flags = field_idx; | |
| } | |
| if (!ctrn->use_inherit) { | |
| field_idx = ctrn_ctts_to_index(ctrn, a_ent->CTS_Offset); | |
| if (ctrn->ctrn_ctts < field_idx) | |
| ctrn->ctrn_ctts = field_idx; | |
| } | |
| } | |
| count-=1; | |
| if (ctrn->ctrn_dur) { | |
| ctrn->size += count * ctrn_field_size(ctrn->ctrn_dur); | |
| ctrn->ctrn_flags |= ctrn->ctrn_dur<<14; | |
| } | |
| if (ctrn->ctrn_size) { | |
| ctrn->size += count * ctrn_field_size(ctrn->ctrn_size); | |
| ctrn->ctrn_flags |= ctrn->ctrn_size<<12; | |
| } | |
| if (ctrn->ctrn_sample_flags) { | |
| ctrn->size += count * ctrn_field_size(ctrn->ctrn_sample_flags); | |
| ctrn->ctrn_flags |= ctrn->ctrn_sample_flags<<10; | |
| } | |
| if (ctrn->ctrn_ctts) { | |
| ctrn->size += count * ctrn_field_size(ctrn->ctrn_ctts); | |
| ctrn->ctrn_flags |= ctrn->ctrn_ctts<<8; | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| GF_Err trun_box_size(GF_Box *s) | |
| { | |
| GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s; | |
| #ifdef GF_ENABLE_CTRN | |
| if (ptr->use_ctrn) | |
| return ctrn_box_size(ptr); | |
| #endif | |
| ptr->size += 4; | |
| //The rest depends on the flags | |
| if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) ptr->size += 4; | |
| if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) ptr->size += 4; | |
| if (ptr->sample_order) { | |
| u32 nb_bytes = 1; | |
| if (ptr->sample_count>0xFFFFFF) nb_bytes = 4; | |
| else if (ptr->sample_count>0xFFFF) nb_bytes = 3; | |
| else if (ptr->sample_count>0xFF) nb_bytes = 2; | |
| ptr->size += ptr->sample_count*nb_bytes; | |
| } | |
| if (! (ptr->flags & (GF_ISOM_TRUN_DURATION | GF_ISOM_TRUN_SIZE | GF_ISOM_TRUN_FLAGS | GF_ISOM_TRUN_CTS_OFFSET) ) ) { | |
| return GF_OK; | |
| } | |
| //if nothing to do, this will be skipped automatically | |
| if (ptr->flags & GF_ISOM_TRUN_DURATION) ptr->size += 4*ptr->nb_samples; | |
| if (ptr->flags & GF_ISOM_TRUN_SIZE) ptr->size += 4*ptr->nb_samples; | |
| //SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED | |
| if (ptr->flags & GF_ISOM_TRUN_FLAGS) ptr->size += 4*ptr->nb_samples; | |
| if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) ptr->size += 4*ptr->nb_samples; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| void tsro_box_del(GF_Box *s) | |
| { | |
| GF_TimeOffHintEntryBox *tsro = (GF_TimeOffHintEntryBox *)s; | |
| gf_free(tsro); | |
| } | |
| GF_Err tsro_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TimeOffHintEntryBox *ptr = (GF_TimeOffHintEntryBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->TimeOffset = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *tsro_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TimeOffHintEntryBox, GF_ISOM_BOX_TYPE_TSRO); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tsro_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TimeOffHintEntryBox *ptr = (GF_TimeOffHintEntryBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->TimeOffset); | |
| return GF_OK; | |
| } | |
| GF_Err tsro_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void udta_box_del(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_UserDataMap *map; | |
| GF_UserDataBox *ptr = (GF_UserDataBox *)s; | |
| if (ptr == NULL) return; | |
| i=0; | |
| while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) { | |
| gf_isom_box_array_del(map->boxes); | |
| gf_free(map); | |
| } | |
| gf_list_del(ptr->recordList); | |
| gf_free(ptr); | |
| } | |
| GF_UserDataMap *udta_getEntry(GF_UserDataBox *ptr, u32 box_type, bin128 *uuid) | |
| { | |
| u32 i; | |
| GF_UserDataMap *map; | |
| if (ptr == NULL) return NULL; | |
| i=0; | |
| while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) { | |
| if (map->boxType == box_type) { | |
| if ((box_type != GF_ISOM_BOX_TYPE_UUID) || !uuid) return map; | |
| if (!memcmp(map->uuid, *uuid, 16)) return map; | |
| } | |
| } | |
| return NULL; | |
| } | |
| GF_Err udta_on_child_box_ex(GF_Box *s, GF_Box *a, Bool is_rem, Bool rem_same_type) | |
| { | |
| GF_Err e; | |
| u32 box_type; | |
| GF_UserDataMap *map; | |
| GF_UserDataBox *ptr = (GF_UserDataBox *)s; | |
| if (!ptr) return GF_BAD_PARAM; | |
| if (!a) return GF_OK; | |
| //detach from parent list if any | |
| gf_list_del_item(ptr->child_boxes, a); | |
| /* for unknown udta boxes, we reference them by their original box type */ | |
| box_type = a->type; | |
| if (box_type == GF_ISOM_BOX_TYPE_UNKNOWN) { | |
| GF_UnknownBox* unkn = (GF_UnknownBox *)a; | |
| box_type = unkn->original_4cc; | |
| } | |
| map = udta_getEntry(ptr, box_type, (a->type==GF_ISOM_BOX_TYPE_UUID) ? & ((GF_UUIDBox *)a)->uuid : NULL); | |
| if (map == NULL) { | |
| if (is_rem) return GF_OK; | |
| map = (GF_UserDataMap *) gf_malloc(sizeof(GF_UserDataMap)); | |
| if (map == NULL) return GF_OUT_OF_MEM; | |
| memset(map, 0, sizeof(GF_UserDataMap)); | |
| map->boxType = box_type; | |
| if (a->type == GF_ISOM_BOX_TYPE_UUID) | |
| memcpy(map->uuid, ((GF_UUIDBox *)a)->uuid, 16); | |
| map->boxes = gf_list_new(); | |
| if (!map->boxes) { | |
| gf_free(map); | |
| return GF_OUT_OF_MEM; | |
| } | |
| e = gf_list_add(ptr->recordList, map); | |
| if (e) return e; | |
| } | |
| if (is_rem) { | |
| gf_list_del_item(map->boxes, a); | |
| return GF_OK; | |
| } | |
| if (rem_same_type) { | |
| u32 i, count = gf_list_count(map->boxes); | |
| for (i=0; i<count; i++) { | |
| GF_Box *b = gf_list_get(map->boxes, i); | |
| u32 btype = b->type; | |
| if (b->type==GF_ISOM_BOX_TYPE_UNKNOWN) btype = ((GF_UnknownBox*)b)->original_4cc; | |
| if (btype != box_type) continue; | |
| if (box_type == GF_ISOM_BOX_TYPE_UUID) { | |
| if (memcmp( ((GF_UUIDBox *)a)->uuid, ((GF_UUIDBox *)b)->uuid, 16)) continue; | |
| } | |
| gf_isom_box_del(b); | |
| gf_list_rem(map->boxes, i); | |
| break; | |
| } | |
| } | |
| return gf_list_add(map->boxes, a); | |
| } | |
| GF_Err udta_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| return udta_on_child_box_ex(s, a, is_rem, GF_FALSE); | |
| } | |
| GF_Err udta_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e = gf_isom_box_array_read(s, bs); | |
| if (e) return e; | |
| if (s->size==4) { | |
| u32 val = gf_bs_read_u32(bs); | |
| s->size = 0; | |
| if (val) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] udta has 4 remaining bytes set to %08X but they should be 0\n", val)); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *udta_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_UserDataBox, GF_ISOM_BOX_TYPE_UDTA); | |
| tmp->recordList = gf_list_new(); | |
| if (!tmp->recordList) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err udta_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_UserDataMap *map; | |
| GF_UserDataBox *ptr = (GF_UserDataBox *)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| i=0; | |
| while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) { | |
| //warning: here we are not passing the actual "parent" of the list | |
| //but the UDTA box. The parent itself is not an box, we don't care about it | |
| e = gf_isom_box_array_write(s, map->boxes, bs); | |
| if (e) return e; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err udta_box_size(GF_Box *s) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_UserDataMap *map; | |
| GF_UserDataBox *ptr = (GF_UserDataBox *)s; | |
| i=0; | |
| while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) { | |
| //warning: here we are not passing the actual "parent" of the list | |
| //but the UDTA box. The parent itself is not an box, we don't care about it | |
| e = gf_isom_box_array_size(s, map->boxes); | |
| if (e) return e; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void vmhd_box_del(GF_Box *s) | |
| { | |
| GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err vmhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->reserved = gf_bs_read_u64(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *vmhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_VideoMediaHeaderBox, GF_ISOM_BOX_TYPE_VMHD); | |
| tmp->flags = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err vmhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u64(bs, ptr->reserved); | |
| return GF_OK; | |
| } | |
| GF_Err vmhd_box_size(GF_Box *s) | |
| { | |
| GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s; | |
| ptr->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void void_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err void_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| if (s->size) return GF_ISOM_INVALID_FILE; | |
| return GF_OK; | |
| } | |
| GF_Box *void_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Box, GF_ISOM_BOX_TYPE_VOID); | |
| return tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err void_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| gf_bs_write_u32(bs, 0); | |
| return GF_OK; | |
| } | |
| GF_Err void_box_size(GF_Box *s) | |
| { | |
| s->size = 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *pdin_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ProgressiveDownloadBox, GF_ISOM_BOX_TYPE_PDIN); | |
| return (GF_Box *)tmp; | |
| } | |
| void pdin_box_del(GF_Box *s) | |
| { | |
| GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox*)s; | |
| if (ptr == NULL) return; | |
| if (ptr->rates) gf_free(ptr->rates); | |
| if (ptr->times) gf_free(ptr->times); | |
| gf_free(ptr); | |
| } | |
| GF_Err pdin_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox*)s; | |
| ptr->count = (u32) (ptr->size) / 8; | |
| ptr->rates = (u32*)gf_malloc(sizeof(u32)*ptr->count); | |
| if (!ptr->rates) return GF_OUT_OF_MEM; | |
| ptr->times = (u32*)gf_malloc(sizeof(u32)*ptr->count); | |
| if (!ptr->times) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->count; i++) { | |
| ptr->rates[i] = gf_bs_read_u32(bs); | |
| ptr->times[i] = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err pdin_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| for (i=0; i<ptr->count; i++) { | |
| gf_bs_write_u32(bs, ptr->rates[i]); | |
| gf_bs_write_u32(bs, ptr->times[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err pdin_box_size(GF_Box *s) | |
| { | |
| GF_ProgressiveDownloadBox *ptr = (GF_ProgressiveDownloadBox *)s; | |
| ptr->size += 8*ptr->count; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *sdtp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleDependencyTypeBox, GF_ISOM_BOX_TYPE_SDTP); | |
| return (GF_Box *)tmp; | |
| } | |
| void sdtp_box_del(GF_Box *s) | |
| { | |
| GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox*)s; | |
| if (ptr == NULL) return; | |
| if (ptr->sample_info) gf_free(ptr->sample_info); | |
| gf_free(ptr); | |
| } | |
| GF_Err sdtp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox*)s; | |
| /*out-of-order sdtp, assume no padding at the end*/ | |
| if (!ptr->sampleCount) ptr->sampleCount = (u32) ptr->size; | |
| else if (ptr->sampleCount > (u32) ptr->size) return GF_ISOM_INVALID_FILE; | |
| ptr->sample_info = (u8 *) gf_malloc(sizeof(u8)*ptr->sampleCount); | |
| if (!ptr->sample_info) return GF_OUT_OF_MEM; | |
| ptr->sample_alloc = ptr->sampleCount; | |
| gf_bs_read_data(bs, (char*)ptr->sample_info, ptr->sampleCount); | |
| ISOM_DECREASE_SIZE(ptr, ptr->sampleCount); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err sdtp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_data(bs, (char*)ptr->sample_info, ptr->sampleCount); | |
| return GF_OK; | |
| } | |
| GF_Err sdtp_box_size(GF_Box *s) | |
| { | |
| GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox *)s; | |
| ptr->size += ptr->sampleCount; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *pasp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PixelAspectRatioBox, GF_ISOM_BOX_TYPE_PASP); | |
| return (GF_Box *)tmp; | |
| } | |
| void pasp_box_del(GF_Box *s) | |
| { | |
| GF_PixelAspectRatioBox *ptr = (GF_PixelAspectRatioBox*)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err pasp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_PixelAspectRatioBox *ptr = (GF_PixelAspectRatioBox*)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->hSpacing = gf_bs_read_u32(bs); | |
| ptr->vSpacing = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err pasp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_PixelAspectRatioBox *ptr = (GF_PixelAspectRatioBox *)s; | |
| GF_Err e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->hSpacing); | |
| gf_bs_write_u32(bs, ptr->vSpacing); | |
| return GF_OK; | |
| } | |
| GF_Err pasp_box_size(GF_Box *s) | |
| { | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *clap_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_CleanApertureBox, GF_ISOM_BOX_TYPE_CLAP); | |
| return (GF_Box *)tmp; | |
| } | |
| void clap_box_del(GF_Box *s) | |
| { | |
| GF_CleanApertureBox *ptr = (GF_CleanApertureBox*)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err clap_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_CleanApertureBox *ptr = (GF_CleanApertureBox*)s; | |
| ISOM_DECREASE_SIZE(ptr, 32); | |
| ptr->cleanApertureWidthN = gf_bs_read_u32(bs); | |
| ptr->cleanApertureWidthD = gf_bs_read_u32(bs); | |
| ptr->cleanApertureHeightN = gf_bs_read_u32(bs); | |
| ptr->cleanApertureHeightD = gf_bs_read_u32(bs); | |
| ptr->horizOffN = (s32) gf_bs_read_u32(bs); | |
| ptr->horizOffD = gf_bs_read_u32(bs); | |
| ptr->vertOffN = (s32) gf_bs_read_u32(bs); | |
| ptr->vertOffD = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err clap_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_CleanApertureBox *ptr = (GF_CleanApertureBox *)s; | |
| GF_Err e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->cleanApertureWidthN); | |
| gf_bs_write_u32(bs, ptr->cleanApertureWidthD); | |
| gf_bs_write_u32(bs, ptr->cleanApertureHeightN); | |
| gf_bs_write_u32(bs, ptr->cleanApertureHeightD); | |
| gf_bs_write_u32(bs, (u32) ptr->horizOffN); | |
| gf_bs_write_u32(bs, ptr->horizOffD); | |
| gf_bs_write_u32(bs, (u32) ptr->vertOffN); | |
| gf_bs_write_u32(bs, ptr->vertOffD); | |
| return GF_OK; | |
| } | |
| GF_Err clap_box_size(GF_Box *s) | |
| { | |
| s->size += 32; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *metx_box_new() | |
| { | |
| //type is overridden by the box constructor | |
| ISOM_DECL_BOX_ALLOC(GF_MetaDataSampleEntryBox, GF_ISOM_BOX_TYPE_METX); | |
| gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| void metx_box_del(GF_Box *s) | |
| { | |
| GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox*)s; | |
| if (ptr == NULL) return; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); | |
| if (ptr->content_encoding) gf_free(ptr->content_encoding); | |
| if (ptr->xml_namespace) gf_free(ptr->xml_namespace); | |
| if (ptr->xml_schema_loc) gf_free(ptr->xml_schema_loc); | |
| if (ptr->mime_type) gf_free(ptr->mime_type); | |
| gf_free(ptr); | |
| } | |
| GF_Err metx_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_TXTC: | |
| //we allow the config box on metx | |
| BOX_FIELD_ASSIGN(config, GF_TextConfigBox) | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err metx_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 size, i; | |
| GF_Err e; | |
| char *str; | |
| GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox*)s; | |
| e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| if (ptr->size > (u64)SIZE_MAX) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size "LLU" in metx\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| size = (u32) ptr->size; | |
| str = gf_malloc(sizeof(char)*size); | |
| if (!str) return GF_OUT_OF_MEM; | |
| i=0; | |
| while (size) { | |
| str[i] = gf_bs_read_u8(bs); | |
| size--; | |
| if (!str[i]) { | |
| i++; | |
| break; | |
| } | |
| i++; | |
| } | |
| if (!size && i>1 && str[i-1]) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] metx read invalid string\n")); | |
| gf_free(str); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (i>1) { | |
| if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { | |
| ptr->xml_namespace = gf_strdup(str); | |
| } else { | |
| ptr->content_encoding = gf_strdup(str); | |
| } | |
| } | |
| i=0; | |
| while (size) { | |
| str[i] = gf_bs_read_u8(bs); | |
| size--; | |
| if (!str[i]) { | |
| i++; | |
| break; | |
| } | |
| i++; | |
| } | |
| if (!size && i>1 && str[i-1]) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] metx read invalid string\n")); | |
| gf_free(str); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) { | |
| if (i>1) { | |
| if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { | |
| ptr->xml_schema_loc = gf_strdup(str); | |
| } else { | |
| ptr->xml_namespace = gf_strdup(str); | |
| } | |
| } | |
| i=0; | |
| while (size) { | |
| str[i] = gf_bs_read_u8(bs); | |
| size--; | |
| if (!str[i]) { | |
| i++; | |
| break; | |
| } | |
| i++; | |
| } | |
| if (!size && i>1 && str[i-1]) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] metx read invalid string\n")); | |
| gf_free(str); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if (i>1) { | |
| if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { | |
| ptr->mime_type = gf_strdup(str); | |
| } else { | |
| ptr->xml_schema_loc = gf_strdup(str); | |
| } | |
| } | |
| } | |
| //mett, sbtt, stxt, stpp | |
| else { | |
| if (i>1) ptr->mime_type = gf_strdup(str); | |
| } | |
| ptr->size = size; | |
| gf_free(str); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err metx_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s; | |
| GF_Err 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); | |
| if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) { | |
| if (ptr->content_encoding) | |
| gf_bs_write_data(bs, ptr->content_encoding, (u32) strlen(ptr->content_encoding)); | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) { | |
| if (ptr->xml_namespace) | |
| gf_bs_write_data(bs, ptr->xml_namespace, (u32) strlen(ptr->xml_namespace)); | |
| gf_bs_write_u8(bs, 0); | |
| if (ptr->xml_schema_loc) | |
| gf_bs_write_data(bs, ptr->xml_schema_loc, (u32) strlen(ptr->xml_schema_loc)); | |
| gf_bs_write_u8(bs, 0); | |
| if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { | |
| if (ptr->mime_type) | |
| gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type)); | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| } | |
| //mett, sbtt, stxt | |
| else { | |
| if (ptr->mime_type) | |
| gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type)); | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err metx_box_size(GF_Box *s) | |
| { | |
| GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s; | |
| ptr->size += 8; | |
| if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) { | |
| if (ptr->content_encoding) | |
| ptr->size += strlen(ptr->content_encoding); | |
| ptr->size++; | |
| } | |
| if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) { | |
| if (ptr->xml_namespace) | |
| ptr->size += strlen(ptr->xml_namespace); | |
| ptr->size++; | |
| if (ptr->xml_schema_loc) | |
| ptr->size += strlen(ptr->xml_schema_loc); | |
| ptr->size++; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { | |
| if (ptr->mime_type) | |
| ptr->size += strlen(ptr->mime_type); | |
| ptr->size++; | |
| } | |
| } | |
| //mett, sbtt, stxt | |
| else { | |
| if (ptr->mime_type) | |
| ptr->size += strlen(ptr->mime_type); | |
| ptr->size++; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /* SimpleTextSampleEntry */ | |
| GF_Box *txtc_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TextConfigBox, GF_ISOM_BOX_TYPE_TXTC); | |
| return (GF_Box *)tmp; | |
| } | |
| void txtc_box_del(GF_Box *s) | |
| { | |
| GF_TextConfigBox *ptr = (GF_TextConfigBox*)s; | |
| if (ptr == NULL) return; | |
| if (ptr->config) gf_free(ptr->config); | |
| gf_free(ptr); | |
| } | |
| GF_Err txtc_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TextConfigBox *ptr = (GF_TextConfigBox*)s; | |
| if ((u32)ptr->size >= (u32)0xFFFFFFFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in txtc box\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->config = (char *)gf_malloc(sizeof(char)*((u32) ptr->size+1)); | |
| if (!ptr->config) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->config, (u32) ptr->size); | |
| ptr->config[ptr->size] = 0; | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err txtc_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TextConfigBox *ptr = (GF_TextConfigBox *)s; | |
| GF_Err e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->config) | |
| gf_bs_write_data(bs, ptr->config, (u32) strlen(ptr->config)); | |
| gf_bs_write_u8(bs, 0); | |
| return GF_OK; | |
| } | |
| GF_Err txtc_box_size(GF_Box *s) | |
| { | |
| GF_TextConfigBox *ptr = (GF_TextConfigBox *)s; | |
| if (ptr->config) | |
| ptr->size += strlen(ptr->config); | |
| ptr->size++; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *dac3_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_AC3ConfigBox, GF_ISOM_BOX_TYPE_DAC3); | |
| return (GF_Box *)tmp; | |
| } | |
| GF_Box *dec3_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_AC3ConfigBox, GF_ISOM_BOX_TYPE_DAC3); | |
| tmp->cfg.is_ec3 = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| void dac3_box_del(GF_Box *s) | |
| { | |
| GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s; | |
| gf_free(ptr); | |
| } | |
| GF_Err dac3_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u64 pos; | |
| GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| pos = gf_bs_get_position(bs); | |
| e = gf_odf_ac3_cfg_parse_bs(bs, ptr->cfg.is_ec3, &ptr->cfg); | |
| if (e) return e; | |
| pos = gf_bs_get_position(bs) - pos; | |
| ISOM_DECREASE_SIZE(ptr, pos); | |
| if (ptr->size>=2) { | |
| ptr->size-=2; | |
| gf_bs_read_int(bs, 7); | |
| ptr->cfg.atmos_ec3_ext = gf_bs_read_int(bs, 1); | |
| ptr->cfg.complexity_index_type = gf_bs_read_u8(bs); | |
| } | |
| //the rest is reserved | |
| gf_bs_skip_bytes(bs, ptr->size); | |
| ptr->size = 0; | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dac3_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s; | |
| if (ptr->cfg.is_ec3) s->type = GF_ISOM_BOX_TYPE_DEC3; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (ptr->cfg.is_ec3) s->type = GF_ISOM_BOX_TYPE_DAC3; | |
| if (e) return e; | |
| e = gf_odf_ac3_cfg_write_bs(&ptr->cfg, bs); | |
| if (e) return e; | |
| if (ptr->cfg.atmos_ec3_ext || ptr->cfg.complexity_index_type) { | |
| gf_bs_write_int(bs, 0, 7); | |
| gf_bs_write_int(bs, ptr->cfg.atmos_ec3_ext, 1); | |
| gf_bs_write_u8(bs, ptr->cfg.complexity_index_type); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err dac3_box_size(GF_Box *s) | |
| { | |
| GF_AC3ConfigBox *ptr = (GF_AC3ConfigBox *)s; | |
| if (ptr->cfg.is_ec3) { | |
| u32 i; | |
| s->size += 2; | |
| for (i=0; i<ptr->cfg.nb_streams; i++) { | |
| s->size += 3; | |
| if (ptr->cfg.streams[i].nb_dep_sub) | |
| s->size += 1; | |
| } | |
| } else { | |
| s->size += 3; | |
| } | |
| if (ptr->cfg.atmos_ec3_ext || ptr->cfg.complexity_index_type) { | |
| s->size += 2; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *dac4_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_AC4ConfigBox, GF_ISOM_BOX_TYPE_DAC3); | |
| return (GF_Box *)tmp; | |
| } | |
| void dac4_box_del(GF_Box *s) | |
| { | |
| GF_AC4ConfigBox *ptr = (GF_AC4ConfigBox *)s; | |
| gf_odf_ac4_cfg_clean_list(&ptr->cfg); | |
| gf_free(ptr); | |
| } | |
| GF_Err dac4_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u64 pos; | |
| GF_AC4ConfigBox *ptr = (GF_AC4ConfigBox *)s; | |
| if (ptr == NULL) return GF_BAD_PARAM; | |
| pos = gf_bs_get_position(bs); | |
| e = gf_odf_ac4_cfg_parse_bs(bs, &ptr->cfg); | |
| if (e) return e; | |
| pos = gf_bs_get_position(bs) - pos; | |
| ISOM_DECREASE_SIZE(ptr, pos); | |
| //the rest is reserved | |
| gf_bs_skip_bytes(bs, ptr->size); | |
| ptr->size = 0; | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dac4_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_AC4ConfigBox *ptr = (GF_AC4ConfigBox *)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| e = gf_odf_ac4_cfg_write_bs(&ptr->cfg, bs); | |
| if (e) return e; | |
| return GF_OK; | |
| } | |
| GF_Err dac4_box_size(GF_Box *s) | |
| { | |
| GF_AC4ConfigBox *ptr = (GF_AC4ConfigBox *)s; | |
| s->size += gf_odf_ac4_cfg_size(&ptr->cfg); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void lsrc_box_del(GF_Box *s) | |
| { | |
| GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->hdr) gf_free(ptr->hdr); | |
| gf_free(ptr); | |
| } | |
| GF_Err lsrc_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s; | |
| ptr->hdr_size = (u32) ptr->size; | |
| ptr->hdr = gf_malloc(sizeof(char)*ptr->hdr_size); | |
| if (!ptr->hdr) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->hdr, ptr->hdr_size); | |
| return GF_OK; | |
| } | |
| GF_Box *lsrc_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_LASERConfigurationBox, GF_ISOM_BOX_TYPE_LSRC); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err lsrc_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_data(bs, ptr->hdr, ptr->hdr_size); | |
| return GF_OK; | |
| } | |
| GF_Err lsrc_box_size(GF_Box *s) | |
| { | |
| GF_LASERConfigurationBox *ptr = (GF_LASERConfigurationBox *)s; | |
| ptr->size += ptr->hdr_size; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void lsr1_box_del(GF_Box *s) | |
| { | |
| GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s; | |
| if (ptr == NULL) return; | |
| gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); | |
| if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc); | |
| gf_free(ptr); | |
| } | |
| GF_Err lsr1_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s; | |
| switch (a->type) { | |
| case GF_ISOM_BOX_TYPE_LSRC: | |
| BOX_FIELD_ASSIGN(lsr_config, GF_LASERConfigurationBox) | |
| break; | |
| case GF_ISOM_BOX_TYPE_M4DS: | |
| BOX_FIELD_ASSIGN(descr, GF_MPEG4ExtensionDescriptorsBox) | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err lsr1_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox*)s; | |
| e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *lsr1_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_LASeRSampleEntryBox, GF_ISOM_BOX_TYPE_LSR1); | |
| gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err lsr1_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)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); | |
| return GF_OK; | |
| } | |
| GF_Err lsr1_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s; | |
| s->size += 8; | |
| gf_isom_check_position(s, (GF_Box *)ptr->lsr_config, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void sidx_box_del(GF_Box *s) | |
| { | |
| GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->refs) gf_free(ptr->refs); | |
| gf_free(ptr); | |
| } | |
| GF_Err sidx_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->reference_ID = gf_bs_read_u32(bs); | |
| ptr->timescale = gf_bs_read_u32(bs); | |
| if (ptr->version==0) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->earliest_presentation_time = gf_bs_read_u32(bs); | |
| ptr->first_offset = gf_bs_read_u32(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| ptr->earliest_presentation_time = gf_bs_read_u64(bs); | |
| ptr->first_offset = gf_bs_read_u64(bs); | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| gf_bs_read_u16(bs); /* reserved */ | |
| ptr->nb_refs = gf_bs_read_u16(bs); | |
| if ((u64)ptr->nb_refs > ptr->size / 12 || (u64)ptr->nb_refs > (u64)SIZE_MAX / sizeof(GF_SIDXReference)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of references %u in sidx\n", ptr->nb_refs)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->refs = gf_malloc(sizeof(GF_SIDXReference)*ptr->nb_refs); | |
| if (!ptr->refs) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->nb_refs; i++) { | |
| ptr->refs[i].reference_type = gf_bs_read_int(bs, 1); | |
| ptr->refs[i].reference_size = gf_bs_read_int(bs, 31); | |
| ptr->refs[i].subsegment_duration = gf_bs_read_u32(bs); | |
| ptr->refs[i].starts_with_SAP = gf_bs_read_int(bs, 1); | |
| ptr->refs[i].SAP_type = gf_bs_read_int(bs, 3); | |
| ptr->refs[i].SAP_delta_time = gf_bs_read_int(bs, 28); | |
| ISOM_DECREASE_SIZE(ptr, 12); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *sidx_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SegmentIndexBox, GF_ISOM_BOX_TYPE_SIDX); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err sidx_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->reference_ID); | |
| gf_bs_write_u32(bs, ptr->timescale); | |
| if (ptr->version==0) { | |
| gf_bs_write_u32(bs, (u32) ptr->earliest_presentation_time); | |
| gf_bs_write_u32(bs, (u32) ptr->first_offset); | |
| } else { | |
| gf_bs_write_u64(bs, ptr->earliest_presentation_time); | |
| gf_bs_write_u64(bs, ptr->first_offset); | |
| } | |
| gf_bs_write_u16(bs, 0); | |
| gf_bs_write_u16(bs, ptr->nb_refs); | |
| for (i=0; i<ptr->nb_refs; i++ ) { | |
| gf_bs_write_int(bs, ptr->refs[i].reference_type, 1); | |
| gf_bs_write_int(bs, ptr->refs[i].reference_size, 31); | |
| gf_bs_write_u32(bs, ptr->refs[i].subsegment_duration); | |
| gf_bs_write_int(bs, ptr->refs[i].starts_with_SAP, 1); | |
| gf_bs_write_int(bs, ptr->refs[i].SAP_type, 3); | |
| gf_bs_write_int(bs, ptr->refs[i].SAP_delta_time, 28); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err sidx_box_size(GF_Box *s) | |
| { | |
| GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s; | |
| ptr->size += 12; | |
| if (ptr->version==0) { | |
| ptr->size += 8; | |
| } else { | |
| ptr->size += 16; | |
| } | |
| ptr->size += ptr->nb_refs * 12; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ssix_box_del(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->subsegments) { | |
| for (i = 0; i < ptr->subsegment_alloc; i++) { | |
| GF_SubsegmentInfo *subsegment = &ptr->subsegments[i]; | |
| if (subsegment->ranges) gf_free(subsegment->ranges); | |
| } | |
| gf_free(ptr->subsegments); | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err ssix_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i,j; | |
| GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox*)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->subsegment_count = gf_bs_read_u32(bs); | |
| //each subseg has at least one range_count (4 bytes), abort if not enough bytes (broken box) | |
| if (ptr->size / 4 < ptr->subsegment_count || (u64)ptr->subsegment_count > (u64)SIZE_MAX/sizeof(GF_SubsegmentInfo)) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->subsegment_alloc = ptr->subsegment_count; | |
| GF_SAFE_ALLOC_N(ptr->subsegments, ptr->subsegment_count, GF_SubsegmentInfo); | |
| if (!ptr->subsegments) | |
| return GF_OUT_OF_MEM; | |
| for (i = 0; i < ptr->subsegment_count; i++) { | |
| GF_SubsegmentInfo *subseg = &ptr->subsegments[i]; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| subseg->range_count = gf_bs_read_u32(bs); | |
| //each range is 4 bytes, abort if not enough bytes | |
| if (ptr->size / 4 < subseg->range_count || (u64)subseg->range_count > (u64)SIZE_MAX/sizeof(GF_SubsegmentRangeInfo)) | |
| return GF_ISOM_INVALID_FILE; | |
| subseg->ranges = (GF_SubsegmentRangeInfo*) gf_malloc(sizeof(GF_SubsegmentRangeInfo) * subseg->range_count); | |
| if (!subseg->ranges) return GF_OUT_OF_MEM; | |
| for (j = 0; j < subseg->range_count; j++) { | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| subseg->ranges[j].level = gf_bs_read_u8(bs); | |
| subseg->ranges[j].range_size = gf_bs_read_u24(bs); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *ssix_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SubsegmentIndexBox, GF_ISOM_BOX_TYPE_SSIX); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ssix_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i, j; | |
| GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox*)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->subsegment_count); | |
| for (i = 0; i<ptr->subsegment_count; i++) { | |
| gf_bs_write_u32(bs, ptr->subsegments[i].range_count); | |
| for (j = 0; j < ptr->subsegments[i].range_count; j++) { | |
| gf_bs_write_u8(bs, ptr->subsegments[i].ranges[j].level); | |
| gf_bs_write_u24(bs, ptr->subsegments[i].ranges[j].range_size); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err ssix_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_SubsegmentIndexBox *ptr = (GF_SubsegmentIndexBox*)s; | |
| ptr->size += 4; | |
| for (i = 0; i < ptr->subsegment_count; i++) { | |
| ptr->size += 4 + 4 * ptr->subsegments[i].range_count; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void leva_box_del(GF_Box *s) | |
| { | |
| GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->levels) gf_free(ptr->levels); | |
| gf_free(ptr); | |
| } | |
| GF_Err leva_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s; | |
| ISOM_DECREASE_SIZE(ptr, 1) | |
| ptr->level_count = gf_bs_read_u8(bs); | |
| //each level is at least 5 bytes | |
| if (ptr->size / 5 < ptr->level_count) | |
| return GF_ISOM_INVALID_FILE; | |
| GF_SAFE_ALLOC_N(ptr->levels, ptr->level_count, GF_LevelAssignment); | |
| if (!ptr->levels) return GF_OUT_OF_MEM; | |
| for (i = 0; i < ptr->level_count; i++) { | |
| GF_LevelAssignment *level = &ptr->levels[i]; | |
| u8 tmp; | |
| if (!level || ptr->size < 5) return GF_BAD_PARAM; | |
| ISOM_DECREASE_SIZE(ptr, 5) | |
| level->track_id = gf_bs_read_u32(bs); | |
| tmp = gf_bs_read_u8(bs); | |
| level->padding_flag = tmp >> 7; | |
| level->type = tmp & 0x7F; | |
| if (level->type == 0) { | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| level->grouping_type = gf_bs_read_u32(bs); | |
| } | |
| else if (level->type == 1) { | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| level->grouping_type = gf_bs_read_u32(bs); | |
| level->grouping_type_parameter = gf_bs_read_u32(bs); | |
| } | |
| else if (level->type == 4) { | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| level->sub_track_id = gf_bs_read_u32(bs); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *leva_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_LevelAssignmentBox, GF_ISOM_BOX_TYPE_LEVA); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err leva_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->level_count); | |
| for (i = 0; i<ptr->level_count; i++) { | |
| gf_bs_write_u32(bs, ptr->levels[i].track_id); | |
| gf_bs_write_u8(bs, ptr->levels[i].padding_flag << 7 | (ptr->levels[i].type & 0x7F)); | |
| if (ptr->levels[i].type == 0) { | |
| gf_bs_write_u32(bs, ptr->levels[i].grouping_type); | |
| } | |
| else if (ptr->levels[i].type == 1) { | |
| gf_bs_write_u32(bs, ptr->levels[i].grouping_type); | |
| gf_bs_write_u32(bs, ptr->levels[i].grouping_type_parameter); | |
| } | |
| else if (ptr->levels[i].type == 4) { | |
| gf_bs_write_u32(bs, ptr->levels[i].sub_track_id); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err leva_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s; | |
| ptr->size += 1; | |
| for (i = 0; i < ptr->level_count; i++) { | |
| ptr->size += 5; | |
| if (ptr->levels[i].type == 0 || ptr->levels[i].type == 4) { | |
| ptr->size += 4; | |
| } | |
| else if (ptr->levels[i].type == 1) { | |
| ptr->size += 8; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *pcrb_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PcrInfoBox, GF_ISOM_BOX_TYPE_PCRB); | |
| return (GF_Box *)tmp; | |
| } | |
| void pcrb_box_del(GF_Box *s) | |
| { | |
| GF_PcrInfoBox *ptr = (GF_PcrInfoBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->pcr_values) gf_free(ptr->pcr_values); | |
| gf_free(ptr); | |
| } | |
| GF_Err pcrb_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->subsegment_count = gf_bs_read_u32(bs); | |
| if ((u64)ptr->subsegment_count > ptr->size / 8 || (u64)ptr->subsegment_count > (u64)SIZE_MAX/sizeof(u64)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of subsegment %d in pcrb\n", ptr->subsegment_count)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->pcr_values = gf_malloc(sizeof(u64)*ptr->subsegment_count); | |
| if (!ptr->pcr_values) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->subsegment_count; i++) { | |
| u64 data1 = gf_bs_read_u32(bs); | |
| u64 data2 = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(ptr, 6); | |
| ptr->pcr_values[i] = (data1 << 10) | (data2 >> 6); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err pcrb_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->subsegment_count); | |
| for (i=0; i<ptr->subsegment_count; i++ ) { | |
| u32 data1 = (u32) (ptr->pcr_values[i] >> 10); | |
| u16 data2 = (u16) (ptr->pcr_values[i] << 6); | |
| gf_bs_write_u32(bs, data1); | |
| gf_bs_write_u16(bs, data2); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err pcrb_box_size(GF_Box *s) | |
| { | |
| GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s; | |
| ptr->size += 4; | |
| ptr->size += ptr->subsegment_count * 6; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *subs_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SubSampleInformationBox, GF_ISOM_BOX_TYPE_SUBS); | |
| tmp->Samples = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| void subs_box_del(GF_Box *s) | |
| { | |
| GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *)s; | |
| if (ptr == NULL) return; | |
| while (gf_list_count(ptr->Samples)) { | |
| GF_SubSampleInfoEntry *pSamp; | |
| pSamp = (GF_SubSampleInfoEntry*)gf_list_get(ptr->Samples, 0); | |
| while (gf_list_count(pSamp->SubSamples)) { | |
| GF_SubSampleEntry *pSubSamp; | |
| pSubSamp = (GF_SubSampleEntry*) gf_list_get(pSamp->SubSamples, 0); | |
| gf_free(pSubSamp); | |
| gf_list_rem(pSamp->SubSamples, 0); | |
| } | |
| gf_list_del(pSamp->SubSamples); | |
| gf_free(pSamp); | |
| gf_list_rem(ptr->Samples, 0); | |
| } | |
| gf_list_del(ptr->Samples); | |
| gf_free(ptr); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err subs_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i, j, entry_count; | |
| u16 subsample_count; | |
| GF_SubSampleEntry *pSubSamp; | |
| GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| entry_count = gf_list_count(ptr->Samples); | |
| gf_bs_write_u32(bs, entry_count); | |
| for (i=0; i<entry_count; i++) { | |
| GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry*) gf_list_get(ptr->Samples, i); | |
| subsample_count = gf_list_count(pSamp->SubSamples); | |
| gf_bs_write_u32(bs, pSamp->sample_delta); | |
| gf_bs_write_u16(bs, subsample_count); | |
| for (j=0; j<subsample_count; j++) { | |
| pSubSamp = (GF_SubSampleEntry*) gf_list_get(pSamp->SubSamples, j); | |
| if (ptr->version == 1) { | |
| gf_bs_write_u32(bs, pSubSamp->subsample_size); | |
| } else { | |
| gf_bs_write_u16(bs, pSubSamp->subsample_size); | |
| } | |
| gf_bs_write_u8(bs, pSubSamp->subsample_priority); | |
| gf_bs_write_u8(bs, pSubSamp->discardable); | |
| gf_bs_write_u32(bs, pSubSamp->reserved); | |
| } | |
| } | |
| return e; | |
| } | |
| GF_Err subs_box_size(GF_Box *s) | |
| { | |
| GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *) s; | |
| u32 entry_count, i; | |
| u16 subsample_count; | |
| // add 4 byte for entry_count | |
| ptr->size += 4; | |
| entry_count = gf_list_count(ptr->Samples); | |
| for (i=0; i<entry_count; i++) { | |
| GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry*) gf_list_get(ptr->Samples, i); | |
| subsample_count = gf_list_count(pSamp->SubSamples); | |
| // 4 byte for sample_delta, 2 byte for subsample_count | |
| // and 6 + (4 or 2) bytes for each subsample | |
| ptr->size += 4 + 2 + subsample_count * (6 + (ptr->version==1 ? 4 : 2)); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Err subs_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SubSampleInformationBox *ptr = (GF_SubSampleInformationBox *)s; | |
| u32 entry_count, i, j; | |
| u16 subsample_count; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| entry_count = gf_bs_read_u32(bs); | |
| if ((u64)entry_count*6 > gf_bs_available(bs)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] subs box: available buffer (%lu) too small for entry count read (%u)\n", gf_bs_available(bs), entry_count)); | |
| return GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| for (i=0; i<entry_count; i++) { | |
| u32 subs_size=0; | |
| GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry*) gf_malloc(sizeof(GF_SubSampleInfoEntry)); | |
| if (!pSamp) return GF_OUT_OF_MEM; | |
| memset(pSamp, 0, sizeof(GF_SubSampleInfoEntry)); | |
| pSamp->SubSamples = gf_list_new(); | |
| pSamp->sample_delta = gf_bs_read_u32(bs); | |
| subsample_count = gf_bs_read_u16(bs); | |
| subs_size=6; | |
| for (j=0; j<subsample_count; j++) { | |
| GF_SubSampleEntry *pSubSamp = (GF_SubSampleEntry*) gf_malloc(sizeof(GF_SubSampleEntry)); | |
| if (!pSubSamp) return GF_OUT_OF_MEM; | |
| memset(pSubSamp, 0, sizeof(GF_SubSampleEntry)); | |
| if (ptr->version==1) { | |
| pSubSamp->subsample_size = gf_bs_read_u32(bs); | |
| subs_size+=4; | |
| } else { | |
| pSubSamp->subsample_size = gf_bs_read_u16(bs); | |
| subs_size+=2; | |
| } | |
| pSubSamp->subsample_priority = gf_bs_read_u8(bs); | |
| pSubSamp->discardable = gf_bs_read_u8(bs); | |
| pSubSamp->reserved = gf_bs_read_u32(bs); | |
| subs_size+=6; | |
| gf_list_add(pSamp->SubSamples, pSubSamp); | |
| } | |
| gf_list_add(ptr->Samples, pSamp); | |
| ISOM_DECREASE_SIZE(ptr, subs_size); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_FRAGMENTS | |
| GF_Box *tfdt_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TFBaseMediaDecodeTimeBox, GF_ISOM_BOX_TYPE_TFDT); | |
| return (GF_Box *)tmp; | |
| } | |
| void tfdt_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| /*this is using chpl format according to some NeroRecode samples*/ | |
| GF_Err tfdt_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox *)s; | |
| if (ptr->version==1) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->baseMediaDecodeTime = gf_bs_read_u64(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->baseMediaDecodeTime = (u32) gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err tfdt_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version==1) { | |
| gf_bs_write_u64(bs, ptr->baseMediaDecodeTime); | |
| } else { | |
| gf_bs_write_u32(bs, (u32) ptr->baseMediaDecodeTime); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err tfdt_box_size(GF_Box *s) | |
| { | |
| GF_TFBaseMediaDecodeTimeBox *ptr = (GF_TFBaseMediaDecodeTimeBox *)s; | |
| if (!ptr->version && (ptr->baseMediaDecodeTime<=0xFFFFFFFF)) { | |
| //ptr->version = 0; | |
| ptr->size += 4; | |
| } else { | |
| ptr->version = 1; | |
| ptr->size += 8; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *rsot_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TFOriginalDurationBox, GF_ISOM_BOX_TYPE_RSOT); | |
| return (GF_Box *)tmp; | |
| } | |
| void rsot_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| /*this is using chpl format according to some NeroRecode samples*/ | |
| GF_Err rsot_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_TFOriginalDurationBox *ptr = (GF_TFOriginalDurationBox *)s; | |
| if (ptr->flags & 1) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->original_duration = gf_bs_read_u32(bs); | |
| } | |
| if (ptr->flags & 2) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->elapsed_duration = (u32) gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err rsot_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TFOriginalDurationBox *ptr = (GF_TFOriginalDurationBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->flags & 1) { | |
| gf_bs_write_u32(bs, ptr->original_duration); | |
| } | |
| if (ptr->flags & 2) { | |
| gf_bs_write_u32(bs, (u32) ptr->elapsed_duration); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err rsot_box_size(GF_Box *s) | |
| { | |
| GF_TFOriginalDurationBox *ptr = (GF_TFOriginalDurationBox *)s; | |
| if (ptr->original_duration) { | |
| ptr->flags |= 1; | |
| ptr->size+=4; | |
| } | |
| if (ptr->elapsed_duration) { | |
| ptr->flags |= 2; | |
| ptr->size+=4; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ | |
| GF_Box *rvcc_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_RVCConfigurationBox, GF_ISOM_BOX_TYPE_RVCC); | |
| return (GF_Box *)tmp; | |
| } | |
| void rvcc_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err rvcc_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox*)s; | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| ptr->predefined_rvc_config = gf_bs_read_u16(bs); | |
| if (!ptr->predefined_rvc_config) { | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| ptr->rvc_meta_idx = gf_bs_read_u16(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err rvcc_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox*) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->predefined_rvc_config); | |
| if (!ptr->predefined_rvc_config) { | |
| gf_bs_write_u16(bs, ptr->rvc_meta_idx); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err rvcc_box_size(GF_Box *s) | |
| { | |
| GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox *)s; | |
| ptr->size += 2; | |
| if (! ptr->predefined_rvc_config) ptr->size += 2; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *sbgp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleGroupBox, GF_ISOM_BOX_TYPE_SBGP); | |
| return (GF_Box *)tmp; | |
| } | |
| void sbgp_box_del(GF_Box *a) | |
| { | |
| GF_SampleGroupBox *p = (GF_SampleGroupBox *)a; | |
| if (p->sample_entries) gf_free(p->sample_entries); | |
| gf_free(p); | |
| } | |
| GF_Err sbgp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_SampleGroupBox *ptr = (GF_SampleGroupBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->grouping_type = gf_bs_read_u32(bs); | |
| if (ptr->version==1) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->grouping_type_parameter = gf_bs_read_u32(bs); | |
| } | |
| ptr->entry_count = gf_bs_read_u32(bs); | |
| if (ptr->size < sizeof(GF_SampleGroupEntry)*ptr->entry_count || (u64)ptr->entry_count > (u64)SIZE_MAX/sizeof(GF_SampleGroupEntry)) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->sample_entries = gf_malloc(sizeof(GF_SampleGroupEntry)*ptr->entry_count); | |
| if (!ptr->sample_entries) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->entry_count; i++) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->sample_entries[i].sample_count = gf_bs_read_u32(bs); | |
| ptr->sample_entries[i].group_description_index = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err sbgp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_Err e; | |
| GF_SampleGroupBox *p = (GF_SampleGroupBox*)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, p->grouping_type); | |
| if (p->version==1) | |
| gf_bs_write_u32(bs, p->grouping_type_parameter); | |
| gf_bs_write_u32(bs, p->entry_count); | |
| for (i = 0; i<p->entry_count; i++ ) { | |
| gf_bs_write_u32(bs, p->sample_entries[i].sample_count); | |
| gf_bs_write_u32(bs, p->sample_entries[i].group_description_index); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err sbgp_box_size(GF_Box *s) | |
| { | |
| GF_SampleGroupBox *p = (GF_SampleGroupBox*)s; | |
| p->size += 8; | |
| if (p->grouping_type_parameter) p->version=1; | |
| if (p->version==1) p->size += 4; | |
| p->size += 8*p->entry_count; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void *sgpd_parse_entry(GF_SampleGroupDescriptionBox *p, GF_BitStream *bs, s32 bytes_in_box, u32 entry_size, u32 *total_bytes) | |
| { | |
| Bool null_size_ok = GF_FALSE; | |
| GF_DefaultSampleGroupDescriptionEntry *def_ptr; | |
| p->is_opaque = GF_FALSE; | |
| switch (p->grouping_type) { | |
| case GF_ISOM_SAMPLE_GROUP_ROLL: | |
| case GF_ISOM_SAMPLE_GROUP_PROL: | |
| { | |
| GF_RollRecoveryEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_RollRecoveryEntry); | |
| if (!ptr) return NULL; | |
| ptr->roll_distance = gf_bs_read_int(bs, 16); | |
| *total_bytes = 2; | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_RAP: | |
| { | |
| GF_VisualRandomAccessEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_VisualRandomAccessEntry); | |
| if (!ptr) return NULL; | |
| ptr->num_leading_samples_known = gf_bs_read_int(bs, 1); | |
| ptr->num_leading_samples = gf_bs_read_int(bs, 7); | |
| *total_bytes = 1; | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_SAP: | |
| { | |
| GF_SAPEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_SAPEntry); | |
| if (!ptr) return NULL; | |
| ptr->dependent_flag = gf_bs_read_int(bs, 1); | |
| gf_bs_read_int(bs, 3); | |
| ptr->SAP_type = gf_bs_read_int(bs, 4); | |
| *total_bytes = 1; | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_SYNC: | |
| { | |
| GF_SYNCEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_SYNCEntry); | |
| if (!ptr) return NULL; | |
| gf_bs_read_int(bs, 2); | |
| ptr->NALU_type = gf_bs_read_int(bs, 6); | |
| *total_bytes = 1; | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_TELE: | |
| { | |
| GF_TemporalLevelEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_TemporalLevelEntry); | |
| if (!ptr) return NULL; | |
| ptr->level_independently_decodable = gf_bs_read_int(bs, 1); | |
| gf_bs_read_int(bs, 7); | |
| *total_bytes = 1; | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_SEIG: | |
| { | |
| GF_CENCSampleEncryptionGroupEntry *ptr; | |
| if (bytes_in_box<3) return NULL; | |
| GF_SAFEALLOC(ptr, GF_CENCSampleEncryptionGroupEntry); | |
| if (!ptr) return NULL; | |
| Bool use_mkey = gf_bs_read_int(bs, 1); | |
| Bool ext_pattern = gf_bs_read_int(bs, 1); | |
| gf_bs_read_int(bs, 6); //reserved | |
| if (ext_pattern) { | |
| ptr->crypt_byte_block = gf_bs_read_u32(bs); | |
| ptr->skip_byte_block = gf_bs_read_u32(bs); | |
| } else { | |
| ptr->crypt_byte_block = gf_bs_read_int(bs, 4); | |
| ptr->skip_byte_block = gf_bs_read_int(bs, 4); | |
| } | |
| ptr->IsProtected = gf_bs_read_u8(bs); | |
| bytes_in_box -= 3; | |
| if (use_mkey) { | |
| u64 pos = gf_bs_get_position(bs); | |
| u32 i, count = gf_bs_read_u16(bs); | |
| bytes_in_box -= 2; | |
| if (bytes_in_box<0) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| for (i=0; i<count; i++) { | |
| u8 ivsize = gf_bs_read_u8(bs); | |
| gf_bs_skip_bytes(bs, 16); | |
| bytes_in_box -= 17; | |
| if (!ivsize) { | |
| //const IV | |
| ivsize = gf_bs_read_u8(bs); | |
| gf_bs_skip_bytes(bs, ivsize); | |
| bytes_in_box -= 1 + ivsize; | |
| } | |
| if (bytes_in_box<0) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| } | |
| ptr->key_info_size = 1 + (u32) (gf_bs_get_position(bs) - pos); | |
| ptr->key_info = gf_malloc(sizeof(u8) * ptr->key_info_size); | |
| if (!ptr->key_info) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| gf_bs_seek(bs, pos); | |
| ptr->key_info[0] = 1; | |
| gf_bs_read_data(bs, ptr->key_info + 1, ptr->key_info_size - 1); | |
| *total_bytes = 3 + ptr->key_info_size - 1; | |
| if (!gf_cenc_validate_key_info(ptr->key_info, ptr->key_info_size)) { | |
| gf_free(ptr->key_info); | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| } else { | |
| bin128 kid; | |
| u8 const_iv_size = 0; | |
| u8 iv_size = gf_bs_read_u8(bs); | |
| gf_bs_read_data(bs, kid, 16); | |
| bytes_in_box -= 17; | |
| if (bytes_in_box<0) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| *total_bytes = 20; | |
| if ((ptr->IsProtected == 1) && !iv_size) { | |
| const_iv_size = gf_bs_read_u8(bs); | |
| if ((const_iv_size != 8) && (const_iv_size != 16)) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] seig sample group have invalid constant_IV size\n")); | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| } | |
| ptr->key_info_size = 20; | |
| if (!iv_size && ptr->IsProtected) { | |
| ptr->key_info_size += 1 + const_iv_size; | |
| } | |
| ptr->key_info = gf_malloc(sizeof(u8) * ptr->key_info_size); | |
| if (!ptr->key_info) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| ptr->key_info[0] = 0; | |
| ptr->key_info[1] = 0; | |
| ptr->key_info[2] = 0; | |
| ptr->key_info[3] = iv_size; | |
| memcpy(ptr->key_info+4, kid, 16); | |
| if (!iv_size && ptr->IsProtected) { | |
| ptr->key_info[20] = const_iv_size; | |
| gf_bs_read_data(bs, (char *)ptr->key_info+21, const_iv_size); | |
| *total_bytes += 1 + const_iv_size; | |
| } | |
| } | |
| if (!entry_size) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] seig sample group does not indicate entry size, deprecated in spec\n")); | |
| } | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_OINF: | |
| { | |
| GF_OperatingPointsInformation *ptr = gf_isom_oinf_new_entry(); | |
| u32 s = (u32) gf_bs_get_position(bs); | |
| gf_isom_oinf_read_entry(ptr, bs); | |
| *total_bytes = (u32) gf_bs_get_position(bs) - s; | |
| if (!entry_size) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] oinf sample group does not indicate entry size, deprecated in spec\n")); | |
| } | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_LINF: | |
| { | |
| GF_LHVCLayerInformation *ptr = gf_isom_linf_new_entry(); | |
| u32 s = (u32) gf_bs_get_position(bs); | |
| gf_isom_linf_read_entry(ptr, bs); | |
| *total_bytes = (u32) gf_bs_get_position(bs) - s; | |
| if (!entry_size) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] linf sample group does not indicate entry size, deprecated in spec\n")); | |
| } | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_TRIF: | |
| if (! entry_size) { | |
| u32 flags = gf_bs_peek_bits(bs, 24, 0); | |
| if (flags & 0x10000) entry_size=3; | |
| else { | |
| if (flags & 0x80000) entry_size=7; | |
| else entry_size=11; | |
| //have dependency list | |
| if (flags & 0x200000) { | |
| u32 nb_entries = gf_bs_peek_bits(bs, 16, entry_size); | |
| entry_size += 2 + 2*nb_entries; | |
| } | |
| } | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] trif sample group does not indicate entry size, deprecated in spec\n")); | |
| } | |
| break; | |
| case GF_ISOM_SAMPLE_GROUP_NALM: | |
| if (! entry_size) { | |
| u64 start = gf_bs_get_position(bs); | |
| Bool rle, large_size; | |
| u32 entry_count; | |
| gf_bs_read_int(bs, 6); | |
| large_size = gf_bs_read_int(bs, 1); | |
| rle = gf_bs_read_int(bs, 1); | |
| entry_count = gf_bs_read_int(bs, large_size ? 16 : 8); | |
| gf_bs_seek(bs, start); | |
| entry_size = 1 + (large_size ? 2 : 1); | |
| entry_size += entry_count * 2; | |
| if (rle) entry_size += entry_count * (large_size ? 2 : 1); | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] nalm sample group does not indicate entry size, deprecated in spec\n")); | |
| } | |
| break; | |
| case GF_ISOM_SAMPLE_GROUP_AV1S: | |
| case GF_ISOM_SAMPLE_GROUP_TSAS: | |
| case GF_ISOM_SAMPLE_GROUP_STSA: | |
| null_size_ok = GF_TRUE; | |
| break; | |
| //TODO, add support for these ones ? | |
| case GF_ISOM_SAMPLE_GROUP_TSCL: | |
| entry_size = 20; | |
| break; | |
| case GF_ISOM_SAMPLE_GROUP_LBLI: | |
| entry_size = 2; | |
| break; | |
| case GF_ISOM_SAMPLE_GROUP_SPOR: | |
| { | |
| u32 i; | |
| GF_SubpictureOrderEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_SubpictureOrderEntry); | |
| if (!ptr) return NULL; | |
| ptr->subpic_id_info_flag = gf_bs_read_int(bs, 1); | |
| ptr->num_subpic_ref_idx = gf_bs_read_int(bs, 15); | |
| *total_bytes = 2; | |
| ptr->subp_track_ref_idx = gf_malloc(sizeof(u16) * ptr->num_subpic_ref_idx); | |
| if (!ptr->subp_track_ref_idx) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| for (i=0; i<ptr->num_subpic_ref_idx; i++) { | |
| ptr->subp_track_ref_idx[i] = gf_bs_read_u16(bs); | |
| *total_bytes += 2; | |
| if (gf_bs_is_overflow(bs)) { | |
| gf_free(ptr->subp_track_ref_idx); | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| } | |
| if (ptr->subpic_id_info_flag) { | |
| ptr->spinfo.subpic_id_len_minus1 = gf_bs_read_int(bs, 4); | |
| ptr->spinfo.subpic_id_bit_pos = gf_bs_read_int(bs, 12); | |
| ptr->spinfo.start_code_emul_flag = gf_bs_read_int(bs, 1); | |
| ptr->spinfo.pps_sps_subpic_id_flag = gf_bs_read_int(bs, 1); | |
| if (ptr->spinfo.pps_sps_subpic_id_flag) { | |
| ptr->spinfo.xps_id = gf_bs_read_int(bs, 6); | |
| } else { | |
| ptr->spinfo.xps_id = gf_bs_read_int(bs, 4); | |
| gf_bs_read_int(bs, 2); | |
| } | |
| *total_bytes += 3; | |
| } | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_SULM: | |
| { | |
| u32 i; | |
| GF_SubpictureLayoutMapEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_SubpictureLayoutMapEntry); | |
| if (!ptr) return NULL; | |
| ptr->groupID_info_4cc = gf_bs_read_u32(bs); | |
| ptr->nb_entries = 1 + gf_bs_read_u16(bs); | |
| *total_bytes = 6; | |
| ptr->groupIDs = gf_malloc(sizeof(u16) * ptr->nb_entries); | |
| if (!ptr->groupIDs) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| ptr->groupIDs[i] = gf_bs_read_u16(bs); | |
| *total_bytes += 2; | |
| if (gf_bs_is_overflow(bs)) { | |
| gf_free(ptr->groupIDs); | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| } | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_ILCE: | |
| { | |
| GF_FieldInterlaceType *ptr; | |
| GF_SAFEALLOC(ptr, GF_FieldInterlaceType); | |
| if (!ptr) return NULL; | |
| ptr->ilce_type = gf_bs_read_u8(bs); | |
| *total_bytes = 1; | |
| return ptr; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_ESGH: | |
| { | |
| u32 i; | |
| GF_EssentialSamplegroupEntry *ptr; | |
| GF_SAFEALLOC(ptr, GF_EssentialSamplegroupEntry); | |
| if (!ptr) return NULL; | |
| ptr->nb_types = gf_bs_read_u32(bs); | |
| if ((u64)ptr->nb_types * 4 + 4 > entry_size) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| *total_bytes = 4; | |
| ptr->group_types = gf_malloc(sizeof(u32) * ptr->nb_types); | |
| if (!ptr->group_types) { | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| for (i=0; i<ptr->nb_types; i++) { | |
| ptr->group_types[i] = gf_bs_read_u32(bs); | |
| *total_bytes += 4; | |
| if (gf_bs_is_overflow(bs)) { | |
| gf_free(ptr->group_types); | |
| gf_free(ptr); | |
| return NULL; | |
| } | |
| } | |
| return ptr; | |
| } | |
| case 0: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] sgpd entry null grouping_type is invalid\n") ); | |
| return NULL; | |
| default: | |
| break; | |
| } | |
| if (!entry_size && !null_size_ok) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] %s sample group does not indicate entry size and is not implemented, cannot parse!\n", gf_4cc_to_str( p->grouping_type) )); | |
| return NULL; | |
| } | |
| p->is_opaque = GF_TRUE; | |
| GF_SAFEALLOC(def_ptr, GF_DefaultSampleGroupDescriptionEntry); | |
| if (!def_ptr) return NULL; | |
| if (entry_size) { | |
| def_ptr->length = entry_size; | |
| def_ptr->data = (u8 *) gf_malloc(sizeof(u8)*def_ptr->length); | |
| if (!def_ptr->data) { | |
| gf_free(def_ptr); | |
| return NULL; | |
| } | |
| gf_bs_read_data(bs, (char *) def_ptr->data, def_ptr->length); | |
| *total_bytes = entry_size; | |
| } | |
| return def_ptr; | |
| } | |
| void sgpd_del_entry(u32 grouping_type, void *entry, Bool is_opaque) | |
| { | |
| if (is_opaque) { | |
| GF_DefaultSampleGroupDescriptionEntry *ptr = (GF_DefaultSampleGroupDescriptionEntry *)entry; | |
| if (ptr && ptr->data) gf_free(ptr->data); | |
| gf_free(entry); | |
| return; | |
| } | |
| switch (grouping_type) { | |
| case GF_ISOM_SAMPLE_GROUP_SYNC: | |
| case GF_ISOM_SAMPLE_GROUP_ROLL: | |
| case GF_ISOM_SAMPLE_GROUP_PROL: | |
| case GF_ISOM_SAMPLE_GROUP_RAP: | |
| case GF_ISOM_SAMPLE_GROUP_TELE: | |
| case GF_ISOM_SAMPLE_GROUP_SAP: | |
| case GF_ISOM_SAMPLE_GROUP_AV1S: | |
| gf_free(entry); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SEIG: | |
| { | |
| GF_CENCSampleEncryptionGroupEntry *seig = (GF_CENCSampleEncryptionGroupEntry *)entry; | |
| if (seig->key_info) gf_free(seig->key_info); | |
| gf_free(entry); | |
| } | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_OINF: | |
| gf_isom_oinf_del_entry(entry); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_LINF: | |
| gf_isom_linf_del_entry(entry); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SPOR: | |
| { | |
| GF_SubpictureOrderEntry *spor = (GF_SubpictureOrderEntry *)entry; | |
| if (spor->subp_track_ref_idx) gf_free(spor->subp_track_ref_idx); | |
| gf_free(spor); | |
| } | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SULM: | |
| { | |
| GF_SubpictureLayoutMapEntry *sulm = (GF_SubpictureLayoutMapEntry *) entry; | |
| if (sulm->groupIDs) gf_free(sulm->groupIDs); | |
| gf_free(sulm); | |
| return; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_ILCE: | |
| gf_free(entry); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_ESGH: | |
| { | |
| GF_EssentialSamplegroupEntry *esgh = (GF_EssentialSamplegroupEntry *) entry; | |
| if (esgh->group_types) gf_free(esgh->group_types); | |
| gf_free(esgh); | |
| return; | |
| } | |
| default: | |
| { | |
| GF_DefaultSampleGroupDescriptionEntry *ptr = (GF_DefaultSampleGroupDescriptionEntry *)entry; | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| } | |
| } | |
| void sgpd_write_entry(u32 grouping_type, void *entry, GF_BitStream *bs) | |
| { | |
| switch (grouping_type) { | |
| case GF_ISOM_SAMPLE_GROUP_ROLL: | |
| case GF_ISOM_SAMPLE_GROUP_PROL: | |
| gf_bs_write_int(bs, ((GF_RollRecoveryEntry*)entry)->roll_distance, 16); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_RAP: | |
| gf_bs_write_int(bs, ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples_known, 1); | |
| gf_bs_write_int(bs, ((GF_VisualRandomAccessEntry*)entry)->num_leading_samples, 7); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SAP: | |
| gf_bs_write_int(bs, ((GF_SAPEntry*)entry)->dependent_flag, 1); | |
| gf_bs_write_int(bs, 0, 3); | |
| gf_bs_write_int(bs, ((GF_SAPEntry*)entry)->SAP_type, 4); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SYNC: | |
| gf_bs_write_int(bs, 0, 2); | |
| gf_bs_write_int(bs, ((GF_SYNCEntry*)entry)->NALU_type, 6); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_TELE: | |
| gf_bs_write_int(bs, ((GF_TemporalLevelEntry*)entry)->level_independently_decodable, 1); | |
| gf_bs_write_int(bs, 0, 7); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SEIG: | |
| { | |
| GF_CENCSampleEncryptionGroupEntry *seig = (GF_CENCSampleEncryptionGroupEntry *)entry; | |
| Bool use_mkey = seig->key_info[0]; | |
| /* | |
| u32 nb_keys = 1; | |
| if (use_mkey) { | |
| nb_keys = seig->key_info[1]; | |
| nb_keys<<=8; | |
| nb_keys |= seig->key_info[2]; | |
| } | |
| */ | |
| gf_bs_write_int(bs, use_mkey ? 1 : 0, 1); | |
| if ((seig->crypt_byte_block>15) || (seig->skip_byte_block>15)) { | |
| gf_bs_write_int(bs, 1, 1); | |
| gf_bs_write_int(bs, 0, 6); | |
| gf_bs_write_u32(bs, seig->crypt_byte_block); | |
| gf_bs_write_u32(bs, seig->skip_byte_block); | |
| } else { | |
| gf_bs_write_int(bs, 0, 7); | |
| gf_bs_write_int(bs, seig->crypt_byte_block, 4); | |
| gf_bs_write_int(bs, seig->skip_byte_block, 4); | |
| } | |
| gf_bs_write_u8(bs, seig->IsProtected); | |
| if (use_mkey) { | |
| gf_bs_write_data(bs, seig->key_info+1, seig->key_info_size-1); | |
| } else { | |
| gf_bs_write_data(bs, seig->key_info+3, seig->key_info_size - 3); | |
| } | |
| } | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_OINF: | |
| gf_isom_oinf_write_entry(entry, bs); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_LINF: | |
| gf_isom_linf_write_entry(entry, bs); | |
| return; | |
| case GF_ISOM_SAMPLE_GROUP_SPOR: | |
| { | |
| u32 i; | |
| GF_SubpictureOrderEntry *spor = (GF_SubpictureOrderEntry *) entry; | |
| gf_bs_write_int(bs, spor->subpic_id_info_flag, 1); | |
| gf_bs_write_int(bs, spor->num_subpic_ref_idx, 15); | |
| for (i=0; i<spor->num_subpic_ref_idx; i++) { | |
| gf_bs_write_u16(bs, spor->subp_track_ref_idx[i]); | |
| } | |
| if (spor->subpic_id_info_flag) { | |
| gf_bs_write_int(bs, spor->spinfo.subpic_id_len_minus1, 4); | |
| gf_bs_write_int(bs, spor->spinfo.subpic_id_bit_pos, 12); | |
| gf_bs_write_int(bs, spor->spinfo.start_code_emul_flag, 1); | |
| gf_bs_write_int(bs, spor->spinfo.pps_sps_subpic_id_flag, 1); | |
| if (spor->spinfo.pps_sps_subpic_id_flag) { | |
| gf_bs_write_int(bs, spor->spinfo.xps_id, 6); | |
| } else { | |
| gf_bs_write_int(bs, spor->spinfo.xps_id, 4); | |
| gf_bs_write_int(bs, 0, 2); | |
| } | |
| } | |
| return; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_SULM: | |
| { | |
| u32 i; | |
| GF_SubpictureLayoutMapEntry *sulm = (GF_SubpictureLayoutMapEntry *) entry; | |
| gf_bs_write_u32(bs, sulm->groupID_info_4cc); | |
| gf_bs_write_u16(bs, sulm->nb_entries - 1); | |
| for (i=0; i<sulm->nb_entries; i++) { | |
| gf_bs_write_u16(bs, sulm->groupIDs[i]); | |
| } | |
| return; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_ILCE: | |
| { | |
| GF_FieldInterlaceType *ilce = (GF_FieldInterlaceType *) entry; | |
| gf_bs_write_u8(bs, ilce->ilce_type); | |
| return; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_ESGH: | |
| { | |
| u32 i; | |
| GF_EssentialSamplegroupEntry *esgh = (GF_EssentialSamplegroupEntry *) entry; | |
| gf_bs_write_u32(bs, esgh->nb_types); | |
| for (i=0; i<esgh->nb_types; i++) { | |
| gf_bs_write_u32(bs, esgh->group_types[i]); | |
| } | |
| return; | |
| } | |
| default: | |
| { | |
| GF_DefaultSampleGroupDescriptionEntry *ptr = (GF_DefaultSampleGroupDescriptionEntry *)entry; | |
| if (ptr->length) | |
| gf_bs_write_data(bs, (char *) ptr->data, ptr->length); | |
| } | |
| } | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| static u32 sgpd_size_entry(u32 grouping_type, void *entry) | |
| { | |
| switch (grouping_type) { | |
| case GF_ISOM_SAMPLE_GROUP_ROLL: | |
| case GF_ISOM_SAMPLE_GROUP_PROL: | |
| return 2; | |
| case GF_ISOM_SAMPLE_GROUP_TELE: | |
| case GF_ISOM_SAMPLE_GROUP_RAP: | |
| case GF_ISOM_SAMPLE_GROUP_SAP: | |
| case GF_ISOM_SAMPLE_GROUP_SYNC: | |
| return 1; | |
| case GF_ISOM_SAMPLE_GROUP_TSCL: | |
| return 20; | |
| case GF_ISOM_SAMPLE_GROUP_LBLI: | |
| return 2; | |
| case GF_ISOM_SAMPLE_GROUP_AV1S: | |
| case GF_ISOM_SAMPLE_GROUP_TSAS: | |
| case GF_ISOM_SAMPLE_GROUP_STSA: | |
| return 0; | |
| case GF_ISOM_SAMPLE_GROUP_SEIG: | |
| { | |
| GF_CENCSampleEncryptionGroupEntry *seig = (GF_CENCSampleEncryptionGroupEntry *)entry; | |
| u32 base_size = 3; | |
| if ((seig->crypt_byte_block>15) || (seig->skip_byte_block>15)) { | |
| base_size += 7; | |
| } | |
| Bool use_mkey = seig->key_info[0] ? GF_TRUE : GF_FALSE; | |
| if (use_mkey) { | |
| return base_size + seig->key_info_size-1; | |
| } | |
| return base_size + seig->key_info_size-3; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_OINF: | |
| return gf_isom_oinf_size_entry(entry); | |
| case GF_ISOM_SAMPLE_GROUP_LINF: | |
| return gf_isom_linf_size_entry(entry); | |
| case GF_ISOM_SAMPLE_GROUP_SPOR: | |
| { | |
| GF_SubpictureOrderEntry *spor = (GF_SubpictureOrderEntry *)entry; | |
| u32 s = 2 + 2*spor->num_subpic_ref_idx; | |
| if (spor->subpic_id_info_flag) { | |
| s += 3; | |
| } | |
| return s; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_SULM: | |
| { | |
| GF_SubpictureLayoutMapEntry *sulm = (GF_SubpictureLayoutMapEntry *) entry; | |
| return 6 + 2*sulm->nb_entries; | |
| } | |
| case GF_ISOM_SAMPLE_GROUP_ILCE: | |
| return 1; | |
| case GF_ISOM_SAMPLE_GROUP_ESGH: | |
| { | |
| GF_EssentialSamplegroupEntry *esgh = (GF_EssentialSamplegroupEntry *) entry; | |
| return 4 + 4*esgh->nb_types; | |
| } | |
| default: | |
| return ((GF_DefaultSampleGroupDescriptionEntry *)entry)->length; | |
| } | |
| } | |
| #endif | |
| GF_Box *sgpd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleGroupDescriptionBox, GF_ISOM_BOX_TYPE_SGPD); | |
| /*version 0 is deprecated, use v1 by default*/ | |
| tmp->version = 1; | |
| tmp->group_descriptions = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| void sgpd_box_del(GF_Box *a) | |
| { | |
| GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)a; | |
| while (gf_list_count(p->group_descriptions)) { | |
| void *ptr = gf_list_last(p->group_descriptions); | |
| sgpd_del_entry(p->grouping_type, ptr, p->is_opaque); | |
| gf_list_rem_last(p->group_descriptions); | |
| } | |
| gf_list_del(p->group_descriptions); | |
| gf_free(p); | |
| } | |
| GF_Err sgpd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 entry_count; | |
| GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)s; | |
| ISOM_DECREASE_SIZE(p, 8); | |
| p->grouping_type = gf_bs_read_u32(bs); | |
| if (p->version>=1) { | |
| ISOM_DECREASE_SIZE(p, 4); | |
| p->default_length = gf_bs_read_u32(bs); | |
| } | |
| if (p->version>=2) { | |
| ISOM_DECREASE_SIZE(p, 4); | |
| p->default_description_index = gf_bs_read_u32(bs); | |
| } | |
| entry_count = gf_bs_read_u32(bs); | |
| if (entry_count>p->size) | |
| return GF_ISOM_INVALID_FILE; | |
| while (entry_count) { | |
| void *ptr; | |
| u32 parsed_bytes=0; | |
| u32 size = p->default_length; | |
| if ((p->version>=1) && !size) { | |
| size = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(p, 4); | |
| } | |
| if (size && size>p->size) { | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr = sgpd_parse_entry(p, bs, (s32) p->size, size, &parsed_bytes); | |
| //don't return an error, just stop parsing so that we skip over the sgpd box | |
| if (!ptr) return GF_OK; | |
| gf_list_add(p->group_descriptions, ptr); | |
| ISOM_DECREASE_SIZE(p, parsed_bytes); | |
| entry_count--; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err sgpd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, nb_descs; | |
| GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)s; | |
| GF_Err e; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, p->grouping_type); | |
| if (p->version>=1) gf_bs_write_u32(bs, p->default_length); | |
| if (p->version>=2) gf_bs_write_u32(bs, p->default_description_index); | |
| nb_descs = gf_list_count(p->group_descriptions); | |
| gf_bs_write_u32(bs, nb_descs); | |
| for (i=0; i<nb_descs; i++) { | |
| void *ptr = gf_list_get(p->group_descriptions, i); | |
| if ((p->version >= 1) && !p->default_length) { | |
| u32 size = sgpd_size_entry(p->grouping_type, ptr); | |
| gf_bs_write_u32(bs, size); | |
| } | |
| sgpd_write_entry(p->grouping_type, ptr, bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err sgpd_box_size(GF_Box *s) | |
| { | |
| u32 i, nb_descs; | |
| Bool use_def_size = GF_TRUE; | |
| GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)s; | |
| p->size += 8; | |
| //we force all sample groups to version 1, v0 being deprecated | |
| if (!p->version) | |
| p->version = 1; | |
| p->size += 4; | |
| if (p->version>=2) | |
| p->size += 4; | |
| p->default_length = 0; | |
| nb_descs = gf_list_count(p->group_descriptions); | |
| for (i=0; i<nb_descs; i++) { | |
| void *ptr = gf_list_get(p->group_descriptions, i); | |
| u32 size = sgpd_size_entry(p->grouping_type, ptr); | |
| p->size += size; | |
| if (use_def_size && !p->default_length) { | |
| p->default_length = size; | |
| } else if (p->default_length != size) { | |
| use_def_size = GF_FALSE; | |
| p->default_length = 0; | |
| } | |
| } | |
| if (p->version>=1) { | |
| if (!p->default_length) p->size += nb_descs * 4; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void saiz_box_del(GF_Box *s) | |
| { | |
| GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*)s; | |
| if (ptr == NULL) return; | |
| if (ptr->sample_info_size) gf_free(ptr->sample_info_size); | |
| gf_free(ptr); | |
| } | |
| GF_Err saiz_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*)s; | |
| if (ptr->flags & 1) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->aux_info_type = gf_bs_read_u32(bs); | |
| ptr->aux_info_type_parameter = gf_bs_read_u32(bs); | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 5); | |
| ptr->default_sample_info_size = gf_bs_read_u8(bs); | |
| ptr->sample_count = gf_bs_read_u32(bs); | |
| if (ptr->default_sample_info_size == 0) { | |
| if (ptr->size < ptr->sample_count) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->sample_info_size = gf_malloc(sizeof(u8)*ptr->sample_count); | |
| ptr->sample_alloc = ptr->sample_count; | |
| if (!ptr->sample_info_size) | |
| return GF_OUT_OF_MEM; | |
| ISOM_DECREASE_SIZE(ptr, ptr->sample_count); | |
| gf_bs_read_data(bs, (char *) ptr->sample_info_size, ptr->sample_count); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *saiz_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleAuxiliaryInfoSizeBox, GF_ISOM_BOX_TYPE_SAIZ); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err saiz_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->flags & 1) { | |
| gf_bs_write_u32(bs, ptr->aux_info_type); | |
| gf_bs_write_u32(bs, ptr->aux_info_type_parameter); | |
| } | |
| gf_bs_write_u8(bs, ptr->default_sample_info_size); | |
| gf_bs_write_u32(bs, ptr->sample_count); | |
| if (!ptr->default_sample_info_size) { | |
| if (!ptr->sample_info_size) | |
| gf_bs_write_u8(bs, 0); | |
| else | |
| gf_bs_write_data(bs, (char *) ptr->sample_info_size, ptr->sample_count); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err saiz_box_size(GF_Box *s) | |
| { | |
| GF_SampleAuxiliaryInfoSizeBox *ptr = (GF_SampleAuxiliaryInfoSizeBox*)s; | |
| if (ptr->aux_info_type || ptr->aux_info_type_parameter) { | |
| ptr->flags |= 1; | |
| } | |
| if (ptr->flags & 1) ptr->size += 8; | |
| ptr->size += 5; | |
| if (ptr->default_sample_info_size==0) ptr->size += ptr->sample_count; | |
| return GF_OK; | |
| } | |
| #endif //GPAC_DISABLE_ISOM_WRITE | |
| void saio_box_del(GF_Box *s) | |
| { | |
| GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox*)s; | |
| if (ptr == NULL) return; | |
| if (ptr->offsets) gf_free(ptr->offsets); | |
| if (ptr->cached_data) gf_free(ptr->cached_data); | |
| gf_free(ptr); | |
| } | |
| GF_Err saio_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox *)s; | |
| if (ptr->flags & 1) { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->aux_info_type = gf_bs_read_u32(bs); | |
| ptr->aux_info_type_parameter = gf_bs_read_u32(bs); | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->entry_count = gf_bs_read_u32(bs); | |
| if (ptr->entry_count) { | |
| u32 i; | |
| if (ptr->size / (ptr->version == 0 ? 4 : 8) < ptr->entry_count || (u64)ptr->entry_count > (u64)SIZE_MAX/sizeof(u64)) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->offsets = gf_malloc(sizeof(u64)*ptr->entry_count); | |
| if (!ptr->offsets) | |
| return GF_OUT_OF_MEM; | |
| ptr->entry_alloc = ptr->entry_count; | |
| if (ptr->version==0) { | |
| ISOM_DECREASE_SIZE(ptr, 4*ptr->entry_count); | |
| for (i=0; i<ptr->entry_count; i++) | |
| ptr->offsets[i] = gf_bs_read_u32(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 8*ptr->entry_count); | |
| for (i=0; i<ptr->entry_count; i++) | |
| ptr->offsets[i] = gf_bs_read_u64(bs); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *saio_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleAuxiliaryInfoOffsetBox, GF_ISOM_BOX_TYPE_SAIO); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err saio_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->flags & 1) { | |
| gf_bs_write_u32(bs, ptr->aux_info_type); | |
| gf_bs_write_u32(bs, ptr->aux_info_type_parameter); | |
| } | |
| gf_bs_write_u32(bs, ptr->entry_count); | |
| if (ptr->entry_count) { | |
| u32 i; | |
| if (ptr->sai_data) { | |
| if (ptr->sai_data->sai_offset) { | |
| if (ptr->version==0) { | |
| gf_bs_write_u32(bs, (u32) ptr->sai_data->sai_offset); | |
| } else { | |
| gf_bs_write_u64(bs, ptr->sai_data->sai_offset); | |
| } | |
| return GF_OK; | |
| } | |
| ptr->sai_data->saio_box = ptr; | |
| } | |
| //store position in bitstream before writing data - offsets can be NULL if a single offset is rewritten later on (cf senc_box_write) | |
| ptr->offset_first_offset_field = gf_bs_get_position(bs); | |
| if (ptr->version==0) { | |
| if (!ptr->offsets) { | |
| gf_bs_write_u32(bs, 0); | |
| } else { | |
| for (i=0; i<ptr->entry_count; i++) | |
| gf_bs_write_u32(bs, (u32) ptr->offsets[i]); | |
| } | |
| } else { | |
| if (!ptr->offsets) { | |
| gf_bs_write_u64(bs, 0); | |
| } else { | |
| for (i=0; i<ptr->entry_count; i++) | |
| gf_bs_write_u64(bs, ptr->offsets[i]); | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err saio_box_size(GF_Box *s) | |
| { | |
| GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox*)s; | |
| if (ptr->aux_info_type || ptr->aux_info_type_parameter) { | |
| ptr->flags |= 1; | |
| } | |
| if (ptr->flags & 1) ptr->size += 8; | |
| ptr->size += 4; | |
| //a little optim here: in cenc, the saio always points to a single data block, only one entry is needed | |
| switch (ptr->aux_info_type) { | |
| case GF_ISOM_CENC_SCHEME: | |
| case GF_ISOM_CBC_SCHEME: | |
| case GF_ISOM_CENS_SCHEME: | |
| case GF_ISOM_CBCS_SCHEME: | |
| if (ptr->offsets) gf_free(ptr->offsets); | |
| ptr->offsets = NULL; | |
| ptr->entry_alloc = 0; | |
| ptr->entry_count = 1; | |
| break; | |
| } | |
| ptr->size += ((ptr->version==1) ? 8 : 4) * ptr->entry_count; | |
| return GF_OK; | |
| } | |
| #endif //GPAC_DISABLE_ISOM_WRITE | |
| void prft_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err prft_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox *) s; | |
| ISOM_DECREASE_SIZE(ptr, 12); | |
| ptr->refTrackID = gf_bs_read_u32(bs); | |
| ptr->ntp = gf_bs_read_u64(bs); | |
| if (ptr->version==0) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->timestamp = gf_bs_read_u32(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->timestamp = gf_bs_read_u64(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *prft_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ProducerReferenceTimeBox, GF_ISOM_BOX_TYPE_PRFT); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err prft_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->refTrackID); | |
| gf_bs_write_u64(bs, ptr->ntp); | |
| if (ptr->version==0) { | |
| gf_bs_write_u32(bs, (u32) ptr->timestamp); | |
| } else { | |
| gf_bs_write_u64(bs, ptr->timestamp); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err prft_box_size(GF_Box *s) | |
| { | |
| GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox*)s; | |
| ptr->size += 4+8+ (ptr->version ? 8 : 4); | |
| return GF_OK; | |
| } | |
| #endif //GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *trgr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackGroupBox, GF_ISOM_BOX_TYPE_TRGR); | |
| tmp->groups = gf_list_new(); | |
| if (!tmp->groups) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| return (GF_Box *)tmp; | |
| } | |
| void trgr_box_del(GF_Box *s) | |
| { | |
| GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s; | |
| if (ptr == NULL) return; | |
| gf_list_del(ptr->groups); | |
| gf_free(ptr); | |
| } | |
| GF_Err trgr_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s; | |
| BOX_FIELD_LIST_ASSIGN(groups) | |
| return GF_OK; | |
| } | |
| GF_Err trgr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trgr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err trgr_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| GF_TrackGroupBox *ptr = (GF_TrackGroupBox *) s; | |
| gf_isom_check_position_list(s, ptr->groups, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *trgt_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrackGroupTypeBox, GF_ISOM_BOX_TYPE_TRGT); | |
| return (GF_Box *)tmp; | |
| } | |
| void trgt_box_del(GF_Box *s) | |
| { | |
| GF_TrackGroupTypeBox *ptr = (GF_TrackGroupTypeBox *)s; | |
| if (ptr == NULL) return; | |
| gf_free(ptr); | |
| } | |
| GF_Err trgt_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrackGroupTypeBox *ptr = (GF_TrackGroupTypeBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->track_group_id = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trgt_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TrackGroupTypeBox *ptr = (GF_TrackGroupTypeBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| if (ptr->group_type == GF_ISOM_BOX_TYPE_UUID) return GF_BAD_PARAM; | |
| s->type = ptr->group_type; | |
| e = gf_isom_full_box_write(s, bs); | |
| s->type = GF_ISOM_BOX_TYPE_TRGT; | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->track_group_id); | |
| return GF_OK; | |
| } | |
| GF_Err trgt_box_size(GF_Box *s) | |
| { | |
| GF_TrackGroupBox *ptr = (GF_TrackGroupBox *)s; | |
| ptr->size+= 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *stvi_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_StereoVideoBox, GF_ISOM_BOX_TYPE_STVI); | |
| return (GF_Box *)tmp; | |
| } | |
| void stvi_box_del(GF_Box *s) | |
| { | |
| GF_StereoVideoBox *ptr = (GF_StereoVideoBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->stereo_indication_type) gf_free(ptr->stereo_indication_type); | |
| gf_free(ptr); | |
| } | |
| GF_Err stvi_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_StereoVideoBox *ptr = (GF_StereoVideoBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 12); | |
| gf_bs_read_int(bs, 30); | |
| ptr->single_view_allowed = gf_bs_read_int(bs, 2); | |
| ptr->stereo_scheme = gf_bs_read_u32(bs); | |
| ptr->sit_len = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(ptr, ptr->sit_len); | |
| ptr->stereo_indication_type = gf_malloc(sizeof(char)*ptr->sit_len); | |
| if (!ptr->stereo_indication_type) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->stereo_indication_type, ptr->sit_len); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err stvi_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_StereoVideoBox *ptr = (GF_StereoVideoBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, 0, 30); | |
| gf_bs_write_int(bs, ptr->single_view_allowed, 2); | |
| gf_bs_write_u32(bs, ptr->stereo_scheme); | |
| gf_bs_write_u32(bs, ptr->sit_len); | |
| gf_bs_write_data(bs, ptr->stereo_indication_type, ptr->sit_len); | |
| return GF_OK; | |
| } | |
| GF_Err stvi_box_size(GF_Box *s) | |
| { | |
| GF_StereoVideoBox *ptr = (GF_StereoVideoBox *)s; | |
| ptr->size+= 12 + ptr->sit_len; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *fiin_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(FDItemInformationBox, GF_ISOM_BOX_TYPE_FIIN); | |
| return (GF_Box *)tmp; | |
| } | |
| void fiin_box_del(GF_Box *s) | |
| { | |
| FDItemInformationBox *ptr = (FDItemInformationBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->partition_entries) gf_list_del(ptr->partition_entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err fiin_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| FDItemInformationBox *ptr = (FDItemInformationBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_PAEN: | |
| BOX_FIELD_LIST_ASSIGN(partition_entries) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_SEGR: | |
| BOX_FIELD_ASSIGN(session_info, FDSessionGroupBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_GITN: | |
| BOX_FIELD_ASSIGN(group_id_to_name, GroupIdToNameBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fiin_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| FDItemInformationBox *ptr = (FDItemInformationBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| gf_bs_read_u16(bs); | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err fiin_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| FDItemInformationBox *ptr = (FDItemInformationBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, gf_list_count(ptr->partition_entries) ); | |
| return GF_OK; | |
| } | |
| GF_Err fiin_box_size(GF_Box *s) | |
| { | |
| u32 pos=0; | |
| FDItemInformationBox *ptr = (FDItemInformationBox *) s; | |
| s->size+= 2; | |
| gf_isom_check_position_list(s, ptr->partition_entries, &pos); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *paen_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(FDPartitionEntryBox, GF_ISOM_BOX_TYPE_PAEN); | |
| return (GF_Box *)tmp; | |
| } | |
| void paen_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err paen_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| FDPartitionEntryBox *ptr = (FDPartitionEntryBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_FPAR: | |
| BOX_FIELD_ASSIGN(blocks_and_symbols, FilePartitionBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_FECR: | |
| BOX_FIELD_ASSIGN(FEC_symbol_locations, FECReservoirBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_FIRE: | |
| BOX_FIELD_ASSIGN(File_symbol_locations, FileReservoirBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err paen_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err paen_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| if (!s) return GF_BAD_PARAM; | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err paen_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *fpar_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(FilePartitionBox, GF_ISOM_BOX_TYPE_FPAR); | |
| return (GF_Box *)tmp; | |
| } | |
| void fpar_box_del(GF_Box *s) | |
| { | |
| FilePartitionBox *ptr = (FilePartitionBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->scheme_specific_info) gf_free(ptr->scheme_specific_info); | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err gf_isom_read_null_terminated_string(GF_Box *s, GF_BitStream *bs, u64 size, char **out_str) | |
| { | |
| u32 len=10; | |
| u32 i=0; | |
| *out_str = gf_malloc(sizeof(char)*len); | |
| if (! *out_str) return GF_OUT_OF_MEM; | |
| if (!s->size) { | |
| *out_str[0] = 0; | |
| return GF_OK; | |
| } | |
| while (1) { | |
| ISOM_DECREASE_SIZE(s, 1 ); | |
| (*out_str)[i] = gf_bs_read_u8(bs); | |
| if (!(*out_str)[i]) break; | |
| i++; | |
| if (i==len) { | |
| len += 10; | |
| *out_str = gf_realloc(*out_str, sizeof(char)*len); | |
| } | |
| if (gf_bs_available(bs) == 0) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] missing null character in null terminated string\n")); | |
| (*out_str)[i] = 0; | |
| return GF_OK; | |
| } | |
| if (i >= size) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] string bigger than container, probably missing null character\n")); | |
| (*out_str)[i] = 0; | |
| return GF_OK; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fpar_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_Err e; | |
| FilePartitionBox *ptr = (FilePartitionBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, ((ptr->version ? 4 : 2) + 12) ); | |
| ptr->itemID = gf_bs_read_int(bs, ptr->version ? 32 : 16); | |
| ptr->packet_payload_size = gf_bs_read_u16(bs); | |
| gf_bs_read_u8(bs); | |
| ptr->FEC_encoding_ID = gf_bs_read_u8(bs); | |
| ptr->FEC_instance_ID = gf_bs_read_u16(bs); | |
| ptr->max_source_block_length = gf_bs_read_u16(bs); | |
| ptr->encoding_symbol_length = gf_bs_read_u16(bs); | |
| ptr->max_number_of_encoding_symbols = gf_bs_read_u16(bs); | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_specific_info); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(ptr, (ptr->version ? 4 : 2) ); | |
| ptr->nb_entries = gf_bs_read_int(bs, ptr->version ? 32 : 16); | |
| if (ptr->nb_entries > ptr->size / 6 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(FilePartitionEntry)) | |
| return GF_ISOM_INVALID_FILE; | |
| ISOM_DECREASE_SIZE(ptr, ptr->nb_entries * 6 ); | |
| GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, FilePartitionEntry); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| for (i=0;i < ptr->nb_entries; i++) { | |
| ptr->entries[i].block_count = gf_bs_read_u16(bs); | |
| ptr->entries[i].block_size = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err fpar_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| FilePartitionBox *ptr = (FilePartitionBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->itemID, ptr->version ? 32 : 16); | |
| gf_bs_write_u16(bs, ptr->packet_payload_size); | |
| gf_bs_write_u8(bs, 0); | |
| gf_bs_write_u8(bs, ptr->FEC_encoding_ID); | |
| gf_bs_write_u16(bs, ptr->FEC_instance_ID); | |
| gf_bs_write_u16(bs, ptr->max_source_block_length); | |
| gf_bs_write_u16(bs, ptr->encoding_symbol_length); | |
| gf_bs_write_u16(bs, ptr->max_number_of_encoding_symbols); | |
| if (ptr->scheme_specific_info) { | |
| gf_bs_write_data(bs, ptr->scheme_specific_info, (u32)strlen(ptr->scheme_specific_info) ); | |
| } | |
| //null terminated string | |
| gf_bs_write_u8(bs, 0); | |
| gf_bs_write_int(bs, ptr->nb_entries, ptr->version ? 32 : 16); | |
| for (i=0;i < ptr->nb_entries; i++) { | |
| gf_bs_write_u16(bs, ptr->entries[i].block_count); | |
| gf_bs_write_u32(bs, ptr->entries[i].block_size); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fpar_box_size(GF_Box *s) | |
| { | |
| FilePartitionBox *ptr = (FilePartitionBox *)s; | |
| ptr->size += 13 + (ptr->version ? 8 : 4); | |
| if (ptr->scheme_specific_info) | |
| ptr->size += strlen(ptr->scheme_specific_info); | |
| ptr->size+= ptr->nb_entries * 6; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *fecr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(FECReservoirBox, GF_ISOM_BOX_TYPE_FECR); | |
| return (GF_Box *)tmp; | |
| } | |
| void fecr_box_del(GF_Box *s) | |
| { | |
| FECReservoirBox *ptr = (FECReservoirBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err fecr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| FECReservoirBox *ptr = (FECReservoirBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, (ptr->version ? 4 : 2) ); | |
| ptr->nb_entries = gf_bs_read_int(bs, ptr->version ? 32 : 16); | |
| if (ptr->nb_entries > ptr->size / (ptr->version ? 8 : 6) || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(FECReservoirEntry) ) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in fecr\n", ptr->nb_entries)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ISOM_DECREASE_SIZE(ptr, ptr->nb_entries * (ptr->version ? 8 : 6) ); | |
| GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, FECReservoirEntry); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| ptr->entries[i].item_id = gf_bs_read_int(bs, ptr->version ? 32 : 16); | |
| ptr->entries[i].symbol_count = gf_bs_read_u32(bs); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err fecr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| FECReservoirBox *ptr = (FECReservoirBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->nb_entries, ptr->version ? 32 : 16); | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| gf_bs_write_int(bs, ptr->entries[i].item_id, ptr->version ? 32 : 16); | |
| gf_bs_write_u32(bs, ptr->entries[i].symbol_count); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fecr_box_size(GF_Box *s) | |
| { | |
| FECReservoirBox *ptr = (FECReservoirBox *)s; | |
| ptr->size += (ptr->version ? 4 : 2) + ptr->nb_entries * (ptr->version ? 8 : 6); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *segr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(FDSessionGroupBox, GF_ISOM_BOX_TYPE_SEGR); | |
| return (GF_Box *)tmp; | |
| } | |
| void segr_box_del(GF_Box *s) | |
| { | |
| u32 i; | |
| FDSessionGroupBox *ptr = (FDSessionGroupBox *)s; | |
| if (ptr == NULL) return; | |
| for (i=0; i<ptr->num_session_groups; i++) { | |
| if (ptr->session_groups[i].group_ids) gf_free(ptr->session_groups[i].group_ids); | |
| if (ptr->session_groups[i].channels) gf_free(ptr->session_groups[i].channels); | |
| } | |
| if (ptr->session_groups) gf_free(ptr->session_groups); | |
| gf_free(ptr); | |
| } | |
| GF_Err segr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, k; | |
| FDSessionGroupBox *ptr = (FDSessionGroupBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| ptr->num_session_groups = gf_bs_read_u16(bs); | |
| if (ptr->size < ptr->num_session_groups) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in segr\n", ptr->num_session_groups)); | |
| ptr->num_session_groups = 0; | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| GF_SAFE_ALLOC_N(ptr->session_groups, ptr->num_session_groups, SessionGroupEntry); | |
| if (!ptr->session_groups) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->num_session_groups; i++) { | |
| ptr->session_groups[i].nb_groups = gf_bs_read_u8(bs); | |
| ISOM_DECREASE_SIZE(ptr, 1); | |
| ISOM_DECREASE_SIZE(ptr, ptr->session_groups[i].nb_groups*4); | |
| GF_SAFE_ALLOC_N(ptr->session_groups[i].group_ids, ptr->session_groups[i].nb_groups, u32); | |
| if (!ptr->session_groups[i].group_ids) return GF_OUT_OF_MEM; | |
| for (k=0; k<ptr->session_groups[i].nb_groups; k++) { | |
| ptr->session_groups[i].group_ids[k] = gf_bs_read_u32(bs); | |
| } | |
| ptr->session_groups[i].nb_channels = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(ptr, ptr->session_groups[i].nb_channels*4); | |
| GF_SAFE_ALLOC_N(ptr->session_groups[i].channels, ptr->session_groups[i].nb_channels, u32); | |
| if (!ptr->session_groups[i].channels) return GF_OUT_OF_MEM; | |
| for (k=0; k<ptr->session_groups[i].nb_channels; k++) { | |
| ptr->session_groups[i].channels[k] = gf_bs_read_u32(bs); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err segr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, k; | |
| GF_Err e; | |
| FDSessionGroupBox *ptr = (FDSessionGroupBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->num_session_groups); | |
| for (i=0; i<ptr->num_session_groups; i++) { | |
| gf_bs_write_u8(bs, ptr->session_groups[i].nb_groups); | |
| for (k=0; k<ptr->session_groups[i].nb_groups; k++) { | |
| gf_bs_write_u32(bs, ptr->session_groups[i].group_ids[k]); | |
| } | |
| gf_bs_write_u16(bs, ptr->session_groups[i].nb_channels); | |
| for (k=0; k<ptr->session_groups[i].nb_channels; k++) { | |
| gf_bs_write_u32(bs, ptr->session_groups[i].channels[k]); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err segr_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| FDSessionGroupBox *ptr = (FDSessionGroupBox *)s; | |
| ptr->size += 2; | |
| for (i=0; i<ptr->num_session_groups; i++) { | |
| ptr->size += 1 + 4*ptr->session_groups[i].nb_groups; | |
| ptr->size += 2 + 4*ptr->session_groups[i].nb_channels; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *gitn_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GroupIdToNameBox, GF_ISOM_BOX_TYPE_GITN); | |
| return (GF_Box *)tmp; | |
| } | |
| void gitn_box_del(GF_Box *s) | |
| { | |
| u32 i; | |
| GroupIdToNameBox *ptr = (GroupIdToNameBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->entries) { | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| if (ptr->entries[i].name) gf_free(ptr->entries[i].name); | |
| } | |
| gf_free(ptr->entries); | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err gitn_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_Err e; | |
| GroupIdToNameBox *ptr = (GroupIdToNameBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| ptr->nb_entries = gf_bs_read_u16(bs); | |
| if (ptr->size / 4 < ptr->nb_entries) | |
| return GF_ISOM_INVALID_FILE; | |
| GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, GroupIdNameEntry); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->entries[i].group_id = gf_bs_read_u32(bs); | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->entries[i].name); | |
| if (e) return e; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err gitn_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GroupIdToNameBox *ptr = (GroupIdToNameBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u16(bs, ptr->nb_entries); | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| gf_bs_write_u32(bs, ptr->entries[i].group_id); | |
| if (ptr->entries[i].name) gf_bs_write_data(bs, ptr->entries[i].name, (u32)strlen(ptr->entries[i].name) ); | |
| gf_bs_write_u8(bs, 0); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gitn_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GroupIdToNameBox *ptr = (GroupIdToNameBox *)s; | |
| ptr->size += 2; | |
| for (i=0; i<ptr->nb_entries; i++) { | |
| ptr->size += 5; | |
| if (ptr->entries[i].name) ptr->size += strlen(ptr->entries[i].name); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #ifndef GPAC_DISABLE_ISOM_HINTING | |
| GF_Box *fdpa_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_FDpacketBox, GF_ISOM_BOX_TYPE_FDPA); | |
| return (GF_Box *)tmp; | |
| } | |
| void fdpa_box_del(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_FDpacketBox *ptr = (GF_FDpacketBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->headers) { | |
| for (i=0; i<ptr->header_ext_count; i++) { | |
| if (ptr->headers[i].data) gf_free(ptr->headers[i].data); | |
| } | |
| gf_free(ptr->headers); | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err fdpa_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_FDpacketBox *ptr = (GF_FDpacketBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 3); | |
| ptr->info.sender_current_time_present = gf_bs_read_int(bs, 1); | |
| ptr->info.expected_residual_time_present = gf_bs_read_int(bs, 1); | |
| ptr->info.session_close_bit = gf_bs_read_int(bs, 1); | |
| ptr->info.object_close_bit = gf_bs_read_int(bs, 1); | |
| gf_bs_read_int(bs, 4); | |
| ptr->info.transport_object_identifier = gf_bs_read_u16(bs); | |
| ISOM_DECREASE_SIZE(ptr, 2); | |
| ptr->header_ext_count = gf_bs_read_u16(bs); | |
| if (ptr->size / 2 < ptr->header_ext_count) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in fdpa\n", ptr->header_ext_count)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| GF_SAFE_ALLOC_N(ptr->headers, ptr->header_ext_count, GF_LCTheaderExtension); | |
| if (!ptr->headers) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->header_ext_count; i++) { | |
| ptr->headers[i].header_extension_type = gf_bs_read_u8(bs); | |
| ISOM_DECREASE_SIZE(ptr, 1); | |
| if (ptr->headers[i].header_extension_type > 127) { | |
| ISOM_DECREASE_SIZE(ptr, 3); | |
| gf_bs_read_data(bs, (char *) ptr->headers[i].content, 3); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 1); | |
| ptr->headers[i].data_length = gf_bs_read_u8(bs); | |
| if (ptr->headers[i].data_length) { | |
| ptr->headers[i].data_length = 4*ptr->headers[i].data_length - 2; | |
| if (ptr->size < sizeof(char) * ptr->headers[i].data_length) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->headers[i].data = gf_malloc(sizeof(char) * ptr->headers[i].data_length); | |
| if (!ptr->headers[i].data) return GF_OUT_OF_MEM; | |
| ISOM_DECREASE_SIZE(ptr, ptr->headers[i].data_length); | |
| gf_bs_read_data(bs, ptr->headers[i].data, ptr->headers[i].data_length); | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err fdpa_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_FDpacketBox *ptr = (GF_FDpacketBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->info.sender_current_time_present, 1); | |
| gf_bs_write_int(bs, ptr->info.expected_residual_time_present, 1); | |
| gf_bs_write_int(bs, ptr->info.session_close_bit, 1); | |
| gf_bs_write_int(bs, ptr->info.object_close_bit, 1); | |
| gf_bs_write_int(bs, 0, 4); | |
| gf_bs_write_u16(bs, ptr->info.transport_object_identifier); | |
| gf_bs_write_u16(bs, ptr->header_ext_count); | |
| for (i=0; i<ptr->header_ext_count; i++) { | |
| gf_bs_write_u8(bs, ptr->headers[i].header_extension_type); | |
| if (ptr->headers[i].header_extension_type > 127) { | |
| gf_bs_write_data(bs, (const char *) ptr->headers[i].content, 3); | |
| } else { | |
| gf_bs_write_u8(bs, ptr->headers[i].data_length ? (ptr->headers[i].data_length+2)/4 : 0); | |
| if (ptr->headers[i].data_length) { | |
| gf_bs_write_data(bs, ptr->headers[i].data, ptr->headers[i].data_length); | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fdpa_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_FDpacketBox *ptr = (GF_FDpacketBox *)s; | |
| ptr->size += 5; | |
| for (i=0; i<ptr->header_ext_count; i++) { | |
| ptr->size += 1; | |
| if (ptr->headers[i].header_extension_type > 127) { | |
| ptr->size += 3; | |
| } else { | |
| ptr->size += 1 + ptr->headers[i].data_length; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *extr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ExtraDataBox, GF_ISOM_BOX_TYPE_EXTR); | |
| return (GF_Box *)tmp; | |
| } | |
| void extr_box_del(GF_Box *s) | |
| { | |
| GF_ExtraDataBox *ptr = (GF_ExtraDataBox *)s; | |
| if (ptr == NULL) return; | |
| if (ptr->feci) gf_isom_box_del((GF_Box*)ptr->feci); | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Err extr_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ExtraDataBox *ptr = (GF_ExtraDataBox *)s; | |
| e = gf_isom_box_parse_ex((GF_Box**) &ptr->feci, bs, GF_ISOM_BOX_TYPE_EXTR, GF_FALSE, ptr->size); | |
| if (e) return e; | |
| if (!ptr->feci || ptr->feci->size > ptr->size) return GF_ISOM_INVALID_MEDIA; | |
| ptr->data_length = (u32) (ptr->size - ptr->feci->size); | |
| ptr->data = gf_malloc(sizeof(char)*ptr->data_length); | |
| if (!ptr->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->data, ptr->data_length); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err extr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ExtraDataBox *ptr = (GF_ExtraDataBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| if (ptr->feci) { | |
| e = gf_isom_box_write((GF_Box *)ptr->feci, bs); | |
| if (e) return e; | |
| } | |
| gf_bs_write_data(bs, ptr->data, ptr->data_length); | |
| return GF_OK; | |
| } | |
| GF_Err extr_box_size(GF_Box *s) | |
| { | |
| GF_ExtraDataBox *ptr = (GF_ExtraDataBox *) s; | |
| ptr->size += ptr->data_length; | |
| if (ptr->feci) { | |
| GF_Err e = gf_isom_box_size((GF_Box*)ptr->feci); | |
| if (e) return e; | |
| ptr->size += ptr->feci->size; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *fdsa_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_HintSample, GF_ISOM_BOX_TYPE_FDSA); | |
| if (!tmp) return NULL; | |
| tmp->packetTable = gf_list_new(); | |
| tmp->hint_subtype = GF_ISOM_BOX_TYPE_FDP_STSD; | |
| return (GF_Box*)tmp; | |
| } | |
| void fdsa_box_del(GF_Box *s) | |
| { | |
| GF_HintSample *ptr = (GF_HintSample *)s; | |
| gf_list_del(ptr->packetTable); | |
| gf_free(ptr); | |
| } | |
| GF_Err fdsa_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_HintSample *ptr = (GF_HintSample *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_FDPA: | |
| BOX_FIELD_LIST_ASSIGN(packetTable) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_EXTR: | |
| BOX_FIELD_ASSIGN(extra_data, GF_ExtraDataBox) | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fdsa_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err fdsa_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_HintSample *ptr = (GF_HintSample *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| e = gf_isom_box_array_write(s, ptr->packetTable, bs); | |
| if (e) return e; | |
| if (ptr->extra_data) { | |
| e = gf_isom_box_write((GF_Box *)ptr->extra_data, bs); | |
| if (e) return e; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err fdsa_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| #endif /*GPAC_DISABLE_ISOM_HINTING*/ | |
| void trik_box_del(GF_Box *s) | |
| { | |
| GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err trik_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s; | |
| ptr->entry_count = (u32) ptr->size; | |
| if ((u64)ptr->entry_count > (u64)SIZE_MAX/sizeof(GF_TrickPlayBoxEntry)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in trik\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->entries = (GF_TrickPlayBoxEntry *) gf_malloc(ptr->entry_count * sizeof(GF_TrickPlayBoxEntry) ); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| for (i=0; i< ptr->entry_count; i++) { | |
| ptr->entries[i].pic_type = gf_bs_read_int(bs, 2); | |
| ptr->entries[i].dependency_level = gf_bs_read_int(bs, 6); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *trik_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrickPlayBox, GF_ISOM_BOX_TYPE_TRIK); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err trik_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| for (i=0; i < ptr->entry_count; i++ ) { | |
| gf_bs_write_int(bs, ptr->entries[i].pic_type, 2); | |
| gf_bs_write_int(bs, ptr->entries[i].dependency_level, 6); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err trik_box_size(GF_Box *s) | |
| { | |
| GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s; | |
| ptr->size += 8 * ptr->entry_count; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void bloc_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err bloc_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_BaseLocationBox *ptr = (GF_BaseLocationBox *) s; | |
| ISOM_DECREASE_SIZE(s, 256) | |
| gf_bs_read_data(bs, (char *) ptr->baseLocation, 256); | |
| ptr->baseLocation[256]=0; | |
| ISOM_DECREASE_SIZE(s, 256) | |
| gf_bs_read_data(bs, (char *) ptr->basePurlLocation, 256); | |
| ISOM_DECREASE_SIZE(s, 512) | |
| ptr->basePurlLocation[256]=0; | |
| gf_bs_skip_bytes(bs, 512); | |
| return GF_OK; | |
| } | |
| GF_Box *bloc_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_BaseLocationBox, GF_ISOM_BOX_TYPE_BLOC); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err bloc_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_BaseLocationBox *ptr = (GF_BaseLocationBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_data(bs, (const char *) ptr->baseLocation, 256); | |
| gf_bs_write_data(bs, (const char *) ptr->basePurlLocation, 256); | |
| for (i=0; i < 64; i++ ) { | |
| gf_bs_write_u64(bs, 0); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err bloc_box_size(GF_Box *s) | |
| { | |
| s->size += 1024; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ainf_box_del(GF_Box *s) | |
| { | |
| GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s; | |
| if (ptr->APID) gf_free(ptr->APID); | |
| gf_free(s); | |
| } | |
| GF_Err ainf_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s; | |
| ISOM_DECREASE_SIZE(s, 4) | |
| ptr->profile_version = gf_bs_read_u32(bs); | |
| return gf_isom_read_null_terminated_string(s, bs, s->size, &ptr->APID); | |
| } | |
| GF_Box *ainf_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_AssetInformationBox, GF_ISOM_BOX_TYPE_AINF); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ainf_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->profile_version); | |
| if (ptr->APID) | |
| gf_bs_write_data(bs, ptr->APID, (u32) strlen(ptr->APID) ); | |
| gf_bs_write_u8(bs, 0); | |
| return GF_OK; | |
| } | |
| GF_Err ainf_box_size(GF_Box *s) | |
| { | |
| GF_AssetInformationBox *ptr = (GF_AssetInformationBox *) s; | |
| s->size += 4 + (ptr->APID ? strlen(ptr->APID) : 0 ) + 1; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mhac_box_del(GF_Box *s) | |
| { | |
| GF_MHAConfigBox *ptr = (GF_MHAConfigBox *) s; | |
| if (ptr->mha_config) gf_free(ptr->mha_config); | |
| gf_free(s); | |
| } | |
| GF_Err mhac_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_MHAConfigBox *ptr = (GF_MHAConfigBox *) s; | |
| ISOM_DECREASE_SIZE(s, 5) | |
| ptr->configuration_version = gf_bs_read_u8(bs); | |
| ptr->mha_pl_indication = gf_bs_read_u8(bs); | |
| ptr->reference_channel_layout = gf_bs_read_u8(bs); | |
| ptr->mha_config_size = gf_bs_read_u16(bs); | |
| if (ptr->mha_config_size) { | |
| ISOM_DECREASE_SIZE(s, ptr->mha_config_size) | |
| ptr->mha_config = gf_malloc(sizeof(char)*ptr->mha_config_size); | |
| if (!ptr->mha_config) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->mha_config, ptr->mha_config_size); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *mhac_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MHAConfigBox, GF_ISOM_BOX_TYPE_MHAC); | |
| tmp->configuration_version = 1; | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mhac_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_MHAConfigBox *ptr = (GF_MHAConfigBox *) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->configuration_version); | |
| gf_bs_write_u8(bs, ptr->mha_pl_indication); | |
| gf_bs_write_u8(bs, ptr->reference_channel_layout); | |
| gf_bs_write_u16(bs, ptr->mha_config ? ptr->mha_config_size : 0); | |
| if (ptr->mha_config && ptr->mha_config_size) | |
| gf_bs_write_data(bs, ptr->mha_config, ptr->mha_config_size); | |
| return GF_OK; | |
| } | |
| GF_Err mhac_box_size(GF_Box *s) | |
| { | |
| GF_MHAConfigBox *ptr = (GF_MHAConfigBox *) s; | |
| s->size += 5; | |
| if (ptr->mha_config_size && ptr->mha_config) s->size += ptr->mha_config_size; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mhap_box_del(GF_Box *s) | |
| { | |
| GF_MHACompatibleProfilesBox *ptr = (GF_MHACompatibleProfilesBox *) s; | |
| if (ptr->compat_profiles) gf_free(ptr->compat_profiles); | |
| gf_free(s); | |
| } | |
| GF_Err mhap_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_MHACompatibleProfilesBox *ptr = (GF_MHACompatibleProfilesBox *) s; | |
| ISOM_DECREASE_SIZE(s, 1) | |
| ptr->num_profiles = gf_bs_read_u8(bs); | |
| if (!ptr->num_profiles) return GF_OK; | |
| ISOM_DECREASE_SIZE(s, ptr->num_profiles) | |
| ptr->compat_profiles = gf_malloc(sizeof(u8) * ptr->num_profiles); | |
| if (!ptr->compat_profiles) return GF_OUT_OF_MEM; | |
| for (i=0; i<ptr->num_profiles; i++) { | |
| ptr->compat_profiles[i] = gf_bs_read_u8(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *mhap_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MHACompatibleProfilesBox, GF_ISOM_BOX_TYPE_MHAP); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mhap_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_Err e; | |
| GF_MHACompatibleProfilesBox *ptr = (GF_MHACompatibleProfilesBox *) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->num_profiles); | |
| for (i=0; i<ptr->num_profiles; i++) { | |
| gf_bs_write_u8(bs, ptr->compat_profiles[i]); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mhap_box_size(GF_Box *s) | |
| { | |
| GF_MHACompatibleProfilesBox *ptr = (GF_MHACompatibleProfilesBox *) s; | |
| s->size += 1 + ptr->num_profiles; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *jp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_JP2SignatureBox, GF_ISOM_BOX_TYPE_JP); | |
| return (GF_Box *)tmp; | |
| } | |
| void jp_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err jp_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_JP2SignatureBox *ptr = (GF_JP2SignatureBox *) s; | |
| ISOM_DECREASE_SIZE(s, 4) | |
| ptr->signature = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err jp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_JP2SignatureBox *ptr = (GF_JP2SignatureBox *) s; | |
| GF_Err e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->signature); | |
| return GF_OK; | |
| } | |
| GF_Err jp_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void jp2h_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err jp2h_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem) | |
| { | |
| GF_J2KHeaderBox *ptr = (GF_J2KHeaderBox *)s; | |
| switch(a->type) { | |
| case GF_ISOM_BOX_TYPE_IHDR: | |
| BOX_FIELD_ASSIGN(ihdr, GF_J2KImageHeaderBox) | |
| return GF_OK; | |
| case GF_ISOM_BOX_TYPE_COLR: | |
| BOX_FIELD_ASSIGN(colr, GF_ColourInformationBox) | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err jp2h_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *jp2h_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_J2KHeaderBox, GF_ISOM_BOX_TYPE_JP2H); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err jp2h_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err jp2h_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *jp2p_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_JP2ProfileBox, GF_ISOM_BOX_TYPE_JP2P); | |
| tmp->compatible_brands = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| void jp2p_box_del(GF_Box *s) | |
| { | |
| GF_JP2ProfileBox *ptr = (GF_JP2ProfileBox *) s; | |
| u32 i, count = gf_list_count(ptr->compatible_brands); | |
| for (i=0; i<count; i++) { | |
| u32 *brand = (u32 *)gf_list_get(ptr->compatible_brands, i); | |
| gf_free(brand); | |
| } | |
| gf_list_del(ptr->compatible_brands); | |
| gf_free(s); | |
| } | |
| GF_Err jp2p_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_JP2ProfileBox *ptr = (GF_JP2ProfileBox *) s; | |
| while (ptr->size) { | |
| ISOM_DECREASE_SIZE_NO_ERR(s, 4) | |
| u32 *brand = (u32 *)gf_malloc(sizeof(u32)); | |
| if (!brand) return GF_OUT_OF_MEM; | |
| *brand = gf_bs_read_u32(bs); | |
| if (gf_list_add(ptr->compatible_brands, brand) != GF_OK) | |
| return GF_OUT_OF_MEM; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err jp2p_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_JP2ProfileBox *ptr = (GF_JP2ProfileBox *) s; | |
| u32 i, count = gf_list_count(ptr->compatible_brands); | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| for (i=0; i<count; i++) { | |
| u32 *brand = (u32 *)gf_list_get(ptr->compatible_brands, i); | |
| gf_bs_write_u32(bs, *brand); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err jp2p_box_size(GF_Box *s) | |
| { | |
| GF_JP2ProfileBox *ptr = (GF_JP2ProfileBox *) s; | |
| u32 count = gf_list_count(ptr->compatible_brands); | |
| s->size += 4 * count; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *jsub_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_JP2SubSamplingBox, GF_ISOM_BOX_TYPE_JSUB); | |
| return (GF_Box *)tmp; | |
| } | |
| void jsub_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err jsub_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_JP2SubSamplingBox *ptr = (GF_JP2SubSamplingBox *) s; | |
| ISOM_DECREASE_SIZE(s, 4) | |
| ptr->horizontal_sub = gf_bs_read_u8(bs); | |
| ptr->vertical_sub = gf_bs_read_u8(bs); | |
| ptr->horizontal_offset = gf_bs_read_u8(bs); | |
| ptr->vertical_offset = gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err jsub_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_JP2SubSamplingBox *ptr = (GF_JP2SubSamplingBox *) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->horizontal_sub); | |
| gf_bs_write_u8(bs, ptr->vertical_sub); | |
| gf_bs_write_u8(bs, ptr->horizontal_offset); | |
| gf_bs_write_u8(bs, ptr->vertical_offset); | |
| return GF_OK; | |
| } | |
| GF_Err jsub_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *orfo_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_JP2OriginalFormatBox, GF_ISOM_BOX_TYPE_JSUB); | |
| return (GF_Box *)tmp; | |
| } | |
| void orfo_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err orfo_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_JP2OriginalFormatBox *ptr = (GF_JP2OriginalFormatBox *) s; | |
| ISOM_DECREASE_SIZE(s, 2) | |
| ptr->original_fieldcount = gf_bs_read_u8(bs); | |
| ptr->original_fieldorder = gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err orfo_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_JP2OriginalFormatBox *ptr = (GF_JP2OriginalFormatBox *) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->original_fieldcount); | |
| gf_bs_write_u8(bs, ptr->original_fieldorder); | |
| return GF_OK; | |
| } | |
| GF_Err orfo_box_size(GF_Box *s) | |
| { | |
| s->size += 2; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void ihdr_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err ihdr_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_J2KImageHeaderBox *ptr = (GF_J2KImageHeaderBox *) s; | |
| ISOM_DECREASE_SIZE(s, 14) | |
| ptr->height = gf_bs_read_u32(bs); | |
| ptr->width = gf_bs_read_u32(bs); | |
| ptr->nb_comp = gf_bs_read_u16(bs); | |
| ptr->bpc = gf_bs_read_u8(bs); | |
| ptr->Comp = gf_bs_read_u8(bs); | |
| ptr->UnkC = gf_bs_read_u8(bs); | |
| ptr->IPR = gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *ihdr_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_J2KImageHeaderBox, GF_ISOM_BOX_TYPE_IHDR); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ihdr_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_J2KImageHeaderBox *ptr = (GF_J2KImageHeaderBox *) s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->height); | |
| gf_bs_write_u32(bs, ptr->width); | |
| gf_bs_write_u16(bs, ptr->nb_comp); | |
| gf_bs_write_u8(bs, ptr->bpc); | |
| gf_bs_write_u8(bs, ptr->Comp); | |
| gf_bs_write_u8(bs, ptr->UnkC); | |
| gf_bs_write_u8(bs, ptr->IPR); | |
| return GF_OK; | |
| } | |
| GF_Err ihdr_box_size(GF_Box *s) | |
| { | |
| s->size += 14; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| /* Dolby Vision */ | |
| GF_Box *dvcC_box_new() | |
| { | |
| GF_DOVIConfigurationBox *tmp = (GF_DOVIConfigurationBox *)gf_malloc(sizeof(GF_DOVIConfigurationBox)); | |
| if (tmp == NULL) return NULL; | |
| memset(tmp, 0, sizeof(GF_DOVIConfigurationBox)); | |
| tmp->type = GF_ISOM_BOX_TYPE_DVCC; | |
| return (GF_Box *)tmp; | |
| } | |
| void dvcC_box_del(GF_Box *s) | |
| { | |
| GF_DOVIConfigurationBox *ptr = (GF_DOVIConfigurationBox*)s; | |
| gf_free(ptr); | |
| } | |
| GF_Err dvcC_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_DOVIConfigurationBox *ptr = (GF_DOVIConfigurationBox *)s; | |
| //GF_DOVIDecoderConfigurationRecord | |
| ISOM_DECREASE_SIZE(ptr, 24) | |
| ptr->DOVIConfig.dv_version_major = gf_bs_read_u8(bs); | |
| ptr->DOVIConfig.dv_version_minor = gf_bs_read_u8(bs); | |
| ptr->DOVIConfig.dv_profile = gf_bs_read_int(bs, 7); | |
| ptr->DOVIConfig.dv_level = gf_bs_read_int(bs, 6); | |
| ptr->DOVIConfig.rpu_present_flag = gf_bs_read_int(bs, 1); | |
| ptr->DOVIConfig.el_present_flag = gf_bs_read_int(bs, 1); | |
| ptr->DOVIConfig.bl_present_flag = gf_bs_read_int(bs, 1); | |
| ptr->DOVIConfig.dv_bl_signal_compatibility_id = gf_bs_read_int(bs, 4); | |
| ptr->DOVIConfig.dv_md_compression = gf_bs_read_int(bs, 2); | |
| for (i = 0; i < 10; i++) { | |
| ptr->DOVIConfig.dv_feature_flags[i] = gf_bs_read_int(bs, 1); | |
| } | |
| if (gf_bs_read_int(bs, 16) != 0) | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] dvcC reserved bits are not zero\n")); | |
| for (i = 0; i < 4; i++) { | |
| if (gf_bs_read_u32(bs) != 0) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] dvcC reserved bits are not zero\n")); | |
| } | |
| } | |
| switch (ptr->DOVIConfig.dv_bl_signal_compatibility_id) { | |
| case 0: | |
| case 1: | |
| case 2: | |
| case 4: | |
| case 6: | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] dvcC compatibility ID %d is not valid (only 0, 1, 2, 4 or 6 defined), patching to 0\n", ptr->DOVIConfig.dv_bl_signal_compatibility_id)); | |
| ptr->DOVIConfig.dv_bl_signal_compatibility_id = 0; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dvcC_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DOVIConfigurationBox *ptr = (GF_DOVIConfigurationBox *) s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| //GF_DOVIDecoderConfigurationRecord | |
| gf_bs_write_u8(bs, ptr->DOVIConfig.dv_version_major); | |
| gf_bs_write_u8(bs, ptr->DOVIConfig.dv_version_minor); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.dv_profile, 7); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.dv_level, 6); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.rpu_present_flag, 1); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.el_present_flag, 1); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.bl_present_flag, 1); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.dv_bl_signal_compatibility_id, 4); | |
| gf_bs_write_int(bs, ptr->DOVIConfig.dv_md_compression, 2); | |
| for (u32 i = 0; i < 10; i++) { | |
| gf_bs_write_int(bs, ptr->DOVIConfig.dv_feature_flags[i], 1); | |
| } | |
| gf_bs_write_int(bs, 0, 16); | |
| gf_bs_write_u32(bs, 0); | |
| gf_bs_write_u32(bs, 0); | |
| gf_bs_write_u32(bs, 0); | |
| gf_bs_write_u32(bs, 0); | |
| return GF_OK; | |
| } | |
| GF_Err dvcC_box_size(GF_Box *s) | |
| { | |
| GF_DOVIConfigurationBox *ptr = (GF_DOVIConfigurationBox *)s; | |
| ptr->size += 24; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *dvvC_box_new() | |
| { | |
| GF_DOVIConfigurationBox *tmp = (GF_DOVIConfigurationBox *)gf_malloc(sizeof(GF_DOVIConfigurationBox)); | |
| if (tmp == NULL) return NULL; | |
| memset(tmp, 0, sizeof(GF_DOVIConfigurationBox)); | |
| tmp->type = GF_ISOM_BOX_TYPE_DVVC; | |
| return (GF_Box *)tmp; | |
| } | |
| void dvvC_box_del(GF_Box *s) | |
| { | |
| GF_DOVIConfigurationBox *ptr = (GF_DOVIConfigurationBox*)s; | |
| gf_free(ptr); | |
| } | |
| GF_Err dvvC_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return dvcC_box_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dvvC_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return dvcC_box_write(s, bs); | |
| } | |
| GF_Err dvvC_box_size(GF_Box *s) | |
| { | |
| return dvcC_box_size(s); | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *dOps_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_OpusSpecificBox, GF_ISOM_BOX_TYPE_DOPS); | |
| return (GF_Box *)tmp; | |
| } | |
| void dOps_box_del(GF_Box *s) | |
| { | |
| GF_OpusSpecificBox *ptr = (GF_OpusSpecificBox *)s; | |
| if (ptr) gf_free(ptr); | |
| } | |
| //we don't use odf_opus_cfg read due to endianness | |
| GF_Err dOps_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_OpusSpecificBox *ptr = (GF_OpusSpecificBox *)s; | |
| ptr->opcfg.version = gf_bs_read_u8(bs); | |
| if (ptr->opcfg.version) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Opus config version not 0 !\n", ptr->size)); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| //force version to 1 as used in ogg/opus | |
| ptr->opcfg.version = 1; | |
| ptr->opcfg.OutputChannelCount = gf_bs_read_u8(bs); | |
| ptr->opcfg.PreSkip = gf_bs_read_u16(bs); | |
| ptr->opcfg.InputSampleRate = gf_bs_read_u32(bs); | |
| ptr->opcfg.OutputGain = gf_bs_read_u16(bs); | |
| ptr->opcfg.ChannelMappingFamily = gf_bs_read_u8(bs); | |
| ISOM_DECREASE_SIZE(ptr, 11) | |
| if (ptr->size) { | |
| ISOM_DECREASE_SIZE(ptr, 2+ptr->opcfg.OutputChannelCount); | |
| ptr->opcfg.StreamCount = gf_bs_read_u8(bs); | |
| ptr->opcfg.CoupledCount = gf_bs_read_u8(bs); | |
| gf_bs_read_data(bs, (char *) ptr->opcfg.ChannelMapping, ptr->opcfg.OutputChannelCount); | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| //we don't use odf_opus_cfg write due to endianness | |
| GF_Err dOps_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_OpusSpecificBox *ptr = (GF_OpusSpecificBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| //we always write 0 - the version may also be set to 1 when fed from ffenc or opus+ogg | |
| gf_bs_write_u8(bs, /*ptr->opcfg.version*/ 0); | |
| gf_bs_write_u8(bs, ptr->opcfg.OutputChannelCount); | |
| gf_bs_write_u16(bs, ptr->opcfg.PreSkip); | |
| gf_bs_write_u32(bs, ptr->opcfg.InputSampleRate); | |
| gf_bs_write_u16(bs, ptr->opcfg.OutputGain); | |
| gf_bs_write_u8(bs, ptr->opcfg.ChannelMappingFamily); | |
| if (ptr->opcfg.ChannelMappingFamily) { | |
| gf_bs_write_u8(bs, ptr->opcfg.StreamCount); | |
| gf_bs_write_u8(bs, ptr->opcfg.CoupledCount); | |
| gf_bs_write_data(bs, (char *) ptr->opcfg.ChannelMapping, ptr->opcfg.OutputChannelCount); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err dOps_box_size(GF_Box *s) | |
| { | |
| GF_OpusSpecificBox *ptr = (GF_OpusSpecificBox *)s; | |
| ptr->size += 11; | |
| if (ptr->opcfg.ChannelMappingFamily) | |
| ptr->size += 2 + ptr->opcfg.OutputChannelCount; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *iacb_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_IAConfigurationBox, GF_ISOM_BOX_TYPE_IACB); | |
| return (GF_Box *)tmp; | |
| } | |
| void iacb_box_del(GF_Box *s) | |
| { | |
| GF_IAConfigurationBox *ptr = (GF_IAConfigurationBox *)s; | |
| if (ptr->cfg) gf_odf_iamf_cfg_del(ptr->cfg); | |
| gf_free(ptr); | |
| } | |
| GF_Err iacb_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_IAConfigurationBox *ptr = (GF_IAConfigurationBox *)s; | |
| if (ptr->cfg) gf_odf_iamf_cfg_del(ptr->cfg); | |
| ptr->cfg = gf_odf_iamf_cfg_read_bs_size(bs, (u32)ptr->size); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err iacb_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_IAConfigurationBox *ptr = (GF_IAConfigurationBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| if (!ptr->cfg) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| return gf_odf_iamf_cfg_write_bs(ptr->cfg, bs); | |
| } | |
| GF_Err iacb_box_size(GF_Box *s) | |
| { | |
| GF_IAConfigurationBox *ptr = (GF_IAConfigurationBox *)s; | |
| if (!ptr->cfg) { | |
| ptr->size = 0; | |
| return GF_BAD_PARAM; | |
| } | |
| ptr->size += gf_odf_iamf_cfg_size(ptr->cfg); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void dfla_box_del(GF_Box *s) | |
| { | |
| GF_FLACConfigBox *ptr = (GF_FLACConfigBox *) s; | |
| if (ptr->data) gf_free(ptr->data); | |
| gf_free(ptr); | |
| } | |
| GF_Err dfla_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_FLACConfigBox *ptr = (GF_FLACConfigBox *) s; | |
| ptr->dataSize = (u32) ptr->size; | |
| ptr->size=0; | |
| ptr->data = gf_malloc(ptr->dataSize); | |
| gf_bs_read_data(bs, ptr->data, ptr->dataSize); | |
| return GF_OK; | |
| } | |
| GF_Box *dfla_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_FLACConfigBox, GF_ISOM_BOX_TYPE_DFLA); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dfla_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_FLACConfigBox *ptr = (GF_FLACConfigBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_data(bs, ptr->data, ptr->dataSize); | |
| return GF_OK; | |
| } | |
| GF_Err dfla_box_size(GF_Box *s) | |
| { | |
| GF_FLACConfigBox *ptr = (GF_FLACConfigBox *) s; | |
| ptr->size += ptr->dataSize; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *ddts_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_DTSSpecificBox, GF_ISOM_BOX_TYPE_DDTS); | |
| return (GF_Box *)tmp; | |
| } | |
| void ddts_box_del(GF_Box *s) | |
| { | |
| GF_DTSSpecificBox *ptr = (GF_DTSSpecificBox *)s; | |
| if (ptr) gf_free(ptr); | |
| } | |
| GF_Err ddts_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_DTSSpecificBox *ptr = (GF_DTSSpecificBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| ptr->cfg.SamplingFrequency = gf_bs_read_u32(bs); | |
| ptr->cfg.MaxBitrate = gf_bs_read_u32(bs); | |
| ptr->cfg.AvgBitrate = gf_bs_read_u32(bs); | |
| ptr->cfg.SampleDepth = gf_bs_read_u8(bs); | |
| ptr->cfg.FrameDuration = gf_bs_read_int(bs, 2); | |
| ptr->cfg.StreamConstruction = gf_bs_read_int(bs, 5); | |
| ptr->cfg.CoreLFEPresent = gf_bs_read_int(bs, 1); | |
| ptr->cfg.CoreLayout = gf_bs_read_int(bs, 6); | |
| ptr->cfg.CoreSize = gf_bs_read_int(bs, 14); | |
| ptr->cfg.StereoDownmix = gf_bs_read_int(bs, 1); | |
| ptr->cfg.RepresentationType = gf_bs_read_int(bs, 3); | |
| ptr->cfg.ChannelLayout = gf_bs_read_u16(bs); | |
| ptr->cfg.MultiAssetFlag = gf_bs_read_int(bs, 1); | |
| ptr->cfg.LBRDurationMod = gf_bs_read_int(bs, 1); | |
| gf_bs_read_int(bs, 6); // ReservedBox flag and reserved bits | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err ddts_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_DTSSpecificBox *ptr = (GF_DTSSpecificBox *)s; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->cfg.SamplingFrequency); | |
| gf_bs_write_u32(bs, ptr->cfg.MaxBitrate); | |
| gf_bs_write_u32(bs, ptr->cfg.AvgBitrate); | |
| gf_bs_write_u8(bs, ptr->cfg.SampleDepth); | |
| gf_bs_write_int(bs, ptr->cfg.FrameDuration, 2); | |
| gf_bs_write_int(bs, ptr->cfg.StreamConstruction, 5); | |
| gf_bs_write_int(bs, ptr->cfg.CoreLFEPresent, 1); | |
| gf_bs_write_int(bs, ptr->cfg.CoreLayout, 6); | |
| gf_bs_write_int(bs, ptr->cfg.CoreSize, 14); | |
| gf_bs_write_int(bs, ptr->cfg.StereoDownmix, 1); | |
| gf_bs_write_int(bs, ptr->cfg.RepresentationType, 3); | |
| gf_bs_write_u16(bs, ptr->cfg.ChannelLayout); | |
| gf_bs_write_int(bs, ptr->cfg.MultiAssetFlag, 1); | |
| gf_bs_write_int(bs, ptr->cfg.LBRDurationMod, 1); | |
| gf_bs_write_int(bs, 0, 6); // ReservedBoxPresent and reserved bits | |
| return GF_OK; | |
| } | |
| GF_Err ddts_box_size(GF_Box *s) | |
| { | |
| GF_DTSSpecificBox *ptr = (GF_DTSSpecificBox *)s; | |
| ptr->size += 20; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *udts_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_UDTSSpecificBox, GF_ISOM_BOX_TYPE_UDTS); | |
| return (GF_Box *)tmp; | |
| } | |
| void udts_box_del(GF_Box *s) | |
| { | |
| GF_UDTSSpecificBox *ptr = (GF_UDTSSpecificBox *)s; | |
| if (ptr) { | |
| if (ptr->cfg.PresentationIDTagData) gf_free(ptr->cfg.PresentationIDTagData); | |
| if (ptr->cfg.ExpansionBoxData) gf_free(ptr->cfg.ExpansionBoxData); | |
| gf_free(ptr); | |
| } | |
| } | |
| GF_Err udts_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_UDTSSpecificBox *ptr = (GF_UDTSSpecificBox *)s; | |
| u32 i, bits; | |
| ISOM_DECREASE_SIZE(ptr, 6); | |
| ptr->cfg.DecoderProfileCode = gf_bs_read_int(bs, 6); | |
| ptr->cfg.FrameDurationCode = gf_bs_read_int(bs, 2); | |
| ptr->cfg.MaxPayloadCode = gf_bs_read_int(bs, 3); | |
| ptr->cfg.NumPresentationsCode = gf_bs_read_int(bs, 5); | |
| ptr->cfg.ChannelMask = gf_bs_read_u32(bs); | |
| //non-aligned syntax, count bits | |
| bits = 10; | |
| ptr->cfg.BaseSamplingFrequencyCode = gf_bs_read_int(bs, 1); | |
| ptr->cfg.SampleRateMod = gf_bs_read_int(bs, 2); | |
| ptr->cfg.RepresentationType = gf_bs_read_int(bs, 3); | |
| ptr->cfg.StreamIndex = gf_bs_read_int(bs, 3); | |
| ptr->cfg.ExpansionBoxPresent = gf_bs_read_int(bs, 1); | |
| ptr->cfg.PresentationIDTagDataSize = 0; | |
| for (i=0; i<=ptr->cfg.NumPresentationsCode; i++) { | |
| ptr->cfg.IDTagPresent[i] = gf_bs_read_int(bs, 1); | |
| bits++; | |
| ptr->cfg.PresentationIDTagDataSize += 16 * (ptr->cfg.IDTagPresent[i] != 0); | |
| } | |
| bits+= gf_bs_align(bs); | |
| bits/=8; | |
| ISOM_DECREASE_SIZE(ptr, bits); | |
| if (ptr->cfg.PresentationIDTagDataSize > 0) { | |
| ISOM_DECREASE_SIZE(ptr, ptr->cfg.PresentationIDTagDataSize); | |
| ptr->cfg.PresentationIDTagData = gf_realloc(ptr->cfg.PresentationIDTagData, ptr->cfg.PresentationIDTagDataSize); | |
| if (!ptr->cfg.PresentationIDTagData) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->cfg.PresentationIDTagData, ptr->cfg.PresentationIDTagDataSize); | |
| } | |
| //leftover | |
| if (ptr->size && ptr->cfg.ExpansionBoxPresent) { | |
| ptr->cfg.ExpansionBoxDataSize = (u32) ptr->size; | |
| ISOM_DECREASE_SIZE(ptr, ptr->cfg.ExpansionBoxDataSize); | |
| ptr->cfg.ExpansionBoxData = gf_realloc(ptr->cfg.ExpansionBoxData, ptr->cfg.ExpansionBoxDataSize); | |
| if (!ptr->cfg.ExpansionBoxData) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->cfg.ExpansionBoxData, ptr->cfg.ExpansionBoxDataSize); | |
| } else { | |
| ptr->cfg.ExpansionBoxPresent = 0; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err udts_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_UDTSSpecificBox *ptr = (GF_UDTSSpecificBox *)s; | |
| u8 i; | |
| if (!s) return GF_BAD_PARAM; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ptr->cfg.DecoderProfileCode, 6); | |
| gf_bs_write_int(bs, ptr->cfg.FrameDurationCode, 2); | |
| gf_bs_write_int(bs, ptr->cfg.MaxPayloadCode, 3); | |
| gf_bs_write_int(bs, ptr->cfg.NumPresentationsCode, 5); | |
| gf_bs_write_u32(bs, ptr->cfg.ChannelMask); | |
| gf_bs_write_int(bs, ptr->cfg.BaseSamplingFrequencyCode, 1); | |
| gf_bs_write_int(bs, ptr->cfg.SampleRateMod, 2); | |
| gf_bs_write_int(bs, ptr->cfg.RepresentationType, 3); | |
| gf_bs_write_int(bs, ptr->cfg.StreamIndex, 3); | |
| gf_bs_write_int(bs, ptr->cfg.ExpansionBoxPresent, 1); | |
| for (i=0; i<=ptr->cfg.NumPresentationsCode; i++) | |
| gf_bs_write_int(bs, ptr->cfg.IDTagPresent[i], 1); | |
| gf_bs_align(bs); | |
| if (ptr->cfg.PresentationIDTagData && ptr->cfg.PresentationIDTagDataSize) | |
| gf_bs_write_data(bs, ptr->cfg.PresentationIDTagData, ptr->cfg.PresentationIDTagDataSize); | |
| if (ptr->cfg.ExpansionBoxData && ptr->cfg.ExpansionBoxDataSize) | |
| gf_bs_write_data(bs, ptr->cfg.ExpansionBoxData, ptr->cfg.ExpansionBoxDataSize); | |
| return GF_OK; | |
| } | |
| GF_Err udts_box_size(GF_Box *s) | |
| { | |
| GF_UDTSSpecificBox *ptr = (GF_UDTSSpecificBox *)s; | |
| u32 bits = 58 + ptr->cfg.NumPresentationsCode + 1; // 58 bits for fixed fields | |
| ptr->size += (bits + 7) / 8; // align to next byte | |
| ptr->size += ptr->cfg.PresentationIDTagDataSize + ptr->cfg.ExpansionBoxDataSize; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void mvcg_box_del(GF_Box *s) | |
| { | |
| GF_MultiviewGroupBox *ptr = (GF_MultiviewGroupBox *) s; | |
| if (ptr->entries) gf_free(ptr->entries); | |
| gf_free(ptr); | |
| } | |
| GF_Err mvcg_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_MultiviewGroupBox *ptr = (GF_MultiviewGroupBox *) s; | |
| ISOM_DECREASE_SIZE(s, 7) | |
| ptr->multiview_group_id = gf_bs_read_u32(bs); | |
| ptr->num_entries = gf_bs_read_u16(bs); | |
| gf_bs_read_u8(bs); | |
| ptr->entries = gf_malloc(ptr->num_entries * sizeof(MVCIEntry)); | |
| if (!ptr->entries) return GF_OUT_OF_MEM; | |
| memset(ptr->entries, 0, ptr->num_entries * sizeof(MVCIEntry)); | |
| for (i=0; i<ptr->num_entries; i++) { | |
| ISOM_DECREASE_SIZE(s, 1) | |
| ptr->entries[i].entry_type = gf_bs_read_u8(bs); | |
| switch (ptr->entries[i].entry_type) { | |
| case 0: | |
| ISOM_DECREASE_SIZE(s, 4) | |
| ptr->entries[i].trackID = gf_bs_read_u32(bs); | |
| break; | |
| case 1: | |
| ISOM_DECREASE_SIZE(s, 6) | |
| ptr->entries[i].trackID = gf_bs_read_u32(bs); | |
| ptr->entries[i].tierID = gf_bs_read_u16(bs); | |
| break; | |
| case 2: | |
| ISOM_DECREASE_SIZE(s, 2) | |
| gf_bs_read_int(bs, 6); | |
| ptr->entries[i].output_view_id = gf_bs_read_int(bs, 10); | |
| break; | |
| case 3: | |
| ISOM_DECREASE_SIZE(s, 4) | |
| gf_bs_read_int(bs, 6) ; | |
| ptr->entries[i].start_view_id = gf_bs_read_int(bs, 10); | |
| ptr->entries[i].view_count = gf_bs_read_u16(bs); | |
| break; | |
| } | |
| } | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| GF_Box *mvcg_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_MultiviewGroupBox, GF_ISOM_BOX_TYPE_MVCG); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err mvcg_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i; | |
| GF_MultiviewGroupBox *ptr = (GF_MultiviewGroupBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->multiview_group_id); | |
| gf_bs_write_u16(bs, ptr->num_entries); | |
| gf_bs_write_u8(bs, 0); | |
| for (i=0; i<ptr->num_entries; i++) { | |
| gf_bs_write_u8(bs, ptr->entries[i].entry_type); | |
| switch (ptr->entries[i].entry_type) { | |
| case 0: | |
| gf_bs_write_u32(bs, ptr->entries[i].trackID); | |
| break; | |
| case 1: | |
| gf_bs_write_u32(bs, ptr->entries[i].trackID); | |
| gf_bs_write_u16(bs, ptr->entries[i].tierID); | |
| break; | |
| case 2: | |
| gf_bs_write_int(bs, 0, 6); | |
| gf_bs_write_int(bs, ptr->entries[i].output_view_id, 10); | |
| break; | |
| case 3: | |
| gf_bs_write_int(bs, 0, 6) ; | |
| gf_bs_write_int(bs, ptr->entries[i].start_view_id, 10); | |
| gf_bs_write_u16(bs, ptr->entries[i].view_count); | |
| break; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err mvcg_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_MultiviewGroupBox *ptr = (GF_MultiviewGroupBox *) s; | |
| ptr->size += 7; | |
| for (i=0; i<ptr->num_entries; i++) { | |
| switch (ptr->entries[i].entry_type) { | |
| case 0: | |
| ptr->size += 1 + 4; | |
| break; | |
| case 1: | |
| ptr->size += 1 + 6; | |
| break; | |
| case 2: | |
| ptr->size += 1 + 2; | |
| break; | |
| case 3: | |
| ptr->size += 1 + 4; | |
| break; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void vwid_box_del(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_ViewIdentifierBox *ptr = (GF_ViewIdentifierBox *) s; | |
| if (ptr->views) { | |
| for (i=0; i<ptr->num_views; i++) { | |
| if (ptr->views[i].view_refs) | |
| gf_free(ptr->views[i].view_refs); | |
| } | |
| gf_free(ptr->views); | |
| } | |
| gf_free(ptr); | |
| } | |
| GF_Err vwid_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_ViewIdentifierBox *ptr = (GF_ViewIdentifierBox *) s; | |
| ISOM_DECREASE_SIZE(s, 3) | |
| gf_bs_read_int(bs, 2); | |
| ptr->min_temporal_id = gf_bs_read_int(bs, 3); | |
| ptr->max_temporal_id = gf_bs_read_int(bs, 3); | |
| ptr->num_views = gf_bs_read_u16(bs); | |
| if (ptr->num_views > ptr->size / 6) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->views = gf_malloc(sizeof(ViewIDEntry)*ptr->num_views); | |
| memset(ptr->views, 0, sizeof(ViewIDEntry)*ptr->num_views); | |
| for (i=0; i<ptr->num_views; i++) { | |
| u32 j; | |
| ISOM_DECREASE_SIZE(s, 6) | |
| gf_bs_read_int(bs, 6); | |
| ptr->views[i].view_id = gf_bs_read_int(bs, 10); | |
| gf_bs_read_int(bs, 6); | |
| ptr->views[i].view_order_index = gf_bs_read_int(bs, 10); | |
| ptr->views[i].texture_in_stream = gf_bs_read_int(bs, 1); | |
| ptr->views[i].texture_in_track = gf_bs_read_int(bs, 1); | |
| ptr->views[i].depth_in_stream = gf_bs_read_int(bs, 1); | |
| ptr->views[i].depth_in_track = gf_bs_read_int(bs, 1); | |
| ptr->views[i].base_view_type = gf_bs_read_int(bs, 2); | |
| ptr->views[i].num_ref_views = gf_bs_read_int(bs, 10); | |
| if (ptr->views[i].num_ref_views > ptr->size / 2) | |
| return GF_ISOM_INVALID_FILE; | |
| ptr->views[i].view_refs = gf_malloc(sizeof(ViewIDRefViewEntry)*ptr->views[i].num_ref_views); | |
| for (j=0; j<ptr->views[i].num_ref_views; j++) { | |
| ISOM_DECREASE_SIZE(s, 2) | |
| gf_bs_read_int(bs, 4); | |
| ptr->views[i].view_refs[j].dep_comp_idc = gf_bs_read_int(bs, 2); | |
| ptr->views[i].view_refs[j].ref_view_id = gf_bs_read_int(bs, 10); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *vwid_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ViewIdentifierBox, GF_ISOM_BOX_TYPE_VWID); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err vwid_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 i, j; | |
| GF_ViewIdentifierBox *ptr = (GF_ViewIdentifierBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_int(bs, 0, 2); | |
| gf_bs_write_int(bs, ptr->min_temporal_id, 3); | |
| gf_bs_write_int(bs, ptr->max_temporal_id, 3); | |
| gf_bs_write_u16(bs, ptr->num_views); | |
| for (i=0; i<ptr->num_views; i++) { | |
| gf_bs_write_int(bs, 0, 6); | |
| gf_bs_write_int(bs, ptr->views[i].view_id, 10); | |
| gf_bs_write_int(bs, 0, 6); | |
| gf_bs_write_int(bs, ptr->views[i].view_order_index, 10); | |
| gf_bs_write_int(bs, ptr->views[i].texture_in_stream, 1); | |
| gf_bs_write_int(bs, ptr->views[i].texture_in_track, 1); | |
| gf_bs_write_int(bs, ptr->views[i].depth_in_stream, 1); | |
| gf_bs_write_int(bs, ptr->views[i].depth_in_track, 1); | |
| gf_bs_write_int(bs, ptr->views[i].base_view_type, 2); | |
| gf_bs_write_int(bs, ptr->views[i].num_ref_views, 10); | |
| for (j=0; j<ptr->views[i].num_ref_views; j++) { | |
| gf_bs_write_int(bs, 0, 4); | |
| gf_bs_write_int(bs, ptr->views[i].view_refs[j].dep_comp_idc, 2); | |
| gf_bs_write_int(bs, ptr->views[i].view_refs[j].ref_view_id, 10); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err vwid_box_size(GF_Box *s) | |
| { | |
| u32 i; | |
| GF_ViewIdentifierBox *ptr = (GF_ViewIdentifierBox *) s; | |
| ptr->size += 3; | |
| for (i=0; i<ptr->num_views; i++) { | |
| ptr->size += 6 + 2 * ptr->views[i].num_ref_views; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void pcmC_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err pcmC_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_PCMConfigBox *ptr = (GF_PCMConfigBox *) s; | |
| ISOM_DECREASE_SIZE(s, 2) | |
| ptr->format_flags = gf_bs_read_u8(bs); | |
| ptr->PCM_sample_size = gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| GF_Box *pcmC_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_PCMConfigBox, GF_ISOM_BOX_TYPE_PCMC); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err pcmC_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_PCMConfigBox *ptr = (GF_PCMConfigBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->format_flags); | |
| gf_bs_write_u8(bs, ptr->PCM_sample_size); | |
| return GF_OK; | |
| } | |
| GF_Err pcmC_box_size(GF_Box *s) | |
| { | |
| s->size += 2; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void chnl_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err chnl_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_ChannelLayoutBox *ptr = (GF_ChannelLayoutBox *) s; | |
| ISOM_DECREASE_SIZE(s, 1) | |
| if (ptr->version==0) { | |
| ptr->layout.stream_structure = gf_bs_read_u8(bs); | |
| } else { | |
| ptr->layout.stream_structure = gf_bs_read_int(bs, 4); | |
| ptr->layout.format_ordering = gf_bs_read_int(bs, 4); | |
| ISOM_DECREASE_SIZE(s, 1) | |
| ptr->layout.base_channel_count = gf_bs_read_u8(bs); | |
| } | |
| if (ptr->layout.stream_structure & 1) { | |
| ISOM_DECREASE_SIZE(s, 1) | |
| ptr->layout.definedLayout = gf_bs_read_u8(bs); | |
| if (ptr->layout.definedLayout==0) { | |
| u32 remain = (u32) ptr->size; | |
| if (ptr->layout.stream_structure & 2) remain--; | |
| ptr->layout.channels_count = 0; | |
| u32 nb_channels = 0; | |
| if (ptr->version) { | |
| ISOM_DECREASE_SIZE(s, 1) | |
| nb_channels = gf_bs_read_u8(bs); | |
| } | |
| while (remain) { | |
| if (ptr->layout.channels_count==64) return GF_ISOM_INVALID_FILE; | |
| ISOM_DECREASE_SIZE(s, 1) | |
| ptr->layout.layouts[ptr->layout.channels_count].position = gf_bs_read_u8(bs); | |
| remain--; | |
| if (ptr->layout.layouts[ptr->layout.channels_count].position == 126) { | |
| ISOM_DECREASE_SIZE(s, 3) | |
| ptr->layout.layouts[ptr->layout.channels_count].azimuth = gf_bs_read_int(bs, 16); | |
| ptr->layout.layouts[ptr->layout.channels_count].elevation = gf_bs_read_int(bs, 8); | |
| remain-=3; | |
| } | |
| ptr->layout.channels_count++; | |
| if (ptr->version) { | |
| nb_channels--; | |
| if (!nb_channels) break; | |
| } | |
| } | |
| } else { | |
| if (ptr->version==0) { | |
| ISOM_DECREASE_SIZE(s, 8) | |
| ptr->layout.omittedChannelsMap = gf_bs_read_u64(bs); | |
| ptr->layout.omitted_channels_present = 1; | |
| ptr->layout.channel_order_definition = 0; | |
| } else { | |
| ISOM_DECREASE_SIZE(s, 1) | |
| gf_bs_read_int(bs, 4); | |
| ptr->layout.channel_order_definition = gf_bs_read_int(bs, 3); | |
| ptr->layout.omitted_channels_present = gf_bs_read_int(bs, 1); | |
| if (ptr->layout.omitted_channels_present) { | |
| ISOM_DECREASE_SIZE(s, 8) | |
| ptr->layout.omittedChannelsMap = gf_bs_read_u64(bs); | |
| } | |
| } | |
| } | |
| } | |
| if ((ptr->version==0) && (ptr->layout.stream_structure & 2)) { | |
| ISOM_DECREASE_SIZE(s, 1) | |
| ptr->layout.object_count = gf_bs_read_u8(bs); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *chnl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ChannelLayoutBox, GF_ISOM_BOX_TYPE_CHNL); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err chnl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ChannelLayoutBox *ptr = (GF_ChannelLayoutBox *) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version==0) { | |
| gf_bs_write_u8(bs, ptr->layout.stream_structure); | |
| } else { | |
| gf_bs_write_int(bs, ptr->layout.stream_structure, 4); | |
| gf_bs_write_int(bs, ptr->layout.format_ordering, 4); | |
| gf_bs_write_u8(bs, ptr->layout.base_channel_count); | |
| } | |
| if (ptr->layout.stream_structure & 1) { | |
| gf_bs_write_u8(bs, ptr->layout.definedLayout); | |
| if (ptr->layout.definedLayout==0) { | |
| u32 i; | |
| if (ptr->version==1) { | |
| gf_bs_write_u8(bs, ptr->layout.channels_count); | |
| } | |
| for (i=0; i<ptr->layout.channels_count; i++) { | |
| gf_bs_write_u8(bs, ptr->layout.layouts[i].position); | |
| if (ptr->layout.layouts[i].position==126) { | |
| gf_bs_write_int(bs, ptr->layout.layouts[i].azimuth, 16); | |
| gf_bs_write_int(bs, ptr->layout.layouts[i].elevation, 8); | |
| } | |
| } | |
| } else { | |
| if (ptr->version==1) { | |
| gf_bs_write_int(bs, 0, 4); | |
| gf_bs_write_int(bs, ptr->layout.channel_order_definition, 3); | |
| gf_bs_write_int(bs, ptr->layout.omitted_channels_present, 1); | |
| if (ptr->layout.omitted_channels_present) | |
| gf_bs_write_u64(bs, ptr->layout.omittedChannelsMap); | |
| } else { | |
| gf_bs_write_u64(bs, ptr->layout.omittedChannelsMap); | |
| } | |
| } | |
| } | |
| if ((ptr->version==0) && (ptr->layout.stream_structure & 2)) { | |
| gf_bs_write_u8(bs, ptr->layout.object_count); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err chnl_box_size(GF_Box *s) | |
| { | |
| GF_ChannelLayoutBox *ptr = (GF_ChannelLayoutBox *) s; | |
| s->size += 1; | |
| if (ptr->version==1) s->size++; | |
| if (ptr->layout.stream_structure & 1) { | |
| s->size += 1; | |
| if (ptr->layout.definedLayout==0) { | |
| u32 i; | |
| if (ptr->version==1) s->size++; | |
| for (i=0; i<ptr->layout.channels_count; i++) { | |
| s->size+=1; | |
| if (ptr->layout.layouts[i].position==126) | |
| s->size+=3; | |
| } | |
| } else { | |
| if (ptr->version==1) { | |
| s->size += 1; | |
| if (ptr->layout.omitted_channels_present) | |
| s->size += 8; | |
| } else { | |
| s->size += 8; | |
| } | |
| } | |
| } | |
| if ((ptr->version==0) && (ptr->layout.stream_structure & 2)) { | |
| s->size += 1; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *emsg_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_EventMessageBox, GF_ISOM_BOX_TYPE_EMSG); | |
| return (GF_Box *)tmp; | |
| } | |
| void emsg_box_del(GF_Box *s) | |
| { | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->scheme_id_uri) gf_free(ptr->scheme_id_uri); | |
| if (ptr->value) gf_free(ptr->value); | |
| if (ptr->message_data) gf_free(ptr->message_data); | |
| gf_free(ptr); | |
| } | |
| GF_Err emsg_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox*) s; | |
| if (ptr->version==0) { | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_id_uri); | |
| if (e) return e; | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->value); | |
| if (e) return e; | |
| ISOM_DECREASE_SIZE(ptr, 16); | |
| ptr->timescale = gf_bs_read_u32(bs); | |
| ptr->presentation_time_delta = gf_bs_read_u32(bs); | |
| ptr->event_duration = gf_bs_read_u32(bs); | |
| ptr->event_id = gf_bs_read_u32(bs); | |
| } else if (ptr->version==1) { | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| ptr->timescale = gf_bs_read_u32(bs); | |
| ptr->presentation_time_delta = gf_bs_read_u64(bs); | |
| ptr->event_duration = gf_bs_read_u32(bs); | |
| ptr->event_id = gf_bs_read_u32(bs); | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_id_uri); | |
| if (e) return e; | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->value); | |
| if (e) return e; | |
| } else { | |
| return GF_OK; | |
| } | |
| if (ptr->size) { | |
| if (ptr->size>0xFFFFFFFUL) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] emsg message data size too big ("LLU") to be loaded\n", ptr->size)); | |
| return GF_OUT_OF_MEM; | |
| } | |
| ptr->message_data_size = (u32) ptr->size; | |
| ptr->message_data = gf_malloc(ptr->message_data_size); | |
| if (!ptr->message_data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->message_data, ptr->message_data_size); | |
| ptr->size = 0; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err emsg_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 len; | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox*) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->version==1) { | |
| gf_bs_write_u32(bs, ptr->timescale); | |
| gf_bs_write_u64(bs, ptr->presentation_time_delta); | |
| gf_bs_write_u32(bs, ptr->event_duration); | |
| gf_bs_write_u32(bs, ptr->event_id); | |
| } | |
| len = ptr->scheme_id_uri ? (u32) strlen(ptr->scheme_id_uri) : 0; | |
| if (len) gf_bs_write_data(bs, ptr->scheme_id_uri, len); | |
| gf_bs_write_u8(bs, 0); | |
| len = ptr->value ? (u32) strlen(ptr->value) : 0; | |
| if (len) gf_bs_write_data(bs, ptr->value, len); | |
| gf_bs_write_u8(bs, 0); | |
| if (ptr->version==0) { | |
| gf_bs_write_u32(bs, ptr->timescale); | |
| gf_bs_write_u32(bs, (u32) ptr->presentation_time_delta); | |
| gf_bs_write_u32(bs, ptr->event_duration); | |
| gf_bs_write_u32(bs, ptr->event_id); | |
| } | |
| if (ptr->message_data) | |
| gf_bs_write_data(bs, ptr->message_data, ptr->message_data_size); | |
| return GF_OK; | |
| } | |
| GF_Err emsg_box_size(GF_Box *s) | |
| { | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox*) s; | |
| if (ptr->version) { | |
| ptr->size += 20; | |
| } else { | |
| ptr->size += 16; | |
| } | |
| ptr->size+=2; //1 NULL-terminated strings | |
| if (ptr->scheme_id_uri) ptr->size += strlen(ptr->scheme_id_uri); | |
| if (ptr->value) ptr->size += strlen(ptr->value); | |
| if (ptr->message_data) | |
| ptr->size += ptr->message_data_size; | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *silb_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SchemeIdListBox, GF_ISOM_BOX_TYPE_SILB); | |
| return (GF_Box *)tmp; | |
| } | |
| void silb_box_del(GF_Box *s) | |
| { | |
| GF_SchemeIdListBox *ptr = (GF_SchemeIdListBox *) s; | |
| if (ptr == NULL) return; | |
| while (gf_list_count(ptr->schemes)) { | |
| GF_SchemeIdListBoxEntry *ent = (GF_SchemeIdListBoxEntry *)gf_list_get(ptr->schemes, 0); | |
| gf_free(ent->scheme_id_uri); | |
| gf_free(ent->value); | |
| gf_free(ent); | |
| gf_list_rem(ptr->schemes, 0); | |
| } | |
| gf_list_del(ptr->schemes); | |
| gf_free(ptr); | |
| } | |
| GF_Err silb_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SchemeIdListBox *ptr = (GF_SchemeIdListBox*) s; | |
| ptr->number_of_schemes = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(ptr, 4+ptr->number_of_schemes*sizeof(GF_SchemeIdListBoxEntry)+1); | |
| if (ptr->number_of_schemes) { | |
| ptr->schemes = gf_list_new(); | |
| if (!ptr->schemes) return GF_OUT_OF_MEM; | |
| for (u32 i=0; i<ptr->number_of_schemes; i++) { | |
| GF_SchemeIdListBoxEntry *ent = gf_malloc(sizeof(GF_SchemeIdListBoxEntry)); | |
| if (!ent) return GF_OUT_OF_MEM; | |
| memset(ent, 0, sizeof(GF_SchemeIdListBoxEntry)); | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ent->scheme_id_uri); | |
| if (e) { | |
| gf_free(ent); | |
| return e; | |
| } | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ent->value); | |
| if (e) { | |
| if (ent->scheme_id_uri) gf_free(ent->scheme_id_uri); | |
| gf_free(ent); | |
| return e; | |
| } | |
| ent->reserved = gf_bs_read_int(bs, 7); | |
| ent->atleast_once_flag = gf_bs_read_int(bs, 1); | |
| gf_list_add(ptr->schemes, ent); | |
| } | |
| } | |
| ptr->reserved = gf_bs_read_int(bs, 7); | |
| ptr->other_schemes_flag = gf_bs_read_int(bs, 1); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err silb_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SchemeIdListBox *ptr = (GF_SchemeIdListBox*) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->number_of_schemes); | |
| for (u32 i=0; i<ptr->number_of_schemes; i++) { | |
| GF_SchemeIdListBoxEntry *ent = gf_list_get(ptr->schemes, i); | |
| u32 len = ent->scheme_id_uri ? (u32) strlen(ent->scheme_id_uri) : 0; | |
| if (len) gf_bs_write_data(bs, ent->scheme_id_uri, len); | |
| gf_bs_write_u8(bs, 0); | |
| len = ent->value ? (u32) strlen(ent->value) : 0; | |
| if (len) gf_bs_write_data(bs, ent->value, len); | |
| gf_bs_write_u8(bs, 0); | |
| gf_bs_write_int(bs, ent->reserved, 7); | |
| gf_bs_write_int(bs, ent->atleast_once_flag, 1); | |
| } | |
| gf_bs_write_int(bs, ptr->reserved, 7); | |
| gf_bs_write_int(bs, ptr->other_schemes_flag, 1); | |
| return GF_OK; | |
| } | |
| GF_Err silb_box_size(GF_Box *s) | |
| { | |
| GF_SchemeIdListBox *ptr = (GF_SchemeIdListBox*) s; | |
| ptr->size += 4; //number_of_schemes | |
| for (u32 i=0; i<ptr->number_of_schemes; i++) { | |
| GF_SchemeIdListBoxEntry *ent = gf_list_get(ptr->schemes, i); | |
| if (!ent) return GF_BAD_PARAM; | |
| ptr->size += 2; //2 NULL-terminated strings | |
| if (ent->scheme_id_uri) ptr->size += strlen(ent->scheme_id_uri); | |
| if (ent->value) ptr->size += strlen(ent->value); | |
| ptr->size += 1; //reserved + atleast_once_flag | |
| } | |
| ptr->size += 1; //reserved + other_schemes_flag | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *emib_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_EventMessageBox, GF_ISOM_BOX_TYPE_EMIB); | |
| return (GF_Box *)tmp; | |
| } | |
| void emib_box_del(GF_Box *s) | |
| { | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox *) s; | |
| if (ptr == NULL) return; | |
| if (ptr->scheme_id_uri) gf_free(ptr->scheme_id_uri); | |
| if (ptr->value) gf_free(ptr->value); | |
| if (ptr->message_data) gf_free(ptr->message_data); | |
| gf_free(ptr); | |
| } | |
| GF_Err emib_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox*) s; | |
| ISOM_DECREASE_SIZE(ptr, 20); | |
| gf_bs_read_u32(bs); /*reserved*/ | |
| ptr->presentation_time_delta = gf_bs_read_u64(bs); | |
| ptr->event_duration = gf_bs_read_u32(bs); | |
| ptr->event_id = gf_bs_read_u32(bs); | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_id_uri); | |
| if (e) return e; | |
| e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->value); | |
| if (e) return e; | |
| if (ptr->size) { | |
| if (ptr->size>0xFFFFFFFUL) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] emib message data size too big ("LLU") to be loaded\n", ptr->size)); | |
| return GF_OUT_OF_MEM; | |
| } | |
| ptr->message_data_size = (u32) ptr->size; | |
| ptr->message_data = gf_malloc(ptr->message_data_size); | |
| if (!ptr->message_data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->message_data, ptr->message_data_size); | |
| ptr->size = 0; | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err emib_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| u32 len; | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox*) s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, 0); /*reserved*/ | |
| gf_bs_write_u64(bs, ptr->presentation_time_delta); | |
| gf_bs_write_u32(bs, ptr->event_duration); | |
| gf_bs_write_u32(bs, ptr->event_id); | |
| len = ptr->scheme_id_uri ? (u32) strlen(ptr->scheme_id_uri) : 0; | |
| if (len) gf_bs_write_data(bs, ptr->scheme_id_uri, len); | |
| gf_bs_write_u8(bs, 0); | |
| len = ptr->value ? (u32) strlen(ptr->value) : 0; | |
| if (len) gf_bs_write_data(bs, ptr->value, len); | |
| gf_bs_write_u8(bs, 0); | |
| if (ptr->message_data) | |
| gf_bs_write_data(bs, ptr->message_data, ptr->message_data_size); | |
| return GF_OK; | |
| } | |
| GF_Err emib_box_size(GF_Box *s) | |
| { | |
| GF_EventMessageBox *ptr = (GF_EventMessageBox*) s; | |
| ptr->size += 20; | |
| ptr->size += 2; //1 NULL-terminated strings | |
| if (ptr->scheme_id_uri) ptr->size += strlen(ptr->scheme_id_uri); | |
| if (ptr->value) ptr->size += strlen(ptr->value); | |
| if (ptr->message_data) | |
| ptr->size += ptr->message_data_size; | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *emeb_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Box, GF_ISOM_BOX_TYPE_EMEB); | |
| return (GF_Box *)tmp; | |
| } | |
| void emeb_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err emeb_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err emeb_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err emeb_box_size(GF_Box *s) | |
| { | |
| (void)s; | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *evte_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Box, GF_ISOM_BOX_TYPE_EVTE); | |
| return (GF_Box *)tmp; | |
| } | |
| void evte_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err evte_box_read(GF_Box *s,GF_BitStream *bs) | |
| { | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err evte_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err evte_box_size(GF_Box *s) | |
| { | |
| (void)s; | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *csgp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_CompactSampleGroupBox, GF_ISOM_BOX_TYPE_CSGP); | |
| return (GF_Box *)tmp; | |
| } | |
| void csgp_box_del(GF_Box *a) | |
| { | |
| GF_CompactSampleGroupBox *p = (GF_CompactSampleGroupBox *)a; | |
| if (p->patterns) { | |
| u32 i; | |
| for (i=0; i<p->pattern_count; i++) { | |
| if (p->patterns[i].sample_group_description_indices) | |
| gf_free(p->patterns[i].sample_group_description_indices); | |
| } | |
| gf_free(p->patterns); | |
| } | |
| gf_free(p); | |
| } | |
| u32 get_size_by_code(u32 code) | |
| { | |
| if (code==0) return 4; | |
| if (code==1) return 8; | |
| if (code==2) return 16; | |
| return 32; | |
| } | |
| GF_Err csgp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i, bits, gidx_mask; | |
| Bool index_msb_indicates_fragment_local_description, grouping_type_parameter_present; | |
| u32 pattern_size, scount_size, index_size; | |
| GF_CompactSampleGroupBox *ptr = (GF_CompactSampleGroupBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->version = gf_bs_read_u8(bs); | |
| ptr->flags = gf_bs_read_u24(bs); | |
| index_msb_indicates_fragment_local_description = (ptr->flags & (1<<7)) ? GF_TRUE : GF_FALSE; | |
| grouping_type_parameter_present = (ptr->flags & (1<<6)) ? GF_TRUE : GF_FALSE; | |
| pattern_size = get_size_by_code( ((ptr->flags>>4) & 0x3) ); | |
| scount_size = get_size_by_code( ((ptr->flags>>2) & 0x3) ); | |
| index_size = get_size_by_code( (ptr->flags & 0x3) ); | |
| if (((pattern_size==4) && (scount_size!=4)) || ((pattern_size!=4) && (scount_size==4))) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] compact sample group pattern_size and sample_count_size mare not both 4 bits\n")); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->grouping_type = gf_bs_read_u32(bs); | |
| if (grouping_type_parameter_present) { | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->grouping_type_parameter = gf_bs_read_u32(bs); | |
| } | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->pattern_count = gf_bs_read_u32(bs); | |
| if ( (ptr->size / ( (pattern_size + scount_size) / 8 ) < ptr->pattern_count) || (u64)ptr->pattern_count > (u64)SIZE_MAX/sizeof(GF_CompactSampleGroupPattern) ) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] compact sample group pattern_count value (%lu) invalid\n", ptr->pattern_count)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->patterns = gf_malloc(sizeof(GF_CompactSampleGroupPattern) * ptr->pattern_count); | |
| if (!ptr->patterns) return GF_OUT_OF_MEM; | |
| memset(ptr->patterns, 0, sizeof(GF_CompactSampleGroupPattern) * ptr->pattern_count); | |
| u64 patterns_sizes=0; | |
| bits = 0; | |
| for (i=0; i<ptr->pattern_count; i++) { | |
| ptr->patterns[i].length = gf_bs_read_int(bs, pattern_size); | |
| ptr->patterns[i].sample_count = gf_bs_read_int(bs, scount_size); | |
| bits += pattern_size + scount_size; | |
| if (! (bits % 8)) { | |
| bits/=8; | |
| ISOM_DECREASE_SIZE(ptr, bits); | |
| bits=0; | |
| } | |
| patterns_sizes+=ptr->patterns[i].length; | |
| if (patterns_sizes * index_size > ptr->size*8) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] compact sample group pattern cumulated sizes "LLU" larger than box size "LLU"\n", patterns_sizes, ptr->size)); | |
| ptr->patterns[i].sample_group_description_indices = NULL; | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| if ( (u64)ptr->patterns[i].length > (u64)SIZE_MAX/sizeof(u32) ) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] compact sample group pattern #%d value (%lu) invalid\n", i, ptr->patterns[i].length)); | |
| ptr->patterns[i].sample_group_description_indices = NULL; | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->patterns[i].sample_group_description_indices = gf_malloc(sizeof(u32) * ptr->patterns[i].length); | |
| if (!ptr->patterns[i].sample_group_description_indices) return GF_OUT_OF_MEM; | |
| } | |
| bits = 0; | |
| gidx_mask = ((u32)1) << (index_size-1); | |
| for (i=0; i<ptr->pattern_count; i++) { | |
| u32 j; | |
| for (j=0; j<ptr->patterns[i].length; j++) { | |
| u32 idx = gf_bs_read_int(bs, index_size); | |
| if (index_msb_indicates_fragment_local_description) { | |
| //MSB set, this is a index of a group described in the fragment | |
| if (idx & gidx_mask) { | |
| idx += 0x10000; | |
| idx &= ~gidx_mask; | |
| } | |
| } | |
| ptr->patterns[i].sample_group_description_indices[j] = idx; | |
| bits += index_size; | |
| if (! (bits % 8)) { | |
| bits/=8; | |
| ISOM_DECREASE_SIZE(ptr, bits); | |
| bits=0; | |
| } | |
| } | |
| } | |
| if (bits) | |
| gf_bs_align(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err csgp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| u32 i; | |
| GF_Err e; | |
| GF_CompactSampleGroupBox *ptr = (GF_CompactSampleGroupBox*)s; | |
| u32 pattern_size = get_size_by_code( ((ptr->flags>>4) & 0x3) ); | |
| u32 scount_size = get_size_by_code( ((ptr->flags>>2) & 0x3) ); | |
| u32 index_size = get_size_by_code( (ptr->flags & 0x3) ); | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->version); | |
| gf_bs_write_int(bs, ptr->flags, 24); | |
| gf_bs_write_u32(bs, ptr->grouping_type); | |
| if (ptr->flags & (1<<6)) | |
| gf_bs_write_u32(bs, ptr->grouping_type_parameter); | |
| gf_bs_write_u32(bs, ptr->pattern_count); | |
| for (i = 0; i<ptr->pattern_count; i++ ) { | |
| gf_bs_write_int(bs, ptr->patterns[i].length, pattern_size); | |
| gf_bs_write_int(bs, ptr->patterns[i].sample_count, scount_size); | |
| } | |
| for (i = 0; i<ptr->pattern_count; i++ ) { | |
| u32 j; | |
| for (j=0; j<ptr->patterns[i].length; j++) { | |
| u32 idx = ptr->patterns[i].sample_group_description_indices[j]; | |
| if (idx > 0x10000) { | |
| idx -= 0x10000; | |
| gf_bs_write_int(bs, 1, 1); | |
| gf_bs_write_int(bs, idx, index_size-1); | |
| } else { | |
| gf_bs_write_int(bs, idx, index_size); | |
| } | |
| } | |
| } | |
| gf_bs_align(bs); | |
| return GF_OK; | |
| } | |
| GF_Err csgp_box_size(GF_Box *s) | |
| { | |
| u32 i, bits; | |
| GF_CompactSampleGroupBox *ptr = (GF_CompactSampleGroupBox*)s; | |
| u32 pattern_size = get_size_by_code( ((ptr->flags>>4) & 0x3) ); | |
| u32 scount_size = get_size_by_code( ((ptr->flags>>2) & 0x3) ); | |
| u32 index_size = get_size_by_code( (ptr->flags & 0x3) ); | |
| ptr->size += 12; //v, flags , grouping_type, pattern_length | |
| if (ptr->flags & (1<<6)) | |
| ptr->size+=4; | |
| ptr->size += ptr->pattern_count * (pattern_size + scount_size) / 8; | |
| bits=0; | |
| for (i=0; i<ptr->pattern_count; i++) | |
| bits += ptr->patterns[i].length * index_size; | |
| ptr->size += bits/8; | |
| if (bits % 8) ptr->size++; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *dmlp_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_TrueHDConfigBox, GF_ISOM_BOX_TYPE_DMLP); | |
| return (GF_Box *)tmp; | |
| } | |
| void dmlp_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err dmlp_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_TrueHDConfigBox *ptr = (GF_TrueHDConfigBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 10) | |
| ptr->format_info = gf_bs_read_u32(bs); | |
| ptr->peak_data_rate = gf_bs_read_int(bs, 15); | |
| gf_bs_read_int(bs, 1); | |
| gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err dmlp_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_TrueHDConfigBox *ptr = (GF_TrueHDConfigBox *)s; | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->format_info); | |
| gf_bs_write_int(bs, ptr->peak_data_rate, 15); | |
| gf_bs_write_int(bs, 0, 1); | |
| gf_bs_write_u32(bs, 0); | |
| return GF_OK; | |
| } | |
| GF_Err dmlp_box_size(GF_Box *s) | |
| { | |
| s->size += 10; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *xtra_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_XtraBox, GF_ISOM_BOX_TYPE_XTRA); | |
| tmp->tags = gf_list_new(); | |
| return (GF_Box *)tmp; | |
| } | |
| void xtra_box_del(GF_Box *s) | |
| { | |
| GF_XtraBox *ptr = (GF_XtraBox *)s; | |
| while (gf_list_count(ptr->tags)) { | |
| GF_XtraTag *tag = gf_list_pop_back(ptr->tags); | |
| if (tag->name) gf_free(tag->name); | |
| if (tag->prop_value) gf_free(tag->prop_value); | |
| gf_free(tag); | |
| } | |
| gf_list_del(ptr->tags); | |
| gf_free(s); | |
| } | |
| GF_Err xtra_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_XtraBox *ptr = (GF_XtraBox *)s; | |
| while (ptr->size) { | |
| GF_XtraTag *tag; | |
| u32 prop_type = 0; | |
| char *data=NULL, *data2=NULL; | |
| ISOM_DECREASE_SIZE_NO_ERR(ptr, 8) | |
| s32 tag_size = gf_bs_read_u32(bs); | |
| u32 name_size = gf_bs_read_u32(bs); | |
| if (tag_size < 8) return GF_ISOM_INVALID_FILE; | |
| tag_size -= 8; | |
| if ((tag_size>ptr->size) || (name_size>ptr->size)) { | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ISOM_DECREASE_SIZE_NO_ERR(ptr, 10) | |
| ISOM_DECREASE_SIZE_NO_ERR(ptr, name_size) | |
| data = gf_malloc(sizeof(char) * (name_size+1)); | |
| gf_bs_read_data(bs, data, name_size); | |
| data[name_size] = 0; | |
| tag_size-=name_size; | |
| u32 flags = gf_bs_read_u32(bs); | |
| u32 prop_size = gf_bs_read_u32(bs); | |
| tag_size-=8; | |
| if (prop_size>6 ) { | |
| tag_size-=2; | |
| prop_type = gf_bs_read_u16(bs); | |
| prop_size -= 6; | |
| if (ptr->size < prop_size && data) { | |
| gf_free(data); | |
| } | |
| ISOM_DECREASE_SIZE_NO_ERR(ptr, prop_size) | |
| //add 3 extra bytes for UTF16 case string dump (3 because we need 0-aligned short value) | |
| data2 = gf_malloc(sizeof(char) * (prop_size+3)); | |
| gf_bs_read_data(bs, data2, prop_size); | |
| data2[prop_size] = 0; | |
| data2[prop_size+1] = 0; | |
| data2[prop_size+2] = 0; | |
| tag_size-=prop_size; | |
| } else { | |
| prop_size = 0; | |
| } | |
| GF_SAFEALLOC(tag, GF_XtraTag) | |
| tag->flags = flags; | |
| tag->name = data; | |
| tag->prop_size = prop_size; | |
| tag->prop_value = data2; | |
| tag->prop_type = prop_type; | |
| gf_list_add(ptr->tags, tag); | |
| if (tag_size) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[isom] left-over bytes in tag %s in Xtra !\n", data)); | |
| gf_bs_skip_bytes(bs, tag_size); | |
| ISOM_DECREASE_SIZE_NO_ERR(ptr, tag_size) | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err xtra_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_XtraBox *ptr = (GF_XtraBox *)s; | |
| u32 i, count = gf_list_count(ptr->tags); | |
| e = gf_isom_box_write_header(s, bs); | |
| if (e) return e; | |
| for (i=0; i<count; i++) { | |
| GF_XtraTag *tag = gf_list_get(ptr->tags, i); | |
| u32 tag_size = 16; | |
| u32 name_len = tag->name ? (u32) strlen(tag->name) : 0; | |
| tag_size += name_len; | |
| if (tag->prop_value) { | |
| tag_size += 2 + tag->prop_size; | |
| } | |
| gf_bs_write_u32(bs, tag_size); | |
| gf_bs_write_u32(bs, name_len); | |
| gf_bs_write_data(bs, tag->name, name_len); | |
| gf_bs_write_u32(bs, tag->flags); | |
| gf_bs_write_u32(bs, 6 + tag->prop_size); | |
| gf_bs_write_u16(bs, tag->prop_type); | |
| gf_bs_write_data(bs, tag->prop_value, tag->prop_size); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err xtra_box_size(GF_Box *s) | |
| { | |
| GF_XtraBox *ptr = (GF_XtraBox *)s; | |
| u32 i, count = gf_list_count(ptr->tags); | |
| for (i=0; i<count; i++) { | |
| GF_XtraTag *tag = gf_list_get(ptr->tags, i); | |
| ptr->size += 18 + (u32) strlen(tag->name) + tag->prop_size; | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *st3d_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Stereo3DBox, GF_ISOM_BOX_TYPE_ST3D); | |
| return (GF_Box *)tmp; | |
| } | |
| void st3d_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err st3d_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Stereo3DBox *ptr = (GF_Stereo3DBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 1) | |
| ptr->stereo_type = gf_bs_read_u8(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err st3d_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_Stereo3DBox *ptr = (GF_Stereo3DBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u8(bs, ptr->stereo_type); | |
| return GF_OK; | |
| } | |
| GF_Err st3d_box_size(GF_Box *s) | |
| { | |
| s->size += 1; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *svhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SphericalVideoInfoBox, GF_ISOM_BOX_TYPE_SVHD); | |
| return (GF_Box *)tmp; | |
| } | |
| void svhd_box_del(GF_Box *s) | |
| { | |
| GF_SphericalVideoInfoBox *ptr = (GF_SphericalVideoInfoBox *)s; | |
| if (ptr->string) gf_free(ptr->string); | |
| gf_free(s); | |
| } | |
| GF_Err svhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SphericalVideoInfoBox *ptr = (GF_SphericalVideoInfoBox *)s; | |
| if ((u32)ptr->size >= (u32)0xFFFFFFFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in svhd box\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->string = gf_malloc(sizeof(char) * ((u32) ptr->size+1)); | |
| if (!ptr->string) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->string, (u32) ptr->size); | |
| ptr->string[ptr->size] = 0; | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err svhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SphericalVideoInfoBox *ptr = (GF_SphericalVideoInfoBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->string) | |
| gf_bs_write_data(bs, ptr->string, (u32) strlen(ptr->string)); | |
| gf_bs_write_u8(bs, 0); | |
| return GF_OK; | |
| } | |
| GF_Err svhd_box_size(GF_Box *s) | |
| { | |
| GF_SphericalVideoInfoBox *ptr = (GF_SphericalVideoInfoBox *)s; | |
| if (ptr->string) | |
| s->size += (u32) strlen(ptr->string); | |
| s->size += 1; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *prhd_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ProjectionHeaderBox, GF_ISOM_BOX_TYPE_PRHD); | |
| return (GF_Box *)tmp; | |
| } | |
| void prhd_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err prhd_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_ProjectionHeaderBox *ptr = (GF_ProjectionHeaderBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 12) | |
| ptr->yaw = (s32) gf_bs_read_u32(bs); | |
| ptr->pitch = (s32) gf_bs_read_u32(bs); | |
| ptr->roll = (s32) gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err prhd_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ProjectionHeaderBox *ptr = (GF_ProjectionHeaderBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->yaw); | |
| gf_bs_write_u32(bs, ptr->pitch); | |
| gf_bs_write_u32(bs, ptr->roll); | |
| return GF_OK; | |
| } | |
| GF_Err prhd_box_size(GF_Box *s) | |
| { | |
| s->size += 12; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *proj_type_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ProjectionTypeBox, GF_ISOM_BOX_TYPE_EQUI); //will be overwritten | |
| return (GF_Box *)tmp; | |
| } | |
| void proj_type_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err proj_type_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_ProjectionTypeBox *ptr = (GF_ProjectionTypeBox *)s; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_CBMP) { | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| ptr->layout = gf_bs_read_u32(bs); | |
| ptr->padding = gf_bs_read_u32(bs); | |
| } | |
| else if (ptr->type==GF_ISOM_BOX_TYPE_EQUI) { | |
| ISOM_DECREASE_SIZE(ptr, 16) | |
| ptr->bounds_top = gf_bs_read_u32(bs); | |
| ptr->bounds_bottom = gf_bs_read_u32(bs); | |
| ptr->bounds_left = gf_bs_read_u32(bs); | |
| ptr->bounds_right = gf_bs_read_u32(bs); | |
| } else { | |
| ISOM_DECREASE_SIZE(ptr, 8) | |
| ptr->crc = gf_bs_read_u32(bs); | |
| ptr->encoding_4cc = gf_bs_read_u32(bs); | |
| } | |
| return gf_isom_box_array_read(s, bs); | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err proj_type_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ProjectionTypeBox *ptr = (GF_ProjectionTypeBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_CBMP) { | |
| gf_bs_write_u32(bs, ptr->layout); | |
| gf_bs_write_u32(bs, ptr->padding); | |
| } | |
| else if (ptr->type==GF_ISOM_BOX_TYPE_EQUI) { | |
| gf_bs_write_u32(bs, ptr->bounds_top); | |
| gf_bs_write_u32(bs, ptr->bounds_bottom); | |
| gf_bs_write_u32(bs, ptr->bounds_left); | |
| gf_bs_write_u32(bs, ptr->bounds_right); | |
| } else { | |
| gf_bs_write_u32(bs, ptr->crc); | |
| gf_bs_write_u32(bs, ptr->encoding_4cc); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err proj_type_box_size(GF_Box *s) | |
| { | |
| GF_ProjectionTypeBox *ptr = (GF_ProjectionTypeBox *)s; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_CBMP) | |
| s->size += 8; | |
| else if (ptr->type==GF_ISOM_BOX_TYPE_EQUI) | |
| s->size += 16; | |
| else | |
| s->size += 8; | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| GF_Box *empty_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_Box, GF_QT_BOX_TYPE_FRCD); | |
| return (GF_Box *) tmp; | |
| } | |
| void empty_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err empty_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err empty_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| return gf_isom_box_write_header(s, bs); | |
| } | |
| GF_Err empty_box_size(GF_Box *s) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| void extl_box_del(GF_Box *s) | |
| { | |
| GF_ExternalTrackLocationBox *ptr = (GF_ExternalTrackLocationBox *)s; | |
| if (ptr->location) gf_free(ptr->location); | |
| gf_free(ptr); | |
| return; | |
| } | |
| GF_Err extl_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_ExternalTrackLocationBox *ptr = (GF_ExternalTrackLocationBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 8); | |
| ptr->referenced_track_ID = gf_bs_read_u32(bs); | |
| ptr->referenced_handler_type = gf_bs_read_u32(bs); | |
| ISOM_DECREASE_SIZE(ptr, 4); | |
| ptr->media_timescale = gf_bs_read_u32(bs); | |
| if (ptr->size) { | |
| u32 name_size = (u32) ptr->size; | |
| if (name_size < 1 || name_size >= GF_UINT_MAX-1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in hdlr\n", ptr->size)); | |
| return GF_ISOM_INVALID_FILE; | |
| } | |
| ptr->location = (char*)gf_malloc(name_size+1); | |
| if (!ptr->location) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ptr->location, name_size); | |
| ptr->location[name_size] = 0; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Box *extl_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_ExternalTrackLocationBox, GF_ISOM_BOX_TYPE_EXTL); | |
| return (GF_Box *)tmp; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err extl_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_ExternalTrackLocationBox *ptr = (GF_ExternalTrackLocationBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, (u32) ptr->referenced_track_ID); | |
| gf_bs_write_u32(bs, (u32) ptr->referenced_handler_type); | |
| gf_bs_write_u32(bs, ptr->media_timescale); | |
| gf_bs_write_utf8(bs, ptr->location); | |
| return GF_OK; | |
| } | |
| GF_Err extl_box_size(GF_Box *s) | |
| { | |
| GF_ExternalTrackLocationBox *ptr = (GF_ExternalTrackLocationBox *)s; | |
| ptr->size += 12; | |
| ptr->size += 1 + (ptr->location ? (u32) strlen(ptr->location) : 0); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_ISOM_WRITE*/ | |
| //#define DUMP_STATS | |
| #ifdef DUMP_STATS | |
| static u32 global_boxes=0; | |
| static u32 global_samples=0; | |
| static u32 global_cost=0; | |
| static u32 global_cost_full=0; | |
| static s32 global_cost_diff=0; | |
| static u32 global_patterns_diff=0; | |
| static s32 global_cost_nodiff=0; | |
| static u32 global_patterns_nodiff=0; | |
| static s32 global_cost_refs_sbgp=0; | |
| #endif | |
| GF_Box *sref_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SampleReferences, GF_ISOM_BOX_TYPE_CDRF); | |
| tmp->entries = gf_list_new(); | |
| return (GF_Box *) tmp; | |
| } | |
| void sref_box_del(GF_Box *s) | |
| { | |
| GF_SampleReferences *ptr = (GF_SampleReferences*)s; | |
| while (gf_list_count(ptr->entries)) { | |
| GF_SampleRefEntry *ent = gf_list_pop_back(ptr->entries); | |
| if (ent->sample_refs) gf_free(ent->sample_refs); | |
| gf_free(ent); | |
| } | |
| gf_list_del(ptr->entries); | |
| gf_free(s); | |
| #ifdef DUMP_STATS | |
| if (global_boxes) | |
| fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", global_boxes, global_samples, global_cost, global_cost_full, global_cost_diff, global_cost_nodiff, global_cost_refs_sbgp, global_patterns_diff, global_patterns_nodiff); | |
| #endif | |
| } | |
| typedef struct | |
| { | |
| Bool is_abs; | |
| u32 orig_sampleID; | |
| s32 diff_sampleID; | |
| u32 nb_refs; | |
| s32 *sample_refs; | |
| s32 *orig_sample_refs; | |
| u32 flags; | |
| } GF_SampleRefDiffEntry; | |
| static s32 read_signed_int(GF_BitStream *bs, u32 nb_bits, s32 max_val) | |
| { | |
| s32 val = gf_bs_read_int(bs, nb_bits); | |
| if (val<max_val) return val; | |
| if (max_val>=GF_INT_MAX/2) return max_val; | |
| return val - (2*max_val); | |
| } | |
| GF_Err cdrf_box_read(GF_SampleReferences *s, GF_BitStream *bs) | |
| { | |
| GF_Err e = GF_OK; | |
| ISOM_DECREASE_SIZE(s, 1) | |
| s->flags = gf_bs_read_u8(bs); | |
| Bool use_nodiff = (s->flags & 16) ? GF_TRUE : GF_FALSE; | |
| u32 i, j; | |
| u32 bits = 8, entry_bits=8; | |
| if (s->flags & 1) bits = 16; | |
| else if (s->flags & 2) bits = 32; | |
| s32 max_val = 1; | |
| i=0; | |
| while (i<bits-1) { | |
| i++; | |
| max_val = i<31 ? max_val<<1 : GF_INT_MAX; | |
| } | |
| s32 max_val2 = max_val>>1; | |
| if (s->flags & 4) entry_bits = 16; | |
| else if (s->flags & 8) entry_bits = 32; | |
| s->cdrf_entries = gf_bs_read_int(bs, entry_bits); | |
| GF_List *def_refs = gf_list_new(); | |
| GF_List *samples = gf_list_new(); | |
| for (i=0; i<s->cdrf_entries; i++) { | |
| ISOM_DECREASE_SIZE_GOTO_EXIT(s, bits/8) | |
| Bool is_ref = gf_bs_read_int(bs, 1); | |
| if (!is_ref) { | |
| GF_SampleRefDiffEntry *ent; | |
| u32 nb_refs = gf_bs_read_int(bs, bits-1); | |
| if ( nb_refs >= GF_UINT_MAX || bits < 8 || (1+nb_refs) > GF_UINT_MAX / (bits/8) ) { | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| goto exit; | |
| } | |
| ISOM_DECREASE_SIZE_GOTO_EXIT(s, (1+nb_refs)*(bits/8)) | |
| GF_SAFEALLOC(ent, GF_SampleRefDiffEntry); | |
| if (!ent) { | |
| e = GF_OUT_OF_MEM; | |
| goto exit; | |
| } | |
| gf_list_add(def_refs, ent); | |
| gf_list_add(samples, ent); | |
| ent->sample_refs = gf_malloc(sizeof(s32)*nb_refs); | |
| if (!ent->sample_refs) { | |
| e = GF_OUT_OF_MEM; | |
| goto exit; | |
| } | |
| ent->nb_refs = nb_refs; | |
| if (use_nodiff) { | |
| ent->diff_sampleID = (s32) read_signed_int(bs, bits, max_val); | |
| } else { | |
| ent->is_abs = gf_bs_read_int(bs, 1); | |
| ent->diff_sampleID = (s32) read_signed_int(bs, bits-1, max_val2); | |
| } | |
| for (j=0; j<nb_refs; j++) { | |
| ent->sample_refs[j] = (s32) (s8) read_signed_int(bs, bits, max_val); | |
| } | |
| } else { | |
| ISOM_DECREASE_SIZE_GOTO_EXIT(s, 3*bits/8) | |
| u32 offset = gf_bs_read_int(bs, bits-1); | |
| u32 pattern_len = gf_bs_read_int(bs, bits); | |
| u32 nb_samples = gf_bs_read_int(bs, bits); | |
| if (nb_samples > GF_INT_MAX) { | |
| e = GF_ISOM_INVALID_FILE; | |
| goto exit; | |
| } | |
| u32 pattern_idx=0; | |
| for (j=0; j<nb_samples; j++) { | |
| u32 s_offset = offset + pattern_idx; | |
| GF_SampleRefDiffEntry *ent = gf_list_get(samples, s_offset); | |
| if (!ent) { | |
| e = GF_ISOM_INVALID_FILE; | |
| goto exit; | |
| } | |
| if (use_nodiff) { | |
| GF_SampleRefDiffEntry *rent; | |
| ISOM_DECREASE_SIZE_GOTO_EXIT(s, bits/8) | |
| GF_SAFEALLOC(rent, GF_SampleRefDiffEntry); | |
| if (!rent) { | |
| e = GF_OUT_OF_MEM; | |
| goto exit; | |
| } | |
| rent->diff_sampleID = (s32) read_signed_int(bs, bits, max_val); | |
| rent->nb_refs = ent->nb_refs; | |
| rent->sample_refs = ent->sample_refs; | |
| rent->flags = 1; | |
| gf_list_add(samples, rent); | |
| } else { | |
| gf_list_add(samples, ent); | |
| } | |
| pattern_idx++; | |
| if (pattern_idx==pattern_len) pattern_idx=0; | |
| } | |
| } | |
| } | |
| u32 prev_sample_id = 0; | |
| while (gf_list_count(samples)) { | |
| GF_SampleRefDiffEntry *ent = gf_list_pop_front(samples); | |
| GF_SampleRefEntry *final_ent; | |
| GF_SAFEALLOC(final_ent, GF_SampleRefEntry); | |
| if (final_ent) { | |
| final_ent->sample_refs = gf_malloc(sizeof(u32)*ent->nb_refs); | |
| gf_list_add(s->entries, final_ent); | |
| } | |
| if (!final_ent || !final_ent->sample_refs) { | |
| e = GF_OUT_OF_MEM; | |
| goto exit; | |
| } | |
| if (use_nodiff) | |
| final_ent->sampleID = ent->diff_sampleID; | |
| else | |
| if (ent->is_abs) final_ent->sampleID = ent->diff_sampleID; | |
| else final_ent->sampleID = prev_sample_id + ent->diff_sampleID; | |
| prev_sample_id = final_ent->sampleID; | |
| final_ent->nb_refs = ent->nb_refs; | |
| for (j=0; j<ent->nb_refs;j++) { | |
| s32 ref; | |
| if (use_nodiff) | |
| ref = ent->sample_refs[j]; | |
| else | |
| ref = final_ent->sampleID - ent->sample_refs[j]; | |
| assert(ref>=0); | |
| final_ent->sample_refs[j] = ref; | |
| } | |
| if (ent->flags) { | |
| gf_free(ent); | |
| } | |
| } | |
| exit: | |
| if (use_nodiff) { | |
| while (gf_list_count(samples)) { | |
| GF_SampleRefDiffEntry *ent = gf_list_pop_front(samples); | |
| if (gf_list_find(def_refs, ent) < 0) { | |
| gf_free(ent); | |
| } | |
| } | |
| } | |
| gf_list_del(samples); | |
| while (gf_list_count(def_refs)) { | |
| GF_SampleRefDiffEntry *ent = gf_list_pop_back(def_refs); | |
| if (ent->sample_refs) gf_free(ent->sample_refs); | |
| gf_free(ent); | |
| } | |
| gf_list_del(def_refs); | |
| return e; | |
| } | |
| GF_Err sref_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SampleReferences *ptr = (GF_SampleReferences*)s; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_CDRF) { | |
| return cdrf_box_read(ptr, bs); | |
| } | |
| ISOM_DECREASE_SIZE(s, 4) | |
| u32 bits = 8; | |
| if (ptr->flags & (1<<1)) bits = 32; | |
| else if (ptr->flags & (1)) bits = 16; | |
| u32 max_val = (u32)(((u64)1<<bits) - 1); | |
| u32 i, nb_entries = gf_bs_read_u32(bs); | |
| if (nb_entries * bits / 8 > s->size) return GF_ISOM_INVALID_FILE; | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefEntry *ent; | |
| GF_SAFEALLOC(ent, GF_SampleRefEntry); | |
| if (!ent) return GF_OUT_OF_MEM; | |
| gf_list_add(ptr->entries, ent); | |
| ISOM_DECREASE_SIZE(s, bits/8) | |
| ent->sampleID = gf_bs_read_int(bs, bits); | |
| if (ent->sampleID == max_val) | |
| continue; | |
| ISOM_DECREASE_SIZE(s, bits/8) | |
| ent->nb_refs = gf_bs_read_int(bs, bits); | |
| if (ent->nb_refs > s->size * 8 / bits) return GF_ISOM_INVALID_FILE; | |
| if (ent->nb_refs) { | |
| u32 j; | |
| ent->sample_refs = gf_malloc(sizeof(u32) * ent->nb_refs); | |
| for (j=0; j<ent->nb_refs; j++) { | |
| ent->sample_refs[j] = gf_bs_read_int(bs, bits); | |
| ISOM_DECREASE_SIZE(s, bits/8) | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| #ifdef DUMP_STATS | |
| static Bool cdrf_sample_is_leaf(GF_SampleReferences *ptr, u32 sample_id) | |
| { | |
| u32 i, j, nb_entries = gf_list_count(ptr->entries); | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefEntry *ent = gf_list_get(ptr->entries, i); | |
| for (j=0; j<ent->nb_refs; j++) { | |
| if (ent->sample_refs[j]==sample_id) return GF_TRUE; | |
| } | |
| } | |
| return GF_FALSE; | |
| } | |
| #endif | |
| static GF_List *cdrf_get_refs(GF_SampleReferences *ptr, s32 *out_max_id, s32 *out_max_id_nodiff) | |
| { | |
| Bool all_intra=GF_TRUE; | |
| s32 max_id_diff=-1; | |
| s32 max_id_nodiff=-1; | |
| u32 i, j, nb_entries = gf_list_count(ptr->entries); | |
| u32 prev_sample_id = 0; | |
| Bool prev_is_irap=GF_FALSE; | |
| GF_List *refs = gf_list_new(); | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefEntry *ent = gf_list_get(ptr->entries, i); | |
| GF_SampleRefDiffEntry *rent; | |
| GF_SAFEALLOC(rent, GF_SampleRefDiffEntry); | |
| rent->diff_sampleID = rent->orig_sampleID = ent->sampleID; | |
| if (ent->sampleID==GF_INT_MAX) { | |
| rent->is_abs = GF_TRUE; | |
| prev_is_irap = GF_FALSE; | |
| } else if (!ent->nb_refs) { | |
| //if prev is irap code as diff | |
| if (prev_is_irap) { | |
| rent->is_abs = GF_FALSE; | |
| rent->diff_sampleID -= prev_sample_id; | |
| } else { | |
| rent->is_abs = GF_TRUE; | |
| } | |
| prev_is_irap = GF_TRUE; | |
| } else { | |
| prev_is_irap = GF_FALSE; | |
| all_intra = GF_FALSE; | |
| rent->nb_refs = ent->nb_refs; | |
| rent->orig_sample_refs = ent->sample_refs; | |
| rent->sample_refs = gf_malloc(sizeof(s32) * ent->nb_refs); | |
| for (j=0; j<rent->nb_refs; j++) { | |
| rent->sample_refs[j] = ent->sampleID; | |
| rent->sample_refs[j] -= ent->sample_refs[j]; | |
| if (out_max_id) { | |
| if (max_id_diff < ABS(rent->sample_refs[j])) | |
| max_id_diff = ABS(rent->sample_refs[j]); | |
| if (max_id_nodiff < rent->orig_sample_refs[j]) | |
| max_id_nodiff = rent->orig_sample_refs[j]; | |
| } | |
| } | |
| if (!i) | |
| rent->is_abs = GF_TRUE; | |
| else | |
| rent->diff_sampleID -= prev_sample_id; | |
| } | |
| #ifdef DUMP_STATS | |
| if (cdrf_sample_is_leaf(ptr, ent->sampleID)) | |
| rent->flags = 1; | |
| #endif | |
| prev_sample_id = ent->sampleID; | |
| gf_list_add(refs, rent); | |
| if (out_max_id) { | |
| if (max_id_diff < rent->diff_sampleID) | |
| max_id_diff = rent->diff_sampleID; | |
| if (max_id_nodiff < rent->orig_sampleID) | |
| max_id_nodiff = rent->orig_sampleID; | |
| } | |
| } | |
| if (all_intra) { | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefDiffEntry *ent = gf_list_get(refs, i); | |
| ent->flags = 1; | |
| } | |
| } | |
| if (out_max_id) *out_max_id = max_id_diff; | |
| if (out_max_id_nodiff) *out_max_id_nodiff = max_id_nodiff; | |
| return refs; | |
| } | |
| static void cdrf_clean_refs(GF_List *refs) | |
| { | |
| while (gf_list_count(refs)) { | |
| GF_SampleRefDiffEntry *rent = gf_list_pop_back(refs); | |
| if (rent->sample_refs) gf_free(rent->sample_refs); | |
| gf_free(rent); | |
| } | |
| gf_list_del(refs); | |
| } | |
| static Bool cdrf_same_entry(GF_SampleRefDiffEntry *ref_ent, GF_SampleRefDiffEntry *ref, u32 mode) | |
| { | |
| //diff cdrf | |
| if (mode==0) { | |
| if (ref->is_abs != ref_ent->is_abs) return GF_FALSE; | |
| if (ref->diff_sampleID != ref_ent->diff_sampleID) return GF_FALSE; | |
| } | |
| #ifdef DUMP_STATS | |
| //refs | |
| if (mode==2) { | |
| //both leaf samples, check ID | |
| if (!ref->flags || !ref_ent->flags) { | |
| if (ref->orig_sampleID != ref_ent->orig_sampleID) return GF_FALSE; | |
| } | |
| } | |
| #endif | |
| if (ref->nb_refs != ref_ent->nb_refs) return GF_FALSE; | |
| u32 k, l, match = 0; | |
| s32 *ref_ent_ids = mode ? ref_ent->orig_sample_refs : ref_ent->sample_refs; | |
| s32 *ref_ids = mode ? ref->orig_sample_refs : ref->sample_refs; | |
| for (k=0; k<ref_ent->nb_refs; k++) { | |
| for (l=0; l<ref->nb_refs; l++) { | |
| if (ref_ids[l] == ref_ent_ids[k]) { | |
| match ++; | |
| break; | |
| } | |
| } | |
| } | |
| if (match==ref_ent->nb_refs) return GF_TRUE; | |
| return GF_FALSE; | |
| } | |
| static s32 cdrf_locate_first_ref(GF_SampleRefDiffEntry *ref_ent, u32 max_idx, GF_List *refs, s32 pattern_offset, u32 nb_in_pattern, u32 mode) | |
| { | |
| u32 j; | |
| if (pattern_offset>=0) { | |
| GF_SampleRefDiffEntry *ref = gf_list_get(refs, pattern_offset); | |
| //detect loop | |
| if (cdrf_same_entry(ref_ent, ref, mode)) | |
| return pattern_offset; | |
| //detect following | |
| pattern_offset += nb_in_pattern; | |
| ref = gf_list_get(refs, pattern_offset); | |
| if (cdrf_same_entry(ref_ent, ref, mode)) | |
| return pattern_offset; | |
| } | |
| //browse from start | |
| for (j=0; j<max_idx; j++) { | |
| GF_SampleRefDiffEntry *ref = gf_list_get(refs, j); | |
| if (cdrf_same_entry(ref_ent, ref, mode)) | |
| return j; | |
| } | |
| return -1; | |
| } | |
| static void cdrf_box_flush_pattern(GF_BitStream *bs, u32 pattern_len, s32 prev_offset, u32 nb_samples, u32 *sample_ids, u32 bits) | |
| { | |
| gf_assert(pattern_len); | |
| gf_assert(nb_samples); | |
| gf_bs_write_int(bs, 1, 1); | |
| gf_bs_write_int(bs, prev_offset, bits-1); | |
| gf_bs_write_int(bs, pattern_len, bits); | |
| gf_bs_write_int(bs, nb_samples, bits); | |
| if (sample_ids) { | |
| u32 j; | |
| for (j=0; j<nb_samples; j++) | |
| gf_bs_write_int(bs, sample_ids[j], bits); | |
| } | |
| } | |
| GF_Err cdrf_box_write(GF_SampleReferences *ptr, GF_BitStream *bs) | |
| { | |
| GF_List *refs = cdrf_get_refs(ptr, NULL, NULL); | |
| u32 i, j; | |
| u32 bits = 8, entry_bits=8; | |
| if (ptr->flags & 1) bits = 16; | |
| else if (ptr->flags & 2) bits = 32; | |
| if (ptr->flags & 4) entry_bits = 16; | |
| else if (ptr->flags & 8) entry_bits = 32; | |
| gf_isom_box_write_header((GF_Box*)ptr, bs); | |
| gf_bs_write_u8(bs, ptr->flags); | |
| gf_bs_write_int(bs, ptr->cdrf_entries, entry_bits); | |
| u32 mode = (ptr->flags & 16) ? 1 : 0; | |
| s32 prev_offset = -1; | |
| u32 prev_len = 0; | |
| u32 pattern_len = 0; | |
| u32 nb_samples = 0; | |
| u32 nb_entries = gf_list_count(ptr->entries); | |
| s32 *sample_ids = NULL; | |
| if (mode) { | |
| sample_ids = gf_malloc(sizeof(s32)*nb_entries); | |
| if (!sample_ids) return GF_OUT_OF_MEM; | |
| } | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefDiffEntry *rent = gf_list_get(refs, i); | |
| s32 found = cdrf_locate_first_ref(rent, i, refs, prev_offset, prev_len, mode); | |
| if (found<0) { | |
| if (prev_len) { | |
| cdrf_box_flush_pattern(bs, pattern_len ? pattern_len : prev_len, prev_offset, nb_samples, sample_ids, bits); | |
| } | |
| //write direct sample | |
| gf_bs_write_int(bs, 0, 1); | |
| gf_bs_write_int(bs, rent->nb_refs, bits-1); | |
| if (mode) { | |
| gf_bs_write_int(bs, rent->orig_sampleID, bits); | |
| for (j=0; j<rent->nb_refs; j++) | |
| gf_bs_write_int(bs, rent->orig_sample_refs[j], bits); | |
| } else { | |
| gf_bs_write_int(bs, rent->is_abs, 1); | |
| gf_bs_write_int(bs, rent->diff_sampleID, bits-1); | |
| for (j=0; j<rent->nb_refs; j++) | |
| gf_bs_write_int(bs, rent->sample_refs[j], bits); | |
| } | |
| //reset pattern to empty | |
| prev_offset = -1; | |
| prev_len = 0; | |
| pattern_len = 0; | |
| nb_samples=0; | |
| } else { | |
| if (pattern_len && (pattern_len == prev_len)) { | |
| prev_len = 0; | |
| } | |
| if ((prev_offset>=0) && (found == prev_offset+prev_len)) { | |
| prev_len++; | |
| if (sample_ids) | |
| sample_ids[nb_samples] = rent->orig_sampleID; | |
| nb_samples++; | |
| continue; | |
| } | |
| if (!pattern_len && (found == prev_offset)) { | |
| pattern_len = prev_len; | |
| prev_len = 1; | |
| if (sample_ids) | |
| sample_ids[nb_samples] = rent->orig_sampleID; | |
| nb_samples++; | |
| continue; | |
| } | |
| if (prev_len || pattern_len) { | |
| cdrf_box_flush_pattern(bs, pattern_len ? pattern_len : prev_len, prev_offset, nb_samples, sample_ids, bits); | |
| } | |
| //reset pattern to one sample found | |
| prev_offset = found; | |
| pattern_len = 0; | |
| prev_len = 1; | |
| nb_samples = 1; | |
| if (sample_ids) | |
| sample_ids[0] = rent->orig_sampleID; | |
| } | |
| } | |
| if (prev_len) { | |
| cdrf_box_flush_pattern(bs, pattern_len ? pattern_len : prev_len, prev_offset, nb_samples, sample_ids, bits); | |
| } | |
| if (sample_ids) | |
| gf_free(sample_ids); | |
| cdrf_clean_refs(refs); | |
| return GF_OK; | |
| } | |
| GF_Err sref_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SampleReferences *ptr = (GF_SampleReferences*)s; | |
| if (ptr->type==GF_ISOM_BOX_TYPE_CDRF) { | |
| return cdrf_box_write(ptr, bs); | |
| } | |
| GF_Err e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| u32 bits = 8; | |
| if (ptr->flags & (1<<1)) bits = 32; | |
| else if (ptr->flags & (1)) bits = 16; | |
| u32 i, nb_entries = gf_list_count(ptr->entries); | |
| gf_bs_write_u32(bs, nb_entries); | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefEntry *ent = gf_list_get(ptr->entries, i); | |
| if (ent->sampleID == GF_INT_MAX) { | |
| gf_bs_write_int(bs, 0xFFFFFFFF, bits); | |
| continue; | |
| } | |
| gf_bs_write_int(bs, ent->sampleID, bits); | |
| gf_bs_write_int(bs, ent->nb_refs, bits); | |
| if (ent->nb_refs) { | |
| u32 j; | |
| for (j=0; j<ent->nb_refs; j++) { | |
| gf_bs_write_int(bs, ent->sample_refs[j], bits); | |
| } | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| //#define DUMP_REFS | |
| static u32 cdrf_get_cost(GF_List *refs, u32 mode, s32 max_id, u32 *cost_full, u32 *total_entries, u8 *flags) | |
| { | |
| s32 prev_offset = -1; | |
| u32 prev_len = 0; | |
| u32 nb_samples = 0; | |
| u32 pattern_len = 0; | |
| #ifdef DUMP_STATS | |
| u32 cost_refs=0; | |
| u32 cost_sbgp=0; | |
| #endif | |
| u32 i, nb_entries = gf_list_count(refs); | |
| u32 nb_direct_cost=0, nb_direct_entries=0, nb_pattern_entries=0, nb_samples_reused=0; | |
| *cost_full=0; | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefDiffEntry *rent = gf_list_get(refs, i); | |
| s32 found = cdrf_locate_first_ref(rent, i, refs, prev_offset, prev_len, mode); | |
| *cost_full += 2 + rent->nb_refs; | |
| #ifdef DUMP_REFS | |
| Bool pattern_start=GF_FALSE; | |
| Bool pattern_end=GF_FALSE; | |
| #endif | |
| if (found<0) { | |
| #ifdef DUMP_STATS | |
| if (mode==2) { | |
| //need refs sample entry + length | |
| cost_refs += 4 + 5+4*rent->nb_refs; | |
| //need sgpd entry | |
| cost_sbgp += 8; | |
| continue; | |
| } | |
| #endif | |
| if (prev_len > max_id) { | |
| max_id = prev_len; | |
| } | |
| if (prev_len) { | |
| gf_fatal_assert(nb_samples); | |
| nb_pattern_entries += 1; | |
| #ifdef DUMP_REFS | |
| pattern_end=GF_TRUE; | |
| #endif | |
| } | |
| if (prev_offset > max_id) | |
| max_id = prev_offset; | |
| prev_offset = -1; | |
| prev_len = 0; | |
| pattern_len = 0; | |
| nb_samples = 0; | |
| nb_direct_entries += 1; | |
| nb_direct_cost += 2 + rent->nb_refs; | |
| } else { | |
| #ifdef DUMP_STATS | |
| if (mode==2) { | |
| //reuse existing refs sample group, no refs extra cost | |
| GF_SampleRefDiffEntry *prev_ent = gf_list_get(refs, i-1); | |
| //same as previous, RLE from previous sbgp entry can be used | |
| if (prev_ent && cdrf_same_entry(rent, prev_ent, 2)) { | |
| } else { | |
| //need sgpd entry | |
| cost_sbgp += 8; | |
| } | |
| continue; | |
| } | |
| #endif | |
| nb_samples_reused += 1; | |
| if (pattern_len && (pattern_len == prev_len)) { | |
| prev_len = 0; | |
| } | |
| if ((prev_offset>=0) && (found == prev_offset+prev_len)) { | |
| prev_len++; | |
| nb_samples ++; | |
| } | |
| else if (!pattern_len && (found == prev_offset)) { | |
| pattern_len = prev_len; | |
| prev_len = 1; | |
| nb_samples ++; | |
| } else { | |
| if (prev_len > max_id) { | |
| max_id = prev_len; | |
| } | |
| if (prev_len || pattern_len) { | |
| nb_pattern_entries += 1; | |
| gf_assert(nb_samples); | |
| #ifdef DUMP_REFS | |
| pattern_end=GF_TRUE; | |
| #endif | |
| } | |
| if (prev_offset > max_id) | |
| max_id = prev_offset; | |
| pattern_len = 0; | |
| prev_offset = found; | |
| prev_len = 1; | |
| nb_samples = 1; | |
| #ifdef DUMP_REFS | |
| pattern_start=GF_TRUE; | |
| #endif | |
| } | |
| } | |
| #ifdef DUMP_REFS | |
| fprintf(stderr, "Sample #%d %d %d refs[", i+1, rent->orig_sampleID, rent->diff_sampleID); | |
| for (u32 j=0; j<rent->nb_refs; j++) fprintf(stderr, " %d", mode ? rent->orig_sample_refs[j] : rent->sample_refs[j]); | |
| fprintf(stderr, "] Pattern End %d Start %d", pattern_end, pattern_start); | |
| if (found>=0) | |
| fprintf(stderr, " reuse entry #%u", found+1); | |
| fprintf(stderr, "\n"); | |
| #endif | |
| } | |
| if (prev_len || pattern_len) { | |
| nb_pattern_entries += 1; | |
| } | |
| #ifdef DUMP_STATS | |
| if (mode==2) { | |
| *flags = 0; | |
| cost_refs += 24; //Full box + grouping type + length + nb_entries | |
| cost_sbgp += 20; //FullBox + grouping_type + nb_entries | |
| return cost_refs+cost_sbgp; | |
| } | |
| #endif | |
| *flags = 0; | |
| u32 byte_s=1; | |
| if (max_id > 32767) { | |
| byte_s=4; | |
| *flags |= 2; | |
| } | |
| else if (max_id > 255) { | |
| byte_s=2; | |
| *flags |= 1; | |
| } | |
| *total_entries = nb_pattern_entries + nb_direct_entries; | |
| u32 byte_e=1; | |
| if (nb_pattern_entries + nb_direct_entries > 32767) { | |
| byte_e=4; | |
| *flags |= 8; | |
| } | |
| else if (nb_pattern_entries + nb_direct_entries > 255) { | |
| byte_e=2; | |
| *flags |= 4; | |
| } | |
| //move to bytes | |
| *cost_full *= byte_s; | |
| //size+type+flags | |
| *cost_full += 9; | |
| if (nb_entries > 32767) *cost_full += 4; | |
| else if (nb_entries > 255) *cost_full += 2; | |
| else *cost_full += 1; | |
| u32 final_size = 8 + 1 + byte_e; | |
| final_size += nb_direct_cost * byte_s + nb_pattern_entries * 3 * byte_s; | |
| if (mode==1) { | |
| final_size += nb_samples_reused * byte_s; | |
| *flags |= 16; | |
| } | |
| #ifdef DUMP_STATS | |
| if (mode==1) global_patterns_nodiff += nb_pattern_entries; | |
| else global_patterns_diff += nb_pattern_entries; | |
| #endif | |
| return final_size; | |
| } | |
| GF_Err cdrf_box_size(GF_SampleReferences *ptr) | |
| { | |
| if (ptr->cdrf_cache_size) { | |
| ptr->size = ptr->cdrf_cache_size; | |
| return GF_OK; | |
| } | |
| s32 max_id = 0; | |
| s32 max_id_nodiff = 0; | |
| GF_List *refs = cdrf_get_refs(ptr, &max_id, &max_id_nodiff); | |
| u32 cost_full, nb_entries; | |
| u8 flags; | |
| #ifdef DUMP_STATS | |
| //get cost for refs+sbgp | |
| u32 final_size_refs_sbgp = cdrf_get_cost(refs, 2, max_id_nodiff, &cost_full, &nb_entries, &flags); | |
| #endif | |
| //get cost in diff mode | |
| u32 final_size = cdrf_get_cost(refs, 0, max_id, &cost_full, &nb_entries, &flags); | |
| //get cost in nodiff mode | |
| u32 nb_entries_nodiff; | |
| u8 flags_nodiff; | |
| u32 final_size_nodiff = cdrf_get_cost(refs, 1, max_id_nodiff, &cost_full, &nb_entries_nodiff, &flags_nodiff); | |
| if (final_size_nodiff < final_size) { | |
| ptr->size = final_size_nodiff; | |
| ptr->flags = flags_nodiff; | |
| ptr->cdrf_entries = nb_entries_nodiff; | |
| } else { | |
| ptr->size = final_size; | |
| ptr->flags = flags; | |
| ptr->cdrf_entries = nb_entries; | |
| } | |
| ptr->cdrf_cache_size = ptr->size; | |
| cdrf_clean_refs(refs); | |
| #ifdef DUMP_STATS | |
| global_boxes+=1; | |
| global_samples+=gf_list_count(ptr->entries); | |
| global_cost += ptr->size; | |
| global_cost_full += cost_full; | |
| global_cost_diff += final_size; | |
| global_cost_nodiff += final_size_nodiff; | |
| global_cost_refs_sbgp += final_size_refs_sbgp; | |
| #endif | |
| return GF_OK; | |
| } | |
| GF_Err sref_box_size(GF_Box *s) | |
| { | |
| GF_SampleReferences *ptr = (GF_SampleReferences*)s; | |
| if ((ptr->type!=GF_GPAC_BOX_TYPE_SREF) && gf_opts_get_bool("core", "no-cdrf")) { | |
| ptr->type = GF_GPAC_BOX_TYPE_SREF; | |
| } | |
| if (ptr->type == GF_ISOM_BOX_TYPE_CDRF) { | |
| return cdrf_box_size(ptr); | |
| } | |
| u32 i, j, tot_entries = 0, nb_entries = gf_list_count(ptr->entries), nb_refs=0; | |
| ptr->size += 4; | |
| u32 max_size = 1; | |
| for (i=0; i<nb_entries; i++) { | |
| GF_SampleRefEntry *ent = gf_list_get(ptr->entries, i); | |
| if (ent->sampleID==GF_INT_MAX) { | |
| continue; | |
| } | |
| nb_refs++; | |
| tot_entries += ent->nb_refs; | |
| if (ent->sampleID >= 0xFFFF) max_size = 4; | |
| else if (ent->sampleID >= 0xFF) max_size = MAX(2, max_size); | |
| else max_size = MAX(1, max_size); | |
| for (j=0; j<ent->nb_refs; j++) { | |
| if (ent->sample_refs[j] > 0xFFFF) max_size = 4; | |
| else if (ent->sample_refs[j] > 0xFF) max_size = MAX(2, max_size); | |
| else max_size = MAX(1, max_size); | |
| } | |
| } | |
| ptr->size += max_size*nb_entries + max_size*nb_refs + max_size*tot_entries; | |
| if (max_size==4) ptr->flags = 1<<1; | |
| else if (max_size==2) ptr->flags = 1; | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| GF_Box *srat_box_new() | |
| { | |
| ISOM_DECL_BOX_ALLOC(GF_SamplingRateBox, GF_ISOM_BOX_TYPE_SRAT); | |
| return (GF_Box *)tmp; | |
| } | |
| void srat_box_del(GF_Box *s) | |
| { | |
| gf_free(s); | |
| } | |
| GF_Err srat_box_read(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_SamplingRateBox *ptr = (GF_SamplingRateBox *)s; | |
| ISOM_DECREASE_SIZE(ptr, 4) | |
| ptr->sampling_rate = gf_bs_read_u32(bs); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_ISOM_WRITE | |
| GF_Err srat_box_write(GF_Box *s, GF_BitStream *bs) | |
| { | |
| GF_Err e; | |
| GF_SamplingRateBox *ptr = (GF_SamplingRateBox *)s; | |
| e = gf_isom_full_box_write(s, bs); | |
| if (e) return e; | |
| gf_bs_write_u32(bs, ptr->sampling_rate); | |
| return GF_OK; | |
| } | |
| GF_Err srat_box_size(GF_Box *s) | |
| { | |
| s->size += 4; | |
| return GF_OK; | |
| } | |
| #endif // GPAC_DISABLE_ISOM_WRITE | |
| #endif /*GPAC_DISABLE_ISOM*/ |