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 <assert.h> 14 #include <stdlib.h> 15 16 #include <string> 17 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_engine/include/vie_base.h" 23 #include "webrtc/video_engine/include/vie_capture.h" 24 #include "webrtc/video_engine/include/vie_codec.h" 25 #include "webrtc/video_engine/include/vie_external_codec.h" 26 #include "webrtc/video_engine/include/vie_image_process.h" 27 #include "webrtc/video_engine/include/vie_network.h" 28 #include "webrtc/video_engine/include/vie_render.h" 29 #include "webrtc/video_engine/include/vie_rtp_rtcp.h" 30 #include "webrtc/video_receive_stream.h" 31 32 namespace webrtc { 33 namespace internal { 34 35 VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine, 36 const VideoReceiveStream::Config& config, 37 newapi::Transport* transport, 38 webrtc::VoiceEngine* voice_engine, 39 int base_channel) 40 : transport_adapter_(transport), 41 encoded_frame_proxy_(config.pre_decode_callback), 42 config_(config), 43 clock_(Clock::GetRealTimeClock()), 44 channel_(-1) { 45 video_engine_base_ = ViEBase::GetInterface(video_engine); 46 video_engine_base_->CreateReceiveChannel(channel_, base_channel); 47 assert(channel_ != -1); 48 49 rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine); 50 assert(rtp_rtcp_ != NULL); 51 52 // TODO(pbos): This is not fine grained enough... 53 rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0); 54 rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp); 55 SetRtcpMode(config_.rtp.rtcp_mode); 56 57 assert(config_.rtp.remote_ssrc != 0); 58 // TODO(pbos): What's an appropriate local_ssrc for receive-only streams? 59 assert(config_.rtp.local_ssrc != 0); 60 assert(config_.rtp.remote_ssrc != config_.rtp.local_ssrc); 61 62 rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.local_ssrc); 63 // TODO(pbos): Support multiple RTX, per video payload. 64 Config::Rtp::RtxMap::const_iterator it = config_.rtp.rtx.begin(); 65 if (it != config_.rtp.rtx.end()) { 66 assert(it->second.ssrc != 0); 67 assert(it->second.payload_type != 0); 68 69 rtp_rtcp_->SetRemoteSSRCType(channel_, kViEStreamTypeRtx, it->second.ssrc); 70 rtp_rtcp_->SetRtxReceivePayloadType(channel_, it->second.payload_type); 71 } 72 73 rtp_rtcp_->SetRembStatus(channel_, false, config_.rtp.remb); 74 75 for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) { 76 const std::string& extension = config_.rtp.extensions[i].name; 77 int id = config_.rtp.extensions[i].id; 78 if (extension == RtpExtension::kTOffset) { 79 if (rtp_rtcp_->SetReceiveTimestampOffsetStatus(channel_, true, id) != 0) 80 abort(); 81 } else if (extension == RtpExtension::kAbsSendTime) { 82 if (rtp_rtcp_->SetReceiveAbsoluteSendTimeStatus(channel_, true, id) != 0) 83 abort(); 84 } else { 85 abort(); // Unsupported extension. 86 } 87 } 88 89 network_ = ViENetwork::GetInterface(video_engine); 90 assert(network_ != NULL); 91 92 network_->RegisterSendTransport(channel_, transport_adapter_); 93 94 codec_ = ViECodec::GetInterface(video_engine); 95 96 if (config_.rtp.fec.ulpfec_payload_type != -1) { 97 // ULPFEC without RED doesn't make sense. 98 assert(config_.rtp.fec.red_payload_type != -1); 99 VideoCodec codec; 100 memset(&codec, 0, sizeof(codec)); 101 codec.codecType = kVideoCodecULPFEC; 102 strcpy(codec.plName, "ulpfec"); 103 codec.plType = config_.rtp.fec.ulpfec_payload_type; 104 if (codec_->SetReceiveCodec(channel_, codec) != 0) { 105 LOG(LS_ERROR) << "Could not set ULPFEC codec. This shouldn't happen."; 106 abort(); 107 } 108 } 109 if (config_.rtp.fec.red_payload_type != -1) { 110 VideoCodec codec; 111 memset(&codec, 0, sizeof(codec)); 112 codec.codecType = kVideoCodecRED; 113 strcpy(codec.plName, "red"); 114 codec.plType = config_.rtp.fec.red_payload_type; 115 if (codec_->SetReceiveCodec(channel_, codec) != 0) { 116 LOG(LS_ERROR) << "Could not set RED codec. This shouldn't happen."; 117 abort(); 118 } 119 } 120 121 assert(!config_.codecs.empty()); 122 for (size_t i = 0; i < config_.codecs.size(); ++i) { 123 if (codec_->SetReceiveCodec(channel_, config_.codecs[i]) != 0) { 124 // TODO(pbos): Abort gracefully, this can be a runtime error. 125 // Factor out to an Init() method. 126 abort(); 127 } 128 } 129 130 stats_proxy_.reset(new ReceiveStatisticsProxy( 131 config_.rtp.local_ssrc, clock_, rtp_rtcp_, codec_, channel_)); 132 133 if (rtp_rtcp_->RegisterReceiveChannelRtcpStatisticsCallback( 134 channel_, stats_proxy_.get()) != 0) 135 abort(); 136 137 if (rtp_rtcp_->RegisterReceiveChannelRtpStatisticsCallback( 138 channel_, stats_proxy_.get()) != 0) 139 abort(); 140 141 if (codec_->RegisterDecoderObserver(channel_, *stats_proxy_) != 0) 142 abort(); 143 144 external_codec_ = ViEExternalCodec::GetInterface(video_engine); 145 for (size_t i = 0; i < config_.external_decoders.size(); ++i) { 146 const ExternalVideoDecoder& decoder = config_.external_decoders[i]; 147 if (external_codec_->RegisterExternalReceiveCodec( 148 channel_, 149 decoder.payload_type, 150 decoder.decoder, 151 decoder.renderer, 152 decoder.expected_delay_ms) != 0) { 153 // TODO(pbos): Abort gracefully? Can this be a runtime error? 154 abort(); 155 } 156 } 157 158 render_ = ViERender::GetInterface(video_engine); 159 assert(render_ != NULL); 160 161 render_->AddRenderCallback(channel_, this); 162 163 if (voice_engine) { 164 video_engine_base_->SetVoiceEngine(voice_engine); 165 video_engine_base_->ConnectAudioChannel(channel_, config_.audio_channel_id); 166 } 167 168 image_process_ = ViEImageProcess::GetInterface(video_engine); 169 if (config.pre_decode_callback) { 170 image_process_->RegisterPreDecodeImageCallback(channel_, 171 &encoded_frame_proxy_); 172 } 173 image_process_->RegisterPreRenderCallback(channel_, this); 174 175 if (config.rtp.rtcp_xr.receiver_reference_time_report) { 176 rtp_rtcp_->SetRtcpXrRrtrStatus(channel_, true); 177 } 178 } 179 180 VideoReceiveStream::~VideoReceiveStream() { 181 image_process_->DeRegisterPreRenderCallback(channel_); 182 image_process_->DeRegisterPreDecodeCallback(channel_); 183 184 render_->RemoveRenderer(channel_); 185 186 for (size_t i = 0; i < config_.external_decoders.size(); ++i) { 187 external_codec_->DeRegisterExternalReceiveCodec( 188 channel_, config_.external_decoders[i].payload_type); 189 } 190 191 network_->DeregisterSendTransport(channel_); 192 193 video_engine_base_->SetVoiceEngine(NULL); 194 image_process_->Release(); 195 video_engine_base_->Release(); 196 external_codec_->Release(); 197 codec_->DeregisterDecoderObserver(channel_); 198 rtp_rtcp_->DeregisterReceiveChannelRtpStatisticsCallback(channel_, 199 stats_proxy_.get()); 200 rtp_rtcp_->DeregisterReceiveChannelRtcpStatisticsCallback(channel_, 201 stats_proxy_.get()); 202 codec_->Release(); 203 network_->Release(); 204 render_->Release(); 205 rtp_rtcp_->Release(); 206 } 207 208 void VideoReceiveStream::Start() { 209 transport_adapter_.Enable(); 210 if (render_->StartRender(channel_) != 0) 211 abort(); 212 if (video_engine_base_->StartReceive(channel_) != 0) 213 abort(); 214 } 215 216 void VideoReceiveStream::Stop() { 217 if (render_->StopRender(channel_) != 0) 218 abort(); 219 if (video_engine_base_->StopReceive(channel_) != 0) 220 abort(); 221 transport_adapter_.Disable(); 222 } 223 224 VideoReceiveStream::Stats VideoReceiveStream::GetStats() const { 225 return stats_proxy_->GetStats(); 226 } 227 228 void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) { 229 // TODO(pbos): Implement 230 } 231 232 bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) { 233 return network_->ReceivedRTCPPacket( 234 channel_, packet, static_cast<int>(length)) == 0; 235 } 236 237 bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, size_t length) { 238 return network_->ReceivedRTPPacket( 239 channel_, packet, static_cast<int>(length), PacketTime()) == 0; 240 } 241 242 void VideoReceiveStream::FrameCallback(I420VideoFrame* video_frame) { 243 stats_proxy_->OnDecodedFrame(); 244 245 if (config_.pre_render_callback) 246 config_.pre_render_callback->FrameCallback(video_frame); 247 } 248 249 int32_t VideoReceiveStream::RenderFrame(const uint32_t stream_id, 250 I420VideoFrame& video_frame) { 251 if (config_.renderer != NULL) 252 config_.renderer->RenderFrame( 253 video_frame, 254 video_frame.render_time_ms() - clock_->TimeInMilliseconds()); 255 256 stats_proxy_->OnRenderedFrame(); 257 258 return 0; 259 } 260 261 void VideoReceiveStream::SignalNetworkState(Call::NetworkState state) { 262 if (state == Call::kNetworkUp) 263 SetRtcpMode(config_.rtp.rtcp_mode); 264 network_->SetNetworkTransmissionState(channel_, state == Call::kNetworkUp); 265 if (state == Call::kNetworkDown) 266 rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone); 267 } 268 269 void VideoReceiveStream::SetRtcpMode(newapi::RtcpMode mode) { 270 switch (mode) { 271 case newapi::kRtcpCompound: 272 rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585); 273 break; 274 case newapi::kRtcpReducedSize: 275 rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNonCompound_RFC5506); 276 break; 277 } 278 } 279 } // namespace internal 280 } // namespace webrtc 281