⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp4track.cpp

📁 AAC编解码源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		}
	}

	m_pStszSampleCountProperty->IncrementValue();
}

u_int32_t MP4Track::GetAvgBitrate()
{
	if (GetDuration() == 0) {
		return 0;
	}

	u_int64_t durationSecs =
		MP4ConvertTime(GetDuration(), GetTimeScale(), MP4_SECS_TIME_SCALE);

	if (GetDuration() % GetTimeScale() != 0) {
		durationSecs++;
	}

	return (GetTotalOfSampleSizes() * 8) / durationSecs;
}

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;
}

u_int32_t MP4Track::GetSampleStscIndex(MP4SampleId sampleId)
{
	u_int32_t stscIndex;
	u_int32_t numStscs = m_pStscCountProperty->GetValue();

	if (numStscs == 0) {
		throw new MP4Error("No data chunks exist", "GetSampleStscIndex");
	}

	for (stscIndex = 0; stscIndex < numStscs; stscIndex++) {
		if (sampleId < m_pStscFirstSampleProperty->GetValue(stscIndex)) {
			ASSERT(stscIndex != 0);
			stscIndex -= 1;
			break;
		}
	}
	if (stscIndex == numStscs) {
		ASSERT(stscIndex != 0);
		stscIndex -= 1;
	}

	return stscIndex;
}

FILE* MP4Track::GetSampleFile(MP4SampleId sampleId)
{
	u_int32_t stscIndex =
		GetSampleStscIndex(sampleId);

	u_int32_t stsdIndex = 
		m_pStscSampleDescrIndexProperty->GetValue(stscIndex);

	// check if the answer will be the same as last time
	if (m_lastStsdIndex && stsdIndex == m_lastStsdIndex) {
		return m_lastSampleFile;
	}

	MP4Atom* pStsdAtom = 
		m_pTrakAtom->FindAtom("trak.mdia.minf.stbl.stsd");
	ASSERT(pStsdAtom);

	MP4Atom* pStsdEntryAtom = 
		pStsdAtom->GetChildAtom(stsdIndex - 1);
	ASSERT(pStsdEntryAtom);

	MP4Integer16Property* pDrefIndexProperty = NULL;
	pStsdEntryAtom->FindProperty(
		"*.dataReferenceIndex",
		(MP4Property**)&pDrefIndexProperty);
	
	if (pDrefIndexProperty == NULL) {
		throw new MP4Error("invalid stsd entry", "GetSampleFile");
	}

	u_int32_t drefIndex =
		pDrefIndexProperty->GetValue();

	MP4Atom* pDrefAtom =
		m_pTrakAtom->FindAtom("trak.mdia.minf.dinf.dref");
	ASSERT(pDrefAtom);

	MP4Atom* pUrlAtom =
		pDrefAtom->GetChildAtom(drefIndex - 1);
	ASSERT(pUrlAtom);

	FILE* pFile;

	if (pUrlAtom->GetFlags() & 1) {
		pFile = NULL;	// self-contained
	} else {
#ifndef USE_FILE_CALLBACKS
		MP4StringProperty* pLocationProperty = NULL;
		pUrlAtom->FindProperty(
			"*.location", 
			(MP4Property**)&pLocationProperty);
		ASSERT(pLocationProperty);

		const char* url = pLocationProperty->GetValue();

		VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(),
			printf("dref url = %s\n", url));

		pFile = (FILE*)-1;

		// attempt to open url if it's a file url 
		// currently this is the only thing we understand
		if (!strncmp(url, "file:", 5)) {
			const char* fileName = url + 5;
			if (!strncmp(fileName, "//", 2)) {
				fileName = strchr(fileName + 2, '/');
			}
			if (fileName) {
				pFile = fopen(fileName, "rb");
				if (!pFile) {
					pFile = (FILE*)-1;
				}
			}
		} 
#else
        throw new MP4Error(errno, "Function not supported when using callbacks", "GetSampleFile");
#endif
	}

	if (m_lastSampleFile) {
#ifndef USE_FILE_CALLBACKS
		fclose(m_lastSampleFile);
#else
        throw new MP4Error(errno, "Function not supported when using callbacks", "GetSampleFile");
#endif
	}

	// cache the answer
	m_lastStsdIndex = stsdIndex;
	m_lastSampleFile = pFile;

	return pFile;
}

u_int64_t MP4Track::GetSampleFileOffset(MP4SampleId sampleId)
{
	u_int32_t stscIndex =
		GetSampleStscIndex(sampleId);

	u_int32_t firstChunk = 
		m_pStscFirstChunkProperty->GetValue(stscIndex);

	MP4SampleId firstSample = 
		m_pStscFirstSampleProperty->GetValue(stscIndex);

	u_int32_t samplesPerChunk = 
		m_pStscSamplesPerChunkProperty->GetValue(stscIndex);

	MP4ChunkId chunkId = firstChunk +
		((sampleId - firstSample) / samplesPerChunk);

	u_int64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1);

	MP4SampleId firstSampleInChunk = 
		sampleId - ((sampleId - firstSample) % samplesPerChunk);

	// need cumulative samples sizes from firstSample to sampleId - 1
	u_int32_t sampleOffset = 0;
	for (MP4SampleId i = firstSampleInChunk; i < sampleId; i++) {
		sampleOffset += GetSampleSize(i);
	}

	return chunkOffset + sampleOffset;
}

void MP4Track::UpdateSampleToChunk(MP4SampleId sampleId,
	 MP4ChunkId chunkId, u_int32_t samplesPerChunk)
{
	u_int32_t numStsc = m_pStscCountProperty->GetValue();

	// if samplesPerChunk == samplesPerChunk of last entry
	if (numStsc && samplesPerChunk == 
	  m_pStscSamplesPerChunkProperty->GetValue(numStsc-1)) {

		// nothing to do

	} else {
		// add stsc entry
		m_pStscFirstChunkProperty->AddValue(chunkId);
		m_pStscSamplesPerChunkProperty->AddValue(samplesPerChunk);
		m_pStscSampleDescrIndexProperty->AddValue(1);
		m_pStscFirstSampleProperty->AddValue(sampleId - samplesPerChunk + 1);

		m_pStscCountProperty->IncrementValue();
	}
}

void MP4Track::UpdateChunkOffsets(u_int64_t chunkOffset)
{
	if (m_pChunkOffsetProperty->GetType() == Integer32Property) {
		((MP4Integer32Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset);
	} else {
		((MP4Integer64Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset);
	}
	m_pChunkCountProperty->IncrementValue();
}

MP4Duration MP4Track::GetFixedSampleDuration()
{
	u_int32_t numStts = m_pSttsCountProperty->GetValue();

	if (numStts == 0) {
		return m_fixedSampleDuration;
	}
	if (numStts != 1) {
		return MP4_INVALID_DURATION;	// sample duration is not fixed
	}
	return m_pSttsSampleDeltaProperty->GetValue(0);
}

bool MP4Track::SetFixedSampleDuration(MP4Duration duration)
{
	u_int32_t numStts = m_pSttsCountProperty->GetValue();

	// setting this is only allowed before samples have been written
	if (numStts != 0) {
		return false;
	}
	m_fixedSampleDuration = duration;
	return true;
}

void MP4Track::GetSampleTimes(MP4SampleId sampleId,
	MP4Timestamp* pStartTime, MP4Duration* pDuration)
{
	u_int32_t numStts = m_pSttsCountProperty->GetValue();
	MP4SampleId sid = 1;
	MP4Duration elapsed = 0;

	for (u_int32_t sttsIndex = 0; sttsIndex < numStts; sttsIndex++) {
		u_int32_t sampleCount = 
			m_pSttsSampleCountProperty->GetValue(sttsIndex);
		u_int32_t sampleDelta = 
			m_pSttsSampleDeltaProperty->GetValue(sttsIndex);

		if (sampleId <= sid + sampleCount - 1) {
			if (pStartTime) {
			  *pStartTime = (sampleId - sid);
			  *pStartTime *= sampleDelta;
			  *pStartTime += elapsed;
			}
			if (pDuration) {
				*pDuration = sampleDelta;
			}
			return;
		}
		sid += sampleCount;
		elapsed += sampleCount * sampleDelta;
	}

	throw new MP4Error("sample id out of range", 
		"MP4Track::GetSampleTimes");
}

MP4SampleId MP4Track::GetSampleIdFromTime(
	MP4Timestamp when, 
	bool wantSyncSample) 
{
	u_int32_t numStts = m_pSttsCountProperty->GetValue();
	MP4SampleId sid = 1;
	MP4Duration elapsed = 0;

	for (u_int32_t sttsIndex = 0; sttsIndex < numStts; sttsIndex++) {
		u_int32_t sampleCount = 
			m_pSttsSampleCountProperty->GetValue(sttsIndex);
		u_int32_t sampleDelta = 
			m_pSttsSampleDeltaProperty->GetValue(sttsIndex);

		if (sampleDelta == 0 && sttsIndex < numStts - 1) {
			VERBOSE_READ(m_pFile->GetVerbosity(),
				printf("Warning: Zero sample duration, stts entry %u\n",
				sttsIndex));
		}

		MP4Duration d = when - elapsed;

		if (d <= sampleCount * sampleDelta) {
			MP4SampleId sampleId = sid;
			if (sampleDelta) {
				sampleId += (d / sampleDelta);
			}

			if (wantSyncSample) {
				return GetNextSyncSample(sampleId);
			}
			return sampleId;
		}

		sid += sampleCount;
		elapsed += sampleCount * sampleDelta;
	}

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

	return 0; // satisfy MS compiler
}

void MP4Track::UpdateSampleTimes(MP4Duration duration)
{
	u_int32_t numStts = m_pSttsCountProperty->GetValue();

	// if duration == duration of last entry
	if (numStts 
	  && duration == m_pSttsSampleDeltaProperty->GetValue(numStts-1)) {
		// increment last entry sampleCount
		m_pSttsSampleCountProperty->IncrementValue(1, numStts-1);

	} else {
		// add stts entry, sampleCount = 1, sampleDuration = duration
		m_pSttsSampleCountProperty->AddValue(1);
		m_pSttsSampleDeltaProperty->AddValue(duration);
		m_pSttsCountProperty->IncrementValue();;
	}
}

u_int32_t MP4Track::GetSampleCttsIndex(MP4SampleId sampleId, 
	MP4SampleId* pFirstSampleId)
{
	u_int32_t numCtts = m_pCttsCountProperty->GetValue();

	MP4SampleId sid = 1;
	
	for (u_int32_t cttsIndex = 0; cttsIndex < numCtts; cttsIndex++) {
		u_int32_t sampleCount = 
			m_pCttsSampleCountProperty->GetValue(cttsIndex);

		if (sampleId <= sid + sampleCount - 1) {
			if (pFirstSampleId) {
				*pFirstSampleId = sid;
			}
			return cttsIndex;
		}
		sid += sampleCount;
	}

	throw new MP4Error("sample id out of range", 
		"MP4Track::GetSampleCttsIndex");
	return 0; // satisfy MS compiler
}

MP4Duration MP4Track::GetSampleRenderingOffset(MP4SampleId sampleId)
{
	if (m_pCttsCountProperty == NULL) {
		return 0;
	}
	if (m_pCttsCountProperty->GetValue() == 0) {
		return 0;
	}

	u_int32_t cttsIndex = GetSampleCttsIndex(sampleId);

	return m_pCttsSampleOffsetProperty->GetValue(cttsIndex);
}

void MP4Track::UpdateRenderingOffsets(MP4SampleId sampleId, 
	MP4Duration renderingOffset)
{
	// if ctts atom doesn't exist
	if (m_pCttsCountProperty == NULL) {

		// no rendering offset, so nothing to do
		if (renderingOffset == 0) {
			return;
		}

		// else create a ctts atom
		MP4Atom* pCttsAtom = AddAtom("trak.mdia.minf.stbl", "ctts");

		// and get handles on the properties
		pCttsAtom->FindProperty(
			"ctts.entryCount",
			(MP4Property**)&m_pCttsCountProperty);

		pCttsAtom->FindProperty(
			"ctts.entries.sampleCount",
			(MP4Property**)&m_pCttsSampleCountProperty);

		pCttsAtom->FindProperty(
			"ctts.entries.sampleOffset",
			(MP4Property**)&m_pCttsSampleOffsetProperty);

		// if this is not the first sample
		if (sampleId > 1) {
			// add a ctts entry for all previous samples
			// with rendering offset equal to zero
			m_pCttsSampleCountProperty->AddValue(sampleId - 1);
			m_pCttsSampleOffsetProperty->AddValue(0);
			m_pCttsCountProperty->IncrementValue();;
		}
	}

	// ctts atom exists (now)

	u_int32_t numCtts = m_pCttsCountProperty->GetValue();

	// if renderingOffset == renderingOffset of last entry
	if (numCtts && renderingOffset
	   == m_pCttsSampleOffsetProperty->GetValue(numCtts-1)) {

		// increment last entry sampleCount
		m_pCttsSampleCountProperty->IncrementValue(1, numCtts-1);

	} else {
		// add ctts entry, sampleCount = 1, sampleOffset = renderingOffset
		m_pCttsSampleCountProperty->AddValue(1);
		m_pCttsSampleOffsetProperty->AddValue(renderingOffset);
		m_pCttsCountProperty->IncrementValue();
	}
}

void MP4Track::SetSampleRenderingOffset(MP4SampleId sampleId,
	 MP4Duration renderingOffset)
{
	// check if any ctts entries exist
	if (m_pCttsCountProperty == NULL
	  || m_pCttsCountProperty->GetValue() == 0) {
		// if not then Update routine can be used 
		// to create a ctts entry for samples before this one
		// and a ctts entry for this sample 
		UpdateRenderingOffsets(sampleId, renderingOffset);

		// but we also need a ctts entry 
		// for all samples after this one
		u_int32_t afterSamples = GetNumberOfSamples() - sampleId;

		if (afterSamples) {
			m_pCttsSampleCountProperty->AddValue(afterSamples);
			m_pCttsSampleOffsetProperty->AddValue(0);
			m_pCttsCountProperty->IncrementValue();;
		}

		return;
	}

	MP4SampleId firstSampleId;
	u_int32_t cttsIndex = GetSampleCttsIndex(sampleId, &firstSampleId);

	// do nothing in the degenerate case
	if (renderingOffset == 
	  m_pCttsSampleOffsetProperty->GetValue(cttsIndex)) {
		return;
	}

	u_int32_t sampleCount =
		m_pCttsSampleCountProperty->GetValue(cttsIndex);

	// if this sample has it's own ctts entry
	if (sampleCount == 1) {
		// then just set the value, 
		// note we don't attempt to collapse entries
		m_pCttsSampleOffsetProperty->SetValue(renderingOffset, cttsIndex);
		return;
	}

	MP4SampleId lastSampleId = firstSampleId + sampleCount - 1;

	// else we share this entry with other samples
	// we need to insert our own entry
	if (sampleId == firstSampleId) {
		// our sample is the first one
		m_pCttsSampleCountProperty->
			InsertValue(1, cttsIndex);
		m_pCttsSampleOffsetProperty->
			InsertValue(renderingOffset, cttsIndex);

		m_pCttsSampleCountProperty->
			SetValue(sampleCount - 1, cttsIndex + 1);

		m_pCttsCountProperty->IncrementValue();

	} else if (sampleId == lastSampleId) {
		// our sample is the last one
		m_pCttsSampleCountProperty->
			InsertValue(1, cttsIndex + 1);
		m_pCttsSampleOffsetProperty->
			InsertValue(renderingOffset, cttsIndex + 1);

		m_pCttsSampleCountProperty->
			SetValue(sampleCount - 1, cttsIndex);

		m_pCttsCountProperty->IncrementValue();

	} else {
		// our sample is in the middle, UGH!

		// insert our new entry
		m_pCttsSampleCountProperty->
			InsertValue(1, cttsIndex + 1);
		m_pCttsSampleOffsetProperty->
			InsertValue(renderingOffset, cttsIndex + 1);

		// adjust count of previous entry
		m_pCttsSampleCountProperty->
			SetValue(sampleId - firstSampleId, cttsIndex);

		// insert new entry for those samples beyond our sample
		m_pCttsSampleCountProperty->
			InsertValue(lastSampleId - sampleId, cttsIndex + 2);
		u_int32_t oldRenderingOffset =
			m_pCttsSampleOffsetProperty->GetValue(cttsIndex);
		m_pCttsSampleOffsetProperty->
			InsertValue(oldRenderingOffset, cttsIndex + 2);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -