OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/protocol/rtp_utils.h" | 5 #include "remoting/protocol/rtp_utils.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "third_party/libjingle/source/talk/base/byteorder.h" | 8 #include "third_party/libjingle/source/talk/base/byteorder.h" |
9 | 9 |
10 using talk_base::GetBE16; | 10 using talk_base::GetBE16; |
11 using talk_base::GetBE32; | 11 using talk_base::GetBE32; |
12 using talk_base::SetBE16; | 12 using talk_base::SetBE16; |
13 using talk_base::SetBE32; | 13 using talk_base::SetBE32; |
14 | 14 |
15 namespace remoting { | 15 namespace remoting { |
16 namespace protocol { | 16 namespace protocol { |
17 | 17 |
18 namespace { | 18 namespace { |
19 const int kRtpBaseHeaderSize = 12; | 19 const int kRtpBaseHeaderSize = 12; |
20 const uint8 kRtpVersionNumber = 2; | 20 const uint8 kRtpVersionNumber = 2; |
21 const int kRtpMaxSources = 16; | 21 const int kRtpMaxSources = 16; |
| 22 const int kBytesPerCSRC = 4; |
22 } // namespace | 23 } // namespace |
23 | 24 |
24 int GetRtpHeaderSize(int sources) { | 25 static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) { |
25 DCHECK_GE(sources, 0); | 26 return (byte >> shift) & ((1 << bits_count) - 1); |
26 DCHECK_LT(sources, kRtpMaxSources); | |
27 return kRtpBaseHeaderSize + sources * 4; | |
28 } | 27 } |
29 | 28 |
30 void PackRtpHeader(uint8* buffer, int buffer_size, | 29 // RTP Header format: |
31 const RtpHeader& header) { | 30 // |
| 31 // 0 1 2 3 |
| 32 // 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 |
| 33 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 34 // |V=2|P|X| CC |M| PT | sequence number | |
| 35 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 36 // | timestamp | |
| 37 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 38 // | synchronization source (SSRC) identifier | |
| 39 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| 40 // | contributing source (CSRC) identifiers | |
| 41 // | .... | |
| 42 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| 43 // |
| 44 // On the diagram above order of bytes and order of bits within each |
| 45 // byte are big-endian. So bits 0 and 7 are the most and the least |
| 46 // significant bits in the first byte, bit 8 is the most significant |
| 47 // bit in the second byte, etc. |
| 48 |
| 49 int GetRtpHeaderSize(const RtpHeader& header) { |
| 50 DCHECK_GE(header.sources, 0); |
| 51 DCHECK_LT(header.sources, kRtpMaxSources); |
| 52 return kRtpBaseHeaderSize + header.sources * kBytesPerCSRC; |
| 53 } |
| 54 |
| 55 void PackRtpHeader(const RtpHeader& header, uint8* buffer, int buffer_size) { |
32 DCHECK_LT(header.sources, kRtpMaxSources); | 56 DCHECK_LT(header.sources, kRtpMaxSources); |
33 DCHECK_LT(header.payload_type, 1 << 7); | 57 DCHECK_LT(header.payload_type, 1 << 7); |
34 CHECK_GT(buffer_size, GetRtpHeaderSize(header.sources)); | 58 CHECK_GE(buffer_size, GetRtpHeaderSize(header)); |
35 | 59 |
36 buffer[0] = (kRtpVersionNumber << 6) + | 60 buffer[0] = (kRtpVersionNumber << 6) | |
37 ((uint8)header.padding << 5) + | 61 ((uint8)header.padding << 5) | |
38 ((uint8)header.extension << 4) + | 62 ((uint8)header.extension << 4) | |
39 header.sources; | 63 header.sources; |
40 buffer[1] = ((uint8)header.marker << 7) + | 64 buffer[1] = ((uint8)header.marker << 7) | |
41 header.payload_type; | 65 header.payload_type; |
42 SetBE16(buffer + 2, header.sequence_number); | 66 SetBE16(buffer + 2, header.sequence_number); |
43 SetBE32(buffer + 4, header.timestamp); | 67 SetBE32(buffer + 4, header.timestamp); |
44 SetBE32(buffer + 8, header.sync_source_id); | 68 SetBE32(buffer + 8, header.sync_source_id); |
45 | 69 |
46 for (int i = 0; i < header.sources; i++) { | 70 for (int i = 0; i < header.sources; i++) { |
47 SetBE32(buffer + i * 4 + 12, header.source_id[i]); | 71 SetBE32(buffer + i * 4 + 12, header.source_id[i]); |
48 } | 72 } |
49 } | 73 } |
50 | 74 |
51 static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) { | |
52 return (byte >> shift) & ((1 << bits_count) - 1); | |
53 } | |
54 | |
55 int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) { | 75 int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) { |
56 if (buffer_size < kRtpBaseHeaderSize) { | 76 if (buffer_size < kRtpBaseHeaderSize) { |
57 return -1; | 77 return -1; |
58 } | 78 } |
59 | 79 |
60 int version = ExtractBits(buffer[0], 2, 6); | 80 int version = ExtractBits(buffer[0], 2, 6); |
61 if (version != kRtpVersionNumber) { | 81 if (version != kRtpVersionNumber) { |
62 return -1; | 82 return -1; |
63 } | 83 } |
64 | 84 |
65 header->padding = ExtractBits(buffer[0], 1, 5) != 0; | 85 header->padding = ExtractBits(buffer[0], 1, 5) != 0; |
66 header->extension = ExtractBits(buffer[0], 1, 4) != 0; | 86 header->extension = ExtractBits(buffer[0], 1, 4) != 0; |
67 header->sources = ExtractBits(buffer[0], 4, 0); | 87 header->sources = ExtractBits(buffer[0], 4, 0); |
68 | 88 |
69 header->marker = ExtractBits(buffer[1], 1, 7) != 0; | 89 header->marker = ExtractBits(buffer[1], 1, 7) != 0; |
70 header->payload_type = ExtractBits(buffer[1], 7, 0); | 90 header->payload_type = ExtractBits(buffer[1], 7, 0); |
71 | 91 |
72 header->sequence_number = GetBE16(buffer + 2); | 92 header->sequence_number = GetBE16(buffer + 2); |
73 header->timestamp = GetBE32(buffer + 4); | 93 header->timestamp = GetBE32(buffer + 4); |
74 header->sync_source_id = GetBE32(buffer + 8); | 94 header->sync_source_id = GetBE32(buffer + 8); |
75 | 95 |
76 DCHECK_LT(header->sources, 16); | 96 DCHECK_LT(header->sources, 16); |
77 | 97 |
78 if (buffer_size < GetRtpHeaderSize(header->sources)) { | 98 if (buffer_size < GetRtpHeaderSize(*header)) { |
79 return -1; | 99 return -1; |
80 } | 100 } |
81 for (int i = 0; i < header->sources; i++) { | 101 for (int i = 0; i < header->sources; i++) { |
82 header->source_id[i] = GetBE32(buffer + i * 4 + 12); | 102 header->source_id[i] = GetBE32(buffer + i * 4 + 12); |
83 } | 103 } |
84 | 104 |
85 return GetRtpHeaderSize(header->sources); | 105 return GetRtpHeaderSize(*header); |
| 106 } |
| 107 |
| 108 // VP8 Payload Descriptor format: |
| 109 // |
| 110 // 0 1 2 3 |
| 111 // 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 |
| 112 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 113 // | RSV |I|N|FI |B| PictureID (integer #bytes) | |
| 114 // +-+-+-+-+-+-+-+-+ | |
| 115 // : : |
| 116 // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 117 // | : (VP8 data or VP8 payload header; byte aligned)| |
| 118 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 119 // |
| 120 // On the diagram above order of bytes and order of bits within each |
| 121 // byte are big-endian. So bits 0 and 7 are the most and the least |
| 122 // significant bits in the first byte, bit 8 is the most significant |
| 123 // bit in the second byte, etc. |
| 124 // |
| 125 // RSV: 3 bits |
| 126 // Bits reserved for future use. MUST be equal to zero and MUST be |
| 127 // ignored by the receiver. |
| 128 // |
| 129 // I: 1 bit |
| 130 // PictureID present. When set to one, a PictureID is provided after |
| 131 // the first byte of the payload descriptor. When set to zero, the |
| 132 // PictureID is omitted, and the one-byte payload descriptor is |
| 133 // immediately followed by the VP8 payload. |
| 134 // |
| 135 // N: 1 bit |
| 136 // Non-reference frame. When set to one, the frame can be discarded |
| 137 // without affecting any other future or past frames. |
| 138 // |
| 139 // FI: 2 bits |
| 140 // Fragmentation information field. This field contains information |
| 141 // about the fragmentation of VP8 payloads carried in the RTP |
| 142 // packet. The four different values are listed below. |
| 143 // |
| 144 // FI Fragmentation status |
| 145 // 00 The RTP packet contains no fragmented VP8 partitions. The |
| 146 // payload is one or several complete partitions. |
| 147 // 01 The RTP packet contains the first part of a fragmented |
| 148 // partition. The fragment must be placed in its own RTP packet. |
| 149 // 10 The RTP packet contains a fragment that is neither the first nor |
| 150 // the last part of a fragmented partition. The fragment must be |
| 151 // placed in its own RTP packet. |
| 152 // 11 The RTP packet contains the last part of a fragmented |
| 153 // partition. The fragment must be placed in its own RTP packet. |
| 154 // |
| 155 // B: 1 bit |
| 156 // Beginning VP8 frame. When set to 1 this signals that a new VP8 |
| 157 // frame starts in this RTP packet. |
| 158 // |
| 159 // PictureID: Multiple of 8 bits |
| 160 // This is a running index of the frames. The field is present only if |
| 161 // the I bit is equal to one. The most significant bit of each byte is |
| 162 // an extension flag. The 7 following bits carry (parts of) the |
| 163 // PictureID. If the extension flag is one, the PictureID continues in |
| 164 // the next byte. If the extension flag is zero, the 7 remaining bits |
| 165 // are the last (and least significant) bits in the PictureID. The |
| 166 // sender may choose any number of bytes for the PictureID. The |
| 167 // PictureID SHALL start on a random number, and SHALL wrap after |
| 168 // reaching the maximum ID as chosen by the application |
| 169 |
| 170 int GetVp8DescriptorSize(const Vp8Descriptor& descriptor) { |
| 171 if (descriptor.picture_id == kuint32max) |
| 172 return 1; |
| 173 int result = 2; |
| 174 // We need 1 byte per each 7 bits in picture_id. |
| 175 uint32 picture_id = descriptor.picture_id >> 7; |
| 176 while (picture_id > 0) { |
| 177 picture_id >>= 7; |
| 178 ++result; |
| 179 } |
| 180 return result; |
| 181 } |
| 182 |
| 183 void PackVp8Descriptor(const Vp8Descriptor& descriptor, uint8* buffer, |
| 184 int buffer_size) { |
| 185 CHECK_GT(buffer_size, 0); |
| 186 |
| 187 buffer[0] = |
| 188 ((uint8)(descriptor.picture_id != kuint32max) << 4) | |
| 189 ((uint8)descriptor.non_reference_frame << 3) | |
| 190 (descriptor.fragmentation_info << 1) | |
| 191 ((uint8)descriptor.frame_beginning); |
| 192 |
| 193 uint32 picture_id = descriptor.picture_id; |
| 194 if (picture_id == kuint32max) |
| 195 return; |
| 196 |
| 197 int pos = 1; |
| 198 while (picture_id > 0) { |
| 199 CHECK_LT(pos, buffer_size); |
| 200 buffer[pos] = picture_id & 0x7F; |
| 201 picture_id >>= 7; |
| 202 |
| 203 // Set the extension bit if neccessary. |
| 204 if (picture_id > 0) |
| 205 buffer[pos] |= 0x80; |
| 206 ++pos; |
| 207 } |
| 208 } |
| 209 |
| 210 int UnpackVp8Descriptor(const uint8* buffer, int buffer_size, |
| 211 Vp8Descriptor* descriptor) { |
| 212 if (buffer_size <= 0) |
| 213 return -1; |
| 214 |
| 215 bool picture_id_present = ExtractBits(buffer[0], 1, 4) != 0; |
| 216 descriptor->non_reference_frame = ExtractBits(buffer[0], 1, 3) != 0; |
| 217 descriptor->fragmentation_info = ExtractBits(buffer[0], 2, 1); |
| 218 descriptor->frame_beginning = ExtractBits(buffer[0], 1, 0) != 0; |
| 219 |
| 220 // Return here if we don't need to decode PictureID. |
| 221 if (!picture_id_present) { |
| 222 descriptor->picture_id = kuint32max; |
| 223 return 1; |
| 224 } |
| 225 |
| 226 // Decode PictureID. |
| 227 bool extension = true; |
| 228 int pos = 1; |
| 229 descriptor->picture_id = 0; |
| 230 while (extension) { |
| 231 if (pos >= buffer_size) |
| 232 return -1; |
| 233 |
| 234 descriptor->picture_id |= buffer[pos] & 0x7F; |
| 235 extension = (buffer[pos] & 0x80) != 0; |
| 236 pos += 1; |
| 237 } |
| 238 return pos; |
86 } | 239 } |
87 | 240 |
88 } // namespace protocol | 241 } // namespace protocol |
89 } // namespace remoting | 242 } // namespace remoting |
OLD | NEW |