blob: c9af76ca69ab7036ebb82a990419937e47e8a0bc [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
solenberg@webrtc.orgd8a6e722013-03-26 14:02:30 +000048enum {
49 kRtcpMinHeaderLength = 4,
50 kRtcpExpectedVersion = 2
51};
52
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000053/*
54 * Time routines.
55 */
56
pbos@webrtc.org2f446732013-04-08 11:08:41 +000057uint32_t GetCurrentRTP(Clock* clock, uint32_t freq) {
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000058 const bool use_global_clock = (clock == NULL);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000059 Clock* local_clock = clock;
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000060 if (use_global_clock) {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000061 local_clock = Clock::GetRealTimeClock();
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000062 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +000063 uint32_t secs = 0, frac = 0;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000064 local_clock->CurrentNtp(secs, frac);
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000065 if (use_global_clock) {
66 delete local_clock;
67 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000068 return ConvertNTPTimeToRTP(secs, frac, freq);
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000069}
70
pbos@webrtc.org2f446732013-04-08 11:08:41 +000071uint32_t ConvertNTPTimeToRTP(uint32_t NTPsec, uint32_t NTPfrac, uint32_t freq) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000072 float ftemp = (float)NTPfrac / (float)NTP_FRAC;
pbos@webrtc.org2f446732013-04-08 11:08:41 +000073 uint32_t tmp = (uint32_t)(ftemp * freq);
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000074 return NTPsec * freq + tmp;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000075}
76
pbos@webrtc.org2f446732013-04-08 11:08:41 +000077uint32_t ConvertNTPTimeToMS(uint32_t NTPsec, uint32_t NTPfrac) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000078 int freq = 1000;
79 float ftemp = (float)NTPfrac / (float)NTP_FRAC;
pbos@webrtc.org2f446732013-04-08 11:08:41 +000080 uint32_t tmp = (uint32_t)(ftemp * freq);
81 uint32_t MStime = NTPsec * freq + tmp;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000082 return MStime;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000083}
84
marpan@webrtc.org57353a32011-12-16 17:21:09 +000085bool OldTimestamp(uint32_t newTimestamp,
86 uint32_t existingTimestamp,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000087 bool* wrapped) {
88 bool tmpWrapped =
89 (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
90 (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
91 *wrapped = tmpWrapped;
92 if (existingTimestamp > newTimestamp && !tmpWrapped) {
93 return true;
94 } else if (existingTimestamp <= newTimestamp && !tmpWrapped) {
95 return false;
96 } else if (existingTimestamp < newTimestamp && tmpWrapped) {
97 return true;
98 } else {
99 return false;
100 }
marpan@webrtc.org57353a32011-12-16 17:21:09 +0000101}
102
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000103/*
104 * Misc utility routines
105 */
106
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000107const uint8_t* GetPayloadData(const WebRtcRTPHeader* rtp_header,
108 const uint8_t* packet) {
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000109 return packet + rtp_header->header.headerLength;
110}
111
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000112uint16_t GetPayloadDataLength(const WebRtcRTPHeader* rtp_header,
113 const uint16_t packet_length) {
114 uint16_t length = packet_length - rtp_header->header.paddingLength -
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000115 rtp_header->header.headerLength;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000116 return static_cast<uint16_t>(length);
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000117}
118
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000119#if defined(_WIN32)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000120bool StringCompare(const char* str1, const char* str2,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000121 const uint32_t length) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000122 return (_strnicmp(str1, str2, length) == 0) ? true : false;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000123}
124#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000125bool StringCompare(const char* str1, const char* str2,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000126 const uint32_t length) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000127 return (strncasecmp(str1, str2, length) == 0) ? true : false;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000128}
129#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000130
131#if !defined(WEBRTC_LITTLE_ENDIAN) && !defined(WEBRTC_BIG_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000132#error Either WEBRTC_LITTLE_ENDIAN or WEBRTC_BIG_ENDIAN must be defined
niklase@google.com470e71d2011-07-07 08:21:25 +0000133#endif
134
135/* for RTP/RTCP
136 All integer fields are carried in network byte order, that is, most
137 significant byte (octet) first. AKA big-endian.
138*/
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000139void AssignUWord32ToBuffer(uint8_t* dataBuffer, uint32_t value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000140#if defined(WEBRTC_LITTLE_ENDIAN)
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000141 dataBuffer[0] = static_cast<uint8_t>(value >> 24);
142 dataBuffer[1] = static_cast<uint8_t>(value >> 16);
143 dataBuffer[2] = static_cast<uint8_t>(value >> 8);
144 dataBuffer[3] = static_cast<uint8_t>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000145#else
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000146 uint32_t* ptr = reinterpret_cast<uint32_t*>(dataBuffer);
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000147 ptr[0] = value;
niklase@google.com470e71d2011-07-07 08:21:25 +0000148#endif
149}
150
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000151void AssignUWord24ToBuffer(uint8_t* dataBuffer, uint32_t value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000152#if defined(WEBRTC_LITTLE_ENDIAN)
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000153 dataBuffer[0] = static_cast<uint8_t>(value >> 16);
154 dataBuffer[1] = static_cast<uint8_t>(value >> 8);
155 dataBuffer[2] = static_cast<uint8_t>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000156#else
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000157 dataBuffer[0] = static_cast<uint8_t>(value);
158 dataBuffer[1] = static_cast<uint8_t>(value >> 8);
159 dataBuffer[2] = static_cast<uint8_t>(value >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000160#endif
161}
162
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000163void AssignUWord16ToBuffer(uint8_t* dataBuffer, uint16_t value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000164#if defined(WEBRTC_LITTLE_ENDIAN)
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000165 dataBuffer[0] = static_cast<uint8_t>(value >> 8);
166 dataBuffer[1] = static_cast<uint8_t>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000167#else
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000168 uint16_t* ptr = reinterpret_cast<uint16_t*>(dataBuffer);
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000169 ptr[0] = value;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170#endif
171}
172
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000173uint16_t BufferToUWord16(const uint8_t* dataBuffer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000174#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000175 return (dataBuffer[0] << 8) + dataBuffer[1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000176#else
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000177 return *reinterpret_cast<const uint16_t*>(dataBuffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178#endif
179}
180
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000181uint32_t BufferToUWord24(const uint8_t* dataBuffer) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000182 return (dataBuffer[0] << 16) + (dataBuffer[1] << 8) + dataBuffer[2];
niklase@google.com470e71d2011-07-07 08:21:25 +0000183}
184
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000185uint32_t BufferToUWord32(const uint8_t* dataBuffer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000186#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000187 return (dataBuffer[0] << 24) + (dataBuffer[1] << 16) + (dataBuffer[2] << 8) +
188 dataBuffer[3];
niklase@google.com470e71d2011-07-07 08:21:25 +0000189#else
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000190 return *reinterpret_cast<const uint32_t*>(dataBuffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000191#endif
192}
193
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000194uint32_t pow2(uint8_t exp) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000195 return 1 << exp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000196}
197
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000198void RTPPayload::SetType(RtpVideoCodecTypes videoType) {
199 type = videoType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000200
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000201 switch (type) {
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000202 case kRtpGenericVideo:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000203 break;
204 case kRtpVp8Video: {
205 info.VP8.nonReferenceFrame = false;
206 info.VP8.beginningOfPartition = false;
207 info.VP8.partitionID = 0;
208 info.VP8.hasPictureID = false;
209 info.VP8.hasTl0PicIdx = false;
210 info.VP8.hasTID = false;
211 info.VP8.hasKeyIdx = false;
212 info.VP8.pictureID = -1;
213 info.VP8.tl0PicIdx = -1;
214 info.VP8.tID = -1;
215 info.VP8.layerSync = false;
216 info.VP8.frameWidth = 0;
217 info.VP8.frameHeight = 0;
218 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 }
220 default:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000221 break;
222 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000223}
224
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000225RTPHeaderParser::RTPHeaderParser(const uint8_t* rtpData,
226 const uint32_t rtpDataLength)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000227 : _ptrRTPDataBegin(rtpData),
228 _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000229}
230
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000231RTPHeaderParser::~RTPHeaderParser() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000232}
233
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000234bool RTPHeaderParser::RTCP() const {
235 // 72 to 76 is reserved for RTP
236 // 77 to 79 is not reserver but they are not assigned we will block them
237 // for RTCP 200 SR == marker bit + 72
238 // for RTCP 204 APP == marker bit + 76
239 /*
240 * RTCP
241 *
242 * FIR full INTRA-frame request 192 [RFC2032] supported
243 * NACK negative acknowledgement 193 [RFC2032]
244 * IJ Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff
245 * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
246 * SR sender report 200 [RFC3551] supported
247 * RR receiver report 201 [RFC3551] supported
248 * SDES source description 202 [RFC3551] supported
249 * BYE goodbye 203 [RFC3551] supported
250 * APP application-defined 204 [RFC3551] ignored
251 * RTPFB Transport layer FB message 205 [RFC4585] supported
252 * PSFB Payload-specific FB message 206 [RFC4585] supported
253 * XR extended report 207 [RFC3611] supported
254 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000255
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000256 /* 205 RFC 5104
257 * FMT 1 NACK supported
258 * FMT 2 reserved
259 * FMT 3 TMMBR supported
260 * FMT 4 TMMBN supported
261 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000263 /* 206 RFC 5104
264 * FMT 1: Picture Loss Indication (PLI) supported
265 * FMT 2: Slice Lost Indication (SLI)
266 * FMT 3: Reference Picture Selection Indication (RPSI)
267 * FMT 4: Full Intra Request (FIR) Command supported
268 * FMT 5: Temporal-Spatial Trade-off Request (TSTR)
269 * FMT 6: Temporal-Spatial Trade-off Notification (TSTN)
270 * FMT 7: Video Back Channel Message (VBCM)
271 * FMT 15: Application layer FB message
272 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
solenberg@webrtc.orgd8a6e722013-03-26 14:02:30 +0000274 const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
275 if (length < kRtcpMinHeaderLength) {
276 return false;
277 }
278
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000279 const uint8_t V = _ptrRTPDataBegin[0] >> 6;
solenberg@webrtc.orgd8a6e722013-03-26 14:02:30 +0000280 if (V != kRtcpExpectedVersion) {
281 return false;
282 }
283
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000284 const uint8_t payloadType = _ptrRTPDataBegin[1];
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000285 bool RTCP = false;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000286 switch (payloadType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 case 192:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000288 RTCP = true;
289 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 case 193:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000291 // not supported
292 // pass through and check for a potential RTP packet
293 break;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000294 case 195:
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 case 200:
296 case 201:
297 case 202:
298 case 203:
299 case 204:
300 case 205:
301 case 206:
302 case 207:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000303 RTCP = true;
304 break;
305 }
306 return RTCP;
niklase@google.com470e71d2011-07-07 08:21:25 +0000307}
308
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000309bool RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket,
310 RtpHeaderExtensionMap* ptrExtensionMap) const {
311 const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
niklase@google.com470e71d2011-07-07 08:21:25 +0000312
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000313 if (length < 12) {
314 return false;
315 }
316
317 // Version
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000318 const uint8_t V = _ptrRTPDataBegin[0] >> 6;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000319 // Padding
320 const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
321 // eXtension
322 const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000323 const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000324 const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
325
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000326 const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000327
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000328 const uint16_t sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000329 _ptrRTPDataBegin[3];
330
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000331 const uint8_t* ptr = &_ptrRTPDataBegin[4];
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000332
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000333 uint32_t RTPTimestamp = *ptr++ << 24;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000334 RTPTimestamp += *ptr++ << 16;
335 RTPTimestamp += *ptr++ << 8;
336 RTPTimestamp += *ptr++;
337
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000338 uint32_t SSRC = *ptr++ << 24;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000339 SSRC += *ptr++ << 16;
340 SSRC += *ptr++ << 8;
341 SSRC += *ptr++;
342
343 if (V != 2) {
344 return false;
345 }
346
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000347 const uint8_t CSRCocts = CC * 4;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000348
349 if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
350 return false;
351 }
352
353 parsedPacket.header.markerBit = M;
354 parsedPacket.header.payloadType = PT;
355 parsedPacket.header.sequenceNumber = sequenceNumber;
356 parsedPacket.header.timestamp = RTPTimestamp;
357 parsedPacket.header.ssrc = SSRC;
358 parsedPacket.header.numCSRCs = CC;
359 parsedPacket.header.paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;
360
361 for (unsigned int i = 0; i < CC; ++i) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000362 uint32_t CSRC = *ptr++ << 24;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000363 CSRC += *ptr++ << 16;
364 CSRC += *ptr++ << 8;
365 CSRC += *ptr++;
366 parsedPacket.header.arrOfCSRCs[i] = CSRC;
367 }
368 parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs;
369
370 parsedPacket.header.headerLength = 12 + CSRCocts;
371
372 // If in effect, MAY be omitted for those packets for which the offset
373 // is zero.
374 parsedPacket.extension.transmissionTimeOffset = 0;
375
376 if (X) {
377 /* RTP header extension, RFC 3550.
378 0 1 2 3
379 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
380 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381 | defined by profile | length |
382 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383 | header extension |
384 | .... |
385 */
386 const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
387 if (remain < 4) {
388 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 }
390
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000391 parsedPacket.header.headerLength += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000392
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000393 uint16_t definedByProfile = *ptr++ << 8;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000394 definedByProfile += *ptr++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000395
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000396 uint16_t XLen = *ptr++ << 8;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000397 XLen += *ptr++; // in 32 bit words
398 XLen *= 4; // in octs
niklase@google.com470e71d2011-07-07 08:21:25 +0000399
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000400 if (remain < (4 + XLen)) {
401 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000403 if (definedByProfile == RTP_ONE_BYTE_HEADER_EXTENSION) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000404 const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000405 ParseOneByteExtensionHeader(parsedPacket,
406 ptrExtensionMap,
407 ptrRTPDataExtensionEnd,
408 ptr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000410 parsedPacket.header.headerLength += XLen;
411 }
412 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000413}
414
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000415void RTPHeaderParser::ParseOneByteExtensionHeader(
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000416 WebRtcRTPHeader& parsedPacket,
417 const RtpHeaderExtensionMap* ptrExtensionMap,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000418 const uint8_t* ptrRTPDataExtensionEnd,
419 const uint8_t* ptr) const {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000420 if (!ptrExtensionMap) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000421 return;
422 }
423
424 while (ptrRTPDataExtensionEnd - ptr > 0) {
425 // 0
426 // 0 1 2 3 4 5 6 7
427 // +-+-+-+-+-+-+-+-+
428 // | ID | len |
429 // +-+-+-+-+-+-+-+-+
430
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000431 const uint8_t id = (*ptr & 0xf0) >> 4;
432 const uint8_t len = (*ptr & 0x0f);
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000433 ptr++;
434
435 if (id == 15) {
436 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
437 "Ext id: 15 encountered, parsing terminated.");
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000438 return;
439 }
440
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000441 RTPExtensionType type;
442 if (ptrExtensionMap->GetType(id, &type) != 0) {
443 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
444 "Failed to find extension id: %d", id);
445 return;
446 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000447
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000448 switch (type) {
449 case kRtpExtensionTransmissionTimeOffset: {
450 if (len != 2) {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000451 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000452 "Incorrect transmission time offset len: %d", len);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000453 return;
454 }
455 // 0 1 2 3
456 // 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
457 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458 // | ID | len=2 | transmission offset |
459 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000461 int32_t transmissionTimeOffset = *ptr++ << 16;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000462 transmissionTimeOffset += *ptr++ << 8;
463 transmissionTimeOffset += *ptr++;
464 parsedPacket.extension.transmissionTimeOffset = transmissionTimeOffset;
asapersson@webrtc.orgd2e67792012-06-28 07:53:15 +0000465 if (transmissionTimeOffset & 0x800000) {
466 // Negative offset, correct sign for Word24 to Word32.
467 parsedPacket.extension.transmissionTimeOffset |= 0xFF000000;
468 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000469 break;
470 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000471 case kRtpExtensionAudioLevel: {
472 // --- Only used for debugging ---
473 // 0 1 2 3
474 // 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
475 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
476 // | ID | len=0 |V| level | 0x00 | 0x00 |
477 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
478 //
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000479
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000480 // Parse out the fields but only use it for debugging for now.
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000481 // const uint8_t V = (*ptr & 0x80) >> 7;
482 // const uint8_t level = (*ptr & 0x7f);
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000483 // DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u,
484 // level=%u", ID, len, V, level);
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +0000485 break;
486 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000487 default: {
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +0000488 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000489 "Extension type not implemented.");
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000490 return;
491 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000492 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000493 uint8_t num_bytes = ParsePaddingBytes(ptrRTPDataExtensionEnd, ptr);
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000494 ptr += num_bytes;
495 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000496}
497
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000498uint8_t RTPHeaderParser::ParsePaddingBytes(
499 const uint8_t* ptrRTPDataExtensionEnd,
500 const uint8_t* ptr) const {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000501
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000502 uint8_t num_zero_bytes = 0;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000503 while (ptrRTPDataExtensionEnd - ptr > 0) {
504 if (*ptr != 0) {
505 return num_zero_bytes;
506 }
507 ptr++;
508 num_zero_bytes++;
509 }
510 return num_zero_bytes;
511}
512
niklase@google.com470e71d2011-07-07 08:21:25 +0000513// RTP payload parser
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000514RTPPayloadParser::RTPPayloadParser(const RtpVideoCodecTypes videoType,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000515 const uint8_t* payloadData,
516 uint16_t payloadDataLength,
517 int32_t id)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000518 :
519 _id(id),
520 _dataPtr(payloadData),
521 _dataLength(payloadDataLength),
522 _videoType(videoType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000523}
524
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000525RTPPayloadParser::~RTPPayloadParser() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000526}
527
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000528bool RTPPayloadParser::Parse(RTPPayload& parsedPacket) const {
529 parsedPacket.SetType(_videoType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000530
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000531 switch (_videoType) {
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000532 case kRtpGenericVideo:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000533 return ParseGeneric(parsedPacket);
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 case kRtpVp8Video:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000535 return ParseVP8(parsedPacket);
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 default:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000537 return false;
538 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000539}
540
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000541bool RTPPayloadParser::ParseGeneric(RTPPayload& /*parsedPacket*/) const {
542 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000543}
544
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000545//
546// VP8 format:
547//
548// Payload descriptor
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000549// 0 1 2 3 4 5 6 7
550// +-+-+-+-+-+-+-+-+
551// |X|R|N|S|PartID | (REQUIRED)
552// +-+-+-+-+-+-+-+-+
553// X: |I|L|T|K| RSV | (OPTIONAL)
554// +-+-+-+-+-+-+-+-+
555// I: | PictureID | (OPTIONAL)
556// +-+-+-+-+-+-+-+-+
557// L: | TL0PICIDX | (OPTIONAL)
558// +-+-+-+-+-+-+-+-+
henrik.lundin@webrtc.orgeda86dc2011-12-13 14:11:06 +0000559// T/K: |TID:Y| KEYIDX | (OPTIONAL)
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000560// +-+-+-+-+-+-+-+-+
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000561//
562// Payload header (considered part of the actual payload, sent to decoder)
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000563// 0 1 2 3 4 5 6 7
564// +-+-+-+-+-+-+-+-+
565// |Size0|H| VER |P|
566// +-+-+-+-+-+-+-+-+
567// | ... |
568// + +
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000569
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000570bool RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const {
571 RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000572 const uint8_t* dataPtr = _dataPtr;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000573 int dataLength = _dataLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000574
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000575 // Parse mandatory first byte of payload descriptor
576 bool extension = (*dataPtr & 0x80) ? true : false; // X bit
577 vp8->nonReferenceFrame = (*dataPtr & 0x20) ? true : false; // N bit
578 vp8->beginningOfPartition = (*dataPtr & 0x10) ? true : false; // S bit
579 vp8->partitionID = (*dataPtr & 0x0F); // PartID field
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000580
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000581 if (vp8->partitionID > 8) {
582 // Weak check for corrupt data: PartID MUST NOT be larger than 8.
583 return false;
584 }
andrew@webrtc.org7fe219f2012-02-01 02:40:37 +0000585
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000586 // Advance dataPtr and decrease remaining payload size
587 dataPtr++;
588 dataLength--;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000589
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000590 if (extension) {
591 const int parsedBytes = ParseVP8Extension(vp8, dataPtr, dataLength);
592 if (parsedBytes < 0) return false;
593 dataPtr += parsedBytes;
594 dataLength -= parsedBytes;
595 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000596
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000597 if (dataLength <= 0) {
598 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
599 "Error parsing VP8 payload descriptor; payload too short");
600 return false;
601 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000602
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000603 // Read P bit from payload header (only at beginning of first partition)
604 if (dataLength > 0 && vp8->beginningOfPartition && vp8->partitionID == 0) {
605 parsedPacket.frameType = (*dataPtr & 0x01) ? kPFrame : kIFrame;
606 } else {
607 parsedPacket.frameType = kPFrame;
608 }
609 if (0 != ParseVP8FrameSize(parsedPacket, dataPtr, dataLength)) {
610 return false;
611 }
612 parsedPacket.info.VP8.data = dataPtr;
613 parsedPacket.info.VP8.dataLength = dataLength;
614 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000615}
616
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000617int RTPPayloadParser::ParseVP8FrameSize(RTPPayload& parsedPacket,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000618 const uint8_t* dataPtr,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000619 int dataLength) const {
620 if (parsedPacket.frameType != kIFrame) {
621 // Included in payload header for I-frames.
pwestin@webrtc.org075e91f2011-11-02 23:14:58 +0000622 return 0;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000623 }
624 if (dataLength < 10) {
625 // For an I-frame we should always have the uncompressed VP8 header
626 // in the beginning of the partition.
627 return -1;
628 }
629 RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
630 vp8->frameWidth = ((dataPtr[7] << 8) + dataPtr[6]) & 0x3FFF;
631 vp8->frameHeight = ((dataPtr[9] << 8) + dataPtr[8]) & 0x3FFF;
632 return 0;
pwestin@webrtc.org075e91f2011-11-02 23:14:58 +0000633}
634
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000635int RTPPayloadParser::ParseVP8Extension(RTPPayloadVP8* vp8,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000636 const uint8_t* dataPtr,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000637 int dataLength) const {
638 int parsedBytes = 0;
639 if (dataLength <= 0) return -1;
640 // Optional X field is present
641 vp8->hasPictureID = (*dataPtr & 0x80) ? true : false; // I bit
642 vp8->hasTl0PicIdx = (*dataPtr & 0x40) ? true : false; // L bit
643 vp8->hasTID = (*dataPtr & 0x20) ? true : false; // T bit
644 vp8->hasKeyIdx = (*dataPtr & 0x10) ? true : false; // K bit
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000645
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000646 // Advance dataPtr and decrease remaining payload size
647 dataPtr++;
648 parsedBytes++;
649 dataLength--;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000650
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000651 if (vp8->hasPictureID) {
652 if (ParseVP8PictureID(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
653 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000654 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000655 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000656
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000657 if (vp8->hasTl0PicIdx) {
658 if (ParseVP8Tl0PicIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
659 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000660 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000661 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000662
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000663 if (vp8->hasTID || vp8->hasKeyIdx) {
664 if (ParseVP8TIDAndKeyIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
665 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000666 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000667 }
668 return parsedBytes;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000669}
670
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000671int RTPPayloadParser::ParseVP8PictureID(RTPPayloadVP8* vp8,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000672 const uint8_t** dataPtr,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000673 int* dataLength,
674 int* parsedBytes) const {
675 if (*dataLength <= 0) return -1;
676 vp8->pictureID = (**dataPtr & 0x7F);
677 if (**dataPtr & 0x80) {
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000678 (*dataPtr)++;
679 (*parsedBytes)++;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000680 if (--(*dataLength) <= 0) return -1;
681 // PictureID is 15 bits
682 vp8->pictureID = (vp8->pictureID << 8) +** dataPtr;
683 }
684 (*dataPtr)++;
685 (*parsedBytes)++;
686 (*dataLength)--;
687 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000688}
689
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000690int RTPPayloadParser::ParseVP8Tl0PicIdx(RTPPayloadVP8* vp8,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000691 const uint8_t** dataPtr,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000692 int* dataLength,
693 int* parsedBytes) const {
694 if (*dataLength <= 0) return -1;
695 vp8->tl0PicIdx = **dataPtr;
696 (*dataPtr)++;
697 (*parsedBytes)++;
698 (*dataLength)--;
699 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000700}
701
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000702int RTPPayloadParser::ParseVP8TIDAndKeyIdx(RTPPayloadVP8* vp8,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000703 const uint8_t** dataPtr,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000704 int* dataLength,
705 int* parsedBytes) const {
706 if (*dataLength <= 0) return -1;
707 if (vp8->hasTID) {
708 vp8->tID = ((**dataPtr >> 6) & 0x03);
709 vp8->layerSync = (**dataPtr & 0x20) ? true : false; // Y bit
710 }
711 if (vp8->hasKeyIdx) {
712 vp8->keyIdx = (**dataPtr & 0x1F);
713 }
714 (*dataPtr)++;
715 (*parsedBytes)++;
716 (*dataLength)--;
717 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000718}
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000719
720} // namespace ModuleRTPUtility
721
722} // namespace webrtc