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

📄 mp4track.cpp

📁 网络MPEG4IP流媒体开发源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			// add size value for this sample			m_pStszSampleSizeProperty->AddValue(numBytes);		}	}	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 {		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;				}			}		} 	}	if (m_lastSampleFile) {		fclose(m_lastSampleFile);	}	// 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 = elapsed + ((sampleId - sid) * sampleDelta);			}			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);		m_pCttsCountProperty->IncrementValue(2);	}

⌨️ 快捷键说明

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