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

📄 mp4track.cpp

📁 完整的RTP RTSP代码库
💻 CPP
📖 第 1 页 / 共 4 页
字号:
	if (m_chunkBufferSize == 0) {		return;	}	u_int64_t chunkOffset = m_pFile->GetPosition();	// write chunk buffer	m_pFile->WriteBytes(m_pChunkBuffer, m_chunkBufferSize);	VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(),		printf("WriteChunk: track %u offset 0x"X64" size %u (0x%x) numSamples %u\n",			m_trackId, chunkOffset, m_chunkBufferSize, 			m_chunkBufferSize, m_chunkSamples));	UpdateSampleToChunk(m_writeSampleId, 		m_pChunkCountProperty->GetValue() + 1, 		m_chunkSamples);	UpdateChunkOffsets(chunkOffset);	// clean up chunk buffer	MP4Free(m_pChunkBuffer);	m_pChunkBuffer = NULL;	m_chunkBufferSize = 0;	m_chunkSamples = 0;	m_chunkDuration = 0;}void MP4Track::FinishWrite(){	// write out any remaining samples in chunk buffer	WriteChunkBuffer();	if (m_pStszFixedSampleSizeProperty == NULL &&	    m_stsz_sample_bits == 4) {	  if (m_have_stz2_4bit_sample) {	    ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(m_stz2_4bit_sample_value);	    m_pStszSampleSizeProperty->IncrementValue();	  }	}	// record buffer size and bitrates	MP4BitfieldProperty* pBufferSizeProperty;	if (m_pTrakAtom->FindProperty(	  "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.bufferSizeDB",	  (MP4Property**)&pBufferSizeProperty)) {		pBufferSizeProperty->SetValue(GetMaxSampleSize());	}	MP4Integer32Property* pBitrateProperty;	if (m_pTrakAtom->FindProperty(	  "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.maxBitrate",	  (MP4Property**)&pBitrateProperty)) {		pBitrateProperty->SetValue(GetMaxBitrate());	}	if (m_pTrakAtom->FindProperty(	  "trak.mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate",	  (MP4Property**)&pBitrateProperty)) {		pBitrateProperty->SetValue(GetAvgBitrate());	}}bool MP4Track::IsChunkFull(MP4SampleId sampleId){	if (m_samplesPerChunk) {		return m_chunkSamples >= m_samplesPerChunk;	}	ASSERT(m_durationPerChunk);	return m_chunkDuration >= m_durationPerChunk;}u_int32_t MP4Track::GetNumberOfSamples(){	return m_pStszSampleCountProperty->GetValue();}u_int32_t MP4Track::GetSampleSize(MP4SampleId sampleId){  if (m_pStszFixedSampleSizeProperty != NULL) {	u_int32_t fixedSampleSize = 		m_pStszFixedSampleSizeProperty->GetValue(); 	if (fixedSampleSize != 0) {	  return fixedSampleSize * m_bytesPerSample;	}  }  // will have to check for 4 bit sample size here  if (m_stsz_sample_bits == 4) {    uint8_t value = m_pStszSampleSizeProperty->GetValue((sampleId - 1) / 2);    if ((sampleId - 1) / 2 == 0) {      value >>= 4;    } else value &= 0xf;    return m_bytesPerSample * value;  }  return m_bytesPerSample *     m_pStszSampleSizeProperty->GetValue(sampleId - 1);}u_int32_t MP4Track::GetMaxSampleSize(){  if (m_pStszFixedSampleSizeProperty != NULL) {	u_int32_t fixedSampleSize = 		m_pStszFixedSampleSizeProperty->GetValue(); 	if (fixedSampleSize != 0) {		return fixedSampleSize * m_bytesPerSample;	}  }	u_int32_t maxSampleSize = 0;	u_int32_t numSamples = m_pStszSampleSizeProperty->GetCount();	for (MP4SampleId sid = 1; sid <= numSamples; sid++) {		u_int32_t sampleSize =			m_pStszSampleSizeProperty->GetValue(sid - 1);		if (sampleSize > maxSampleSize) {			maxSampleSize = sampleSize;		}	}	return maxSampleSize * m_bytesPerSample;}u_int64_t MP4Track::GetTotalOfSampleSizes(){  uint64_t retval;  if (m_pStszFixedSampleSizeProperty != NULL) {	u_int32_t fixedSampleSize = 		m_pStszFixedSampleSizeProperty->GetValue(); 	// if fixed sample size, just need to multiply by number of samples	if (fixedSampleSize != 0) {	  retval = m_bytesPerSample;	  retval *= fixedSampleSize;	  retval *= GetNumberOfSamples();	  return retval;	}  }	// else non-fixed sample size, sum them	u_int64_t totalSampleSizes = 0;	u_int32_t numSamples = m_pStszSampleSizeProperty->GetCount();	for (MP4SampleId sid = 1; sid <= numSamples; sid++) {		u_int32_t sampleSize =			m_pStszSampleSizeProperty->GetValue(sid - 1);		totalSampleSizes += sampleSize;	}	return totalSampleSizes * m_bytesPerSample;}void MP4Track::SampleSizePropertyAddValue (uint32_t size){  // this has to deal with different sample size values  switch (m_pStszSampleSizeProperty->GetType()) {  case Integer32Property:    ((MP4Integer32Property *)m_pStszSampleSizeProperty)->AddValue(size);    break;  case Integer16Property:    ((MP4Integer16Property *)m_pStszSampleSizeProperty)->AddValue(size);    break;  case Integer8Property:    if (m_stsz_sample_bits == 4) {      if (m_have_stz2_4bit_sample == false) {	m_have_stz2_4bit_sample = true;	m_stz2_4bit_sample_value = size << 4;	return;      } else {	m_have_stz2_4bit_sample = false;	size &= 0xf;	size |= m_stz2_4bit_sample_value;      }    }    ((MP4Integer8Property *)m_pStszSampleSizeProperty)->AddValue(size);    break;  default: break;  }  //  m_pStszSampleSizeProperty->IncrementValue();}void MP4Track::UpdateSampleSizes(MP4SampleId sampleId, u_int32_t numBytes){  if (m_bytesPerSample > 1) {    if ((numBytes % m_bytesPerSample) != 0) {      // error      VERBOSE_ERROR(m_pFile->GetVerbosity(), 		    printf("UpdateSampleSize: numBytes %u not divisible by bytesPerSample %u sampleId %u\n", 			   numBytes, m_bytesPerSample, sampleId);		    );    }    numBytes /= m_bytesPerSample;  }	// for first sample	// wmay - if we are adding, we want to make sure that	// we don't inadvertently set up the fixed size again.	// so, we check the number of samples	if (sampleId == 1 && GetNumberOfSamples() == 0) {	  if (m_pStszFixedSampleSizeProperty == NULL ||	      numBytes == 0) {	    // special case of first sample is zero bytes in length	    // leave m_pStszFixedSampleSizeProperty at 0	    // start recording variable sample sizes	    if (m_pStszFixedSampleSizeProperty != NULL)	      m_pStszFixedSampleSizeProperty->SetValue(0); 	    SampleSizePropertyAddValue(0);	  } else {	    // presume sample size is fixed	    m_pStszFixedSampleSizeProperty->SetValue(numBytes); 	  }	} else { // sampleId > 1	  u_int32_t fixedSampleSize = 0;	  if (m_pStszFixedSampleSizeProperty != NULL) {	    fixedSampleSize = m_pStszFixedSampleSizeProperty->GetValue(); 	  }	  // if we don't have a fixed size, or the current sample size	  // doesn't match our sample size, we need to write the current	  // sample size into the table	  if (fixedSampleSize == 0 || numBytes != fixedSampleSize) {	    if (fixedSampleSize != 0) {	      // fixed size was set; we need to clear fixed sample size	      m_pStszFixedSampleSizeProperty->SetValue(0); 	      	      // and create sizes for all previous samples	      // use GetNumberOfSamples due to needing the total number	      // not just the appended part of the file	      uint32_t samples = GetNumberOfSamples();	      for (MP4SampleId sid = 1; sid <= samples; sid++) {		SampleSizePropertyAddValue(fixedSampleSize);	      }	    }	    // add size value for this sample	    SampleSizePropertyAddValue(numBytes);	  }	}	// either way, we increment the number of samples.	m_pStszSampleCountProperty->IncrementValue();#if 0	printf("track %u sample id %u bytes %u fixed %u count %u prop %u\n", 	       m_trackId, sampleId, numBytes,	       m_pStszFixedSampleSizeProperty->GetValue(),	       m_pStszSampleSizeProperty->GetCount(),	       m_pStszSampleCountProperty->GetValue());#endif}u_int32_t MP4Track::GetAvgBitrate(){	if (GetDuration() == 0) {		return 0;	}	double calc = UINT64_TO_DOUBLE(GetTotalOfSampleSizes());	// this is a bit better - we use the whole duration	calc *= 8.0;	calc *= GetTimeScale();	calc /=	UINT64_TO_DOUBLE(GetDuration());	// we might want to think about rounding to the next 100 or 1000	return (uint32_t) ceil(calc);}u_int32_t MP4Track::GetMaxBitrate(){	u_int32_t timeScale = GetTimeScale();	MP4SampleId numSamples = GetNumberOfSamples();	u_int32_t maxBytesPerSec = 0;	u_int32_t bytesThisSec = 0;	MP4Timestamp thisSecStart = 0;	MP4Timestamp lastSampleTime = 0;	uint32_t lastSampleSize = 0;	MP4SampleId thisSecStartSid = 1;	for (MP4SampleId sid = 1; sid <= numSamples; sid++) {	  uint32_t sampleSize;	  MP4Timestamp sampleTime;	  sampleSize = GetSampleSize(sid);	  GetSampleTimes(sid, &sampleTime, NULL);	  	  if (sampleTime < thisSecStart + timeScale) {	    bytesThisSec += sampleSize;	    lastSampleSize = sampleSize;	    lastSampleTime = sampleTime;	  } else {	    // we've already written the last sample and sampleSize.	    // this means that we've probably overflowed the last second	    // calculate the time we've overflowed	    MP4Duration overflow_dur = 	      (thisSecStart + timeScale) - lastSampleTime;	    // calculate the duration of the last sample	    MP4Duration lastSampleDur = sampleTime - lastSampleTime;	    uint32_t overflow_bytes;	    // now, calculate the number of bytes we overflowed.  Round up.	    overflow_bytes = 	      ((lastSampleSize * overflow_dur) + (lastSampleDur - 1)) / lastSampleDur;	    if (bytesThisSec - overflow_bytes > maxBytesPerSec) {	      maxBytesPerSec = bytesThisSec - overflow_bytes;	    }	    // now adjust the values for this sample.  Remove the bytes	    // from the first sample in this time frame	    lastSampleTime = sampleTime;	    lastSampleSize = sampleSize;	    bytesThisSec += sampleSize;	    bytesThisSec -= GetSampleSize(thisSecStartSid);	    thisSecStartSid++;	    GetSampleTimes(thisSecStartSid, &thisSecStart, NULL);	  }	}	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;	if (!pStsdEntryAtom->FindProperty(					 "*.dataReferenceIndex",					 (MP4Property**)&pDrefIndexProperty) ||		    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;		ASSERT(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);	// firstChunk is the chunk index of the first chunk with 	// samplesPerChunk samples in the chunk.  There may be multiples -	// ie: several chunks with the same number of samples per chunk.	u_int32_t firstChunk = 		m_pStscFirstChunkProperty->GetValue(stscIndex);	MP4SampleId firstSample = 		m_pStscFirstSampleProperty->GetValue(stscIndex);	u_int32_t samplesPerChunk = 		m_pStscSamplesPerChunkProperty->GetValue(stscIndex);	// chunkId tells which is the absolute chunk number that this sample	// is stored in.	MP4ChunkId chunkId = firstChunk +		((sampleId - firstSample) / samplesPerChunk);	// chunkOffset is the file offset (absolute) for the start of the chunk	u_int64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1);

⌨️ 快捷键说明

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