Exemplo n.º 1
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;
}
Exemplo n.º 2
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;
}