blob: d3eedc36203f4b50b4ae0d983f6f5b48e96074e0 [file] [log] [blame]
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +00001/*
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
pbos@webrtc.org24e20892013-10-28 16:32:01 +000011#include "webrtc/video/video_receive_stream.h"
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000012
pbos@webrtc.org3f45c2e2013-08-05 16:22:53 +000013#include <assert.h>
14#include <stdlib.h>
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000015
mflodman@webrtc.org5e0cbcf2013-12-18 09:46:22 +000016#include <string>
17
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000018#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19#include "webrtc/system_wrappers/interface/clock.h"
pbos@webrtc.orgea15f8d2014-04-08 11:21:45 +000020#include "webrtc/system_wrappers/interface/logging.h"
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +000021#include "webrtc/video/receive_statistics_proxy.h"
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000022#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"
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +000025#include "webrtc/video_engine/include/vie_external_codec.h"
pbos@webrtc.org63301bd2013-10-21 10:34:43 +000026#include "webrtc/video_engine/include/vie_image_process.h"
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000027#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"
pbos@webrtc.org24e20892013-10-28 16:32:01 +000030#include "webrtc/video_receive_stream.h"
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000031
32namespace webrtc {
33namespace internal {
34
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +000035VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
36 const VideoReceiveStream::Config& config,
stefan@webrtc.orge0284102013-11-18 11:45:11 +000037 newapi::Transport* transport,
mflodman@webrtc.orgdadfc9e2013-12-13 09:40:45 +000038 webrtc::VoiceEngine* voice_engine,
39 int base_channel)
sprang@webrtc.org2e98d452013-11-26 11:41:59 +000040 : transport_adapter_(transport),
41 encoded_frame_proxy_(config.pre_decode_callback),
42 config_(config),
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +000043 clock_(Clock::GetRealTimeClock()),
sprang@webrtc.org2e98d452013-11-26 11:41:59 +000044 channel_(-1) {
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000045 video_engine_base_ = ViEBase::GetInterface(video_engine);
mflodman@webrtc.orgdadfc9e2013-12-13 09:40:45 +000046 video_engine_base_->CreateReceiveChannel(channel_, base_channel);
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000047 assert(channel_ != -1);
48
49 rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
50 assert(rtp_rtcp_ != NULL);
51
pbos@webrtc.orgce851092013-08-05 12:01:36 +000052 // TODO(pbos): This is not fine grained enough...
53 rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +000054 rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp);
pbos@webrtc.org51e01012013-10-17 14:14:42 +000055 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 }
pbos@webrtc.orgce851092013-08-05 12:01:36 +000063
pbos@webrtc.org4b50db12013-12-03 10:13:04 +000064 assert(config_.rtp.remote_ssrc != 0);
pbos@webrtc.orgc71929d2014-01-24 09:30:53 +000065 // TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
pbos@webrtc.org4b50db12013-12-03 10:13:04 +000066 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);
pbos@webrtc.orgc71929d2014-01-24 09:30:53 +000070 // 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
mflodman@webrtc.org7ff40892013-12-13 16:36:28 +000080 rtp_rtcp_->SetRembStatus(channel_, false, config_.rtp.remb);
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000081
pbos@webrtc.org46f72882013-12-16 12:24:44 +000082 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
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +000096 network_ = ViENetwork::GetInterface(video_engine);
97 assert(network_ != NULL);
98
pbos@webrtc.org1ddd57f2013-09-18 11:52:42 +000099 network_->RegisterSendTransport(channel_, transport_adapter_);
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000100
101 codec_ = ViECodec::GetInterface(video_engine);
102
pbos@webrtc.orgea15f8d2014-04-08 11:21:45 +0000103 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
pbos@webrtc.orge2a7a772014-03-19 08:43:57 +0000128 assert(!config_.codecs.empty());
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000129 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
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000137 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
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +0000151 external_codec_ = ViEExternalCodec::GetInterface(video_engine);
152 for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
153 ExternalVideoDecoder* decoder = &config_.external_decoders[i];
154 if (external_codec_->RegisterExternalReceiveCodec(
155 channel_,
156 decoder->payload_type,
157 decoder->decoder,
158 decoder->renderer,
pbos@webrtc.orgc71929d2014-01-24 09:30:53 +0000159 decoder->expected_delay_ms) != 0) {
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +0000160 // TODO(pbos): Abort gracefully? Can this be a runtime error?
161 abort();
162 }
163 }
164
pbos@webrtc.org30519512013-11-20 13:19:54 +0000165 render_ = ViERender::GetInterface(video_engine);
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000166 assert(render_ != NULL);
167
pbos@webrtc.org30519512013-11-20 13:19:54 +0000168 render_->AddRenderCallback(channel_, this);
pbos@webrtc.org63301bd2013-10-21 10:34:43 +0000169
stefan@webrtc.orge0284102013-11-18 11:45:11 +0000170 if (voice_engine) {
171 video_engine_base_->SetVoiceEngine(voice_engine);
172 video_engine_base_->ConnectAudioChannel(channel_, config_.audio_channel_id);
173 }
174
pbos@webrtc.org63301bd2013-10-21 10:34:43 +0000175 image_process_ = ViEImageProcess::GetInterface(video_engine);
sprang@webrtc.org2e98d452013-11-26 11:41:59 +0000176 if (config.pre_decode_callback) {
177 image_process_->RegisterPreDecodeImageCallback(channel_,
178 &encoded_frame_proxy_);
179 }
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000180 image_process_->RegisterPreRenderCallback(channel_, this);
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000181
asapersson@webrtc.orgb4263e02014-01-20 08:34:49 +0000182 if (config.rtp.rtcp_xr.receiver_reference_time_report) {
183 rtp_rtcp_->SetRtcpXrRrtrStatus(channel_, true);
184 }
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000185}
186
187VideoReceiveStream::~VideoReceiveStream() {
sprang@webrtc.org2e98d452013-11-26 11:41:59 +0000188 image_process_->DeRegisterPreRenderCallback(channel_);
189 image_process_->DeRegisterPreDecodeCallback(channel_);
pbos@webrtc.org63301bd2013-10-21 10:34:43 +0000190
pbos@webrtc.orgc5080a92013-10-01 11:33:24 +0000191 render_->RemoveRenderer(channel_);
pbos@webrtc.org63301bd2013-10-21 10:34:43 +0000192
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +0000193 for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
194 external_codec_->DeRegisterExternalReceiveCodec(
195 channel_, config_.external_decoders[i].payload_type);
196 }
pbos@webrtc.org63301bd2013-10-21 10:34:43 +0000197
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000198 network_->DeregisterSendTransport(channel_);
199
stefan@webrtc.orge0284102013-11-18 11:45:11 +0000200 video_engine_base_->SetVoiceEngine(NULL);
pbos@webrtc.org63301bd2013-10-21 10:34:43 +0000201 image_process_->Release();
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000202 video_engine_base_->Release();
pbos@webrtc.org618a0ec2013-09-09 08:26:30 +0000203 external_codec_->Release();
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000204 codec_->DeregisterDecoderObserver(channel_);
205 rtp_rtcp_->DeregisterReceiveChannelRtpStatisticsCallback(channel_,
206 stats_proxy_.get());
207 rtp_rtcp_->DeregisterReceiveChannelRtcpStatisticsCallback(channel_,
208 stats_proxy_.get());
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000209 codec_->Release();
210 network_->Release();
211 render_->Release();
212 rtp_rtcp_->Release();
213}
214
pbos@webrtc.org7f9f8402013-11-20 11:36:47 +0000215void VideoReceiveStream::StartReceiving() {
sprang@webrtc.org0a298152014-01-27 13:03:02 +0000216 transport_adapter_.Enable();
pbos@webrtc.org30519512013-11-20 13:19:54 +0000217 if (render_->StartRender(channel_) != 0)
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000218 abort();
pbos@webrtc.org30519512013-11-20 13:19:54 +0000219 if (video_engine_base_->StartReceive(channel_) != 0)
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000220 abort();
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000221}
222
pbos@webrtc.org7f9f8402013-11-20 11:36:47 +0000223void VideoReceiveStream::StopReceiving() {
pbos@webrtc.org30519512013-11-20 13:19:54 +0000224 if (render_->StopRender(channel_) != 0)
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000225 abort();
pbos@webrtc.org30519512013-11-20 13:19:54 +0000226 if (video_engine_base_->StopReceive(channel_) != 0)
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000227 abort();
sprang@webrtc.org0a298152014-01-27 13:03:02 +0000228 transport_adapter_.Disable();
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000229}
230
sprang@webrtc.org0feb8fa2014-02-07 15:32:45 +0000231VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000232 return stats_proxy_->GetStats();
233}
234
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000235void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) {
236 // TODO(pbos): Implement
237}
238
pbos@webrtc.orgce851092013-08-05 12:01:36 +0000239bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
pbos@webrtc.org24e20892013-10-28 16:32:01 +0000240 return network_->ReceivedRTCPPacket(
241 channel_, packet, static_cast<int>(length)) == 0;
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000242}
243
pbos@webrtc.orgce851092013-08-05 12:01:36 +0000244bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, size_t length) {
pbos@webrtc.org24e20892013-10-28 16:32:01 +0000245 return network_->ReceivedRTPPacket(
pbos@webrtc.orgc71929d2014-01-24 09:30:53 +0000246 channel_, packet, static_cast<int>(length), PacketTime()) == 0;
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000247}
248
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000249void 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
pbos@webrtc.org30519512013-11-20 13:19:54 +0000256int32_t VideoReceiveStream::RenderFrame(const uint32_t stream_id,
257 I420VideoFrame& video_frame) {
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000258 if (config_.renderer != NULL)
259 config_.renderer->RenderFrame(
260 video_frame,
261 video_frame.render_time_ms() - clock_->TimeInMilliseconds());
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000262
sprang@webrtc.orgc8ab7212014-02-07 12:06:29 +0000263 stats_proxy_->OnRenderedFrame();
264
pbos@webrtc.org2a9108f2013-05-16 12:08:03 +0000265 return 0;
266}
mflodman@webrtc.orgdadfc9e2013-12-13 09:40:45 +0000267} // namespace internal
268} // namespace webrtc