📄 rtphint.cpp
字号:
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");
}
m_rtpData.Add(pData);
// read data entry's properties
pData->Read(pFile);
}
}
void MP4RtpPacket::ReadExtra(MP4File* pFile)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -