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

📄 mp4track.cpp

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

		m_pCttsCountProperty->IncrementValue(2);
	}
}

bool MP4Track::IsSyncSample(MP4SampleId sampleId)
{
	if (m_pStssCountProperty == NULL) {
		return true;
	}

	u_int32_t numStss = m_pStssCountProperty->GetValue();
	
	for (u_int32_t stssIndex = 0; stssIndex < numStss; stssIndex++) {
		MP4SampleId syncSampleId = 
			m_pStssSampleProperty->GetValue(stssIndex);

		if (sampleId == syncSampleId) {
			return true;
		} 
		if (sampleId < syncSampleId) {
			break;
		}
	}

	return false;
}

// N.B. "next" is inclusive of this sample id
MP4SampleId MP4Track::GetNextSyncSample(MP4SampleId sampleId)
{
	if (m_pStssCountProperty == NULL) {
		return sampleId;
	}

	u_int32_t numStss = m_pStssCountProperty->GetValue();
	
	for (u_int32_t stssIndex = 0; stssIndex < numStss; stssIndex++) {
		MP4SampleId syncSampleId = 
			m_pStssSampleProperty->GetValue(stssIndex);

		if (sampleId > syncSampleId) {
			continue;
		}
		return syncSampleId;
	}

	// LATER check stsh for alternate sample

	return MP4_INVALID_SAMPLE_ID;
}

void MP4Track::UpdateSyncSamples(MP4SampleId sampleId, bool isSyncSample)
{
	if (isSyncSample) {
		// if stss atom exists, add entry
		if (m_pStssCountProperty) {
			m_pStssSampleProperty->AddValue(sampleId);
			m_pStssCountProperty->IncrementValue();
		} // else nothing to do (yet)

	} else { // !isSyncSample
		// if stss atom doesn't exist, create one
		if (m_pStssCountProperty == NULL) {

			MP4Atom* pStssAtom = AddAtom("trak.mdia.minf.stbl", "stss");

			pStssAtom->FindProperty(
				"stss.entryCount",
				(MP4Property**)&m_pStssCountProperty);

			pStssAtom->FindProperty(
				"stss.entries.sampleNumber",
				(MP4Property**)&m_pStssSampleProperty);

			// set values for all samples that came before this one
			for (MP4SampleId sid = 1; sid < sampleId; sid++) {
				m_pStssSampleProperty->AddValue(sid);
				m_pStssCountProperty->IncrementValue();
			}
		} // else nothing to do
	}
}

MP4Atom* MP4Track::AddAtom(char* parentName, char* childName)
{
	MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName);

	MP4Atom* pParentAtom = m_pTrakAtom->FindAtom(parentName);
	ASSERT(pParentAtom);

	pParentAtom->AddChildAtom(pChildAtom);

	pChildAtom->Generate();

	return pChildAtom;
}

u_int64_t MP4Track::GetDuration()
{
	return m_pMediaDurationProperty->GetValue();
}

u_int32_t MP4Track::GetTimeScale()
{
	return m_pTimeScaleProperty->GetValue();
}

void MP4Track::UpdateDurations(MP4Duration duration)
{
	// update media, track, and movie durations
	m_pMediaDurationProperty->SetValue(
		m_pMediaDurationProperty->GetValue() + duration);

	MP4Duration movieDuration = ToMovieDuration(duration);
	m_pTrackDurationProperty->SetValue(
		m_pTrackDurationProperty->GetValue() + movieDuration);

	m_pFile->UpdateDuration(m_pTrackDurationProperty->GetValue());
}

MP4Duration MP4Track::ToMovieDuration(MP4Duration trackDuration)
{
	return (trackDuration * m_pFile->GetTimeScale()) 
		/ m_pTimeScaleProperty->GetValue();
}

void MP4Track::UpdateModificationTimes()
{
	// update media and track modification times
	MP4Timestamp now = MP4GetAbsTimestamp();
	m_pMediaModificationProperty->SetValue(now);
	m_pTrackModificationProperty->SetValue(now);
}

u_int32_t MP4Track::GetNumberOfChunks()
{
	return m_pChunkOffsetProperty->GetCount();
}

u_int32_t MP4Track::GetChunkStscIndex(MP4ChunkId chunkId)
{
	u_int32_t stscIndex;
	u_int32_t numStscs = m_pStscCountProperty->GetValue();

	ASSERT(chunkId);
	ASSERT(numStscs > 0);

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

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

u_int32_t MP4Track::GetChunkSize(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);

	// need cumulative sizes of samples in chunk 
	u_int32_t chunkSize = 0;
	for (u_int32_t i = 0; i < samplesPerChunk; i++) {
		chunkSize += GetSampleSize(firstSampleInChunk + i);
	}

	return chunkSize;
}

void MP4Track::ReadChunk(MP4ChunkId chunkId, 
	u_int8_t** ppChunk, u_int32_t* pChunkSize)
{
	ASSERT(chunkId);
	ASSERT(ppChunk);
	ASSERT(pChunkSize);

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

	*pChunkSize = GetChunkSize(chunkId);
	*ppChunk = (u_int8_t*)MP4Malloc(*pChunkSize);

	VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(),
		printf("ReadChunk: track %u id %u offset 0x"LLX" size %u (0x%x)\n",
			m_trackId, chunkId, chunkOffset, *pChunkSize, *pChunkSize));

	u_int64_t oldPos = m_pFile->GetPosition(); // only used in mode == 'w'
	try {
		m_pFile->SetPosition(chunkOffset);
		m_pFile->ReadBytes(*ppChunk, *pChunkSize);
	}
	catch (MP4Error* e) {
		// let's not leak memory
		MP4Free(*ppChunk);
		*ppChunk = NULL;

		if (m_pFile->GetMode() == 'w') {
			m_pFile->SetPosition(oldPos);
		}
		throw e;
	}

	if (m_pFile->GetMode() == 'w') {
		m_pFile->SetPosition(oldPos);
	}
}

void MP4Track::RewriteChunk(MP4ChunkId chunkId, 
	u_int8_t* pChunk, u_int32_t chunkSize)
{
	u_int64_t chunkOffset = m_pFile->GetPosition();

	m_pFile->WriteBytes(pChunk, chunkSize);

	m_pChunkOffsetProperty->SetValue(chunkOffset, chunkId - 1);

	VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(),
		printf("RewriteChunk: track %u id %u offset 0x"LLX" size %u (0x%x)\n",
			m_trackId, chunkId, chunkOffset, chunkSize, chunkSize)); 
}

// map track type name aliases to official names

const char* MP4Track::NormalizeTrackType(const char* type)
{
	if (!strcasecmp(type, "vide")
	  || !strcasecmp(type, "video")
	  || !strcasecmp(type, "mp4v")
	  || !strcasecmp(type, "encv")) {
		return MP4_VIDEO_TRACK_TYPE;
	}

	if (!strcasecmp(type, "soun")
	  || !strcasecmp(type, "sound")
	  || !strcasecmp(type, "audio")
	  || !strcasecmp(type, "enca")  // ismacrypt 
	  || !strcasecmp(type, "mp4a")) {
		return MP4_AUDIO_TRACK_TYPE;
	}

	if (!strcasecmp(type, "sdsm")
	  || !strcasecmp(type, "scene")
	  || !strcasecmp(type, "bifs")) {
		return MP4_SCENE_TRACK_TYPE;
	}

	if (!strcasecmp(type, "odsm")
	  || !strcasecmp(type, "od")) {
		return MP4_OD_TRACK_TYPE;
	}

	return type;
}

bool MP4Track::InitEditListProperties()
{
	m_pElstCountProperty = NULL;
	m_pElstMediaTimeProperty = NULL;
	m_pElstDurationProperty = NULL;
	m_pElstRateProperty = NULL;
	m_pElstReservedProperty = NULL;

	MP4Atom* pElstAtom =
		m_pTrakAtom->FindAtom("trak.edts.elst");

	if (!pElstAtom) {
		return false;
	}

	pElstAtom->FindProperty(
		"elst.entryCount",
		(MP4Property**)&m_pElstCountProperty);

	pElstAtom->FindProperty(
		"elst.entries.mediaTime",
		(MP4Property**)&m_pElstMediaTimeProperty);

	pElstAtom->FindProperty(
		"elst.entries.segmentDuration",
		(MP4Property**)&m_pElstDurationProperty);

	pElstAtom->FindProperty(
		"elst.entries.mediaRate",
		(MP4Property**)&m_pElstRateProperty);

	pElstAtom->FindProperty(
		"elst.entries.reserved",
		(MP4Property**)&m_pElstReservedProperty);

	return m_pElstCountProperty
		&& m_pElstMediaTimeProperty
		&& m_pElstDurationProperty
		&& m_pElstRateProperty
		&& m_pElstReservedProperty;
}

MP4EditId MP4Track::AddEdit(MP4EditId editId)
{
	if (!m_pElstCountProperty) {
		m_pFile->AddDescendantAtoms(m_pTrakAtom, "edts.elst");
		InitEditListProperties();
	}

	if (editId == MP4_INVALID_EDIT_ID) {
		editId = m_pElstCountProperty->GetValue() + 1;
	}

	m_pElstMediaTimeProperty->InsertValue(0, editId - 1);
	m_pElstDurationProperty->InsertValue(0, editId - 1);
	m_pElstRateProperty->InsertValue(1, editId - 1);
	m_pElstReservedProperty->InsertValue(0, editId - 1);

	m_pElstCountProperty->IncrementValue();

	return editId;
}

void MP4Track::DeleteEdit(MP4EditId editId)
{
	if (editId == MP4_INVALID_EDIT_ID) {
		throw new MP4Error("edit id can't be zero", 
			"MP4Track::DeleteEdit");
	}

	if (!m_pElstCountProperty
	  || m_pElstCountProperty->GetValue() == 0) {
		throw new MP4Error("no edits exist", 
			"MP4Track::DeleteEdit");
	}

	m_pElstMediaTimeProperty->DeleteValue(editId - 1);
	m_pElstDurationProperty->DeleteValue(editId - 1);
	m_pElstRateProperty->DeleteValue(editId - 1);
	m_pElstReservedProperty->DeleteValue(editId - 1);

	m_pElstCountProperty->IncrementValue(-1);

	// clean up if last edit is deleted
	if (m_pElstCountProperty->GetValue() == 0) {
		m_pElstCountProperty = NULL;
		m_pElstMediaTimeProperty = NULL;
		m_pElstDurationProperty = NULL;
		m_pElstRateProperty = NULL;
		m_pElstReservedProperty = NULL;

		m_pTrakAtom->DeleteChildAtom(
			m_pTrakAtom->FindAtom("trak.edts"));
	}
}

MP4Timestamp MP4Track::GetEditStart(
	MP4EditId editId) 
{
	if (editId == MP4_INVALID_EDIT_ID) {
		return MP4_INVALID_TIMESTAMP;
	} else if (editId == 1) {
		return 0;
	}
	return (MP4Timestamp)GetEditTotalDuration(editId - 1);
}	

MP4Duration MP4Track::GetEditTotalDuration(
	MP4EditId editId)
{
	u_int32_t numEdits = 0;

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

	if (editId == MP4_INVALID_EDIT_ID) {
		editId = numEdits;
	}

	if (numEdits == 0 || editId > numEdits) {
		return MP4_INVALID_DURATION;
	}

	MP4Duration totalDuration = 0;

	for (MP4EditId eid = 1; eid <= editId; eid++) {
		totalDuration += 
			m_pElstDurationProperty->GetValue(eid - 1);
	}

	return totalDuration;
}

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

⌨️ 快捷键说明

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