Index: remoting/protocol/rtp_utils.cc |
diff --git a/remoting/protocol/rtp_utils.cc b/remoting/protocol/rtp_utils.cc |
index 133779511362ee6b579eda37a27b255662311373..4075c7b6e5d01e56bdbfbc968fa87258966e6132 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 |