blob: efc985cd160129928ab737ce65c639bea20e5422 [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
niklase@google.com470e71d2011-07-07 08:21:25 +000052#if defined(_WIN32)
niklase@google.com470e71d2011-07-07 08:21:25 +000053
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000054struct reference_point {
55 FILETIME file_time;
56 LARGE_INTEGER counterMS;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000057};
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000058
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000059struct WindowsHelpTimer {
60 volatile LONG _timeInMs;
61 volatile LONG _numWrapTimeInMs;
62 reference_point _ref_point;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000063
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000064 volatile LONG _sync_flag;
65};
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +000066
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000067void Synchronize(WindowsHelpTimer* help_timer) {
68 const LONG start_value = 0;
69 const LONG new_value = 1;
70 const LONG synchronized_value = 2;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000071
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000072 LONG compare_flag = new_value;
73 while (help_timer->_sync_flag == start_value) {
74 const LONG new_value = 1;
75 compare_flag = InterlockedCompareExchange(
76 &help_timer->_sync_flag, new_value, start_value);
77 }
78 if (compare_flag != start_value) {
79 // This thread was not the one that incremented the sync flag.
80 // Block until synchronization finishes.
81 while (compare_flag != synchronized_value) {
82 ::Sleep(0);
83 }
84 return;
85 }
86 // Only the synchronizing thread gets here so this part can be
87 // considered single threaded.
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +000088
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +000089 // set timer accuracy to 1 ms
90 timeBeginPeriod(1);
91 FILETIME ft0 = { 0, 0 },
92 ft1 = { 0, 0 };
93 //
94 // Spin waiting for a change in system time. Get the matching
95 // performance counter value for that time.
96 //
97 ::GetSystemTimeAsFileTime(&ft0);
98 do {
99 ::GetSystemTimeAsFileTime(&ft1);
100
101 help_timer->_ref_point.counterMS.QuadPart = ::timeGetTime();
102 ::Sleep(0);
103 } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
104 (ft0.dwLowDateTime == ft1.dwLowDateTime));
105 help_timer->_ref_point.file_time = ft1;
106}
107
108void get_time(WindowsHelpTimer* help_timer, FILETIME& current_time) {
109 // we can't use query performance counter due to speed stepping
110 DWORD t = timeGetTime();
111 // NOTE: we have a missmatch in sign between _timeInMs(LONG) and
112 // (DWORD) however we only use it here without +- etc
113 volatile LONG* timeInMsPtr = &help_timer->_timeInMs;
114 // Make sure that we only inc wrapper once.
115 DWORD old = InterlockedExchange(timeInMsPtr, t);
116 if(old > t) {
117 // wrap
118 help_timer->_numWrapTimeInMs++;
119 }
120 LARGE_INTEGER elapsedMS;
121 elapsedMS.HighPart = help_timer->_numWrapTimeInMs;
122 elapsedMS.LowPart = t;
123
124 elapsedMS.QuadPart = elapsedMS.QuadPart -
125 help_timer->_ref_point.counterMS.QuadPart;
126
127 // Translate to 100-nanoseconds intervals (FILETIME resolution)
128 // and add to reference FILETIME to get current FILETIME.
129 ULARGE_INTEGER filetime_ref_as_ul;
130
131 filetime_ref_as_ul.HighPart =
132 help_timer->_ref_point.file_time.dwHighDateTime;
133 filetime_ref_as_ul.LowPart =
134 help_timer->_ref_point.file_time.dwLowDateTime;
135 filetime_ref_as_ul.QuadPart +=
136 (ULONGLONG)((elapsedMS.QuadPart)*1000*10);
137
138 // Copy to result
139 current_time.dwHighDateTime = filetime_ref_as_ul.HighPart;
140 current_time.dwLowDateTime = filetime_ref_as_ul.LowPart;
141 }
142
143 // A clock reading times from the Windows API.
144 class WindowsSystemClock : public RtpRtcpClock {
145 public:
146 WindowsSystemClock(WindowsHelpTimer* helpTimer)
147 : _helpTimer(helpTimer) {}
148
149 virtual ~WindowsSystemClock() {}
150
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000151 virtual WebRtc_Word64 GetTimeInMS();
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000152
153 virtual void CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac);
154
155 private:
156 WindowsHelpTimer* _helpTimer;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000157};
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000160
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000161// A clock reading times from the POSIX API.
162class UnixSystemClock : public RtpRtcpClock {
163public:
164 UnixSystemClock() {}
165 virtual ~UnixSystemClock() {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000166
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000167 virtual WebRtc_Word64 GetTimeInMS();
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000168
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000169 virtual void CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac);
170};
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000171#endif
172
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000173#if defined(_WIN32)
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000174WebRtc_Word64 WindowsSystemClock::GetTimeInMS() {
175 return TickTime::MillisecondTimestamp();
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000176}
177
178// Use the system time (roughly synchronised to the tick, and
179// extrapolated using the system performance counter.
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000180void WindowsSystemClock::CurrentNTP(WebRtc_UWord32& secs,
181 WebRtc_UWord32& frac) {
182 const WebRtc_UWord64 FILETIME_1970 = 0x019db1ded53e8000;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000183
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000184 FILETIME StartTime;
185 WebRtc_UWord64 Time;
186 struct timeval tv;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000187
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000188 // We can't use query performance counter since they can change depending on
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000189 // speed steping
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000190 get_time(_helpTimer, StartTime);
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000191
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000192 Time = (((WebRtc_UWord64) StartTime.dwHighDateTime) << 32) +
193 (WebRtc_UWord64) StartTime.dwLowDateTime;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000194
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000195 // Convert the hecto-nano second time to tv format
196 Time -= FILETIME_1970;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000197
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000198 tv.tv_sec = (WebRtc_UWord32)(Time / (WebRtc_UWord64)10000000);
199 tv.tv_usec = (WebRtc_UWord32)((Time % (WebRtc_UWord64)10000000) / 10);
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000200
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000201 double dtemp;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000202
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000203 secs = tv.tv_sec + NTP_JAN_1970;
204 dtemp = tv.tv_usec / 1e6;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000205
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000206 if (dtemp >= 1) {
207 dtemp -= 1;
208 secs++;
209 } else if (dtemp < -1) {
210 dtemp += 1;
211 secs--;
212 }
213 dtemp *= NTP_FRAC;
214 frac = (WebRtc_UWord32)dtemp;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000215}
216
217#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
218
pwestin@webrtc.org18530052012-07-03 10:41:54 +0000219WebRtc_Word64 UnixSystemClock::GetTimeInMS() {
220 return TickTime::MillisecondTimestamp();
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000221}
222
223// Use the system time.
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000224void UnixSystemClock::CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac) {
225 double dtemp;
226 struct timeval tv;
227 struct timezone tz;
228 tz.tz_minuteswest = 0;
229 tz.tz_dsttime = 0;
230 gettimeofday(&tv, &tz);
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000231
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000232 secs = tv.tv_sec + NTP_JAN_1970;
233 dtemp = tv.tv_usec / 1e6;
234 if (dtemp >= 1) {
235 dtemp -= 1;
236 secs++;
237 } else if (dtemp < -1) {
238 dtemp += 1;
239 secs--;
240 }
241 dtemp *= NTP_FRAC;
242 frac = (WebRtc_UWord32)dtemp;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000243}
244#endif
245
henrike@webrtc.org441b3fe2011-12-08 02:03:49 +0000246#if defined(_WIN32)
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000247// Keeps the global state for the Windows implementation of RtpRtcpClock.
248// Note that this is a POD. Only PODs are allowed to have static storage
249// duration according to the Google Style guide.
250static WindowsHelpTimer global_help_timer = {0, 0, {{ 0, 0}, 0}, 0};
henrike@webrtc.org441b3fe2011-12-08 02:03:49 +0000251#endif
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000252
253RtpRtcpClock* GetSystemClock() {
254#if defined(_WIN32)
255 return new WindowsSystemClock(&global_help_timer);
256#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
257 return new UnixSystemClock();
258#else
259 return NULL;
260#endif
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000261}
262
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000263WebRtc_UWord32 GetCurrentRTP(RtpRtcpClock* clock, WebRtc_UWord32 freq) {
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000264 const bool use_global_clock = (clock == NULL);
265 RtpRtcpClock* local_clock = clock;
266 if (use_global_clock) {
267 local_clock = GetSystemClock();
268 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000269 WebRtc_UWord32 secs = 0, frac = 0;
henrike@webrtc.orgf5da4da2012-02-15 23:54:59 +0000270 local_clock->CurrentNTP(secs, frac);
271 if (use_global_clock) {
272 delete local_clock;
273 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000274 return ConvertNTPTimeToRTP(secs, frac, freq);
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000275}
276
277WebRtc_UWord32 ConvertNTPTimeToRTP(WebRtc_UWord32 NTPsec,
278 WebRtc_UWord32 NTPfrac,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000279 WebRtc_UWord32 freq) {
280 float ftemp = (float)NTPfrac / (float)NTP_FRAC;
281 WebRtc_UWord32 tmp = (WebRtc_UWord32)(ftemp * freq);
282 return NTPsec * freq + tmp;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000283}
284
285WebRtc_UWord32 ConvertNTPTimeToMS(WebRtc_UWord32 NTPsec,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000286 WebRtc_UWord32 NTPfrac) {
287 int freq = 1000;
288 float ftemp = (float)NTPfrac / (float)NTP_FRAC;
289 WebRtc_UWord32 tmp = (WebRtc_UWord32)(ftemp * freq);
290 WebRtc_UWord32 MStime = NTPsec * freq + tmp;
291 return MStime;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000292}
293
marpan@webrtc.org57353a32011-12-16 17:21:09 +0000294bool OldTimestamp(uint32_t newTimestamp,
295 uint32_t existingTimestamp,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000296 bool* wrapped) {
297 bool tmpWrapped =
298 (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
299 (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
300 *wrapped = tmpWrapped;
301 if (existingTimestamp > newTimestamp && !tmpWrapped) {
302 return true;
303 } else if (existingTimestamp <= newTimestamp && !tmpWrapped) {
304 return false;
305 } else if (existingTimestamp < newTimestamp && tmpWrapped) {
306 return true;
307 } else {
308 return false;
309 }
marpan@webrtc.org57353a32011-12-16 17:21:09 +0000310}
311
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000312/*
313 * Misc utility routines
314 */
315
phoglund@webrtc.org07bf43c2012-12-18 15:40:53 +0000316const WebRtc_UWord8* GetPayloadData(const WebRtcRTPHeader* rtp_header,
317 const WebRtc_UWord8* packet) {
318 return packet + rtp_header->header.headerLength;
319}
320
321WebRtc_UWord16 GetPayloadDataLength(const WebRtcRTPHeader* rtp_header,
322 const WebRtc_UWord16 packet_length) {
323 WebRtc_UWord16 length = packet_length - rtp_header->header.paddingLength -
324 rtp_header->header.headerLength;
325 return static_cast<WebRtc_UWord16>(length);
326}
327
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000328#if defined(_WIN32)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000329bool StringCompare(const char* str1, const char* str2,
330 const WebRtc_UWord32 length) {
331 return (_strnicmp(str1, str2, length) == 0) ? true : false;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000332}
333#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000334bool StringCompare(const char* str1, const char* str2,
335 const WebRtc_UWord32 length) {
336 return (strncasecmp(str1, str2, length) == 0) ? true : false;
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000337}
338#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000339
340#if !defined(WEBRTC_LITTLE_ENDIAN) && !defined(WEBRTC_BIG_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000341#error Either WEBRTC_LITTLE_ENDIAN or WEBRTC_BIG_ENDIAN must be defined
niklase@google.com470e71d2011-07-07 08:21:25 +0000342#endif
343
344/* for RTP/RTCP
345 All integer fields are carried in network byte order, that is, most
346 significant byte (octet) first. AKA big-endian.
347*/
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000348void AssignUWord32ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord32 value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000349#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000350 dataBuffer[0] = static_cast<WebRtc_UWord8>(value >> 24);
351 dataBuffer[1] = static_cast<WebRtc_UWord8>(value >> 16);
352 dataBuffer[2] = static_cast<WebRtc_UWord8>(value >> 8);
353 dataBuffer[3] = static_cast<WebRtc_UWord8>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000354#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000355 WebRtc_UWord32* ptr = reinterpret_cast<WebRtc_UWord32*>(dataBuffer);
356 ptr[0] = value;
niklase@google.com470e71d2011-07-07 08:21:25 +0000357#endif
358}
359
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000360void AssignUWord24ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord32 value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000361#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000362 dataBuffer[0] = static_cast<WebRtc_UWord8>(value >> 16);
363 dataBuffer[1] = static_cast<WebRtc_UWord8>(value >> 8);
364 dataBuffer[2] = static_cast<WebRtc_UWord8>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000365#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000366 dataBuffer[0] = static_cast<WebRtc_UWord8>(value);
367 dataBuffer[1] = static_cast<WebRtc_UWord8>(value >> 8);
368 dataBuffer[2] = static_cast<WebRtc_UWord8>(value >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000369#endif
370}
371
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000372void AssignUWord16ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord16 value) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000373#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000374 dataBuffer[0] = static_cast<WebRtc_UWord8>(value >> 8);
375 dataBuffer[1] = static_cast<WebRtc_UWord8>(value);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000377 WebRtc_UWord16* ptr = reinterpret_cast<WebRtc_UWord16*>(dataBuffer);
378 ptr[0] = value;
niklase@google.com470e71d2011-07-07 08:21:25 +0000379#endif
380}
381
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000382WebRtc_UWord16 BufferToUWord16(const WebRtc_UWord8* dataBuffer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000383#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000384 return (dataBuffer[0] << 8) + dataBuffer[1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000385#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000386 return *reinterpret_cast<const WebRtc_UWord16*>(dataBuffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000387#endif
388}
389
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000390WebRtc_UWord32 BufferToUWord24(const WebRtc_UWord8* dataBuffer) {
391 return (dataBuffer[0] << 16) + (dataBuffer[1] << 8) + dataBuffer[2];
niklase@google.com470e71d2011-07-07 08:21:25 +0000392}
393
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000394WebRtc_UWord32 BufferToUWord32(const WebRtc_UWord8* dataBuffer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000395#if defined(WEBRTC_LITTLE_ENDIAN)
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000396 return (dataBuffer[0] << 24) + (dataBuffer[1] << 16) + (dataBuffer[2] << 8) +
397 dataBuffer[3];
niklase@google.com470e71d2011-07-07 08:21:25 +0000398#else
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000399 return *reinterpret_cast<const WebRtc_UWord32*>(dataBuffer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000400#endif
401}
402
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000403WebRtc_UWord32 pow2(WebRtc_UWord8 exp) {
404 return 1 << exp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000405}
406
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000407void RTPPayload::SetType(RtpVideoCodecTypes videoType) {
408 type = videoType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000409
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000410 switch (type) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 case kRtpNoVideo:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000412 break;
413 case kRtpVp8Video: {
414 info.VP8.nonReferenceFrame = false;
415 info.VP8.beginningOfPartition = false;
416 info.VP8.partitionID = 0;
417 info.VP8.hasPictureID = false;
418 info.VP8.hasTl0PicIdx = false;
419 info.VP8.hasTID = false;
420 info.VP8.hasKeyIdx = false;
421 info.VP8.pictureID = -1;
422 info.VP8.tl0PicIdx = -1;
423 info.VP8.tID = -1;
424 info.VP8.layerSync = false;
425 info.VP8.frameWidth = 0;
426 info.VP8.frameHeight = 0;
427 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 }
429 default:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000430 break;
431 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000432}
433
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000434RTPHeaderParser::RTPHeaderParser(const WebRtc_UWord8* rtpData,
435 const WebRtc_UWord32 rtpDataLength)
436 : _ptrRTPDataBegin(rtpData),
437 _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000438}
439
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000440RTPHeaderParser::~RTPHeaderParser() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000441}
442
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000443bool RTPHeaderParser::RTCP() const {
444 // 72 to 76 is reserved for RTP
445 // 77 to 79 is not reserver but they are not assigned we will block them
446 // for RTCP 200 SR == marker bit + 72
447 // for RTCP 204 APP == marker bit + 76
448 /*
449 * RTCP
450 *
451 * FIR full INTRA-frame request 192 [RFC2032] supported
452 * NACK negative acknowledgement 193 [RFC2032]
453 * IJ Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff
454 * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
455 * SR sender report 200 [RFC3551] supported
456 * RR receiver report 201 [RFC3551] supported
457 * SDES source description 202 [RFC3551] supported
458 * BYE goodbye 203 [RFC3551] supported
459 * APP application-defined 204 [RFC3551] ignored
460 * RTPFB Transport layer FB message 205 [RFC4585] supported
461 * PSFB Payload-specific FB message 206 [RFC4585] supported
462 * XR extended report 207 [RFC3611] supported
463 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000465 /* 205 RFC 5104
466 * FMT 1 NACK supported
467 * FMT 2 reserved
468 * FMT 3 TMMBR supported
469 * FMT 4 TMMBN supported
470 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000471
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000472 /* 206 RFC 5104
473 * FMT 1: Picture Loss Indication (PLI) supported
474 * FMT 2: Slice Lost Indication (SLI)
475 * FMT 3: Reference Picture Selection Indication (RPSI)
476 * FMT 4: Full Intra Request (FIR) Command supported
477 * FMT 5: Temporal-Spatial Trade-off Request (TSTR)
478 * FMT 6: Temporal-Spatial Trade-off Notification (TSTN)
479 * FMT 7: Video Back Channel Message (VBCM)
480 * FMT 15: Application layer FB message
481 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000482
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000483 const WebRtc_UWord8 payloadType = _ptrRTPDataBegin[1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000484
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000485 bool RTCP = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000486
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000487 // check if this is a RTCP packet
488 switch (payloadType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 case 192:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000490 RTCP = true;
491 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 case 193:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000493 // not supported
494 // pass through and check for a potential RTP packet
495 break;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000496 case 195:
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 case 200:
498 case 201:
499 case 202:
500 case 203:
501 case 204:
502 case 205:
503 case 206:
504 case 207:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000505 RTCP = true;
506 break;
507 }
508 return RTCP;
niklase@google.com470e71d2011-07-07 08:21:25 +0000509}
510
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000511bool RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket,
512 RtpHeaderExtensionMap* ptrExtensionMap) const {
513 const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
niklase@google.com470e71d2011-07-07 08:21:25 +0000514
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000515 if (length < 12) {
516 return false;
517 }
518
519 // Version
520 const WebRtc_UWord8 V = _ptrRTPDataBegin[0] >> 6;
521 // Padding
522 const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
523 // eXtension
524 const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
525 const WebRtc_UWord8 CC = _ptrRTPDataBegin[0] & 0x0f;
526 const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
527
528 const WebRtc_UWord8 PT = _ptrRTPDataBegin[1] & 0x7f;
529
530 const WebRtc_UWord16 sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
531 _ptrRTPDataBegin[3];
532
533 const WebRtc_UWord8* ptr = &_ptrRTPDataBegin[4];
534
535 WebRtc_UWord32 RTPTimestamp = *ptr++ << 24;
536 RTPTimestamp += *ptr++ << 16;
537 RTPTimestamp += *ptr++ << 8;
538 RTPTimestamp += *ptr++;
539
540 WebRtc_UWord32 SSRC = *ptr++ << 24;
541 SSRC += *ptr++ << 16;
542 SSRC += *ptr++ << 8;
543 SSRC += *ptr++;
544
545 if (V != 2) {
546 return false;
547 }
548
549 const WebRtc_UWord8 CSRCocts = CC * 4;
550
551 if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
552 return false;
553 }
554
555 parsedPacket.header.markerBit = M;
556 parsedPacket.header.payloadType = PT;
557 parsedPacket.header.sequenceNumber = sequenceNumber;
558 parsedPacket.header.timestamp = RTPTimestamp;
559 parsedPacket.header.ssrc = SSRC;
560 parsedPacket.header.numCSRCs = CC;
561 parsedPacket.header.paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;
562
563 for (unsigned int i = 0; i < CC; ++i) {
564 WebRtc_UWord32 CSRC = *ptr++ << 24;
565 CSRC += *ptr++ << 16;
566 CSRC += *ptr++ << 8;
567 CSRC += *ptr++;
568 parsedPacket.header.arrOfCSRCs[i] = CSRC;
569 }
570 parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs;
571
572 parsedPacket.header.headerLength = 12 + CSRCocts;
573
574 // If in effect, MAY be omitted for those packets for which the offset
575 // is zero.
576 parsedPacket.extension.transmissionTimeOffset = 0;
577
578 if (X) {
579 /* RTP header extension, RFC 3550.
580 0 1 2 3
581 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
582 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 | defined by profile | length |
584 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585 | header extension |
586 | .... |
587 */
588 const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
589 if (remain < 4) {
590 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000591 }
592
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000593 parsedPacket.header.headerLength += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000594
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000595 WebRtc_UWord16 definedByProfile = *ptr++ << 8;
596 definedByProfile += *ptr++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000598 WebRtc_UWord16 XLen = *ptr++ << 8;
599 XLen += *ptr++; // in 32 bit words
600 XLen *= 4; // in octs
niklase@google.com470e71d2011-07-07 08:21:25 +0000601
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000602 if (remain < (4 + XLen)) {
603 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000605 if (definedByProfile == RTP_ONE_BYTE_HEADER_EXTENSION) {
606 const WebRtc_UWord8* ptrRTPDataExtensionEnd = ptr + XLen;
607 ParseOneByteExtensionHeader(parsedPacket,
608 ptrExtensionMap,
609 ptrRTPDataExtensionEnd,
610 ptr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000611 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000612 parsedPacket.header.headerLength += XLen;
613 }
614 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000615}
616
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000617void RTPHeaderParser::ParseOneByteExtensionHeader(
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000618 WebRtcRTPHeader& parsedPacket,
619 const RtpHeaderExtensionMap* ptrExtensionMap,
620 const WebRtc_UWord8* ptrRTPDataExtensionEnd,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000621 const WebRtc_UWord8* ptr) const {
622 if (!ptrExtensionMap) {
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000623 return;
624 }
625
626 while (ptrRTPDataExtensionEnd - ptr > 0) {
627 // 0
628 // 0 1 2 3 4 5 6 7
629 // +-+-+-+-+-+-+-+-+
630 // | ID | len |
631 // +-+-+-+-+-+-+-+-+
632
633 const WebRtc_UWord8 id = (*ptr & 0xf0) >> 4;
634 const WebRtc_UWord8 len = (*ptr & 0x0f);
635 ptr++;
636
637 if (id == 15) {
638 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
639 "Ext id: 15 encountered, parsing terminated.");
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000640 return;
641 }
642
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000643 RTPExtensionType type;
644 if (ptrExtensionMap->GetType(id, &type) != 0) {
645 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
646 "Failed to find extension id: %d", id);
647 return;
648 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000649
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000650 switch (type) {
651 case kRtpExtensionTransmissionTimeOffset: {
652 if (len != 2) {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000653 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000654 "Incorrect transmission time offset len: %d", len);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000655 return;
656 }
657 // 0 1 2 3
658 // 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
659 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
660 // | ID | len=2 | transmission offset |
661 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
662
663 WebRtc_Word32 transmissionTimeOffset = *ptr++ << 16;
664 transmissionTimeOffset += *ptr++ << 8;
665 transmissionTimeOffset += *ptr++;
666 parsedPacket.extension.transmissionTimeOffset = transmissionTimeOffset;
asapersson@webrtc.orgd2e67792012-06-28 07:53:15 +0000667 if (transmissionTimeOffset & 0x800000) {
668 // Negative offset, correct sign for Word24 to Word32.
669 parsedPacket.extension.transmissionTimeOffset |= 0xFF000000;
670 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000671 break;
672 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000673 case kRtpExtensionAudioLevel: {
674 // --- Only used for debugging ---
675 // 0 1 2 3
676 // 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
677 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
678 // | ID | len=0 |V| level | 0x00 | 0x00 |
679 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
680 //
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000681
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000682 // Parse out the fields but only use it for debugging for now.
683 // const WebRtc_UWord8 V = (*ptr & 0x80) >> 7;
684 // const WebRtc_UWord8 level = (*ptr & 0x7f);
685 // DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u,
686 // level=%u", ID, len, V, level);
pwestin@webrtc.org6c1d4152012-01-04 17:04:51 +0000687 break;
688 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000689 default: {
mflodman@webrtc.orgba853c92012-08-10 14:30:53 +0000690 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000691 "Extension type not implemented.");
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000692 return;
693 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000694 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000695 WebRtc_UWord8 num_bytes = ParsePaddingBytes(ptrRTPDataExtensionEnd, ptr);
696 ptr += num_bytes;
697 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000698}
699
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000700WebRtc_UWord8 RTPHeaderParser::ParsePaddingBytes(
701 const WebRtc_UWord8* ptrRTPDataExtensionEnd,
702 const WebRtc_UWord8* ptr) const {
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000703
704 WebRtc_UWord8 num_zero_bytes = 0;
705 while (ptrRTPDataExtensionEnd - ptr > 0) {
706 if (*ptr != 0) {
707 return num_zero_bytes;
708 }
709 ptr++;
710 num_zero_bytes++;
711 }
712 return num_zero_bytes;
713}
714
niklase@google.com470e71d2011-07-07 08:21:25 +0000715// RTP payload parser
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000716RTPPayloadParser::RTPPayloadParser(const RtpVideoCodecTypes videoType,
717 const WebRtc_UWord8* payloadData,
718 WebRtc_UWord16 payloadDataLength,
719 WebRtc_Word32 id)
720 :
721 _id(id),
722 _dataPtr(payloadData),
723 _dataLength(payloadDataLength),
724 _videoType(videoType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000725}
726
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000727RTPPayloadParser::~RTPPayloadParser() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000728}
729
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000730bool RTPPayloadParser::Parse(RTPPayload& parsedPacket) const {
731 parsedPacket.SetType(_videoType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000732
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000733 switch (_videoType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 case kRtpNoVideo:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000735 return ParseGeneric(parsedPacket);
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 case kRtpVp8Video:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000737 return ParseVP8(parsedPacket);
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 default:
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000739 return false;
740 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000741}
742
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000743bool RTPPayloadParser::ParseGeneric(RTPPayload& /*parsedPacket*/) const {
744 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000745}
746
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000747//
748// VP8 format:
749//
750// Payload descriptor
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000751// 0 1 2 3 4 5 6 7
752// +-+-+-+-+-+-+-+-+
753// |X|R|N|S|PartID | (REQUIRED)
754// +-+-+-+-+-+-+-+-+
755// X: |I|L|T|K| RSV | (OPTIONAL)
756// +-+-+-+-+-+-+-+-+
757// I: | PictureID | (OPTIONAL)
758// +-+-+-+-+-+-+-+-+
759// L: | TL0PICIDX | (OPTIONAL)
760// +-+-+-+-+-+-+-+-+
henrik.lundin@webrtc.orgeda86dc2011-12-13 14:11:06 +0000761// T/K: |TID:Y| KEYIDX | (OPTIONAL)
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000762// +-+-+-+-+-+-+-+-+
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000763//
764// Payload header (considered part of the actual payload, sent to decoder)
henrik.lundin@webrtc.org6f2c0162011-11-24 12:52:40 +0000765// 0 1 2 3 4 5 6 7
766// +-+-+-+-+-+-+-+-+
767// |Size0|H| VER |P|
768// +-+-+-+-+-+-+-+-+
769// | ... |
770// + +
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000771
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000772bool RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const {
773 RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
774 const WebRtc_UWord8* dataPtr = _dataPtr;
775 int dataLength = _dataLength;
niklase@google.com470e71d2011-07-07 08:21:25 +0000776
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000777 // Parse mandatory first byte of payload descriptor
778 bool extension = (*dataPtr & 0x80) ? true : false; // X bit
779 vp8->nonReferenceFrame = (*dataPtr & 0x20) ? true : false; // N bit
780 vp8->beginningOfPartition = (*dataPtr & 0x10) ? true : false; // S bit
781 vp8->partitionID = (*dataPtr & 0x0F); // PartID field
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000782
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000783 if (vp8->partitionID > 8) {
784 // Weak check for corrupt data: PartID MUST NOT be larger than 8.
785 return false;
786 }
andrew@webrtc.org7fe219f2012-02-01 02:40:37 +0000787
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000788 // Advance dataPtr and decrease remaining payload size
789 dataPtr++;
790 dataLength--;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000791
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000792 if (extension) {
793 const int parsedBytes = ParseVP8Extension(vp8, dataPtr, dataLength);
794 if (parsedBytes < 0) return false;
795 dataPtr += parsedBytes;
796 dataLength -= parsedBytes;
797 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000798
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000799 if (dataLength <= 0) {
800 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
801 "Error parsing VP8 payload descriptor; payload too short");
802 return false;
803 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000804
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000805 // Read P bit from payload header (only at beginning of first partition)
806 if (dataLength > 0 && vp8->beginningOfPartition && vp8->partitionID == 0) {
807 parsedPacket.frameType = (*dataPtr & 0x01) ? kPFrame : kIFrame;
808 } else {
809 parsedPacket.frameType = kPFrame;
810 }
811 if (0 != ParseVP8FrameSize(parsedPacket, dataPtr, dataLength)) {
812 return false;
813 }
814 parsedPacket.info.VP8.data = dataPtr;
815 parsedPacket.info.VP8.dataLength = dataLength;
816 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000817}
818
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000819int RTPPayloadParser::ParseVP8FrameSize(RTPPayload& parsedPacket,
820 const WebRtc_UWord8* dataPtr,
821 int dataLength) const {
822 if (parsedPacket.frameType != kIFrame) {
823 // Included in payload header for I-frames.
pwestin@webrtc.org075e91f2011-11-02 23:14:58 +0000824 return 0;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000825 }
826 if (dataLength < 10) {
827 // For an I-frame we should always have the uncompressed VP8 header
828 // in the beginning of the partition.
829 return -1;
830 }
831 RTPPayloadVP8* vp8 = &parsedPacket.info.VP8;
832 vp8->frameWidth = ((dataPtr[7] << 8) + dataPtr[6]) & 0x3FFF;
833 vp8->frameHeight = ((dataPtr[9] << 8) + dataPtr[8]) & 0x3FFF;
834 return 0;
pwestin@webrtc.org075e91f2011-11-02 23:14:58 +0000835}
836
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000837int RTPPayloadParser::ParseVP8Extension(RTPPayloadVP8* vp8,
838 const WebRtc_UWord8* dataPtr,
839 int dataLength) const {
840 int parsedBytes = 0;
841 if (dataLength <= 0) return -1;
842 // Optional X field is present
843 vp8->hasPictureID = (*dataPtr & 0x80) ? true : false; // I bit
844 vp8->hasTl0PicIdx = (*dataPtr & 0x40) ? true : false; // L bit
845 vp8->hasTID = (*dataPtr & 0x20) ? true : false; // T bit
846 vp8->hasKeyIdx = (*dataPtr & 0x10) ? true : false; // K bit
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000847
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000848 // Advance dataPtr and decrease remaining payload size
849 dataPtr++;
850 parsedBytes++;
851 dataLength--;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000852
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000853 if (vp8->hasPictureID) {
854 if (ParseVP8PictureID(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
855 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000856 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000857 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000858
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000859 if (vp8->hasTl0PicIdx) {
860 if (ParseVP8Tl0PicIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
861 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000862 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000863 }
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000864
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000865 if (vp8->hasTID || vp8->hasKeyIdx) {
866 if (ParseVP8TIDAndKeyIdx(vp8, &dataPtr, &dataLength, &parsedBytes) != 0) {
867 return -1;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000868 }
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000869 }
870 return parsedBytes;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000871}
872
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000873int RTPPayloadParser::ParseVP8PictureID(RTPPayloadVP8* vp8,
874 const WebRtc_UWord8** dataPtr,
875 int* dataLength,
876 int* parsedBytes) const {
877 if (*dataLength <= 0) return -1;
878 vp8->pictureID = (**dataPtr & 0x7F);
879 if (**dataPtr & 0x80) {
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000880 (*dataPtr)++;
881 (*parsedBytes)++;
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000882 if (--(*dataLength) <= 0) return -1;
883 // PictureID is 15 bits
884 vp8->pictureID = (vp8->pictureID << 8) +** dataPtr;
885 }
886 (*dataPtr)++;
887 (*parsedBytes)++;
888 (*dataLength)--;
889 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000890}
891
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000892int RTPPayloadParser::ParseVP8Tl0PicIdx(RTPPayloadVP8* vp8,
893 const WebRtc_UWord8** dataPtr,
894 int* dataLength,
895 int* parsedBytes) const {
896 if (*dataLength <= 0) return -1;
897 vp8->tl0PicIdx = **dataPtr;
898 (*dataPtr)++;
899 (*parsedBytes)++;
900 (*dataLength)--;
901 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000902}
903
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000904int RTPPayloadParser::ParseVP8TIDAndKeyIdx(RTPPayloadVP8* vp8,
905 const WebRtc_UWord8** dataPtr,
906 int* dataLength,
907 int* parsedBytes) const {
908 if (*dataLength <= 0) return -1;
909 if (vp8->hasTID) {
910 vp8->tID = ((**dataPtr >> 6) & 0x03);
911 vp8->layerSync = (**dataPtr & 0x20) ? true : false; // Y bit
912 }
913 if (vp8->hasKeyIdx) {
914 vp8->keyIdx = (**dataPtr & 0x1F);
915 }
916 (*dataPtr)++;
917 (*parsedBytes)++;
918 (*dataLength)--;
919 return 0;
henrik.lundin@webrtc.org8571af72011-08-29 15:37:12 +0000920}
henrike@webrtc.orgd5657c22012-02-08 23:41:49 +0000921
922} // namespace ModuleRTPUtility
923
924} // namespace webrtc