rtp_receiver_video.cc revision 14b43beb7ce4440b30dcea31196de5b4a529cb6b
1/* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 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_receiver_video.h" 12 13#include <cassert> //assert 14#include <cstring> // memcpy() 15#include <math.h> 16 17#include "critical_section_wrapper.h" 18#include "receiver_fec.h" 19#include "rtp_rtcp_impl.h" 20#include "rtp_utility.h" 21#include "trace.h" 22 23namespace webrtc { 24WebRtc_UWord32 BitRateBPS(WebRtc_UWord16 x ) 25{ 26 return (x & 0x3fff) * WebRtc_UWord32(pow(10.0f,(2 + (x >> 14)))); 27} 28 29RTPReceiverVideo::RTPReceiverVideo(const WebRtc_Word32 id, 30 ModuleRtpRtcpImpl* owner) 31 : _id(id), 32 _criticalSectionReceiverVideo( 33 CriticalSectionWrapper::CreateCriticalSection()), 34 _currentFecFrameDecoded(false), 35 _receiveFEC(NULL) { 36} 37 38RTPReceiverVideo::~RTPReceiverVideo() { 39 delete _criticalSectionReceiverVideo; 40 delete _receiveFEC; 41} 42 43ModuleRTPUtility::Payload* RTPReceiverVideo::RegisterReceiveVideoPayload( 44 const char payloadName[RTP_PAYLOAD_NAME_SIZE], 45 const WebRtc_Word8 payloadType, 46 const WebRtc_UWord32 maxRate) { 47 RtpVideoCodecTypes videoType = kRtpNoVideo; 48 if (ModuleRTPUtility::StringCompare(payloadName, "VP8", 3)) { 49 videoType = kRtpVp8Video; 50 } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) { 51 videoType = kRtpNoVideo; 52 } else if (ModuleRTPUtility::StringCompare(payloadName, "ULPFEC", 6)) { 53 // store this 54 if (_receiveFEC == NULL) { 55 _receiveFEC = new ReceiverFEC(_id, this); 56 } 57 _receiveFEC->SetPayloadTypeFEC(payloadType); 58 videoType = kRtpFecVideo; 59 } else { 60 return NULL; 61 } 62 ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload; 63 64 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; 65 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); 66 payload->typeSpecific.Video.videoCodecType = videoType; 67 payload->typeSpecific.Video.maxRate = maxRate; 68 payload->audio = false; 69 return payload; 70} 71 72// we have no critext when calling this 73// we are not allowed to have any critsects when calling 74// CallbackOfReceivedPayloadData 75WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecific( 76 WebRtcRTPHeader* rtpHeader, 77 const WebRtc_UWord8* payloadData, 78 const WebRtc_UWord16 payloadDataLength, 79 const RtpVideoCodecTypes videoType, 80 const bool isRED, 81 const WebRtc_UWord8* incomingRtpPacket, 82 const WebRtc_UWord16 incomingRtpPacketSize, 83 const WebRtc_Word64 nowMS) { 84 WebRtc_Word32 retVal = 0; 85 86 _criticalSectionReceiverVideo->Enter(); 87 88 if (isRED) { 89 if(_receiveFEC == NULL) { 90 _criticalSectionReceiverVideo->Leave(); 91 return -1; 92 } 93 bool FECpacket = false; 94 retVal = _receiveFEC->AddReceivedFECPacket( 95 rtpHeader, 96 incomingRtpPacket, 97 payloadDataLength, 98 FECpacket); 99 if (retVal != -1) { 100 retVal = _receiveFEC->ProcessReceivedFEC(); 101 } 102 _criticalSectionReceiverVideo->Leave(); 103 104 if(retVal == 0 && FECpacket) { 105 // Callback with the received FEC packet. 106 // The normal packets are delivered after parsing. 107 // This contains the original RTP packet header but with 108 // empty payload and data length. 109 rtpHeader->frameType = kFrameEmpty; 110 // We need this for the routing. 111 WebRtc_Word32 retVal = SetCodecType(videoType, rtpHeader); 112 if(retVal != 0) { 113 return retVal; 114 } 115 // Pass the length of FEC packets so that they can be accounted for in 116 // the bandwidth estimator. 117 retVal = CallbackOfReceivedPayloadData(NULL, payloadDataLength, 118 rtpHeader); 119 } 120 } else { 121 // will leave the _criticalSectionReceiverVideo critsect 122 retVal = ParseVideoCodecSpecificSwitch(rtpHeader, 123 payloadData, 124 payloadDataLength, 125 videoType); 126 } 127 return retVal; 128} 129 130WebRtc_Word32 RTPReceiverVideo::BuildRTPheader( 131 const WebRtcRTPHeader* rtpHeader, 132 WebRtc_UWord8* dataBuffer) const { 133 dataBuffer[0] = static_cast<WebRtc_UWord8>(0x80); // version 2 134 dataBuffer[1] = static_cast<WebRtc_UWord8>(rtpHeader->header.payloadType); 135 if (rtpHeader->header.markerBit) { 136 dataBuffer[1] |= kRtpMarkerBitMask; // MarkerBit is 1 137 } 138 ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + 2, 139 rtpHeader->header.sequenceNumber); 140 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer + 4, 141 rtpHeader->header.timestamp); 142 ModuleRTPUtility::AssignUWord32ToBuffer(dataBuffer + 8, 143 rtpHeader->header.ssrc); 144 145 WebRtc_Word32 rtpHeaderLength = 12; 146 147 // Add the CSRCs if any 148 if (rtpHeader->header.numCSRCs > 0) { 149 if (rtpHeader->header.numCSRCs > 16) { 150 // error 151 assert(false); 152 } 153 WebRtc_UWord8* ptr = &dataBuffer[rtpHeaderLength]; 154 for (WebRtc_UWord32 i = 0; i < rtpHeader->header.numCSRCs; ++i) { 155 ModuleRTPUtility::AssignUWord32ToBuffer(ptr, 156 rtpHeader->header.arrOfCSRCs[i]); 157 ptr +=4; 158 } 159 dataBuffer[0] = (dataBuffer[0]&0xf0) | rtpHeader->header.numCSRCs; 160 // Update length of header 161 rtpHeaderLength += sizeof(WebRtc_UWord32)*rtpHeader->header.numCSRCs; 162 } 163 return rtpHeaderLength; 164} 165 166WebRtc_Word32 RTPReceiverVideo::ReceiveRecoveredPacketCallback( 167 WebRtcRTPHeader* rtpHeader, 168 const WebRtc_UWord8* payloadData, 169 const WebRtc_UWord16 payloadDataLength) { 170 // TODO(pwestin) Re-factor this to avoid the messy critsect handling. 171 _criticalSectionReceiverVideo->Enter(); 172 173 _currentFecFrameDecoded = true; 174 175 ModuleRTPUtility::Payload* payload = NULL; 176 if (PayloadTypeToPayload(rtpHeader->header.payloadType, payload) != 0) { 177 _criticalSectionReceiverVideo->Leave(); 178 return -1; 179 } 180 // here we can re-create the original lost packet so that we can use it for 181 // the relay we need to re-create the RED header too 182 WebRtc_UWord8 recoveredPacket[IP_PACKET_SIZE]; 183 WebRtc_UWord16 rtpHeaderLength = (WebRtc_UWord16)BuildRTPheader( 184 rtpHeader, recoveredPacket); 185 186 const WebRtc_UWord8 REDForFECHeaderLength = 1; 187 188 // replace pltype 189 recoveredPacket[1] &= 0x80; // reset 190 recoveredPacket[1] += REDPayloadType(); // replace with RED payload type 191 192 // add RED header 193 recoveredPacket[rtpHeaderLength] = rtpHeader->header.payloadType; 194 // f-bit always 0 195 196 memcpy(recoveredPacket + rtpHeaderLength + REDForFECHeaderLength, payloadData, 197 payloadDataLength); 198 199 return ParseVideoCodecSpecificSwitch( 200 rtpHeader, 201 payloadData, 202 payloadDataLength, 203 payload->typeSpecific.Video.videoCodecType); 204} 205 206WebRtc_Word32 RTPReceiverVideo::SetCodecType(const RtpVideoCodecTypes videoType, 207 WebRtcRTPHeader* rtpHeader) const { 208 switch (videoType) { 209 case kRtpNoVideo: 210 rtpHeader->type.Video.codec = kRTPVideoGeneric; 211 break; 212 case kRtpVp8Video: 213 rtpHeader->type.Video.codec = kRTPVideoVP8; 214 break; 215 case kRtpFecVideo: 216 rtpHeader->type.Video.codec = kRTPVideoFEC; 217 break; 218 } 219 return 0; 220} 221 222WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecificSwitch( 223 WebRtcRTPHeader* rtpHeader, 224 const WebRtc_UWord8* payloadData, 225 const WebRtc_UWord16 payloadDataLength, 226 const RtpVideoCodecTypes videoType) { 227 WebRtc_Word32 retVal = SetCodecType(videoType, rtpHeader); 228 if (retVal != 0) { 229 _criticalSectionReceiverVideo->Leave(); 230 return retVal; 231 } 232 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "%s(timestamp:%u)", 233 __FUNCTION__, rtpHeader->header.timestamp); 234 235 // All receive functions release _criticalSectionReceiverVideo before 236 // returning. 237 switch (videoType) { 238 case kRtpNoVideo: 239 return ReceiveGenericCodec(rtpHeader, payloadData, payloadDataLength); 240 case kRtpVp8Video: 241 return ReceiveVp8Codec(rtpHeader, payloadData, payloadDataLength); 242 case kRtpFecVideo: 243 break; 244 } 245 _criticalSectionReceiverVideo->Leave(); 246 return -1; 247} 248 249WebRtc_Word32 RTPReceiverVideo::ReceiveVp8Codec( 250 WebRtcRTPHeader* rtpHeader, 251 const WebRtc_UWord8* payloadData, 252 const WebRtc_UWord16 payloadDataLength) { 253 bool success; 254 ModuleRTPUtility::RTPPayload parsedPacket; 255 if (payloadDataLength == 0) { 256 success = true; 257 parsedPacket.info.VP8.dataLength = 0; 258 } else { 259 ModuleRTPUtility::RTPPayloadParser rtpPayloadParser(kRtpVp8Video, 260 payloadData, 261 payloadDataLength, 262 _id); 263 264 success = rtpPayloadParser.Parse(parsedPacket); 265 } 266 // from here down we only work on local data 267 _criticalSectionReceiverVideo->Leave(); 268 269 if (!success) { 270 return -1; 271 } 272 if (parsedPacket.info.VP8.dataLength == 0) { 273 // we have an "empty" VP8 packet, it's ok, could be one way video 274 // Inform the jitter buffer about this packet. 275 rtpHeader->frameType = kFrameEmpty; 276 if (CallbackOfReceivedPayloadData(NULL, 0, rtpHeader) != 0) { 277 return -1; 278 } 279 return 0; 280 } 281 rtpHeader->frameType = (parsedPacket.frameType == ModuleRTPUtility::kIFrame) ? 282 kVideoFrameKey : kVideoFrameDelta; 283 284 RTPVideoHeaderVP8 *toHeader = &rtpHeader->type.Video.codecHeader.VP8; 285 ModuleRTPUtility::RTPPayloadVP8 *fromHeader = &parsedPacket.info.VP8; 286 287 rtpHeader->type.Video.isFirstPacket = fromHeader->beginningOfPartition 288 && (fromHeader->partitionID == 0); 289 toHeader->pictureId = fromHeader->hasPictureID ? fromHeader->pictureID : 290 kNoPictureId; 291 toHeader->tl0PicIdx = fromHeader->hasTl0PicIdx ? fromHeader->tl0PicIdx : 292 kNoTl0PicIdx; 293 if (fromHeader->hasTID) { 294 toHeader->temporalIdx = fromHeader->tID; 295 toHeader->layerSync = fromHeader->layerSync; 296 } else { 297 toHeader->temporalIdx = kNoTemporalIdx; 298 toHeader->layerSync = false; 299 } 300 toHeader->keyIdx = fromHeader->hasKeyIdx ? fromHeader->keyIdx : kNoKeyIdx; 301 302 toHeader->frameWidth = fromHeader->frameWidth; 303 toHeader->frameHeight = fromHeader->frameHeight; 304 305 toHeader->partitionId = fromHeader->partitionID; 306 toHeader->beginningOfPartition = fromHeader->beginningOfPartition; 307 308 if(CallbackOfReceivedPayloadData(parsedPacket.info.VP8.data, 309 parsedPacket.info.VP8.dataLength, 310 rtpHeader) != 0) { 311 return -1; 312 } 313 return 0; 314} 315 316 317WebRtc_Word32 RTPReceiverVideo::ReceiveGenericCodec( 318 WebRtcRTPHeader* rtpHeader, 319 const WebRtc_UWord8* payloadData, 320 const WebRtc_UWord16 payloadDataLength) { 321 rtpHeader->frameType = kVideoFrameKey; 322 323 if(((SequenceNumber() + 1) == rtpHeader->header.sequenceNumber) && 324 (TimeStamp() != rtpHeader->header.timestamp)) { 325 rtpHeader->type.Video.isFirstPacket = true; 326 } 327 _criticalSectionReceiverVideo->Leave(); 328 329 if(CallbackOfReceivedPayloadData(payloadData, payloadDataLength, 330 rtpHeader) != 0) { 331 return -1; 332 } 333 return 0; 334} 335} // namespace webrtc 336