示例#1
0
BOOL CMpcAudioRenderer::ScheduleSample(IMediaSample *pMediaSample)
{
    REFERENCE_TIME		StartSample;
    REFERENCE_TIME		EndSample;

    // Is someone pulling our leg
    if (pMediaSample == NULL) {
        return FALSE;
    }

    // Get the next sample due up for rendering.  If there aren't any ready
    // then GetNextSampleTimes returns an error.  If there is one to be done
    // then it succeeds and yields the sample times. If it is due now then
    // it returns S_OK other if it's to be done when due it returns S_FALSE
    HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample);
    if (FAILED(hr)) {
        return FALSE;
    }

    // If we don't have a reference clock then we cannot set up the advise
    // time so we simply set the event indicating an image to render. This
    // will cause us to run flat out without any timing or synchronisation
    if (hr == S_OK) {
        EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent));
        return TRUE;
    }

    if (m_dRate <= 1.1) {
        ASSERT(m_dwAdvise == 0);
        ASSERT(m_pClock);
        WaitForSingleObject((HANDLE)m_RenderEvent,0);

        hr = m_pClock->AdviseTime( (REFERENCE_TIME) m_tStart, StartSample, (HEVENT)(HANDLE) m_RenderEvent, &m_dwAdvise);
        if (SUCCEEDED(hr)) {
            return TRUE;
        }
    } else {
        hr = DoRenderSample (pMediaSample);
    }

    // We could not schedule the next sample for rendering despite the fact
    // we have a valid sample here. This is a fair indication that either
    // the system clock is wrong or the time stamp for the sample is duff
    ASSERT(m_dwAdvise == 0);

    return FALSE;
}
示例#2
0
MP4Timestamp MP4Track::GetChunkTime(MP4ChunkId chunkId)
{
	u_int32_t stscIndex = GetChunkStscIndex(chunkId);

	MP4ChunkId firstChunkId = 
		m_pStscFirstChunkProperty->GetValue(stscIndex);

	MP4SampleId firstSample = 
		m_pStscFirstSampleProperty->GetValue(stscIndex);

	u_int32_t samplesPerChunk = 
		m_pStscSamplesPerChunkProperty->GetValue(stscIndex);

	MP4SampleId firstSampleInChunk = 
		firstSample + ((chunkId - firstChunkId) * samplesPerChunk);

	MP4Timestamp chunkTime;

	GetSampleTimes(firstSampleInChunk, &chunkTime, NULL);

	return chunkTime;
}
示例#3
0
u_int32_t MP4Track::GetMaxBitrate()
{
	u_int32_t timeScale = GetTimeScale();
	MP4SampleId numSamples = GetNumberOfSamples();
	u_int32_t maxBytesPerSec = 0;
	u_int32_t bytesThisSec = 0;
	MP4Timestamp thisSec = 0;

	for (MP4SampleId sid = 1; sid <= numSamples; sid++) {
		u_int32_t sampleSize;
		MP4Timestamp sampleTime;

		sampleSize = GetSampleSize(sid);

		GetSampleTimes(sid, &sampleTime, NULL);

		// sample counts for current second
		if (sampleTime < thisSec + timeScale) {
			bytesThisSec += sampleSize;
		} else { // sample is in a future second
			if (bytesThisSec > maxBytesPerSec) {
				maxBytesPerSec = bytesThisSec;
			}

			thisSec = sampleTime - (sampleTime % timeScale);
			bytesThisSec = sampleSize;
		}
	}

	// last second (or partial second) 
	if (bytesThisSec > maxBytesPerSec) {
		maxBytesPerSec = bytesThisSec;
	}

	return maxBytesPerSec * 8;
}
示例#4
0
void MP4Track::ReadSample(
	MP4SampleId sampleId,
	u_int8_t** ppBytes, 
	u_int32_t* pNumBytes, 
	MP4Timestamp* pStartTime, 
	MP4Duration* pDuration,
	MP4Duration* pRenderingOffset, 
	bool* pIsSyncSample)
{
	if (sampleId == MP4_INVALID_SAMPLE_ID) {
		throw new MP4Error("sample id can't be zero", 
			"MP4Track::ReadSample");
	}

	// handle unusual case of wanting to read a sample
	// that is still sitting in the write chunk buffer
	if (m_pChunkBuffer && sampleId >= m_writeSampleId - m_chunkSamples) {
		WriteChunkBuffer();
	}

	FILE* pFile = GetSampleFile(sampleId);

	if (pFile == (FILE*)-1) {
		throw new MP4Error("sample is located in an inaccessible file",
			"MP4Track::ReadSample");
	}

	u_int64_t fileOffset = GetSampleFileOffset(sampleId);

	u_int32_t sampleSize = GetSampleSize(sampleId);
	if (*ppBytes != NULL && *pNumBytes < sampleSize) {
		throw new MP4Error("sample buffer is too small",
			 "MP4Track::ReadSample");
	}
	*pNumBytes = sampleSize;

	VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(),
		printf("ReadSample: track %u id %u offset 0x"LLX" size %u (0x%x)\n",
			m_trackId, sampleId, fileOffset, *pNumBytes, *pNumBytes));

	bool bufferMalloc = false;
	if (*ppBytes == NULL) {
		*ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
		bufferMalloc = true;
	}

	u_int64_t oldPos = m_pFile->GetPosition(pFile); // only used in mode == 'w'
	try { 
		m_pFile->SetPosition(fileOffset, pFile);
		m_pFile->ReadBytes(*ppBytes, *pNumBytes, pFile);

		if (pStartTime || pDuration) {
			GetSampleTimes(sampleId, pStartTime, pDuration);

			VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(),
				printf("ReadSample:  start "LLU" duration "LLD"\n",
					(pStartTime ? *pStartTime : 0), 
					(pDuration ? *pDuration : 0)));
		}
		if (pRenderingOffset) {
			*pRenderingOffset = GetSampleRenderingOffset(sampleId);

			VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(),
				printf("ReadSample:  renderingOffset "LLD"\n",
					*pRenderingOffset));
		}
		if (pIsSyncSample) {
			*pIsSyncSample = IsSyncSample(sampleId);

			VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(),
				printf("ReadSample:  isSyncSample %u\n",
					*pIsSyncSample));
		}
	}

	catch (MP4Error* e) {
		if (bufferMalloc) {
			// let's not leak memory
			MP4Free(*ppBytes);
			*ppBytes = NULL;
		}
		if (m_pFile->GetMode() == 'w') {
			m_pFile->SetPosition(oldPos, pFile);
		}
		throw e;
	}

	if (m_pFile->GetMode() == 'w') {
		m_pFile->SetPosition(oldPos, pFile);
	}
}
示例#5
0
MP4SampleId MP4Track::GetSampleIdFromEditTime(
	MP4Timestamp editWhen, 
	MP4Timestamp* pStartTime, 
	MP4Duration* pDuration)
{
	MP4SampleId sampleId = MP4_INVALID_SAMPLE_ID;
	u_int32_t numEdits = 0;

	if (m_pElstCountProperty) {
		numEdits = m_pElstCountProperty->GetValue();
	}

	if (numEdits) {
		MP4Duration editElapsedDuration = 0;

		for (MP4EditId editId = 1; editId <= numEdits; editId++) {
			// remember edit segment's start time (in edit timeline)
			MP4Timestamp editStartTime = 
				(MP4Timestamp)editElapsedDuration;

			// accumulate edit segment's duration
			editElapsedDuration += 
				m_pElstDurationProperty->GetValue(editId - 1);

			// calculate difference between the specified edit time
			// and the end of this edit segment
			if (editElapsedDuration - editWhen <= 0) {
				// the specified time has not yet been reached
				continue;
			}

			// 'editWhen' is within this edit segment

			// calculate the specified edit time
			// relative to just this edit segment
			MP4Duration editOffset =
				editWhen - editStartTime;

			// calculate the media (track) time that corresponds
			// to the specified edit time based on the edit list
			MP4Timestamp mediaWhen = 
				m_pElstMediaTimeProperty->GetValue(editId - 1)
				+ editOffset;

			// lookup the sample id for the media time
			sampleId = GetSampleIdFromTime(mediaWhen, false);

			// lookup the sample's media start time and duration
			MP4Timestamp sampleStartTime;
			MP4Duration sampleDuration;

			GetSampleTimes(sampleId, &sampleStartTime, &sampleDuration);

			// calculate the difference if any between when the sample
			// would naturally start and when it starts in the edit timeline 
			MP4Duration sampleStartOffset =
				mediaWhen - sampleStartTime;

			// calculate the start time for the sample in the edit time line
			MP4Timestamp editSampleStartTime =
				editWhen - MIN(editOffset, sampleStartOffset);

			MP4Duration editSampleDuration = 0;

			// calculate how long this sample lasts in the edit list timeline
			if (m_pElstRateProperty->GetValue(editId - 1) == 0) {
				// edit segment is a "dwell"
				// so sample duration is that of the edit segment
				editSampleDuration =
					m_pElstDurationProperty->GetValue(editId - 1);

			} else {
				// begin with the natural sample duration
				editSampleDuration = sampleDuration;

				// now shorten that if the edit segment starts
				// after the sample would naturally start 
				if (editOffset < sampleStartOffset) {
					editSampleDuration -= sampleStartOffset - editOffset;
				}

				// now shorten that if the edit segment ends
				// before the sample would naturally end
				if (editElapsedDuration 
				  < editSampleStartTime + sampleDuration) {
					editSampleDuration -= (editSampleStartTime + sampleDuration) 
						- editElapsedDuration;
				}
			}

			if (pStartTime) {
				*pStartTime = editSampleStartTime;
			}

			if (pDuration) {
				*pDuration = editSampleDuration;
			}

			VERBOSE_EDIT(m_pFile->GetVerbosity(),
				printf("GetSampleIdFromEditTime: when %llu "
					"sampleId %u start %llu duration %lld\n", 
					editWhen, sampleId, 
					editSampleStartTime, editSampleDuration));

			return sampleId;
		}

		throw new MP4Error("time out of range", 
			"MP4Track::GetSampleIdFromEditTime");

	} else { // no edit list
		sampleId = GetSampleIdFromTime(editWhen, false);

		if (pStartTime || pDuration) {
			GetSampleTimes(sampleId, pStartTime, pDuration);
		}
	}

	return sampleId;
}