/*****************************************************************
|
| AP4 - RTP Hint Objects
|
| Copyright 2002-2005 Gilles Boccon-Gibod & Julien Boeuf
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
| Unless you have obtained Bento4 under a difference license,
| this version of Bento4 is Bento4|GPL.
| Bento4|GPL is free software; you can redistribute it and/or modify
| it under the terms of the GNU General Public License as published by
| the Free Software Foundation; either version 2, or (at your option)
| any later version.
|
| Bento4|GPL is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with Bento4|GPL; see the file COPYING. If not, write to the
| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
| 02111-1307, USA.
|
****************************************************************/
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include "Ap4.h"
#include "Ap4RtpHint.h"
#include "Ap4ByteStream.h"
#include "Ap4Atom.h"
/*----------------------------------------------------------------------
| AP4_RtpSampleData::~AP4_RtpSampleData
+---------------------------------------------------------------------*/
AP4_RtpSampleData::~AP4_RtpSampleData()
{
AP4_List<AP4_RtpPacket>::Item* it = m_Packets.FirstItem();
while (it != NULL) {
it->GetData()->Release();
it = it->GetNext();
}
}
/*----------------------------------------------------------------------
| AP4_RtpSampleData::AP4_RtpSampleData
+---------------------------------------------------------------------*/
AP4_RtpSampleData::AP4_RtpSampleData(AP4_ByteStream& stream, AP4_Size size)
{
// save the start position
AP4_Offset start, extra_data_start;
stream.Tell(start);
AP4_UI16 packet_count;
stream.ReadUI16(packet_count);
AP4_UI16 reserved;
stream.ReadUI16(reserved); // later, check that reserved is 0
// packets
for (AP4_UI16 i=0; i<packet_count; i++) {
AP4_RtpPacket* packet = new AP4_RtpPacket(stream);
m_Packets.Add(packet);
}
// extra data
stream.Tell(extra_data_start);
AP4_Size extra_data_size = size - (extra_data_start-start);
if (extra_data_size != 0) {
m_ExtraData.SetDataSize(extra_data_size);
stream.Read(m_ExtraData.UseData(), extra_data_size);
}
}
/*----------------------------------------------------------------------
| AP4_RtpSampleData::GetSize
+---------------------------------------------------------------------*/
AP4_Size
AP4_RtpSampleData::GetSize()
{
// packet count and reserved
AP4_Size result = 4;
// packets
AP4_List<AP4_RtpPacket>::Item* it = m_Packets.FirstItem();
while (it != NULL) {
result = it->GetData()->GetSize();
it = it->GetNext();
}
// extra data
result += m_ExtraData.GetDataSize();
return result;
}
/*----------------------------------------------------------------------
| AP4_RtpSampleData::ToByteStream
+---------------------------------------------------------------------*/
AP4_ByteStream*
AP4_RtpSampleData::ToByteStream()
{
// refresh the size
AP4_Size size = GetSize();
// create a memory stream
AP4_MemoryByteStream* stream = new AP4_MemoryByteStream(size);
// write in it
AP4_Result result = stream->WriteUI16(static_cast<AP4_UI16>(m_Packets.ItemCount()));
if (AP4_FAILED(result)) goto bail;
result = stream->WriteUI16(0); // reserved
if (AP4_FAILED(result)) goto bail;
{
AP4_List<AP4_RtpPacket>::Item* it = m_Packets.FirstItem();
while (it != NULL) {
result = it->GetData()->Write(*stream);
if (AP4_FAILED(result)) goto bail;
it = it->GetNext();
}
}
result = stream->Write(m_ExtraData.GetData(), m_ExtraData.GetDataSize());
if (AP4_FAILED(result)) goto bail;
// return
return stream;
bail:
stream->Release();
return NULL;
}
/*----------------------------------------------------------------------
| AP4_RtpSampleData::AddPacket
+---------------------------------------------------------------------*/
AP4_Result
AP4_RtpSampleData::AddPacket(AP4_RtpPacket* packet)
{
packet->AddReference();
return m_Packets.Add(packet);
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::AP4_RtpPacket
+---------------------------------------------------------------------*/
AP4_RtpPacket::AP4_RtpPacket(AP4_Integer relative_time,
bool p_bit,
bool x_bit,
bool m_bit,
AP4_UI08 payload_type,
AP4_UI16 sequence_seed,
AP4_Integer time_stamp_offset /* = 0 */,
bool bframe_flag /* = false */,
bool repeat_flag /* = false */) :
m_ReferenceCount(1),
m_RelativeTime(relative_time),
m_PBit(p_bit),
m_XBit(x_bit),
m_MBit(m_bit),
m_PayloadType(payload_type),
m_SequenceSeed(sequence_seed),
m_TimeStampOffset(time_stamp_offset),
m_BFrameFlag(bframe_flag),
m_RepeatFlag(repeat_flag)
{}
/*----------------------------------------------------------------------
| AP4_RtpPacket::AP4_RtpPacket
+---------------------------------------------------------------------*/
AP4_RtpPacket::AP4_RtpPacket(AP4_ByteStream& stream) :
m_ReferenceCount(1),
m_TimeStampOffset(0)
{
AP4_UI08 octet;
// relative time
AP4_UI32 relative_time;
stream.ReadUI32(relative_time);
m_RelativeTime = relative_time;
// pbit and xbit
stream.ReadUI08(octet);
m_PBit = (octet & 0x20) != 0;
m_XBit = (octet & 0x10) != 0;
// mbit and payload type
stream.ReadUI08(octet);
m_MBit = (octet & 0x80) != 0;
m_PayloadType = octet & 0x7F;
// sequence seed
stream.ReadUI16(m_SequenceSeed);
// extra, bframe and repeat flags
stream.ReadUI08(octet);
stream.ReadUI08(octet); // repeat on purpose
bool extra_flag = (octet & 0x04) != 0;
// bframe and repeat flags
m_BFrameFlag = (octet & 0x02) != 0;
m_RepeatFlag = (octet & 0x01) != 0;
// constructor count
AP4_UI16 constructor_count;
stream.ReadUI16(constructor_count);
// parse the packet extra data
if (extra_flag) {
// read the length
AP4_UI32 extra_length;
stream.ReadUI32(extra_length);
// check it
if (extra_length < 4)
throw AP4_Exception(AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA);
// now read the entries
extra_length -= 4;
while (extra_length > 0) {
AP4_UI32 entry_length;
AP4_UI32 entry_tag;
stream.ReadUI32(entry_length);
stream.ReadUI32(entry_tag);
// check the entry
if (entry_length < 8) {
throw AP4_Exception(AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA);
}
// parse the single entry that's currently defined in the spec
if (entry_tag == AP4_ATOM_TYPE('r','t','p','o') && entry_length == 12) {
AP4_UI32 time_stamp_offset;
stream.ReadUI32(time_stamp_offset);
m_TimeStampOffset = time_stamp_offset;
} else {
// ignore it
AP4_Offset cur_pos;
stream.Tell(cur_pos);
stream.Seek(cur_pos + entry_length - 8); // 8 = length + tag
}
extra_length -= entry_length;
}
}
// constructors
for (AP4_UI16 i=0; i<constructor_count; i++) {
AP4_RtpConstructor* constructor = NULL;
AP4_RtpConstructorFactory::CreateConstructorFromStream(stream, constructor);
m_Constructors.Add(constructor);
}
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::AP4_RtpPacket
+---------------------------------------------------------------------*/
AP4_RtpPacket::~AP4_RtpPacket()
{
AP4_List<AP4_RtpConstructor>::Item* it = m_Constructors.FirstItem();
while (it != NULL) {
it->GetData()->Release();
it = it->GetNext();
}
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::AddReference
+---------------------------------------------------------------------*/
void
AP4_RtpPacket::AddReference()
{
m_ReferenceCount++;
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::Release
+---------------------------------------------------------------------*/
void
AP4_RtpPacket::Release()
{
if (--m_ReferenceCount == 0) {
delete this;
}
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::GetSize
+---------------------------------------------------------------------*/
AP4_Size
AP4_RtpPacket::GetSize()
{
AP4_Size result = 12 + (m_TimeStampOffset != 0)?16:0;
result += m_Constructors.ItemCount() * AP4_RTP_CONSTRUCTOR_SIZE;
return result;
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::Write
+---------------------------------------------------------------------*/
AP4_Result
AP4_RtpPacket::Write(AP4_ByteStream& stream)
{
// check the payload type
if (m_PayloadType > 128) return AP4_FAILURE;
// now write
AP4_Result result = stream.WriteUI32(m_RelativeTime);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI08(0x80 | m_PBit << 5 | m_XBit << 4);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI08(m_MBit << 7 | m_PayloadType);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI16(m_SequenceSeed);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI08(0);
if (AP4_FAILED(result)) return result;
// deal with extra flag
bool extra_flag = m_TimeStampOffset != 0;
result = stream.WriteUI08(0x00 | extra_flag << 2
| m_BFrameFlag << 1
| m_RepeatFlag << 0);
if (AP4_FAILED(result)) return result;
// constructor count
result = stream.WriteUI16(static_cast<AP4_UI16>(m_Constructors.ItemCount()));
// write extra data
if (extra_flag) {
// extra_length
result = stream.WriteUI32(16); // 4 (extra_length) + 12 (rtpo atom)
if (AP4_FAILED(result)) return result;
// rtpo atom
result = stream.WriteUI32(12); // size
if (AP4_FAILED(result)) return result;
result = stream.WriteUI32(AP4_ATOM_TYPE('r','t','p','o'));
if (AP4_FAILED(result)) return result;
result = stream.WriteUI32(m_TimeStampOffset);
if (AP4_FAILED(result)) return result;
}
// constructors
AP4_List<AP4_RtpConstructor>::Item* it = m_Constructors.FirstItem();
while (it != NULL) {
result = it->GetData()->Write(stream);
if (AP4_FAILED(result)) return result;
it = it->GetNext();
}
return result;
}
/*----------------------------------------------------------------------
| AP4_RtpPacket::AddConstructor
+---------------------------------------------------------------------*/
AP4_Result
AP4_RtpPacket::AddConstructor(AP4_RtpConstructor* constructor)
{
constructor->AddReference();
return m_Constructors.Add(constructor);
}
/*----------------------------------------------------------------------
| AP4_RtpConstructor::GetConstructedDataSize
+---------------------------------------------------------------------*/
AP4_Size
AP4_RtpPacket::GetConstructedDataSize()
{
// header + ssrc
AP4_Size size = 12;
// constructed data from constructors
AP4_List<AP4_RtpConstructor>::Item* constructors_it
= m_Constructors.FirstItem();
while (constructors_it != NULL) {
size += constructors_it->GetData()->GetConstructedDataSize();
constructors_it = constructors_it->GetNext();
}
return size;
}
/*----------------------------------------------------------------------
| AP4_RtpConstructor::AddReference
+---------------------------------------------------------------------*/
void
AP4_RtpConstructor::AddReference()
{
m_ReferenceCount++;
}
/*----------------------------------------------------------------------
| AP4_RtpConstructor::Release
+---------------------------------------------------------------------*/
void
AP4_RtpConstructor::Release()
{
if (--m_ReferenceCount == 0) {
delete this;
}
}
/*----------------------------------------------------------------------
| AP4_RtpConstructor::Write
+---------------------------------------------------------------------*/
AP4_Result
AP4_RtpConstructor::Write(AP4_ByteStream& stream)
{
AP4_Result result = stream.WriteUI08(m_Type);
if (AP4_FAILED(result)) return result;
return DoWrite(stream);
}
/*----------------------------------------------------------------------
| AP4_NoopRtpConstructor::AP4_NoopRtpConstructor
+---------------------------------------------------------------------*/
AP4_NoopRtpConstructor::AP4_NoopRtpConstructor(AP4_ByteStream& stream) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_NOOP)
{
AP4_Offset cur_offset;
stream.Tell(cur_offset);
stream.Seek(cur_offset+15);
}
/*----------------------------------------------------------------------
| AP4_NoopRtpConstructor::DoWrite
+---------------------------------------------------------------------*/
AP4_Result
AP4_NoopRtpConstructor::DoWrite(AP4_ByteStream& stream)
{
AP4_UI08 pad[15];
return stream.Write(pad, sizeof(pad));
}
/*----------------------------------------------------------------------
| AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor
+---------------------------------------------------------------------*/
AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor(const AP4_DataBuffer& data) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE),
m_Data(data)
{}
/*----------------------------------------------------------------------
| AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor
+---------------------------------------------------------------------*/
AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor(AP4_ByteStream& stream) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE)
{
AP4_Offset cur_offset;
stream.Tell(cur_offset);
// data
AP4_UI08 data_size;
stream.ReadUI08(data_size);
m_Data.SetDataSize(data_size);
stream.Read(m_Data.UseData(), data_size);
// reposition the stream
stream.Seek(cur_offset+15);
}
/*----------------------------------------------------------------------
| AP4_ImmediateRtpConstructor::DoWrite
+---------------------------------------------------------------------*/
AP4_Result
AP4_ImmediateRtpConstructor::DoWrite(AP4_ByteStream& stream)
{
// first check that the data is not too large
if (m_Data.GetDataSize() > 14) return AP4_FAILURE;
// now write
AP4_Result result = stream.WriteUI08(static_cast<AP4_UI08>(m_Data.GetDataSize()));
if (AP4_FAILED(result)) return result;
result = stream.Write(m_Data.GetData(), m_Data.GetDataSize());
if (AP4_FAILED(result)) return result;
// pad
AP4_Byte pad[14];
return stream.Write(pad, sizeof(pad)-m_Data.GetDataSize());
}
/*----------------------------------------------------------------------
| AP4_SampleRtpConstructor::AP4_SampleRtpConstructor
+---------------------------------------------------------------------*/
AP4_SampleRtpConstructor::AP4_SampleRtpConstructor(AP4_UI08 track_ref_index,
AP4_UI16 length,
AP4_UI32 sample_num,
AP4_UI32 sample_offset) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE),
m_TrackRefIndex(track_ref_index),
m_Length(length),
m_SampleNum(sample_num),
m_SampleOffset(sample_offset)
{}
/*----------------------------------------------------------------------
| AP4_SampleRtpConstructor::AP4_SampleRtpConstructor
+---------------------------------------------------------------------*/
AP4_SampleRtpConstructor::AP4_SampleRtpConstructor(AP4_ByteStream& stream) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE)
{
// offset
AP4_Offset cur_offset;
stream.Tell(cur_offset);
// data
stream.ReadUI08(m_TrackRefIndex);
stream.ReadUI16(m_Length);
stream.ReadUI32(m_SampleNum);
stream.ReadUI32(m_SampleOffset);
// reposition the stream
stream.Seek(cur_offset+15);
}
/*----------------------------------------------------------------------
| AP4_SampleRtpConstructor::DoWrite
+---------------------------------------------------------------------*/
AP4_Result
AP4_SampleRtpConstructor::DoWrite(AP4_ByteStream& stream)
{
AP4_Result result = stream.WriteUI08(m_TrackRefIndex);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI16(m_Length);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI32(m_SampleNum);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI32(m_SampleOffset);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI16(1); // bytes per block
if (AP4_FAILED(result)) return result;
return stream.WriteUI16(1); // samples per block
}
/*----------------------------------------------------------------------
| AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor
+---------------------------------------------------------------------*/
AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor(AP4_UI08 track_ref_index,
AP4_UI16 length,
AP4_UI32 sample_desc_index,
AP4_UI32 sample_desc_offset) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC),
m_TrackRefIndex(track_ref_index),
m_Length(length),
m_SampleDescIndex(sample_desc_index),
m_SampleDescOffset(sample_desc_offset)
{}
/*----------------------------------------------------------------------
| AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor
+---------------------------------------------------------------------*/
AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor(AP4_ByteStream& stream) :
AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC)
{
// offset
AP4_Offset cur_offset;
stream.Tell(cur_offset);
// data
stream.ReadUI08(m_TrackRefIndex);
stream.ReadUI16(m_Length);
stream.ReadUI32(m_SampleDescIndex);
stream.ReadUI32(m_SampleDescOffset);
// reposition the stream
stream.Seek(cur_offset+15);
}
/*----------------------------------------------------------------------
| AP4_SampleDescRtpConstructor::DoWrite
+---------------------------------------------------------------------*/
AP4_Result
AP4_SampleDescRtpConstructor::DoWrite(AP4_ByteStream& stream)
{
AP4_Result result = stream.WriteUI08(m_TrackRefIndex);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI16(m_Length);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI32(m_SampleDescIndex);
if (AP4_FAILED(result)) return result;
result = stream.WriteUI32(m_SampleDescOffset);
if (AP4_FAILED(result)) return result;
return stream.WriteUI32(0); // reserved
}
/*----------------------------------------------------------------------
| AP4_RtpConstructorFactory::CreateConstructorFromStream
+---------------------------------------------------------------------*/
AP4_Result
AP4_RtpConstructorFactory::CreateConstructorFromStream(AP4_ByteStream& stream,
AP4_RtpConstructor*& constructor)
{
// read the first byte (type)
AP4_RtpConstructor::Type type;
AP4_Result result = stream.ReadUI08(type);
if (AP4_FAILED(result)) return result;
switch(type) {
case AP4_RTP_CONSTRUCTOR_TYPE_NOOP:
constructor = new AP4_NoopRtpConstructor(stream);
break;
case AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE:
constructor = new AP4_ImmediateRtpConstructor(stream);
break;
case AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE:
constructor = new AP4_SampleRtpConstructor(stream);
break;
case AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC:
constructor = new AP4_SampleDescRtpConstructor(stream);
break;
default:
return AP4_ERROR_INVALID_RTP_CONSTRUCTOR_TYPE;
}
return AP4_SUCCESS;
}
↑ V502 Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a lower priority than the '+' operator.
↑ V614 Uninitialized buffer 'pad' used. Consider checking the first actual argument of the 'Write' function.
↑ V614 Uninitialized buffer 'pad' used. Consider checking the first actual argument of the 'Write' function.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_Constructors.