Пример #1
0
//Get the total media duration based on the TimeToSample table
M4Err Media_SetDuration(TrackAtom *trak)
{
	ESDescriptor *esd;
	u32 DTS, DTSprev;
	u32 nbSamp = trak->Media->information->sampleTable->SampleSize->sampleCount;

	//we need to check how many samples we have. 
	// == 1 -> last sample duration == default duration
	// > 1 -> last sample duration == prev sample duration
	switch (nbSamp) {
	case 0:
		trak->Media->mediaHeader->duration = 0;
		//we have an URL stream, set duration to its max
		if (!Track_IsMPEG4Stream(trak->Media->handler->handlerType)) {
			Media_GetESD(trak->Media, 1, &esd, 1);
			if (esd && esd->URLString) trak->Media->mediaHeader->duration = -1;
		}
		return M4OK;

	case 1:
		trak->Media->mediaHeader->duration = trak->Media->mediaHeader->timeScale;
		return M4OK;

	default:
		//we assume a constant frame rate for the media and assume the last sample
		//will be hold the same time as the prev one
		stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp, &DTS);
		stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp-1, &DTSprev);
		trak->Media->mediaHeader->duration = DTS + (DTS - DTSprev);
		return M4OK;
	}
}
Пример #2
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;
}
Пример #3
0
//Get the total media duration based on the TimeToSample table
GF_Err Media_SetDuration(GF_TrackBox *trak)
{
	GF_ESD *esd;
	u64 DTS;
	GF_SttsEntry *ent;
	u32 nbSamp = trak->Media->information->sampleTable->SampleSize->sampleCount;

	//we need to check how many samples we have. 
	// == 1 -> last sample duration == default duration
	// > 1 -> last sample duration == prev sample duration
	switch (nbSamp) {
	case 0:
		trak->Media->mediaHeader->duration = 0;
		if (Track_IsMPEG4Stream(trak->Media->handler->handlerType)) {
			Media_GetESD(trak->Media, 1, &esd, 1);
			if (esd && esd->URLString) trak->Media->mediaHeader->duration = (u64) -1;
		}
		return GF_OK;

//	case 1:
//		trak->Media->mediaHeader->duration = trak->Media->mediaHeader->timeScale;
//		return GF_OK;

	default:
		//we assume a constant frame rate for the media and assume the last sample
		//will be hold the same time as the prev one
		stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp, &DTS);
		ent = &trak->Media->information->sampleTable->TimeToSample->entries[trak->Media->information->sampleTable->TimeToSample->nb_entries-1];
		trak->Media->mediaHeader->duration = DTS;

#if 1
		trak->Media->mediaHeader->duration += ent->sampleDelta;
#else
		if (!ent) {
			u64 DTSprev;
			stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp-1, &DTSprev);
			trak->Media->mediaHeader->duration += (DTS - DTSprev);
		} else {
#ifndef GPAC_DISABLE_ISOM_WRITE
			if (trak->moov->mov->editFileMap && trak->Media->information->sampleTable->CompositionOffset) {
				u32 count, i;
				u64 max_ts;
				GF_DttsEntry *cts_ent;
				GF_CompositionOffsetBox *ctts = trak->Media->information->sampleTable->CompositionOffset;
				if (ctts->w_LastSampleNumber==nbSamp) {
					count = gf_list_count(ctts->entryList);
					max_ts = trak->Media->mediaHeader->duration;
					while (count) {
						count -= 1;
						cts_ent = gf_list_get(ctts->entryList, count);
						if (nbSamp<cts_ent->sampleCount) break;

						for (i=0; i<cts_ent->sampleCount; i++) {
							stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp-i, &DTS);
							if ((s32) cts_ent->decodingOffset < 0) max_ts = DTS;
							else max_ts = DTS + cts_ent->decodingOffset;
							if (max_ts>=trak->Media->mediaHeader->duration) {
								trak->Media->mediaHeader->duration = max_ts;
							} else {
								break;
							}
						}
						if (max_ts<trak->Media->mediaHeader->duration) {
							break;
						}
						nbSamp-=cts_ent->sampleCount;
					}
				}
			}
#endif /*GPAC_DISABLE_ISOM_WRITE*/
			trak->Media->mediaHeader->duration += ent->sampleDelta;
		}
#endif
		return GF_OK;
	}
}
Пример #4
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;
}