blob: 75f01b12c73c4e62a4a8d6681596e9a64ad4d814 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "rtp_utility.h"
12
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <cassert>
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000014#include <cmath> // ceil
15#include <cstring> // memcpy
16
17#if defined(_WIN32)
18#include <Windows.h> // FILETIME
19#include <WinSock.h> // timeval
20#include <MMSystem.h> // timeGetTime
21#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
22#include <sys/time.h> // gettimeofday
23#include <time.h>
24#endif
25#if (defined(_DEBUG) && defined(_WIN32) && (_MSC_VER >= 1400))
26#include <stdio.h>
27#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000028
pwestin@webrtc.org18530052012-07-03 10:41:54 +000029#include "system_wrappers/interface/tick_util.h"
30#include "system_wrappers/interface/trace.h"
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +000031
niklase@google.com470e71d2011-07-07 08:21:25 +000032#if (defined(_DEBUG) && defined(_WIN32) && (_MSC_VER >= 1400))
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000033#define DEBUG_PRINT(...) \
34 { \
35 char msg[256]; \
36 sprintf(msg, __VA_ARGS__); \
niklase@google.com470e71d2011-07-07 08:21:25 +000037 OutputDebugString(msg); \
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000038 }
niklase@google.com470e71d2011-07-07 08:21:25 +000039#else
40// special fix for visual 2003
41#define DEBUG_PRINT(exp) ((void)0)
42#endif // defined(_DEBUG) && defined(_WIN32)
43
niklase@google.com470e71d2011-07-07 08:21:25 +000044namespace webrtc {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000045
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000046namespace ModuleRTPUtility {
47
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000048/*
49 * Time routines.
50 */
51
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000052WebRtc_UWord32 GetCurrentRTP(Clock* clock, WebRtc_UWord32 freq) {
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000053 const bool use_global_clock = (clock == NULL);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000054 Clock* local_clock = clock;
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000055 if (use_global_clock) {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000056 local_clock = Clock::GetRealTimeClock();
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000057 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000058 WebRtc_UWord32 secs = 0, frac = 0;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000059 local_clock->CurrentNtp(secs, frac);
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000060 if (use_global_clock) {
61 delete local_clock;
62 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000063 return ConvertNTPTimeToRTP(secs, frac, freq);
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000064}
65
66WebRtc_UWord32 ConvertNTPTimeToRTP(WebRtc_UWord32 NTPsec,
67 WebRtc_UWord32 NTPfrac,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000068 WebRtc_UWord32 freq) {
69 float ftemp = (float)NTPfrac / (float)NTP_FRAC;
70 WebRtc_UWord32 tmp = (WebRtc_UWord32)(ftemp * freq);
71 return NTPsec * freq + tmp;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000072}
73
74WebRtc_UWord32 ConvertNTPTimeToMS(WebRtc_UWord32 NTPsec,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000075 WebRtc_UWord32 NTPfrac) {
76 int freq = 1000;
77 float ftemp = (float)NTPfrac / (float)NTP_FRAC;
78 WebRtc_UWord32 tmp = (WebRtc_UWord32)(ftemp * freq);
79 WebRtc_UWord32 MStime = NTPsec * freq + tmp;
80 return MStime;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000081}
82
marpan@webrtc.org57353a32011-12-16 17:21:09 +000083bool OldTimestamp(uint32_t newTimestamp,
84 uint32_t existingTimestamp,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000085 bool* wrapped) {
86 bool tmpWrapped =
87 (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
88 (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
89 *wrapped = tmpWrapped;
90 if (existingTimestamp > newTimestamp && !tmpWrapped) {
91 return true;
92 } else if (existingTimestamp <= newTimestamp && !tmpWrapped) {
93 return false;
94 } else if (existingTimestamp < newTimestamp && tmpWrapped) {
95 return true;
96 } else {
97 return false;
98 }
marpan@webrtc.org57353a32011-12-16 17:21:09 +000099}
100
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000101/*
102 * Misc utility routines
103 */
104
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000105const WebRtc_UWord8* GetPayloadData(const WebRtcRTPHeader* rtp_header,
106 const WebRtc_UWord8* packet) {
107 return packet + rtp_header->header.headerLength;
108}
109
110WebRtc_UWord16 GetPayloadDataLength(const WebRtcRTPHeader* rtp_header,
111 const WebRtc_UWord16 packet_length) {
112 WebRtc_UWord16 length = packet_length - rtp_header->header.paddingLength -
113 rtp_header->header.headerLength;
114 return static_cast<WebRtc_UWord16>(length);
115}
116
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000117#if defined(_WIN32)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000118bool StringCompare(const char* str1, const char* str2,
119 const WebRtc_UWord32 length) {
120 return (_strnicmp(str1, str2, length) == 0) ? true : false;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000121}
122#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000123bool StringCompare(const char* str1, const char* str2,
124 const WebRtc_UWord32 length) {
125 return (strncasecmp(str1, str2, length) == 0) ? true : false;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000126}
127#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
129#if !defined(WEBRTC_LITTLE_ENDIAN) && !defined(WEBRTC_BIG_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000130#error Either WEBRTC_LITTLE_ENDIAN or WEBRTC_BIG_ENDIAN must be defined
niklase@google.com470e71d2011-07-07 08:21:25 +0000131#endif
132
133/* for RTP/RTCP
134 All integer fields are carried in network byte order, that is, most
135 significant byte (octet) first. AKA big-endian.
136*/
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000137void AssignUWord32ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord32 value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000138#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000139 dataBuffer[0] = static_cast<WebRtc_UWord8>(value >> 24);
140 dataBuffer[1] = static_cast<WebRtc_UWord8>(value >> 16);
141 dataBuffer[2] = static_cast<WebRtc_UWord8>(value >> 8);
142 dataBuffer[3] = static_cast<WebRtc_UWord8>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000144 WebRtc_UWord32* ptr = reinterpret_cast<WebRtc_UWord32*>(dataBuffer);
145 ptr[0] = value;
niklase@google.com470e71d2011-07-07 08:21:25 +0000146#endif
147}
148
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000149void AssignUWord24ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord32 value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000150#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000151 dataBuffer[0] = static_cast<WebRtc_UWord8>(value >> 16);
152 dataBuffer[1] = static_cast<WebRtc_UWord8>(value >> 8);
153 dataBuffer[2] = static_cast<WebRtc_UWord8>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000154#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000155 dataBuffer[0] = static_cast<WebRtc_UWord8>(value);
156 dataBuffer[1] = static_cast<WebRtc_UWord8>(value >> 8);
157 dataBuffer[2] = static_cast<WebRtc_UWord8>(value >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000158#endif
159}
160
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000161void AssignUWord16ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord16 value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000162#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000163 dataBuffer[0] = static_cast<WebRtc_UWord8>(value >> 8);
164 dataBuffer[1] = static_cast<WebRtc_UWord8>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000166 WebRtc_UWord16* ptr = reinterpret_cast<WebRtc_UWord16*>(dataBuffer);
167 ptr[0] = value;
niklase@google.com470e71d2011-07-07 08:21:25 +0000168#endif
169}
170
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000171WebRtc_UWord16 BufferToUWord16(const WebRtc_UWord8* dataBuffer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000172#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000173 return (dataBuffer[0] << 8) + dataBuffer[1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000174#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000175 return *reinterpret_cast<const WebRtc_UWord16*>(dataBuffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000176#endif
177}
178
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000179WebRtc_UWord32 BufferToUWord24(const WebRtc_UWord8* dataBuffer) {
180 return (dataBuffer[0] << 16) + (dataBuffer[1] << 8) + dataBuffer[2];
niklase@google.com470e71d2011-07-07 08:21:25 +0000181}
182
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000183WebRtc_UWord32 BufferToUWord32(const WebRtc_UWord8* dataBuffer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000184#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000185 return (dataBuffer[0] << 24) + (dataBuffer[1] << 16) + (dataBuffer[2] << 8) +
186 dataBuffer[3];
niklase@google.com470e71d2011-07-07 08:21:25 +0000187#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000188 return *reinterpret_cast<const WebRtc_UWord32*>(dataBuffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000189#endif
190}
191
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000192WebRtc_UWord32 pow2(WebRtc_UWord8 exp) {
193 return 1 << exp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194}
195
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000196void RTPPayload::SetType(RtpVideoCodecTypes videoType) {
197 type = videoType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000199 switch (type) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000200 case kRtpNoVideo:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000201 break;
202 case kRtpVp8Video: {
203 info.VP8.nonReferenceFrame = false;
204 info.VP8.beginningOfPartition = false;
205 info.VP8.partitionID = 0;
206 info.VP8.hasPictureID = false;
207 info.VP8.hasTl0PicIdx = false;
208 info.VP8.hasTID = false;
209 info.VP8.hasKeyIdx = false;
210 info.VP8.pictureID = -1;
211 info.VP8.tl0PicIdx = -1;
212 info.VP8.tID = -1;
213 info.VP8.layerSync = false;
214 info.VP8.frameWidth = 0;
215 info.VP8.frameHeight = 0;
216 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 }
218 default:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000219 break;
220 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000221}
222
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000223RTPHeaderParser::RTPHeaderParser(const WebRtc_UWord8* rtpData,
224 const WebRtc_UWord32 rtpDataLength)
225 : _ptrRTPDataBegin(rtpData),
226 _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000227}
228
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000229RTPHeaderParser::~RTPHeaderParser() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000230}
231
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000232bool RTPHeaderParser::RTCP() const {
233 // 72 to 76 is reserved for RTP
234 // 77 to 79 is not reserver but they are not assigned we will block them
235 // for RTCP 200 SR == marker bit + 72
236 // for RTCP 204 APP == marker bit + 76
237 /*
238 * RTCP
239 *
240 * FIR full INTRA-frame request 192 [RFC2032] supported
241 * NACK negative acknowledgement 193 [RFC2032]
242 * IJ Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff
243 * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
244 * SR sender report 200 [RFC3551] supported
245 * RR receiver report 201 [RFC3551] supported
246 * SDES source description 202 [RFC3551] supported
247 * BYE goodbye 203 [RFC3551] supported
248 * APP application-defined 204 [RFC3551] ignored
249 * RTPFB Transport layer FB message 205 [RFC4585] supported
250 * PSFB Payload-specific FB message 206 [RFC4585] supported
251 * XR extended report 207 [RFC3611] supported
252 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000254 /* 205 RFC 5104
255 * FMT 1 NACK supported
256 * FMT 2 reserved
257 * FMT 3 TMMBR supported
258 * FMT 4 TMMBN supported
259 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000261 /* 206 RFC 5104
262 * FMT 1: Picture Loss Indication (PLI) supported
263 * FMT 2: Slice Lost Indication (SLI)
264 * FMT 3: Reference Picture Selection Indication (RPSI)
265 * FMT 4: Full Intra Request (FIR) Command supported
266 * FMT 5: Temporal-Spatial Trade-off Request (TSTR)
267 * FMT 6: Temporal-Spatial Trade-off Notification (TSTN)
268 * FMT 7: Video Back Channel Message (VBCM)
269 * FMT 15: Application layer FB message
270 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000271
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000272 const WebRtc_UWord8 payloadType = _ptrRTPDataBegin[1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000274 bool RTCP = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000276 // check if this is a RTCP packet
277 switch (payloadType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 case 192:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000279 RTCP = true;
280 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 case 193:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000282 // not supported
283 // pass through and check for a potential RTP packet
284 break;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000285 case 195:
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 case 200:
287 case 201:
288 case 202:
289 case 203:
290 case 204:
291 case 205:
292 case 206:
293 case 207:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000294 RTCP = true;
295 break;
296 }
297 return RTCP;
niklase@google.com470e71d2011-07-07 08:21:25 +0000298}
299
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000300bool RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket,
301 RtpHeaderExtensionMap* ptrExtensionMap) const {
302 const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
niklase@google.com470e71d2011-07-07 08:21:25 +0000303
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000304 if (length < 12) {
305 return false;
306 }
307
308 // Version
309 const WebRtc_UWord8 V = _ptrRTPDataBegin[0] >> 6;
310 // Padding
311 const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
312 // eXtension
313 const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
314 const WebRtc_UWord8 CC = _ptrRTPDataBegin[0] & 0x0f;
315 const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
316
317 const WebRtc_UWord8 PT = _ptrRTPDataBegin[1] & 0x7f;
318
319 const WebRtc_UWord16 sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
320 _ptrRTPDataBegin[3];
321
322 const WebRtc_UWord8* ptr = &_ptrRTPDataBegin[4];
323
324 WebRtc_UWord32 RTPTimestamp = *ptr++ << 24;
325 RTPTimestamp += *ptr++ << 16;
326 RTPTimestamp += *ptr++ << 8;
327 RTPTimestamp += *ptr++;
328
329 WebRtc_UWord32 SSRC = *ptr++ << 24;
330 SSRC += *ptr++ << 16;
331 SSRC += *ptr++ << 8;
332 SSRC += *ptr++;
333
334 if (V != 2) {
335 return false;
336 }
337
338 const WebRtc_UWord8 CSRCocts = CC * 4;
339
340 if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
341 return false;
342 }
343
344 parsedPacket.header.markerBit = M;
345 parsedPacket.header.payloadType = PT;
346 parsedPacket.header.sequenceNumber = sequenceNumber;
347 parsedPacket.header.timestamp = RTPTimestamp;
348 parsedPacket.header.ssrc = SSRC;
349 parsedPacket.header.numCSRCs = CC;
350 parsedPacket.header.paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;
351
352 for (unsigned int i = 0; i < CC; ++i) {
353 WebRtc_UWord32 CSRC = *ptr++ << 24;
354 CSRC += *ptr++ << 16;
355 CSRC += *ptr++ << 8;
356 CSRC += *ptr++;
357 parsedPacket.header.arrOfCSRCs[i] = CSRC;
358 }
359 parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs;
360
361 parsedPacket.header.headerLength = 12 + CSRCocts;
362
363 // If in effect, MAY be omitted for those packets for which the offset
364 // is zero.
365 parsedPacket.extension.transmissionTimeOffset = 0;
366
367 if (X) {
368 /* RTP header extension, RFC 3550.
369 0 1 2 3
370 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
371 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 | defined by profile | length |
373 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 | header extension |
375 | .... |
376 */
377 const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
378 if (remain < 4) {
379 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 }
381
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000382 parsedPacket.header.headerLength += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000383
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000384 WebRtc_UWord16 definedByProfile = *ptr++ << 8;
385 definedByProfile += *ptr++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000386
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000387 WebRtc_UWord16 XLen = *ptr++ << 8;
388 XLen += *ptr++; // in 32 bit words
389 XLen *= 4; // in octs
niklase@google.com470e71d2011-07-07 08:21:25 +0000390
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000391 if (remain < (4 + XLen)) {
392 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000394 if (definedByProfile == RTP_ONE_BYTE_HEADER_EXTENSION) {
395 const WebRtc_UWord8* ptrRTPDataExtensionEnd = ptr + XLen;
396 ParseOneByteExtensionHeader(parsedPacket,
397 ptrExtensionMap,
398 ptrRTPDataExtensionEnd,
399 ptr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000401 parsedPacket.header.headerLength += XLen;
402 }
403 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000404}
405
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000406void RTPHeaderParser::ParseOneByteExtensionHeader(
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000407 WebRtcRTPHeader& parsedPacket,
408 const RtpHeaderExtensionMap* ptrExtensionMap,
409 const WebRtc_UWord8* ptrRTPDataExtensionEnd,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000410 const WebRtc_UWord8* ptr) const {
411 if (!ptrExtensionMap) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000412 return;
413 }
414
415 while (ptrRTPDataExtensionEnd - ptr > 0) {
416 // 0
417 // 0 1 2 3 4 5 6 7
418 // +-+-+-+-+-+-+-+-+
419 // | ID | len |
420 // +-+-+-+-+-+-+-+-+
421
422 const WebRtc_UWord8 id = (*ptr & 0xf0) >> 4;
423 const WebRtc_UWord8 len = (*ptr & 0x0f);
424 ptr++;
425
426 if (id == 15) {
427 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
428 "Ext id: 15 encountered, parsing terminated.");
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000429 return;
430 }
431
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000432 RTPExtensionType type;
433 if (ptrExtensionMap->GetType(id, &type) != 0) {
434 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
435 "Failed to find extension id: %d", id);
436 return;
437 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000438
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000439 switch (type) {
440 case kRtpExtensionTransmissionTimeOffset: {
441 if (len != 2) {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000442 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000443 "Incorrect transmission time offset len: %d", len);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000444 return;
445 }
446 // 0 1 2 3
447 // 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
448 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
449 // | ID | len=2 | transmission offset |
450 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
451
452 WebRtc_Word32 transmissionTimeOffset = *ptr++ << 16;
453 transmissionTimeOffset += *ptr++ << 8;
454 transmissionTimeOffset += *ptr++;
455 parsedPacket.extension.transmissionTimeOffset = transmissionTimeOffset;
asapersson@webrtc.orgd2e67792012-06-28 07:53:15 +0000456 if (transmissionTimeOffset & 0x800000) {
457 // Negative offset, correct sign for Word24 to Word32.
458 parsedPacket.extension.transmissionTimeOffset |= 0xFF000000;
459 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000460 break;
461 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000462 case kRtpExtensionAudioLevel: {
463 // --- Only used for debugging ---
464 // 0 1 2 3
465 // 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
466 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
467 // | ID | len=0 |V| level | 0x00 | 0x00 |
468 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
469 //
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000470
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000471 // Parse out the fields but only use it for debugging for now.
472 // const WebRtc_UWord8 V = (*ptr & 0x80) >> 7;
473 // const WebRtc_UWord8 level = (*ptr & 0x7f);
474 // DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u,
475 // level=%u", ID, len, V, level);
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +0000476 break;
477 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000478 default: {
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +0000479 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000480 "Extension type not implemented.");
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000481 return;
482 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000483 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000484 WebRtc_UWord8 num_bytes = ParsePaddingBytes(ptrRTPDataExtensionEnd, ptr);
485 ptr += num_bytes;
486 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000487}
488
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000489WebRtc_UWord8 RTPHeaderParser::ParsePaddingBytes(
490 const WebRtc_UWord8* ptrRTPDataExtensionEnd,
491 const WebRtc_UWord8* ptr) const {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000492
493 WebRtc_UWord8 num_zero_bytes = 0;
494 while (ptrRTPDataExtensionEnd - ptr > 0) {
495 if (*ptr != 0) {
496 return num_zero_bytes;
497 }
498 ptr++;
499 num_zero_bytes++;
500 }
501 return num_zero_bytes;
502}
503
niklase@google.com470e71d2011-07-07 08:21:25 +0000504// RTP payload parser
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000505RTPPayloadParser::RTPPayloadParser(const RtpVideoCodecTypes videoType,
506 const WebRtc_UWord8* payloadData,
507 WebRtc_UWord16 payloadDataLength,
508 WebRtc_Word32 id)
509 :
510 _id(id),
511 _dataPtr(payloadData),
512 _dataLength(payloadDataLength),
513 _videoType(videoType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000514}
515
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000516RTPPayloadParser::~RTPPayloadParser() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000517}
518
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000519bool RTPPayloadParser::Parse(RTPPayload& parsedPacket) const {
520 parsedPacket.SetType(_videoType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000521
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000522 switch (_videoType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000523 case kRtpNoVideo:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000524 return ParseGeneric(parsedPacket);
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 case kRtpVp8Video:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000526 return ParseVP8(parsedPacket);
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 default:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000528 return false;
529 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000530}
531
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000532bool RTPPayloadParser::ParseGeneric(RTPPayload& /*parsedPacket*/) const {
533 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000534}
535
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000536//
537// VP8 format:
538//
539// Payload descriptor
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000540// 0 1 2 3 4 5 6 7
541// +-+-+-+-+-+-+-+-+
542// |X|R|N|S|PartID | (REQUIRED)
543// +-+-+-+-+-+-+-+-+
544// X: |I|L|T|K| RSV | (OPTIONAL)
545// +-+-+-+-+-+-+-+-+
546// I: | PictureID | (OPTIONAL)
547// +-+-+-+-+-+-+-+-+
548// L: | TL0PICIDX | (OPTIONAL)
549// +-+-+-+-+-+-+-+-+
henrik.lundin@webrtc.orgeda86dc2011-12-13 14:11:06 +0000550// T/K: |TID:Y| KEYIDX | (OPTIONAL)
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000551// +-+-+-+-+-+-+-+-+
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000552//
553// Payload header (considered part of the actual payload, sent to decoder)
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000554// 0 1 2 3 4 5 6 7
555// +-+-+-+-+-+-+-+-+
556// |Size0|H| VER |P|
557// +-+-+-+-+-+-+-+-+
558// | ... |
559// + +
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000560
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000561bool RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const {
562 RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
563 const WebRtc_UWord8* dataPtr = _dataPtr;
564 int dataLength = _dataLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000565
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000566 // Parse mandatory first byte of payload descriptor
567 bool extension = (*dataPtr & 0x80) ? true : false; // X bit
568 vp8->nonReferenceFrame = (*dataPtr & 0x20) ? true : false; // N bit
569 vp8->beginningOfPartition = (*dataPtr & 0x10) ? true : false; // S bit
570 vp8->partitionID = (*dataPtr & 0x0F); // PartID field
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000571
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000572 if (vp8->partitionID > 8) {
573 // Weak check for corrupt data: PartID MUST NOT be larger than 8.
574 return false;
575 }
andrew@webrtc.org7fe219f2012-02-01 02:40:37 +0000576
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000577 // Advance dataPtr and decrease remaining payload size
578 dataPtr++;
579 dataLength--;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000580
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000581 if (extension) {
582 const int parsedBytes = ParseVP8Extension(vp8, dataPtr, dataLength);
583 if (parsedBytes < 0) return false;
584 dataPtr += parsedBytes;
585 dataLength -= parsedBytes;
586 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000587
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000588 if (dataLength <= 0) {
589 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
590 "Error parsing VP8 payload descriptor; payload too short");
591 return false;
592 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000593
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000594 // Read P bit from payload header (only at beginning of first partition)
595 if (dataLength > 0 && vp8->beginningOfPartition && vp8->partitionID == 0) {
596 parsedPacket.frameType = (*dataPtr & 0x01) ? kPFrame : kIFrame;
597 } else {
598 parsedPacket.frameType = kPFrame;
599 }
600 if (0 != ParseVP8FrameSize(parsedPacket, dataPtr, dataLength)) {
601 return false;
602 }
603 parsedPacket.info.VP8.data = dataPtr;
604 parsedPacket.info.VP8.dataLength = dataLength;
605 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000606}
607
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000608int RTPPayloadParser::ParseVP8FrameSize(RTPPayload& parsedPacket,
609 const WebRtc_UWord8* dataPtr,
610 int dataLength) const {
611 if (parsedPacket.frameType != kIFrame) {
612 // Included in payload header for I-frames.
pwestin@webrtc.org075e91f2011-11-02 23:14:58 +0000613 return 0;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000614 }
615 if (dataLength < 10) {
616 // For an I-frame we should always have the uncompressed VP8 header
617 // in the beginning of the partition.
618 return -1;
619 }
620 RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
621 vp8->frameWidth = ((dataPtr[7] << 8) + dataPtr[6]) & 0x3FFF;
622 vp8->frameHeight = ((dataPtr[9] << 8) + dataPtr[8]) & 0x3FFF;
623 return 0;
pwestin@webrtc.org075e91f2011-11-02 23:14:58 +0000624}
625
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000626int RTPPayloadParser::ParseVP8Extension(RTPPayloadVP8* vp8,
627 const WebRtc_UWord8* dataPtr,
628 int dataLength) const {
629 int parsedBytes = 0;
630 if (dataLength <= 0) return -1;
631 // Optional X field is present
632 vp8->hasPictureID = (*dataPtr & 0x80) ? true : false; // I bit
633 vp8->hasTl0PicIdx = (*dataPtr & 0x40) ? true : false; // L bit
634 vp8->hasTID = (*dataPtr & 0x20) ? true : false; // T bit
635 vp8->hasKeyIdx = (*dataPtr & 0x10) ? true : false; // K bit
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000636
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000637 // Advance dataPtr and decrease remaining payload size
638 dataPtr++;
639 parsedBytes++;
640 dataLength--;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000641
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000642 if (vp8->hasPictureID) {
643 if (ParseVP8PictureID(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
644 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000645 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000646 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000647
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000648 if (vp8->hasTl0PicIdx) {
649 if (ParseVP8Tl0PicIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
650 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000651 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000652 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000653
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000654 if (vp8->hasTID || vp8->hasKeyIdx) {
655 if (ParseVP8TIDAndKeyIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
656 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000657 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000658 }
659 return parsedBytes;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000660}
661
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000662int RTPPayloadParser::ParseVP8PictureID(RTPPayloadVP8* vp8,
663 const WebRtc_UWord8** dataPtr,
664 int* dataLength,
665 int* parsedBytes) const {
666 if (*dataLength <= 0) return -1;
667 vp8->pictureID = (**dataPtr & 0x7F);
668 if (**dataPtr & 0x80) {
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000669 (*dataPtr)++;
670 (*parsedBytes)++;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000671 if (--(*dataLength) <= 0) return -1;
672 // PictureID is 15 bits
673 vp8->pictureID = (vp8->pictureID << 8) +** dataPtr;
674 }
675 (*dataPtr)++;
676 (*parsedBytes)++;
677 (*dataLength)--;
678 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000679}
680
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000681int RTPPayloadParser::ParseVP8Tl0PicIdx(RTPPayloadVP8* vp8,
682 const WebRtc_UWord8** dataPtr,
683 int* dataLength,
684 int* parsedBytes) const {
685 if (*dataLength <= 0) return -1;
686 vp8->tl0PicIdx = **dataPtr;
687 (*dataPtr)++;
688 (*parsedBytes)++;
689 (*dataLength)--;
690 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000691}
692
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000693int RTPPayloadParser::ParseVP8TIDAndKeyIdx(RTPPayloadVP8* vp8,
694 const WebRtc_UWord8** dataPtr,
695 int* dataLength,
696 int* parsedBytes) const {
697 if (*dataLength <= 0) return -1;
698 if (vp8->hasTID) {
699 vp8->tID = ((**dataPtr >> 6) & 0x03);
700 vp8->layerSync = (**dataPtr & 0x20) ? true : false; // Y bit
701 }
702 if (vp8->hasKeyIdx) {
703 vp8->keyIdx = (**dataPtr & 0x1F);
704 }
705 (*dataPtr)++;
706 (*parsedBytes)++;
707 (*dataLength)--;
708 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000709}
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000710
711} // namespace ModuleRTPUtility
712
713} // namespace webrtc