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