Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(249)

Side by Side Diff: remoting/protocol/rtp_utils.cc

Issue 4925001: Packetizer/Depacketizer for RTP. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 } // namespace 22 } // namespace
23 23
24 int GetRtpHeaderSize(int sources) { 24 static inline uint8 ExtractBits(uint8 byte, int bits_count, int shift) {
25 DCHECK_GE(sources, 0); 25 return (byte >> shift) & ((1 << bits_count) - 1);
26 DCHECK_LT(sources, kRtpMaxSources);
27 return kRtpBaseHeaderSize + sources * 4;
28 } 26 }
29 27
30 void PackRtpHeader(uint8* buffer, int buffer_size, 28 // RTP Header format:
31 const RtpHeader& header) { 29 //
30 // 0 1 2 3
31 // 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
32 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 // |V=2|P|X| CC |M| PT | sequence number |
34 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 // | timestamp |
36 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 // | synchronization source (SSRC) identifier |
38 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
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 :)
39 // | contributing source (CSRC) identifiers |
40 // | .... |
41 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
42
43 int GetRtpHeaderSize(const RtpHeader& header) {
44 DCHECK_GE(header.sources, 0);
45 DCHECK_LT(header.sources, kRtpMaxSources);
46 return kRtpBaseHeaderSize + header.sources * 4;
47 }
48
49 void PackRtpHeader(const RtpHeader& header, uint8* buffer, int buffer_size) {
32 DCHECK_LT(header.sources, kRtpMaxSources); 50 DCHECK_LT(header.sources, kRtpMaxSources);
33 DCHECK_LT(header.payload_type, 1 << 7); 51 DCHECK_LT(header.payload_type, 1 << 7);
34 CHECK_GT(buffer_size, GetRtpHeaderSize(header.sources)); 52 CHECK_GE(buffer_size, GetRtpHeaderSize(header));
35 53
36 buffer[0] = (kRtpVersionNumber << 6) + 54 buffer[0] = (kRtpVersionNumber << 6) +
37 ((uint8)header.padding << 5) + 55 ((uint8)header.padding << 5) +
38 ((uint8)header.extension << 4) + 56 ((uint8)header.extension << 4) +
39 header.sources; 57 header.sources;
40 buffer[1] = ((uint8)header.marker << 7) + 58 buffer[1] = ((uint8)header.marker << 7) +
41 header.payload_type; 59 header.payload_type;
42 SetBE16(buffer + 2, header.sequence_number); 60 SetBE16(buffer + 2, header.sequence_number);
43 SetBE32(buffer + 4, header.timestamp); 61 SetBE32(buffer + 4, header.timestamp);
44 SetBE32(buffer + 8, header.sync_source_id); 62 SetBE32(buffer + 8, header.sync_source_id);
45 63
46 for (int i = 0; i < header.sources; i++) { 64 for (int i = 0; i < header.sources; i++) {
47 SetBE32(buffer + i * 4 + 12, header.source_id[i]); 65 SetBE32(buffer + i * 4 + 12, header.source_id[i]);
48 } 66 }
49 } 67 }
50 68
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) { 69 int UnpackRtpHeader(const uint8* buffer, int buffer_size, RtpHeader* header) {
56 if (buffer_size < kRtpBaseHeaderSize) { 70 if (buffer_size < kRtpBaseHeaderSize) {
57 return -1; 71 return -1;
58 } 72 }
59 73
60 int version = ExtractBits(buffer[0], 2, 6); 74 int version = ExtractBits(buffer[0], 2, 6);
61 if (version != kRtpVersionNumber) { 75 if (version != kRtpVersionNumber) {
62 return -1; 76 return -1;
63 } 77 }
64 78
65 header->padding = ExtractBits(buffer[0], 1, 5) != 0; 79 header->padding = ExtractBits(buffer[0], 1, 5) != 0;
66 header->extension = ExtractBits(buffer[0], 1, 4) != 0; 80 header->extension = ExtractBits(buffer[0], 1, 4) != 0;
67 header->sources = ExtractBits(buffer[0], 4, 0); 81 header->sources = ExtractBits(buffer[0], 4, 0);
68 82
69 header->marker = ExtractBits(buffer[1], 1, 7) != 0; 83 header->marker = ExtractBits(buffer[1], 1, 7) != 0;
70 header->payload_type = ExtractBits(buffer[1], 7, 0); 84 header->payload_type = ExtractBits(buffer[1], 7, 0);
71 85
72 header->sequence_number = GetBE16(buffer + 2); 86 header->sequence_number = GetBE16(buffer + 2);
73 header->timestamp = GetBE32(buffer + 4); 87 header->timestamp = GetBE32(buffer + 4);
74 header->sync_source_id = GetBE32(buffer + 8); 88 header->sync_source_id = GetBE32(buffer + 8);
75 89
76 DCHECK_LT(header->sources, 16); 90 DCHECK_LT(header->sources, 16);
77 91
78 if (buffer_size < GetRtpHeaderSize(header->sources)) { 92 if (buffer_size < GetRtpHeaderSize(*header)) {
79 return -1; 93 return -1;
80 } 94 }
81 for (int i = 0; i < header->sources; i++) { 95 for (int i = 0; i < header->sources; i++) {
82 header->source_id[i] = GetBE32(buffer + i * 4 + 12); 96 header->source_id[i] = GetBE32(buffer + i * 4 + 12);
83 } 97 }
84 98
85 return GetRtpHeaderSize(header->sources); 99 return GetRtpHeaderSize(*header);
100 }
101
102 // VP8 Payload Descriptor format:
103 //
104 // 0 1 2 3
105 // 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
106 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107 // | RSV |I|N|FI |B| PictureID (integer #bytes) |
108 // +-+-+-+-+-+-+-+-+ |
109 // : :
110 // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 // | : (VP8 data or VP8 payload header; byte aligned)|
112 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
113 //
114 // 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.
115 // PictureID present. When set to one, a PictureID is provided after
116 // the first byte of the payload descriptor. When set to zero, the
117 // PictureID is omitted, and the one-byte payload descriptor is
118 // immediately followed by the VP8 payload.
119 //
120 // N: 1 bit
121 // Non-reference frame. When set to one, the frame can be discarded
122 // without affecting any other future or past frames.
123 //
124 // FI: 2 bits
125 // Fragmentation information field. This field contains information
126 // about the fragmentation of VP8 payloads carried in the RTP
127 // packet. The four different values are listed below.
128 //
129 // FI Fragmentation status
130 // 00 The RTP packet contains no fragmented VP8 partitions. The
131 // payload is one or several complete partitions.
132 // 01 The RTP packet contains the first part of a fragmented
133 // partition. The fragment must be placed in its own RTP packet.
134 // 10 The RTP packet contains a fragment that is neither the first nor
135 // the last part of a fragmented partition. The fragment must be
136 // placed in its own RTP packet.
137 // 11 The RTP packet contains the last part of a fragmented
138 // partition. The fragment must be placed in its own RTP packet.
139 //
140 // B: 1 bit
141 // Beginning VP8 frame. When set to 1 this signals that a new VP8
142 // frame starts in this RTP packet.
143 //
144 // PictureID: Multiple of 8 bits
145 // This is a running index of the frames. The field is present only if
146 // the I bit is equal to one. The most significant bit of each byte is
147 // an extension flag. The 7 following bits carry (parts of) the
148 // PictureID. If the extension flag is one, the PictureID continues in
149 // the next byte. If the extension flag is zero, the 7 remaining bits
150 // are the last (and least significant) bits in the PictureID. The
151 // sender may choose any number of bytes for the PictureID. The
152 // PictureID SHALL start on a random number, and SHALL wrap after
153 // reaching the maximum ID as chosen by the application
154
155 int GetVp8DescriptorSize(const Vp8Descriptor& descriptor) {
156 if (descriptor.picture_id == kuint32max)
157 return 1;
158 int result = 2;
159 // We need 1 byte per each 7 bits in picture_id.
160 uint32 picture_id = descriptor.picture_id >> 7;
161 while (picture_id > 0) {
162 picture_id >>= 7;
163 ++result;
164 }
165 return result;
166 }
167
168 void PackVp8Descriptor(const Vp8Descriptor& descriptor, uint8* buffer,
169 int buffer_size) {
170 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
171
172 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
173 ((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
174 ((uint8)descriptor.non_reference_frame << 3) +
175 (descriptor.fragmentation_info << 1) +
176 ((uint8)descriptor.frame_beginning);
177
178 uint32 picture_id = descriptor.picture_id;
179 if (picture_id == kuint32max)
180 return;
181
182 int pos = 1;
183 while (picture_id > 0) {
184 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
185 buffer[pos] = picture_id & 0x7F;
186 picture_id >>= 7;
187
188 // Set the extension bit if neccessary.
189 if (picture_id > 0)
190 buffer[pos] |= 1 << 7;
191 ++pos;
192 }
193 }
194
195 int UnpackVp8Descriptor(const uint8* buffer, int buffer_size,
196 Vp8Descriptor* descriptor) {
197 if (buffer_size <= 0)
198 return -1;
199
200 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?
201 descriptor->non_reference_frame = ExtractBits(buffer[0], 1, 3) != 0;
Alpha Left Google 2010/11/15 23:46:35 ditto.
202 descriptor->fragmentation_info = ExtractBits(buffer[0], 2, 1);
203 descriptor->frame_beginning = ExtractBits(buffer[0], 1, 0) != 0;
Alpha Left Google 2010/11/15 23:46:35 ditto.
204
205 // Decode PictureID if it is present.
206 if (picture_id_present) {
207 bool extension = true;
208 int pos = 1;
209 descriptor->picture_id = 0;
210 while (extension) {
211 if (pos >= buffer_size)
212 return -1;
213
214 descriptor->picture_id |= buffer[pos] & 0x7F;
215 extension = (buffer[pos] & 0x80) != 0;
216 pos += 1;
217 }
218 return pos;
219 } else {
220 descriptor->picture_id = kuint32max;
221 return 1;
222 }
86 } 223 }
87 224
88 } // namespace protocol 225 } // namespace protocol
89 } // namespace remoting 226 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698