video_receive_stream.cc revision 6b8d3551681f40b880507cecc88f478a12383cc7
1/*
2 *  Copyright (c) 2013 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 "webrtc/video/video_receive_stream.h"
12
13#include <stdlib.h>
14
15#include <string>
16
17#include "webrtc/base/checks.h"
18#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19#include "webrtc/system_wrappers/interface/clock.h"
20#include "webrtc/system_wrappers/interface/logging.h"
21#include "webrtc/video/receive_statistics_proxy.h"
22#include "webrtc/video_encoder.h"
23#include "webrtc/video_receive_stream.h"
24
25namespace webrtc {
26std::string VideoReceiveStream::Decoder::ToString() const {
27  std::stringstream ss;
28  ss << "{decoder: " << (decoder != nullptr ? "(VideoDecoder)" : "nullptr");
29  ss << ", payload_type: " << payload_type;
30  ss << ", payload_name: " << payload_name;
31  ss << ", is_renderer: " << (is_renderer ? "yes" : "no");
32  ss << ", expected_delay_ms: " << expected_delay_ms;
33  ss << '}';
34
35  return ss.str();
36}
37
38std::string VideoReceiveStream::Config::ToString() const {
39  std::stringstream ss;
40  ss << "{decoders: [";
41  for (size_t i = 0; i < decoders.size(); ++i) {
42    ss << decoders[i].ToString();
43    if (i != decoders.size() - 1)
44      ss << ", ";
45  }
46  ss << ']';
47  ss << ", rtp: " << rtp.ToString();
48  ss << ", renderer: " << (renderer != nullptr ? "(renderer)" : "nullptr");
49  ss << ", render_delay_ms: " << render_delay_ms;
50  if (!sync_group.empty())
51    ss << ", sync_group: " << sync_group;
52  ss << ", pre_decode_callback: "
53     << (pre_decode_callback != nullptr ? "(EncodedFrameObserver)" : "nullptr");
54  ss << ", pre_render_callback: "
55     << (pre_render_callback != nullptr ? "(I420FrameCallback)" : "nullptr");
56  ss << ", target_delay_ms: " << target_delay_ms;
57  ss << '}';
58
59  return ss.str();
60}
61
62std::string VideoReceiveStream::Config::Rtp::ToString() const {
63  std::stringstream ss;
64  ss << "{remote_ssrc: " << remote_ssrc;
65  ss << ", local_ssrc: " << local_ssrc;
66  ss << ", rtcp_mode: " << (rtcp_mode == newapi::kRtcpCompound
67                                ? "kRtcpCompound"
68                                : "kRtcpReducedSize");
69  ss << ", rtcp_xr: ";
70  ss << "{receiver_reference_time_report: "
71     << (rtcp_xr.receiver_reference_time_report ? "on" : "off");
72  ss << '}';
73  ss << ", remb: " << (remb ? "on" : "off");
74  ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
75  ss << ", fec: " << fec.ToString();
76  ss << ", rtx: {";
77  for (auto& kv : rtx) {
78    ss << kv.first << " -> ";
79    ss << "{ssrc: " << kv.second.ssrc;
80    ss << ", payload_type: " << kv.second.payload_type;
81    ss << '}';
82  }
83  ss << '}';
84  ss << ", extensions: [";
85  for (size_t i = 0; i < extensions.size(); ++i) {
86    ss << extensions[i].ToString();
87    if (i != extensions.size() - 1)
88      ss << ", ";
89  }
90  ss << ']';
91  ss << '}';
92  return ss.str();
93}
94
95namespace internal {
96namespace {
97
98VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
99  VideoCodec codec;
100  memset(&codec, 0, sizeof(codec));
101
102  codec.plType = decoder.payload_type;
103  strcpy(codec.plName, decoder.payload_name.c_str());
104  if (decoder.payload_name == "VP8") {
105    codec.codecType = kVideoCodecVP8;
106  } else if (decoder.payload_name == "VP9") {
107    codec.codecType = kVideoCodecVP9;
108  } else if (decoder.payload_name == "H264") {
109    codec.codecType = kVideoCodecH264;
110  } else {
111    codec.codecType = kVideoCodecGeneric;
112  }
113
114  if (codec.codecType == kVideoCodecVP8) {
115    codec.codecSpecific.VP8 = VideoEncoder::GetDefaultVp8Settings();
116  } else if (codec.codecType == kVideoCodecVP9) {
117    codec.codecSpecific.VP9 = VideoEncoder::GetDefaultVp9Settings();
118  } else if (codec.codecType == kVideoCodecH264) {
119    codec.codecSpecific.H264 = VideoEncoder::GetDefaultH264Settings();
120  }
121
122  codec.width = 320;
123  codec.height = 180;
124  codec.startBitrate = codec.minBitrate = codec.maxBitrate =
125      Call::Config::kDefaultStartBitrateBps / 1000;
126
127  return codec;
128}
129}  // namespace
130
131VideoReceiveStream::VideoReceiveStream(int num_cpu_cores,
132                                       ChannelGroup* channel_group,
133                                       int channel_id,
134                                       const VideoReceiveStream::Config& config,
135                                       webrtc::VoiceEngine* voice_engine)
136    : transport_adapter_(config.rtcp_send_transport),
137      encoded_frame_proxy_(config.pre_decode_callback),
138      config_(config),
139      clock_(Clock::GetRealTimeClock()),
140      channel_group_(channel_group),
141      channel_id_(channel_id) {
142  RTC_CHECK(channel_group_->CreateReceiveChannel(
143      channel_id_, &transport_adapter_, num_cpu_cores, config));
144
145  vie_channel_ = channel_group_->GetChannel(channel_id_);
146
147  // TODO(pbos): This is not fine grained enough...
148  vie_channel_->SetProtectionMode(config_.rtp.nack.rtp_history_ms > 0, false,
149                                  -1, -1);
150  vie_channel_->SetKeyFrameRequestMethod(kKeyFrameReqPliRtcp);
151  SetRtcpMode(config_.rtp.rtcp_mode);
152
153  RTC_DCHECK(config_.rtp.remote_ssrc != 0);
154  // TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
155  RTC_DCHECK(config_.rtp.local_ssrc != 0);
156  RTC_DCHECK(config_.rtp.remote_ssrc != config_.rtp.local_ssrc);
157
158  vie_channel_->SetSSRC(config_.rtp.local_ssrc, kViEStreamTypeNormal, 0);
159  // TODO(pbos): Support multiple RTX, per video payload.
160  Config::Rtp::RtxMap::const_iterator it = config_.rtp.rtx.begin();
161  for (; it != config_.rtp.rtx.end(); ++it) {
162    RTC_DCHECK(it->second.ssrc != 0);
163    RTC_DCHECK(it->second.payload_type != 0);
164
165    vie_channel_->SetRemoteSSRCType(kViEStreamTypeRtx, it->second.ssrc);
166    vie_channel_->SetRtxReceivePayloadType(it->second.payload_type, it->first);
167  }
168
169  // TODO(pbos): Remove channel_group_ usage from VideoReceiveStream. This
170  // should be configured in call.cc.
171  channel_group_->SetChannelRembStatus(false, config_.rtp.remb, vie_channel_);
172
173  for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
174    const std::string& extension = config_.rtp.extensions[i].name;
175    int id = config_.rtp.extensions[i].id;
176    // One-byte-extension local identifiers are in the range 1-14 inclusive.
177    RTC_DCHECK_GE(id, 1);
178    RTC_DCHECK_LE(id, 14);
179    if (extension == RtpExtension::kTOffset) {
180      RTC_CHECK_EQ(0, vie_channel_->SetReceiveTimestampOffsetStatus(true, id));
181    } else if (extension == RtpExtension::kAbsSendTime) {
182      RTC_CHECK_EQ(0, vie_channel_->SetReceiveAbsoluteSendTimeStatus(true, id));
183    } else if (extension == RtpExtension::kVideoRotation) {
184      RTC_CHECK_EQ(0, vie_channel_->SetReceiveVideoRotationStatus(true, id));
185    } else if (extension == RtpExtension::kTransportSequenceNumber) {
186      RTC_CHECK_EQ(0,
187                   vie_channel_->SetReceiveTransportSequenceNumber(true, id));
188    } else {
189      RTC_NOTREACHED() << "Unsupported RTP extension.";
190    }
191  }
192
193  if (config_.rtp.fec.ulpfec_payload_type != -1) {
194    // ULPFEC without RED doesn't make sense.
195    RTC_DCHECK(config_.rtp.fec.red_payload_type != -1);
196    VideoCodec codec;
197    memset(&codec, 0, sizeof(codec));
198    codec.codecType = kVideoCodecULPFEC;
199    strcpy(codec.plName, "ulpfec");
200    codec.plType = config_.rtp.fec.ulpfec_payload_type;
201    RTC_CHECK_EQ(0, vie_channel_->SetReceiveCodec(codec));
202  }
203  if (config_.rtp.fec.red_payload_type != -1) {
204    VideoCodec codec;
205    memset(&codec, 0, sizeof(codec));
206    codec.codecType = kVideoCodecRED;
207    strcpy(codec.plName, "red");
208    codec.plType = config_.rtp.fec.red_payload_type;
209    RTC_CHECK_EQ(0, vie_channel_->SetReceiveCodec(codec));
210    if (config_.rtp.fec.red_rtx_payload_type != -1) {
211      vie_channel_->SetRtxReceivePayloadType(
212          config_.rtp.fec.red_rtx_payload_type,
213          config_.rtp.fec.red_payload_type);
214    }
215  }
216
217  if (config.rtp.rtcp_xr.receiver_reference_time_report)
218    vie_channel_->SetRtcpXrRrtrStatus(true);
219
220  stats_proxy_.reset(
221      new ReceiveStatisticsProxy(config_.rtp.remote_ssrc, clock_));
222
223  vie_channel_->RegisterReceiveStatisticsProxy(stats_proxy_.get());
224  vie_channel_->RegisterReceiveChannelRtcpStatisticsCallback(
225      stats_proxy_.get());
226  vie_channel_->RegisterReceiveChannelRtpStatisticsCallback(stats_proxy_.get());
227  vie_channel_->RegisterRtcpPacketTypeCounterObserver(stats_proxy_.get());
228
229  RTC_DCHECK(!config_.decoders.empty());
230  for (size_t i = 0; i < config_.decoders.size(); ++i) {
231    const Decoder& decoder = config_.decoders[i];
232    RTC_CHECK_EQ(0,
233                 vie_channel_->RegisterExternalDecoder(
234                     decoder.payload_type, decoder.decoder, decoder.is_renderer,
235                     decoder.is_renderer ? decoder.expected_delay_ms
236                                         : config.render_delay_ms));
237
238    VideoCodec codec = CreateDecoderVideoCodec(decoder);
239
240    RTC_CHECK_EQ(0, vie_channel_->SetReceiveCodec(codec));
241  }
242
243  incoming_video_stream_.reset(new IncomingVideoStream(0));
244  incoming_video_stream_->SetExpectedRenderDelay(config.render_delay_ms);
245  incoming_video_stream_->SetExternalCallback(this);
246  vie_channel_->SetIncomingVideoStream(incoming_video_stream_.get());
247
248  if (config.pre_decode_callback)
249    vie_channel_->RegisterPreDecodeImageCallback(&encoded_frame_proxy_);
250  vie_channel_->RegisterPreRenderCallback(this);
251}
252
253VideoReceiveStream::~VideoReceiveStream() {
254  incoming_video_stream_->Stop();
255  vie_channel_->RegisterPreRenderCallback(nullptr);
256  vie_channel_->RegisterPreDecodeImageCallback(nullptr);
257
258  for (size_t i = 0; i < config_.decoders.size(); ++i)
259    vie_channel_->DeRegisterExternalDecoder(config_.decoders[i].payload_type);
260
261  channel_group_->DeleteChannel(channel_id_);
262}
263
264void VideoReceiveStream::Start() {
265  transport_adapter_.Enable();
266  incoming_video_stream_->Start();
267  vie_channel_->StartReceive();
268}
269
270void VideoReceiveStream::Stop() {
271  incoming_video_stream_->Stop();
272  vie_channel_->StopReceive();
273  transport_adapter_.Disable();
274}
275
276void VideoReceiveStream::SetSyncChannel(VoiceEngine* voice_engine,
277                                        int audio_channel_id) {
278  if (voice_engine != nullptr && audio_channel_id != -1) {
279    VoEVideoSync* voe_sync_interface = VoEVideoSync::GetInterface(voice_engine);
280    vie_channel_->SetVoiceChannel(audio_channel_id, voe_sync_interface);
281    voe_sync_interface->Release();
282  } else {
283    vie_channel_->SetVoiceChannel(-1, nullptr);
284  }
285}
286
287VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
288  return stats_proxy_->GetStats();
289}
290
291bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
292  return vie_channel_->ReceivedRTCPPacket(packet, length) == 0;
293}
294
295bool VideoReceiveStream::DeliverRtp(const uint8_t* packet,
296                                    size_t length,
297                                    const PacketTime& packet_time) {
298  return vie_channel_->ReceivedRTPPacket(packet, length, packet_time) == 0;
299}
300
301void VideoReceiveStream::FrameCallback(VideoFrame* video_frame) {
302  stats_proxy_->OnDecodedFrame();
303
304  // Post processing is not supported if the frame is backed by a texture.
305  if (video_frame->native_handle() == NULL) {
306    if (config_.pre_render_callback)
307      config_.pre_render_callback->FrameCallback(video_frame);
308  }
309}
310
311int VideoReceiveStream::RenderFrame(const uint32_t /*stream_id*/,
312                                    const VideoFrame& video_frame) {
313  // TODO(pbos): Wire up config_.render->IsTextureSupported() and convert if not
314  // supported. Or provide methods for converting a texture frame in
315  // VideoFrame.
316
317  if (config_.renderer != nullptr)
318    config_.renderer->RenderFrame(
319        video_frame,
320        video_frame.render_time_ms() - clock_->TimeInMilliseconds());
321
322  stats_proxy_->OnRenderedFrame(video_frame.width(), video_frame.height());
323
324  return 0;
325}
326
327void VideoReceiveStream::SignalNetworkState(NetworkState state) {
328  if (state == kNetworkUp)
329    SetRtcpMode(config_.rtp.rtcp_mode);
330  if (state == kNetworkDown)
331    vie_channel_->SetRTCPMode(kRtcpOff);
332}
333
334void VideoReceiveStream::SetRtcpMode(newapi::RtcpMode mode) {
335  switch (mode) {
336    case newapi::kRtcpCompound:
337      vie_channel_->SetRTCPMode(kRtcpCompound);
338      break;
339    case newapi::kRtcpReducedSize:
340      vie_channel_->SetRTCPMode(kRtcpNonCompound);
341      break;
342  }
343}
344}  // namespace internal
345}  // namespace webrtc
346