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