• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VideoReceiveStream(webrtc::VideoEngine * video_engine,const VideoReceiveStream::Config & config,newapi::Transport * transport,webrtc::VoiceEngine * voice_engine,int base_channel)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 
~VideoReceiveStream()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 
Start()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 
Stop()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 
GetStats() const224 VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
225   return stats_proxy_->GetStats();
226 }
227 
GetCurrentReceiveCodec(VideoCodec * receive_codec)228 void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) {
229   // TODO(pbos): Implement
230 }
231 
DeliverRtcp(const uint8_t * packet,size_t length)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 
DeliverRtp(const uint8_t * packet,size_t length)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 
FrameCallback(I420VideoFrame * video_frame)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 
RenderFrame(const uint32_t stream_id,I420VideoFrame & video_frame)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 
SignalNetworkState(Call::NetworkState state)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 
SetRtcpMode(newapi::RtcpMode mode)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