Example #1
0
File: hinting.c Project: erelh/gpac
GF_EXPORT
GF_Err gf_isom_reset_hint_reader(GF_ISOFile *the_file, u32 trackNumber, u32 sample_start, u32 ts_offset, u32 sn_offset, u32 ssrc)
{
	GF_Err e;
	GF_TrackBox *trak;
	GF_HintSampleEntryBox *entry;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak) return GF_BAD_PARAM;

	if (!sample_start) return GF_BAD_PARAM;
	if (sample_start>=trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;

	e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **) &entry, NULL);
	if (e) return e;
	switch (entry->type) {
	case GF_ISOM_BOX_TYPE_RTP_STSD:
		break;
	default:
		return GF_NOT_SUPPORTED;
	}

	entry->hint_ref = NULL;
	e = Track_FindRef(trak, GF_ISOM_REF_HINT, &entry->hint_ref);
	if (e) return e;

	entry->cur_sample = sample_start;
	entry->pck_sn = 1 + sn_offset;
	entry->ssrc = ssrc;
	entry->ts_offset = ts_offset;
	if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
	entry->hint_sample = NULL;
	return GF_OK;
}
Example #2
0
M4Err M4H_AddStreamDescriptionData(M4File *the_file, u32 trackNumber, u32 SourceTrackID, u32 StreamDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin)
{
	TrackAtom *trak;
	HintSampleEntryAtom *entry;
	u32 count;
	u16 refIndex;
	HintPacket *pck;
	StreamDescDTE *dte;
	M4Err e;
	TrackReferenceTypeAtom *hint;

	M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex);

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !IsHintTrack(trak)) return M4BadParam;

	e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &count);
	if (e) return e;
	if (!entry->w_sample) return M4BadParam;
	count = ChainGetCount(entry->w_sample->packetTable);
	if (!count) return M4BadParam;
	pck = ChainGetEntry(entry->w_sample->packetTable, count - 1);

	dte = (StreamDescDTE *) NewDTE(3);
	dte->byteOffset = offsetInDescription;
	dte->dataLength = DataLength;
	dte->streamDescIndex = StreamDescriptionIndex;
	if (SourceTrackID == trak->Header->trackID) {
		dte->trackRefIndex = -1;
	} else {
		//get (or set) the track reference index 
		e = Track_FindRef(trak, M4_HintTrack_Ref, &hint);
		if (e) return e;
		e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
		if (e) return e;
		//WARNING: IN QT, MUST BE 0-based !!!
		dte->trackRefIndex = (u8) (refIndex - 1);
	}
	return AddDTE_HintPacket(entry->w_sample->HintType, pck, (GenericDTE *)dte, AtBegin);
}
Example #3
0
GF_Err gf_isom_hint_sample_description_data(GF_ISOFile *the_file, u32 trackNumber, u32 SourceTrackID, u32 StreamDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin)
{
	GF_TrackBox *trak;
	GF_HintSampleEntryBox *entry;
	u32 count;
	u16 refIndex;
	GF_HintPacket *pck;
	GF_StreamDescDTE *dte;
	GF_Err e;
	GF_TrackReferenceTypeBox *hint;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;

	e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
	if (e) return e;
	if (!entry->hint_sample) return GF_BAD_PARAM;
	count = gf_list_count(entry->hint_sample->packetTable);
	if (!count) return GF_BAD_PARAM;
	pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);

	dte = (GF_StreamDescDTE *) NewDTE(3);
	dte->byteOffset = offsetInDescription;
	dte->dataLength = DataLength;
	dte->streamDescIndex = StreamDescriptionIndex;
	if (SourceTrackID == trak->Header->trackID) {
		dte->trackRefIndex = (s8) -1;
	} else {
		//get (or set) the track reference index 
		e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint);
		if (e) return e;
		e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
		if (e) return e;
		//WARNING: IN QT, MUST BE 0-based !!!
		dte->trackRefIndex = (u8) (refIndex - 1);
	}
	return gf_isom_hint_pck_add_dte(entry->hint_sample->HintType, pck, (GF_GenericDTE *)dte, AtBegin);
}
Example #4
0
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;
}
Example #5
0
GF_Err gf_isom_hint_sample_data(GF_ISOFile *the_file, u32 trackNumber, u32 SourceTrackID, u32 SampleNumber, u16 DataLength, u32 offsetInSample, char *extra_data, u8 AtBegin)
{
	GF_TrackBox *trak;
	GF_HintSampleEntryBox *entry;
	u32 count;
	u16 refIndex;
	GF_HintPacket *pck;
	GF_SampleDTE *dte;
	GF_Err e;
	GF_TrackReferenceTypeBox *hint;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;


	e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
	if (e) return e;
	if (!entry->hint_sample) return GF_BAD_PARAM;
	count = gf_list_count(entry->hint_sample->packetTable);
	if (!count) return GF_BAD_PARAM;
	pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);

	dte = (GF_SampleDTE *) NewDTE(2);

	dte->dataLength = DataLength;
	dte->sampleNumber = SampleNumber;
	dte->byteOffset = offsetInSample;

	//we're getting data from another track
	if (SourceTrackID != trak->Header->trackID) {
		//get (or set) the track reference index 
		e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint);
		if (e) return e;
		e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
		if (e) return e;
		//WARNING: IN QT, MUST BE 0-based !!!
		dte->trackRefIndex = (u8) (refIndex - 1);
	} else {
		//we're in the hint track
		dte->trackRefIndex = (s8) -1;
		//basic check...
		if (SampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount + 1) {
			DelDTE((GF_GenericDTE *)dte);
			return GF_BAD_PARAM;
		}

		//are we in the current sample ??
		if (!SampleNumber || (SampleNumber == trak->Media->information->sampleTable->SampleSize->sampleCount + 1)) {
			//we adding some stuff in the current sample ...
			dte->byteOffset += entry->hint_sample->dataLength;
			entry->hint_sample->AdditionalData = (char*)gf_realloc(entry->hint_sample->AdditionalData, sizeof(char) * (entry->hint_sample->dataLength + DataLength));
			if (AtBegin) {
				if (entry->hint_sample->dataLength)
					memmove(entry->hint_sample->AdditionalData + DataLength, entry->hint_sample->AdditionalData, entry->hint_sample->dataLength);
				memcpy(entry->hint_sample->AdditionalData, extra_data, DataLength);
				/*offset existing DTE*/
				gf_isom_hint_pck_offset(entry->hint_sample->HintType, pck, DataLength, SampleNumber);
			} else {
				memcpy(entry->hint_sample->AdditionalData + entry->hint_sample->dataLength, extra_data, DataLength);
			}
			entry->hint_sample->dataLength += DataLength;
			//and set the sample number ...
			dte->sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount + 1;
		}
	}
	//OK, add the entry
	return gf_isom_hint_pck_add_dte(entry->hint_sample->HintType, pck, (GF_GenericDTE *)dte, AtBegin);
}
Example #6
0
// Rewrite the good dependancies when an OD AU is extracted from the file
static u32 Media_FindOD_ID(GF_MediaBox *mdia, GF_ISOSample *sample, u32 track_id)
{
	GF_Err e;
	GF_ODCodec *ODdecode;
	GF_ODCom *com;
	u32 the_od_id;
	GF_ODUpdate *odU;
	GF_ESD *esd;
	GF_Descriptor *desc;
	GF_TrackReferenceTypeBox *mpod;
	u32 i, j;

	if (!mdia || !sample || !sample->data || !sample->dataLength) return 0;

	mpod = NULL;
	e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod);
	if (e) return 0;
	//no references, nothing to do...
	if (!mpod) return 0;

	the_od_id = 0;

	ODdecode = gf_odf_codec_new();
	if (!ODdecode) return 0;
	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) {
		GF_List *esd_list = NULL;
		com = gf_odf_codec_get_com(ODdecode);
		if (!com) break;
		if (com->tag != GF_ODF_OD_UPDATE_TAG) continue;
		odU = (GF_ODUpdate *) com;

		i=0;
		while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) {
			switch (desc->tag) {
			case GF_ODF_OD_TAG:
			case GF_ODF_IOD_TAG:
				esd_list = ((GF_ObjectDescriptor *)desc)->ESDescriptors; break;
			default:
				continue;
			}	
			j=0;
			while ((esd = (GF_ESD*)gf_list_enum( esd_list, &j))){
				if (esd->ESID==track_id) {
					the_od_id = ((GF_IsomObjectDescriptor*)desc)->objectDescriptorID;
					break;
				}
			}
			if (the_od_id) break;
		}
		gf_odf_com_del((GF_ODCom **)&odU);
		if (the_od_id) break;
	}

err_exit:
	gf_odf_codec_del(ODdecode);
	if (e) return 0;
	return the_od_id;
}
Example #7
0
// Rewrite the good dependancies when an OD AU is extracted from the file
GF_Err Media_RewriteODFrame(GF_MediaBox *mdia, GF_ISOSample *sample)
{
	GF_Err e;
	GF_ODCodec *ODdecode;
	GF_ODCodec *ODencode;
	GF_ODCom *com;
	
	//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;
	GF_TrackReferenceTypeBox *mpod;
	u32 i, j, skipped;

	if (!mdia || !sample || !sample->data || !sample->dataLength) return GF_BAD_PARAM;

	mpod = NULL;
	e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod);
	if (e) return e;
	//no references, nothing to do...
	if (!mpod) return GF_OK;

	ODdecode = gf_odf_codec_new();
	if (!ODdecode) return GF_OUT_OF_MEM;
	ODencode = gf_odf_codec_new();
	if (!ODencode) {
		gf_odf_codec_del(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;

		//we only need to rewrite commands with ESDs inside: ESDUpdate and ODUpdate
		switch (com->tag) {
		case GF_ODF_OD_UPDATE_TAG:
			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))) {
				switch (desc->tag) {
				case GF_ODF_OD_TAG:
				case GF_ODF_ISOM_OD_TAG:
				//IOD can be used in OD streams
				case GF_ODF_ISOM_IOD_TAG:
					break;
				default:
					return GF_ISOM_INVALID_FILE;
				}
				e = gf_odf_desc_copy(desc, (GF_Descriptor **)&isom_od);
				if (e) goto err_exit;
					
				//create our OD...
				if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
					od = (GF_ObjectDescriptor *) gf_malloc(sizeof(GF_InitialObjectDescriptor));
				} else {
					od = (GF_ObjectDescriptor *) gf_malloc(sizeof(GF_ObjectDescriptor));
				}
				if (!od) {
					e = GF_OUT_OF_MEM;
					goto err_exit;
				}
				od->ESDescriptors = gf_list_new();
				//and duplicate...
				od->objectDescriptorID = isom_od->objectDescriptorID;
				od->tag = GF_ODF_OD_TAG;
				od->URLString = isom_od->URLString;
				isom_od->URLString = NULL;
				od->extensionDescriptors = isom_od->extensionDescriptors;
				isom_od->extensionDescriptors = NULL;
				od->IPMP_Descriptors = isom_od->IPMP_Descriptors;
				isom_od->IPMP_Descriptors = NULL;
				od->OCIDescriptors = isom_od->OCIDescriptors;
				isom_od->OCIDescriptors = NULL;
				
				//init as IOD
				if (isom_od->tag == GF_ODF_ISOM_IOD_TAG) {
					((GF_InitialObjectDescriptor *)od)->audio_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->audio_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->inlineProfileFlag = ((GF_IsomInitialObjectDescriptor *)isom_od)->inlineProfileFlag;
					((GF_InitialObjectDescriptor *)od)->graphics_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->graphics_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->OD_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->OD_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->scene_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->scene_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->visual_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->visual_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->IPMPToolList = ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList;
					((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList = NULL;
				}
				
				//then rewrite the ESDesc
				j=0;
				while ((ref = (GF_ES_ID_Ref*)gf_list_enum(isom_od->ES_ID_RefDescriptors, &j))){
					//if the ref index is not valid, skip this desc...
					if (!mpod->trackIDs || gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue;
					//OK, get the esd
					e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd);
					if (!e) e = gf_odf_desc_add_desc((GF_Descriptor *) od, (GF_Descriptor *) esd);
					if (e) {
						gf_odf_desc_del((GF_Descriptor *)od);
						gf_odf_com_del((GF_ODCom **)&odU2);
						gf_odf_desc_del((GF_Descriptor *)isom_od);
						gf_odf_com_del((GF_ODCom **)&odU);
						goto err_exit;
					}

				}
				//delete our desc
				gf_odf_desc_del((GF_Descriptor *)isom_od);
				gf_list_add(odU2->objectDescriptors, od);
			}
			//clean a bit
			gf_odf_com_del((GF_ODCom **)&odU);
			gf_odf_codec_add_com(ODencode, (GF_ODCom *)odU2);
			break;

		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 ((ref = (GF_ES_ID_Ref*)gf_list_enum(esdU->ESDescriptors, &i))) {
				//if the ref index is not valid, skip this desc...
				if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue;
				//OK, get the esd
				e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd);
				if (e) goto err_exit;
				gf_list_add(esdU2->ESDescriptors, esd);
			}
			gf_odf_com_del((GF_ODCom **)&esdU);
			gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdU2);
			break;

		//brand new case: the ESRemove follows the same principle according to the spec...
		case GF_ODF_ESD_REMOVE_REF_TAG:
			//both commands have the same structure, only the tags change
			esdR = (GF_ESDRemove *) com;
			esdR2 = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG);
			esdR2->ODID = esdR->ODID;
			esdR2->NbESDs = 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;
			}
			skipped = 0;
			//get the ES_ID in the mpod indicated in the ES_ID[]
			for (i = 0; i < esdR->NbESDs; i++) {
				//if the ref index is not valid, remove this desc...
				if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[esdR->ES_ID[i] - 1]) == NULL) {
					skipped ++;
				} else {
					//the command in the file has the ref index of the trackID in the mpod
					esdR2->ES_ID[i - skipped] = mpod->trackIDs[esdR->ES_ID[i] - 1];
				}
			}
			//gf_realloc...
			if (skipped && (skipped != esdR2->NbESDs) ) {
				esdR2->NbESDs -= skipped;
				esdR2->ES_ID = (unsigned short*)gf_realloc(esdR2->ES_ID, sizeof(u32) * esdR2->NbESDs);
			}
			gf_odf_com_del((GF_ODCom **)&esdR);
			gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdR2);
			break;

		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
	gf_free(sample->data);
	sample->data = NULL;
	sample->dataLength = 0;
	e = gf_odf_codec_get_au(ODencode, &sample->data, &sample->dataLength);

err_exit:
	gf_odf_codec_del(ODdecode);
	gf_odf_codec_del(ODencode);
	return e;
}
Example #8
0
// 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;
}
Example #9
0
M4Err Track_SetStreamDescriptor(TrackAtom *trak, u32 StreamDescriptionIndex, u32 DataReferenceIndex, ESDescriptor *esd, u32 *outStreamIndex)
{
	M4Err e;
	MPEGSampleEntryAtom *entry;
	MPEGVisualSampleEntryAtom *entry_v;
	MPEGAudioSampleEntryAtom *entry_a;
	TrackReferenceAtom *tref;
	TrackReferenceTypeAtom *dpnd;
	u16 tmpRef;

	M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex);
	M4Err tref_AddAtom(TrackReferenceAtom *ptr, Atom *a);
	M4Err stsd_AddAtom(SampleDescriptionAtom *ptr, Atom *a);
	M4Err trak_AddAtom(TrackAtom *ptr, Atom *a);

	entry = NULL;
	tref = NULL;

	if (!trak || !esd || (!outStreamIndex && !DataReferenceIndex) ) return M4BadParam;
	if (!Track_IsMPEG4Stream(trak->Media->handler->handlerType)) return M4InvalidMP4Media;

	
	esd->ESID = 0;
	//set SL to predefined if no url
	if (esd->URLString == NULL) {
		esd->slConfig->predefined = SLPredef_MP4;
		esd->slConfig->durationFlag = 0;
		esd->slConfig->useTimestampsFlag = 1;
	}

	//get the REF atom if needed
	if (esd->dependsOnESID  || esd->OCRESID ) {
		if (!trak->References) {
			tref = (TrackReferenceAtom *) CreateAtom(TrackReferenceAtomType);
			e = trak_AddAtom(trak, (Atom *)tref);
			if (e) return e;
		}
		tref = trak->References;
	}

	//Update Stream dependancies
	e = Track_FindRef(trak, M4_StreamDependence_Ref, &dpnd);
	if (e) return e;
	if (!dpnd && esd->dependsOnESID) {
		dpnd = (TrackReferenceTypeAtom *) CreateAtom(StreamDependenceAtomType);
		e = tref_AddAtom(tref, (Atom *) dpnd);
		if (e) return e;
		e = reftype_AddRefTrack(dpnd, esd->dependsOnESID, NULL);
		if (e) return e;
	} else if (dpnd && !esd->dependsOnESID) {
		Track_RemoveRef(trak, StreamDependenceAtomType);
	}
	esd->dependsOnESID = 0;

	//Update Clock dependancies
	e = Track_FindRef(trak, M4_OCR_Ref, &dpnd);
	if (e) return e;
	if (!dpnd && esd->OCRESID) {
		dpnd = (TrackReferenceTypeAtom *) CreateAtom(OCRReferenceAtomType);
		e = tref_AddAtom(tref, (Atom *) dpnd);
		if (e) return e;
		e = reftype_AddRefTrack(dpnd, esd->OCRESID, NULL);
		if (e) return e;
	} else if (dpnd && !esd->OCRESID) {
		Track_RemoveRef(trak, OCRReferenceAtomType);
	} else if (dpnd && esd->OCRESID) {
		if (dpnd->trackIDCount != 1) return M4InvalidMP4Media;
		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, M4_IPI_Ref, &dpnd);
		if (e) return e;
		if (!dpnd) {
			tmpRef = 0;
			dpnd = (TrackReferenceTypeAtom *) CreateAtom(IPIReferenceAtomType);
			e = tref_AddAtom(tref, (Atom *) 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 = IPI_DescPtr_Tag;
		} else {
			//Watch out! ONLY ONE IPI dependancy is allowed per stream
			if (dpnd->trackIDCount != 1) return M4InvalidMP4Media;
			//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 = IPI_DescPtr_Tag;
		}
	}

	//we have a streamDescritpionIndex, use it
	if (StreamDescriptionIndex) {
		entry = (MPEGSampleEntryAtom*)ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, StreamDescriptionIndex - 1);
		if (!entry) return M4InvalidMP4File;

		switch (entry->type) {
		case MPEGSampleEntryAtomType:
			//OK, delete the previous ESD
			e = OD_DeleteDescriptor((Descriptor **) &entry->esd->desc);
			if (e) return e;
			entry->esd->desc = esd;
			break;
		case MPEGVisualSampleEntryAtomType:
			entry_v = (MPEGVisualSampleEntryAtom*) entry;
			//OK, delete the previous ESD
			e = OD_DeleteDescriptor((Descriptor **) &entry_v->esd->desc);
			if (e) return e;
			entry_v->esd->desc = esd;
			break;
		case MPEGAudioSampleEntryAtomType:
			entry_a = (MPEGAudioSampleEntryAtom*) entry;
			//OK, delete the previous ESD
			e = OD_DeleteDescriptor((Descriptor **) &entry_a->esd->desc);
			if (e) return e;
			entry_a->esd->desc = esd;
			break;
		}
	} else {
		//need to check we're not in URL mode where only ONE description is allowed...
		StreamDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
		if (StreamDescriptionIndex) {
			entry = (MPEGSampleEntryAtom*)ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, StreamDescriptionIndex - 1);
			if (!entry) return M4InvalidMP4File;
			if (entry->esd->desc->URLString) return M4BadParam;
		}

		//OK, check the handler and create the entry
		switch (trak->Media->handler->handlerType) {
		case M4_VisualMediaType:
			entry_v = (MPEGVisualSampleEntryAtom *) CreateAtom(MPEGVisualSampleEntryAtomType);
			if (!entry_v) return M4OutOfMem;
			//create an esdAtom
			entry_v->esd = (ESDAtom *) CreateAtom(ESDAtomType);
			entry_v->esd->desc = esd;

			//type cast possible now
			entry = (MPEGSampleEntryAtom*) entry_v;
			break;
		case M4_AudioMediaType:
			entry_a = (MPEGAudioSampleEntryAtom *) CreateAtom(MPEGAudioSampleEntryAtomType);
			entry_a->samplerate_hi = trak->Media->mediaHeader->timeScale;
			if (!entry_a) return M4OutOfMem;
			//create an esdAtom
			entry_a->esd = (ESDAtom *) CreateAtom(ESDAtomType);
			entry_a->esd->desc = esd;
			//type cast possible now
			entry = (MPEGSampleEntryAtom*) entry_a;
			break;
		case M4_ODMediaType:
		case M4_OCRMediaType:
		case M4_BIFSMediaType:
		case M4_MPEG7MediaType:
		case M4_OCIMediaType:
		case M4_IPMPMediaType:
		case M4_MPEGJMediaType:
			entry = (MPEGSampleEntryAtom *) CreateAtom(MPEGSampleEntryAtomType);
			//create an esdAtom
			entry->esd = (ESDAtom *) CreateAtom(ESDAtomType);
			entry->esd->desc = esd;
			break;
		}
		entry->dataReferenceIndex = DataReferenceIndex;

		//and add the entry to our table...
		e = stsd_AddAtom(trak->Media->information->sampleTable->SampleDescription, (Atom *) entry);
		if (e) return e;
		if(outStreamIndex) *outStreamIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
	}
	return M4OK;
}
Example #10
0
// Update the dependancies when an OD AU is inserted in the file
M4Err Media_ParseODFrame(MediaAtom *mdia, M4Sample *sample)
{
	TrackReferenceAtom *tref;
	TrackReferenceTypeAtom *mpod;
	M4Err e;
	ODCommand *com;
	LPODCODEC ODencode;
	LPODCODEC ODdecode;
	u32 i, j;

	//the commands we proceed
	ESDescriptorUpdate *esdU, *esdU2;
	ESDescriptorRemove *esdR, *esdR2;
	ObjectDescriptorUpdate *odU, *odU2;

	//the desc they contain
	ObjectDescriptor *od;
	M4F_ObjectDescriptor *m4_od;
	ESDescriptor *esd;
	ES_ID_Ref *ref;
	Descriptor *desc;
	M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex);
	M4Err trak_AddAtom(TrackAtom *ptr, Atom *a);
	M4Err tref_AddAtom(TrackReferenceAtom *ptr, Atom *a);

	if (!mdia || !sample || !sample->data || !sample->dataLength) return M4BadParam;

	//First find the references, and create them if none
	tref = mdia->mediaTrack->References;
	if (!tref) {
		tref = (TrackReferenceAtom *) CreateAtom(TrackReferenceAtomType);
		e = trak_AddAtom(mdia->mediaTrack, (Atom *) tref);
		if (e) return e;
	}
	//then find the OD reference, and create it if none
	e = Track_FindRef(mdia->mediaTrack, ODTrackReferenceAtomType, &mpod);
	if (e) return e;
	if (!mpod) {
		mpod = (TrackReferenceTypeAtom *) CreateAtom(ODTrackReferenceAtomType);
		e = tref_AddAtom(tref, (Atom *)mpod);
		if (e) return e;
	}

	//OK, create our codecs
	ODencode = OD_NewCodec(OD_WRITE);
	if (!ODencode) return M4OutOfMem;
	ODdecode = OD_NewCodec(OD_READ);
	if (!ODdecode) return M4OutOfMem;

	e = OD_SetBuffer(ODdecode, sample->data, sample->dataLength);
	if (e) goto err_exit;
	e = OD_DecodeAU(ODdecode);
	if (e) goto err_exit;

	while (1) {
		com = OD_GetCommand(ODdecode);
		if (!com) break;

		//check our commands
		switch (com->tag) {
		//Rewrite OD Update
		case ODUpdate_Tag:
			//duplicate our command
			odU = (ObjectDescriptorUpdate *) com;
			odU2 = (ObjectDescriptorUpdate *) OD_NewCommand(ODUpdate_Tag);

			for (i = 0; i < ChainGetCount(odU->objectDescriptors); i++) {
				desc = (Descriptor*)ChainGetEntry(odU->objectDescriptors, i);
				//both OD and IODs are accepted
				switch (desc->tag) {
				case ObjectDescriptor_Tag:
				case InitialObjectDescriptor_Tag:
					break;
				default:
					e = M4InvalidDescriptor;
					goto err_exit;
				}
				//get the esd
				e = OD_DuplicateDescriptor(desc, (Descriptor **)&od);
				if (e) goto err_exit;
				if (desc->tag == ObjectDescriptor_Tag) {
					m4_od = (M4F_ObjectDescriptor *) malloc(sizeof(M4F_ObjectDescriptor));
					m4_od->tag = MP4_OD_Tag;
				} else {
					m4_od = (M4F_ObjectDescriptor *) malloc(sizeof(M4F_InitialObjectDescriptor));
					m4_od->tag = MP4_IOD_Tag;
					//copy PL
					((M4F_InitialObjectDescriptor *)m4_od)->inlineProfileFlag = ((InitialObjectDescriptor *)od)->inlineProfileFlag;
					((M4F_InitialObjectDescriptor *)m4_od)->graphics_profileAndLevel = ((InitialObjectDescriptor *)od)->graphics_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->audio_profileAndLevel = ((InitialObjectDescriptor *)od)->audio_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->OD_profileAndLevel = ((InitialObjectDescriptor *)od)->OD_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->scene_profileAndLevel = ((InitialObjectDescriptor *)od)->scene_profileAndLevel;
					((M4F_InitialObjectDescriptor *)m4_od)->visual_profileAndLevel = ((InitialObjectDescriptor *)od)->visual_profileAndLevel;
				}
				//in OD stream only ref desc are accepted
				m4_od->ES_ID_RefDescriptors = NewChain();
				m4_od->ES_ID_IncDescriptors = NULL;
	
				//TO DO: check that a given sampleDescription exists
				m4_od->extensionDescriptors = od->extensionDescriptors;
				od->extensionDescriptors = NULL;
				m4_od->IPMPDescriptorPointers = od->IPMPDescriptorPointers;
				od->IPMPDescriptorPointers = NULL;
				m4_od->OCIDescriptors = od->OCIDescriptors;
				od->OCIDescriptors = NULL;
				m4_od->URLString = od->URLString;
				od->URLString = NULL;
				m4_od->objectDescriptorID = od->objectDescriptorID;

				for (j = 0; j < ChainGetCount(od->ESDescriptors); j++) {
					esd =(ESDescriptor*)ChainGetEntry(od->ESDescriptors, j);
					ref = (ES_ID_Ref *) OD_NewDescriptor(ES_ID_RefTag);
					//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 = OD_AddDescToDesc((Descriptor *)m4_od, (Descriptor *)ref);
					if (e) goto err_exit;
				}
				//delete our desc
				OD_DeleteDescriptor((Descriptor **)&od);
				//and add the new one to our command
				ChainAddEntry(odU2->objectDescriptors, m4_od);
			}
			//delete the command
			OD_DeleteCommand((ODCommand **)&odU);
			//and add the new one to the codec
			OD_AddCommand(ODencode, (ODCommand *)odU2);
			break;

		//Rewrite ESD Update
		case ESDUpdate_Tag:
			esdU = (ESDescriptorUpdate *) com;
			esdU2 = (ESDescriptorUpdate *) OD_NewCommand(ESDUpdate_Tag);
			esdU2->ODID = esdU->ODID;
			for (i = 0; i< ChainGetCount(esdU->ESDescriptors); i++) {
				esd = (ESDescriptor*)ChainGetEntry(esdU->ESDescriptors, i);
				ref = (ES_ID_Ref *) OD_NewDescriptor(ES_ID_RefTag);
				//1 to 1 mapping trackID and ESID
				e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef);
				e = ChainAddEntry(esdU2->ESDescriptors, ref);
				if (e) goto err_exit;
			}
			OD_DeleteCommand((ODCommand **)&esdU);
			OD_AddCommand(ODencode, (ODCommand *)esdU2);
			break;

		//Brand new case: the ESRemove has to be rewritten too according to the specs...
		case ESDRemove_Tag:
			esdR = (ESDescriptorRemove *) com;
			esdR2 = (ESDescriptorRemove *) OD_NewCommand(ESDRemove_Tag);
			//change the tag for the file format
			esdR2->tag = ESDRemove_Ref_Tag;
			esdR2->ODID = esdR->ODID;
			esdR2->NbESDs = esdR->NbESDs;
			//alloc our stuff
			esdR2->ES_ID = (unsigned short*)malloc(sizeof(u32) * esdR->NbESDs);
			if (!esdR2->ES_ID) {
				e = M4OutOfMem;
				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;
			}
			OD_DeleteCommand(&com);
			OD_AddCommand(ODencode, (ODCommand *)esdR2);
			break;

		//Add the command as is
		default:
			e = OD_AddCommand(ODencode, com);
			if (e) goto err_exit;
		}
	}

	//encode our new AU
	e = OD_EncodeAU(ODencode);
	if (e) goto err_exit;

	//and set the buffer in the sample
	free(sample->data);
	sample->data = NULL;
	sample->dataLength = 0;
	e = OD_GetEncodedAU(ODencode, &sample->data, &sample->dataLength);

err_exit:

	OD_DeleteCodec(ODencode);
	OD_DeleteCodec(ODdecode);
	return e;
}
Example #11
0
M4Err M4H_SetupHintTrack(M4File *the_file, u32 trackNumber, u32 HintType)
{
	M4Err e;
	TrackAtom *trak;
	TrackReferenceAtom *tref;
	TrackReferenceTypeAtom *dpnd;
	HintMediaHeaderAtom *hmhd;
	//UDTA related ...
	UserDataAtom *udta;

	M4Err tref_AddAtom(TrackReferenceAtom *ptr, Atom *a);
	M4Err trak_AddAtom(TrackAtom *ptr, Atom *a);
	M4Err moov_AddAtom(MovieAtom *ptr, Atom *a);
	M4Err udta_AddAtom(UserDataAtom *ptr, Atom *a);

	//what do we support
	switch (HintType) {
	case M4_Hint_RTP:
		break;
	default:
		return M4NotSupported;
	}

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak) return M4_GetLastError(the_file);
	if (((M4Movie *)the_file)->openMode != M4_OPEN_EDIT) return M4InvalidMP4Mode;

	//check we have a hint ...
	if ( !IsHintTrack(trak)) {
		return M4BadParam;
	}
	hmhd = (HintMediaHeaderAtom *)trak->Media->information->InfoHeader;
	//make sure the subtype was not already defined
	if (hmhd->subType) return M4HintPresent;
	//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 = (TrackReferenceAtom *) CreateAtom(TrackReferenceAtomType);
			e = trak_AddAtom(trak, (Atom *)tref);
			if (e) return e;
		}
	}
	tref = trak->References;

	//do we have a hint reference on this trak ???
	e = Track_FindRef(trak, HintTrackReferenceAtomType, &dpnd);
	if (e) return e;
	//if yes, return false (existing hint track...)
	if (dpnd) return M4HintPresent;

	//create our dep
	dpnd = (TrackReferenceTypeAtom *) CreateAtom(HintTrackReferenceAtomType);
	e = tref_AddAtom(tref, (Atom *) dpnd);
	if (e) return e;

	//for RTP, we need to do some UDTA-related stuff...
	if (HintType != M4_Hint_RTP) return M4OK;

	if (!trak->udta) {
		//create one
		udta = (UserDataAtom *) CreateAtom(UserDataAtomType);
		e = trak_AddAtom(trak, (Atom *) udta);
		if (e) return e;
	}
	udta = trak->udta;
	//end-of-udta marker for Darwin...
//	if (!udta->voidAtom) {
//		e = udta_AddAtom(udta, CreateAtom(VoidAtomType));
//		if (e) return e;
//	}

	//HNTI
	e = udta_AddAtom(udta, CreateAtom(HintTrackInfoAtomType));
	if (e) return e;

/*
	//NAME
	e = udta_AddAtom(udta, CreateAtom(nameAtomType));
	if (e) return e;
	//HINF
	return udta_AddAtom(udta, CreateAtom(HintInfoAtomType));
*/
	return M4OK;
}
Example #12
0
M4Err M4H_AddSampleData(M4File *the_file, u32 trackNumber, u32 SourceTrackID, u32 SampleNumber, u16 DataLength, u32 offsetInSample, char *extra_data, u8 AtBegin)
{
	TrackAtom *trak;
	HintSampleEntryAtom *entry;
	u32 count;
	u16 refIndex;
	HintPacket *pck;
	SampleDTE *dte;
	M4Err e;
	TrackReferenceTypeAtom *hint;

	M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex);

	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !IsHintTrack(trak)) return M4BadParam;


	e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &count);
	if (e) return e;
	if (!entry->w_sample) return M4BadParam;
	count = ChainGetCount(entry->w_sample->packetTable);
	if (!count) return M4BadParam;
	pck = ChainGetEntry(entry->w_sample->packetTable, count - 1);

	dte = (SampleDTE *) NewDTE(2);

	dte->dataLength = DataLength;
	dte->sampleNumber = SampleNumber;
	dte->byteOffset = offsetInSample;

	//we're getting data from another track
	if (SourceTrackID != trak->Header->trackID) {
		//get (or set) the track reference index 
		e = Track_FindRef(trak, M4_HintTrack_Ref, &hint);
		if (e) return e;
		e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
		if (e) return e;
		//WARNING: IN QT, MUST BE 0-based !!!
		dte->trackRefIndex = (u8) (refIndex - 1);
	} else {
		//we're in the hint track
		dte->trackRefIndex = -1;
		//basic check...
		if (SampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount + 1) {
			DelDTE((GenericDTE *)dte);
			return M4BadParam;
		}

		//are we in the current sample ??
		if (!SampleNumber || (SampleNumber == trak->Media->information->sampleTable->SampleSize->sampleCount + 1)) {
			//we adding some stuff in the current sample ...
			dte->byteOffset += entry->w_sample->dataLength;
			if (entry->w_sample->AdditionalData) {
				entry->w_sample->AdditionalData = realloc(entry->w_sample->AdditionalData, sizeof(char) * (entry->w_sample->dataLength + DataLength));
				memcpy(entry->w_sample->AdditionalData + entry->w_sample->dataLength, extra_data, DataLength);
				entry->w_sample->dataLength += DataLength;
			} else {
				entry->w_sample->AdditionalData = malloc(sizeof(char) * DataLength);
				memcpy(entry->w_sample->AdditionalData, extra_data, DataLength);
				entry->w_sample->dataLength = DataLength;
			}
			//and set the sample number ...
			dte->sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount + 1;
		}
	}
	//OK, add the entry
	return AddDTE_HintPacket(entry->w_sample->HintType, pck, (GenericDTE *)dte, AtBegin);
}
Example #13
0
//extraction of the ESD from the track
M4Err GetESD(MovieAtom *moov, u32 trackID, u32 StreamDescIndex, ESDescriptor **outESD)
{
	M4Err e;
	ESDescriptor *esd;
	SampleTableAtom *stbl;
	TrackAtom *trak, *OCRTrack;
	TrackReferenceTypeAtom *dpnd;
	SLConfigDescriptor *slc;
	MPEGSampleEntryAtom *entry;

	dpnd = NULL;
	*outESD = NULL;

	trak = GetTrack(moov, GetTrackNumberByID(moov, trackID));
	if (!trak) return M4InvalidMP4File;

	e = Media_GetESD(trak->Media, StreamDescIndex, &esd, 0);
	if (e) return e;

	e = Media_GetSampleDesc(trak->Media, StreamDescIndex, (SampleEntryAtom **) &entry, NULL);
	if (e) return e;
	//set the ID
	esd->ESID = trackID;
	
	//find stream dependencies
	e = Track_FindRef(trak, StreamDependenceAtomType , &dpnd);
	if (e) return e;
	if (dpnd) {
		//ONLY ONE STREAM DEPENDENCY IS ALLOWED
		if (dpnd->trackIDCount != 1) return M4InvalidMP4Media;
		//fix the spec: where is the index located ??
		esd->dependsOnESID = dpnd->trackIDs[0];
	} else {
		esd->dependsOnESID = 0;
	}

	//OK, get the OCR (in a REAL MP4File, OCR is 0 in ESD and is specified through track reference
	dpnd = NULL;
	OCRTrack = NULL;
	//find OCR dependencies
	e = Track_FindRef(trak, OCRReferenceAtomType, &dpnd);
	if (e) return e;
	if (dpnd) {
		if (dpnd->trackIDCount != 1) return M4InvalidMP4Media;
		esd->OCRESID = dpnd->trackIDs[0];
		OCRTrack = GetTrackFromID(trak->moov, dpnd->trackIDs[0]);

		while (OCRTrack) {
			/*if we have a dependency on a track that doesn't have OCR dep, remove that dependency*/
			e = Track_FindRef(OCRTrack, OCRReferenceAtomType, &dpnd);
			if (e || !dpnd || !dpnd->trackIDCount) {
				OCRTrack = NULL;
				goto default_sync;
			}
			/*this is explicit desync*/
			if (dpnd && ((dpnd->trackIDs[0]==0) || (dpnd->trackIDs[0]==OCRTrack->Header->trackID))) break;
			/*loop in OCRs, break it*/
			if (esd->ESID == OCRTrack->Header->trackID) {
				OCRTrack = NULL;
				goto default_sync;
			}
			/*check next*/
			OCRTrack = GetTrackFromID(trak->moov, dpnd->trackIDs[0]);
		}
		if (!OCRTrack) goto default_sync;
	} else {
default_sync:
		/*all tracks are sync'ed by default*/
		if (trak->moov->mov->es_id_default_sync<0) {
			if (esd->OCRESID)
				trak->moov->mov->es_id_default_sync = esd->OCRESID;
			else
				trak->moov->mov->es_id_default_sync = esd->ESID;
		}
		if (trak->moov->mov->es_id_default_sync) esd->OCRESID = (u16) trak->moov->mov->es_id_default_sync;
		/*cf ESD writer*/
		if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
	}



	//update the IPI stuff if needed
	if (esd->ipiPtr != NULL) {
		dpnd = NULL;
		e = Track_FindRef(trak, IPIReferenceAtomType, &dpnd);
		if (e) return e;
		if (dpnd) {
			if (esd->ipiPtr->tag != IPI_DescPtr_Tag) return M4InvalidMP4File;
			//OK, retrieve the ID: the IPI_ES_Id is currently the ref track
			esd->ipiPtr->IPI_ES_Id = dpnd->trackIDs[esd->ipiPtr->IPI_ES_Id - 1];
			//and change the tag
			esd->ipiPtr->tag = IPIPtr_Tag;
		} else {
			return M4InvalidMP4File;
		}
	}

	/*normally all files shall be stored with predefined=SLPredef_MP4, but of course some are broken (philips)
	so we just check the ESD_URL. If set, use the given cfg, otherwise always rewrite it*/
	if (esd->URLString != NULL) {
		*outESD = esd;
		return M4OK;
	}

	//if we are in publishing mode and we have an SLConfig specified, use it as is
	switch (entry->type) {
	case MPEGVisualSampleEntryAtomType:
		slc = ((MPEGVisualSampleEntryAtom *)entry)->slc;
		break;
	case MPEGAudioSampleEntryAtomType:
		slc = ((MPEGAudioSampleEntryAtom *)entry)->slc;
		break;
	case MPEGSampleEntryAtomType:
		slc = entry->slc;
		break;
	default:
		slc = NULL;
		break;
	}
	if (slc) {
		OD_DeleteDescriptor((Descriptor **)&esd->slConfig);
		OD_DuplicateDescriptor((Descriptor *)slc, (Descriptor **)&esd->slConfig);
		*outESD = esd;
		return M4OK;
	}
	//otherwise use the regular mapping
	
	//this is a desc for a media in the file, let's rewrite some param
	esd->slConfig->timestampLength = 32;
	esd->slConfig->timestampResolution = trak->Media->mediaHeader->timeScale;
	//NO OCR from MP4File streams (eg, constant OC Res one)
	esd->slConfig->OCRLength = 0;
	if (OCRTrack) {
		esd->slConfig->OCRResolution = OCRTrack->Media->mediaHeader->timeScale;
	} else {
		esd->slConfig->OCRResolution = 0;
	}
	stbl = trak->Media->information->sampleTable;
	// a little optimization here: if all our samples are sync, 
	//set the RAPOnly to true... for external users...
	if (! stbl->SyncSample) {
		esd->slConfig->useRandomAccessUnitsOnlyFlag = 1;
		esd->slConfig->useRandomAccessPointFlag = 0;
	} else {
		esd->slConfig->useRandomAccessUnitsOnlyFlag = 0;
		//signal we are NOT using sync points if no info is present in the table
		esd->slConfig->useRandomAccessPointFlag = stbl->SyncSample->entryCount ? 1 : 0;
	}
	//do we have DegradationPriority ?
	if (stbl->DegradationPriority) {
		esd->slConfig->degradationPriorityLength = 15;
	} else {
		esd->slConfig->degradationPriorityLength = 0;
	}
	//paddingBits
	if (stbl->PaddingBits) {
		esd->slConfig->usePaddingFlag = 1;
	}
	//change to support reflecting OD streams
	esd->slConfig->useAccessUnitEndFlag = 1;
	esd->slConfig->useAccessUnitStartFlag = 1;

	//signal we do have padding flag (since we only use logical SL packet
	//the user can decide whether to use the info or not
	esd->slConfig->usePaddingFlag = stbl->PaddingBits ? 1 : 0;

	//same with degradation priority
	esd->slConfig->degradationPriorityLength = stbl->DegradationPriority ? 32 : 0;

	//this new SL will be OUT OF THE FILE. Let's set its predefined to 0
	esd->slConfig->predefined = 0;
	
	*outESD = esd;
	return M4OK;
}
Example #14
0
//extraction of the ESD from the track
GF_Err GetESD(GF_MovieBox *moov, u32 trackID, u32 StreamDescIndex, GF_ESD **outESD)
{
    GF_Err e;
    GF_ESD *esd;
    u32 track_num = 0;
    GF_SampleTableBox *stbl;
    GF_TrackBox *trak, *OCRTrack;
    GF_TrackReferenceTypeBox *dpnd;
    GF_SLConfig *slc;
    GF_MPEGSampleEntryBox *entry;

    track_num = gf_isom_get_tracknum_from_id(moov, trackID);
    dpnd = NULL;
    *outESD = NULL;

    trak = gf_isom_get_track(moov, track_num);
    if (!trak) return GF_ISOM_INVALID_FILE;

    e = Media_GetESD(trak->Media, StreamDescIndex, &esd, 0);
    if (e) return e;

    e = Media_GetSampleDesc(trak->Media, StreamDescIndex, (GF_SampleEntryBox **) &entry, NULL);
    if (e) return e;
    //set the ID
    esd->ESID = trackID;

    //find stream dependencies
    e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_DPND , &dpnd);
    if (e) return e;
    if (dpnd) {
        //ONLY ONE STREAM DEPENDENCY IS ALLOWED
        if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
        //fix the spec: where is the index located ??
        esd->dependsOnESID = dpnd->trackIDs[0];
    } else {
        esd->dependsOnESID = 0;
    }

    if (trak->udta) {
        GF_UserDataMap *map;
        u32 i = 0;
        while ((map = (GF_UserDataMap*)gf_list_enum(trak->udta->recordList, &i))) {
            if (map->boxType == GF_4CC('A','U','X','V')) {
                GF_Descriptor *d = gf_odf_desc_new(GF_ODF_AUX_VIDEO_DATA);
                gf_list_add(esd->extensionDescriptors, d);
                break;
            }
        }
    }

    //OK, get the OCR (in a REAL MP4File, OCR is 0 in ESD and is specified through track reference
    dpnd = NULL;
    OCRTrack = NULL;
    //find OCR dependencies
    e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_SYNC, &dpnd);
    if (e) return e;
    if (dpnd) {
        if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
        esd->OCRESID = dpnd->trackIDs[0];
        OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]);

        while (OCRTrack) {
            /*if we have a dependency on a track that doesn't have OCR dep, remove that dependency*/
            e = Track_FindRef(OCRTrack, GF_ISOM_BOX_TYPE_SYNC, &dpnd);
            if (e || !dpnd || !dpnd->trackIDCount) {
                OCRTrack = NULL;
                goto default_sync;
            }
            /*this is explicit desync*/
            if (dpnd && ((dpnd->trackIDs[0]==0) || (dpnd->trackIDs[0]==OCRTrack->Header->trackID))) break;
            /*loop in OCRs, break it*/
            if (esd->ESID == OCRTrack->Header->trackID) {
                OCRTrack = NULL;
                goto default_sync;
            }
            /*check next*/
            OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]);
        }
        if (!OCRTrack) goto default_sync;
    } else {
default_sync:
        /*all tracks are sync'ed by default*/
        if (trak->moov->mov->es_id_default_sync<0) {
            if (esd->OCRESID)
                trak->moov->mov->es_id_default_sync = esd->OCRESID;
            else
                trak->moov->mov->es_id_default_sync = esd->ESID;
        }
        if (trak->moov->mov->es_id_default_sync) esd->OCRESID = (u16) trak->moov->mov->es_id_default_sync;
        /*cf ESD writer*/
        if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
    }



    //update the IPI stuff if needed
    if (esd->ipiPtr != NULL) {
        dpnd = NULL;
        e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_IPIR, &dpnd);
        if (e) return e;
        if (dpnd) {
            if (esd->ipiPtr->tag != GF_ODF_ISOM_IPI_PTR_TAG) return GF_ISOM_INVALID_FILE;
            //OK, retrieve the ID: the IPI_ES_Id is currently the ref track
            esd->ipiPtr->IPI_ES_Id = dpnd->trackIDs[esd->ipiPtr->IPI_ES_Id - 1];
            //and change the tag
            esd->ipiPtr->tag = GF_ODF_IPI_PTR_TAG;
        } else {
            return GF_ISOM_INVALID_FILE;
        }
    }

    if ((trak->Media->mediaHeader->packedLanguage[0] != 'u')
            || (trak->Media->mediaHeader->packedLanguage[1] != 'n')
            || (trak->Media->mediaHeader->packedLanguage[2] != 'd') ) {
        if (!esd->langDesc) esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG);

        esd->langDesc->langCode = trak->Media->mediaHeader->packedLanguage[0];
        esd->langDesc->langCode <<= 8;
        esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[1];
        esd->langDesc->langCode <<= 8;
        esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[2];
    }


    {
        u16 rvc_predefined;
        char *rvc_cfg_data;
        const char *mime_type;
        u32 rvc_cfg_size;
        e = gf_isom_get_rvc_config(moov->mov, track_num, 1, &rvc_predefined, &rvc_cfg_data, &rvc_cfg_size, &mime_type);
        if (e==GF_OK) {
            if (rvc_predefined) {
                esd->decoderConfig->predefined_rvc_config = rvc_predefined;
            } else {
                esd->decoderConfig->rvc_config = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
                if (mime_type && !strcmp(mime_type, "application/rvc-config+xml+gz") ) {
#if !defined(GPAC_DISABLE_CORE_TOOLS) && !defined(GPAC_DISABLE_ZLIB)
                    gf_gz_decompress_payload(rvc_cfg_data, rvc_cfg_size, &esd->decoderConfig->rvc_config->data, &esd->decoderConfig->rvc_config->dataLength);
                    gf_free(rvc_cfg_data);
#endif
                } else {
                    esd->decoderConfig->rvc_config->data = rvc_cfg_data;
                    esd->decoderConfig->rvc_config->dataLength = rvc_cfg_size;
                }
            }
        }
    }


    /*normally all files shall be stored with predefined=SLPredef_MP4, but of course some are broken (philips)
    so we just check the ESD_URL. If set, use the given cfg, otherwise always rewrite it*/
    if (esd->URLString != NULL) {
        *outESD = esd;
        return GF_OK;
    }

    //if we are in publishing mode and we have an SLConfig specified, use it as is
    switch (entry->type) {
    case GF_ISOM_BOX_TYPE_MP4V:
        slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
        break;
    case GF_ISOM_BOX_TYPE_MP4A:
        slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
        break;
    case GF_ISOM_BOX_TYPE_MP4S:
        slc = entry->slc;
        break;
    default:
        slc = NULL;
        break;
    }
    if (slc) {
        gf_odf_desc_del((GF_Descriptor *)esd->slConfig);
        gf_odf_desc_copy((GF_Descriptor *)slc, (GF_Descriptor **)&esd->slConfig);
        *outESD = esd;
        return GF_OK;
    }
    //otherwise use the regular mapping

    //this is a desc for a media in the file, let's rewrite some param
    esd->slConfig->timestampLength = 32;
    esd->slConfig->timestampResolution = trak->Media->mediaHeader->timeScale;
    //NO OCR from MP4File streams (eg, constant OC Res one)
    esd->slConfig->OCRLength = 0;
    esd->slConfig->OCRResolution = 0;
//	if (OCRTrack) esd->slConfig->OCRResolution = OCRTrack->Media->mediaHeader->timeScale;

    stbl = trak->Media->information->sampleTable;
    // a little optimization here: if all our samples are sync,
    //set the RAPOnly to true... for external users...
    if (! stbl->SyncSample) {
        esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
        esd->slConfig->useRandomAccessPointFlag = 0;
    } else {
        esd->slConfig->hasRandomAccessUnitsOnlyFlag = 0;
        //signal we are NOT using sync points if no info is present in the table
        esd->slConfig->useRandomAccessPointFlag = stbl->SyncSample->nb_entries ? 1 : 0;
    }
    //do we have DegradationPriority ?
    if (stbl->DegradationPriority) {
        esd->slConfig->degradationPriorityLength = 15;
    } else {
        esd->slConfig->degradationPriorityLength = 0;
    }
    //paddingBits
    if (stbl->PaddingBits) {
        esd->slConfig->usePaddingFlag = 1;
    }
    //change to support reflecting OD streams
    esd->slConfig->useAccessUnitEndFlag = 1;
    esd->slConfig->useAccessUnitStartFlag = 1;

    //signal we do have padding flag (since we only use logical SL packet
    //the user can decide whether to use the info or not
    esd->slConfig->usePaddingFlag = stbl->PaddingBits ? 1 : 0;

    //same with degradation priority
    esd->slConfig->degradationPriorityLength = stbl->DegradationPriority ? 32 : 0;

    //this new SL will be OUT OF THE FILE. Let's set its predefined to 0
    esd->slConfig->predefined = 0;


    *outESD = esd;
    return GF_OK;
}
Example #15
0
// Rewrite the good dependancies when an OD AU is extracted from the file
M4Err Media_RewriteODFrame(MediaAtom *mdia, M4Sample *sample)
{
	M4Err e;
	LPODCODEC ODdecode;
	LPODCODEC ODencode;
	ODCommand *com;
	
	//the commands we proceed
	ESDescriptorUpdate *esdU, *esdU2;
	ESDescriptorRemove *esdR, *esdR2;
	ObjectDescriptorUpdate *odU, *odU2;

	//the desc they contain
	ObjectDescriptor *od;
	M4F_ObjectDescriptor *m4_od;
	ESDescriptor *esd;
	ES_ID_Ref *ref;
	Descriptor *desc;
	TrackReferenceTypeAtom *mpod;
	u32 i, j, skipped;

	if (!mdia || !sample || !sample->data || !sample->dataLength) return M4BadParam;

	mpod = NULL;
	e = Track_FindRef(mdia->mediaTrack, ODTrackReferenceAtomType, &mpod);
	if (e) return e;
	//no references, nothing to do...
	if (!mpod) return M4OK;

	ODdecode = OD_NewCodec(OD_READ);
	if (!ODdecode) return M4OutOfMem;
	ODencode = OD_NewCodec(OD_WRITE);
	if (!ODencode) {
		OD_DeleteCodec(ODdecode);
		return M4OutOfMem;
	}
	e = OD_SetBuffer(ODdecode, sample->data, sample->dataLength);
	if (e) goto err_exit;
	e = OD_DecodeAU(ODdecode);
	if (e) goto err_exit;

	while (1) {
		com = OD_GetCommand(ODdecode);
		if (!com) break;

		//we only need to rewrite commands with ESDs inside: ESDUpdate and ODUpdate
		switch (com->tag) {
		case ODUpdate_Tag:
			odU = (ObjectDescriptorUpdate *) com;
			odU2 = (ObjectDescriptorUpdate *) OD_NewCommand(ODUpdate_Tag);

			for (i = 0; i< ChainGetCount(odU->objectDescriptors); i++) {
				desc = (Descriptor*)ChainGetEntry(odU->objectDescriptors, i);
				switch (desc->tag) {
				case ObjectDescriptor_Tag:
				case MP4_OD_Tag:
				//IOD can be used in OD streams
				case MP4_IOD_Tag:
					break;
				default:
					return M4InvalidMP4File;
				}
				e = OD_DuplicateDescriptor(desc, (Descriptor **)&m4_od);
				if (e) goto err_exit;
					
				//create our OD...
				if (desc->tag == MP4_IOD_Tag) {
					od = (ObjectDescriptor *) malloc(sizeof(InitialObjectDescriptor));
				} else {
					od = (ObjectDescriptor *) malloc(sizeof(ObjectDescriptor));
				}
				if (!od) {
					e = M4OutOfMem;
					goto err_exit;
				}
				od->ESDescriptors = NewChain();
				//and duplicate...
				od->objectDescriptorID = m4_od->objectDescriptorID;
				od->tag = ObjectDescriptor_Tag;
				od->URLString = m4_od->URLString;
				m4_od->URLString = NULL;
				od->extensionDescriptors = m4_od->extensionDescriptors;
				m4_od->extensionDescriptors = NULL;
				od->IPMPDescriptorPointers = m4_od->IPMPDescriptorPointers;
				m4_od->IPMPDescriptorPointers = NULL;
				od->OCIDescriptors = m4_od->OCIDescriptors;
				m4_od->OCIDescriptors = NULL;
				
				//init as IOD
				if (m4_od->tag == MP4_IOD_Tag) {
					((InitialObjectDescriptor *)od)->audio_profileAndLevel = ((M4F_InitialObjectDescriptor *)m4_od)->audio_profileAndLevel;
					((InitialObjectDescriptor *)od)->inlineProfileFlag = ((M4F_InitialObjectDescriptor *)m4_od)->inlineProfileFlag;
					((InitialObjectDescriptor *)od)->graphics_profileAndLevel = ((M4F_InitialObjectDescriptor *)m4_od)->graphics_profileAndLevel;
					((InitialObjectDescriptor *)od)->OD_profileAndLevel = ((M4F_InitialObjectDescriptor *)m4_od)->OD_profileAndLevel;
					((InitialObjectDescriptor *)od)->scene_profileAndLevel = ((M4F_InitialObjectDescriptor *)m4_od)->scene_profileAndLevel;
					((InitialObjectDescriptor *)od)->visual_profileAndLevel = ((M4F_InitialObjectDescriptor *)m4_od)->visual_profileAndLevel;
				}
				
				//then rewrite the ESDesc
				for (j = 0; j < ChainGetCount(m4_od->ES_ID_RefDescriptors); j++) {
					ref = (ES_ID_Ref*)ChainGetEntry(m4_od->ES_ID_RefDescriptors, j);
					//if the ref index is not valid, skip this desc...
					if (!mpod->trackIDs || GetTrackFromID(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue;
					//OK, get the esd
					e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd);
					if (!e) e = OD_AddDescToDesc((Descriptor *) od, (Descriptor *) esd);
					if (e) {
						OD_DeleteDescriptor((Descriptor **)&od);
						OD_DeleteCommand((ODCommand **)&odU2);
						OD_DeleteDescriptor((Descriptor **)&m4_od);
						OD_DeleteCommand((ODCommand **)&odU);
						goto err_exit;
					}

				}
				//delete our desc
				OD_DeleteDescriptor((Descriptor **)&m4_od);
				ChainAddEntry(odU2->objectDescriptors, od);
			}
			//clean a bit
			OD_DeleteCommand((ODCommand **)&odU);
			//if no desc in the command, remove it
			if (ChainGetCount(odU2->objectDescriptors)) {
				OD_AddCommand(ODencode, (ODCommand *)odU2);
			} else {
				OD_DeleteCommand((ODCommand **)&odU2);
			}
			break;

		case ESDUpdate_Tag:
			esdU = (ESDescriptorUpdate *) com;
			esdU2 = (ESDescriptorUpdate *) OD_NewCommand(ESDUpdate_Tag);
			esdU2->ODID = esdU->ODID;
			for (i = 0; i< ChainGetCount(esdU->ESDescriptors); i++) {
				ref = (ES_ID_Ref*)ChainGetEntry(esdU->ESDescriptors, i);
				//if the ref index is not valid, skip this desc...
				if (GetTrackFromID(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue;
				//OK, get the esd
				e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd);
				if (e) goto err_exit;
				ChainAddEntry(esdU2->ESDescriptors, esd);
			}
			OD_DeleteCommand((ODCommand **)&esdU);
			//if our command is not empty, add it. Otherwise delete it...
			if (ChainGetCount(esdU2->ESDescriptors)) {
				OD_AddCommand(ODencode, (ODCommand *)esdU2);
			} else {
				OD_DeleteCommand((ODCommand **)&esdU2);
			}
			break;

		//brand new case: the ESRemove follows the same principle according to the spec...
		case ESDRemove_Ref_Tag:
			//both commands have the same structure, only the tags change
			esdR = (ESDescriptorRemove *) com;
			esdR2 = (ESDescriptorRemove *) OD_NewCommand(ESDRemove_Tag);
			esdR2->ODID = esdR->ODID;
			esdR2->NbESDs = esdR->NbESDs;
			//alloc our stuff
			esdR2->ES_ID = (unsigned short*)malloc(sizeof(u32) * esdR->NbESDs);
			if (!esdR2->ES_ID) {
				e = M4OutOfMem;
				goto err_exit;
			}
			skipped = 0;
			//get the ES_ID in the mpod indicated in the ES_ID[]
			for (i = 0; i < esdR->NbESDs; i++) {
				//if the ref index is not valid, remove this desc...
				if (GetTrackFromID(mdia->mediaTrack->moov, mpod->trackIDs[esdR->ES_ID[i] - 1]) == NULL) {
					skipped ++;
				} else {
					//the command in the file has the ref index of the trackID in the mpod
					esdR2->ES_ID[i - skipped] = mpod->trackIDs[esdR->ES_ID[i] - 1];
				}
			}
			//realloc...
			if (skipped && (skipped != esdR2->NbESDs) ) {
				esdR2->NbESDs -= skipped;
				esdR2->ES_ID = (unsigned short*)realloc(esdR2->ES_ID, sizeof(u32) * esdR2->NbESDs);
			}
			OD_DeleteCommand((ODCommand **)&esdR);
			//if empty, remove it otherwise add it
			if (skipped == esdR2->NbESDs) {
				OD_DeleteCommand((ODCommand **)&esdR2);
			} else {
				OD_AddCommand(ODencode, (ODCommand *)esdR2);
			}
			break;

		default:
			e = OD_AddCommand(ODencode, com);
			if (e) goto err_exit;
		}
	}
	//encode our new AU
	e = OD_EncodeAU(ODencode);
	if (e) goto err_exit;

	//and set the buffer in the sample
	free(sample->data);
	sample->data = NULL;
	sample->dataLength = 0;
	e = OD_GetEncodedAU(ODencode, &sample->data, &sample->dataLength);

err_exit:
	OD_DeleteCodec(ODdecode);
	OD_DeleteCodec(ODencode);
	return e;
}
Example #16
0
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;
    }
Example #17
0
/* Rewrite mode:
 * mode = 0: playback
 * mode = 1: streaming
 */
GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry)
{
	Bool is_hevc = 0;
	GF_Err e = GF_OK;
	GF_ISOSample *ref_samp;
	GF_BitStream *src_bs, *ref_bs, *dst_bs;
	u64 offset;
	u32 ref_nalu_size, data_offset, data_length, copy_size, nal_size, max_size, di, nal_unit_size_field, cur_extract_mode, extractor_mode;
	Bool rewrite_ps, rewrite_start_codes;
	u8 ref_track_ID, ref_track_num;
	s8 sample_offset, nal_type;
	u32 nal_hdr;
	char *buffer;
	GF_ISOFile *file = mdia->mediaTrack->moov->mov;

	src_bs = ref_bs = dst_bs = NULL;
	ref_samp = NULL;
	buffer = NULL;
	rewrite_ps = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ? 1 : 0;
	if (! sample->IsRAP) rewrite_ps = 0;
	rewrite_start_codes = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG) ? 1 : 0;
	extractor_mode = mdia->mediaTrack->extractor_mode&0x0000FFFF;

	if (extractor_mode == GF_ISOM_NALU_EXTRACT_INSPECT) {
		if (!rewrite_ps && !rewrite_start_codes)
			return GF_OK;
	}

	if (!entry) return GF_BAD_PARAM;
	nal_unit_size_field = 0;
	/*if svc rewrire*/
	if (entry->svc_config && entry->svc_config->config) nal_unit_size_field = entry->svc_config->config->nal_unit_size;
	/*if mvc rewrire*/

	/*otherwise do nothing*/
	else if (!rewrite_ps && !rewrite_start_codes) {
		return GF_OK;
	}

	if (!nal_unit_size_field) {
		if (entry->avc_config) nal_unit_size_field = entry->avc_config->config->nal_unit_size;
		else if (entry->hevc_config) {
			nal_unit_size_field = entry->hevc_config->config->nal_unit_size;
			is_hevc = 1;
		}
	}
	if (!nal_unit_size_field) return GF_ISOM_INVALID_FILE;

	dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
	src_bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ);
	max_size = 4096;

	/*rewrite start code with NALU delim*/
	if (rewrite_start_codes) {
		gf_bs_write_int(dst_bs, 1, 32);
		if (is_hevc) {
			gf_bs_write_int(dst_bs, 0, 1);
			gf_bs_write_int(dst_bs, GF_HEVC_NALU_ACCESS_UNIT, 6);
			gf_bs_write_int(dst_bs, 0, 9);
			/*pic-type - by default we signal all slice types possible*/
			gf_bs_write_int(dst_bs, 2, 3);
			gf_bs_write_int(dst_bs, 0, 5);
		} else {
			gf_bs_write_int(dst_bs, (sample->data[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8);
			gf_bs_write_int(dst_bs, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
		}
	}

	if (rewrite_ps) {
		if (is_hevc) {
			u32 i, count;
			count = gf_list_count(entry->hevc_config->config->param_array);
			for (i=0; i<count; i++) {
				GF_HEVCParamArray *ar = gf_list_get(entry->hevc_config->config->param_array, i);
				rewrite_nalus_list(ar->nalus, dst_bs, rewrite_start_codes, nal_unit_size_field);
			}

			/*little optimization if we are not asked to start codes: copy over the sample*/
			if (!rewrite_start_codes) {
				gf_bs_write_data(dst_bs, sample->data, sample->dataLength);
				gf_free(sample->data);
				sample->data = NULL;
				gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
				gf_bs_del(src_bs);
				gf_bs_del(dst_bs);
				return GF_OK;
			}
		} else {

			/*this is an SVC track: get all SPS/PPS from this track down to the base layer and rewrite them*/
			if (mdia->mediaTrack->has_base_layer) {
				u32 j;
				GF_List *nalu_sps = gf_list_new();
				GF_List *nalu_pps = gf_list_new();
				GF_TrackReferenceTypeBox *dpnd = NULL;
				Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &dpnd);

#if 0
				/*get all upper layers with SCAL reference to this track*/
				for (j = 0; j < gf_isom_get_track_count(file); j++) {
					if (gf_isom_has_track_reference(file, j+1, GF_ISOM_REF_SCAL, mdia->mediaTrack->Header->trackID)) {
						u32 tkID;
						GF_TrackBox *base_track;
						GF_MPEGVisualSampleEntryBox *base_entry;
						gf_isom_get_reference_ID(file, j+1, GF_ISOM_REF_SCAL, 1, &tkID);

						base_track = GetTrackbyID(mdia->mediaTrack->moov, tkID);
						base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL;
						if (base_entry)
							merge_nalus(base_entry, nalu_sps, nalu_pps);
					}
				}

#endif

				merge_nalus(entry, nalu_sps, nalu_pps);
				if (dpnd) {
					for (j=0; j<dpnd->trackIDCount; j++) {
						GF_TrackBox *base_track = GetTrackbyID(mdia->mediaTrack->moov, dpnd->trackIDs[j]);
						GF_MPEGVisualSampleEntryBox *base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL;
						if (base_entry)
							merge_nalus(base_entry, nalu_sps, nalu_pps);
					}
				}

				//rewrite nalus
				rewrite_nalus_list(nalu_sps, dst_bs, rewrite_start_codes, nal_unit_size_field);
				rewrite_nalus_list(nalu_pps, dst_bs, rewrite_start_codes, nal_unit_size_field);

				gf_list_del(nalu_sps);
				gf_list_del(nalu_pps);
			} else {

				if (entry->avc_config) {
					rewrite_nalus_list(entry->avc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
					rewrite_nalus_list(entry->avc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
					rewrite_nalus_list(entry->avc_config->config->sequenceParameterSetExtensions, dst_bs, rewrite_start_codes, nal_unit_size_field);
				}

				/*add svc config */
				if (entry->svc_config) {
					rewrite_nalus_list(entry->svc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
					rewrite_nalus_list(entry->svc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field);
				}

				/*little optimization if we are not asked to rewrite extractors or start codes: copy over the sample*/
				if (!entry->svc_config && !rewrite_start_codes) {
					gf_bs_write_data(dst_bs, sample->data, sample->dataLength);
					gf_free(sample->data);
					sample->data = NULL;
					gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
					gf_bs_del(src_bs);
					gf_bs_del(dst_bs);
					return GF_OK;
				}

			}
		}
	}

	buffer = (char *)gf_malloc(sizeof(char)*max_size);

	while (gf_bs_available(src_bs))
	{
		nal_size = gf_bs_read_int(src_bs, 8*nal_unit_size_field);
		if (nal_size>max_size) {
			buffer = (char*) gf_realloc(buffer, sizeof(char)*nal_size);
			max_size = nal_size;
		}
		if (is_hevc) {
			nal_hdr = gf_bs_read_u16(src_bs);
			nal_type = (nal_hdr&0x7E00) >> 9;
		} else {
			nal_hdr = gf_bs_read_u8(src_bs);
			nal_type = nal_hdr & 0x1F;
		}

		if (is_hevc) {
			/*we already wrote this stuff*/
			if (nal_type==GF_HEVC_NALU_ACCESS_UNIT) {
				gf_bs_skip_bytes(src_bs, nal_size-2);
				continue;
			}

			/*rewrite nal*/
			gf_bs_read_data(src_bs, buffer, nal_size-2);
			if (rewrite_start_codes)
				gf_bs_write_u32(dst_bs, 1);
			else
				gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field);

			gf_bs_write_u16(dst_bs, nal_hdr);
			gf_bs_write_data(dst_bs, buffer, nal_size-2);

			continue;
		}

		/*we already wrote this stuff*/
		if (nal_type==GF_AVC_NALU_ACCESS_UNIT) {
			gf_bs_skip_bytes(src_bs, nal_size-1);
			continue;
		}

		//extractor
		if (nal_type == 31) {
			switch (extractor_mode) {
			case 0:
				gf_bs_read_int(src_bs, 24); //3 bytes of NALUHeader in extractor
				ref_track_ID = gf_bs_read_u8(src_bs);
				sample_offset = (s8) gf_bs_read_int(src_bs, 8);
				data_offset = gf_bs_read_u32(src_bs);
				data_length = gf_bs_read_u32(src_bs);

				ref_track_num = gf_isom_get_track_by_id(file, ref_track_ID);
				if (!ref_track_num) {
					e = GF_BAD_PARAM;
					goto exit;
				}
				cur_extract_mode = gf_isom_get_nalu_extract_mode(file, ref_track_num);
				gf_isom_set_nalu_extract_mode(file, ref_track_num, GF_ISOM_NALU_EXTRACT_INSPECT);
				ref_samp = gf_isom_get_sample(file, ref_track_num, sampleNumber+sample_offset, &di);
				if (!ref_samp) {
					e = GF_IO_ERR;
					goto exit;
				}
				ref_bs = gf_bs_new(ref_samp->data, ref_samp->dataLength, GF_BITSTREAM_READ);
				offset = 0;
				while (gf_bs_available(ref_bs)) {
					if (gf_bs_get_position(ref_bs) < data_offset) {
						ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field);
						offset += ref_nalu_size + nal_unit_size_field;
						if ((offset > data_offset) || (offset >= gf_bs_get_size(ref_bs))) {
							e = GF_BAD_PARAM;
							goto exit;
						}

						e = gf_bs_seek(ref_bs, offset);
						if (e)
							goto exit;
						continue;
					}
					ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field);
					copy_size = data_length ? data_length : ref_nalu_size;
					assert(copy_size <= ref_nalu_size);
					nal_hdr = gf_bs_read_u8(ref_bs); //rewrite NAL type
					if ((copy_size-1)>max_size) {
						buffer = (char*)gf_realloc(buffer, sizeof(char)*(copy_size-1));
						max_size = copy_size-1;
					}
					gf_bs_read_data(ref_bs, buffer, copy_size-1);

					if (rewrite_start_codes)
						gf_bs_write_u32(dst_bs, 1);
					else
						gf_bs_write_int(dst_bs, copy_size, 8*nal_unit_size_field);

					gf_bs_write_u8(dst_bs, nal_hdr);
					gf_bs_write_data(dst_bs, buffer, copy_size-1);
				}

				gf_isom_sample_del(&ref_samp);
				ref_samp = NULL;
				gf_bs_del(ref_bs);
				ref_bs = NULL;
				gf_isom_set_nalu_extract_mode(file, ref_track_num, cur_extract_mode);
				break;
			default:
				//skip to end of this NALU
				gf_bs_skip_bytes(src_bs, nal_size-1);
				continue;
			}
		} else {
			gf_bs_read_data(src_bs, buffer, nal_size-1);
			if (rewrite_start_codes)
				gf_bs_write_u32(dst_bs, 1);
			else
				gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field);

			gf_bs_write_u8(dst_bs, nal_hdr);
			gf_bs_write_data(dst_bs, buffer, nal_size-1);
		}
	}