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