blob: cca0511790e6e3e21f2ede2b3bc3f623d9d1d57b [file] [log] [blame]
pbos@webrtc.org29d58392013-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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/video_receive_stream.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <stdlib.h>
pbos@webrtc.org29d58392013-05-16 12:08:03 +000014
mflodmand1590b22015-12-09 07:07:59 -080015#include <set>
mflodman@webrtc.orgb429e512013-12-18 09:46:22 +000016#include <string>
Erik Språng737336d2016-07-29 12:59:36 +020017#include <utility>
mflodman@webrtc.orgb429e512013-12-18 09:46:22 +000018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/optional.h"
20#include "call/rtp_stream_receiver_controller_interface.h"
21#include "call/rtx_receive_stream.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020022#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "common_video/h264/profile_level_id.h"
24#include "common_video/libyuv/include/webrtc_libyuv.h"
25#include "modules/rtp_rtcp/include/rtp_receiver.h"
26#include "modules/rtp_rtcp/include/rtp_rtcp.h"
27#include "modules/utility/include/process_thread.h"
28#include "modules/video_coding/frame_object.h"
29#include "modules/video_coding/include/video_coding.h"
30#include "modules/video_coding/jitter_estimator.h"
31#include "modules/video_coding/timing.h"
32#include "modules/video_coding/utility/ivf_file_writer.h"
33#include "rtc_base/checks.h"
34#include "rtc_base/location.h"
35#include "rtc_base/logging.h"
36#include "rtc_base/ptr_util.h"
37#include "rtc_base/trace_event.h"
38#include "system_wrappers/include/clock.h"
39#include "system_wrappers/include/field_trial.h"
40#include "video/call_stats.h"
41#include "video/receive_statistics_proxy.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000042
43namespace webrtc {
mflodmana20de202015-10-18 22:08:19 -070044
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000045namespace {
46VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
47 VideoCodec codec;
48 memset(&codec, 0, sizeof(codec));
49
50 codec.plType = decoder.payload_type;
mflodmand1590b22015-12-09 07:07:59 -080051 strncpy(codec.plName, decoder.payload_name.c_str(), sizeof(codec.plName));
kthelgason1cdddc92017-08-24 03:52:48 -070052 codec.codecType = PayloadStringToCodecType(decoder.payload_name);
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000053
54 if (codec.codecType == kVideoCodecVP8) {
hta257dc392016-10-25 09:05:06 -070055 *(codec.VP8()) = VideoEncoder::GetDefaultVp8Settings();
ivica05cfcd32015-09-07 06:04:16 -070056 } else if (codec.codecType == kVideoCodecVP9) {
hta257dc392016-10-25 09:05:06 -070057 *(codec.VP9()) = VideoEncoder::GetDefaultVp9Settings();
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000058 } else if (codec.codecType == kVideoCodecH264) {
hta257dc392016-10-25 09:05:06 -070059 *(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
magjede69a1a92016-11-25 10:06:31 -080060 codec.H264()->profile =
61 H264::ParseSdpProfileLevelId(decoder.codec_params)->profile;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000062 }
63
64 codec.width = 320;
65 codec.height = 180;
stefanb4bc65b2016-11-02 10:10:20 -070066 const int kDefaultStartBitrate = 300;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000067 codec.startBitrate = codec.minBitrate = codec.maxBitrate =
stefanb4bc65b2016-11-02 10:10:20 -070068 kDefaultStartBitrate;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000069
70 return codec;
71}
72} // namespace
pbos@webrtc.org29d58392013-05-16 12:08:03 +000073
Peter Boströmca835252016-02-11 15:59:46 +010074namespace internal {
tommi2e82f382016-06-21 00:26:43 -070075
nisse0f15f922017-06-21 01:05:22 -070076VideoReceiveStream::VideoReceiveStream(
77 RtpStreamReceiverControllerInterface* receiver_controller,
78 int num_cpu_cores,
79 PacketRouter* packet_router,
80 VideoReceiveStream::Config config,
81 ProcessThread* process_thread,
82 CallStats* call_stats)
solenberg4fbae2b2015-08-28 04:07:10 -070083 : transport_adapter_(config.rtcp_send_transport),
Tommi733b5472016-06-10 17:58:01 +020084 config_(std::move(config)),
sprang113bdca2016-10-11 03:10:10 -070085 num_cpu_cores_(num_cpu_cores),
Peter Boström1d04ac62016-02-05 11:25:46 +010086 process_thread_(process_thread),
sprang@webrtc.org09315702014-02-07 12:06:29 +000087 clock_(Clock::GetRealTimeClock()),
tommic8ece432017-06-20 02:44:38 -070088 decode_thread_(&DecodeThreadFunction,
89 this,
90 "DecodingThread",
91 rtc::kHighestPriority),
Peter Boström1d04ac62016-02-05 11:25:46 +010092 call_stats_(call_stats),
nisseca5706d2017-09-11 02:32:16 -070093 rtp_receive_statistics_(ReceiveStatistics::Create(clock_)),
philipelfd5a20f2016-11-15 00:57:57 -080094 timing_(new VCMTiming(clock_)),
philipel721d4022016-12-15 07:10:57 -080095 video_receiver_(clock_, nullptr, this, timing_.get(), this, this),
96 stats_proxy_(&config_, clock_),
nisseb1f2ff92017-06-09 04:01:55 -070097 rtp_video_stream_receiver_(&transport_adapter_,
98 call_stats_->rtcp_rtt_stats(),
99 packet_router,
100 &config_,
nisseca5706d2017-09-11 02:32:16 -0700101 rtp_receive_statistics_.get(),
nisseb1f2ff92017-06-09 04:01:55 -0700102 &stats_proxy_,
103 process_thread_,
104 this, // NackSender
105 this, // KeyFrameRequestSender
106 this, // OnCompleteFrameCallback
107 timing_.get()),
philipela45102f2017-02-22 05:30:39 -0800108 rtp_stream_sync_(this) {
pbosa2f30de2015-10-15 05:22:13 -0700109 LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000110
Stefan Holmer58c664c2016-02-08 14:31:30 +0100111 RTC_DCHECK(process_thread_);
Stefan Holmer58c664c2016-02-08 14:31:30 +0100112 RTC_DCHECK(call_stats_);
mflodmancfc8e3b2016-05-03 21:22:04 -0700113
eladalona28122f2017-08-18 04:02:48 -0700114 module_process_sequence_checker_.Detach();
solenberg3ebbcb52017-01-31 03:58:40 -0800115
henrikg91d6ede2015-09-17 00:24:34 -0700116 RTC_DCHECK(!config_.decoders.empty());
Peter Boström521af4e2015-11-27 16:35:04 +0100117 std::set<int> decoder_payload_types;
Peter Boströmb1ae3a42016-02-15 17:52:40 +0100118 for (const Decoder& decoder : config_.decoders) {
Peter Boström795dbe42015-11-27 14:09:07 +0100119 RTC_CHECK(decoder.decoder);
Peter Boström521af4e2015-11-27 16:35:04 +0100120 RTC_CHECK(decoder_payload_types.find(decoder.payload_type) ==
121 decoder_payload_types.end())
122 << "Duplicate payload type (" << decoder.payload_type
123 << ") for different decoders.";
124 decoder_payload_types.insert(decoder.payload_type);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000125 }
126
nisseca5706d2017-09-11 02:32:16 -0700127 video_receiver_.SetRenderDelay(config_.render_delay_ms);
Peter Boström1d04ac62016-02-05 11:25:46 +0100128
philipela45102f2017-02-22 05:30:39 -0800129 jitter_estimator_.reset(new VCMJitterEstimator(clock_));
130 frame_buffer_.reset(new video_coding::FrameBuffer(
131 clock_, jitter_estimator_.get(), timing_.get(), &stats_proxy_));
philipelfd5a20f2016-11-15 00:57:57 -0800132
tommidea489f2017-03-03 03:20:24 -0800133 process_thread_->RegisterModule(&rtp_stream_sync_, RTC_FROM_HERE);
nisse0f15f922017-06-21 01:05:22 -0700134
135 // Register with RtpStreamReceiverController.
136 media_receiver_ = receiver_controller->CreateReceiver(
137 config_.rtp.remote_ssrc, &rtp_video_stream_receiver_);
nisseca5706d2017-09-11 02:32:16 -0700138 if (config_.rtp.rtx_ssrc) {
139 rtx_receive_stream_ = rtc::MakeUnique<RtxReceiveStream>(
140 &rtp_video_stream_receiver_, config.rtp.rtx_associated_payload_types,
141 config_.rtp.remote_ssrc, rtp_receive_statistics_.get());
nisse0f15f922017-06-21 01:05:22 -0700142 rtx_receiver_ = receiver_controller->CreateReceiver(
nisseca5706d2017-09-11 02:32:16 -0700143 config_.rtp.rtx_ssrc, rtx_receive_stream_.get());
nisse0f15f922017-06-21 01:05:22 -0700144 }
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000145}
146
147VideoReceiveStream::~VideoReceiveStream() {
eladalona28122f2017-08-18 04:02:48 -0700148 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
pbosa2f30de2015-10-15 05:22:13 -0700149 LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString();
Peter Boströmca835252016-02-11 15:59:46 +0100150 Stop();
151
mflodman4cd27902016-08-05 06:28:45 -0700152 process_thread_->DeRegisterModule(&rtp_stream_sync_);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000153}
154
pbos1ba8d392016-05-01 20:18:34 -0700155void VideoReceiveStream::SignalNetworkState(NetworkState state) {
eladalona28122f2017-08-18 04:02:48 -0700156 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700157 rtp_video_stream_receiver_.SignalNetworkState(state);
pbos1ba8d392016-05-01 20:18:34 -0700158}
159
pbos1ba8d392016-05-01 20:18:34 -0700160bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
nisseb1f2ff92017-06-09 04:01:55 -0700161 return rtp_video_stream_receiver_.DeliverRtcp(packet, length);
pbos1ba8d392016-05-01 20:18:34 -0700162}
163
solenberg3ebbcb52017-01-31 03:58:40 -0800164void VideoReceiveStream::SetSync(Syncable* audio_syncable) {
eladalona28122f2017-08-18 04:02:48 -0700165 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800166 rtp_stream_sync_.ConfigureSync(audio_syncable);
brandtr090c9402017-01-25 08:28:02 -0800167}
168
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000169void VideoReceiveStream::Start() {
eladalona28122f2017-08-18 04:02:48 -0700170 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
Peter Boströmca835252016-02-11 15:59:46 +0100171 if (decode_thread_.IsRunning())
172 return;
brandtrfb45c6c2017-01-27 06:47:55 -0800173
nissec69385d2017-03-09 06:13:20 -0800174 bool protected_by_fec = config_.rtp.protected_by_flexfec ||
nisseb1f2ff92017-06-09 04:01:55 -0700175 rtp_video_stream_receiver_.IsUlpfecEnabled();
brandtrfb45c6c2017-01-27 06:47:55 -0800176
philipela45102f2017-02-22 05:30:39 -0800177 frame_buffer_->Start();
nisseb1f2ff92017-06-09 04:01:55 -0700178 call_stats_->RegisterStatsObserver(&rtp_video_stream_receiver_);
philipele21be1d2017-09-25 06:37:12 -0700179 call_stats_->RegisterStatsObserver(this);
philipelfd5a20f2016-11-15 00:57:57 -0800180
nisseb1f2ff92017-06-09 04:01:55 -0700181 if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
182 protected_by_fec) {
philipela45102f2017-02-22 05:30:39 -0800183 frame_buffer_->SetProtectionMode(kProtectionNackFEC);
philipelfd5a20f2016-11-15 00:57:57 -0800184 }
philipela45102f2017-02-22 05:30:39 -0800185
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000186 transport_adapter_.Enable();
tommi2e82f382016-06-21 00:26:43 -0700187 rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
188 if (config_.renderer) {
189 if (config_.disable_prerenderer_smoothing) {
190 renderer = this;
191 } else {
192 incoming_video_stream_.reset(
193 new IncomingVideoStream(config_.render_delay_ms, this));
194 renderer = incoming_video_stream_.get();
195 }
196 }
sakal55d932b2016-09-30 06:19:08 -0700197 RTC_DCHECK(renderer != nullptr);
tommi2e82f382016-06-21 00:26:43 -0700198
sprang113bdca2016-10-11 03:10:10 -0700199 for (const Decoder& decoder : config_.decoders) {
200 video_receiver_.RegisterExternalDecoder(decoder.decoder,
201 decoder.payload_type);
sprang113bdca2016-10-11 03:10:10 -0700202 VideoCodec codec = CreateDecoderVideoCodec(decoder);
nisseb1f2ff92017-06-09 04:01:55 -0700203 RTC_CHECK(rtp_video_stream_receiver_.AddReceiveCodec(codec,
204 decoder.codec_params));
sprang113bdca2016-10-11 03:10:10 -0700205 RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
206 &codec, num_cpu_cores_, false));
207 }
208
tommi2e82f382016-06-21 00:26:43 -0700209 video_stream_decoder_.reset(new VideoStreamDecoder(
nisseb1f2ff92017-06-09 04:01:55 -0700210 &video_receiver_, &rtp_video_stream_receiver_,
211 &rtp_video_stream_receiver_,
212 rtp_video_stream_receiver_.IsRetransmissionsEnabled(), protected_by_fec,
nisse76bc8e82017-02-07 09:37:41 -0800213 &stats_proxy_, renderer));
tommi2e82f382016-06-21 00:26:43 -0700214 // Register the channel to receive stats updates.
215 call_stats_->RegisterStatsObserver(video_stream_decoder_.get());
tommic8ece432017-06-20 02:44:38 -0700216
217 process_thread_->RegisterModule(&video_receiver_, RTC_FROM_HERE);
218
Peter Boströmca835252016-02-11 15:59:46 +0100219 // Start the decode thread
220 decode_thread_.Start();
nisseb1f2ff92017-06-09 04:01:55 -0700221 rtp_video_stream_receiver_.StartReceive();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000222}
223
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000224void VideoReceiveStream::Stop() {
eladalona28122f2017-08-18 04:02:48 -0700225 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700226 rtp_video_stream_receiver_.StopReceive();
philipelfd5a20f2016-11-15 00:57:57 -0800227
philipela45102f2017-02-22 05:30:39 -0800228 frame_buffer_->Stop();
philipele21be1d2017-09-25 06:37:12 -0700229 call_stats_->DeregisterStatsObserver(this);
nisseb1f2ff92017-06-09 04:01:55 -0700230 call_stats_->DeregisterStatsObserver(&rtp_video_stream_receiver_);
tommic8ece432017-06-20 02:44:38 -0700231 process_thread_->DeRegisterModule(&video_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800232
sprang0d348d62016-10-07 08:28:39 -0700233 if (decode_thread_.IsRunning()) {
tommic8ece432017-06-20 02:44:38 -0700234 // TriggerDecoderShutdown will release any waiting decoder thread and make
235 // it stop immediately, instead of waiting for a timeout. Needs to be called
236 // before joining the decoder thread.
237 video_receiver_.TriggerDecoderShutdown();
238
sprang0d348d62016-10-07 08:28:39 -0700239 decode_thread_.Stop();
240 // Deregister external decoders so they are no longer running during
241 // destruction. This effectively stops the VCM since the decoder thread is
242 // stopped, the VCM is deregistered and no asynchronous decoder threads are
243 // running.
244 for (const Decoder& decoder : config_.decoders)
245 video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
246 }
philipelfd5a20f2016-11-15 00:57:57 -0800247
tommi2e82f382016-06-21 00:26:43 -0700248 call_stats_->DeregisterStatsObserver(video_stream_decoder_.get());
249 video_stream_decoder_.reset();
250 incoming_video_stream_.reset();
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000251 transport_adapter_.Disable();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000252}
253
sprang@webrtc.org9510e532014-02-07 15:32:45 +0000254VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
Peter Boströmf751bf82016-02-05 14:00:53 +0100255 return stats_proxy_.GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000256}
257
brandtr090c9402017-01-25 08:28:02 -0800258void VideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file,
259 size_t byte_limit) {
260 {
261 rtc::CritScope lock(&ivf_writer_lock_);
262 if (file == rtc::kInvalidPlatformFileValue) {
263 ivf_writer_.reset();
264 } else {
265 ivf_writer_ = IvfFileWriter::Wrap(rtc::File(file), byte_limit);
266 }
267 }
268
269 if (file != rtc::kInvalidPlatformFileValue) {
270 // Make a keyframe appear as early as possible in the logs, to give actually
271 // decodable output.
272 RequestKeyFrame();
273 }
274}
275
eladalonc0d481a2017-08-02 07:39:07 -0700276void VideoReceiveStream::AddSecondarySink(RtpPacketSinkInterface* sink) {
277 rtp_video_stream_receiver_.AddSecondarySink(sink);
278}
279
280void VideoReceiveStream::RemoveSecondarySink(
281 const RtpPacketSinkInterface* sink) {
282 rtp_video_stream_receiver_.RemoveSecondarySink(sink);
283}
284
tommi2e82f382016-06-21 00:26:43 -0700285// TODO(tommi): This method grabs a lock 6 times.
Tommibd3380f2016-06-10 17:38:17 +0200286void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
asaperssonf8cdd182016-03-15 01:00:47 -0700287 int64_t sync_offset_ms;
asaperssonde9e5ff2016-11-02 07:14:03 -0700288 double estimated_freq_khz;
tommi2e82f382016-06-21 00:26:43 -0700289 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the
290 // function itself, another in GetChannel() and a third in
291 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function
292 // succeeds most of the time, which leads to grabbing a fourth lock.
solenberg3ebbcb52017-01-31 03:58:40 -0800293 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame.timestamp(),
294 video_frame.render_time_ms(),
295 &sync_offset_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700296 &estimated_freq_khz)) {
tommi2e82f382016-06-21 00:26:43 -0700297 // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
asaperssonde9e5ff2016-11-02 07:14:03 -0700298 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
tommi2e82f382016-06-21 00:26:43 -0700299 }
tommi2e82f382016-06-21 00:26:43 -0700300 // config_.renderer must never be null if we're getting this callback.
301 config_.renderer->OnFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000302
tommi2e82f382016-06-21 00:26:43 -0700303 // TODO(tommi): OnRenderFrame grabs a lock too.
asapersson1490f7a2016-09-23 02:09:46 -0700304 stats_proxy_.OnRenderedFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000305}
pbos@webrtc.org26c0c412014-09-03 16:17:12 +0000306
asapersson86b01602015-10-20 23:55:26 -0700307// TODO(asapersson): Consider moving callback from video_encoder.h or
308// creating a different callback.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700309EncodedImageCallback::Result VideoReceiveStream::OnEncodedImage(
asapersson86b01602015-10-20 23:55:26 -0700310 const EncodedImage& encoded_image,
311 const CodecSpecificInfo* codec_specific_info,
312 const RTPFragmentationHeader* fragmentation) {
Peter Boströmf751bf82016-02-05 14:00:53 +0100313 stats_proxy_.OnPreDecode(encoded_image, codec_specific_info);
ilnikcb8c1462017-03-09 09:23:30 -0800314 size_t simulcast_idx = 0;
315 if (codec_specific_info->codecType == kVideoCodecVP8) {
316 simulcast_idx = codec_specific_info->codecSpecific.VP8.simulcastIdx;
317 }
asapersson86b01602015-10-20 23:55:26 -0700318 if (config_.pre_decode_callback) {
ilnikcb8c1462017-03-09 09:23:30 -0800319 config_.pre_decode_callback->EncodedFrameCallback(EncodedFrame(
320 encoded_image._buffer, encoded_image._length, encoded_image._frameType,
321 simulcast_idx, encoded_image._timeStamp));
asapersson86b01602015-10-20 23:55:26 -0700322 }
palmkviste75f2042016-09-28 06:19:48 -0700323 {
324 rtc::CritScope lock(&ivf_writer_lock_);
sprang3911c262016-04-15 01:24:14 -0700325 if (ivf_writer_.get()) {
palmkviste75f2042016-09-28 06:19:48 -0700326 RTC_DCHECK(codec_specific_info);
327 bool ok = ivf_writer_->WriteFrame(encoded_image,
328 codec_specific_info->codecType);
sprang3911c262016-04-15 01:24:14 -0700329 RTC_DCHECK(ok);
330 }
331 }
332
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700333 return Result(Result::OK, encoded_image._timeStamp);
asapersson86b01602015-10-20 23:55:26 -0700334}
335
brandtr090c9402017-01-25 08:28:02 -0800336void VideoReceiveStream::SendNack(
337 const std::vector<uint16_t>& sequence_numbers) {
nisseb1f2ff92017-06-09 04:01:55 -0700338 rtp_video_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
brandtr090c9402017-01-25 08:28:02 -0800339}
340
341void VideoReceiveStream::RequestKeyFrame() {
nisseb1f2ff92017-06-09 04:01:55 -0700342 rtp_video_stream_receiver_.RequestKeyFrame();
brandtr090c9402017-01-25 08:28:02 -0800343}
344
345void VideoReceiveStream::OnCompleteFrame(
346 std::unique_ptr<video_coding::FrameObject> frame) {
347 int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
348 if (last_continuous_pid != -1)
nisseb1f2ff92017-06-09 04:01:55 -0700349 rtp_video_stream_receiver_.FrameContinuous(last_continuous_pid);
brandtr090c9402017-01-25 08:28:02 -0800350}
351
philipele21be1d2017-09-25 06:37:12 -0700352void VideoReceiveStream::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
353 frame_buffer_->UpdateRtt(max_rtt_ms);
354}
355
solenberg3ebbcb52017-01-31 03:58:40 -0800356int VideoReceiveStream::id() const {
eladalona28122f2017-08-18 04:02:48 -0700357 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800358 return config_.rtp.remote_ssrc;
359}
360
361rtc::Optional<Syncable::Info> VideoReceiveStream::GetInfo() const {
eladalona28122f2017-08-18 04:02:48 -0700362 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800363 Syncable::Info info;
364
nisseb1f2ff92017-06-09 04:01:55 -0700365 RtpReceiver* rtp_receiver = rtp_video_stream_receiver_.GetRtpReceiver();
solenberg3ebbcb52017-01-31 03:58:40 -0800366 RTC_DCHECK(rtp_receiver);
Niels Möllerc3fa8e12017-10-03 15:28:26 +0200367 if (!rtp_receiver->GetLatestTimestamps(
368 &info.latest_received_capture_timestamp,
369 &info.latest_receive_time_ms))
solenberg3ebbcb52017-01-31 03:58:40 -0800370 return rtc::Optional<Syncable::Info>();
371
nisseb1f2ff92017-06-09 04:01:55 -0700372 RtpRtcp* rtp_rtcp = rtp_video_stream_receiver_.rtp_rtcp();
solenberg3ebbcb52017-01-31 03:58:40 -0800373 RTC_DCHECK(rtp_rtcp);
374 if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs,
375 &info.capture_time_ntp_frac,
376 nullptr,
377 nullptr,
378 &info.capture_time_source_clock) != 0) {
379 return rtc::Optional<Syncable::Info>();
380 }
381
382 info.current_delay_ms = video_receiver_.Delay();
383 return rtc::Optional<Syncable::Info>(info);
384}
385
386uint32_t VideoReceiveStream::GetPlayoutTimestamp() const {
387 RTC_NOTREACHED();
388 return 0;
389}
390
391void VideoReceiveStream::SetMinimumPlayoutDelay(int delay_ms) {
eladalona28122f2017-08-18 04:02:48 -0700392 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800393 video_receiver_.SetMinimumPlayoutDelay(delay_ms);
394}
395
tommic8ece432017-06-20 02:44:38 -0700396void VideoReceiveStream::DecodeThreadFunction(void* ptr) {
397 while (static_cast<VideoReceiveStream*>(ptr)->Decode()) {
398 }
Peter Boströmca835252016-02-11 15:59:46 +0100399}
400
philipel2dfea3e2017-02-28 07:19:43 -0800401bool VideoReceiveStream::Decode() {
tommidb23ea62017-03-03 07:21:18 -0800402 TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
philipela45102f2017-02-22 05:30:39 -0800403 static const int kMaxWaitForFrameMs = 3000;
philipel3042c2d2017-08-18 04:55:02 -0700404 static const int kMaxWaitForKeyFrameMs = 200;
405
406 int wait_ms = keyframe_required_ ? kMaxWaitForKeyFrameMs : kMaxWaitForFrameMs;
philipela45102f2017-02-22 05:30:39 -0800407 std::unique_ptr<video_coding::FrameObject> frame;
philipel3042c2d2017-08-18 04:55:02 -0700408 // TODO(philipel): Call NextFrame with |keyframe_required| argument when
409 // downstream project has been fixed.
guidouc3372582017-04-04 07:16:21 -0700410 video_coding::FrameBuffer::ReturnReason res =
philipel3042c2d2017-08-18 04:55:02 -0700411 frame_buffer_->NextFrame(wait_ms, &frame);
philipelfd5a20f2016-11-15 00:57:57 -0800412
guidouc3372582017-04-04 07:16:21 -0700413 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) {
414 video_receiver_.DecodingStopped();
philipel2dfea3e2017-02-28 07:19:43 -0800415 return false;
guidouc3372582017-04-04 07:16:21 -0700416 }
philipelfd5a20f2016-11-15 00:57:57 -0800417
philipela45102f2017-02-22 05:30:39 -0800418 if (frame) {
philipel48462b62017-09-26 02:54:58 -0700419 int64_t now_ms = clock_->TimeInMilliseconds();
tommic8ece432017-06-20 02:44:38 -0700420 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kFrameFound);
philipel3042c2d2017-08-18 04:55:02 -0700421 if (video_receiver_.Decode(frame.get()) == VCM_OK) {
422 keyframe_required_ = false;
423 frame_decoded_ = true;
nisseb1f2ff92017-06-09 04:01:55 -0700424 rtp_video_stream_receiver_.FrameDecoded(frame->picture_id);
philipel48462b62017-09-26 02:54:58 -0700425 } else if (!frame_decoded_ || !keyframe_required_ ||
426 (last_keyframe_request_ms_ + kMaxWaitForKeyFrameMs < now_ms)) {
philipel3042c2d2017-08-18 04:55:02 -0700427 keyframe_required_ = true;
428 // TODO(philipel): Remove this keyframe request when downstream project
429 // has been fixed.
430 RequestKeyFrame();
philipel48462b62017-09-26 02:54:58 -0700431 last_keyframe_request_ms_ = now_ms;
philipel3042c2d2017-08-18 04:55:02 -0700432 }
philipelfd5a20f2016-11-15 00:57:57 -0800433 } else {
tommic8ece432017-06-20 02:44:38 -0700434 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kTimeout);
philipel3184f8e2017-05-18 08:08:53 -0700435 int64_t now_ms = clock_->TimeInMilliseconds();
436 rtc::Optional<int64_t> last_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700437 rtp_video_stream_receiver_.LastReceivedPacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700438 rtc::Optional<int64_t> last_keyframe_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700439 rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700440
441 // To avoid spamming keyframe requests for a stream that is not active we
442 // check if we have received a packet within the last 5 seconds.
443 bool stream_is_active = last_packet_ms && now_ms - *last_packet_ms < 5000;
sprang3e86e7e2017-08-22 09:23:28 -0700444 if (!stream_is_active)
445 stats_proxy_.OnStreamInactive();
philipel3184f8e2017-05-18 08:08:53 -0700446
philipel3042c2d2017-08-18 04:55:02 -0700447 // If we recently have been receiving packets belonging to a keyframe then
448 // we assume a keyframe is currently being received.
philipel3184f8e2017-05-18 08:08:53 -0700449 bool receiving_keyframe =
450 last_keyframe_packet_ms &&
philipel3042c2d2017-08-18 04:55:02 -0700451 now_ms - *last_keyframe_packet_ms < kMaxWaitForKeyFrameMs;
philipel3184f8e2017-05-18 08:08:53 -0700452
453 if (stream_is_active && !receiving_keyframe) {
philipel3042c2d2017-08-18 04:55:02 -0700454 LOG(LS_WARNING) << "No decodable frame in " << wait_ms
philipel3184f8e2017-05-18 08:08:53 -0700455 << " ms, requesting keyframe.";
456 RequestKeyFrame();
457 }
philipelfd5a20f2016-11-15 00:57:57 -0800458 }
philipel2dfea3e2017-02-28 07:19:43 -0800459 return true;
Peter Boströmca835252016-02-11 15:59:46 +0100460}
mflodman@webrtc.orgf3973e82013-12-13 09:40:45 +0000461} // namespace internal
462} // namespace webrtc