diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-16 01:53:07 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-16 01:53:07 +0000 |
commit | 6357e609331c79bda865ac4ec9301a3f0f59d9c7 (patch) | |
tree | 9008d83ee315f5ed9422e6b3cbe10e715707f5a7 /remoting/protocol/rtp_utils.cc | |
parent | b1081e5dde10ee027a3fc9dfa3781380fb9b49c1 (diff) | |
download | chromium_src-6357e609331c79bda865ac4ec9301a3f0f59d9c7.zip chromium_src-6357e609331c79bda865ac4ec9301a3f0f59d9c7.tar.gz chromium_src-6357e609331c79bda865ac4ec9301a3f0f59d9c7.tar.bz2 |
Packetizer/Depacketizer for RTP.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/4925001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66213 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/protocol/rtp_utils.cc')
-rw-r--r-- | remoting/protocol/rtp_utils.cc | 187 |
1 files changed, 170 insertions, 17 deletions
diff --git a/remoting/protocol/rtp_utils.cc b/remoting/protocol/rtp_utils.cc index 1337795..4075c7b 100644 --- a/remoting/protocol/rtp_utils.cc +++ b/remoting/protocol/rtp_utils.cc @@ -19,25 +19,49 @@ namespace { const int kRtpBaseHeaderSize = 12; const uint8 kRtpVersionNumber = 2; const int kRtpMaxSources = 16; +const int kBytesPerCSRC = 4; } // namespace -int GetRtpHeaderSize(int sources) { - DCHECK_GE(sources, 0); - DCHECK_LT(sources, kRtpMaxSources); - return kRtpBaseHeaderSize + sources * 4; +static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) { + return (byte >> shift) & ((1 << bits_count) - 1); +} + +// RTP Header format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P|X| CC |M| PT | sequence number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | synchronization source (SSRC) identifier | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | contributing source (CSRC) identifiers | +// | .... | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// On the diagram above order of bytes and order of bits within each +// byte are big-endian. So bits 0 and 7 are the most and the least +// significant bits in the first byte, bit 8 is the most significant +// bit in the second byte, etc. + +int GetRtpHeaderSize(const RtpHeader& header) { + DCHECK_GE(header.sources, 0); + DCHECK_LT(header.sources, kRtpMaxSources); + return kRtpBaseHeaderSize + header.sources * kBytesPerCSRC; } -void PackRtpHeader(uint8* buffer, int buffer_size, - const RtpHeader& header) { +void PackRtpHeader(const RtpHeader& header, uint8* buffer, int buffer_size) { DCHECK_LT(header.sources, kRtpMaxSources); DCHECK_LT(header.payload_type, 1 << 7); - CHECK_GT(buffer_size, GetRtpHeaderSize(header.sources)); + CHECK_GE(buffer_size, GetRtpHeaderSize(header)); - buffer[0] = (kRtpVersionNumber << 6) + - ((uint8)header.padding << 5) + - ((uint8)header.extension << 4) + + buffer[0] = (kRtpVersionNumber << 6) | + ((uint8)header.padding << 5) | + ((uint8)header.extension << 4) | header.sources; - buffer[1] = ((uint8)header.marker << 7) + + buffer[1] = ((uint8)header.marker << 7) | header.payload_type; SetBE16(buffer + 2, header.sequence_number); SetBE32(buffer + 4, header.timestamp); @@ -48,10 +72,6 @@ void PackRtpHeader(uint8* buffer, int buffer_size, } } -static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) { - return (byte >> shift) & ((1 << bits_count) - 1); -} - int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) { if (buffer_size < kRtpBaseHeaderSize) { return -1; @@ -75,14 +95,147 @@ int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) { DCHECK_LT(header->sources, 16); - if (buffer_size < GetRtpHeaderSize(header->sources)) { + if (buffer_size < GetRtpHeaderSize(*header)) { return -1; } for (int i = 0; i < header->sources; i++) { header->source_id[i] = GetBE32(buffer + i * 4 + 12); } - return GetRtpHeaderSize(header->sources); + return GetRtpHeaderSize(*header); +} + +// VP8 Payload Descriptor format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | RSV |I|N|FI |B| PictureID (integer #bytes) | +// +-+-+-+-+-+-+-+-+ | +// : : +// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | : (VP8 data or VP8 payload header; byte aligned)| +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// On the diagram above order of bytes and order of bits within each +// byte are big-endian. So bits 0 and 7 are the most and the least +// significant bits in the first byte, bit 8 is the most significant +// bit in the second byte, etc. +// +// RSV: 3 bits +// Bits reserved for future use. MUST be equal to zero and MUST be +// ignored by the receiver. +// +// I: 1 bit +// PictureID present. When set to one, a PictureID is provided after +// the first byte of the payload descriptor. When set to zero, the +// PictureID is omitted, and the one-byte payload descriptor is +// immediately followed by the VP8 payload. +// +// N: 1 bit +// Non-reference frame. When set to one, the frame can be discarded +// without affecting any other future or past frames. +// +// FI: 2 bits +// Fragmentation information field. This field contains information +// about the fragmentation of VP8 payloads carried in the RTP +// packet. The four different values are listed below. +// +// FI Fragmentation status +// 00 The RTP packet contains no fragmented VP8 partitions. The +// payload is one or several complete partitions. +// 01 The RTP packet contains the first part of a fragmented +// partition. The fragment must be placed in its own RTP packet. +// 10 The RTP packet contains a fragment that is neither the first nor +// the last part of a fragmented partition. The fragment must be +// placed in its own RTP packet. +// 11 The RTP packet contains the last part of a fragmented +// partition. The fragment must be placed in its own RTP packet. +// +// B: 1 bit +// Beginning VP8 frame. When set to 1 this signals that a new VP8 +// frame starts in this RTP packet. +// +// PictureID: Multiple of 8 bits +// This is a running index of the frames. The field is present only if +// the I bit is equal to one. The most significant bit of each byte is +// an extension flag. The 7 following bits carry (parts of) the +// PictureID. If the extension flag is one, the PictureID continues in +// the next byte. If the extension flag is zero, the 7 remaining bits +// are the last (and least significant) bits in the PictureID. The +// sender may choose any number of bytes for the PictureID. The +// PictureID SHALL start on a random number, and SHALL wrap after +// reaching the maximum ID as chosen by the application + +int GetVp8DescriptorSize(const Vp8Descriptor& descriptor) { + if (descriptor.picture_id == kuint32max) + return 1; + int result = 2; + // We need 1 byte per each 7 bits in picture_id. + uint32 picture_id = descriptor.picture_id >> 7; + while (picture_id > 0) { + picture_id >>= 7; + ++result; + } + return result; +} + +void PackVp8Descriptor(const Vp8Descriptor& descriptor, uint8* buffer, + int buffer_size) { + CHECK_GT(buffer_size, 0); + + buffer[0] = + ((uint8)(descriptor.picture_id != kuint32max) << 4) | + ((uint8)descriptor.non_reference_frame << 3) | + (descriptor.fragmentation_info << 1) | + ((uint8)descriptor.frame_beginning); + + uint32 picture_id = descriptor.picture_id; + if (picture_id == kuint32max) + return; + + int pos = 1; + while (picture_id > 0) { + CHECK_LT(pos, buffer_size); + buffer[pos] = picture_id & 0x7F; + picture_id >>= 7; + + // Set the extension bit if neccessary. + if (picture_id > 0) + buffer[pos] |= 0x80; + ++pos; + } +} + +int UnpackVp8Descriptor(const uint8* buffer, int buffer_size, + Vp8Descriptor* descriptor) { + if (buffer_size <= 0) + return -1; + + bool picture_id_present = ExtractBits(buffer[0], 1, 4) != 0; + descriptor->non_reference_frame = ExtractBits(buffer[0], 1, 3) != 0; + descriptor->fragmentation_info = ExtractBits(buffer[0], 2, 1); + descriptor->frame_beginning = ExtractBits(buffer[0], 1, 0) != 0; + + // Return here if we don't need to decode PictureID. + if (!picture_id_present) { + descriptor->picture_id = kuint32max; + return 1; + } + + // Decode PictureID. + bool extension = true; + int pos = 1; + descriptor->picture_id = 0; + while (extension) { + if (pos >= buffer_size) + return -1; + + descriptor->picture_id |= buffer[pos] & 0x7F; + extension = (buffer[pos] & 0x80) != 0; + pos += 1; + } + return pos; } } // namespace protocol |