blob: bca6d94fe684457f37a6b020269bd5ce5a2d0615 [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
Karl Wiberg918f50c2018-07-05 11:40:33 +020019#include "absl/memory/memory.h"
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020020#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "call/rtp_stream_receiver_controller_interface.h"
22#include "call/rtx_receive_stream.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020023#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "common_video/h264/profile_level_id.h"
Patrik Höglundbe214a22018-01-04 12:14:35 +010025#include "common_video/include/incoming_video_stream.h"
Danil Chapovalovb9b146c2018-06-15 12:28:07 +020026#include "common_video/libyuv/include/webrtc_libyuv.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "modules/rtp_rtcp/include/rtp_receiver.h"
28#include "modules/rtp_rtcp/include/rtp_rtcp.h"
29#include "modules/utility/include/process_thread.h"
30#include "modules/video_coding/frame_object.h"
31#include "modules/video_coding/include/video_coding.h"
32#include "modules/video_coding/jitter_estimator.h"
33#include "modules/video_coding/timing.h"
34#include "modules/video_coding/utility/ivf_file_writer.h"
35#include "rtc_base/checks.h"
36#include "rtc_base/location.h"
37#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/trace_event.h"
39#include "system_wrappers/include/clock.h"
40#include "system_wrappers/include/field_trial.h"
41#include "video/call_stats.h"
42#include "video/receive_statistics_proxy.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000043
44namespace webrtc {
mflodmana20de202015-10-18 22:08:19 -070045
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000046namespace {
47VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
48 VideoCodec codec;
49 memset(&codec, 0, sizeof(codec));
50
51 codec.plType = decoder.payload_type;
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;
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080062 } else if (codec.codecType == kVideoCodecMultiplex) {
Emircan Uysaler0a375472017-12-11 12:21:02 +053063 VideoReceiveStream::Decoder associated_decoder = decoder;
64 associated_decoder.payload_name = CodecTypeToPayloadString(kVideoCodecVP9);
65 VideoCodec associated_codec = CreateDecoderVideoCodec(associated_decoder);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080066 associated_codec.codecType = kVideoCodecMultiplex;
Emircan Uysaler0a375472017-12-11 12:21:02 +053067 return associated_codec;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000068 }
69
70 codec.width = 320;
71 codec.height = 180;
stefanb4bc65b2016-11-02 10:10:20 -070072 const int kDefaultStartBitrate = 300;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000073 codec.startBitrate = codec.minBitrate = codec.maxBitrate =
stefanb4bc65b2016-11-02 10:10:20 -070074 kDefaultStartBitrate;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000075
76 return codec;
77}
78} // namespace
pbos@webrtc.org29d58392013-05-16 12:08:03 +000079
Peter Boströmca835252016-02-11 15:59:46 +010080namespace internal {
tommi2e82f382016-06-21 00:26:43 -070081
nisse0f15f922017-06-21 01:05:22 -070082VideoReceiveStream::VideoReceiveStream(
83 RtpStreamReceiverControllerInterface* receiver_controller,
84 int num_cpu_cores,
85 PacketRouter* packet_router,
86 VideoReceiveStream::Config config,
87 ProcessThread* process_thread,
88 CallStats* call_stats)
solenberg4fbae2b2015-08-28 04:07:10 -070089 : transport_adapter_(config.rtcp_send_transport),
Tommi733b5472016-06-10 17:58:01 +020090 config_(std::move(config)),
sprang113bdca2016-10-11 03:10:10 -070091 num_cpu_cores_(num_cpu_cores),
Peter Boström1d04ac62016-02-05 11:25:46 +010092 process_thread_(process_thread),
sprang@webrtc.org09315702014-02-07 12:06:29 +000093 clock_(Clock::GetRealTimeClock()),
tommic8ece432017-06-20 02:44:38 -070094 decode_thread_(&DecodeThreadFunction,
95 this,
96 "DecodingThread",
97 rtc::kHighestPriority),
Peter Boström1d04ac62016-02-05 11:25:46 +010098 call_stats_(call_stats),
nisseca5706d2017-09-11 02:32:16 -070099 rtp_receive_statistics_(ReceiveStatistics::Create(clock_)),
philipelfd5a20f2016-11-15 00:57:57 -0800100 timing_(new VCMTiming(clock_)),
philipel721d4022016-12-15 07:10:57 -0800101 video_receiver_(clock_, nullptr, this, timing_.get(), this, this),
102 stats_proxy_(&config_, clock_),
nisseb1f2ff92017-06-09 04:01:55 -0700103 rtp_video_stream_receiver_(&transport_adapter_,
Tommi38c5d932018-03-27 23:11:09 +0200104 call_stats,
nisseb1f2ff92017-06-09 04:01:55 -0700105 packet_router,
106 &config_,
nisseca5706d2017-09-11 02:32:16 -0700107 rtp_receive_statistics_.get(),
nisseb1f2ff92017-06-09 04:01:55 -0700108 &stats_proxy_,
109 process_thread_,
philipel0a9f6de2018-02-28 11:29:47 +0100110 this, // NackSender
111 this, // KeyFrameRequestSender
112 this), // OnCompleteFrameCallback
philipela45102f2017-02-22 05:30:39 -0800113 rtp_stream_sync_(this) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100114 RTC_LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000115
Stefan Holmer58c664c2016-02-08 14:31:30 +0100116 RTC_DCHECK(process_thread_);
Stefan Holmer58c664c2016-02-08 14:31:30 +0100117 RTC_DCHECK(call_stats_);
mflodmancfc8e3b2016-05-03 21:22:04 -0700118
eladalona28122f2017-08-18 04:02:48 -0700119 module_process_sequence_checker_.Detach();
solenberg3ebbcb52017-01-31 03:58:40 -0800120
henrikg91d6ede2015-09-17 00:24:34 -0700121 RTC_DCHECK(!config_.decoders.empty());
Peter Boström521af4e2015-11-27 16:35:04 +0100122 std::set<int> decoder_payload_types;
Peter Boströmb1ae3a42016-02-15 17:52:40 +0100123 for (const Decoder& decoder : config_.decoders) {
Peter Boström795dbe42015-11-27 14:09:07 +0100124 RTC_CHECK(decoder.decoder);
Peter Boström521af4e2015-11-27 16:35:04 +0100125 RTC_CHECK(decoder_payload_types.find(decoder.payload_type) ==
126 decoder_payload_types.end())
127 << "Duplicate payload type (" << decoder.payload_type
128 << ") for different decoders.";
129 decoder_payload_types.insert(decoder.payload_type);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000130 }
131
nisseca5706d2017-09-11 02:32:16 -0700132 video_receiver_.SetRenderDelay(config_.render_delay_ms);
Peter Boström1d04ac62016-02-05 11:25:46 +0100133
philipela45102f2017-02-22 05:30:39 -0800134 jitter_estimator_.reset(new VCMJitterEstimator(clock_));
135 frame_buffer_.reset(new video_coding::FrameBuffer(
136 clock_, jitter_estimator_.get(), timing_.get(), &stats_proxy_));
philipelfd5a20f2016-11-15 00:57:57 -0800137
tommidea489f2017-03-03 03:20:24 -0800138 process_thread_->RegisterModule(&rtp_stream_sync_, RTC_FROM_HERE);
nisse0f15f922017-06-21 01:05:22 -0700139
140 // Register with RtpStreamReceiverController.
141 media_receiver_ = receiver_controller->CreateReceiver(
142 config_.rtp.remote_ssrc, &rtp_video_stream_receiver_);
nisseca5706d2017-09-11 02:32:16 -0700143 if (config_.rtp.rtx_ssrc) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200144 rtx_receive_stream_ = absl::make_unique<RtxReceiveStream>(
nisseca5706d2017-09-11 02:32:16 -0700145 &rtp_video_stream_receiver_, config.rtp.rtx_associated_payload_types,
146 config_.rtp.remote_ssrc, rtp_receive_statistics_.get());
nisse0f15f922017-06-21 01:05:22 -0700147 rtx_receiver_ = receiver_controller->CreateReceiver(
nisseca5706d2017-09-11 02:32:16 -0700148 config_.rtp.rtx_ssrc, rtx_receive_stream_.get());
nisse0f15f922017-06-21 01:05:22 -0700149 }
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000150}
151
152VideoReceiveStream::~VideoReceiveStream() {
eladalona28122f2017-08-18 04:02:48 -0700153 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100154 RTC_LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString();
Peter Boströmca835252016-02-11 15:59:46 +0100155 Stop();
156
mflodman4cd27902016-08-05 06:28:45 -0700157 process_thread_->DeRegisterModule(&rtp_stream_sync_);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000158}
159
pbos1ba8d392016-05-01 20:18:34 -0700160void VideoReceiveStream::SignalNetworkState(NetworkState state) {
eladalona28122f2017-08-18 04:02:48 -0700161 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700162 rtp_video_stream_receiver_.SignalNetworkState(state);
pbos1ba8d392016-05-01 20:18:34 -0700163}
164
pbos1ba8d392016-05-01 20:18:34 -0700165bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
nisseb1f2ff92017-06-09 04:01:55 -0700166 return rtp_video_stream_receiver_.DeliverRtcp(packet, length);
pbos1ba8d392016-05-01 20:18:34 -0700167}
168
solenberg3ebbcb52017-01-31 03:58:40 -0800169void VideoReceiveStream::SetSync(Syncable* audio_syncable) {
eladalona28122f2017-08-18 04:02:48 -0700170 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800171 rtp_stream_sync_.ConfigureSync(audio_syncable);
brandtr090c9402017-01-25 08:28:02 -0800172}
173
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000174void VideoReceiveStream::Start() {
eladalona28122f2017-08-18 04:02:48 -0700175 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
Peter Boströmca835252016-02-11 15:59:46 +0100176 if (decode_thread_.IsRunning())
177 return;
brandtrfb45c6c2017-01-27 06:47:55 -0800178
nissec69385d2017-03-09 06:13:20 -0800179 bool protected_by_fec = config_.rtp.protected_by_flexfec ||
nisseb1f2ff92017-06-09 04:01:55 -0700180 rtp_video_stream_receiver_.IsUlpfecEnabled();
brandtrfb45c6c2017-01-27 06:47:55 -0800181
philipela45102f2017-02-22 05:30:39 -0800182 frame_buffer_->Start();
philipelfd5a20f2016-11-15 00:57:57 -0800183
nisseb1f2ff92017-06-09 04:01:55 -0700184 if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
185 protected_by_fec) {
philipela45102f2017-02-22 05:30:39 -0800186 frame_buffer_->SetProtectionMode(kProtectionNackFEC);
philipelfd5a20f2016-11-15 00:57:57 -0800187 }
philipela45102f2017-02-22 05:30:39 -0800188
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000189 transport_adapter_.Enable();
tommi2e82f382016-06-21 00:26:43 -0700190 rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
191 if (config_.renderer) {
192 if (config_.disable_prerenderer_smoothing) {
193 renderer = this;
194 } else {
195 incoming_video_stream_.reset(
196 new IncomingVideoStream(config_.render_delay_ms, this));
197 renderer = incoming_video_stream_.get();
198 }
199 }
sakal55d932b2016-09-30 06:19:08 -0700200 RTC_DCHECK(renderer != nullptr);
tommi2e82f382016-06-21 00:26:43 -0700201
sprang113bdca2016-10-11 03:10:10 -0700202 for (const Decoder& decoder : config_.decoders) {
203 video_receiver_.RegisterExternalDecoder(decoder.decoder,
204 decoder.payload_type);
sprang113bdca2016-10-11 03:10:10 -0700205 VideoCodec codec = CreateDecoderVideoCodec(decoder);
nisseb1f2ff92017-06-09 04:01:55 -0700206 RTC_CHECK(rtp_video_stream_receiver_.AddReceiveCodec(codec,
207 decoder.codec_params));
sprang113bdca2016-10-11 03:10:10 -0700208 RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
209 &codec, num_cpu_cores_, false));
210 }
211
tommi2e82f382016-06-21 00:26:43 -0700212 video_stream_decoder_.reset(new VideoStreamDecoder(
nisseb1f2ff92017-06-09 04:01:55 -0700213 &video_receiver_, &rtp_video_stream_receiver_,
214 &rtp_video_stream_receiver_,
215 rtp_video_stream_receiver_.IsRetransmissionsEnabled(), protected_by_fec,
nisse76bc8e82017-02-07 09:37:41 -0800216 &stats_proxy_, renderer));
tommic8ece432017-06-20 02:44:38 -0700217
Tommief3e28a2018-03-30 08:42:39 +0200218 // Make sure we register as a stats observer *after* we've prepared the
219 // |video_stream_decoder_|.
220 call_stats_->RegisterStatsObserver(this);
221
tommic8ece432017-06-20 02:44:38 -0700222 process_thread_->RegisterModule(&video_receiver_, RTC_FROM_HERE);
223
Peter Boströmca835252016-02-11 15:59:46 +0100224 // Start the decode thread
Tommifbf3bce2018-02-21 15:56:05 +0100225 video_receiver_.DecoderThreadStarting();
Tommi132e28e2018-02-24 17:57:33 +0100226 stats_proxy_.DecoderThreadStarting();
Peter Boströmca835252016-02-11 15:59:46 +0100227 decode_thread_.Start();
nisseb1f2ff92017-06-09 04:01:55 -0700228 rtp_video_stream_receiver_.StartReceive();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000229}
230
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000231void VideoReceiveStream::Stop() {
eladalona28122f2017-08-18 04:02:48 -0700232 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700233 rtp_video_stream_receiver_.StopReceive();
philipelfd5a20f2016-11-15 00:57:57 -0800234
Ilya Nikolaevskiyd397a0d2018-02-21 15:57:09 +0100235 stats_proxy_.OnUniqueFramesCounted(
236 rtp_video_stream_receiver_.GetUniqueFramesSeen());
237
philipela45102f2017-02-22 05:30:39 -0800238 frame_buffer_->Stop();
philipele21be1d2017-09-25 06:37:12 -0700239 call_stats_->DeregisterStatsObserver(this);
tommic8ece432017-06-20 02:44:38 -0700240 process_thread_->DeRegisterModule(&video_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800241
sprang0d348d62016-10-07 08:28:39 -0700242 if (decode_thread_.IsRunning()) {
tommic8ece432017-06-20 02:44:38 -0700243 // TriggerDecoderShutdown will release any waiting decoder thread and make
244 // it stop immediately, instead of waiting for a timeout. Needs to be called
245 // before joining the decoder thread.
246 video_receiver_.TriggerDecoderShutdown();
247
sprang0d348d62016-10-07 08:28:39 -0700248 decode_thread_.Stop();
Tommifbf3bce2018-02-21 15:56:05 +0100249 video_receiver_.DecoderThreadStopped();
Tommi132e28e2018-02-24 17:57:33 +0100250 stats_proxy_.DecoderThreadStopped();
sprang0d348d62016-10-07 08:28:39 -0700251 // Deregister external decoders so they are no longer running during
252 // destruction. This effectively stops the VCM since the decoder thread is
253 // stopped, the VCM is deregistered and no asynchronous decoder threads are
254 // running.
255 for (const Decoder& decoder : config_.decoders)
256 video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
257 }
philipelfd5a20f2016-11-15 00:57:57 -0800258
tommi2e82f382016-06-21 00:26:43 -0700259 video_stream_decoder_.reset();
260 incoming_video_stream_.reset();
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000261 transport_adapter_.Disable();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000262}
263
sprang@webrtc.org9510e532014-02-07 15:32:45 +0000264VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
Peter Boströmf751bf82016-02-05 14:00:53 +0100265 return stats_proxy_.GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000266}
267
brandtr090c9402017-01-25 08:28:02 -0800268void VideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file,
269 size_t byte_limit) {
270 {
271 rtc::CritScope lock(&ivf_writer_lock_);
272 if (file == rtc::kInvalidPlatformFileValue) {
273 ivf_writer_.reset();
274 } else {
275 ivf_writer_ = IvfFileWriter::Wrap(rtc::File(file), byte_limit);
276 }
277 }
278
279 if (file != rtc::kInvalidPlatformFileValue) {
280 // Make a keyframe appear as early as possible in the logs, to give actually
281 // decodable output.
282 RequestKeyFrame();
283 }
284}
285
eladalonc0d481a2017-08-02 07:39:07 -0700286void VideoReceiveStream::AddSecondarySink(RtpPacketSinkInterface* sink) {
287 rtp_video_stream_receiver_.AddSecondarySink(sink);
288}
289
290void VideoReceiveStream::RemoveSecondarySink(
291 const RtpPacketSinkInterface* sink) {
292 rtp_video_stream_receiver_.RemoveSecondarySink(sink);
293}
294
tommi2e82f382016-06-21 00:26:43 -0700295// TODO(tommi): This method grabs a lock 6 times.
Tommibd3380f2016-06-10 17:38:17 +0200296void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
asaperssonf8cdd182016-03-15 01:00:47 -0700297 int64_t sync_offset_ms;
asaperssonde9e5ff2016-11-02 07:14:03 -0700298 double estimated_freq_khz;
tommi2e82f382016-06-21 00:26:43 -0700299 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the
300 // function itself, another in GetChannel() and a third in
301 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function
302 // succeeds most of the time, which leads to grabbing a fourth lock.
Yves Gerey665174f2018-06-19 15:03:05 +0200303 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(
304 video_frame.timestamp(), video_frame.render_time_ms(),
305 &sync_offset_ms, &estimated_freq_khz)) {
tommi2e82f382016-06-21 00:26:43 -0700306 // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
asaperssonde9e5ff2016-11-02 07:14:03 -0700307 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
tommi2e82f382016-06-21 00:26:43 -0700308 }
tommi2e82f382016-06-21 00:26:43 -0700309 // config_.renderer must never be null if we're getting this callback.
310 config_.renderer->OnFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000311
tommi2e82f382016-06-21 00:26:43 -0700312 // TODO(tommi): OnRenderFrame grabs a lock too.
asapersson1490f7a2016-09-23 02:09:46 -0700313 stats_proxy_.OnRenderedFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000314}
pbos@webrtc.org26c0c412014-09-03 16:17:12 +0000315
asapersson86b01602015-10-20 23:55:26 -0700316// TODO(asapersson): Consider moving callback from video_encoder.h or
317// creating a different callback.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700318EncodedImageCallback::Result VideoReceiveStream::OnEncodedImage(
asapersson86b01602015-10-20 23:55:26 -0700319 const EncodedImage& encoded_image,
320 const CodecSpecificInfo* codec_specific_info,
321 const RTPFragmentationHeader* fragmentation) {
Peter Boströmf751bf82016-02-05 14:00:53 +0100322 stats_proxy_.OnPreDecode(encoded_image, codec_specific_info);
ilnikcb8c1462017-03-09 09:23:30 -0800323 size_t simulcast_idx = 0;
324 if (codec_specific_info->codecType == kVideoCodecVP8) {
325 simulcast_idx = codec_specific_info->codecSpecific.VP8.simulcastIdx;
326 }
palmkviste75f2042016-09-28 06:19:48 -0700327 {
328 rtc::CritScope lock(&ivf_writer_lock_);
sprang3911c262016-04-15 01:24:14 -0700329 if (ivf_writer_.get()) {
palmkviste75f2042016-09-28 06:19:48 -0700330 RTC_DCHECK(codec_specific_info);
331 bool ok = ivf_writer_->WriteFrame(encoded_image,
332 codec_specific_info->codecType);
sprang3911c262016-04-15 01:24:14 -0700333 RTC_DCHECK(ok);
334 }
335 }
336
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700337 return Result(Result::OK, encoded_image._timeStamp);
asapersson86b01602015-10-20 23:55:26 -0700338}
339
brandtr090c9402017-01-25 08:28:02 -0800340void VideoReceiveStream::SendNack(
341 const std::vector<uint16_t>& sequence_numbers) {
nisseb1f2ff92017-06-09 04:01:55 -0700342 rtp_video_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
brandtr090c9402017-01-25 08:28:02 -0800343}
344
345void VideoReceiveStream::RequestKeyFrame() {
nisseb1f2ff92017-06-09 04:01:55 -0700346 rtp_video_stream_receiver_.RequestKeyFrame();
brandtr090c9402017-01-25 08:28:02 -0800347}
348
349void VideoReceiveStream::OnCompleteFrame(
philipele7c891f2018-02-22 14:35:06 +0100350 std::unique_ptr<video_coding::EncodedFrame> frame) {
Sergey Silkinacb4cba2018-05-08 17:16:39 +0200351 // TODO(webrtc:9249): Workaround to allow decoding of VP9 SVC stream with
352 // partially enabled inter-layer prediction.
353 frame->id.spatial_layer = 0;
354
philipel1610f942017-12-12 13:58:31 +0100355 int64_t last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
brandtr090c9402017-01-25 08:28:02 -0800356 if (last_continuous_pid != -1)
nisseb1f2ff92017-06-09 04:01:55 -0700357 rtp_video_stream_receiver_.FrameContinuous(last_continuous_pid);
brandtr090c9402017-01-25 08:28:02 -0800358}
359
philipele21be1d2017-09-25 06:37:12 -0700360void VideoReceiveStream::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
Tommi81de14f2018-03-25 22:19:25 +0200361 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
philipele21be1d2017-09-25 06:37:12 -0700362 frame_buffer_->UpdateRtt(max_rtt_ms);
Tommi81de14f2018-03-25 22:19:25 +0200363 rtp_video_stream_receiver_.UpdateRtt(max_rtt_ms);
364 video_stream_decoder_->UpdateRtt(max_rtt_ms);
philipele21be1d2017-09-25 06:37:12 -0700365}
366
solenberg3ebbcb52017-01-31 03:58:40 -0800367int VideoReceiveStream::id() const {
eladalona28122f2017-08-18 04:02:48 -0700368 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800369 return config_.rtp.remote_ssrc;
370}
371
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200372absl::optional<Syncable::Info> VideoReceiveStream::GetInfo() const {
eladalona28122f2017-08-18 04:02:48 -0700373 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800374 Syncable::Info info;
375
nisseb1f2ff92017-06-09 04:01:55 -0700376 RtpReceiver* rtp_receiver = rtp_video_stream_receiver_.GetRtpReceiver();
solenberg3ebbcb52017-01-31 03:58:40 -0800377 RTC_DCHECK(rtp_receiver);
Niels Möllerc3fa8e12017-10-03 15:28:26 +0200378 if (!rtp_receiver->GetLatestTimestamps(
379 &info.latest_received_capture_timestamp,
380 &info.latest_receive_time_ms))
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200381 return absl::nullopt;
solenberg3ebbcb52017-01-31 03:58:40 -0800382
nisseb1f2ff92017-06-09 04:01:55 -0700383 RtpRtcp* rtp_rtcp = rtp_video_stream_receiver_.rtp_rtcp();
solenberg3ebbcb52017-01-31 03:58:40 -0800384 RTC_DCHECK(rtp_rtcp);
385 if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs,
Yves Gerey665174f2018-06-19 15:03:05 +0200386 &info.capture_time_ntp_frac, nullptr, nullptr,
solenberg3ebbcb52017-01-31 03:58:40 -0800387 &info.capture_time_source_clock) != 0) {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200388 return absl::nullopt;
solenberg3ebbcb52017-01-31 03:58:40 -0800389 }
390
391 info.current_delay_ms = video_receiver_.Delay();
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100392 return info;
solenberg3ebbcb52017-01-31 03:58:40 -0800393}
394
395uint32_t VideoReceiveStream::GetPlayoutTimestamp() const {
396 RTC_NOTREACHED();
397 return 0;
398}
399
400void VideoReceiveStream::SetMinimumPlayoutDelay(int delay_ms) {
eladalona28122f2017-08-18 04:02:48 -0700401 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800402 video_receiver_.SetMinimumPlayoutDelay(delay_ms);
403}
404
tommic8ece432017-06-20 02:44:38 -0700405void VideoReceiveStream::DecodeThreadFunction(void* ptr) {
406 while (static_cast<VideoReceiveStream*>(ptr)->Decode()) {
407 }
Peter Boströmca835252016-02-11 15:59:46 +0100408}
409
philipel2dfea3e2017-02-28 07:19:43 -0800410bool VideoReceiveStream::Decode() {
tommidb23ea62017-03-03 07:21:18 -0800411 TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
philipela45102f2017-02-22 05:30:39 -0800412 static const int kMaxWaitForFrameMs = 3000;
philipel3042c2d2017-08-18 04:55:02 -0700413 static const int kMaxWaitForKeyFrameMs = 200;
414
415 int wait_ms = keyframe_required_ ? kMaxWaitForKeyFrameMs : kMaxWaitForFrameMs;
philipele7c891f2018-02-22 14:35:06 +0100416 std::unique_ptr<video_coding::EncodedFrame> frame;
philipel3042c2d2017-08-18 04:55:02 -0700417 // TODO(philipel): Call NextFrame with |keyframe_required| argument when
418 // downstream project has been fixed.
guidouc3372582017-04-04 07:16:21 -0700419 video_coding::FrameBuffer::ReturnReason res =
philipel3042c2d2017-08-18 04:55:02 -0700420 frame_buffer_->NextFrame(wait_ms, &frame);
philipelfd5a20f2016-11-15 00:57:57 -0800421
guidouc3372582017-04-04 07:16:21 -0700422 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) {
philipel2dfea3e2017-02-28 07:19:43 -0800423 return false;
guidouc3372582017-04-04 07:16:21 -0700424 }
philipelfd5a20f2016-11-15 00:57:57 -0800425
philipela45102f2017-02-22 05:30:39 -0800426 if (frame) {
philipel48462b62017-09-26 02:54:58 -0700427 int64_t now_ms = clock_->TimeInMilliseconds();
tommic8ece432017-06-20 02:44:38 -0700428 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kFrameFound);
philipel49b46e02017-12-11 14:52:58 +0100429 int decode_result = video_receiver_.Decode(frame.get());
430 if (decode_result == WEBRTC_VIDEO_CODEC_OK ||
431 decode_result == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME) {
philipel3042c2d2017-08-18 04:55:02 -0700432 keyframe_required_ = false;
433 frame_decoded_ = true;
philipel0fa82a62018-03-19 15:34:53 +0100434 rtp_video_stream_receiver_.FrameDecoded(frame->id.picture_id);
philipel49b46e02017-12-11 14:52:58 +0100435
436 if (decode_result == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME)
437 RequestKeyFrame();
philipel48462b62017-09-26 02:54:58 -0700438 } else if (!frame_decoded_ || !keyframe_required_ ||
439 (last_keyframe_request_ms_ + kMaxWaitForKeyFrameMs < now_ms)) {
philipel3042c2d2017-08-18 04:55:02 -0700440 keyframe_required_ = true;
441 // TODO(philipel): Remove this keyframe request when downstream project
442 // has been fixed.
443 RequestKeyFrame();
philipel48462b62017-09-26 02:54:58 -0700444 last_keyframe_request_ms_ = now_ms;
philipel3042c2d2017-08-18 04:55:02 -0700445 }
philipelfd5a20f2016-11-15 00:57:57 -0800446 } else {
tommic8ece432017-06-20 02:44:38 -0700447 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kTimeout);
philipel3184f8e2017-05-18 08:08:53 -0700448 int64_t now_ms = clock_->TimeInMilliseconds();
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200449 absl::optional<int64_t> last_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700450 rtp_video_stream_receiver_.LastReceivedPacketMs();
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200451 absl::optional<int64_t> last_keyframe_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700452 rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700453
454 // To avoid spamming keyframe requests for a stream that is not active we
455 // check if we have received a packet within the last 5 seconds.
456 bool stream_is_active = last_packet_ms && now_ms - *last_packet_ms < 5000;
sprang3e86e7e2017-08-22 09:23:28 -0700457 if (!stream_is_active)
458 stats_proxy_.OnStreamInactive();
philipel3184f8e2017-05-18 08:08:53 -0700459
philipel3042c2d2017-08-18 04:55:02 -0700460 // If we recently have been receiving packets belonging to a keyframe then
461 // we assume a keyframe is currently being received.
philipel3184f8e2017-05-18 08:08:53 -0700462 bool receiving_keyframe =
463 last_keyframe_packet_ms &&
philipel3042c2d2017-08-18 04:55:02 -0700464 now_ms - *last_keyframe_packet_ms < kMaxWaitForKeyFrameMs;
philipel3184f8e2017-05-18 08:08:53 -0700465
466 if (stream_is_active && !receiving_keyframe) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100467 RTC_LOG(LS_WARNING) << "No decodable frame in " << wait_ms
468 << " ms, requesting keyframe.";
philipel3184f8e2017-05-18 08:08:53 -0700469 RequestKeyFrame();
470 }
philipelfd5a20f2016-11-15 00:57:57 -0800471 }
philipel2dfea3e2017-02-28 07:19:43 -0800472 return true;
Peter Boströmca835252016-02-11 15:59:46 +0100473}
mflodman@webrtc.orgf3973e82013-12-13 09:40:45 +0000474} // namespace internal
475} // namespace webrtc