/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtp_utility.h" #include // memcpy #include // ceil #include #if defined(_WIN32) #include // FILETIME #include // timeval #include //timeGetTime #elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC)) #include // gettimeofday #include #endif #if (defined(_DEBUG) && defined(_WIN32) && (_MSC_VER >= 1400)) #include #define DEBUG_PRINT(...) \ { \ char msg[256]; \ sprintf(msg, __VA_ARGS__); \ OutputDebugString(msg); \ } #else // special fix for visual 2003 #define DEBUG_PRINT(exp) ((void)0) #endif // defined(_DEBUG) && defined(_WIN32) namespace { const float FRAC = 4.294967296E9; } namespace webrtc { // PLATFORM SPECIFIC [BEGIN] #if defined(_WIN32) #include namespace ModuleRTPUtility { WebRtc_UWord32 GetTimeInMS() { return timeGetTime(); } bool StringCompare(const WebRtc_Word8* str1 , const WebRtc_Word8* str2, const WebRtc_UWord32 length) { return (_strnicmp(str1, str2, length) == 0)?true: false; } class HelpTimer { public: struct reference_point { FILETIME file_time; LARGE_INTEGER counterMS; }; HelpTimer() { // set timer accuracy to 1 ms timeBeginPeriod(1); _timeInMs = 0; _numWrapTimeInMs = 0; synchronize(); }; virtual ~HelpTimer() { timeEndPeriod(1); }; void get_time(FILETIME& current_time) { // we can't use query performance counter due to speed stepping DWORD t = timeGetTime(); // NOTE: we have a miss match in sign between _timeInMs(LONG) and t(DWORD) however we only use it here without +- etc volatile LONG* timeInMsPtr = &_timeInMs; DWORD old = InterlockedExchange(timeInMsPtr, t); // make sure that we only inc wrapper once if(old > t) { // wrap _numWrapTimeInMs++; } LARGE_INTEGER elapsedMS; elapsedMS.HighPart = _numWrapTimeInMs; elapsedMS.LowPart = t; elapsedMS.QuadPart = elapsedMS.QuadPart - _ref_point.counterMS.QuadPart; // // Translate to 100-nanoseconds intervals (FILETIME resolution) and add to // reference FILETIME to get current FILETIME. // ULARGE_INTEGER filetime_ref_as_ul; filetime_ref_as_ul.HighPart = _ref_point.file_time.dwHighDateTime; filetime_ref_as_ul.LowPart = _ref_point.file_time.dwLowDateTime; filetime_ref_as_ul.QuadPart += (ULONGLONG)((elapsedMS.QuadPart)*1000*10); // // Copy to result // current_time.dwHighDateTime = filetime_ref_as_ul.HighPart; current_time.dwLowDateTime = filetime_ref_as_ul.LowPart; }; private: void synchronize() { FILETIME ft0 = { 0, 0 }, ft1 = { 0, 0 }; // // Spin waiting for a change in system time. Get the matching // performance counter value for that time. // ::GetSystemTimeAsFileTime(&ft0); do { ::GetSystemTimeAsFileTime(&ft1); _ref_point.counterMS.QuadPart = ::timeGetTime(); ::Sleep(0); } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) && (ft0.dwLowDateTime == ft1.dwLowDateTime)); _ref_point.file_time = ft1; } volatile LONG _timeInMs; // this needs to be long due to Windows, not an issue due to its usage volatile WebRtc_UWord32 _numWrapTimeInMs; reference_point _ref_point; }; static HelpTimer helpTimer; }; // end namespace #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) #include // gettimeofday #include // nanosleep, gettimeofday WebRtc_UWord32 ModuleRTPUtility::GetTimeInMS() { struct timeval tv; struct timezone tz; WebRtc_UWord32 val; gettimeofday(&tv, &tz); val = (WebRtc_UWord32)(tv.tv_sec*1000 + tv.tv_usec/1000); return val; } bool ModuleRTPUtility::StringCompare(const WebRtc_Word8* str1 , const WebRtc_Word8* str2, const WebRtc_UWord32 length) { return (strncasecmp(str1, str2, length) == 0)?true: false; } #endif // PLATFORM SPECIFIC [END] #if !defined(WEBRTC_LITTLE_ENDIAN) && !defined(WEBRTC_BIG_ENDIAN) #error Either WEBRTC_LITTLE_ENDIAN or WEBRTC_BIG_ENDIAN must be defined #endif /* for RTP/RTCP All integer fields are carried in network byte order, that is, most significant byte (octet) first. AKA big-endian. */ void ModuleRTPUtility::AssignUWord32ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord32 value) { #if defined(WEBRTC_LITTLE_ENDIAN) dataBuffer[0] = static_cast(value>>24); dataBuffer[1] = static_cast(value>>16); dataBuffer[2] = static_cast(value>>8); dataBuffer[3] = static_cast(value); #else WebRtc_UWord32* ptr = reinterpret_cast(dataBuffer); ptr[0] = value; #endif } void ModuleRTPUtility::AssignUWord24ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord32 value) { #if defined(WEBRTC_LITTLE_ENDIAN) dataBuffer[0] = static_cast(value>>16); dataBuffer[1] = static_cast(value>>8); dataBuffer[2] = static_cast(value); #else dataBuffer[0] = static_cast(value); dataBuffer[1] = static_cast(value>>8); dataBuffer[2] = static_cast(value>>16); #endif } void ModuleRTPUtility::AssignUWord16ToBuffer(WebRtc_UWord8* dataBuffer, WebRtc_UWord16 value) { #if defined(WEBRTC_LITTLE_ENDIAN) dataBuffer[0] = static_cast(value>>8); dataBuffer[1] = static_cast(value); #else WebRtc_UWord16* ptr = reinterpret_cast(dataBuffer); ptr[0] = value; #endif } WebRtc_UWord16 ModuleRTPUtility::BufferToUWord16(const WebRtc_UWord8* dataBuffer) { #if defined(WEBRTC_LITTLE_ENDIAN) return (dataBuffer[0] << 8) + dataBuffer[1]; #else return *reinterpret_cast(dataBuffer); #endif } WebRtc_UWord32 ModuleRTPUtility::BufferToUWord24(const WebRtc_UWord8* dataBuffer) { return (dataBuffer[0] << 16) + (dataBuffer[1] << 8) + dataBuffer[2]; } WebRtc_UWord32 ModuleRTPUtility::BufferToUWord32(const WebRtc_UWord8* dataBuffer) { #if defined(WEBRTC_LITTLE_ENDIAN) return (dataBuffer[0] << 24) + (dataBuffer[1] << 16) + (dataBuffer[2] << 8) + dataBuffer[3]; #else return *reinterpret_cast(dataBuffer); #endif } WebRtc_UWord32 ModuleRTPUtility::pow2(WebRtc_UWord8 exp) { return 1 << exp; } WebRtc_Word32 ModuleRTPUtility::CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac) { /* * Use the system time (roughly synchronised to the tick, and * extrapolated using the system performance counter. */ const WebRtc_UWord32 JAN_1970 = 2208988800UL; // NTP seconds #if defined(_WIN32) const WebRtc_UWord64 FILETIME_1970 = 0x019db1ded53e8000; FILETIME StartTime; WebRtc_UWord64 Time; struct timeval tv; // we can't use query performance counter since they can change depending on speed steping helpTimer.get_time(StartTime); Time = (((WebRtc_UWord64) StartTime.dwHighDateTime) << 32) + (WebRtc_UWord64) StartTime.dwLowDateTime; // Convert the hecto-nano second time to tv format Time -= FILETIME_1970; tv.tv_sec = (WebRtc_UWord32) ( Time / (WebRtc_UWord64)10000000); tv.tv_usec = (WebRtc_UWord32) (( Time % (WebRtc_UWord64)10000000) / 10); double dtemp; secs = tv.tv_sec + JAN_1970; dtemp = tv.tv_usec / 1e6; if (dtemp >= 1) { dtemp -= 1; secs++; } else if (dtemp < -1) { dtemp += 1; secs--; } dtemp *= FRAC; frac = (WebRtc_UWord32)dtemp; return 0; #endif #if ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC)) double dtemp; struct timeval tv; struct timezone tz; tz.tz_minuteswest = 0; tz.tz_dsttime = 0; gettimeofday(&tv,&tz); secs = tv.tv_sec + JAN_1970; dtemp = tv.tv_usec / 1e6; if (dtemp >= 1) { dtemp -= 1; secs++; } else if (dtemp < -1) { dtemp += 1; secs--; } dtemp *= FRAC; frac = (WebRtc_UWord32)dtemp; return(0); #endif } WebRtc_UWord32 ModuleRTPUtility::ConvertNTPTimeToMS(WebRtc_UWord32 NTPsec, WebRtc_UWord32 NTPfrac) { int freq = 1000; float ftemp = (float)NTPfrac/(float)FRAC; WebRtc_UWord32 tmp = (WebRtc_UWord32)(ftemp * freq); WebRtc_UWord32 MStime= NTPsec*freq + tmp; return MStime; } WebRtc_UWord32 ModuleRTPUtility::CurrentRTP(WebRtc_UWord32 freq) { WebRtc_UWord32 NTPsec = 0; WebRtc_UWord32 NTPfrac = 0; CurrentNTP( NTPsec, NTPfrac); float ftemp = (float)NTPfrac/(float)FRAC; WebRtc_UWord32 tmp = (WebRtc_UWord32)(ftemp * freq); return NTPsec*freq + tmp; } void ModuleRTPUtility::RTPPayload::SetType(RtpVideoCodecTypes videoType) { type = videoType; switch (type) { case kRtpNoVideo: break; case kRtpH263Video: case kRtpH2631998Video: { info.H263.hasPictureStartCode = false; info.H263.insert2byteStartCode = false; info.H263.hasPbit = false; info.H263.frameWidth = 0; info.H263.frameHeight = 0; info.H263.startBits = 0; info.H263.endBits = 0; info.H263.data = 0; info.H263.dataLength = 0; break; } case kRtpMpeg4Video: { info.MPEG4.isFirstPacket = false; info.MPEG4.data = 0; info.MPEG4.dataLength = 0; break; } case kRtpVp8Video: { info.VP8.beginningOfFrame = false; info.VP8.nonReferenceFrame = false; info.VP8.hasPictureID = false; info.VP8.fragments = false; info.VP8.startFragment = false; info.VP8.stopFragment = false; break; } default: break; } } ModuleRTPUtility::RTPHeaderParser::RTPHeaderParser(const WebRtc_UWord8* rtpData, const WebRtc_UWord32 rtpDataLength): _ptrRTPDataBegin(rtpData), _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) { } ModuleRTPUtility::RTPHeaderParser::~RTPHeaderParser() { } bool ModuleRTPUtility::RTPHeaderParser::RTCP() const { // 72 to 76 is reserved for RTP // 77 to 79 is not reserver but they are not assigned we will block them // for RTCP 200 SR == marker bit + 72 // for RTCP 204 APP == marker bit + 76 /* * RTCP * * FIR full INTRA-frame request 192 [RFC2032] supported * NACK negative acknowledgement 193 [RFC2032] * IJ Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toffset-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07 * SR sender report 200 [RFC3551] supported * RR receiver report 201 [RFC3551] supported * SDES source description 202 [RFC3551] supported * BYE goodbye 203 [RFC3551] supported * APP application-defined 204 [RFC3551] ignored * RTPFB Transport layer FB message 205 [RFC4585] supported * PSFB Payload-specific FB message 206 [RFC4585] supported * XR extended report 207 [RFC3611] supported */ /* 205 RFC 5104 * FMT 1 NACK supported * FMT 2 reserved * FMT 3 TMMBR supported * FMT 4 TMMBN supported */ /* 206 RFC 5104 * FMT 1: Picture Loss Indication (PLI) supported * FMT 2: Slice Lost Indication (SLI) * FMT 3: Reference Picture Selection Indication (RPSI) * FMT 4: Full Intra Request (FIR) Command supported * FMT 5: Temporal-Spatial Trade-off Request (TSTR) * FMT 6: Temporal-Spatial Trade-off Notification (TSTN) * FMT 7: Video Back Channel Message (VBCM) * FMT 15: Application layer FB message */ const WebRtc_UWord8 payloadType = _ptrRTPDataBegin[1]; bool RTCP = false; // check if this is a RTCP packet switch(payloadType) { case 192: RTCP = true; break; case 193: case 195: // not supported // pass through and check for a potential RTP packet break; case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: RTCP = true; break; } return RTCP; } bool ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const { const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin; if (length < 12) { return false; } const WebRtc_UWord8 V = _ptrRTPDataBegin[0] >> 6 ; // Version const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true; // Padding const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true; // eXtension const WebRtc_UWord8 CC = _ptrRTPDataBegin[0] & 0x0f; const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true; const WebRtc_UWord8 PT = _ptrRTPDataBegin[1] & 0x7f; const WebRtc_UWord16 sequenceNumber = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3]; const WebRtc_UWord8* ptr = &_ptrRTPDataBegin[4]; WebRtc_UWord32 RTPTimestamp = *ptr++ << 24; RTPTimestamp += *ptr++ << 16; RTPTimestamp += *ptr++ << 8; RTPTimestamp += *ptr++; WebRtc_UWord32 SSRC = *ptr++ << 24; SSRC += *ptr++ << 16; SSRC += *ptr++ << 8; SSRC += *ptr++; if (V != 2) { return false; } const WebRtc_UWord8 CSRCocts = CC * 4; if ((ptr + CSRCocts) > _ptrRTPDataEnd) { return false; } parsedPacket.header.markerBit = M; parsedPacket.header.payloadType = PT; parsedPacket.header.sequenceNumber = sequenceNumber; parsedPacket.header.timestamp = RTPTimestamp; parsedPacket.header.ssrc = SSRC; parsedPacket.header.numCSRCs = CC; parsedPacket.header.paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0; for (unsigned int i = 0; i < CC; ++i) { WebRtc_UWord32 CSRC = *ptr++ << 24; CSRC += *ptr++ << 16; CSRC += *ptr++ << 8; CSRC += *ptr++; parsedPacket.header.arrOfCSRCs[i] = CSRC; } parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs; parsedPacket.header.headerLength = 12 + CSRCocts; if (X) { const ptrdiff_t remain = _ptrRTPDataEnd - ptr; if (remain < 4) { return false; } parsedPacket.header.headerLength += 4; WebRtc_UWord16 definedByProfile = *ptr++ << 8; definedByProfile += *ptr++; WebRtc_UWord16 XLen = *ptr++ << 8; XLen += *ptr++; // in 32 bit words XLen *= 4; // in octs if (remain < (4 + XLen)) { return false; } if(definedByProfile == RTP_AUDIO_LEVEL_UNIQUE_ID && XLen == 4) { // --- Only used for debugging --- /* 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0xBE | 0xDE | length=1 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ID | len=0 |V| level | 0x00 | 0x00 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ // Parse out the fields but only use it for debugging for now. const WebRtc_UWord8 ID = (*ptr & 0xf0) >> 4; const WebRtc_UWord8 len = (*ptr & 0x0f); ptr++; const WebRtc_UWord8 V = (*ptr & 0x80) >> 7; const WebRtc_UWord8 level = (*ptr & 0x7f); // DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u, level=%u", ID, len, V, level); } parsedPacket.header.headerLength += XLen; } return true; } // RTP payload parser ModuleRTPUtility::RTPPayloadParser::RTPPayloadParser(const RtpVideoCodecTypes videoType, const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadDataLength) : _dataPtr(payloadData), _dataLength(payloadDataLength), _videoType(videoType) { } ModuleRTPUtility::RTPPayloadParser::~RTPPayloadParser() { } bool ModuleRTPUtility::RTPPayloadParser::Parse( RTPPayload& parsedPacket) const { parsedPacket.SetType(_videoType); switch (_videoType) { case kRtpNoVideo: return ParseGeneric(parsedPacket); case kRtpH263Video: return ParseH263(parsedPacket); case kRtpH2631998Video: return ParseH2631998(parsedPacket); case kRtpMpeg4Video: return ParseMPEG4(parsedPacket); case kRtpVp8Video: return ParseVP8(parsedPacket); default: return false; } } bool ModuleRTPUtility::RTPPayloadParser::ParseGeneric(RTPPayload& /*parsedPacket*/) const { return false; } bool ModuleRTPUtility::RTPPayloadParser::ParseH263(RTPPayload& parsedPacket) const { if(_dataLength <= 2) { // data length sanity check. return false; } const WebRtc_UWord8 header1 = _dataPtr[0]; const WebRtc_UWord8 header2 = _dataPtr[1]; bool modeA = false; bool modeB = false; bool modeC = false; parsedPacket.frameType = ((header2 & 0x10) == 0) ? kIFrame : kPFrame; unsigned int h263HeaderLength = 0; if ((header1 & 0x80) == 0) { // Mode A modeA = true; h263HeaderLength = 4; } else { // In Mode B and Mode C, I bit is in 5th byte of header const WebRtc_UWord8 header5 = _dataPtr[4]; parsedPacket.frameType = ((header5 & 0x80) == 0) ? kIFrame : kPFrame; if((header1 & 0x40) == 0) { // IMPROVEMENT use the information in the H263 header? GQuant of the first MB modeB = true; h263HeaderLength = 8; }else { modeC = true; h263HeaderLength = 12; } } if (_dataLength < h263HeaderLength) { // Received empty H263 packet return false; } // Get SBIT and EBIT WebRtc_UWord8 sbit = 0; WebRtc_UWord8 ebit = 0; const WebRtc_UWord8 seBit = header1 & 0x3f; if (seBit) { // We got SBIT or EBIT sbit = (seBit >> 3) & 0x07; ebit = seBit & 0x07; } const bool isH263PictureStartCode = H263PictureStartCode(_dataPtr + h263HeaderLength); if (isH263PictureStartCode) { // parse out real size and inform the decoder WebRtc_UWord16 width = 0; WebRtc_UWord16 height = 0; GetH263FrameSize(_dataPtr + h263HeaderLength, width, height); parsedPacket.info.H263.hasPictureStartCode = true; parsedPacket.info.H263.frameWidth = width; parsedPacket.info.H263.frameHeight = height; } parsedPacket.info.H263.startBits = sbit; parsedPacket.info.H263.endBits = ebit; parsedPacket.info.H263.data = _dataPtr + h263HeaderLength; parsedPacket.info.H263.dataLength = _dataLength - h263HeaderLength; parsedPacket.info.H263.insert2byteStartCode = false; // not used in this mode parsedPacket.info.H263.hasPbit = true; // not used in this mode return true; } bool ModuleRTPUtility::RTPPayloadParser::ParseH2631998( RTPPayload& parsedPacket) const { unsigned int h2631998HeaderLength = 2; if(_dataLength <= h2631998HeaderLength) { // Received empty H263 (1998) packet return false; } const WebRtc_UWord8 header1 = _dataPtr[0]; const WebRtc_UWord8 header2 = _dataPtr[1]; parsedPacket.frameType = kPFrame; WebRtc_UWord8 p = (header1 >> 2) & 0x01; // picture start or a picture segment WebRtc_UWord8 vrc = header1 & 0x02; // Video Redundancy Coding (VRC) WebRtc_UWord8 pLen = ((header1 & 0x01) << 5) + ((header2 >> 3) & 0x1f); // Length, in bytes, of the extra picture header //WebRtc_UWord8 peBit = (header2 & 0x07); // number of bits that shall be ignored in the last byte of the extra picture header if (vrc) { return false; } if (pLen > 0) { h2631998HeaderLength += pLen; //get extra header // IMPROVEMENT we don't use the redundant picture header } if (_dataLength <= h2631998HeaderLength) { // Received empty H263 (1998) packet return false; } // if p == 0 // it's a follow-on packet, hence it's not independently decodable const bool isH263PictureStartCode = H263PictureStartCode(_dataPtr + h2631998HeaderLength, (p>0)?true:false); if (isH263PictureStartCode) { // parse out real size and inform the decoder WebRtc_UWord16 width = 0; WebRtc_UWord16 height = 0; if(p) { parsedPacket.frameType = GetH263FrameType(_dataPtr + h2631998HeaderLength - 2); GetH263FrameSize(_dataPtr + h2631998HeaderLength - 2, width, height); } parsedPacket.info.H263.hasPictureStartCode = true; parsedPacket.info.H263.frameWidth = width; parsedPacket.info.H263.frameHeight = height; } parsedPacket.info.H263.hasPbit = (p>0)?true:false; parsedPacket.info.H263.insert2byteStartCode = (p>0)?true:false; parsedPacket.info.H263.data = _dataPtr + h2631998HeaderLength; parsedPacket.info.H263.dataLength = _dataLength - h2631998HeaderLength; return true; } bool ModuleRTPUtility::RTPPayloadParser::ParseMPEG4( RTPPayload& parsedPacket) const { if (_dataLength <= 5) { // Received empty MPEG4 packet return false; } parsedPacket.frameType = kPFrame; if (_dataPtr[0] == 0 && _dataPtr[1] == 0 && _dataPtr[2] == 1) { parsedPacket.info.MPEG4.isFirstPacket = true; if (!(_dataPtr[4] & 0x40)) { parsedPacket.frameType = kIFrame; } } parsedPacket.info.MPEG4.data = _dataPtr; parsedPacket.info.MPEG4.dataLength = _dataLength; return true; } bool ModuleRTPUtility::RTPPayloadParser::ParseVP8(RTPPayload& parsedPacket) const { parsedPacket.info.VP8.hasPictureID = (_dataPtr[0] & 0x10)?true:false; parsedPacket.info.VP8.nonReferenceFrame = (_dataPtr[0] & 0x08)?true:false; parsedPacket.info.VP8.fragments = (_dataPtr[0] & 0x06)?true:false; parsedPacket.info.VP8.beginningOfFrame = (_dataPtr[0] & 0x01)?true:false; if(parsedPacket.info.VP8.fragments) { WebRtc_UWord8 fragments = (_dataPtr[0] >> 1) & 0x03; if( fragments == 1) { parsedPacket.info.VP8.startFragment = true; parsedPacket.info.VP8.stopFragment = false; } else if(fragments == 3) { parsedPacket.info.VP8.startFragment = false; parsedPacket.info.VP8.stopFragment = true; } else { parsedPacket.info.VP8.startFragment = false; parsedPacket.info.VP8.stopFragment = false; } } else { parsedPacket.info.VP8.startFragment = true; parsedPacket.info.VP8.stopFragment = true; } if(parsedPacket.info.VP8.hasPictureID) { WebRtc_UWord8 numBytesPictureId = 1; while(_dataPtr[numBytesPictureId] & 0x80) { numBytesPictureId++; } parsedPacket.frameType = (_dataPtr[1+numBytesPictureId] & 0x01) ? kPFrame : kIFrame; // first bit after picture id if(!parsedPacket.info.VP8.startFragment) { // if not start fragment parse away all picture IDs parsedPacket.info.VP8.hasPictureID = false; parsedPacket.info.VP8.data = _dataPtr+numBytesPictureId; parsedPacket.info.VP8.dataLength = _dataLength-numBytesPictureId; return true; } } else { parsedPacket.frameType = (_dataPtr[1] & 0x01) ? kPFrame : kIFrame; // first bit after picture id } parsedPacket.info.VP8.data = _dataPtr+1; parsedPacket.info.VP8.dataLength = _dataLength-1; return true; } bool ModuleRTPUtility::RTPPayloadParser::H263PictureStartCode(const WebRtc_UWord8* data, const bool skipFirst2bytes) const { // data is at least 3 bytes! if(skipFirst2bytes) { const WebRtc_UWord8 h3 = *(data); if((h3 & 0x7C) == 0 && (h3 & 0x80)) { return true; } }else { // first part of the frame const WebRtc_UWord8 h1 = *(data); const WebRtc_UWord8 h2 = *(data+1); const WebRtc_UWord8 h3 = *(data+2); if(h1 == 0 && h2 == 0 && (h3 & 0x7C) == 0 && (h3 & 0x80)) { return true; } } return false; } void ModuleRTPUtility::RTPPayloadParser::GetH263FrameSize(const WebRtc_UWord8* inputVideoBuffer, WebRtc_UWord16& width, WebRtc_UWord16& height) const { WebRtc_UWord8 uiH263PTypeFmt = (inputVideoBuffer[4] >> 2) & 0x07; if (uiH263PTypeFmt == 7) //extended PTYPE (for QQVGA, QVGA, VGA) { const WebRtc_UWord8 uiH263PlusPTypeUFEP = ((inputVideoBuffer[4] & 0x03) << 1) + ((inputVideoBuffer[5] >> 7) & 0x01); if (uiH263PlusPTypeUFEP == 1) //optional part included { WebRtc_UWord8 uiH263PlusPTypeFmt = (inputVideoBuffer[5] >> 4) & 0x07; if(uiH263PlusPTypeFmt == 6) //custom picture format { const WebRtc_UWord16 uiH263PlusPTypeCPFmt_PWI = ((inputVideoBuffer[9] & 0x7F) << 2) + ((inputVideoBuffer[10] >> 6) & 0x03); const WebRtc_UWord16 uiH263PlusPTypeCPFmt_PHI = ((inputVideoBuffer[10] & 0x1F) << 4) + ((inputVideoBuffer[11] >> 4) & 0x0F); width = (uiH263PlusPTypeCPFmt_PWI + 1)*4; width = uiH263PlusPTypeCPFmt_PHI*4; } else { switch (uiH263PlusPTypeFmt) { case 1: // SQCIF width = 128; height = 96; break; case 2: // QCIF width = 176; height = 144; break; case 3: // CIF width = 352; height = 288; break; case 4: // 4CIF width = 704; height = 576; break; case 5: // 16CIF width = 1408; height = 1152; break; default: assert(false); break; } } } } else { switch (uiH263PTypeFmt) { case 1: // SQCIF width = 128; height = 96; break; case 2: // QCIF width = 176; height = 144; break; case 3: // CIF width = 352; height = 288; break; case 4: // 4CIF width = 704; height = 576; break; case 5: // 16CIF width = 1408; height = 1152; break; default: assert(false); break; } } } ModuleRTPUtility::FrameTypes ModuleRTPUtility::RTPPayloadParser::GetH263FrameType( const WebRtc_UWord8* inputVideoBuffer) const { FrameTypes frameType = kPFrame; const WebRtc_UWord8 uiH263PTypeFmt = (inputVideoBuffer[4] >> 2) & 0x07; WebRtc_UWord8 pType = 1; if (uiH263PTypeFmt != 7) { pType = (inputVideoBuffer[4] >> 1) & 0x01; } else { const WebRtc_UWord8 uiH263PlusPTypeUFEP = ((inputVideoBuffer[4] & 0x03) << 1) + ((inputVideoBuffer[5] >> 7) & 0x01); if (uiH263PlusPTypeUFEP == 1) { pType = ((inputVideoBuffer[7] >> 2) & 0x07); } else if (uiH263PlusPTypeUFEP == 0) { pType = ((inputVideoBuffer[5] >> 4) & 0x07); } } if (pType == 0) { frameType = kIFrame; } return frameType; } } // namespace webrtc