| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2019 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / MPEG-4 ObjectDescriptor 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/odf_dev.h> | |
| #include <gpac/utf.h> | |
| #define DATE_CODING_LEN 5 | |
| #ifndef GPAC_MINIMAL_ODF | |
| static GFINLINE GF_Err OD_ReadUTF8String(GF_BitStream *bs, char **string, Bool isUTF8, u32 *read) | |
| { | |
| u32 len; | |
| *read = 1; | |
| len = gf_bs_read_int(bs, 8) + 1; | |
| if (gf_bs_available(bs) < len) return GF_BAD_PARAM; | |
| if (!isUTF8) len *= 2; | |
| (*string) = (char *) gf_malloc(sizeof(char)*(len+1)); | |
| if (! (*string) ) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, (*string), len); | |
| (*string)[len] = 0; | |
| *read += len; | |
| return GF_OK; | |
| } | |
| static GFINLINE u32 OD_SizeUTF8String(char *string, Bool isUTF8) | |
| { | |
| if (isUTF8) return 1 + (u32) strlen(string); | |
| return 1 + 2 * gf_utf8_wcslen((const unsigned short *)string); | |
| } | |
| static GFINLINE void OD_WriteUTF8String(GF_BitStream *bs, char *string, Bool isUTF8) | |
| { | |
| u32 len; | |
| if (isUTF8) { | |
| len = (u32) strlen(string); | |
| gf_bs_write_int(bs, len, 8); | |
| gf_bs_write_data(bs, string, len); | |
| } else { | |
| len = gf_utf8_wcslen((const unsigned short *)string); | |
| gf_bs_write_int(bs, len, 8); | |
| gf_bs_write_data(bs, string, len*2); | |
| } | |
| } | |
| #endif // GPAC_MINIMAL_ODF | |
| /*use to parse strings read the length as well - Warning : the alloc is done here !!*/ | |
| GF_Err gf_odf_read_url_string(GF_BitStream *bs, char **string, u32 *readBytes) | |
| { | |
| u32 length; | |
| *readBytes = 0; | |
| /*if the string is not NULL, return an error...*/ | |
| if (*string != NULL) return GF_BAD_PARAM; | |
| /*the len is always on 8 bits*/ | |
| length = gf_bs_read_int(bs, 8); | |
| *readBytes = 1; | |
| /*JLF AMD to MPEG-4 systems :) - This is not conformant at all, just hoping MPEG will accept it soon | |
| since 255bytes URL is a real pain in the neck*/ | |
| if (!length) { | |
| length = gf_bs_read_int(bs, 32); | |
| *readBytes += 4; | |
| if (length>0xFFFF) return GF_ODF_INVALID_DESCRIPTOR; | |
| } | |
| /*we want to use strlen to get rid of "stringLength" => we need an extra 0*/ | |
| (*string) = (char *) gf_malloc(length + 1); | |
| if (! *string) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, (*string), length); | |
| *readBytes += length; | |
| (*string)[length] = 0; | |
| return GF_OK; | |
| } | |
| /*writes string*/ | |
| GF_Err gf_odf_write_url_string(GF_BitStream *bs, char *string) | |
| { | |
| u32 len; | |
| /*we accept NULL strings now*/ | |
| if (!string) { | |
| gf_bs_write_int(bs, 0, 8); | |
| return GF_OK; | |
| } | |
| len = (u32) strlen(string); | |
| if (len > 255) { | |
| gf_bs_write_int(bs, 0, 8); | |
| gf_bs_write_int(bs, len, 32); | |
| } else { | |
| gf_bs_write_int(bs, len, 8); | |
| } | |
| gf_bs_write_data(bs, string, len); | |
| return GF_OK; | |
| } | |
| u32 gf_odf_size_url_string(char *string) | |
| { | |
| u32 len = (u32) strlen(string); | |
| if (len>255) return len+5; | |
| return len+1; | |
| } | |
| GF_Descriptor *gf_odf_new_esd() | |
| { | |
| GF_ESD *newDesc = (GF_ESD *) gf_malloc(sizeof(GF_ESD)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_ESD)); | |
| newDesc->IPIDataSet = gf_list_new(); | |
| newDesc->IPMPDescriptorPointers = gf_list_new(); | |
| newDesc->extensionDescriptors = gf_list_new(); | |
| newDesc->tag = GF_ODF_ESD_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_esd(GF_ESD *esd) | |
| { | |
| GF_Err e; | |
| if (!esd) return GF_BAD_PARAM; | |
| if (esd->URLString) gf_free(esd->URLString); | |
| if (esd->decoderConfig) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) esd->decoderConfig); | |
| if (e) return e; | |
| } | |
| if (esd->slConfig) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) esd->slConfig); | |
| if (e) return e; | |
| } | |
| if (esd->ipiPtr) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) esd->ipiPtr); | |
| if (e) return e; | |
| } | |
| if (esd->qos) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) esd->qos); | |
| if (e) return e; | |
| } | |
| if (esd->RegDescriptor) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) esd->RegDescriptor); | |
| if (e) return e; | |
| } | |
| if (esd->langDesc) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) esd->langDesc); | |
| if (e) return e; | |
| } | |
| e = gf_odf_delete_descriptor_list(esd->IPIDataSet); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(esd->IPMPDescriptorPointers); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(esd->extensionDescriptors); | |
| if (e) return e; | |
| gf_free(esd); | |
| return GF_OK; | |
| } | |
| GF_Err AddDescriptorToESD(GF_ESD *esd, GF_Descriptor *desc) | |
| { | |
| if (!esd || !desc) return GF_BAD_PARAM; | |
| switch (desc->tag) { | |
| case GF_ODF_DCD_TAG: | |
| if (esd->decoderConfig) return GF_ODF_INVALID_DESCRIPTOR; | |
| esd->decoderConfig = (GF_DecoderConfig *) desc; | |
| break; | |
| case GF_ODF_SLC_TAG: | |
| if (esd->slConfig) return GF_ODF_INVALID_DESCRIPTOR; | |
| esd->slConfig = (GF_SLConfig *) desc; | |
| break; | |
| case GF_ODF_MUXINFO_TAG: | |
| gf_list_add(esd->extensionDescriptors, desc); | |
| break; | |
| case GF_ODF_LANG_TAG: | |
| if (esd->langDesc) return GF_ODF_INVALID_DESCRIPTOR; | |
| esd->langDesc = (GF_Language *) desc; | |
| break; | |
| #ifndef GPAC_MINIMAL_ODF | |
| //the GF_ODF_ISOM_IPI_PTR_TAG is only used in the file format and replaces GF_ODF_IPI_PTR_TAG... | |
| case GF_ODF_ISOM_IPI_PTR_TAG: | |
| case GF_ODF_IPI_PTR_TAG: | |
| if (esd->ipiPtr) return GF_ODF_INVALID_DESCRIPTOR; | |
| esd->ipiPtr = (GF_IPIPtr *) desc; | |
| break; | |
| case GF_ODF_QOS_TAG: | |
| if (esd->qos) return GF_ODF_INVALID_DESCRIPTOR; | |
| esd->qos =(GF_QoS_Descriptor *) desc; | |
| break; | |
| case GF_ODF_CI_TAG: | |
| case GF_ODF_SCI_TAG: | |
| return gf_list_add(esd->IPIDataSet, desc); | |
| //we use the same struct for v1 and v2 IPMP DPs | |
| case GF_ODF_IPMP_PTR_TAG: | |
| return gf_list_add(esd->IPMPDescriptorPointers, desc); | |
| case GF_ODF_REG_TAG: | |
| if (esd->RegDescriptor) return GF_ODF_INVALID_DESCRIPTOR; | |
| esd->RegDescriptor =(GF_Registration *) desc; | |
| break; | |
| #endif | |
| default: | |
| if ( (desc->tag >= GF_ODF_EXT_BEGIN_TAG) && | |
| (desc->tag <= GF_ODF_EXT_END_TAG) ) { | |
| return gf_list_add(esd->extensionDescriptors, desc); | |
| } | |
| return GF_BAD_PARAM; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_esd(GF_BitStream *bs, GF_ESD *esd, u32 DescSize) | |
| { | |
| GF_Err e = GF_OK; | |
| u32 ocrflag, urlflag, streamdependflag, tmp_size, nbBytes, read; | |
| if (! esd) return GF_BAD_PARAM; | |
| nbBytes = 0; | |
| esd->ESID = gf_bs_read_int(bs, 16); | |
| streamdependflag = gf_bs_read_int(bs, 1); | |
| urlflag = gf_bs_read_int(bs, 1); | |
| ocrflag = gf_bs_read_int(bs, 1); | |
| esd->streamPriority = gf_bs_read_int(bs, 5); | |
| nbBytes += 3; | |
| if (streamdependflag) { | |
| esd->dependsOnESID = gf_bs_read_int(bs, 16); | |
| nbBytes += 2; | |
| } | |
| if (urlflag) { | |
| e = gf_odf_read_url_string(bs, & esd->URLString, &read); | |
| if (e) return e; | |
| nbBytes += read; | |
| } | |
| if (ocrflag) { | |
| esd->OCRESID = gf_bs_read_int(bs, 16); | |
| nbBytes += 2; | |
| } | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmp_size); | |
| /*fix for iPod files*/ | |
| if (e==GF_ODF_INVALID_DESCRIPTOR) { | |
| nbBytes += tmp_size; | |
| if (nbBytes>DescSize) return e; | |
| gf_bs_read_int(bs, DescSize-nbBytes); | |
| return GF_OK; | |
| } | |
| if (e) return e; | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = AddDescriptorToESD(esd, tmp); | |
| if (e) { | |
| gf_odf_desc_del(tmp); | |
| return e; | |
| } | |
| nbBytes += tmp_size + gf_odf_size_field_size(tmp_size); | |
| //apple fix | |
| if (!tmp_size) nbBytes = DescSize; | |
| } | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return e; | |
| } | |
| GF_Err gf_odf_size_esd(GF_ESD *esd, u32 *outSize) | |
| { | |
| GF_Err e; | |
| u32 tmpSize; | |
| if (! esd) return GF_BAD_PARAM; | |
| *outSize = 0; | |
| *outSize += 3; | |
| if (esd->dependsOnESID) *outSize += 2; | |
| if (esd->URLString) *outSize += gf_odf_size_url_string(esd->URLString); | |
| if (esd->OCRESID) *outSize += 2; | |
| if (esd->decoderConfig) { | |
| e = gf_odf_size_descriptor((GF_Descriptor *) esd->decoderConfig, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (esd->slConfig) { | |
| e = gf_odf_size_descriptor((GF_Descriptor *) esd->slConfig, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (esd->ipiPtr) { | |
| e = gf_odf_size_descriptor((GF_Descriptor *) esd->ipiPtr, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (esd->langDesc) { | |
| e = gf_odf_size_descriptor((GF_Descriptor *) esd->langDesc, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| e = gf_odf_size_descriptor_list(esd->IPIDataSet, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(esd->IPMPDescriptorPointers, outSize); | |
| if (e) return e; | |
| if (esd->qos) { | |
| e = gf_odf_size_descriptor((GF_Descriptor *) esd->qos, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (esd->RegDescriptor) { | |
| e = gf_odf_size_descriptor((GF_Descriptor *) esd->RegDescriptor, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| return gf_odf_size_descriptor_list(esd->extensionDescriptors, outSize); | |
| } | |
| GF_Err gf_odf_write_esd(GF_BitStream *bs, GF_ESD *esd) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! esd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)esd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, esd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, esd->ESID, 16); | |
| gf_bs_write_int(bs, esd->dependsOnESID ? 1 : 0, 1); | |
| gf_bs_write_int(bs, esd->URLString != NULL ? 1 : 0, 1); | |
| gf_bs_write_int(bs, esd->OCRESID ? 1 : 0, 1); | |
| gf_bs_write_int(bs, esd->streamPriority, 5); | |
| if (esd->dependsOnESID) { | |
| gf_bs_write_int(bs, esd->dependsOnESID, 16); | |
| } | |
| if (esd->URLString) { | |
| e = gf_odf_write_url_string(bs, esd->URLString); | |
| if (e) return e; | |
| } | |
| if (esd->OCRESID) { | |
| gf_bs_write_int(bs, esd->OCRESID, 16); | |
| } | |
| if (esd->decoderConfig) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) esd->decoderConfig); | |
| if (e) return e; | |
| } | |
| if (esd->slConfig) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) esd->slConfig); | |
| if (e) return e; | |
| } | |
| if (esd->ipiPtr) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) esd->ipiPtr); | |
| if (e) return e; | |
| } | |
| if (esd->langDesc) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) esd->langDesc); | |
| if (e) return e; | |
| } | |
| e = gf_odf_write_descriptor_list(bs, esd->IPIDataSet); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, esd->IPMPDescriptorPointers); | |
| if (e) return e; | |
| if (esd->qos) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) esd->qos); | |
| if (e) return e; | |
| } | |
| if (esd->RegDescriptor) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) esd->RegDescriptor); | |
| if (e) return e; | |
| } | |
| return gf_odf_write_descriptor_list(bs, esd->extensionDescriptors); | |
| } | |
| GF_Descriptor *gf_odf_new_iod() | |
| { | |
| GF_InitialObjectDescriptor *newDesc = (GF_InitialObjectDescriptor *) gf_malloc(sizeof(GF_InitialObjectDescriptor)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_InitialObjectDescriptor)); | |
| newDesc->ESDescriptors = gf_list_new(); | |
| newDesc->OCIDescriptors = gf_list_new(); | |
| newDesc->IPMP_Descriptors = gf_list_new(); | |
| newDesc->extensionDescriptors = gf_list_new(); | |
| newDesc->tag = GF_ODF_IOD_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_iod(GF_InitialObjectDescriptor *iod) | |
| { | |
| GF_Err e; | |
| if (!iod) return GF_BAD_PARAM; | |
| if (iod->URLString) gf_free(iod->URLString); | |
| e = gf_odf_delete_descriptor_list(iod->ESDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->IPMP_Descriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->extensionDescriptors); | |
| if (e) return e; | |
| if (iod->IPMPToolList) gf_odf_delete_descriptor((GF_Descriptor *) iod->IPMPToolList); | |
| gf_free(iod); | |
| return GF_OK; | |
| } | |
| GF_Err AddDescriptorToIOD(GF_InitialObjectDescriptor *iod, GF_Descriptor *desc) | |
| { | |
| if (!iod || !desc) return GF_BAD_PARAM; | |
| switch (desc->tag) { | |
| case GF_ODF_ESD_TAG: | |
| return gf_list_add(iod->ESDescriptors, desc); | |
| //we use the same struct for v1 and v2 IPMP DPs | |
| case GF_ODF_IPMP_PTR_TAG: | |
| /*IPMPX*/ | |
| case GF_ODF_IPMP_TAG: | |
| return gf_list_add(iod->IPMP_Descriptors, desc); | |
| /*IPMPX*/ | |
| case GF_ODF_IPMP_TL_TAG: | |
| if (iod->IPMPToolList) gf_odf_desc_del((GF_Descriptor *)iod->IPMPToolList); | |
| iod->IPMPToolList = (GF_IPMP_ToolList *)desc; | |
| return GF_OK; | |
| default: | |
| break; | |
| } | |
| if ( (desc->tag >= GF_ODF_OCI_BEGIN_TAG) && (desc->tag <= GF_ODF_OCI_END_TAG) ) return gf_list_add(iod->OCIDescriptors, desc); | |
| if ( (desc->tag >= GF_ODF_EXT_BEGIN_TAG) && (desc->tag <= GF_ODF_EXT_END_TAG) ) return gf_list_add(iod->extensionDescriptors, desc); | |
| return GF_BAD_PARAM; | |
| } | |
| GF_Err gf_odf_read_iod(GF_BitStream *bs, GF_InitialObjectDescriptor *iod, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 urlflag, read; | |
| u32 tmp_size, nbBytes = 0; | |
| if (! iod) return GF_BAD_PARAM; | |
| iod->objectDescriptorID = gf_bs_read_int(bs, 10); | |
| urlflag = gf_bs_read_int(bs, 1); | |
| iod->inlineProfileFlag = gf_bs_read_int(bs, 1); | |
| /*reserved = */gf_bs_read_int(bs, 4); | |
| nbBytes += 2; | |
| if (urlflag) { | |
| e = gf_odf_read_url_string(bs, & iod->URLString, &read); | |
| if (e) return e; | |
| nbBytes += read; | |
| } else { | |
| iod->OD_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->scene_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->audio_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->visual_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->graphics_profileAndLevel = gf_bs_read_int(bs, 8); | |
| nbBytes += 5; | |
| } | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmp_size); | |
| if (e) return e; | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = AddDescriptorToIOD(iod, tmp); | |
| if (e) { | |
| gf_odf_delete_descriptor(tmp); | |
| return e; | |
| } | |
| nbBytes += tmp_size + gf_odf_size_field_size(tmp_size); | |
| } | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_iod(GF_InitialObjectDescriptor *iod, u32 *outSize) | |
| { | |
| GF_Err e; | |
| if (! iod) return GF_BAD_PARAM; | |
| *outSize = 0; | |
| *outSize += 2; | |
| if (iod->URLString) { | |
| *outSize += gf_odf_size_url_string(iod->URLString); | |
| } else { | |
| *outSize += 5; | |
| e = gf_odf_size_descriptor_list(iod->ESDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(iod->OCIDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(iod->IPMP_Descriptors, outSize); | |
| if (e) return e; | |
| } | |
| e = gf_odf_size_descriptor_list(iod->extensionDescriptors, outSize); | |
| if (e) return e; | |
| if (iod->IPMPToolList) { | |
| u32 tmpSize; | |
| e = gf_odf_size_descriptor((GF_Descriptor *) iod->IPMPToolList, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_iod(GF_BitStream *bs, GF_InitialObjectDescriptor *iod) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! iod) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)iod, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, iod->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, iod->objectDescriptorID, 10); | |
| gf_bs_write_int(bs, iod->URLString != NULL ? 1 : 0, 1); | |
| gf_bs_write_int(bs, iod->inlineProfileFlag, 1); | |
| gf_bs_write_int(bs, 15, 4); //reserved: 0b1111 == 15 | |
| if (iod->URLString) { | |
| gf_odf_write_url_string(bs, iod->URLString); | |
| } else { | |
| gf_bs_write_int(bs, iod->OD_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->scene_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->audio_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->visual_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->graphics_profileAndLevel, 8); | |
| e = gf_odf_write_descriptor_list(bs, iod->ESDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, iod->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, iod->IPMP_Descriptors, GF_ODF_IPMP_PTR_TAG); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, iod->IPMP_Descriptors, GF_ODF_IPMP_TAG); | |
| if (e) return e; | |
| if (iod->IPMPToolList) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) iod->IPMPToolList); | |
| if (e) return e; | |
| } | |
| } | |
| return gf_odf_write_descriptor_list(bs, iod->extensionDescriptors); | |
| } | |
| GF_Descriptor *gf_odf_new_od() | |
| { | |
| GF_ObjectDescriptor *newDesc; | |
| GF_SAFEALLOC(newDesc, GF_ObjectDescriptor); | |
| if (!newDesc) return NULL; | |
| newDesc->URLString = NULL; | |
| newDesc->ESDescriptors = gf_list_new(); | |
| newDesc->OCIDescriptors = gf_list_new(); | |
| newDesc->IPMP_Descriptors = gf_list_new(); | |
| newDesc->extensionDescriptors = gf_list_new(); | |
| newDesc->objectDescriptorID = 0; | |
| newDesc->tag = GF_ODF_OD_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_od(GF_ObjectDescriptor *od) | |
| { | |
| GF_Err e; | |
| if (!od) return GF_BAD_PARAM; | |
| if (od->URLString) gf_free(od->URLString); | |
| e = gf_odf_delete_descriptor_list(od->ESDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->IPMP_Descriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->extensionDescriptors); | |
| if (e) return e; | |
| gf_free(od); | |
| return GF_OK; | |
| } | |
| GF_Err AddDescriptorToOD(GF_ObjectDescriptor *od, GF_Descriptor *desc) | |
| { | |
| if (!od || !desc) return GF_BAD_PARAM; | |
| //check if we can handle ContentClassif tags | |
| if ( (desc->tag >= GF_ODF_OCI_BEGIN_TAG) && | |
| (desc->tag <= GF_ODF_OCI_END_TAG) ) { | |
| return gf_list_add(od->OCIDescriptors, desc); | |
| } | |
| //or extensions | |
| if ( (desc->tag >= GF_ODF_EXT_BEGIN_TAG) && | |
| (desc->tag <= GF_ODF_EXT_END_TAG) ) { | |
| return gf_list_add(od->extensionDescriptors, desc); | |
| } | |
| //to cope with envivio | |
| switch (desc->tag) { | |
| case GF_ODF_ESD_TAG: | |
| case GF_ODF_ESD_REF_TAG: | |
| return gf_list_add(od->ESDescriptors, desc); | |
| //we use the same struct for v1 and v2 IPMP DPs | |
| case GF_ODF_IPMP_PTR_TAG: | |
| case GF_ODF_IPMP_TAG: | |
| return gf_list_add(od->IPMP_Descriptors, desc); | |
| default: | |
| return GF_BAD_PARAM; | |
| } | |
| } | |
| GF_Err gf_odf_read_od(GF_BitStream *bs, GF_ObjectDescriptor *od, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 urlflag; | |
| u32 tmpSize, nbBytes = 0; | |
| if (! od) return GF_BAD_PARAM; | |
| od->objectDescriptorID = gf_bs_read_int(bs, 10); | |
| urlflag = gf_bs_read_int(bs, 1); | |
| /*reserved = */gf_bs_read_int(bs, 5); | |
| nbBytes += 2; | |
| if (urlflag) { | |
| u32 read; | |
| e = gf_odf_read_url_string(bs, & od->URLString, &read); | |
| if (e) return e; | |
| nbBytes += read; | |
| } | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmpSize); | |
| if (e) return e; | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = AddDescriptorToOD(od, tmp); | |
| if (e) { | |
| gf_odf_desc_del(tmp); | |
| return e; | |
| } | |
| nbBytes += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_od(GF_ObjectDescriptor *od, u32 *outSize) | |
| { | |
| GF_Err e; | |
| if (! od) return GF_BAD_PARAM; | |
| *outSize = 2; | |
| if (od->URLString) { | |
| *outSize += gf_odf_size_url_string(od->URLString); | |
| } else { | |
| e = gf_odf_size_descriptor_list(od->ESDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(od->OCIDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(od->IPMP_Descriptors, outSize); | |
| if (e) return e; | |
| } | |
| return gf_odf_size_descriptor_list(od->extensionDescriptors, outSize); | |
| } | |
| GF_Err gf_odf_write_od(GF_BitStream *bs, GF_ObjectDescriptor *od) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! od) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)od, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, od->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, od->objectDescriptorID, 10); | |
| gf_bs_write_int(bs, od->URLString != NULL ? 1 : 0, 1); | |
| gf_bs_write_int(bs, 31, 5); //reserved: 0b1111.1 == 31 | |
| if (od->URLString) { | |
| gf_odf_write_url_string(bs, od->URLString); | |
| } else { | |
| e = gf_odf_write_descriptor_list(bs, od->ESDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, od->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, od->IPMP_Descriptors, GF_ODF_IPMP_PTR_TAG); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, od->IPMP_Descriptors, GF_ODF_IPMP_TAG); | |
| if (e) return e; | |
| } | |
| return gf_odf_write_descriptor_list(bs, od->extensionDescriptors); | |
| } | |
| GF_Descriptor *gf_odf_new_isom_iod() | |
| { | |
| GF_IsomInitialObjectDescriptor *newDesc = (GF_IsomInitialObjectDescriptor *) gf_malloc(sizeof(GF_IsomInitialObjectDescriptor)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_IsomInitialObjectDescriptor)); | |
| newDesc->ES_ID_IncDescriptors = gf_list_new(); | |
| newDesc->ES_ID_RefDescriptors = gf_list_new(); | |
| newDesc->OCIDescriptors = gf_list_new(); | |
| newDesc->IPMP_Descriptors = gf_list_new(); | |
| newDesc->extensionDescriptors = gf_list_new(); | |
| newDesc->tag = GF_ODF_ISOM_IOD_TAG; | |
| //by default create an IOD with no inline and no capabilities | |
| newDesc->audio_profileAndLevel = 0xFF; | |
| newDesc->graphics_profileAndLevel = 0xFF; | |
| newDesc->scene_profileAndLevel = 0xFF; | |
| newDesc->OD_profileAndLevel = 0xFF; | |
| newDesc->visual_profileAndLevel = 0xFF; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_isom_iod(GF_IsomInitialObjectDescriptor *iod) | |
| { | |
| GF_Err e; | |
| if (!iod) return GF_BAD_PARAM; | |
| if (iod->URLString) gf_free(iod->URLString); | |
| e = gf_odf_delete_descriptor_list(iod->ES_ID_IncDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->ES_ID_RefDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->IPMP_Descriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(iod->extensionDescriptors); | |
| if (e) return e; | |
| if (iod->IPMPToolList) gf_odf_delete_descriptor((GF_Descriptor *) iod->IPMPToolList); | |
| gf_free(iod); | |
| return GF_OK; | |
| } | |
| GF_Err AddDescriptorToIsomIOD(GF_IsomInitialObjectDescriptor *iod, GF_Descriptor *desc) | |
| { | |
| if (!iod || !desc) return GF_BAD_PARAM; | |
| switch (desc->tag) { | |
| case GF_ODF_ESD_TAG: | |
| return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| case GF_ODF_ESD_INC_TAG: | |
| //there shouldn't be ref if inc | |
| if (gf_list_count(iod->ES_ID_RefDescriptors)) return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| return gf_list_add(iod->ES_ID_IncDescriptors, desc); | |
| case GF_ODF_ESD_REF_TAG: | |
| //there shouldn't be inc if ref | |
| if (gf_list_count(iod->ES_ID_IncDescriptors)) return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| return gf_list_add(iod->ES_ID_RefDescriptors, desc); | |
| //we use the same struct for v1 and v2 IPMP DPs | |
| case GF_ODF_IPMP_PTR_TAG: | |
| case GF_ODF_IPMP_TAG: | |
| return gf_list_add(iod->IPMP_Descriptors, desc); | |
| /*IPMPX*/ | |
| case GF_ODF_IPMP_TL_TAG: | |
| if (iod->IPMPToolList) gf_odf_desc_del((GF_Descriptor *)iod->IPMPToolList); | |
| iod->IPMPToolList = (GF_IPMP_ToolList *)desc; | |
| return GF_OK; | |
| default: | |
| break; | |
| } | |
| //check if we can handle ContentClassif tags | |
| if ( (desc->tag >= GF_ODF_OCI_BEGIN_TAG) && (desc->tag <= GF_ODF_OCI_END_TAG) ) return gf_list_add(iod->OCIDescriptors, desc); | |
| //or extensions | |
| if ( (desc->tag >= GF_ODF_EXT_BEGIN_TAG) && (desc->tag <= GF_ODF_EXT_END_TAG) ) return gf_list_add(iod->extensionDescriptors, desc); | |
| return GF_BAD_PARAM; | |
| } | |
| GF_Err gf_odf_read_isom_iod(GF_BitStream *bs, GF_IsomInitialObjectDescriptor *iod, u32 DescSize) | |
| { | |
| u32 nbBytes = 0, tmpSize; | |
| u32 urlflag; | |
| GF_Err e; | |
| if (! iod) return GF_BAD_PARAM; | |
| iod->objectDescriptorID = gf_bs_read_int(bs, 10); | |
| urlflag = gf_bs_read_int(bs, 1); | |
| iod->inlineProfileFlag = gf_bs_read_int(bs, 1); | |
| /*reserved = */gf_bs_read_int(bs, 4); | |
| nbBytes += 2; | |
| if (urlflag) { | |
| u32 read; | |
| e = gf_odf_read_url_string(bs, & iod->URLString, &read); | |
| if (e) return e; | |
| nbBytes += read; | |
| } else { | |
| iod->OD_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->scene_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->audio_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->visual_profileAndLevel = gf_bs_read_int(bs, 8); | |
| iod->graphics_profileAndLevel = gf_bs_read_int(bs, 8); | |
| nbBytes += 5; | |
| } | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmpSize); | |
| if (e) { | |
| if (tmp) gf_odf_desc_del((GF_Descriptor *) tmp); | |
| return e; | |
| } | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = AddDescriptorToIsomIOD(iod, tmp); | |
| if (e) { | |
| gf_odf_desc_del(tmp); | |
| return e; | |
| } | |
| nbBytes += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_isom_iod(GF_IsomInitialObjectDescriptor *iod, u32 *outSize) | |
| { | |
| GF_Err e; | |
| if (! iod) return GF_BAD_PARAM; | |
| *outSize = 2; | |
| if (iod->URLString) { | |
| *outSize += gf_odf_size_url_string(iod->URLString); | |
| } else { | |
| *outSize += 5; | |
| e = gf_odf_size_descriptor_list(iod->ES_ID_IncDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(iod->ES_ID_RefDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(iod->OCIDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(iod->IPMP_Descriptors, outSize); | |
| if (e) return e; | |
| } | |
| if (iod->IPMPToolList) { | |
| u32 tmpSize; | |
| e = gf_odf_size_descriptor((GF_Descriptor *) iod->IPMPToolList, &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| return gf_odf_size_descriptor_list(iod->extensionDescriptors, outSize); | |
| } | |
| GF_Err gf_odf_write_isom_iod(GF_BitStream *bs, GF_IsomInitialObjectDescriptor *iod) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! iod) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)iod, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, iod->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, iod->objectDescriptorID, 10); | |
| gf_bs_write_int(bs, iod->URLString != NULL ? 1 : 0, 1); | |
| gf_bs_write_int(bs, iod->inlineProfileFlag, 1); | |
| gf_bs_write_int(bs, 15, 4); //reserved: 0b1111 == 15 | |
| if (iod->URLString) { | |
| gf_odf_write_url_string(bs, iod->URLString); | |
| } else { | |
| gf_bs_write_int(bs, iod->OD_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->scene_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->audio_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->visual_profileAndLevel, 8); | |
| gf_bs_write_int(bs, iod->graphics_profileAndLevel, 8); | |
| e = gf_odf_write_descriptor_list(bs, iod->ES_ID_IncDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, iod->ES_ID_RefDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, iod->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, iod->IPMP_Descriptors, GF_ODF_IPMP_PTR_TAG); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, iod->IPMP_Descriptors, GF_ODF_IPMP_TAG); | |
| if (e) return e; | |
| if (iod->IPMPToolList) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) iod->IPMPToolList); | |
| if (e) return e; | |
| } | |
| } | |
| e = gf_odf_write_descriptor_list(bs, iod->extensionDescriptors); | |
| if (e) return e; | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_isom_od() | |
| { | |
| GF_IsomObjectDescriptor *newDesc = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomObjectDescriptor)); | |
| if (!newDesc) return NULL; | |
| newDesc->URLString = NULL; | |
| newDesc->ES_ID_IncDescriptors = gf_list_new(); | |
| newDesc->ES_ID_RefDescriptors = gf_list_new(); | |
| newDesc->OCIDescriptors = gf_list_new(); | |
| newDesc->IPMP_Descriptors = gf_list_new(); | |
| newDesc->extensionDescriptors = gf_list_new(); | |
| newDesc->objectDescriptorID = 0; | |
| newDesc->tag = GF_ODF_ISOM_OD_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_isom_od(GF_IsomObjectDescriptor *od) | |
| { | |
| GF_Err e; | |
| if (!od) return GF_BAD_PARAM; | |
| if (od->URLString) gf_free(od->URLString); | |
| e = gf_odf_delete_descriptor_list(od->ES_ID_IncDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->ES_ID_RefDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->IPMP_Descriptors); | |
| if (e) return e; | |
| e = gf_odf_delete_descriptor_list(od->extensionDescriptors); | |
| if (e) return e; | |
| gf_free(od); | |
| return GF_OK; | |
| } | |
| GF_Err AddDescriptorToIsomOD(GF_IsomObjectDescriptor *od, GF_Descriptor *desc) | |
| { | |
| if (!od || !desc) return GF_BAD_PARAM; | |
| //check if we can handle ContentClassif tags | |
| if ( (desc->tag >= GF_ODF_OCI_BEGIN_TAG) && | |
| (desc->tag <= GF_ODF_OCI_END_TAG) ) { | |
| return gf_list_add(od->OCIDescriptors, desc); | |
| } | |
| //or extension ... | |
| if ( (desc->tag >= GF_ODF_EXT_BEGIN_TAG) && | |
| (desc->tag <= GF_ODF_EXT_END_TAG) ) { | |
| return gf_list_add(od->extensionDescriptors, desc); | |
| } | |
| switch (desc->tag) { | |
| case GF_ODF_ESD_TAG: | |
| return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| case GF_ODF_ESD_INC_TAG: | |
| //there shouldn't be ref if inc | |
| if (gf_list_count(od->ES_ID_RefDescriptors)) return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| return gf_list_add(od->ES_ID_IncDescriptors, desc); | |
| case GF_ODF_ESD_REF_TAG: | |
| //there shouldn't be inc if ref | |
| if (gf_list_count(od->ES_ID_IncDescriptors)) return GF_ODF_FORBIDDEN_DESCRIPTOR; | |
| return gf_list_add(od->ES_ID_RefDescriptors, desc); | |
| //we use the same struct for v1 and v2 IPMP DPs | |
| case GF_ODF_IPMP_PTR_TAG: | |
| case GF_ODF_IPMP_TAG: | |
| return gf_list_add(od->IPMP_Descriptors, desc); | |
| default: | |
| return GF_BAD_PARAM; | |
| } | |
| } | |
| GF_Err gf_odf_read_isom_od(GF_BitStream *bs, GF_IsomObjectDescriptor *od, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 urlflag; | |
| u32 tmpSize, nbBytes = 0; | |
| if (! od) return GF_BAD_PARAM; | |
| od->objectDescriptorID = gf_bs_read_int(bs, 10); | |
| urlflag = gf_bs_read_int(bs, 1); | |
| /*reserved = */gf_bs_read_int(bs, 5); | |
| nbBytes += 2; | |
| if (urlflag) { | |
| u32 read; | |
| e = gf_odf_read_url_string(bs, & od->URLString, &read); | |
| if (e) return e; | |
| nbBytes += read; | |
| } | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmpSize); | |
| if (e) return e; | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = AddDescriptorToIsomOD(od, tmp); | |
| if (e) { | |
| gf_odf_delete_descriptor(tmp); | |
| return e; | |
| } | |
| nbBytes += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_isom_od(GF_IsomObjectDescriptor *od, u32 *outSize) | |
| { | |
| GF_Err e; | |
| if (! od) return GF_BAD_PARAM; | |
| *outSize = 2; | |
| if (od->URLString) { | |
| *outSize += gf_odf_size_url_string(od->URLString); | |
| } else { | |
| e = gf_odf_size_descriptor_list(od->ES_ID_IncDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(od->ES_ID_RefDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(od->OCIDescriptors, outSize); | |
| if (e) return e; | |
| e = gf_odf_size_descriptor_list(od->IPMP_Descriptors, outSize); | |
| if (e) return e; | |
| } | |
| return gf_odf_size_descriptor_list(od->extensionDescriptors, outSize); | |
| } | |
| GF_Err gf_odf_write_isom_od(GF_BitStream *bs, GF_IsomObjectDescriptor *od) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! od) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)od, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, od->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, od->objectDescriptorID, 10); | |
| gf_bs_write_int(bs, od->URLString != NULL ? 1 : 0, 1); | |
| gf_bs_write_int(bs, 31, 5); //reserved: 0b1111.1 == 31 | |
| if (od->URLString) { | |
| gf_odf_write_url_string(bs, od->URLString); | |
| } else { | |
| e = gf_odf_write_descriptor_list(bs, od->ES_ID_IncDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, od->ES_ID_RefDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list(bs, od->OCIDescriptors); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, od->IPMP_Descriptors, GF_ODF_IPMP_PTR_TAG); | |
| if (e) return e; | |
| e = gf_odf_write_descriptor_list_filter(bs, od->IPMP_Descriptors, GF_ODF_IPMP_TAG); | |
| if (e) return e; | |
| } | |
| e = gf_odf_write_descriptor_list(bs, od->extensionDescriptors); | |
| if (e) return e; | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_dcd() | |
| { | |
| GF_DecoderConfig *newDesc; | |
| GF_SAFEALLOC(newDesc, GF_DecoderConfig); | |
| if (!newDesc) return NULL; | |
| newDesc->profileLevelIndicationIndexDescriptor = gf_list_new(); | |
| newDesc->tag = GF_ODF_DCD_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_dcd(GF_DecoderConfig *dcd) | |
| { | |
| GF_Err e; | |
| if (!dcd) return GF_BAD_PARAM; | |
| if (dcd->decoderSpecificInfo) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) dcd->decoderSpecificInfo); | |
| if (e) return e; | |
| } | |
| if (dcd->rvc_config) { | |
| e = gf_odf_delete_descriptor((GF_Descriptor *) dcd->rvc_config); | |
| if (e) return e; | |
| } | |
| e = gf_odf_delete_descriptor_list(dcd->profileLevelIndicationIndexDescriptor); | |
| if (e) return e; | |
| gf_free(dcd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_dcd(GF_BitStream *bs, GF_DecoderConfig *dcd, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 /*reserved, */tmp_size, nbBytes = 0; | |
| if (! dcd) return GF_BAD_PARAM; | |
| dcd->objectTypeIndication = gf_bs_read_int(bs, 8); | |
| dcd->streamType = gf_bs_read_int(bs, 6); | |
| dcd->upstream = gf_bs_read_int(bs, 1); | |
| /*reserved = */gf_bs_read_int(bs, 1); | |
| dcd->bufferSizeDB = gf_bs_read_int(bs, 24); | |
| dcd->maxBitrate = gf_bs_read_int(bs, 32); | |
| dcd->avgBitrate = gf_bs_read_int(bs, 32); | |
| nbBytes += 13; | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmp_size); | |
| if (e) return e; | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| switch (tmp->tag) { | |
| case GF_ODF_DSI_TAG: | |
| if (dcd->decoderSpecificInfo) { | |
| gf_odf_delete_descriptor(tmp); | |
| return GF_ODF_INVALID_DESCRIPTOR; | |
| } | |
| dcd->decoderSpecificInfo = (GF_DefaultDescriptor *) tmp; | |
| break; | |
| case GF_ODF_EXT_PL_TAG: | |
| e = gf_list_add(dcd->profileLevelIndicationIndexDescriptor, tmp); | |
| if (e < GF_OK) { | |
| gf_odf_delete_descriptor(tmp); | |
| return e; | |
| } | |
| break; | |
| /*iPod fix: delete and aborts, this will create an InvalidDescriptor at the ESD level with a loaded DSI, | |
| loading will abort with a partially valid ESD which is all the matters*/ | |
| case GF_ODF_SLC_TAG: | |
| gf_odf_delete_descriptor(tmp); | |
| return GF_OK; | |
| //what the hell is this descriptor ?? Don't know, so delete it ! | |
| default: | |
| gf_odf_delete_descriptor(tmp); | |
| break; | |
| } | |
| nbBytes += tmp_size + gf_odf_size_field_size(tmp_size); | |
| } | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| #include <gpac/constants.h> | |
| GF_Err gf_odf_size_dcd(GF_DecoderConfig *dcd, u32 *outSize) | |
| { | |
| GF_Err e; | |
| u32 tmpSize; | |
| u32 oti; | |
| if (! dcd) return GF_BAD_PARAM; | |
| oti = dcd->objectTypeIndication; | |
| if (oti > 0xFF) { | |
| oti = gf_codecid_oti(oti); | |
| } | |
| if (oti > 0xFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[ODF] Attempt to write an internal ESD with codec ID %s (%s) , not mappable to 8 bits MPEG-4 Systems OTI", gf_4cc_to_str(dcd->objectTypeIndication), gf_codecid_name(dcd->objectTypeIndication) )); | |
| return GF_BAD_PARAM; | |
| } | |
| *outSize = 0; | |
| *outSize += 13; | |
| if (dcd->decoderSpecificInfo) { | |
| //warning: we don't know anything about the structure of a generic DecSpecInfo | |
| //we check the tag and size of the descriptor, but we most ofthe time can't parse it | |
| //the decSpecInfo is handle as a defaultDescriptor (opaque data, but same structure....) | |
| e = gf_odf_size_descriptor((GF_Descriptor *) dcd->decoderSpecificInfo , &tmpSize); | |
| if (e) return e; | |
| *outSize += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| e = gf_odf_size_descriptor_list(dcd->profileLevelIndicationIndexDescriptor, outSize); | |
| if (e) return e; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_dcd(GF_BitStream *bs, GF_DecoderConfig *dcd) | |
| { | |
| GF_Err e; | |
| u32 size, oti; | |
| if (! dcd) return GF_BAD_PARAM; | |
| oti = dcd->objectTypeIndication; | |
| if (oti > 0xFF) { | |
| oti = gf_codecid_oti(oti); | |
| } | |
| if (oti > 0xFF) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[ODF] Attempt to write an internal ESD with codec ID %s (%s) , not mappable to 8 bits MPEG-4 Systems OTI", gf_4cc_to_str(dcd->objectTypeIndication), gf_codecid_name(dcd->objectTypeIndication) )); | |
| return GF_BAD_PARAM; | |
| } | |
| e = gf_odf_size_descriptor((GF_Descriptor *)dcd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, dcd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, oti, 8); | |
| gf_bs_write_int(bs, dcd->streamType, 6); | |
| gf_bs_write_int(bs, dcd->upstream, 1); | |
| gf_bs_write_int(bs, 1, 1); //reserved field... | |
| gf_bs_write_int(bs, dcd->bufferSizeDB, 24); | |
| gf_bs_write_int(bs, dcd->maxBitrate, 32); | |
| gf_bs_write_int(bs, dcd->avgBitrate, 32); | |
| if (dcd->decoderSpecificInfo) { | |
| e = gf_odf_write_descriptor(bs, (GF_Descriptor *) dcd->decoderSpecificInfo); | |
| if (e) return e; | |
| } | |
| e = gf_odf_write_descriptor_list(bs, dcd->profileLevelIndicationIndexDescriptor); | |
| return e; | |
| } | |
| GF_Descriptor *gf_odf_new_default() | |
| { | |
| GF_DefaultDescriptor *newDesc = (GF_DefaultDescriptor *) gf_malloc(sizeof(GF_DefaultDescriptor)); | |
| if (!newDesc) return NULL; | |
| newDesc->dataLength = 0; | |
| newDesc->data = NULL; | |
| //set it to the Max allowed | |
| newDesc->tag = GF_ODF_USER_END_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_default(GF_DefaultDescriptor *dd) | |
| { | |
| if (!dd) return GF_BAD_PARAM; | |
| if (dd->data) gf_free(dd->data); | |
| gf_free(dd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_default(GF_BitStream *bs, GF_DefaultDescriptor *dd, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (! dd) return GF_BAD_PARAM; | |
| dd->dataLength = DescSize; | |
| dd->data = NULL; | |
| if (DescSize) { | |
| dd->data = (char*)gf_malloc(dd->dataLength); | |
| if (! dd->data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, dd->data, dd->dataLength); | |
| nbBytes += dd->dataLength; | |
| /* internal tags are read as default but deleted as their own types | |
| so dd->data would leak here */ | |
| if ((dd->tag>=GF_ODF_MUXINFO_TAG) && (dd->tag<=GF_ODF_LASER_CFG_TAG)) { | |
| gf_free(dd->data); | |
| dd->data = NULL; | |
| } | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_default(GF_DefaultDescriptor *dd, u32 *outSize) | |
| { | |
| if (! dd) return GF_BAD_PARAM; | |
| *outSize = dd->dataLength; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_default(GF_BitStream *bs, GF_DefaultDescriptor *dd) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! dd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)dd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, dd->tag, size); | |
| if (e) return e; | |
| if (dd->data) { | |
| gf_bs_write_data(bs, dd->data, dd->dataLength); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_esd_inc() | |
| { | |
| GF_ES_ID_Inc *newDesc = (GF_ES_ID_Inc *) gf_malloc(sizeof(GF_ES_ID_Inc)); | |
| if (!newDesc) return NULL; | |
| newDesc->tag = GF_ODF_ESD_INC_TAG; | |
| newDesc->trackID = 0; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_esd_inc(GF_ES_ID_Inc *esd_inc) | |
| { | |
| if (!esd_inc) return GF_BAD_PARAM; | |
| gf_free(esd_inc); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_esd_inc(GF_BitStream *bs, GF_ES_ID_Inc *esd_inc, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (! esd_inc) return GF_BAD_PARAM; | |
| esd_inc->trackID = gf_bs_read_int(bs, 32); | |
| nbBytes += 4; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_esd_inc(GF_ES_ID_Inc *esd_inc, u32 *outSize) | |
| { | |
| if (! esd_inc) return GF_BAD_PARAM; | |
| *outSize = 4; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_esd_inc(GF_BitStream *bs, GF_ES_ID_Inc *esd_inc) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! esd_inc) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)esd_inc, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, esd_inc->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, esd_inc->trackID, 32); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_esd_ref() | |
| { | |
| GF_ES_ID_Ref *newDesc = (GF_ES_ID_Ref *) gf_malloc(sizeof(GF_ES_ID_Ref)); | |
| if (!newDesc) return NULL; | |
| newDesc->tag = GF_ODF_ESD_REF_TAG; | |
| newDesc->trackRef = 0; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_esd_ref(GF_ES_ID_Ref *esd_ref) | |
| { | |
| if (!esd_ref) return GF_BAD_PARAM; | |
| gf_free(esd_ref); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_esd_ref(GF_BitStream *bs, GF_ES_ID_Ref *esd_ref, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (! esd_ref) return GF_BAD_PARAM; | |
| esd_ref->trackRef = gf_bs_read_int(bs, 16); | |
| nbBytes += 2; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_esd_ref(GF_ES_ID_Ref *esd_ref, u32 *outSize) | |
| { | |
| if (! esd_ref) return GF_BAD_PARAM; | |
| *outSize = 2; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_esd_ref(GF_BitStream *bs, GF_ES_ID_Ref *esd_ref) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! esd_ref) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)esd_ref, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, esd_ref->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, esd_ref->trackRef, 16); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_segment() | |
| { | |
| GF_Segment *newDesc = (GF_Segment *) gf_malloc(sizeof(GF_Segment)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_Segment)); | |
| newDesc->tag = GF_ODF_SEGMENT_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_segment(GF_Segment *sd) | |
| { | |
| if (!sd) return GF_BAD_PARAM; | |
| if (sd->SegmentName) gf_free(sd->SegmentName); | |
| gf_free(sd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_segment(GF_BitStream *bs, GF_Segment *sd, u32 DescSize) | |
| { | |
| u32 size, nbBytes = 0; | |
| if (!sd) return GF_BAD_PARAM; | |
| sd->startTime = gf_bs_read_double(bs); | |
| sd->Duration = gf_bs_read_double(bs); | |
| nbBytes += 16; | |
| size = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| if (size) { | |
| sd->SegmentName = (char*) gf_malloc(sizeof(char)*(size+1)); | |
| if (!sd->SegmentName) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, sd->SegmentName, size); | |
| sd->SegmentName[size] = 0; | |
| nbBytes += size; | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_segment(GF_Segment *sd, u32 *outSize) | |
| { | |
| if (!sd) return GF_BAD_PARAM; | |
| *outSize = 17; | |
| if (sd->SegmentName) *outSize += (u32) strlen(sd->SegmentName); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_segment(GF_BitStream *bs, GF_Segment *sd) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!sd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)sd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, sd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_double(bs, sd->startTime); | |
| gf_bs_write_double(bs, sd->Duration); | |
| if (sd->SegmentName) { | |
| gf_bs_write_int(bs, (u32) strlen(sd->SegmentName), 8); | |
| gf_bs_write_data(bs, sd->SegmentName, (u32) strlen(sd->SegmentName)); | |
| } else { | |
| gf_bs_write_int(bs, 0, 8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_lang() | |
| { | |
| GF_Language *newDesc; | |
| GF_SAFEALLOC(newDesc, GF_Language); | |
| if (!newDesc) return NULL; | |
| newDesc->tag = GF_ODF_LANG_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_lang(GF_Language *ld) | |
| { | |
| if (!ld) return GF_BAD_PARAM; | |
| if (ld->full_lang_code) gf_free(ld->full_lang_code); | |
| gf_free(ld); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_lang(GF_BitStream *bs, GF_Language *ld, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!ld) return GF_BAD_PARAM; | |
| ld->langCode = gf_bs_read_int(bs, 24); | |
| nbBytes += 3; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_lang(GF_Language *ld, u32 *outSize) | |
| { | |
| if (!ld) return GF_BAD_PARAM; | |
| *outSize = 3; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_lang(GF_BitStream *bs, GF_Language *ld) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!ld) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ld, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ld->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ld->langCode, 24); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_auxvid() | |
| { | |
| GF_AuxVideoDescriptor *newDesc; | |
| GF_SAFEALLOC(newDesc, GF_AuxVideoDescriptor); | |
| if (!newDesc) return NULL; | |
| newDesc->tag = GF_ODF_AUX_VIDEO_DATA; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_auxvid(GF_AuxVideoDescriptor *ld) | |
| { | |
| if (!ld) return GF_BAD_PARAM; | |
| gf_free(ld); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_auxvid(GF_BitStream *bs, GF_AuxVideoDescriptor *ld, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!ld) return GF_BAD_PARAM; | |
| ld->aux_video_type = gf_bs_read_int(bs, 8); | |
| ld->position_offset_h = gf_bs_read_int(bs, 8); | |
| ld->position_offset_v = gf_bs_read_int(bs, 8); | |
| nbBytes += 3; | |
| switch (ld->aux_video_type) { | |
| case 0x10: | |
| ld->kfar = gf_bs_read_int(bs, 8); | |
| ld->knear = gf_bs_read_int(bs, 8); | |
| nbBytes += 2; | |
| break; | |
| case 0x11: | |
| ld->parallax_zero = gf_bs_read_int(bs, 16); | |
| ld->parallax_scale = gf_bs_read_int(bs, 16); | |
| ld->dref = gf_bs_read_int(bs, 16); | |
| ld->wref = gf_bs_read_int(bs, 16); | |
| nbBytes += 8; | |
| break; | |
| } | |
| while (nbBytes < DescSize) { | |
| gf_bs_read_int(bs, 8); | |
| nbBytes ++; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_auxvid(GF_AuxVideoDescriptor *ld, u32 *outSize) | |
| { | |
| if (!ld) return GF_BAD_PARAM; | |
| switch (ld->aux_video_type) { | |
| case 0x10: | |
| *outSize = 5; | |
| break; | |
| case 0x11: | |
| *outSize = 11; | |
| break; | |
| default: | |
| *outSize = 3; | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_auxvid(GF_BitStream *bs, GF_AuxVideoDescriptor *ld) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!ld) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ld, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ld->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ld->aux_video_type, 8); | |
| gf_bs_write_int(bs, ld->position_offset_h, 8); | |
| gf_bs_write_int(bs, ld->position_offset_v, 8); | |
| switch (ld->aux_video_type) { | |
| case 0x10: | |
| gf_bs_write_int(bs, ld->kfar, 8); | |
| gf_bs_write_int(bs, ld->knear, 8); | |
| break; | |
| case 0x11: | |
| gf_bs_write_int(bs, ld->parallax_zero, 16); | |
| gf_bs_write_int(bs, ld->parallax_scale, 16); | |
| gf_bs_write_int(bs, ld->dref, 16); | |
| gf_bs_write_int(bs, ld->wref, 16); | |
| break; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_muxinfo() | |
| { | |
| GF_MuxInfo *newDesc = (GF_MuxInfo *) gf_malloc(sizeof(GF_MuxInfo)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_MuxInfo)); | |
| newDesc->tag = GF_ODF_MUXINFO_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_muxinfo(GF_MuxInfo *mi) | |
| { | |
| if (!mi) return GF_BAD_PARAM; | |
| if (mi->file_name) gf_free(mi->file_name); | |
| if (mi->src_url) gf_free(mi->src_url); | |
| if (mi->streamFormat) gf_free(mi->streamFormat); | |
| if (mi->textNode) gf_free(mi->textNode); | |
| if (mi->fontNode) gf_free(mi->fontNode); | |
| gf_free(mi); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_muxinfo(GF_MuxInfo *mi, u32 *outSize) | |
| { | |
| *outSize = 0; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_muxinfo(GF_BitStream *bs, GF_MuxInfo *mi) | |
| { | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_New_ElemMask() | |
| { | |
| GF_ElementaryMask *newDesc = (GF_ElementaryMask*) gf_malloc (sizeof(GF_ElementaryMask)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_ElementaryMask)); | |
| newDesc->tag = GF_ODF_ELEM_MASK_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ElemMask(GF_ElementaryMask *desc) | |
| { | |
| if (desc->node_name) gf_free(desc->node_name); | |
| gf_free(desc); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_bifs_cfg() | |
| { | |
| GF_BIFSConfig *newDesc = (GF_BIFSConfig *) gf_malloc(sizeof(GF_BIFSConfig)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_BIFSConfig)); | |
| newDesc->tag = GF_ODF_BIFS_CFG_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_bifs_cfg(GF_BIFSConfig *desc) | |
| { | |
| if (desc->elementaryMasks) { | |
| u32 i, count = gf_list_count(desc->elementaryMasks); | |
| for (i=0; i<count; i++) { | |
| GF_ElementaryMask *tmp = (GF_ElementaryMask *)gf_list_get(desc->elementaryMasks, i); | |
| if (tmp->node_name) gf_free(tmp->node_name); | |
| gf_free(tmp); | |
| } | |
| gf_list_del(desc->elementaryMasks); | |
| } | |
| gf_free(desc); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_laser_cfg() | |
| { | |
| GF_LASERConfig *newDesc = (GF_LASERConfig *) gf_malloc(sizeof(GF_LASERConfig)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_LASERConfig)); | |
| newDesc->tag = GF_ODF_LASER_CFG_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_laser_cfg(GF_LASERConfig *desc) | |
| { | |
| gf_free(desc); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_ui_cfg() | |
| { | |
| GF_UIConfig *newDesc = (GF_UIConfig *) gf_malloc(sizeof(GF_UIConfig)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_UIConfig)); | |
| newDesc->tag = GF_ODF_UI_CFG_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ui_cfg(GF_UIConfig *desc) | |
| { | |
| if (desc->deviceName) gf_free(desc->deviceName); | |
| if (desc->ui_data) gf_free(desc->ui_data); | |
| gf_free(desc); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_MINIMAL_ODF | |
| GF_Descriptor *gf_odf_new_mediatime() | |
| { | |
| GF_MediaTime *newDesc = (GF_MediaTime *) gf_malloc(sizeof(GF_MediaTime)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_MediaTime)); | |
| newDesc->tag = GF_ODF_MEDIATIME_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_mediatime(GF_MediaTime *mt) | |
| { | |
| if (!mt) return GF_BAD_PARAM; | |
| gf_free(mt); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_mediatime(GF_BitStream *bs, GF_MediaTime *mt, u32 DescSize) | |
| { | |
| if (!mt) return GF_BAD_PARAM; | |
| mt->mediaTimeStamp = gf_bs_read_double(bs); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_mediatime(GF_MediaTime *mt, u32 *outSize) | |
| { | |
| if (!mt) return GF_BAD_PARAM; | |
| *outSize = 8; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_mediatime(GF_BitStream *bs, GF_MediaTime *mt) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!mt) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)mt, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, mt->tag, size); | |
| if (e) return e; | |
| gf_bs_write_double(bs, mt->mediaTimeStamp); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_cc() | |
| { | |
| GF_CCDescriptor *newDesc = (GF_CCDescriptor *) gf_malloc(sizeof(GF_CCDescriptor)); | |
| if (!newDesc) return NULL; | |
| newDesc->contentClassificationData = NULL; | |
| newDesc->dataLength = 0; | |
| newDesc->classificationEntity = 0; | |
| newDesc->classificationTable = 0; | |
| newDesc->tag = GF_ODF_CC_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_cc(GF_CCDescriptor *ccd) | |
| { | |
| if (!ccd) return GF_BAD_PARAM; | |
| if (ccd->contentClassificationData) gf_free(ccd->contentClassificationData); | |
| gf_free(ccd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_cc(GF_BitStream *bs, GF_CCDescriptor *ccd, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!ccd) return GF_BAD_PARAM; | |
| ccd->classificationEntity = gf_bs_read_int(bs, 32); | |
| ccd->classificationTable = gf_bs_read_int(bs, 16); | |
| nbBytes += 6; | |
| if (DescSize < 6) return GF_ODF_INVALID_DESCRIPTOR; | |
| ccd->dataLength = DescSize - 6; | |
| ccd->contentClassificationData = (char*)gf_malloc(sizeof(char) * ccd->dataLength); | |
| if (!ccd->contentClassificationData) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ccd->contentClassificationData, ccd->dataLength); | |
| nbBytes += ccd->dataLength; | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_cc(GF_CCDescriptor *ccd, u32 *outSize) | |
| { | |
| if (!ccd) return GF_BAD_PARAM; | |
| *outSize = 6 + ccd->dataLength; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_cc(GF_BitStream *bs, GF_CCDescriptor *ccd) | |
| { | |
| u32 size; | |
| GF_Err e; | |
| if (!ccd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ccd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ccd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ccd->classificationEntity, 32); | |
| gf_bs_write_int(bs, ccd->classificationTable, 16); | |
| gf_bs_write_data(bs, ccd->contentClassificationData, ccd->dataLength); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_cc_date() | |
| { | |
| GF_CC_Date *newDesc = (GF_CC_Date *) gf_malloc(sizeof(GF_CC_Date)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc->contentCreationDate, 0, 5); | |
| newDesc->tag = GF_ODF_CC_DATE_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_cc_date(GF_CC_Date *cdd) | |
| { | |
| if (!cdd) return GF_BAD_PARAM; | |
| gf_free(cdd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_cc_date(GF_BitStream *bs, GF_CC_Date *cdd, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!cdd) return GF_BAD_PARAM; | |
| gf_bs_read_data(bs, cdd->contentCreationDate, DATE_CODING_LEN); | |
| nbBytes += DATE_CODING_LEN; | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_cc_date(GF_CC_Date *cdd, u32 *outSize) | |
| { | |
| if (!cdd) return GF_BAD_PARAM; | |
| *outSize = DATE_CODING_LEN; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_cc_date(GF_BitStream *bs, GF_CC_Date *cdd) | |
| { | |
| u32 size; | |
| GF_Err e; | |
| if (!cdd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)cdd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, cdd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_data(bs, cdd->contentCreationDate, DATE_CODING_LEN); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_cc_name() | |
| { | |
| GF_CC_Name *newDesc = (GF_CC_Name *) gf_malloc(sizeof(GF_CC_Name)); | |
| if (!newDesc) return NULL; | |
| newDesc->ContentCreators = gf_list_new(); | |
| if (! newDesc->ContentCreators) { | |
| gf_free(newDesc); | |
| return NULL; | |
| } | |
| newDesc->tag = GF_ODF_CC_NAME_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_cc_name(GF_CC_Name *cnd) | |
| { | |
| u32 i; | |
| GF_ContentCreatorInfo *tmp; | |
| if (!cnd) return GF_BAD_PARAM; | |
| i=0; | |
| while ((tmp = (GF_ContentCreatorInfo *)gf_list_enum(cnd->ContentCreators, &i))) { | |
| if (tmp->contentCreatorName) gf_free(tmp->contentCreatorName); | |
| gf_free(tmp); | |
| } | |
| gf_list_del(cnd->ContentCreators); | |
| gf_free(cnd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_cc_name(GF_BitStream *bs, GF_CC_Name *cnd, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 i, count, len, nbBytes = 0; | |
| if (!cnd) return GF_BAD_PARAM; | |
| count = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| for (i = 0; i< count; i++) { | |
| GF_ContentCreatorInfo *tmp = (GF_ContentCreatorInfo*)gf_malloc(sizeof(GF_ContentCreatorInfo)); | |
| if (! tmp) return GF_OUT_OF_MEM; | |
| memset(tmp , 0, sizeof(GF_ContentCreatorInfo)); | |
| tmp->langCode = gf_bs_read_int(bs, 24); | |
| tmp->isUTF8 = gf_bs_read_int(bs, 1); | |
| /*aligned = */gf_bs_read_int(bs, 7); | |
| nbBytes += 4; | |
| e = OD_ReadUTF8String(bs, & tmp->contentCreatorName, tmp->isUTF8, &len); | |
| if (e) { | |
| gf_free(tmp); | |
| return e; | |
| } | |
| nbBytes += len; | |
| e = gf_list_add(cnd->ContentCreators, tmp); | |
| if (e) return e; | |
| } | |
| if (DescSize != nbBytes) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_cc_name(GF_CC_Name *cnd, u32 *outSize) | |
| { | |
| u32 i; | |
| GF_ContentCreatorInfo *tmp; | |
| if (!cnd) return GF_BAD_PARAM; | |
| *outSize = 1; | |
| i=0; | |
| while ((tmp = (GF_ContentCreatorInfo *)gf_list_enum(cnd->ContentCreators, &i))) { | |
| *outSize += 4 + OD_SizeUTF8String(tmp->contentCreatorName, tmp->isUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_cc_name(GF_BitStream *bs, GF_CC_Name *cnd) | |
| { | |
| GF_Err e; | |
| GF_ContentCreatorInfo *tmp; | |
| u32 i, size; | |
| if (!cnd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)cnd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, cnd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, gf_list_count(cnd->ContentCreators), 8); | |
| i=0; | |
| while ((tmp = (GF_ContentCreatorInfo *)gf_list_enum(cnd->ContentCreators, &i))) { | |
| gf_bs_write_int(bs, tmp->langCode, 24); | |
| gf_bs_write_int(bs, tmp->isUTF8, 1); | |
| gf_bs_write_int(bs, 0, 7); //aligned | |
| OD_WriteUTF8String(bs, tmp->contentCreatorName, tmp->isUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_ci() | |
| { | |
| GF_CIDesc *newDesc = (GF_CIDesc *) gf_malloc(sizeof(GF_CIDesc)); | |
| if (!newDesc) return NULL; | |
| newDesc->compatibility = 0; | |
| newDesc->contentIdentifier = NULL; | |
| newDesc->tag = GF_ODF_CI_TAG; | |
| newDesc->contentIdentifierFlag = 0; | |
| newDesc->contentIdentifierType = 0; | |
| newDesc->contentType = 0; | |
| newDesc->contentTypeFlag = 0; | |
| newDesc->protectedContent = 0; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ci(GF_CIDesc *cid) | |
| { | |
| if (!cid) return GF_BAD_PARAM; | |
| if (cid->contentIdentifier) gf_free(cid->contentIdentifier); | |
| gf_free(cid); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_ci(GF_BitStream *bs, GF_CIDesc *cid, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (! cid) return GF_BAD_PARAM; | |
| cid->compatibility = gf_bs_read_int(bs, 2); //MUST BE NULL | |
| if (cid->compatibility) return GF_ODF_INVALID_DESCRIPTOR; | |
| cid->contentTypeFlag = gf_bs_read_int(bs, 1); | |
| cid->contentIdentifierFlag = gf_bs_read_int(bs, 1); | |
| cid->protectedContent = gf_bs_read_int(bs, 1); | |
| /*reserved = */gf_bs_read_int(bs, 3); | |
| nbBytes += 1; | |
| if (cid->contentTypeFlag) { | |
| cid->contentType = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| } | |
| if (cid->contentIdentifierFlag) { | |
| cid->contentIdentifierType = gf_bs_read_int(bs, 8); | |
| if (DescSize < (u32) 2 + cid->contentTypeFlag) return GF_ODF_INVALID_DESCRIPTOR; | |
| cid->contentIdentifier = (char*)gf_malloc(DescSize - 2 - cid->contentTypeFlag); | |
| if (! cid->contentIdentifier) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, cid->contentIdentifier, DescSize - 2 - cid->contentTypeFlag); | |
| nbBytes += DescSize - 1 - cid->contentTypeFlag; | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_ci(GF_CIDesc *cid, u32 *outSize) | |
| { | |
| if (! cid) return GF_BAD_PARAM; | |
| *outSize = 1; | |
| if (cid->contentTypeFlag) *outSize += 1; | |
| if (cid->contentIdentifierFlag) | |
| *outSize += (u32) strlen((const char*)cid->contentIdentifier) - 1 - cid->contentTypeFlag; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_ci(GF_BitStream *bs, GF_CIDesc *cid) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! cid) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)cid, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, cid->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, cid->compatibility, 2); | |
| gf_bs_write_int(bs, cid->contentTypeFlag, 1); | |
| gf_bs_write_int(bs, cid->contentIdentifierFlag, 1); | |
| gf_bs_write_int(bs, cid->protectedContent, 1); | |
| gf_bs_write_int(bs, 7, 3); //reserved 0b111 = 7 | |
| if (cid->contentTypeFlag) { | |
| gf_bs_write_int(bs, cid->contentType, 8); | |
| } | |
| if (cid->contentIdentifierFlag) { | |
| gf_bs_write_int(bs, cid->contentIdentifierType, 8); | |
| gf_bs_write_data(bs, cid->contentIdentifier, size - 2 - cid->contentTypeFlag); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_exp_text() | |
| { | |
| GF_ExpandedTextual *newDesc = (GF_ExpandedTextual *) gf_malloc(sizeof(GF_ExpandedTextual)); | |
| if (!newDesc) return NULL; | |
| newDesc->itemDescriptionList = gf_list_new(); | |
| if (! newDesc->itemDescriptionList) { | |
| gf_free(newDesc); | |
| return NULL; | |
| } | |
| newDesc->itemTextList = gf_list_new(); | |
| if (! newDesc->itemTextList) { | |
| gf_free(newDesc->itemDescriptionList); | |
| gf_free(newDesc); | |
| return NULL; | |
| } | |
| newDesc->isUTF8 = 0; | |
| newDesc->langCode = 0; | |
| newDesc->NonItemText = NULL; | |
| newDesc->tag = GF_ODF_TEXT_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_exp_text(GF_ExpandedTextual *etd) | |
| { | |
| if (!etd) return GF_BAD_PARAM; | |
| while (gf_list_count(etd->itemDescriptionList)) { | |
| GF_ETD_ItemText *tmp = (GF_ETD_ItemText*)gf_list_get(etd->itemDescriptionList, 0); | |
| if (tmp) { | |
| if (tmp->text) gf_free(tmp->text); | |
| gf_free(tmp); | |
| } | |
| gf_list_rem(etd->itemDescriptionList, 0); | |
| } | |
| gf_list_del(etd->itemDescriptionList); | |
| while (gf_list_count(etd->itemTextList)) { | |
| GF_ETD_ItemText *tmp = (GF_ETD_ItemText*)gf_list_get(etd->itemTextList, 0); | |
| if (tmp) { | |
| if (tmp->text) gf_free(tmp->text); | |
| gf_free(tmp); | |
| } | |
| gf_list_rem(etd->itemTextList, 0); | |
| } | |
| gf_list_del(etd->itemTextList); | |
| if (etd->NonItemText) gf_free(etd->NonItemText); | |
| gf_free(etd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_exp_text(GF_BitStream *bs, GF_ExpandedTextual *etd, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 nbBytes = 0; | |
| u32 i, len, nonLen, count; | |
| if (!etd) return GF_BAD_PARAM; | |
| etd->langCode = gf_bs_read_int(bs, 24); | |
| etd->isUTF8 = gf_bs_read_int(bs, 1); | |
| /*aligned = */gf_bs_read_int(bs, 7); | |
| count = gf_bs_read_int(bs, 8); | |
| nbBytes += 5; | |
| for (i = 0; i< count; i++) { | |
| //description | |
| GF_ETD_ItemText *description, *Text; | |
| description = (GF_ETD_ItemText*)gf_malloc(sizeof(GF_ETD_ItemText)); | |
| if (! description) return GF_OUT_OF_MEM; | |
| description->text = NULL; | |
| e = OD_ReadUTF8String(bs, & description->text, etd->isUTF8, &len); | |
| if (e) { | |
| gf_free(description); | |
| return e; | |
| } | |
| e = gf_list_add(etd->itemDescriptionList, description); | |
| if (e) return e; | |
| nbBytes += len; | |
| //text | |
| Text = (GF_ETD_ItemText*)gf_malloc(sizeof(GF_ETD_ItemText)); | |
| if (! Text) return GF_OUT_OF_MEM; | |
| Text->text = NULL; | |
| e = OD_ReadUTF8String(bs, & Text->text, etd->isUTF8, &len); | |
| if (e) return e; | |
| e = gf_list_add(etd->itemTextList, Text); | |
| if (e) return e; | |
| nbBytes += len; | |
| } | |
| len = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| nonLen = 0; | |
| while (len == 255) { | |
| nonLen += len; | |
| len = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| } | |
| nonLen += len; | |
| if (nonLen) { | |
| //here we have no choice but do the job ourselves | |
| //because the length is not encoded on 8 bits | |
| etd->NonItemText = (char *) gf_malloc(sizeof(char) * (1+nonLen) * (etd->isUTF8 ? 1 : 2)); | |
| if (! etd->NonItemText) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, etd->NonItemText, nonLen * (etd->isUTF8 ? 1 : 2)); | |
| nbBytes += nonLen * (etd->isUTF8 ? 1 : 2); | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_exp_text(GF_ExpandedTextual *etd, u32 *outSize) | |
| { | |
| u32 i, len, nonLen, lentmp, count; | |
| if (!etd) return GF_BAD_PARAM; | |
| *outSize = 5; | |
| if (gf_list_count(etd->itemDescriptionList) != gf_list_count(etd->itemTextList)) return GF_ODF_INVALID_DESCRIPTOR; | |
| count = gf_list_count(etd->itemDescriptionList); | |
| for (i=0; i<count; i++) { | |
| GF_ETD_ItemText *tmp = (GF_ETD_ItemText *)gf_list_get(etd->itemDescriptionList, i); | |
| *outSize += OD_SizeUTF8String(tmp->text, etd->isUTF8); | |
| tmp = (GF_ETD_ItemText*)gf_list_get(etd->itemTextList, i); | |
| *outSize += OD_SizeUTF8String(tmp->text, etd->isUTF8); | |
| } | |
| *outSize += 1; | |
| if (etd->NonItemText) { | |
| if (etd->isUTF8) { | |
| nonLen = (u32) strlen((const char*)etd->NonItemText); | |
| } else { | |
| nonLen = gf_utf8_wcslen((const unsigned short*)etd->NonItemText); | |
| } | |
| } else { | |
| nonLen = 0; | |
| } | |
| len = 255; | |
| lentmp = nonLen; | |
| if (lentmp < 255) { | |
| len = lentmp; | |
| } | |
| while (len == 255) { | |
| *outSize += 1; | |
| lentmp -= 255; | |
| if (lentmp < 255) { | |
| len = lentmp; | |
| } | |
| } | |
| *outSize += nonLen * (etd->isUTF8 ? 1 : 2); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_exp_text(GF_BitStream *bs, GF_ExpandedTextual *etd) | |
| { | |
| GF_Err e; | |
| u32 size, i, len, nonLen, lentmp, count; | |
| if (!etd) return GF_BAD_PARAM; | |
| if (gf_list_count(etd->itemDescriptionList) != gf_list_count(etd->itemTextList)) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)etd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, etd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, etd->langCode, 24); | |
| gf_bs_write_int(bs, etd->isUTF8, 1); | |
| gf_bs_write_int(bs, 0, 7); //aligned | |
| gf_bs_write_int(bs, gf_list_count(etd->itemDescriptionList), 8); | |
| count = gf_list_count(etd->itemDescriptionList); | |
| for (i=0; i<count; i++) { | |
| GF_ETD_ItemText *tmp = (GF_ETD_ItemText *)gf_list_get(etd->itemDescriptionList, i); | |
| OD_WriteUTF8String(bs, tmp->text, etd->isUTF8); | |
| tmp = (GF_ETD_ItemText*)gf_list_get(etd->itemTextList, i); | |
| OD_WriteUTF8String(bs, tmp->text, etd->isUTF8); | |
| } | |
| if (etd->NonItemText) { | |
| if (etd->isUTF8) { | |
| nonLen = (u32) strlen((const char*)etd->NonItemText); | |
| } else { | |
| nonLen = gf_utf8_wcslen((const unsigned short*)etd->NonItemText); | |
| } | |
| } else { | |
| nonLen = 0; | |
| } | |
| lentmp = nonLen; | |
| len = lentmp < 255 ? lentmp : 255; | |
| while (len == 255) { | |
| gf_bs_write_int(bs, len, 8); | |
| lentmp -= len; | |
| len = lentmp < 255 ? lentmp : 255; | |
| } | |
| gf_bs_write_int(bs, len, 8); | |
| gf_bs_write_data(bs, etd->NonItemText, nonLen * (etd->isUTF8 ? 1 : 2)); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_pl_ext() | |
| { | |
| GF_PLExt *newDesc = (GF_PLExt *) gf_malloc(sizeof(GF_PLExt)); | |
| if (!newDesc) return NULL; | |
| newDesc->AudioProfileLevelIndication = 0; | |
| newDesc->GraphicsProfileLevelIndication = 0; | |
| newDesc->MPEGJProfileLevelIndication = 0; | |
| newDesc->ODProfileLevelIndication = 0; | |
| newDesc->profileLevelIndicationIndex = 0; | |
| newDesc->SceneProfileLevelIndication = 0; | |
| newDesc->VisualProfileLevelIndication = 0; | |
| newDesc->tag = GF_ODF_EXT_PL_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_pl_ext(GF_PLExt *pld) | |
| { | |
| if (!pld) return GF_BAD_PARAM; | |
| gf_free(pld); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_pl_ext(GF_BitStream *bs, GF_PLExt *pld, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!pld) return GF_BAD_PARAM; | |
| pld->profileLevelIndicationIndex = gf_bs_read_int(bs, 8); | |
| pld->ODProfileLevelIndication = gf_bs_read_int(bs, 8); | |
| pld->SceneProfileLevelIndication = gf_bs_read_int(bs, 8); | |
| pld->AudioProfileLevelIndication = gf_bs_read_int(bs, 8); | |
| pld->VisualProfileLevelIndication = gf_bs_read_int(bs, 8); | |
| pld->GraphicsProfileLevelIndication = gf_bs_read_int(bs, 8); | |
| pld->MPEGJProfileLevelIndication = gf_bs_read_int(bs, 8); | |
| nbBytes += 7; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_pl_ext(GF_PLExt *pld, u32 *outSize) | |
| { | |
| if (!pld) return GF_BAD_PARAM; | |
| *outSize = 7; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_pl_ext(GF_BitStream *bs, GF_PLExt *pld) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!pld) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)pld, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, pld->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, pld->profileLevelIndicationIndex, 8); | |
| gf_bs_write_int(bs, pld->ODProfileLevelIndication, 8); | |
| gf_bs_write_int(bs, pld->SceneProfileLevelIndication, 8); | |
| gf_bs_write_int(bs, pld->AudioProfileLevelIndication, 8); | |
| gf_bs_write_int(bs, pld->VisualProfileLevelIndication, 8); | |
| gf_bs_write_int(bs, pld->GraphicsProfileLevelIndication, 8); | |
| gf_bs_write_int(bs, pld->MPEGJProfileLevelIndication, 8); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_ipi_ptr() | |
| { | |
| GF_IPIPtr *newDesc = (GF_IPIPtr *) gf_malloc(sizeof(GF_IPIPtr)); | |
| if (!newDesc) return NULL; | |
| newDesc->IPI_ES_Id = 0; | |
| newDesc->tag = GF_ODF_IPI_PTR_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ipi_ptr(GF_IPIPtr *ipid) | |
| { | |
| if (!ipid) return GF_BAD_PARAM; | |
| gf_free(ipid); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_ipi_ptr(GF_BitStream *bs, GF_IPIPtr *ipid, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (! ipid) return GF_BAD_PARAM; | |
| ipid->IPI_ES_Id = gf_bs_read_int(bs, 16); | |
| nbBytes += 2; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_ipi_ptr(GF_IPIPtr *ipid, u32 *outSize) | |
| { | |
| if (! ipid) return GF_BAD_PARAM; | |
| *outSize = 2; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_ipi_ptr(GF_BitStream *bs, GF_IPIPtr *ipid) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! ipid) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ipid, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ipid->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ipid->IPI_ES_Id, 16); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_ipmp() | |
| { | |
| GF_IPMP_Descriptor *newDesc; | |
| GF_SAFEALLOC(newDesc, GF_IPMP_Descriptor); | |
| if (!newDesc) return NULL; | |
| newDesc->ipmpx_data = gf_list_new(); | |
| newDesc->tag = GF_ODF_IPMP_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ipmp(GF_IPMP_Descriptor *ipmp) | |
| { | |
| if (!ipmp) return GF_BAD_PARAM; | |
| if (ipmp->opaque_data) gf_free(ipmp->opaque_data); | |
| #ifndef GPAC_MINIMAL_ODF | |
| /*TODO DELETE IPMPX*/ | |
| while (gf_list_count(ipmp->ipmpx_data)) { | |
| GF_IPMPX_Data *p = (GF_IPMPX_Data *)gf_list_get(ipmp->ipmpx_data, 0); | |
| gf_list_rem(ipmp->ipmpx_data, 0); | |
| gf_ipmpx_data_del(p); | |
| } | |
| #endif | |
| gf_list_del(ipmp->ipmpx_data); | |
| gf_free(ipmp); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_ipmp(GF_BitStream *bs, GF_IPMP_Descriptor *ipmp, u32 DescSize) | |
| { | |
| u32 size; | |
| u64 nbBytes = 0; | |
| if (!ipmp) return GF_BAD_PARAM; | |
| ipmp->IPMP_DescriptorID = gf_bs_read_int(bs, 8); | |
| ipmp->IPMPS_Type = gf_bs_read_int(bs, 16); | |
| nbBytes += 3; | |
| if (DescSize<3) return GF_ODF_INVALID_DESCRIPTOR; | |
| size = DescSize - 3; | |
| /*IPMPX escape*/ | |
| if ((ipmp->IPMP_DescriptorID==0xFF) && (ipmp->IPMPS_Type==0xFFFF)) { | |
| ipmp->IPMP_DescriptorIDEx = gf_bs_read_int(bs, 16); | |
| if (gf_bs_available(bs) < 16) return GF_ODF_INVALID_DESCRIPTOR; | |
| gf_bs_read_data(bs, (char*)ipmp->IPMP_ToolID, 16); | |
| ipmp->control_point = gf_bs_read_int(bs, 8); | |
| nbBytes += 19; | |
| if (ipmp->control_point) { | |
| ipmp->cp_sequence_code = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| } | |
| while (nbBytes<DescSize) { | |
| u64 pos; | |
| GF_Err e; | |
| GF_IPMPX_Data *p; | |
| pos = gf_bs_get_position(bs); | |
| e = gf_ipmpx_data_parse(bs, &p); | |
| if (e) return e; | |
| gf_list_add(ipmp->ipmpx_data, p); | |
| nbBytes += gf_bs_get_position(bs) - pos; | |
| } | |
| } | |
| /*URL*/ | |
| else if (! ipmp->IPMPS_Type) { | |
| ipmp->opaque_data = (char*)gf_malloc(size + 1); | |
| if (! ipmp->opaque_data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ipmp->opaque_data, size); | |
| nbBytes += size; | |
| ipmp->opaque_data[size] = 0; | |
| ipmp->opaque_data_size = size; | |
| } | |
| /*data*/ | |
| else { | |
| ipmp->opaque_data_size = size; | |
| ipmp->opaque_data = (char*)gf_malloc(size); | |
| if (! ipmp->opaque_data) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, ipmp->opaque_data, size); | |
| nbBytes += size; | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_ipmp(GF_IPMP_Descriptor *ipmp, u32 *outSize) | |
| { | |
| u32 i, s; | |
| if (!ipmp) return GF_BAD_PARAM; | |
| *outSize = 3; | |
| /*IPMPX escape*/ | |
| if ((ipmp->IPMP_DescriptorID==0xFF) && (ipmp->IPMPS_Type==0xFFFF)) { | |
| GF_IPMPX_Data *p; | |
| *outSize += 19; | |
| if (ipmp->control_point) *outSize += 1; | |
| s = 0; | |
| i=0; | |
| while ((p = (GF_IPMPX_Data *)gf_list_enum(ipmp->ipmpx_data, &i))) { | |
| s += gf_ipmpx_data_full_size(p); | |
| } | |
| (*outSize) += s; | |
| } | |
| else if (! ipmp->IPMPS_Type) { | |
| if (!ipmp->opaque_data) return GF_ODF_INVALID_DESCRIPTOR; | |
| *outSize += (u32) strlen(ipmp->opaque_data); | |
| } else { | |
| *outSize += ipmp->opaque_data_size; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_ipmp(GF_BitStream *bs, GF_IPMP_Descriptor *ipmp) | |
| { | |
| GF_Err e; | |
| u32 size, i; | |
| if (!ipmp) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ipmp, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ipmp->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ipmp->IPMP_DescriptorID, 8); | |
| gf_bs_write_int(bs, ipmp->IPMPS_Type, 16); | |
| if ((ipmp->IPMP_DescriptorID==0xFF) && (ipmp->IPMPS_Type==0xFFFF)) { | |
| GF_IPMPX_Data *p; | |
| gf_bs_write_int(bs, ipmp->IPMP_DescriptorIDEx, 16); | |
| gf_bs_write_data(bs, (char*)ipmp->IPMP_ToolID, 16); | |
| gf_bs_write_int(bs, ipmp->control_point, 8); | |
| if (ipmp->control_point) gf_bs_write_int(bs, ipmp->cp_sequence_code, 8); | |
| i=0; | |
| while ((p = (GF_IPMPX_Data *) gf_list_enum(ipmp->ipmpx_data, &i))) { | |
| gf_ipmpx_data_write(bs, p); | |
| } | |
| } | |
| else if (!ipmp->IPMPS_Type) { | |
| if (!ipmp->opaque_data) return GF_ODF_INVALID_DESCRIPTOR; | |
| gf_bs_write_data(bs, ipmp->opaque_data, (u32) strlen(ipmp->opaque_data)); | |
| } else { | |
| gf_bs_write_data(bs, ipmp->opaque_data, ipmp->opaque_data_size); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_ipmp_ptr() | |
| { | |
| GF_IPMPPtr *newDesc; | |
| GF_SAFEALLOC(newDesc, GF_IPMPPtr); | |
| if (!newDesc) return NULL; | |
| newDesc->tag = GF_ODF_IPMP_PTR_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ipmp_ptr(GF_IPMPPtr *ipmpd) | |
| { | |
| if (!ipmpd) return GF_BAD_PARAM; | |
| gf_free(ipmpd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_ipmp_ptr(GF_BitStream *bs, GF_IPMPPtr *ipmpd, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (! ipmpd) return GF_BAD_PARAM; | |
| ipmpd->IPMP_DescriptorID = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| if (ipmpd->IPMP_DescriptorID == 0xFF) { | |
| ipmpd->IPMP_DescriptorIDEx = gf_bs_read_int(bs, 16); | |
| ipmpd->IPMP_ES_ID = gf_bs_read_int(bs, 16); | |
| nbBytes += 4; | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_ipmp_ptr(GF_IPMPPtr *ipmpd, u32 *outSize) | |
| { | |
| if (! ipmpd) return GF_BAD_PARAM; | |
| *outSize = 1; | |
| if (ipmpd->IPMP_DescriptorID == 0xFF) *outSize += 4; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_ipmp_ptr(GF_BitStream *bs, GF_IPMPPtr *ipmpd) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! ipmpd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ipmpd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ipmpd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, ipmpd->IPMP_DescriptorID, 8); | |
| if (ipmpd->IPMP_DescriptorID == 0xFF) { | |
| gf_bs_write_int(bs, ipmpd->IPMP_DescriptorIDEx, 16); | |
| gf_bs_write_int(bs, ipmpd->IPMP_ES_ID, 16); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_kw() | |
| { | |
| GF_KeyWord *newDesc = (GF_KeyWord *) gf_malloc(sizeof(GF_KeyWord)); | |
| if (!newDesc) return NULL; | |
| newDesc->keyWordsList = gf_list_new(); | |
| if (! newDesc->keyWordsList) { | |
| gf_free(newDesc); | |
| return NULL; | |
| } | |
| newDesc->isUTF8 = 0; | |
| newDesc->languageCode = 0; | |
| newDesc->tag = GF_ODF_KW_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_kw(GF_KeyWord *kwd) | |
| { | |
| if (!kwd) return GF_BAD_PARAM; | |
| while (gf_list_count(kwd->keyWordsList)) { | |
| GF_KeyWordItem *tmp = (GF_KeyWordItem*)gf_list_get(kwd->keyWordsList, 0); | |
| if (tmp) { | |
| if (tmp->keyWord) gf_free(tmp->keyWord); | |
| tmp->keyWord = NULL; | |
| gf_list_rem(kwd->keyWordsList, 0); | |
| gf_free(tmp); | |
| } | |
| } | |
| gf_list_del(kwd->keyWordsList); | |
| gf_free(kwd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_kw(GF_BitStream *bs, GF_KeyWord *kwd, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 nbBytes = 0, i, kwcount, len; | |
| if (!kwd) return GF_BAD_PARAM; | |
| kwd->languageCode = gf_bs_read_int(bs, 24); | |
| kwd->isUTF8 = gf_bs_read_int(bs, 1); | |
| /*aligned = */gf_bs_read_int(bs, 7); | |
| kwcount = gf_bs_read_int(bs, 8); | |
| nbBytes += 5; | |
| for (i = 0 ; i < kwcount; i++) { | |
| GF_KeyWordItem *tmp = (GF_KeyWordItem*)gf_malloc(sizeof(GF_KeyWordItem)); | |
| if (! tmp) return GF_OUT_OF_MEM; | |
| e = OD_ReadUTF8String(bs, & tmp->keyWord, kwd->isUTF8, &len); | |
| if (e) { | |
| if (tmp->keyWord) gf_free(tmp->keyWord); | |
| gf_free(tmp); | |
| return e; | |
| } | |
| nbBytes += len; | |
| if (nbBytes > DescSize) { | |
| gf_free(tmp->keyWord); | |
| gf_free(tmp); | |
| return GF_ODF_INVALID_DESCRIPTOR; | |
| } | |
| e = gf_list_add(kwd->keyWordsList, tmp); | |
| if (e) { | |
| if (tmp) gf_free(tmp); | |
| return e; | |
| } | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_kw(GF_KeyWord *kwd, u32 *outSize) | |
| { | |
| u32 i; | |
| GF_KeyWordItem *tmp; | |
| if (!kwd) return GF_BAD_PARAM; | |
| *outSize = 5; | |
| i=0; | |
| while ((tmp = (GF_KeyWordItem *)gf_list_enum(kwd->keyWordsList, &i))) { | |
| *outSize += OD_SizeUTF8String(tmp->keyWord, kwd->isUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_kw(GF_BitStream *bs, GF_KeyWord *kwd) | |
| { | |
| GF_Err e; | |
| u32 size, i; | |
| GF_KeyWordItem *tmp; | |
| if (!kwd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)kwd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, kwd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, kwd->languageCode, 24); | |
| gf_bs_write_int(bs, kwd->isUTF8, 1); | |
| gf_bs_write_int(bs, 0, 7); //aligned(8) | |
| gf_bs_write_int(bs, gf_list_count(kwd->keyWordsList), 8); | |
| i=0; | |
| while ((tmp = (GF_KeyWordItem *)gf_list_enum(kwd->keyWordsList, &i))) { | |
| OD_WriteUTF8String(bs, tmp->keyWord, kwd->isUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_oci_date() | |
| { | |
| GF_OCI_Data *newDesc = (GF_OCI_Data *) gf_malloc(sizeof(GF_OCI_Data)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc->OCICreationDate, 0, 5); | |
| newDesc->tag = GF_ODF_OCI_DATE_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_oci_date(GF_OCI_Data *ocd) | |
| { | |
| if (!ocd) return GF_BAD_PARAM; | |
| gf_free(ocd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_oci_date(GF_BitStream *bs, GF_OCI_Data *ocd, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!ocd) return GF_BAD_PARAM; | |
| gf_bs_read_data(bs, ocd->OCICreationDate, DATE_CODING_LEN); | |
| nbBytes += DATE_CODING_LEN; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_oci_date(GF_OCI_Data *ocd, u32 *outSize) | |
| { | |
| if (!ocd) return GF_BAD_PARAM; | |
| *outSize = DATE_CODING_LEN; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_oci_date(GF_BitStream *bs, GF_OCI_Data *ocd) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!ocd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ocd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ocd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_data(bs, ocd->OCICreationDate, DATE_CODING_LEN); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_oci_name() | |
| { | |
| GF_OCICreators *newDesc = (GF_OCICreators *) gf_malloc(sizeof(GF_OCICreators)); | |
| if (!newDesc) return NULL; | |
| newDesc->OCICreators = gf_list_new(); | |
| if (! newDesc->OCICreators) { | |
| gf_free(newDesc); | |
| return NULL; | |
| } | |
| newDesc->tag = GF_ODF_OCI_NAME_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_oci_name(GF_OCICreators *ocn) | |
| { | |
| u32 i; | |
| GF_OCICreator_item *tmp; | |
| if (!ocn) return GF_BAD_PARAM; | |
| i=0; | |
| while ((tmp = (GF_OCICreator_item *)gf_list_enum(ocn->OCICreators, &i))) { | |
| if (tmp->OCICreatorName) gf_free(tmp->OCICreatorName); | |
| gf_free(tmp); | |
| } | |
| gf_list_del(ocn->OCICreators); | |
| gf_free(ocn); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_oci_name(GF_BitStream *bs, GF_OCICreators *ocn, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 nbBytes = 0; | |
| u32 i, count, len; | |
| if (!ocn) return GF_BAD_PARAM; | |
| count = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| for (i = 0; i< count; i++) { | |
| GF_OCICreator_item *tmp = (GF_OCICreator_item*)gf_malloc(sizeof(GF_OCICreator_item)); | |
| if (! tmp) return GF_OUT_OF_MEM; | |
| tmp->langCode = gf_bs_read_int(bs, 24); | |
| tmp->isUTF8 = gf_bs_read_int(bs, 1); | |
| /*aligned = */gf_bs_read_int(bs, 7); | |
| nbBytes += 4; | |
| e = OD_ReadUTF8String(bs, & tmp->OCICreatorName, tmp->isUTF8, &len); | |
| if (e) { | |
| gf_free(tmp); | |
| return e; | |
| } | |
| nbBytes += len; | |
| e = gf_list_add(ocn->OCICreators, tmp); | |
| if (e) return e; | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_oci_name(GF_OCICreators *ocn, u32 *outSize) | |
| { | |
| u32 i; | |
| GF_OCICreator_item *tmp; | |
| if (!ocn) return GF_BAD_PARAM; | |
| *outSize = 1; | |
| i=0; | |
| while ((tmp = (GF_OCICreator_item *)gf_list_enum(ocn->OCICreators, &i))) { | |
| *outSize += 4 + OD_SizeUTF8String(tmp->OCICreatorName, tmp->isUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_oci_name(GF_BitStream *bs, GF_OCICreators *ocn) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| u32 i; | |
| GF_OCICreator_item *tmp; | |
| if (!ocn) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ocn, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ocn->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, gf_list_count(ocn->OCICreators), 8); | |
| i=0; | |
| while ((tmp = (GF_OCICreator_item *)gf_list_enum(ocn->OCICreators, &i))) { | |
| gf_bs_write_int(bs, tmp->langCode, 24); | |
| gf_bs_write_int(bs, tmp->isUTF8, 1); | |
| gf_bs_write_int(bs, 0, 7); //aligned | |
| gf_bs_write_int(bs, (u32) strlen(tmp->OCICreatorName) , 8); | |
| OD_WriteUTF8String(bs, tmp->OCICreatorName, tmp->isUTF8); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_pl_idx() | |
| { | |
| GF_PL_IDX *newDesc = (GF_PL_IDX *) gf_malloc(sizeof(GF_PL_IDX)); | |
| if (!newDesc) return NULL; | |
| newDesc->profileLevelIndicationIndex = 0; | |
| newDesc->tag = GF_ODF_PL_IDX_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_pl_idx(GF_PL_IDX *plid) | |
| { | |
| if (!plid) return GF_BAD_PARAM; | |
| gf_free(plid); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_pl_idx(GF_BitStream *bs, GF_PL_IDX *plid, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!plid) return GF_BAD_PARAM; | |
| plid->profileLevelIndicationIndex = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_pl_idx(GF_PL_IDX *plid, u32 *outSize) | |
| { | |
| if (!plid) return GF_BAD_PARAM; | |
| *outSize = 1; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_pl_idx(GF_BitStream *bs, GF_PL_IDX *plid) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!plid) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)plid, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, plid->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, plid->profileLevelIndicationIndex, 8); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_rating() | |
| { | |
| GF_Rating *newDesc = (GF_Rating *) gf_malloc(sizeof(GF_Rating)); | |
| if (!newDesc) return NULL; | |
| newDesc->infoLength = 0; | |
| newDesc->ratingInfo = NULL; | |
| newDesc->ratingCriteria = 0; | |
| newDesc->ratingEntity = 0; | |
| newDesc->tag = GF_ODF_RATING_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_rating(GF_Rating *rd) | |
| { | |
| if (!rd) return GF_BAD_PARAM; | |
| if (rd->ratingInfo) gf_free(rd->ratingInfo); | |
| gf_free(rd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_rating(GF_BitStream *bs, GF_Rating *rd, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!rd) return GF_BAD_PARAM; | |
| rd->ratingEntity = gf_bs_read_int(bs, 32); | |
| rd->ratingCriteria = gf_bs_read_int(bs, 16); | |
| if (DescSize<6) return GF_ODF_INVALID_DESCRIPTOR; | |
| rd->infoLength = DescSize - 6; | |
| nbBytes += 6; | |
| rd->ratingInfo = (char*)gf_malloc(rd->infoLength); | |
| if (! rd->ratingInfo) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, rd->ratingInfo, rd->infoLength); | |
| nbBytes += rd->infoLength; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_rating(GF_Rating *rd, u32 *outSize) | |
| { | |
| if (!rd) return GF_BAD_PARAM; | |
| *outSize = 6 + rd->infoLength; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_rating(GF_BitStream *bs, GF_Rating *rd) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!rd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)rd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, rd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, rd->ratingEntity, 32); | |
| gf_bs_write_int(bs, rd->ratingCriteria, 16); | |
| gf_bs_write_data(bs, rd->ratingInfo, rd->infoLength); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_reg() | |
| { | |
| GF_Registration *newDesc = (GF_Registration *) gf_malloc(sizeof(GF_Registration)); | |
| if (!newDesc) return NULL; | |
| newDesc->additionalIdentificationInfo = NULL; | |
| newDesc->dataLength = 0; | |
| newDesc->formatIdentifier = 0; | |
| newDesc->tag = GF_ODF_REG_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_reg(GF_Registration *reg) | |
| { | |
| if (!reg) return GF_BAD_PARAM; | |
| if (reg->additionalIdentificationInfo) gf_free(reg->additionalIdentificationInfo); | |
| gf_free(reg); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_reg(GF_BitStream *bs, GF_Registration *reg, u32 DescSize) | |
| { | |
| u32 nbBytes = 0; | |
| if (!reg) return GF_BAD_PARAM; | |
| reg->formatIdentifier = gf_bs_read_int(bs, 32); | |
| if (DescSize<4) return GF_ODF_INVALID_DESCRIPTOR; | |
| reg->dataLength = DescSize - 4; | |
| reg->additionalIdentificationInfo = (char*)gf_malloc(reg->dataLength); | |
| if (! reg->additionalIdentificationInfo) return GF_OUT_OF_MEM; | |
| gf_bs_read_data(bs, reg->additionalIdentificationInfo, reg->dataLength); | |
| nbBytes += reg->dataLength + 4; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_reg(GF_Registration *reg, u32 *outSize) | |
| { | |
| if (!reg) return GF_BAD_PARAM; | |
| *outSize = 4 + reg->dataLength; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_reg(GF_BitStream *bs, GF_Registration *reg) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!reg) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)reg, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, reg->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, reg->formatIdentifier, 32); | |
| gf_bs_write_data(bs, reg->additionalIdentificationInfo, reg->dataLength); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_short_text() | |
| { | |
| GF_ShortTextual *newDesc = (GF_ShortTextual *) gf_malloc(sizeof(GF_ShortTextual)); | |
| if (!newDesc) return NULL; | |
| newDesc->eventName = NULL; | |
| newDesc->eventText = NULL; | |
| newDesc->isUTF8 = 0; | |
| newDesc->langCode = 0; | |
| newDesc->tag = GF_ODF_SHORT_TEXT_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_short_text(GF_ShortTextual *std) | |
| { | |
| if (!std) return GF_BAD_PARAM; | |
| if (std->eventName) gf_free(std->eventName); | |
| if (std->eventText) gf_free(std->eventText); | |
| gf_free(std); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_short_text(GF_BitStream *bs, GF_ShortTextual *std, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 nbBytes = 0, len; | |
| if (!std) return GF_BAD_PARAM; | |
| std->langCode = gf_bs_read_int(bs, 24); | |
| std->isUTF8 = gf_bs_read_int(bs, 1); | |
| /*aligned = */gf_bs_read_int(bs, 7); | |
| nbBytes += 4; | |
| e = OD_ReadUTF8String(bs, & std->eventName, std->isUTF8, &len); | |
| if (e) return e; | |
| nbBytes += len; | |
| e = OD_ReadUTF8String(bs, & std->eventText, std->isUTF8, &len); | |
| if (e) return e; | |
| nbBytes += len; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_short_text(GF_ShortTextual *std, u32 *outSize) | |
| { | |
| if (!std) return GF_BAD_PARAM; | |
| *outSize = 4; | |
| *outSize += OD_SizeUTF8String(std->eventName, std->isUTF8) + OD_SizeUTF8String(std->eventText, std->isUTF8); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_short_text(GF_BitStream *bs, GF_ShortTextual *std) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!std) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)std, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, std->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, std->langCode, 24); | |
| gf_bs_write_int(bs, std->isUTF8, 1); | |
| gf_bs_write_int(bs, 0, 7); | |
| OD_WriteUTF8String(bs, std->eventName, std->isUTF8); | |
| OD_WriteUTF8String(bs, std->eventText, std->isUTF8); | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_smpte_camera() | |
| { | |
| GF_SMPTECamera *newDesc = (GF_SMPTECamera *) gf_malloc(sizeof(GF_SMPTECamera)); | |
| if (!newDesc) return NULL; | |
| newDesc->ParamList = gf_list_new(); | |
| if (! newDesc->ParamList) { | |
| gf_free(newDesc); | |
| return NULL; | |
| } | |
| newDesc->cameraID = 0; | |
| newDesc->tag = GF_ODF_SMPTE_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_smpte_camera(GF_SMPTECamera *cpd) | |
| { | |
| u32 i; | |
| GF_SmpteParam *tmp; | |
| if (!cpd) return GF_BAD_PARAM; | |
| i=0; | |
| while ((tmp = (GF_SmpteParam *)gf_list_enum(cpd->ParamList, &i))) { | |
| gf_free(tmp); | |
| } | |
| gf_list_del(cpd->ParamList); | |
| gf_free(cpd); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_smpte_camera(GF_BitStream *bs, GF_SMPTECamera *cpd, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 nbBytes = 0, i, count; | |
| if (!cpd) return GF_BAD_PARAM; | |
| cpd->cameraID = gf_bs_read_int(bs, 8); | |
| count = gf_bs_read_int(bs, 8); | |
| nbBytes += 2; | |
| for (i=0; i< count ; i++) { | |
| GF_SmpteParam *tmp = (GF_SmpteParam*)gf_malloc(sizeof(GF_SmpteParam)); | |
| if (! tmp) return GF_OUT_OF_MEM; | |
| tmp->paramID = gf_bs_read_int(bs, 8); | |
| tmp->param = gf_bs_read_int(bs, 32); | |
| nbBytes += 5; | |
| e = gf_list_add(cpd->ParamList, tmp); | |
| if (e) return e; | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_smpte_camera(GF_SMPTECamera *cpd, u32 *outSize) | |
| { | |
| if (!cpd) return GF_BAD_PARAM; | |
| *outSize = 2 + 5 * gf_list_count(cpd->ParamList); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_smpte_camera(GF_BitStream *bs, GF_SMPTECamera *cpd) | |
| { | |
| GF_Err e; | |
| GF_SmpteParam *tmp; | |
| u32 size, i; | |
| if (!cpd) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)cpd, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, cpd->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, cpd->cameraID, 8); | |
| gf_bs_write_int(bs, gf_list_count(cpd->ParamList), 8); | |
| i=0; | |
| while ((tmp = (GF_SmpteParam *)gf_list_enum(cpd->ParamList, &i))) { | |
| gf_bs_write_int(bs, tmp->paramID, 8); | |
| gf_bs_write_int(bs, tmp->param, 32); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Descriptor *gf_odf_new_sup_cid() | |
| { | |
| GF_SCIDesc *newDesc = (GF_SCIDesc *) gf_malloc(sizeof(GF_SCIDesc)); | |
| if (!newDesc) return NULL; | |
| newDesc->supplContentIdentifierTitle = NULL; | |
| newDesc->supplContentIdentifierValue =NULL; | |
| newDesc->languageCode = 0; | |
| newDesc->tag = GF_ODF_SCI_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_sup_cid(GF_SCIDesc *scid) | |
| { | |
| if (!scid) return GF_BAD_PARAM; | |
| if (scid->supplContentIdentifierTitle) gf_free(scid->supplContentIdentifierTitle); | |
| if (scid->supplContentIdentifierValue) gf_free(scid->supplContentIdentifierValue); | |
| gf_free(scid); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_sup_cid(GF_BitStream *bs, GF_SCIDesc *scid, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 nbBytes = 0, len; | |
| if (! scid) return GF_BAD_PARAM; | |
| scid->languageCode = gf_bs_read_int(bs, 24); | |
| nbBytes += 3; | |
| e = OD_ReadUTF8String(bs, & scid->supplContentIdentifierTitle, GF_TRUE, &len); | |
| if (e) return e; | |
| nbBytes += len; | |
| e = OD_ReadUTF8String(bs, & scid->supplContentIdentifierValue, GF_TRUE, &len); | |
| if (e) return e; | |
| nbBytes += len; | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_sup_cid(GF_SCIDesc *scid, u32 *outSize) | |
| { | |
| if (! scid) return GF_BAD_PARAM; | |
| *outSize = 3 + OD_SizeUTF8String(scid->supplContentIdentifierTitle, GF_TRUE) + OD_SizeUTF8String(scid->supplContentIdentifierValue, GF_TRUE); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_sup_cid(GF_BitStream *bs, GF_SCIDesc *scid) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (! scid) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)scid, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, scid->tag, size); | |
| if (e) return e; | |
| gf_bs_write_int(bs, scid->languageCode, 24); | |
| OD_WriteUTF8String(bs, scid->supplContentIdentifierTitle, GF_TRUE); | |
| OD_WriteUTF8String(bs, scid->supplContentIdentifierValue, GF_TRUE); | |
| return GF_OK; | |
| } | |
| /*IPMPX stuff*/ | |
| GF_Descriptor *gf_odf_new_ipmp_tool_list() | |
| { | |
| GF_IPMP_ToolList*newDesc = (GF_IPMP_ToolList*) gf_malloc(sizeof(GF_IPMP_ToolList)); | |
| if (!newDesc) return NULL; | |
| newDesc->ipmp_tools = gf_list_new(); | |
| newDesc->tag = GF_ODF_IPMP_TL_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ipmp_tool_list(GF_IPMP_ToolList *ipmptl) | |
| { | |
| if (!ipmptl) return GF_BAD_PARAM; | |
| while (gf_list_count(ipmptl->ipmp_tools)) { | |
| GF_Descriptor *t = (GF_Descriptor *) gf_list_get(ipmptl->ipmp_tools, 0); | |
| gf_list_rem(ipmptl->ipmp_tools, 0); | |
| gf_odf_delete_descriptor(t); | |
| } | |
| gf_list_del(ipmptl->ipmp_tools); | |
| gf_free(ipmptl); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_ipmp_tool_list(GF_BitStream *bs, GF_IPMP_ToolList *ipmptl, u32 DescSize) | |
| { | |
| GF_Err e; | |
| u32 tmpSize; | |
| u32 nbBytes = 0; | |
| if (! ipmptl) return GF_BAD_PARAM; | |
| while (nbBytes < DescSize) { | |
| GF_Descriptor *tmp = NULL; | |
| e = gf_odf_parse_descriptor(bs, &tmp, &tmpSize); | |
| if (e) return e; | |
| if (!tmp) return GF_ODF_INVALID_DESCRIPTOR; | |
| e = gf_list_add(ipmptl->ipmp_tools, tmp); | |
| if (e) return e; | |
| nbBytes += tmpSize + gf_odf_size_field_size(tmpSize); | |
| } | |
| if (nbBytes != DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_ipmp_tool_list(GF_IPMP_ToolList *ipmptl, u32 *outSize) | |
| { | |
| if (!ipmptl) return GF_BAD_PARAM; | |
| *outSize = 0; | |
| return gf_odf_size_descriptor_list(ipmptl->ipmp_tools, outSize); | |
| } | |
| GF_Err gf_odf_write_ipmp_tool_list(GF_BitStream *bs, GF_IPMP_ToolList *ipmptl) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!ipmptl) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ipmptl, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ipmptl->tag, size); | |
| if (e) return e; | |
| return gf_odf_write_descriptor_list(bs, ipmptl->ipmp_tools); | |
| } | |
| GF_Descriptor *gf_odf_new_ipmp_tool() | |
| { | |
| GF_IPMP_Tool *newDesc = (GF_IPMP_Tool*) gf_malloc(sizeof(GF_IPMP_Tool)); | |
| if (!newDesc) return NULL; | |
| memset(newDesc, 0, sizeof(GF_IPMP_Tool)); | |
| newDesc->tag = GF_ODF_IPMP_TL_TAG; | |
| return (GF_Descriptor *) newDesc; | |
| } | |
| GF_Err gf_odf_del_ipmp_tool(GF_IPMP_Tool *ipmpt) | |
| { | |
| if (!ipmpt) return GF_BAD_PARAM; | |
| if (ipmpt->tool_url) gf_free(ipmpt->tool_url); | |
| gf_free(ipmpt); | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_read_ipmp_tool(GF_BitStream *bs, GF_IPMP_Tool *ipmpt, u32 DescSize) | |
| { | |
| Bool is_alt, is_param; | |
| u32 nbBytes = 0; | |
| if (! ipmpt) return GF_BAD_PARAM; | |
| gf_bs_read_data(bs, (char*) ipmpt->IPMP_ToolID, 16); | |
| is_alt = (Bool)gf_bs_read_int(bs, 1); | |
| is_param = (Bool)gf_bs_read_int(bs, 1); | |
| gf_bs_read_int(bs, 6); | |
| nbBytes = 17; | |
| if (is_alt) { | |
| u32 i; | |
| ipmpt->num_alternate = gf_bs_read_int(bs, 8); | |
| nbBytes += 1; | |
| if (ipmpt->num_alternate > MAX_IPMP_ALT_TOOLS) | |
| return GF_ODF_INVALID_DESCRIPTOR; | |
| for (i=0; i<ipmpt->num_alternate; i++) { | |
| if (nbBytes + 16 > DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| gf_bs_read_data(bs, (char*)ipmpt->specificToolID[i], 16); | |
| nbBytes += 16; | |
| } | |
| } | |
| if (nbBytes>DescSize) return GF_ODF_INVALID_DESCRIPTOR; | |
| if (is_param) { } | |
| if (nbBytes<DescSize) { | |
| u32 s; | |
| nbBytes += gf_ipmpx_array_size(bs, &s); | |
| if (s>0xFFFFFF) return GF_ODF_INVALID_DESCRIPTOR; | |
| if (s) { | |
| ipmpt->tool_url = (char*)gf_malloc(sizeof(char)*(s+1)); | |
| gf_bs_read_data(bs, ipmpt->tool_url, s); | |
| ipmpt->tool_url[s] = 0; | |
| nbBytes += s; | |
| } | |
| } | |
| if (nbBytes!=DescSize) return GF_NON_COMPLIANT_BITSTREAM; | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_size_ipmp_tool(GF_IPMP_Tool *ipmpt, u32 *outSize) | |
| { | |
| if (!ipmpt) return GF_BAD_PARAM; | |
| *outSize = 17; | |
| if (ipmpt->num_alternate) *outSize += 1 + 16*ipmpt->num_alternate; | |
| if (ipmpt->tool_url) { | |
| u32 s = (u32) strlen(ipmpt->tool_url); | |
| *outSize += gf_odf_size_field_size(s) - 1 + s; | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err gf_odf_write_ipmp_tool(GF_BitStream *bs, GF_IPMP_Tool *ipmpt) | |
| { | |
| GF_Err e; | |
| u32 size; | |
| if (!ipmpt) return GF_BAD_PARAM; | |
| e = gf_odf_size_descriptor((GF_Descriptor *)ipmpt, &size); | |
| if (e) return e; | |
| e = gf_odf_write_base_descriptor(bs, ipmpt->tag, size); | |
| if (e) return e; | |
| gf_bs_write_data(bs, (char*)ipmpt->IPMP_ToolID, 16); | |
| gf_bs_write_int(bs, ipmpt->num_alternate ? 1 : 0, 1); | |
| gf_bs_write_int(bs, 0, 1); | |
| gf_bs_write_int(bs, 0, 6); | |
| if (ipmpt->num_alternate) { | |
| u32 i; | |
| gf_bs_write_int(bs, ipmpt->num_alternate, 8); | |
| for (i=0; i<ipmpt->num_alternate; i++) gf_bs_write_data(bs, (char*)ipmpt->specificToolID[i], 16); | |
| } | |
| if (ipmpt->tool_url) gf_ipmpx_write_array(bs, ipmpt->tool_url, (u32) strlen(ipmpt->tool_url)); | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_MINIMAL_ODF*/ |