📄 rtphint.cpp
字号:
} if (include_mpeg4_esid) { sprintf(sdpBuf + buflen, "a=mpeg4-esid:%u\015\012", m_pRefTrack->GetId()); } MP4StringProperty* pSdpProperty = NULL; m_pTrakAtom->FindProperty("trak.udta.hnti.sdp .sdpText", (MP4Property**)&pSdpProperty); ASSERT(pSdpProperty); pSdpProperty->SetValue(sdpBuf); // cleanup MP4Free(rtpMapBuf); MP4Free(sdpBuf);}void MP4RtpHintTrack::AddHint(bool isBFrame, u_int32_t timestampOffset){ // on first hint, need to lookup the reference track if (m_writeHintId == MP4_INVALID_SAMPLE_ID) { InitRefTrack(); InitStats(); } if (m_pWriteHint) { throw new MP4Error("unwritten hint is still pending", "MP4AddRtpHint"); } m_pWriteHint = new MP4RtpHint(this); m_pWriteHint->SetBFrame(isBFrame); m_pWriteHint->SetTimestampOffset(timestampOffset); m_bytesThisHint = 0; m_writeHintId++;}void MP4RtpHintTrack::AddPacket(bool setMbit, int32_t transmitOffset){ if (m_pWriteHint == NULL) { throw new MP4Error("no hint pending", "MP4RtpAddPacket"); } MP4RtpPacket* pPacket = m_pWriteHint->AddPacket(); ASSERT(m_pPayloadNumberProperty); pPacket->Set( m_pPayloadNumberProperty->GetValue(), m_writePacketId++, setMbit); pPacket->SetTransmitOffset(transmitOffset); m_bytesThisHint += 12; if (m_bytesThisPacket > m_pPmax->GetValue()) { m_pPmax->SetValue(m_bytesThisPacket); } m_bytesThisPacket = 12; m_pNump->IncrementValue(); m_pTrpy->IncrementValue(12); // RTP packet header size}void MP4RtpHintTrack::AddImmediateData( const u_int8_t* pBytes, u_int32_t numBytes){ if (m_pWriteHint == NULL) { throw new MP4Error("no hint pending", "MP4RtpAddImmediateData"); } MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); if (pPacket == NULL) { throw new MP4Error("no packet pending", "MP4RtpAddImmediateData"); } if (pBytes == NULL || numBytes == 0) { throw new MP4Error("no data", "AddImmediateData"); } if (numBytes > 14) { throw new MP4Error("data size is larger than 14 bytes", "AddImmediateData"); } MP4RtpImmediateData* pData = new MP4RtpImmediateData(pPacket); pData->Set(pBytes, numBytes); pPacket->AddData(pData); m_bytesThisHint += numBytes; m_bytesThisPacket += numBytes; m_pDimm->IncrementValue(numBytes); m_pTpyl->IncrementValue(numBytes); m_pTrpy->IncrementValue(numBytes);}void MP4RtpHintTrack::AddSampleData( MP4SampleId sampleId, u_int32_t dataOffset, u_int32_t dataLength){ if (m_pWriteHint == NULL) { throw new MP4Error("no hint pending", "MP4RtpAddSampleData"); } MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); if (pPacket == NULL) { throw new MP4Error("no packet pending", "MP4RtpAddSampleData"); } MP4RtpSampleData* pData = new MP4RtpSampleData(pPacket); pData->SetReferenceSample(sampleId, dataOffset, dataLength); pPacket->AddData(pData); m_bytesThisHint += dataLength; m_bytesThisPacket += dataLength; m_pDmed->IncrementValue(dataLength); m_pTpyl->IncrementValue(dataLength); m_pTrpy->IncrementValue(dataLength);}void MP4RtpHintTrack::AddESConfigurationPacket(){ if (m_pWriteHint == NULL) { throw new MP4Error("no hint pending", "MP4RtpAddESConfigurationPacket"); } u_int8_t* pConfig = NULL; u_int32_t configSize = 0; m_pFile->GetTrackESConfiguration(m_pRefTrack->GetId(), &pConfig, &configSize); if (pConfig == NULL) { return; } ASSERT(m_pMaxPacketSizeProperty); if (configSize > m_pMaxPacketSizeProperty->GetValue()) { throw new MP4Error("ES configuration is too large for RTP payload", "MP4RtpAddESConfigurationPacket"); } AddPacket(false); MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket(); ASSERT(pPacket); // This is ugly! // To get the ES configuration data somewhere known // we create a sample data reference that points to // this hint track (not the media track) // and this sample of the hint track // the offset into this sample is filled in during the write process MP4RtpSampleData* pData = new MP4RtpSampleData(pPacket); pData->SetEmbeddedImmediate(m_writeSampleId, pConfig, configSize); pPacket->AddData(pData); m_bytesThisHint += configSize; m_bytesThisPacket += configSize; m_pTpyl->IncrementValue(configSize); m_pTrpy->IncrementValue(configSize);}void MP4RtpHintTrack::WriteHint(MP4Duration duration, bool isSyncSample){ if (m_pWriteHint == NULL) { throw new MP4Error("no hint pending", "MP4WriteRtpHint"); } u_int8_t* pBytes; u_int64_t numBytes; m_pFile->EnableMemoryBuffer(); m_pWriteHint->Write(m_pFile); m_pFile->DisableMemoryBuffer(&pBytes, &numBytes); WriteSample(pBytes, numBytes, duration, 0, isSyncSample); MP4Free(pBytes); // update statistics if (m_bytesThisPacket > m_pPmax->GetValue()) { m_pPmax->SetValue(m_bytesThisPacket); } if (duration > m_pDmax->GetValue()) { m_pDmax->SetValue(duration); } MP4Timestamp startTime; GetSampleTimes(m_writeHintId, &startTime, NULL); if (startTime < m_thisSec + GetTimeScale()) { m_bytesThisSec += m_bytesThisHint; } else { if (m_bytesThisSec > m_pMaxr->GetValue()) { m_pMaxr->SetValue(m_bytesThisSec); } m_thisSec = startTime - (startTime % GetTimeScale()); m_bytesThisSec = m_bytesThisHint; } // cleanup delete m_pWriteHint; m_pWriteHint = NULL;}void MP4RtpHintTrack::FinishWrite(){ if (m_writeHintId != MP4_INVALID_SAMPLE_ID) { m_pMaxPdu->SetValue(m_pPmax->GetValue()); if (m_pNump->GetValue()) { m_pAvgPdu->SetValue(m_pTrpy->GetValue() / m_pNump->GetValue()); } m_pMaxBitRate->SetValue(m_pMaxr->GetValue() * 8); if (GetDuration()) { m_pAvgBitRate->SetValue( m_pTrpy->GetValue() * 8 * GetTimeScale() / GetDuration()); } } MP4Track::FinishWrite();}void MP4RtpHintTrack::InitStats(){ MP4Atom* pHinfAtom = m_pTrakAtom->FindAtom("trak.udta.hinf"); ASSERT(pHinfAtom); pHinfAtom->FindProperty("hinf.trpy.bytes", (MP4Property**)&m_pTrpy); pHinfAtom->FindProperty("hinf.nump.packets", (MP4Property**)&m_pNump); pHinfAtom->FindProperty("hinf.tpyl.bytes", (MP4Property**)&m_pTpyl); pHinfAtom->FindProperty("hinf.maxr.bytes", (MP4Property**)&m_pMaxr); pHinfAtom->FindProperty("hinf.dmed.bytes", (MP4Property**)&m_pDmed); pHinfAtom->FindProperty("hinf.dimm.bytes", (MP4Property**)&m_pDimm); pHinfAtom->FindProperty("hinf.pmax.bytes", (MP4Property**)&m_pPmax); pHinfAtom->FindProperty("hinf.dmax.milliSecs", (MP4Property**)&m_pDmax); MP4Atom* pHmhdAtom = m_pTrakAtom->FindAtom("trak.mdia.minf.hmhd"); ASSERT(pHmhdAtom); pHmhdAtom->FindProperty("hmhd.maxPduSize", (MP4Property**)&m_pMaxPdu); pHmhdAtom->FindProperty("hmhd.avgPduSize", (MP4Property**)&m_pAvgPdu); pHmhdAtom->FindProperty("hmhd.maxBitRate", (MP4Property**)&m_pMaxBitRate); pHmhdAtom->FindProperty("hmhd.avgBitRate", (MP4Property**)&m_pAvgBitRate); MP4Integer32Property* pMaxrPeriod = NULL; pHinfAtom->FindProperty("hinf.maxr.granularity", (MP4Property**)&pMaxrPeriod); if (pMaxrPeriod) { pMaxrPeriod->SetValue(1000); // 1 second }}MP4RtpHint::MP4RtpHint(MP4RtpHintTrack* pTrack){ m_pTrack = pTrack; AddProperty( /* 0 */ new MP4Integer16Property("packetCount")); AddProperty( /* 1 */ new MP4Integer16Property("reserved"));}MP4RtpHint::~MP4RtpHint(){ for (u_int32_t i = 0; i < m_rtpPackets.Size(); i++) { delete m_rtpPackets[i]; }}MP4RtpPacket* MP4RtpHint::AddPacket() { MP4RtpPacket* pPacket = new MP4RtpPacket(this); m_rtpPackets.Add(pPacket); // packetCount property ((MP4Integer16Property*)m_pProperties[0])->IncrementValue(); pPacket->SetBFrame(m_isBFrame); pPacket->SetTimestampOffset(m_timestampOffset); return pPacket;}void MP4RtpHint::Read(MP4File* pFile){ // call base class Read for required properties MP4Container::Read(pFile); u_int16_t numPackets = ((MP4Integer16Property*)m_pProperties[0])->GetValue(); for (u_int16_t i = 0; i < numPackets; i++) { MP4RtpPacket* pPacket = new MP4RtpPacket(this); m_rtpPackets.Add(pPacket); pPacket->Read(pFile); } VERBOSE_READ_HINT(pFile->GetVerbosity(), printf("ReadHint:\n"); Dump(stdout, 10, false););}void MP4RtpHint::Write(MP4File* pFile){ u_int64_t hintStartPos = pFile->GetPosition(); MP4Container::Write(pFile); u_int64_t packetStartPos = pFile->GetPosition(); u_int32_t i; // first write out packet (and data) entries for (i = 0; i < m_rtpPackets.Size(); i++) { m_rtpPackets[i]->Write(pFile); } // now let packets write their extra data into the hint sample for (i = 0; i < m_rtpPackets.Size(); i++) { m_rtpPackets[i]->WriteEmbeddedData(pFile, hintStartPos); } u_int64_t endPos = pFile->GetPosition(); pFile->SetPosition(packetStartPos); // finally rewrite the packet and data entries // which now contain the correct offsets for the embedded data for (i = 0; i < m_rtpPackets.Size(); i++) { m_rtpPackets[i]->Write(pFile); } pFile->SetPosition(endPos); VERBOSE_WRITE_HINT(pFile->GetVerbosity(), printf("WriteRtpHint:\n"); Dump(stdout, 14, false));}void MP4RtpHint::Dump(FILE* pFile, u_int8_t indent, bool dumpImplicits){ MP4Container::Dump(pFile, indent, dumpImplicits); for (u_int32_t i = 0; i < m_rtpPackets.Size(); i++) { Indent(pFile, indent); fprintf(pFile, "RtpPacket: %u\n", i); m_rtpPackets[i]->Dump(pFile, indent + 1, dumpImplicits); }}MP4RtpPacket::MP4RtpPacket(MP4RtpHint* pHint){ m_pHint = pHint; AddProperty( /* 0 */ new MP4Integer32Property("relativeXmitTime")); AddProperty( /* 1 */ new MP4BitfieldProperty("reserved1", 2)); AddProperty( /* 2 */ new MP4BitfieldProperty("Pbit", 1)); AddProperty( /* 3 */ new MP4BitfieldProperty("Xbit", 1)); AddProperty( /* 4 */ new MP4BitfieldProperty("reserved2", 4)); AddProperty( /* 5 */ new MP4BitfieldProperty("Mbit", 1)); AddProperty( /* 6 */ new MP4BitfieldProperty("payloadType", 7)); AddProperty( /* 7 */ new MP4Integer16Property("sequenceNumber")); AddProperty( /* 8 */ new MP4BitfieldProperty("reserved3", 13)); AddProperty( /* 9 */ new MP4BitfieldProperty("extraFlag", 1)); AddProperty( /* 10 */ new MP4BitfieldProperty("bFrameFlag", 1)); AddProperty( /* 11 */ new MP4BitfieldProperty("repeatFlag", 1)); AddProperty( /* 12 */ new MP4Integer16Property("entryCount"));} MP4RtpPacket::~MP4RtpPacket(){ for (u_int32_t i = 0; i < m_rtpData.Size(); i++) { delete m_rtpData[i]; }}void MP4RtpPacket::AddExtraProperties(){ AddProperty( /* 13 */ new MP4Integer32Property("extraInformationLength")); // This is a bit of a hack, since the tlv entries are really defined // as atoms but there is only one type defined now, rtpo, and getting // our atom code hooked up here would be a major pain with little gain AddProperty( /* 14 */ new MP4Integer32Property("tlvLength")); AddProperty( /* 15 */ new MP4StringProperty("tlvType")); AddProperty( /* 16 */ new MP4Integer32Property("timestampOffset")); ((MP4Integer32Property*)m_pProperties[13])->SetValue(16); ((MP4Integer32Property*)m_pProperties[14])->SetValue(12); ((MP4StringProperty*)m_pProperties[15])->SetFixedLength(4); ((MP4StringProperty*)m_pProperties[15])->SetValue("rtpo");}void MP4RtpPacket::Read(MP4File* pFile){ // call base class Read for required properties MP4Container::Read(pFile); // read extra info if present // we only support the rtpo field! if (((MP4BitfieldProperty*)m_pProperties[9])->GetValue() == 1) { ReadExtra(pFile); } u_int16_t numDataEntries = ((MP4Integer16Property*)m_pProperties[12])->GetValue(); // read data entries for (u_int16_t i = 0; i < numDataEntries; i++) { u_int8_t dataType; pFile->PeekBytes(&dataType, 1); MP4RtpData* pData; switch (dataType) { case 0: pData = new MP4RtpNullData(this); break; case 1: pData = new MP4RtpImmediateData(this); break; case 2: pData = new MP4RtpSampleData(this); break; case 3: pData = new MP4RtpSampleDescriptionData(this); break; default: throw new MP4Error("unknown packet data entry type", "MP4ReadHint");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -