GF_Err gf_isom_setup_hint_track(GF_ISOFile *movie, u32 trackNumber, u32 HintType) { GF_Err e; GF_TrackBox *trak; GF_TrackReferenceBox *tref; GF_TrackReferenceTypeBox *dpnd; GF_HintMediaHeaderBox *hmhd; //UDTA related ... GF_UserDataBox *udta; //what do we support switch (HintType) { case GF_ISOM_HINT_RTP: break; default: return GF_NOT_SUPPORTED; } e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); if (e) return e; trak = gf_isom_get_track_from_file(movie, trackNumber); if (!trak) return gf_isom_last_error(movie); //check we have a hint ... if ( !IsHintTrack(trak)) { return GF_BAD_PARAM; } hmhd = (GF_HintMediaHeaderBox *)trak->Media->information->InfoHeader; //make sure the subtype was not already defined if (hmhd->subType) return GF_BAD_PARAM; //store the HintTrack format for later use... hmhd->subType = HintType; //hint tracks always have a tref and everything ... if (!trak->References) { if (!trak->References) { tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF); e = trak_AddBox((GF_Box*)trak, (GF_Box *)tref); if (e) return e; } } tref = trak->References; //do we have a hint reference on this trak ??? e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_HINT, &dpnd); if (e) return e; //if yes, return false (existing hint track...) if (dpnd) return GF_BAD_PARAM; //create our dep dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_HINT; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; //for RTP, we need to do some UDTA-related stuff... if (HintType != GF_ISOM_HINT_RTP) return GF_OK; if (!trak->udta) { //create one udta = (GF_UserDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA); e = trak_AddBox((GF_Box*)trak, (GF_Box *) udta); if (e) return e; } udta = trak->udta; //HNTI e = udta_AddBox(udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI)); if (e) return e; /* //NAME e = udta_AddBox(udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_NAME)); if (e) return e; //HINF return udta_AddBox(udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HINF)); */ return GF_OK; }
GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex, u32 DataReferenceIndex, GF_ESD *esd, u32 *outStreamIndex) { GF_Err e; GF_MPEGSampleEntryBox *entry; GF_MPEGVisualSampleEntryBox *entry_v; GF_MPEGAudioSampleEntryBox *entry_a; GF_TrackReferenceBox *tref; GF_TrackReferenceTypeBox *dpnd; u16 tmpRef; entry = NULL; tref = NULL; if (!trak || !esd || (!outStreamIndex && !DataReferenceIndex) ) return GF_BAD_PARAM; if (!Track_IsMPEG4Stream(trak->Media->handler->handlerType)) return GF_ISOM_INVALID_MEDIA; esd->ESID = 0; //set SL to predefined if no url if (esd->URLString == NULL) { if (!esd->slConfig) esd->slConfig = (GF_SLConfig*) gf_odf_desc_new(GF_ODF_SLC_TAG); esd->slConfig->predefined = SLPredef_MP4; esd->slConfig->durationFlag = 0; esd->slConfig->useTimestampsFlag = 1; } //get the REF box if needed if (esd->dependsOnESID || esd->OCRESID ) { if (!trak->References) { tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF); e = trak_AddBox((GF_Box*)trak, (GF_Box *)tref); if (e) return e; } tref = trak->References; } //Update Stream dependancies e = Track_FindRef(trak, GF_ISOM_REF_DECODE, &dpnd); if (e) return e; if (!dpnd && esd->dependsOnESID) { dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_DPND; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; e = reftype_AddRefTrack(dpnd, esd->dependsOnESID, NULL); if (e) return e; } else if (dpnd && !esd->dependsOnESID) { Track_RemoveRef(trak, GF_ISOM_BOX_TYPE_DPND); } esd->dependsOnESID = 0; //Update GF_Clock dependancies e = Track_FindRef(trak, GF_ISOM_REF_OCR, &dpnd); if (e) return e; if (!dpnd && esd->OCRESID) { dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_SYNC; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; e = reftype_AddRefTrack(dpnd, esd->OCRESID, NULL); if (e) return e; } else if (dpnd && !esd->OCRESID) { Track_RemoveRef(trak, GF_ISOM_BOX_TYPE_SYNC); } else if (dpnd && esd->OCRESID) { if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA; dpnd->trackIDs[0] = esd->OCRESID; } esd->OCRESID = 0; //brand new case: we have to change the IPI desc if (esd->ipiPtr) { e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd); if (e) return e; if (!dpnd) { tmpRef = 0; dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR; e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd); if (e) return e; e = reftype_AddRefTrack(dpnd, esd->ipiPtr->IPI_ES_Id, &tmpRef); if (e) return e; //and replace the tag and value... esd->ipiPtr->IPI_ES_Id = tmpRef; esd->ipiPtr->tag = GF_ODF_ISOM_IPI_PTR_TAG; } else { //Watch out! ONLY ONE IPI dependancy is allowed per stream if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA; //if an existing one is there, what shall we do ??? //donno, erase it dpnd->trackIDs[0] = esd->ipiPtr->IPI_ES_Id; //and replace the tag and value... esd->ipiPtr->IPI_ES_Id = 1; esd->ipiPtr->tag = GF_ODF_ISOM_IPI_PTR_TAG; } } /*don't store the lang desc in ESD, use the media header language info*/ if (esd->langDesc) { trak->Media->mediaHeader->packedLanguage[0] = (esd->langDesc->langCode>>16)&0xFF; trak->Media->mediaHeader->packedLanguage[1] = (esd->langDesc->langCode>>8)&0xFF; trak->Media->mediaHeader->packedLanguage[2] = (esd->langDesc->langCode)&0xFF; gf_odf_desc_del((GF_Descriptor *)esd->langDesc); esd->langDesc = NULL; }
// Update the dependancies when an OD AU is inserted in the file GF_Err Media_ParseODFrame(GF_MediaBox *mdia, GF_ISOSample *sample, GF_ISOSample **od_samp) { GF_TrackReferenceBox *tref; GF_TrackReferenceTypeBox *mpod; GF_Err e; GF_ODCom *com; GF_ODCodec *ODencode; GF_ODCodec *ODdecode; u32 i, j; //the commands we proceed GF_ESDUpdate *esdU, *esdU2; GF_ESDRemove *esdR, *esdR2; GF_ODUpdate *odU, *odU2; //the desc they contain GF_ObjectDescriptor *od; GF_IsomObjectDescriptor *isom_od; GF_ESD *esd; GF_ES_ID_Ref *ref; GF_Descriptor *desc; *od_samp = NULL; if (!mdia || !sample || !sample->data || !sample->dataLength) return GF_BAD_PARAM; //First find the references, and create them if none tref = mdia->mediaTrack->References; if (!tref) { tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF); e = trak_AddBox((GF_Box*)mdia->mediaTrack, (GF_Box *) tref); if (e) return e; } //then find the OD reference, and create it if none e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod); if (e) return e; if (!mpod) { mpod = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); mpod->reference_type = GF_ISOM_BOX_TYPE_MPOD; e = tref_AddBox((GF_Box*)tref, (GF_Box *)mpod); if (e) return e; } //OK, create our codecs ODencode = gf_odf_codec_new(); if (!ODencode) return GF_OUT_OF_MEM; ODdecode = gf_odf_codec_new(); if (!ODdecode) return GF_OUT_OF_MEM; e = gf_odf_codec_set_au(ODdecode, sample->data, sample->dataLength); if (e) goto err_exit; e = gf_odf_codec_decode(ODdecode); if (e) goto err_exit; while (1) { com = gf_odf_codec_get_com(ODdecode); if (!com) break; //check our commands switch (com->tag) { //Rewrite OD Update case GF_ODF_OD_UPDATE_TAG: //duplicate our command odU = (GF_ODUpdate *) com; odU2 = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); i=0; while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) { //both OD and IODs are accepted switch (desc->tag) { case GF_ODF_OD_TAG: case GF_ODF_IOD_TAG: break; default: e = GF_ODF_INVALID_DESCRIPTOR; goto err_exit; } //get the esd e = gf_odf_desc_copy(desc, (GF_Descriptor **)&od); if (e) goto err_exit; if (desc->tag == GF_ODF_OD_TAG) { isom_od = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomObjectDescriptor)); isom_od->tag = GF_ODF_ISOM_OD_TAG; } else { isom_od = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomInitialObjectDescriptor)); isom_od->tag = GF_ODF_ISOM_IOD_TAG; //copy PL ((GF_IsomInitialObjectDescriptor *)isom_od)->inlineProfileFlag = ((GF_InitialObjectDescriptor *)od)->inlineProfileFlag; ((GF_IsomInitialObjectDescriptor *)isom_od)->graphics_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->graphics_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->audio_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->audio_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->OD_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->OD_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->scene_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->scene_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->visual_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->visual_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList = ((GF_InitialObjectDescriptor *)od)->IPMPToolList; ((GF_InitialObjectDescriptor *)od)->IPMPToolList = NULL; } //in OD stream only ref desc are accepted isom_od->ES_ID_RefDescriptors = gf_list_new(); isom_od->ES_ID_IncDescriptors = NULL; //TO DO: check that a given sampleDescription exists isom_od->extensionDescriptors = od->extensionDescriptors; od->extensionDescriptors = NULL; isom_od->IPMP_Descriptors = od->IPMP_Descriptors; od->IPMP_Descriptors = NULL; isom_od->OCIDescriptors = od->OCIDescriptors; od->OCIDescriptors = NULL; isom_od->URLString = od->URLString; od->URLString = NULL; isom_od->objectDescriptorID = od->objectDescriptorID; j=0; while ((esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &j))) { ref = (GF_ES_ID_Ref *) gf_odf_desc_new(GF_ODF_ESD_REF_TAG); //1 to 1 mapping trackID and ESID. Add this track to MPOD //if track does not exist, this will be remove while reading the OD stream e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef); e = gf_odf_desc_add_desc((GF_Descriptor *)isom_od, (GF_Descriptor *)ref); if (e) goto err_exit; } //delete our desc gf_odf_desc_del((GF_Descriptor *)od); //and add the new one to our command gf_list_add(odU2->objectDescriptors, isom_od); } //delete the command gf_odf_com_del((GF_ODCom **)&odU); //and add the new one to the codec gf_odf_codec_add_com(ODencode, (GF_ODCom *)odU2); break; //Rewrite ESD Update case GF_ODF_ESD_UPDATE_TAG: esdU = (GF_ESDUpdate *) com; esdU2 = (GF_ESDUpdate *) gf_odf_com_new(GF_ODF_ESD_UPDATE_TAG); esdU2->ODID = esdU->ODID; i=0; while ((esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &i))) { ref = (GF_ES_ID_Ref *) gf_odf_desc_new(GF_ODF_ESD_REF_TAG); //1 to 1 mapping trackID and ESID e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef); e = gf_list_add(esdU2->ESDescriptors, ref); if (e) goto err_exit; } gf_odf_com_del((GF_ODCom **)&esdU); gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdU2); break; //Brand new case: the ESRemove has to be rewritten too according to the specs... case GF_ODF_ESD_REMOVE_TAG: esdR = (GF_ESDRemove *) com; esdR2 = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG); //change the tag for the file format esdR2->tag = GF_ODF_ESD_REMOVE_REF_TAG; esdR2->ODID = esdR->ODID; esdR2->NbESDs = esdR->NbESDs; if (esdR->NbESDs) { //alloc our stuff esdR2->ES_ID = (unsigned short*)gf_malloc(sizeof(u32) * esdR->NbESDs); if (!esdR2->ES_ID) { e = GF_OUT_OF_MEM; goto err_exit; } for (i = 0; i < esdR->NbESDs; i++) { //1 to 1 mapping trackID and ESID e = reftype_AddRefTrack(mpod, esdR->ES_ID[i], &esdR2->ES_ID[i]); if (e) goto err_exit; } } gf_odf_com_del(&com); gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdR2); break; //Add the command as is default: e = gf_odf_codec_add_com(ODencode, com); if (e) goto err_exit; } } //encode our new AU e = gf_odf_codec_encode(ODencode, 1); if (e) goto err_exit; //and set the buffer in the sample *od_samp = gf_isom_sample_new(); (*od_samp)->CTS_Offset = sample->CTS_Offset; (*od_samp)->DTS = sample->DTS; (*od_samp)->IsRAP = sample->IsRAP; e = gf_odf_codec_get_au(ODencode, & (*od_samp)->data, & (*od_samp)->dataLength); if (e) { gf_isom_sample_del(od_samp); *od_samp = NULL; } err_exit: gf_odf_codec_del(ODencode); gf_odf_codec_del(ODdecode); return e; }