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