Index: remoting/protocol/rtp_utils.cc |
diff --git a/remoting/protocol/rtp_utils.cc b/remoting/protocol/rtp_utils.cc |
index 133779511362ee6b579eda37a27b255662311373..c8f8c730a5c1d6506368d44d4c5fb26fd5603718 100644 |
--- a/remoting/protocol/rtp_utils.cc |
+++ b/remoting/protocol/rtp_utils.cc |
@@ -21,17 +21,35 @@ const uint8 kRtpVersionNumber = 2; |
const int kRtpMaxSources = 16; |
} // 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 | |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
awong
2010/11/16 01:08:40
nice diagram.:)
Sergey Ulanov
2010/11/16 01:52:25
I didn't draw it myself, it's from RTP spec :)
|
+// | contributing source (CSRC) identifiers | |
+// | .... | |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
+ |
+int GetRtpHeaderSize(const RtpHeader& header) { |
+ DCHECK_GE(header.sources, 0); |
+ DCHECK_LT(header.sources, kRtpMaxSources); |
+ return kRtpBaseHeaderSize + header.sources * 4; |
} |
-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) + |
@@ -48,10 +66,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 +89,137 @@ 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)| |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+// |
+// I: 1 bit |
Alpha Left Google
2010/11/15 23:46:35
Doesn't say what is RSV in the description.
Sergey Ulanov
2010/11/16 00:22:55
Done.
|
+// 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); |
Alpha Left Google
2010/11/15 23:46:35
don't use CHECK here.
Sergey Ulanov
2010/11/16 00:22:55
Why? I think, it is better to use CHECK here to pr
awong
2010/11/16 01:08:40
I think CHECK makes sense. allowing a negative si
|
+ |
+ buffer[0] = |
Alpha Left Google
2010/11/15 23:46:35
This doesn't seem to match the diagram above..
Fo
Sergey Ulanov
2010/11/16 00:22:55
B is frame_beginning. It is 7'th bit in the first
Alpha Left Google
2010/11/16 00:47:08
I see.. if this is the case this code won't work o
|
+ ((uint8)(descriptor.picture_id != kuint32max) << 4) + |
awong
2010/11/16 01:08:40
Since we're playing in bits, I'm personally happie
Sergey Ulanov
2010/11/16 01:52:25
Agree that | is better here. Fixed here and in Pac
|
+ ((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); |
Alpha Left Google
2010/11/15 23:46:35
and here.
Sergey Ulanov
2010/11/16 00:22:55
Same reason as above. The check is fairly cheap, a
|
+ buffer[pos] = picture_id & 0x7F; |
+ picture_id >>= 7; |
+ |
+ // Set the extension bit if neccessary. |
+ if (picture_id > 0) |
+ buffer[pos] |= 1 << 7; |
+ ++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; |
Alpha Left Google
2010/11/15 23:46:35
What about
= !!ExtractBits(...);
Sergey Ulanov
2010/11/16 00:22:55
IMHO, !=0 looks nicer, no?
|
+ descriptor->non_reference_frame = ExtractBits(buffer[0], 1, 3) != 0; |
Alpha Left Google
2010/11/15 23:46:35
ditto.
|
+ descriptor->fragmentation_info = ExtractBits(buffer[0], 2, 1); |
+ descriptor->frame_beginning = ExtractBits(buffer[0], 1, 0) != 0; |
Alpha Left Google
2010/11/15 23:46:35
ditto.
|
+ |
+ // Decode PictureID if it is present. |
+ if (picture_id_present) { |
+ 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; |
+ } else { |
+ descriptor->picture_id = kuint32max; |
+ return 1; |
+ } |
} |
} // namespace protocol |