/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / ISO Media File Format sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include void AVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc) { if (avc->emul_esd) gf_odf_desc_del((GF_Descriptor *)avc->emul_esd); avc->emul_esd = gf_odf_desc_esd_new(2); avc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL; /*AVC OTI is 0x21, AVC parameter set stream OTI (not supported in gpac) is 0x22*/ avc->emul_esd->decoderConfig->objectTypeIndication = 0x21; if (avc->bitrate) { avc->emul_esd->decoderConfig->bufferSizeDB = avc->bitrate->bufferSizeDB; avc->emul_esd->decoderConfig->avgBitrate = avc->bitrate->avgBitrate; avc->emul_esd->decoderConfig->maxBitrate = avc->bitrate->maxBitrate; } if (avc->descr) { u32 i=0; GF_Descriptor *desc,*clone; i=0; while ((desc = (GF_Descriptor *)gf_list_enum(avc->descr->descriptors, &i))) { clone = NULL; gf_odf_desc_copy(desc, &clone); if (gf_odf_desc_add_desc((GF_Descriptor *)avc->emul_esd, clone) != GF_OK) gf_odf_desc_del(clone); } } if (avc->avc_config && avc->avc_config->config) { gf_odf_avc_cfg_write(avc->avc_config->config, &avc->emul_esd->decoderConfig->decoderSpecificInfo->data, &avc->emul_esd->decoderConfig->decoderSpecificInfo->dataLength); } } GF_Err AVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd) { if (!avc->bitrate) avc->bitrate = (GF_MPEG4BitRateBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT); if (avc->descr) gf_isom_box_del((GF_Box *) avc->descr); avc->descr = NULL; avc->bitrate->avgBitrate = esd->decoderConfig->avgBitrate; avc->bitrate->maxBitrate = esd->decoderConfig->maxBitrate; avc->bitrate->bufferSizeDB = esd->decoderConfig->bufferSizeDB; if (gf_list_count(esd->IPIDataSet) || gf_list_count(esd->IPMPDescriptorPointers) || esd->langDesc || gf_list_count(esd->extensionDescriptors) || esd->ipiPtr || esd->qos || esd->RegDescriptor) { avc->descr = (GF_MPEG4ExtensionDescriptorsBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_M4DS); if (esd->RegDescriptor) { gf_list_add(avc->descr->descriptors, esd->RegDescriptor); esd->RegDescriptor = NULL; } if (esd->qos) { gf_list_add(avc->descr->descriptors, esd->qos); esd->qos = NULL; } if (esd->ipiPtr) { gf_list_add(avc->descr->descriptors, esd->ipiPtr); esd->ipiPtr= NULL; } while (gf_list_count(esd->IPIDataSet)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->IPIDataSet, 0); gf_list_rem(esd->IPIDataSet, 0); gf_list_add(avc->descr->descriptors, desc); } while (gf_list_count(esd->IPMPDescriptorPointers)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->IPMPDescriptorPointers, 0); gf_list_rem(esd->IPMPDescriptorPointers, 0); gf_list_add(avc->descr->descriptors, desc); } if (esd->langDesc) { gf_list_add(avc->descr->descriptors, esd->langDesc); esd->langDesc = NULL; } while (gf_list_count(esd->extensionDescriptors)) { GF_Descriptor *desc = (GF_Descriptor *)gf_list_get(esd->extensionDescriptors, 0); gf_list_rem(esd->extensionDescriptors, 0); gf_list_add(avc->descr->descriptors, desc); } } /*update GF_AVCConfig*/ if (!avc->avc_config) avc->avc_config = (GF_AVCConfigurationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC); if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { if (avc->avc_config->config) gf_odf_avc_cfg_del(avc->avc_config->config); avc->avc_config->config = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); } gf_odf_desc_del((GF_Descriptor *)esd); AVC_RewriteESDescriptor(avc); return GF_OK; } static GF_AVCConfig *AVC_DuplicateConfig(GF_AVCConfig *cfg) { u32 i, count; GF_AVCConfigSlot *p1, *p2; GF_AVCConfig *cfg_new = gf_odf_avc_cfg_new(); cfg_new->AVCLevelIndication = cfg->AVCLevelIndication; cfg_new->AVCProfileIndication = cfg->AVCProfileIndication; cfg_new->configurationVersion = cfg->configurationVersion; cfg_new->nal_unit_size = cfg->nal_unit_size; cfg_new->profile_compatibility = cfg->profile_compatibility; count = gf_list_count(cfg->sequenceParameterSets); for (i=0; isequenceParameterSets, i); p2 = (GF_AVCConfigSlot*)malloc(sizeof(GF_AVCConfigSlot)); p2->size = p1->size; p2->data = (char *)malloc(sizeof(char)*p1->size); memcpy(p2->data, p1->data, sizeof(char)*p1->size); gf_list_add(cfg_new->sequenceParameterSets, p2); } count = gf_list_count(cfg->pictureParameterSets); for (i=0; ipictureParameterSets, i); p2 = (GF_AVCConfigSlot*)malloc(sizeof(GF_AVCConfigSlot)); p2->size = p1->size; p2->data = (char*)malloc(sizeof(char)*p1->size); memcpy(p2->data, p1->data, sizeof(char)*p1->size); gf_list_add(cfg_new->pictureParameterSets, p2); } return cfg_new; } #ifndef GPAC_READ_ONLY GF_Err gf_isom_avc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, char *URLname, char *URNname, u32 *outDescriptionIndex) { GF_TrackBox *trak; GF_Err e; u32 dataRefIndex; GF_TrackReferenceTypeBox *dpnd; GF_TrackReferenceBox *tref; GF_MPEGVisualSampleEntryBox *entry; e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE); if (e) return e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !trak->Media || !cfg) return GF_BAD_PARAM; dpnd = NULL; tref = NULL; //get or create the data ref e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); if (e) return e; if (!dataRefIndex) { e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); if (e) return e; } trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); //create a new entry entry = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AVC1); if (!entry) return GF_OUT_OF_MEM; entry->avc_config = (GF_AVCConfigurationBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC); entry->avc_config->config = AVC_DuplicateConfig(cfg); entry->dataReferenceIndex = dataRefIndex; e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->boxList, entry); *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->boxList); AVC_RewriteESDescriptor(entry); return e; } GF_Err gf_isom_avc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_AVCConfig *cfg) { GF_TrackBox *trak; GF_Err e; GF_MPEGVisualSampleEntryBox *entry; e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE); if (e) return e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !trak->Media || !cfg || !DescriptionIndex) return GF_BAD_PARAM; entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->boxList, DescriptionIndex-1); if (!entry) return GF_BAD_PARAM; if (entry->type != GF_ISOM_BOX_TYPE_AVC1) return GF_BAD_PARAM; if (entry->avc_config->config) gf_odf_avc_cfg_del(entry->avc_config->config); entry->avc_config->config = AVC_DuplicateConfig(cfg); AVC_RewriteESDescriptor(entry); return GF_OK; } GF_Err gf_isom_set_ipod_compatible(GF_ISOFile *the_file, u32 trackNumber) { static u8 ipod_ext[][16] = { { 0x6B, 0x68, 0x40, 0xF2, 0x5F, 0x24, 0x4F, 0xC5, 0xBA, 0x39, 0xA5, 0x1B, 0xCF, 0x03, 0x23, 0xF3} }; GF_TrackBox *trak; GF_Err e; GF_MPEGVisualSampleEntryBox *entry; e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE); if (e) return e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !trak->Media) return GF_BAD_PARAM; entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->boxList, 0); if (!entry) return GF_OK; if (entry->type != GF_ISOM_BOX_TYPE_AVC1) return GF_OK; if (!entry->ipod_ext) entry->ipod_ext = (GF_UnknownUUIDBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID); memcpy(entry->ipod_ext->uuid, ipod_ext, sizeof(u8)*16); entry->ipod_ext->dataSize = 0; return GF_OK; } #endif GF_EXPORT GF_AVCConfig *gf_isom_avc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex) { GF_TrackBox *trak; GF_MPEGVisualSampleEntryBox *entry; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !trak->Media || !DescriptionIndex) return NULL; entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->boxList, DescriptionIndex-1); if (!entry) return NULL; //if (entry->type != GF_ISOM_BOX_TYPE_AVC1) return NULL; if (!entry->avc_config) return NULL; return AVC_DuplicateConfig(entry->avc_config->config); } void btrt_del(GF_Box *s) { GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *)s; if (ptr) free(ptr); } GF_Err btrt_Read(GF_Box *s, GF_BitStream *bs) { GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *)s; ptr->bufferSizeDB = gf_bs_read_u32(bs); ptr->maxBitrate = gf_bs_read_u32(bs); ptr->avgBitrate = gf_bs_read_u32(bs); return GF_OK; } GF_Box *btrt_New() { GF_MPEG4BitRateBox *tmp = (GF_MPEG4BitRateBox *) malloc(sizeof(GF_MPEG4BitRateBox)); if (tmp == NULL) return NULL; memset(tmp, 0, sizeof(GF_MPEG4BitRateBox)); tmp->type = GF_ISOM_BOX_TYPE_BTRT; return (GF_Box *)tmp; } #ifndef GPAC_READ_ONLY GF_Err btrt_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u32(bs, ptr->bufferSizeDB); gf_bs_write_u32(bs, ptr->maxBitrate); gf_bs_write_u32(bs, ptr->avgBitrate); return GF_OK; } GF_Err btrt_Size(GF_Box *s) { GF_Err e; GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *)s; e = gf_isom_box_get_size(s); ptr->size += 12; return e; } #endif void m4ds_del(GF_Box *s) { GF_MPEG4ExtensionDescriptorsBox *ptr = (GF_MPEG4ExtensionDescriptorsBox *)s; gf_odf_desc_list_del(ptr->descriptors); gf_list_del(ptr->descriptors); free(ptr); } GF_Err m4ds_Read(GF_Box *s, GF_BitStream *bs) { GF_Err e; char *enc_od; GF_MPEG4ExtensionDescriptorsBox *ptr = (GF_MPEG4ExtensionDescriptorsBox *)s; u32 od_size = (u32) ptr->size; if (!od_size) return GF_OK; enc_od = (char *)malloc(sizeof(char) * od_size); gf_bs_read_data(bs, enc_od, od_size); e = gf_odf_desc_list_read((char *)enc_od, od_size, ptr->descriptors); free(enc_od); return e; } GF_Box *m4ds_New() { GF_MPEG4ExtensionDescriptorsBox *tmp = (GF_MPEG4ExtensionDescriptorsBox *) malloc(sizeof(GF_MPEG4ExtensionDescriptorsBox)); if (tmp == NULL) return NULL; memset(tmp, 0, sizeof(GF_MPEG4ExtensionDescriptorsBox)); tmp->type = GF_ISOM_BOX_TYPE_M4DS; tmp->descriptors = gf_list_new(); return (GF_Box *)tmp; } #ifndef GPAC_READ_ONLY GF_Err m4ds_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; char *enc_ods; u32 enc_od_size; GF_MPEG4ExtensionDescriptorsBox *ptr = (GF_MPEG4ExtensionDescriptorsBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; enc_ods = NULL; enc_od_size = 0; e = gf_odf_desc_list_write(ptr->descriptors, &enc_ods, &enc_od_size); if (e) return e; if (enc_od_size) { gf_bs_write_data(bs, enc_ods, enc_od_size); free(enc_ods); } return GF_OK; } GF_Err m4ds_Size(GF_Box *s) { GF_Err e; u32 descSize; GF_MPEG4ExtensionDescriptorsBox *ptr = (GF_MPEG4ExtensionDescriptorsBox *)s; e = gf_isom_box_get_size(s); if (!e) e = gf_odf_desc_list_size(ptr->descriptors, &descSize); ptr->size += descSize; return e; } #endif void avcc_del(GF_Box *s) { GF_AVCConfigurationBox *ptr = (GF_AVCConfigurationBox *)s; if (ptr->config) gf_odf_avc_cfg_del(ptr->config); free(ptr); } GF_Err avcc_Read(GF_Box *s, GF_BitStream *bs) { u32 i, count; GF_AVCConfigurationBox *ptr = (GF_AVCConfigurationBox *)s; if (ptr->config) gf_odf_avc_cfg_del(ptr->config); ptr->config = gf_odf_avc_cfg_new(); ptr->config->configurationVersion = gf_bs_read_u8(bs); ptr->config->AVCProfileIndication = gf_bs_read_u8(bs); ptr->config->profile_compatibility = gf_bs_read_u8(bs); ptr->config->AVCLevelIndication = gf_bs_read_u8(bs); gf_bs_read_int(bs, 6); ptr->config->nal_unit_size = 1 + gf_bs_read_int(bs, 2); gf_bs_read_int(bs, 3); count = gf_bs_read_int(bs, 5); for (i=0; isize = gf_bs_read_u16(bs); sl->data = (char *)malloc(sizeof(char) * sl->size); gf_bs_read_data(bs, sl->data, sl->size); gf_list_add(ptr->config->sequenceParameterSets, sl); } count = gf_bs_read_u8(bs); for (i=0; isize = gf_bs_read_u16(bs); sl->data = (char *)malloc(sizeof(char) * sl->size); gf_bs_read_data(bs, sl->data, sl->size); gf_list_add(ptr->config->pictureParameterSets, sl); } return GF_OK; } GF_Box *avcc_New() { GF_AVCConfigurationBox *tmp = (GF_AVCConfigurationBox *) malloc(sizeof(GF_MPEG4BitRateBox)); if (tmp == NULL) return NULL; memset(tmp, 0, sizeof(GF_AVCConfigurationBox)); tmp->type = GF_ISOM_BOX_TYPE_AVCC; return (GF_Box *)tmp; } #ifndef GPAC_READ_ONLY GF_Err avcc_Write(GF_Box *s, GF_BitStream *bs) { u32 i, count; GF_Err e; GF_AVCConfigurationBox *ptr = (GF_AVCConfigurationBox *) s; if (!s) return GF_BAD_PARAM; if (!ptr->config) return GF_OK; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->config->configurationVersion); gf_bs_write_u8(bs, ptr->config->AVCProfileIndication); gf_bs_write_u8(bs, ptr->config->profile_compatibility); gf_bs_write_u8(bs, ptr->config->AVCLevelIndication); gf_bs_write_int(bs, 0x3F, 6); gf_bs_write_int(bs, ptr->config->nal_unit_size - 1, 2); gf_bs_write_int(bs, 0x7, 3); count = gf_list_count(ptr->config->sequenceParameterSets); gf_bs_write_int(bs, count, 5); for (i=0; iconfig->sequenceParameterSets, i); gf_bs_write_u16(bs, sl->size); gf_bs_write_data(bs, sl->data, sl->size); } count = gf_list_count(ptr->config->pictureParameterSets); gf_bs_write_u8(bs, count); for (i=0; iconfig->pictureParameterSets, i); gf_bs_write_u16(bs, sl->size); gf_bs_write_data(bs, sl->data, sl->size); } return GF_OK; } GF_Err avcc_Size(GF_Box *s) { GF_Err e; u32 i, count; GF_AVCConfigurationBox *ptr = (GF_AVCConfigurationBox *)s; e = gf_isom_box_get_size(s); if (e) return e; if (!ptr->config) { ptr->size = 0; return e; } ptr->size += 7; count = gf_list_count(ptr->config->sequenceParameterSets); for (i=0; isize += 2 + ((GF_AVCConfigSlot *)gf_list_get(ptr->config->sequenceParameterSets, i))->size; count = gf_list_count(ptr->config->pictureParameterSets); for (i=0; isize += 2 + ((GF_AVCConfigSlot *)gf_list_get(ptr->config->pictureParameterSets, i))->size; return GF_OK; } #endif