Exemple #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;
	}
}
Exemple #2
0
M4Err Media_UpdateSampleReference(MediaAtom *mdia, u32 sampleNumber, M4Sample *sample, u64 data_offset)
{
	M4Err e;
	u32 drefIndex, DTS, chunkNum, descIndex;
	u64 off;
	u8 isEdited;
	DataEntryURLAtom *Dentry;
	SampleTableAtom *stbl;
	M4Err stbl_AddAtom(SampleTableAtom *ptr, Atom *a);

	if (!mdia) return M4BadParam;
	stbl = mdia->information->sampleTable;

	//check we have the sampe dts
	e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
	if (e) return e;
	if (DTS != sample->DTS) return M4BadParam;

	//get our infos
	stbl_GetSampleInfos(stbl, sampleNumber, &off, &chunkNum, &descIndex, &isEdited);

	//then check the data ref
	e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
	if (e) return e;
	Dentry = (DataEntryURLAtom*)ChainGetEntry(mdia->information->dataInformation->dref->atomList, drefIndex - 1);
	if (!Dentry) return M4InvalidMP4File;

	//we only modify self-contained data
	if (Dentry->flags == 1) return M4InvalidMP4Mode;

	//and we don't modify the media data
	return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, data_offset, sample->IsRAP);
}
Exemple #3
0
GF_Err Media_UpdateSampleReference(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
{
	GF_Err e;
	u32 drefIndex, chunkNum, descIndex;
	u64 off, DTS;
	u8 isEdited;
	GF_DataEntryURLBox *Dentry;
	GF_SampleTableBox *stbl;

	if (!mdia) return GF_BAD_PARAM;
	stbl = mdia->information->sampleTable;

	//check we have the sampe dts
	e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
	if (e) return e;
	if (DTS != sample->DTS) return GF_BAD_PARAM;

	//get our infos
	stbl_GetSampleInfos(stbl, sampleNumber, &off, &chunkNum, &descIndex, &isEdited);

	//then check the data ref
	e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
	if (e) return e;
	Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->other_boxes, drefIndex - 1);
	if (!Dentry) return GF_ISOM_INVALID_FILE;

	//we only modify self-contained data
	if (Dentry->flags == 1) return GF_ISOM_INVALID_MODE;

	//and we don't modify the media data
	return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, data_offset, sample->IsRAP);
}
Exemple #4
0
GF_Err Media_UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
{
	GF_Err e;
	u32 drefIndex, chunkNum, descIndex;
	u64 newOffset, DTS;
	u8 isEdited;
	GF_DataEntryURLBox *Dentry;
	GF_SampleTableBox *stbl;

	if (!mdia || !sample || !sampleNumber || !mdia->mediaTrack->moov->mov->editFileMap)
		return GF_BAD_PARAM;
	
	stbl = mdia->information->sampleTable;

	if (!data_only) {
		//check we have the sampe dts
		e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
		if (e) return e;
		if (DTS != sample->DTS) return GF_BAD_PARAM;
	}

	//get our infos
	stbl_GetSampleInfos(stbl, sampleNumber, &newOffset, &chunkNum, &descIndex, &isEdited);

	//then check the data ref
	e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
	if (e) return e;
	Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->other_boxes, drefIndex - 1);
	if (!Dentry) return GF_ISOM_INVALID_FILE;

	if (Dentry->flags != 1) return GF_BAD_PARAM;

	//MEDIA DATA EDIT: write this new sample to the edit temp file
	newOffset = gf_isom_datamap_get_offset(mdia->mediaTrack->moov->mov->editFileMap);
	if (sample->dataLength) {
		e = gf_isom_datamap_add_data(mdia->mediaTrack->moov->mov->editFileMap, sample->data, sample->dataLength);
		if (e) return e;
	}

	if (data_only) {
		stbl_SetSampleSize(stbl->SampleSize, sampleNumber, sample->dataLength);
		return stbl_SetChunkOffset(mdia, sampleNumber, newOffset);
	}
	return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, newOffset, sample->IsRAP);
}
Exemple #5
0
M4Err Media_UpdateSample(MediaAtom *mdia, u32 sampleNumber, M4Sample *sample)
{
	M4Err e;
	u32 drefIndex, chunkNum, descIndex, DTS;
	u64 newOffset;
	u8 isEdited;
	DataEntryURLAtom *Dentry;
	SampleTableAtom *stbl;

	M4Err stbl_AddAtom(SampleTableAtom *ptr, Atom *a);

	if (!mdia || !sample || !sampleNumber || !mdia->mediaTrack->moov->mov->editFileMap)
		return M4BadParam;
	
	stbl = mdia->information->sampleTable;

	//check we have the sampe dts
	e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
	if (e) return e;
	if (DTS != sample->DTS) return M4BadParam;

	//get our infos
	stbl_GetSampleInfos(stbl, sampleNumber, &newOffset, &chunkNum, &descIndex, &isEdited);

	//then check the data ref
	e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
	if (e) return e;
	Dentry = (DataEntryURLAtom*)ChainGetEntry(mdia->information->dataInformation->dref->atomList, drefIndex - 1);
	if (!Dentry) return M4InvalidMP4File;

	if (Dentry->flags != 1) return M4BadParam;

	//MEDIA DATA EDIT: write this new sample to the edit temp file
	newOffset = DataMap_GetTotalOffset(mdia->mediaTrack->moov->mov->editFileMap);
	e = DataMap_AddData(mdia->mediaTrack->moov->mov->editFileMap, sample->data, sample->dataLength);
	if (e) return e;

	return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, newOffset, sample->IsRAP);
}
Exemple #6
0
//WARNING: MOVIETIME IS EXPRESSED IN MEDIA TS
GF_Err GetMediaTime(GF_TrackBox *trak, Bool force_non_empty, u64 movieTime, u64 *MediaTime, s64 *SegmentStartTime, s64 *MediaOffset, u8 *useEdit, u64 *next_edit_start_plus_one)
{
#if 0
    GF_Err e;
    u32 sampleNumber, prevSampleNumber;
    u64 firstDTS;
#endif
    u32 i, count;
    Bool last_is_empty = 0;
    u64 time, lastSampleTime;
    s64 mtime;
    GF_EdtsEntry *ent;
    Double scale_ts;
    GF_SampleTableBox *stbl = trak->Media->information->sampleTable;

    if (next_edit_start_plus_one) *next_edit_start_plus_one = 0;
    *useEdit = 1;
    *MediaTime = 0;
    //no segment yet...
    *SegmentStartTime = -1;
    *MediaOffset = -1;
    if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale || !stbl->SampleSize) {
        return GF_ISOM_INVALID_FILE;
    }

    //no samples...
    if (!stbl->SampleSize->sampleCount) {
        lastSampleTime = 0;
    } else {
        lastSampleTime = trak->Media->mediaHeader->duration;
    }

    //No edits, 1 to 1 mapping
    if (! trak->editBox || !trak->editBox->editList) {
        *MediaTime = movieTime;
        //check this is in our media time line
        if ((*MediaTime > lastSampleTime)
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
                && !trak->moov->mov->moof
#endif
           ) {
            *MediaTime = lastSampleTime;
        }
        *useEdit = 0;
        return GF_OK;
    }
    //browse the edit list and get the time
    scale_ts = trak->Media->mediaHeader->timeScale;
    scale_ts /= trak->moov->mvhd->timeScale;

    time = 0;
    ent = NULL;
    count=gf_list_count(trak->editBox->editList->entryList);
    for (i=0; i<count; i++) {
        ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, i);
        if ( (time + ent->segmentDuration) * scale_ts > movieTime) {
            if (!force_non_empty || (ent->mediaTime >= 0)) {
                if (next_edit_start_plus_one) *next_edit_start_plus_one = 1 + (u64) ((time + ent->segmentDuration) * scale_ts);
                goto ent_found;
            }
        }
        time += ent->segmentDuration;
        last_is_empty = ent->segmentDuration ? 0 : 1;
    }

    if (last_is_empty) {
        ent = (GF_EdtsEntry *)gf_list_last(trak->editBox->editList->entryList);
        if (ent->mediaRate==1) {
            *MediaTime = movieTime + ent->mediaTime;
        } else {
            ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, 0);
            if (ent->mediaRate==-1) {
                u64 dur = (u64) (ent->segmentDuration * scale_ts);
                *MediaTime = (movieTime > dur) ? (movieTime-dur) : 0;
            }
        }
        *useEdit = 0;
        return GF_OK;
    }


    //we had nothing in the list (strange file but compliant...)
    //return the 1 to 1 mapped vale of the last media sample
    if (!ent) {
        *MediaTime = movieTime;
        //check this is in our media time line
        if (*MediaTime > lastSampleTime) *MediaTime = lastSampleTime;
        *useEdit = 0;
        return GF_OK;
    }
    //request for a bigger time that what we can give: return the last sample (undefined behavior...)
    *MediaTime = lastSampleTime;
    return GF_OK;

ent_found:
    //OK, we found our entry, set the SegmentTime
    *SegmentStartTime = time;

    //we request an empty list, there's no media here...
    if (ent->mediaTime < 0) {
        *MediaTime = 0;
        return GF_OK;
    }
    //we request a dwell edit
    if (! ent->mediaRate) {
        *MediaTime = ent->mediaTime;
        //no media offset
        *MediaOffset = 0;
        *useEdit = 2;
        return GF_OK;
    }

    /*WARNING: this can be "-1" when doing searchForward mode (to prevent jumping to next entry)*/
    mtime = ent->mediaTime + movieTime - (time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale);
    if (mtime<0) mtime = 0;
    *MediaTime = (u64) mtime;
    *MediaOffset = ent->mediaTime;

#if 0
    //
    //Sanity check: is the requested time valid ? This is to cope with wrong EditLists
    //we have the translated time, but we need to make sure we have a sample at this time ...
    //we have to find a COMPOSITION time
    e = findEntryForTime(stbl, (u32) *MediaTime, 1, &sampleNumber, &prevSampleNumber);
    if (e) return e;

    //first case: our time is after the last sample DTS (it's a broken editList somehow)
    //set the media time to the last sample
    if (!sampleNumber && !prevSampleNumber) {
        *MediaTime = lastSampleTime;
        return GF_OK;
    }
    //get the appropriated sample
    if (!sampleNumber) sampleNumber = prevSampleNumber;

    stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
    CTS = 0;
    if (stbl->CompositionOffset) stbl_GetSampleCTS(stbl->CompositionOffset, sampleNumber, &CTS);

    //now get the entry sample (the entry time gives the CTS, and we need the DTS
    e = findEntryForTime(stbl, (u32) ent->mediaTime, 0, &sampleNumber, &prevSampleNumber);
    if (e) return e;

    //oops, the mediaTime indicates a sample that is not in our media !
    if (!sampleNumber && !prevSampleNumber) {
        *MediaTime = lastSampleTime;
        return GF_ISOM_INVALID_FILE;
    }
    if (!sampleNumber) sampleNumber = prevSampleNumber;

    stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &firstDTS);

    //and store the "time offset" of the desired sample in this segment
    //this is weird, used to rebuild the timeStamp when reading from the track, not the
    //media ...
    *MediaOffset = firstDTS;
#endif
    return GF_OK;
}
Exemple #7
0
M4Err Media_GetSample(MediaAtom *mdia, u32 sampleNumber, M4Sample **samp, u32 *sampleDescriptionIndex, Bool no_data, u64 *out_offset)
{
	M4Err e;
	u32 bytesRead;
	u32 dataRefIndex, chunkNumber;
	u64 offset, new_size;
	u8 isEdited;
	SampleEntryAtom *entry;

	(*sampleDescriptionIndex) = 0;
	
	if (!mdia || !mdia->information->sampleTable) return M4BadParam;

	//OK, here we go....
	if (sampleNumber > mdia->information->sampleTable->SampleSize->sampleCount) return M4BadParam;

	//get the DTS
	e = stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber, &(*samp)->DTS);
	if (e) return e;
	//the CTS offset
	if (mdia->information->sampleTable->CompositionOffset) {
		e = stbl_GetSampleCTS(mdia->information->sampleTable->CompositionOffset , sampleNumber, &(*samp)->CTS_Offset);
		if (e) return e;
	} else {
		(*samp)->CTS_Offset = 0;
	}
	//the size
	e = stbl_GetSampleSize(mdia->information->sampleTable->SampleSize, sampleNumber, &(*samp)->dataLength);
	if (e) return e;
	//the RAP
	if (mdia->information->sampleTable->SyncSample) {
		e = stbl_GetSampleRAP(mdia->information->sampleTable->SyncSample, sampleNumber, &(*samp)->IsRAP, NULL, NULL);
		if (e) return e;
	} else {
		//if no SyncSample, all samples are sync (cf spec)
		(*samp)->IsRAP = 1;
	}
	/*get sync shadow*/
	if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = 2;

	//the data info
	e = stbl_GetSampleInfos(mdia->information->sampleTable, sampleNumber, &offset, &chunkNumber, sampleDescriptionIndex, &isEdited);
	if (e) return e;

	//then get the DataRef
	e = Media_GetSampleDesc(mdia, *sampleDescriptionIndex, &entry, &dataRefIndex);
	if (e) return e;

	// Open the data handler - check our mode, don't reopen in read only if this is 
	//the same entry. In other modes we have no choice because the main data map is 
	//divided into the original and the edition files
	if (mdia->mediaTrack->moov->mov->openMode == M4_OPEN_READ) {	
		//same as last call in read mode
		if (!mdia->information->dataHandler || (mdia->information->dataEntryIndex != dataRefIndex)) {
			e = DataMap_Open(mdia, dataRefIndex, isEdited);
			if (e) return e;
		}
	} else {
		e = DataMap_Open(mdia, dataRefIndex, isEdited);
		if (e) return e;
	}

	if (out_offset) *out_offset = offset;
	if (no_data) return M4OK;

	/*and finally get the data, include padding if needed*/
 	(*samp)->data = (char *) malloc(sizeof(char) * ( (*samp)->dataLength + mdia->mediaTrack->padding_bytes) );
	if (mdia->mediaTrack->padding_bytes)
		memset((*samp)->data + (*samp)->dataLength, 0, sizeof(char) * mdia->mediaTrack->padding_bytes);

	//check if we can get the sample (make sure we have enougth data...)
	new_size = BS_GetSize(mdia->information->dataHandler->bs);
	if (offset + (*samp)->dataLength > new_size) {
		//always refresh the size to avoid wrong info on http/ftp 
		new_size = BS_GetRefreshedSize(mdia->information->dataHandler->bs);
		if (offset + (*samp)->dataLength > new_size) {
			mdia->BytesMissing = offset + (*samp)->dataLength - new_size;
			return M4UncompleteFile;
		}	
	}

	bytesRead = DataMap_GetData(mdia->information->dataHandler, (*samp)->data, (*samp)->dataLength, offset);
	//if bytesRead != sampleSize, we have an IO err
	if (bytesRead < (*samp)->dataLength) {
		return M4IOErr;
	}
	mdia->BytesMissing = 0;
	//finally rewrite the sample if this is an OD Access Unit
	if (mdia->handler->handlerType == M4_ODMediaType) {
		e = Media_RewriteODFrame(mdia, *samp);
		if (e) return e;
	}
	else if (mdia->mediaTrack->moov->mov->convert_streaming_text 
		&& (mdia->handler->handlerType == M4_TimedTextMediaType) ) {
		u32 dur;
		if (sampleNumber == mdia->information->sampleTable->SampleSize->sampleCount) {
			dur = (u32) mdia->mediaHeader->duration - (*samp)->DTS;
		} else {
			stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber+1, &dur);
			dur -= (*samp)->DTS;
		}
		e = M4_RewriteTextSample(*samp, *sampleDescriptionIndex, dur);
		if (e) return e;
	}
	return M4OK;
}
Exemple #8
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;
	}
}
Exemple #9
0
GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, u32 *sIDX, Bool no_data, u64 *out_offset)
{
	GF_Err e;
	u32 bytesRead;
	u32 dataRefIndex, chunkNumber;
	u64 offset, new_size;
	u8 isEdited;
	GF_SampleEntryBox *entry;

	
	if (!mdia || !mdia->information->sampleTable) return GF_BAD_PARAM;

	//OK, here we go....
	if (sampleNumber > mdia->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;

	//get the DTS
	e = stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber, &(*samp)->DTS);
	if (e) return e;
	//the CTS offset
	if (mdia->information->sampleTable->CompositionOffset) {
		e = stbl_GetSampleCTS(mdia->information->sampleTable->CompositionOffset , sampleNumber, &(*samp)->CTS_Offset);
		if (e) return e;
	} else {
		(*samp)->CTS_Offset = 0;
	}
	//the size
	e = stbl_GetSampleSize(mdia->information->sampleTable->SampleSize, sampleNumber, &(*samp)->dataLength);
	if (e) return e;
	//the RAP
	if (mdia->information->sampleTable->SyncSample) {
		e = stbl_GetSampleRAP(mdia->information->sampleTable->SyncSample, sampleNumber, &(*samp)->IsRAP, NULL, NULL);
		if (e) return e;
	} else {
		//if no SyncSample, all samples are sync (cf spec)
		(*samp)->IsRAP = 1;
	}
	/*overwrite sync sample with sample dep if any*/
	if (mdia->information->sampleTable->SampleDep) {
		u32 dependsOn, dependedOn, redundant;
		e = stbl_GetSampleDepType(mdia->information->sampleTable->SampleDep, sampleNumber, &dependsOn, &dependedOn, &redundant);
		if (!e) {
			if (dependsOn==1) (*samp)->IsRAP = 0;
			else if (dependsOn==2) (*samp)->IsRAP = 1;
			/*if not depended upon and redundant, mark as carousel sample*/
			if ((dependedOn==2) && (redundant==1)) (*samp)->IsRAP = 2;
			/*TODO FIXME - we must enhance the IsRAP semantics to carry disposable info ... */
		}
	}
	/*get sync shadow*/
	if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = 2;

	//the data info
	if (!sIDX && !no_data) return GF_BAD_PARAM;
	if (!sIDX && !out_offset) return GF_OK;

	(*sIDX) = 0;
	e = stbl_GetSampleInfos(mdia->information->sampleTable, sampleNumber, &offset, &chunkNumber, sIDX, &isEdited);
	if (e) return e;

	//then get the DataRef
	e = Media_GetSampleDesc(mdia, *sIDX, &entry, &dataRefIndex);
	if (e) return e;

	// Open the data handler - check our mode, don't reopen in read only if this is 
	//the same entry. In other modes we have no choice because the main data map is 
	//divided into the original and the edition files
	if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) {	
		//same as last call in read mode
		if (!mdia->information->dataHandler) {
			e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited);
			if (e) return e;
		}
		if (mdia->information->dataEntryIndex != dataRefIndex)
			mdia->information->dataEntryIndex = dataRefIndex;
	} else {
		e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited);
		if (e) return e;
	}

	if (out_offset) *out_offset = offset;
	if (no_data) return GF_OK;

	/*and finally get the data, include padding if needed*/
 	(*samp)->data = (char *) gf_malloc(sizeof(char) * ( (*samp)->dataLength + mdia->mediaTrack->padding_bytes) );
	if (mdia->mediaTrack->padding_bytes)
		memset((*samp)->data + (*samp)->dataLength, 0, sizeof(char) * mdia->mediaTrack->padding_bytes);

	//check if we can get the sample (make sure we have enougth data...)
	new_size = gf_bs_get_size(mdia->information->dataHandler->bs);
	if (offset + (*samp)->dataLength > new_size) {
		//always refresh the size to avoid wrong info on http/ftp 
		new_size = gf_bs_get_refreshed_size(mdia->information->dataHandler->bs);
		if (offset + (*samp)->dataLength > new_size) {
			mdia->BytesMissing = offset + (*samp)->dataLength - new_size;
			return GF_ISOM_INCOMPLETE_FILE;
		}	
	}

	bytesRead = gf_isom_datamap_get_data(mdia->information->dataHandler, (*samp)->data, (*samp)->dataLength, offset);
	//if bytesRead != sampleSize, we have an IO err
	if (bytesRead < (*samp)->dataLength) {
		return GF_IO_ERR;
	}
	mdia->BytesMissing = 0;
	//finally rewrite the sample if this is an OD Access Unit
	if (mdia->handler->handlerType == GF_ISOM_MEDIA_OD) {
		e = Media_RewriteODFrame(mdia, *samp);
		if (e) return e;
	}
	/*FIXME: we don NOT rewrite sample if we have a encrypted track*/
	else if (gf_isom_is_nalu_based_entry(mdia, entry) && 
		!gf_isom_is_track_encrypted(mdia->mediaTrack->moov->mov, gf_isom_get_tracknum_from_id(mdia->mediaTrack->moov, mdia->mediaTrack->Header->trackID))
	) {
		e = gf_isom_nalu_sample_rewrite(mdia, *samp, sampleNumber, (GF_MPEGVisualSampleEntryBox *)entry);
		if (e) return e;
	} 
	else if (mdia->mediaTrack->moov->mov->convert_streaming_text 
		&& ((mdia->handler->handlerType == GF_ISOM_MEDIA_TEXT) || (mdia->handler->handlerType == GF_ISOM_MEDIA_SUBT)) 
		&& (entry->type == GF_ISOM_BOX_TYPE_TX3G || entry->type == GF_ISOM_BOX_TYPE_TEXT) 
	) {
		u64 dur;
		if (sampleNumber == mdia->information->sampleTable->SampleSize->sampleCount) {
			dur = mdia->mediaHeader->duration - (*samp)->DTS;
		} else {
			stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber+1, &dur);
			dur -= (*samp)->DTS;
		}
		e = gf_isom_rewrite_text_sample(*samp, *sIDX, (u32) dur);
		if (e) return e;
	}
	return GF_OK;
}
Exemple #10
0
GF_Err DoInterleave(MovieWriter *mw, GF_List *writers, GF_BitStream *bs, u8 Emulation, u64 StartOffset, Bool drift_inter)
{
	u32 i, tracksDone;
	TrackWriter *tmp, *curWriter;
	GF_Err e;
	u32 descIndex, sampSize, chunkNumber;
	u64 DTS;
	u16 curGroupID;
	u8 forceNewChunk, writeGroup, isEdited;
	//this is used to emulate the write ...
	u64 offset, sampOffset, size, mdatSize;
	u32 count;
	GF_ISOFile *movie = mw->movie;

	mdatSize = 0;

#ifdef TEST_LARGE_FILES
	if (!Emulation) {
		char *blank;
		u32 count, i;
		i = count = 0;
		blank = gf_malloc(sizeof(char)*1024*1024);
		memset(blank, 0, sizeof(char)*1024*1024);
		count = 4096;
		memset(blank, 0, sizeof(char)*1024*1024);
		while (i<count) {
			u32 res = gf_bs_write_data(bs, blank, 1024*1024);
			if (res != 1024*1024) fprintf(stdout, "error writing to disk: only %d bytes written\n", res);
			i++;
			fprintf(stdout, "writing blank block: %.02f done - %d/%d \r", (100.0*i)/count , i, count);
		}
		gf_free(blank);
	}
	mdatSize = 4096*1024;
	mdatSize *= 1024;
#endif

	/*write meta content first - WE DON'T support fragmentation of resources in ISOM atm*/
	if (movie->meta) {
		e = DoWriteMeta(movie, movie->meta, bs, Emulation, StartOffset, &size);
		if (e) return e;
		mdatSize += size;
		StartOffset += (u32) size;
	}
	if (movie->moov && movie->moov->meta) {
		e = DoWriteMeta(movie, movie->moov->meta, bs, Emulation, StartOffset, &size);
		if (e) return e;
		mdatSize += size;
		StartOffset += (u32) size;
	}
	i=0;
	while ((tmp = (TrackWriter*)gf_list_enum(writers, &i))) {
		if (tmp->mdia->mediaTrack->meta) {
			e = DoWriteMeta(movie, tmp->mdia->mediaTrack->meta, bs, Emulation, StartOffset, &size);
			if (e) return e;
			mdatSize += size;
			StartOffset += (u32) size;
		}
	}



	if (movie->storageMode == GF_ISOM_STORE_TIGHT) 
		return DoFullInterleave(mw, writers, bs, Emulation, StartOffset);

	e = GF_OK;

	curGroupID = 1;
	//we emulate a write from this offset...
	offset = StartOffset;
	writeGroup = 1;
	tracksDone = 0;

#ifdef TEST_LARGE_FILES
	offset += mdatSize;
#endif

	count = gf_list_count(writers);
	//browse each groups
	while (1) {
		/*the max DTS the chunk of the current writer*/
		u64 chunkLastDTS = 0;
		/*the timescale related to the max DTS*/
		u32 chunkLastScale = 0;

		writeGroup = 1;

		//proceed a group
		while (writeGroup) {
			curWriter = NULL;
			for (i=0 ; i < count; i++) {
				tmp = (TrackWriter*)gf_list_get(writers, i);
				
				//is it done writing ?
				if (tmp->isDone) continue;

				//is it in our group ??
				if (tmp->mdia->information->sampleTable->groupID != curGroupID) continue;

				//write till this chunk is full on this track...
				while (1) {
					//To Check: are empty sample tables allowed ???
					if (tmp->sampleNumber > tmp->mdia->information->sampleTable->SampleSize->sampleCount) {
						tmp->isDone = 1;
						tracksDone ++;
						break;
					}

					//OK, get the current sample in this track
					stbl_GetSampleDTS(tmp->mdia->information->sampleTable->TimeToSample, tmp->sampleNumber, &DTS);

					//can this sample fit in our chunk ?
					if ( ( (DTS - tmp->DTSprev) + tmp->chunkDur) *  movie->moov->mvhd->timeScale > movie->interleavingTime * tmp->timeScale
						/*drfit check: reject sample if outside our check window*/
						|| (drift_inter && chunkLastDTS && ( ((u64)tmp->DTSprev*chunkLastScale) > ((u64)chunkLastDTS*tmp->timeScale)) ) 
						) {
						//in case the sample is longer than InterleaveTime
						if (!tmp->chunkDur) {
							forceNewChunk = 1;
						} else {
							//this one is full. go to next one (exit the loop)
							tmp->chunkDur = 0;
							break;
						}
					} else {
						forceNewChunk = tmp->chunkDur ? 0 : 1;
					}
					//OK, we can write this track
					curWriter = tmp;
					
					//small check for first 2 samples (DTS = 0 :)
					if (tmp->sampleNumber == 2 && !tmp->chunkDur) forceNewChunk = 0;

					tmp->chunkDur += (u32) (DTS - tmp->DTSprev);
					tmp->DTSprev = DTS;

					e = stbl_GetSampleInfos(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, &sampOffset, &chunkNumber, &descIndex, &isEdited);
					if (e) return e;
					e = stbl_GetSampleSize(curWriter->mdia->information->sampleTable->SampleSize, curWriter->sampleNumber, &sampSize);
					if (e) return e;
					
					//do we actually write, or do we emulate ?
					if (Emulation) {
						//update our offsets...
						if (Media_IsSelfContained(curWriter->mdia, descIndex) ) {
							e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, offset, forceNewChunk);
							if (e) return e;
							offset += sampSize;
							mdatSize += sampSize;
						} else {
							if (curWriter->prev_offset != sampOffset) forceNewChunk = 1;
							curWriter->prev_offset = sampOffset + sampSize;

							//we have a DataRef, so use the offset idicated in sampleToChunk 
							//and ChunkOffset tables...
							e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, sampOffset, forceNewChunk);
							if (e) return e;
						}
					} else {
						//this is no game, we're writing ....
						if (Media_IsSelfContained(curWriter->mdia, descIndex) ) {
							e = WriteSample(mw, sampSize, sampOffset, isEdited, bs);
							if (e) return e;
						}
					}
					//ok, the sample is done
					if (curWriter->sampleNumber == curWriter->mdia->information->sampleTable->SampleSize->sampleCount) {
						curWriter->isDone = 1;
						//one more track done...
						tracksDone ++;
						break;
					} else {
						curWriter->sampleNumber ++;
					}
				}
				/*record chunk end-time & track timescale for drift-controled interleaving*/
				if (drift_inter && curWriter) {
					chunkLastScale = curWriter->timeScale;
					chunkLastDTS = curWriter->DTSprev;
					/*add one interleave window drift - since the "maxDTS" is the previously written one, we will
					have the following cases:
					- sample doesn't fit: post-pone and force new chunk 
					- sample time larger than previous chunk time + interleave: post-pone and force new chunk
					- otherwise store and track becomes current reference

					this ensures a proper drift regulation (max DTS diff is less than the interleaving window)
					*/
					chunkLastDTS += curWriter->timeScale * movie->interleavingTime / movie->moov->mvhd->timeScale;
				}
			}
			//no sample found, we're done with this group
			if (!curWriter) {
				writeGroup = 0;
				continue;
			}
		}
		//if all our track are done, break
		if (tracksDone == gf_list_count(writers)) break;
		//go to next group
		curGroupID ++;
	}
	if (movie->mdat) movie->mdat->dataSize = mdatSize;
	return GF_OK;
}
Exemple #11
0
GF_Err DoFullInterleave(MovieWriter *mw, GF_List *writers, GF_BitStream *bs, u8 Emulation, u64 StartOffset)
{

	u32 i, tracksDone;
	TrackWriter *tmp, *curWriter, *prevWriter;
	GF_Err e;
	u64 DTS, DTStmp, TStmp;
	s64 res;
	u32 descIndex, sampSize, chunkNumber;
	u16 curGroupID, curTrackPriority;
	u8 forceNewChunk, writeGroup, isEdited;
	//this is used to emulate the write ...
	u64 offset, totSize, sampOffset;
	GF_ISOFile *movie = mw->movie;
	e = GF_OK;


	totSize = 0;
	curGroupID = 1;

	prevWriter = NULL;
	//we emulate a write from this offset...
	offset = StartOffset;
	writeGroup = 1;
	tracksDone = 0;

	
	//browse each groups
	while (1) {
		writeGroup = 1;

		//proceed a group
		while (writeGroup) {
			//first get the appropriated sample for the min time in this group
			curWriter = NULL;
			DTStmp = (u64) -1;
			TStmp = 0;
			curTrackPriority = (u16) -1;

			i=0;
			while ((tmp = (TrackWriter*)gf_list_enum(writers, &i))) {

				//is it done writing ?
				//is it in our group ??
				if (tmp->isDone || tmp->mdia->information->sampleTable->groupID != curGroupID) continue;

				//OK, get the current sample in this track
				stbl_GetSampleDTS(tmp->mdia->information->sampleTable->TimeToSample, tmp->sampleNumber, &DTS);				
				res = TStmp ? DTStmp * tmp->timeScale - DTS * TStmp : 0;
				if (res < 0) continue;
				if ((!res) && curTrackPriority <= tmp->mdia->information->sampleTable->trackPriority) continue;
				curWriter = tmp;
				curTrackPriority = tmp->mdia->information->sampleTable->trackPriority;
				DTStmp = DTS;
				TStmp = tmp->timeScale;
			}
			//no sample found, we're done with this group
			if (!curWriter) {
				//we're done with the group
				curTrackPriority = 0;
				writeGroup = 0;
				continue;
			}
			//To Check: are empty sample tables allowed ???
			if (curWriter->sampleNumber > curWriter->mdia->information->sampleTable->SampleSize->sampleCount) {
				curWriter->isDone = 1;
				tracksDone ++;
				continue;
			}

			e = stbl_GetSampleInfos(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, &sampOffset, &chunkNumber, &descIndex, &isEdited);
			if (e) return e;
			e = stbl_GetSampleSize(curWriter->mdia->information->sampleTable->SampleSize, curWriter->sampleNumber, &sampSize);
			if (e) return e;
			
			//do we actually write, or do we emulate ?
			if (Emulation) {
				//are we in the same track ??? If not, force a new chunk when adding this sample
				if (curWriter != prevWriter) {
					forceNewChunk = 1;
				} else {
					forceNewChunk = 0;
				}
				//update our offsets...
				if (Media_IsSelfContained(curWriter->mdia, descIndex) ) {
					e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, offset, forceNewChunk);
					if (e) return e;
					offset += sampSize;
					totSize += sampSize;
				} else {
					if (curWriter->prev_offset != sampOffset) forceNewChunk = 1;
					curWriter->prev_offset = sampOffset + sampSize;

					//we have a DataRef, so use the offset idicated in sampleToChunk 
					//and ChunkOffset tables...
					e = stbl_SetChunkAndOffset(curWriter->mdia->information->sampleTable, curWriter->sampleNumber, descIndex, curWriter->stsc, &curWriter->stco, sampOffset, 0);
					if (e) return e;
				}
			} else {
				//this is no game, we're writing ....
				if (Media_IsSelfContained(curWriter->mdia, descIndex) ) {
					e = WriteSample(mw, sampSize, sampOffset, isEdited, bs);
					if (e) return e;
				}
			}
			//ok, the sample is done
			if (curWriter->sampleNumber == curWriter->mdia->information->sampleTable->SampleSize->sampleCount) {
				curWriter->isDone = 1;
				//one more track done...
				tracksDone ++;
			} else {
				curWriter->sampleNumber ++;
			}
			prevWriter = curWriter;
		}
		//if all our track are done, break
		if (tracksDone == gf_list_count(writers)) break;
		//go to next group
		curGroupID ++;
	}
	movie->mdat->dataSize = totSize;
	return GF_OK;
}