blob: 74c90134b933d1f217fda6d81fca259c14659e03 [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
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000011#include "webrtc/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
kwiberg84f6a3f2017-09-05 08:43:13 -070019#include "webrtc/api/optional.h"
nisse0f15f922017-06-21 01:05:22 -070020#include "webrtc/call/rtp_stream_receiver_controller_interface.h"
deadbeefc964d0b2017-04-03 10:03:35 -070021#include "webrtc/common_types.h"
magjede69a1a92016-11-25 10:06:31 -080022#include "webrtc/common_video/h264/profile_level_id.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000023#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
solenberg3ebbcb52017-01-31 03:58:40 -080024#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
25#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
Peter Boström1d04ac62016-02-05 11:25:46 +010026#include "webrtc/modules/utility/include/process_thread.h"
philipelfd5a20f2016-11-15 00:57:57 -080027#include "webrtc/modules/video_coding/frame_object.h"
Peter Boströma4c76882016-03-03 16:29:02 +010028#include "webrtc/modules/video_coding/include/video_coding.h"
philipelfd5a20f2016-11-15 00:57:57 -080029#include "webrtc/modules/video_coding/jitter_estimator.h"
30#include "webrtc/modules/video_coding/timing.h"
sprang3911c262016-04-15 01:24:14 -070031#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020032#include "webrtc/rtc_base/checks.h"
33#include "webrtc/rtc_base/location.h"
34#include "webrtc/rtc_base/logging.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020035#include "webrtc/rtc_base/trace_event.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010036#include "webrtc/system_wrappers/include/clock.h"
philipelfd5a20f2016-11-15 00:57:57 -080037#include "webrtc/system_wrappers/include/field_trial.h"
Peter Boström7623ce42015-12-09 12:13:30 +010038#include "webrtc/video/call_stats.h"
sprang@webrtc.org09315702014-02-07 12:06:29 +000039#include "webrtc/video/receive_statistics_proxy.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000040
41namespace webrtc {
mflodmana20de202015-10-18 22:08:19 -070042
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000043namespace {
44VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
45 VideoCodec codec;
46 memset(&codec, 0, sizeof(codec));
47
48 codec.plType = decoder.payload_type;
mflodmand1590b22015-12-09 07:07:59 -080049 strncpy(codec.plName, decoder.payload_name.c_str(), sizeof(codec.plName));
kthelgason1cdddc92017-08-24 03:52:48 -070050 codec.codecType = PayloadStringToCodecType(decoder.payload_name);
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000051
52 if (codec.codecType == kVideoCodecVP8) {
hta257dc392016-10-25 09:05:06 -070053 *(codec.VP8()) = VideoEncoder::GetDefaultVp8Settings();
ivica05cfcd32015-09-07 06:04:16 -070054 } else if (codec.codecType == kVideoCodecVP9) {
hta257dc392016-10-25 09:05:06 -070055 *(codec.VP9()) = VideoEncoder::GetDefaultVp9Settings();
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000056 } else if (codec.codecType == kVideoCodecH264) {
hta257dc392016-10-25 09:05:06 -070057 *(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
magjede69a1a92016-11-25 10:06:31 -080058 codec.H264()->profile =
59 H264::ParseSdpProfileLevelId(decoder.codec_params)->profile;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000060 }
61
62 codec.width = 320;
63 codec.height = 180;
stefanb4bc65b2016-11-02 10:10:20 -070064 const int kDefaultStartBitrate = 300;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000065 codec.startBitrate = codec.minBitrate = codec.maxBitrate =
stefanb4bc65b2016-11-02 10:10:20 -070066 kDefaultStartBitrate;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000067
68 return codec;
69}
70} // namespace
pbos@webrtc.org29d58392013-05-16 12:08:03 +000071
Peter Boströmca835252016-02-11 15:59:46 +010072namespace internal {
tommi2e82f382016-06-21 00:26:43 -070073
nisse0f15f922017-06-21 01:05:22 -070074VideoReceiveStream::VideoReceiveStream(
75 RtpStreamReceiverControllerInterface* receiver_controller,
76 int num_cpu_cores,
77 PacketRouter* packet_router,
78 VideoReceiveStream::Config config,
79 ProcessThread* process_thread,
80 CallStats* call_stats)
solenberg4fbae2b2015-08-28 04:07:10 -070081 : transport_adapter_(config.rtcp_send_transport),
Tommi733b5472016-06-10 17:58:01 +020082 config_(std::move(config)),
sprang113bdca2016-10-11 03:10:10 -070083 num_cpu_cores_(num_cpu_cores),
Peter Boström1d04ac62016-02-05 11:25:46 +010084 process_thread_(process_thread),
sprang@webrtc.org09315702014-02-07 12:06:29 +000085 clock_(Clock::GetRealTimeClock()),
tommic8ece432017-06-20 02:44:38 -070086 decode_thread_(&DecodeThreadFunction,
87 this,
88 "DecodingThread",
89 rtc::kHighestPriority),
Peter Boström1d04ac62016-02-05 11:25:46 +010090 call_stats_(call_stats),
philipelfd5a20f2016-11-15 00:57:57 -080091 timing_(new VCMTiming(clock_)),
philipel721d4022016-12-15 07:10:57 -080092 video_receiver_(clock_, nullptr, this, timing_.get(), this, this),
93 stats_proxy_(&config_, clock_),
nisseb1f2ff92017-06-09 04:01:55 -070094 rtp_video_stream_receiver_(&transport_adapter_,
95 call_stats_->rtcp_rtt_stats(),
96 packet_router,
97 &config_,
98 &stats_proxy_,
99 process_thread_,
100 this, // NackSender
101 this, // KeyFrameRequestSender
102 this, // OnCompleteFrameCallback
103 timing_.get()),
philipela45102f2017-02-22 05:30:39 -0800104 rtp_stream_sync_(this) {
pbosa2f30de2015-10-15 05:22:13 -0700105 LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000106
Stefan Holmer58c664c2016-02-08 14:31:30 +0100107 RTC_DCHECK(process_thread_);
Stefan Holmer58c664c2016-02-08 14:31:30 +0100108 RTC_DCHECK(call_stats_);
mflodmancfc8e3b2016-05-03 21:22:04 -0700109
eladalona28122f2017-08-18 04:02:48 -0700110 module_process_sequence_checker_.Detach();
solenberg3ebbcb52017-01-31 03:58:40 -0800111
henrikg91d6ede2015-09-17 00:24:34 -0700112 RTC_DCHECK(!config_.decoders.empty());
Peter Boström521af4e2015-11-27 16:35:04 +0100113 std::set<int> decoder_payload_types;
Peter Boströmb1ae3a42016-02-15 17:52:40 +0100114 for (const Decoder& decoder : config_.decoders) {
Peter Boström795dbe42015-11-27 14:09:07 +0100115 RTC_CHECK(decoder.decoder);
Peter Boström521af4e2015-11-27 16:35:04 +0100116 RTC_CHECK(decoder_payload_types.find(decoder.payload_type) ==
117 decoder_payload_types.end())
118 << "Duplicate payload type (" << decoder.payload_type
119 << ") for different decoders.";
120 decoder_payload_types.insert(decoder.payload_type);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000121 }
122
nisse3c39c012017-09-04 04:22:15 -0700123 video_receiver_.SetRenderDelay(config.render_delay_ms);
Peter Boström1d04ac62016-02-05 11:25:46 +0100124
philipela45102f2017-02-22 05:30:39 -0800125 jitter_estimator_.reset(new VCMJitterEstimator(clock_));
126 frame_buffer_.reset(new video_coding::FrameBuffer(
127 clock_, jitter_estimator_.get(), timing_.get(), &stats_proxy_));
philipelfd5a20f2016-11-15 00:57:57 -0800128
tommidea489f2017-03-03 03:20:24 -0800129 process_thread_->RegisterModule(&rtp_stream_sync_, RTC_FROM_HERE);
nisse0f15f922017-06-21 01:05:22 -0700130
131 // Register with RtpStreamReceiverController.
132 media_receiver_ = receiver_controller->CreateReceiver(
133 config_.rtp.remote_ssrc, &rtp_video_stream_receiver_);
nisse3c39c012017-09-04 04:22:15 -0700134 if (config.rtp.rtx_ssrc) {
nisse0f15f922017-06-21 01:05:22 -0700135 rtx_receiver_ = receiver_controller->CreateReceiver(
nisse3c39c012017-09-04 04:22:15 -0700136 config_.rtp.rtx_ssrc, &rtp_video_stream_receiver_);
nisse0f15f922017-06-21 01:05:22 -0700137 }
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000138}
139
140VideoReceiveStream::~VideoReceiveStream() {
eladalona28122f2017-08-18 04:02:48 -0700141 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
pbosa2f30de2015-10-15 05:22:13 -0700142 LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString();
Peter Boströmca835252016-02-11 15:59:46 +0100143 Stop();
144
mflodman4cd27902016-08-05 06:28:45 -0700145 process_thread_->DeRegisterModule(&rtp_stream_sync_);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000146}
147
pbos1ba8d392016-05-01 20:18:34 -0700148void VideoReceiveStream::SignalNetworkState(NetworkState state) {
eladalona28122f2017-08-18 04:02:48 -0700149 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700150 rtp_video_stream_receiver_.SignalNetworkState(state);
pbos1ba8d392016-05-01 20:18:34 -0700151}
152
pbos1ba8d392016-05-01 20:18:34 -0700153bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
nisseb1f2ff92017-06-09 04:01:55 -0700154 return rtp_video_stream_receiver_.DeliverRtcp(packet, length);
pbos1ba8d392016-05-01 20:18:34 -0700155}
156
solenberg3ebbcb52017-01-31 03:58:40 -0800157void VideoReceiveStream::SetSync(Syncable* audio_syncable) {
eladalona28122f2017-08-18 04:02:48 -0700158 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800159 rtp_stream_sync_.ConfigureSync(audio_syncable);
brandtr090c9402017-01-25 08:28:02 -0800160}
161
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000162void VideoReceiveStream::Start() {
eladalona28122f2017-08-18 04:02:48 -0700163 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
Peter Boströmca835252016-02-11 15:59:46 +0100164 if (decode_thread_.IsRunning())
165 return;
brandtrfb45c6c2017-01-27 06:47:55 -0800166
nissec69385d2017-03-09 06:13:20 -0800167 bool protected_by_fec = config_.rtp.protected_by_flexfec ||
nisseb1f2ff92017-06-09 04:01:55 -0700168 rtp_video_stream_receiver_.IsUlpfecEnabled();
brandtrfb45c6c2017-01-27 06:47:55 -0800169
philipela45102f2017-02-22 05:30:39 -0800170 frame_buffer_->Start();
nisseb1f2ff92017-06-09 04:01:55 -0700171 call_stats_->RegisterStatsObserver(&rtp_video_stream_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800172
nisseb1f2ff92017-06-09 04:01:55 -0700173 if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
174 protected_by_fec) {
philipela45102f2017-02-22 05:30:39 -0800175 frame_buffer_->SetProtectionMode(kProtectionNackFEC);
philipelfd5a20f2016-11-15 00:57:57 -0800176 }
philipela45102f2017-02-22 05:30:39 -0800177
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000178 transport_adapter_.Enable();
tommi2e82f382016-06-21 00:26:43 -0700179 rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
180 if (config_.renderer) {
181 if (config_.disable_prerenderer_smoothing) {
182 renderer = this;
183 } else {
184 incoming_video_stream_.reset(
185 new IncomingVideoStream(config_.render_delay_ms, this));
186 renderer = incoming_video_stream_.get();
187 }
188 }
sakal55d932b2016-09-30 06:19:08 -0700189 RTC_DCHECK(renderer != nullptr);
tommi2e82f382016-06-21 00:26:43 -0700190
sprang113bdca2016-10-11 03:10:10 -0700191 for (const Decoder& decoder : config_.decoders) {
192 video_receiver_.RegisterExternalDecoder(decoder.decoder,
193 decoder.payload_type);
sprang113bdca2016-10-11 03:10:10 -0700194 VideoCodec codec = CreateDecoderVideoCodec(decoder);
nisseb1f2ff92017-06-09 04:01:55 -0700195 RTC_CHECK(rtp_video_stream_receiver_.AddReceiveCodec(codec,
196 decoder.codec_params));
sprang113bdca2016-10-11 03:10:10 -0700197 RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
198 &codec, num_cpu_cores_, false));
199 }
200
tommi2e82f382016-06-21 00:26:43 -0700201 video_stream_decoder_.reset(new VideoStreamDecoder(
nisseb1f2ff92017-06-09 04:01:55 -0700202 &video_receiver_, &rtp_video_stream_receiver_,
203 &rtp_video_stream_receiver_,
204 rtp_video_stream_receiver_.IsRetransmissionsEnabled(), protected_by_fec,
nisse76bc8e82017-02-07 09:37:41 -0800205 &stats_proxy_, renderer));
tommi2e82f382016-06-21 00:26:43 -0700206 // Register the channel to receive stats updates.
207 call_stats_->RegisterStatsObserver(video_stream_decoder_.get());
tommic8ece432017-06-20 02:44:38 -0700208
209 process_thread_->RegisterModule(&video_receiver_, RTC_FROM_HERE);
210
Peter Boströmca835252016-02-11 15:59:46 +0100211 // Start the decode thread
212 decode_thread_.Start();
nisseb1f2ff92017-06-09 04:01:55 -0700213 rtp_video_stream_receiver_.StartReceive();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000214}
215
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000216void VideoReceiveStream::Stop() {
eladalona28122f2017-08-18 04:02:48 -0700217 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700218 rtp_video_stream_receiver_.StopReceive();
philipelfd5a20f2016-11-15 00:57:57 -0800219
philipela45102f2017-02-22 05:30:39 -0800220 frame_buffer_->Stop();
nisseb1f2ff92017-06-09 04:01:55 -0700221 call_stats_->DeregisterStatsObserver(&rtp_video_stream_receiver_);
tommic8ece432017-06-20 02:44:38 -0700222 process_thread_->DeRegisterModule(&video_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800223
sprang0d348d62016-10-07 08:28:39 -0700224 if (decode_thread_.IsRunning()) {
tommic8ece432017-06-20 02:44:38 -0700225 // TriggerDecoderShutdown will release any waiting decoder thread and make
226 // it stop immediately, instead of waiting for a timeout. Needs to be called
227 // before joining the decoder thread.
228 video_receiver_.TriggerDecoderShutdown();
229
sprang0d348d62016-10-07 08:28:39 -0700230 decode_thread_.Stop();
231 // Deregister external decoders so they are no longer running during
232 // destruction. This effectively stops the VCM since the decoder thread is
233 // stopped, the VCM is deregistered and no asynchronous decoder threads are
234 // running.
235 for (const Decoder& decoder : config_.decoders)
236 video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
237 }
philipelfd5a20f2016-11-15 00:57:57 -0800238
tommi2e82f382016-06-21 00:26:43 -0700239 call_stats_->DeregisterStatsObserver(video_stream_decoder_.get());
240 video_stream_decoder_.reset();
241 incoming_video_stream_.reset();
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000242 transport_adapter_.Disable();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000243}
244
sprang@webrtc.org9510e532014-02-07 15:32:45 +0000245VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
Peter Boströmf751bf82016-02-05 14:00:53 +0100246 return stats_proxy_.GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000247}
248
brandtr090c9402017-01-25 08:28:02 -0800249void VideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file,
250 size_t byte_limit) {
251 {
252 rtc::CritScope lock(&ivf_writer_lock_);
253 if (file == rtc::kInvalidPlatformFileValue) {
254 ivf_writer_.reset();
255 } else {
256 ivf_writer_ = IvfFileWriter::Wrap(rtc::File(file), byte_limit);
257 }
258 }
259
260 if (file != rtc::kInvalidPlatformFileValue) {
261 // Make a keyframe appear as early as possible in the logs, to give actually
262 // decodable output.
263 RequestKeyFrame();
264 }
265}
266
eladalonc0d481a2017-08-02 07:39:07 -0700267void VideoReceiveStream::AddSecondarySink(RtpPacketSinkInterface* sink) {
268 rtp_video_stream_receiver_.AddSecondarySink(sink);
269}
270
271void VideoReceiveStream::RemoveSecondarySink(
272 const RtpPacketSinkInterface* sink) {
273 rtp_video_stream_receiver_.RemoveSecondarySink(sink);
274}
275
tommi2e82f382016-06-21 00:26:43 -0700276// TODO(tommi): This method grabs a lock 6 times.
Tommibd3380f2016-06-10 17:38:17 +0200277void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
asaperssonf8cdd182016-03-15 01:00:47 -0700278 int64_t sync_offset_ms;
asaperssonde9e5ff2016-11-02 07:14:03 -0700279 double estimated_freq_khz;
tommi2e82f382016-06-21 00:26:43 -0700280 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the
281 // function itself, another in GetChannel() and a third in
282 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function
283 // succeeds most of the time, which leads to grabbing a fourth lock.
solenberg3ebbcb52017-01-31 03:58:40 -0800284 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame.timestamp(),
285 video_frame.render_time_ms(),
286 &sync_offset_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700287 &estimated_freq_khz)) {
tommi2e82f382016-06-21 00:26:43 -0700288 // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
asaperssonde9e5ff2016-11-02 07:14:03 -0700289 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
tommi2e82f382016-06-21 00:26:43 -0700290 }
tommi2e82f382016-06-21 00:26:43 -0700291 // config_.renderer must never be null if we're getting this callback.
292 config_.renderer->OnFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000293
tommi2e82f382016-06-21 00:26:43 -0700294 // TODO(tommi): OnRenderFrame grabs a lock too.
asapersson1490f7a2016-09-23 02:09:46 -0700295 stats_proxy_.OnRenderedFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000296}
pbos@webrtc.org26c0c412014-09-03 16:17:12 +0000297
asapersson86b01602015-10-20 23:55:26 -0700298// TODO(asapersson): Consider moving callback from video_encoder.h or
299// creating a different callback.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700300EncodedImageCallback::Result VideoReceiveStream::OnEncodedImage(
asapersson86b01602015-10-20 23:55:26 -0700301 const EncodedImage& encoded_image,
302 const CodecSpecificInfo* codec_specific_info,
303 const RTPFragmentationHeader* fragmentation) {
Peter Boströmf751bf82016-02-05 14:00:53 +0100304 stats_proxy_.OnPreDecode(encoded_image, codec_specific_info);
ilnikcb8c1462017-03-09 09:23:30 -0800305 size_t simulcast_idx = 0;
306 if (codec_specific_info->codecType == kVideoCodecVP8) {
307 simulcast_idx = codec_specific_info->codecSpecific.VP8.simulcastIdx;
308 }
asapersson86b01602015-10-20 23:55:26 -0700309 if (config_.pre_decode_callback) {
ilnikcb8c1462017-03-09 09:23:30 -0800310 config_.pre_decode_callback->EncodedFrameCallback(EncodedFrame(
311 encoded_image._buffer, encoded_image._length, encoded_image._frameType,
312 simulcast_idx, encoded_image._timeStamp));
asapersson86b01602015-10-20 23:55:26 -0700313 }
palmkviste75f2042016-09-28 06:19:48 -0700314 {
315 rtc::CritScope lock(&ivf_writer_lock_);
sprang3911c262016-04-15 01:24:14 -0700316 if (ivf_writer_.get()) {
palmkviste75f2042016-09-28 06:19:48 -0700317 RTC_DCHECK(codec_specific_info);
318 bool ok = ivf_writer_->WriteFrame(encoded_image,
319 codec_specific_info->codecType);
sprang3911c262016-04-15 01:24:14 -0700320 RTC_DCHECK(ok);
321 }
322 }
323
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700324 return Result(Result::OK, encoded_image._timeStamp);
asapersson86b01602015-10-20 23:55:26 -0700325}
326
brandtr090c9402017-01-25 08:28:02 -0800327void VideoReceiveStream::SendNack(
328 const std::vector<uint16_t>& sequence_numbers) {
nisseb1f2ff92017-06-09 04:01:55 -0700329 rtp_video_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
brandtr090c9402017-01-25 08:28:02 -0800330}
331
332void VideoReceiveStream::RequestKeyFrame() {
nisseb1f2ff92017-06-09 04:01:55 -0700333 rtp_video_stream_receiver_.RequestKeyFrame();
brandtr090c9402017-01-25 08:28:02 -0800334}
335
336void VideoReceiveStream::OnCompleteFrame(
337 std::unique_ptr<video_coding::FrameObject> frame) {
338 int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
339 if (last_continuous_pid != -1)
nisseb1f2ff92017-06-09 04:01:55 -0700340 rtp_video_stream_receiver_.FrameContinuous(last_continuous_pid);
brandtr090c9402017-01-25 08:28:02 -0800341}
342
solenberg3ebbcb52017-01-31 03:58:40 -0800343int VideoReceiveStream::id() const {
eladalona28122f2017-08-18 04:02:48 -0700344 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800345 return config_.rtp.remote_ssrc;
346}
347
348rtc::Optional<Syncable::Info> VideoReceiveStream::GetInfo() const {
eladalona28122f2017-08-18 04:02:48 -0700349 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800350 Syncable::Info info;
351
nisseb1f2ff92017-06-09 04:01:55 -0700352 RtpReceiver* rtp_receiver = rtp_video_stream_receiver_.GetRtpReceiver();
solenberg3ebbcb52017-01-31 03:58:40 -0800353 RTC_DCHECK(rtp_receiver);
354 if (!rtp_receiver->Timestamp(&info.latest_received_capture_timestamp))
355 return rtc::Optional<Syncable::Info>();
356 if (!rtp_receiver->LastReceivedTimeMs(&info.latest_receive_time_ms))
357 return rtc::Optional<Syncable::Info>();
358
nisseb1f2ff92017-06-09 04:01:55 -0700359 RtpRtcp* rtp_rtcp = rtp_video_stream_receiver_.rtp_rtcp();
solenberg3ebbcb52017-01-31 03:58:40 -0800360 RTC_DCHECK(rtp_rtcp);
361 if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs,
362 &info.capture_time_ntp_frac,
363 nullptr,
364 nullptr,
365 &info.capture_time_source_clock) != 0) {
366 return rtc::Optional<Syncable::Info>();
367 }
368
369 info.current_delay_ms = video_receiver_.Delay();
370 return rtc::Optional<Syncable::Info>(info);
371}
372
373uint32_t VideoReceiveStream::GetPlayoutTimestamp() const {
374 RTC_NOTREACHED();
375 return 0;
376}
377
378void VideoReceiveStream::SetMinimumPlayoutDelay(int delay_ms) {
eladalona28122f2017-08-18 04:02:48 -0700379 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800380 video_receiver_.SetMinimumPlayoutDelay(delay_ms);
381}
382
tommic8ece432017-06-20 02:44:38 -0700383void VideoReceiveStream::DecodeThreadFunction(void* ptr) {
384 while (static_cast<VideoReceiveStream*>(ptr)->Decode()) {
385 }
Peter Boströmca835252016-02-11 15:59:46 +0100386}
387
philipel2dfea3e2017-02-28 07:19:43 -0800388bool VideoReceiveStream::Decode() {
tommidb23ea62017-03-03 07:21:18 -0800389 TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
philipela45102f2017-02-22 05:30:39 -0800390 static const int kMaxWaitForFrameMs = 3000;
philipel3042c2d2017-08-18 04:55:02 -0700391 static const int kMaxWaitForKeyFrameMs = 200;
392
393 int wait_ms = keyframe_required_ ? kMaxWaitForKeyFrameMs : kMaxWaitForFrameMs;
philipela45102f2017-02-22 05:30:39 -0800394 std::unique_ptr<video_coding::FrameObject> frame;
philipel3042c2d2017-08-18 04:55:02 -0700395 // TODO(philipel): Call NextFrame with |keyframe_required| argument when
396 // downstream project has been fixed.
guidouc3372582017-04-04 07:16:21 -0700397 video_coding::FrameBuffer::ReturnReason res =
philipel3042c2d2017-08-18 04:55:02 -0700398 frame_buffer_->NextFrame(wait_ms, &frame);
philipelfd5a20f2016-11-15 00:57:57 -0800399
guidouc3372582017-04-04 07:16:21 -0700400 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) {
401 video_receiver_.DecodingStopped();
philipel2dfea3e2017-02-28 07:19:43 -0800402 return false;
guidouc3372582017-04-04 07:16:21 -0700403 }
philipelfd5a20f2016-11-15 00:57:57 -0800404
philipela45102f2017-02-22 05:30:39 -0800405 if (frame) {
tommic8ece432017-06-20 02:44:38 -0700406 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kFrameFound);
philipel3042c2d2017-08-18 04:55:02 -0700407 if (video_receiver_.Decode(frame.get()) == VCM_OK) {
408 keyframe_required_ = false;
409 frame_decoded_ = true;
nisseb1f2ff92017-06-09 04:01:55 -0700410 rtp_video_stream_receiver_.FrameDecoded(frame->picture_id);
philipel3042c2d2017-08-18 04:55:02 -0700411 } else if (!keyframe_required_ || !frame_decoded_) {
412 keyframe_required_ = true;
413 // TODO(philipel): Remove this keyframe request when downstream project
414 // has been fixed.
415 RequestKeyFrame();
416 }
philipelfd5a20f2016-11-15 00:57:57 -0800417 } else {
tommic8ece432017-06-20 02:44:38 -0700418 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kTimeout);
philipel3184f8e2017-05-18 08:08:53 -0700419 int64_t now_ms = clock_->TimeInMilliseconds();
420 rtc::Optional<int64_t> last_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700421 rtp_video_stream_receiver_.LastReceivedPacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700422 rtc::Optional<int64_t> last_keyframe_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700423 rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700424
425 // To avoid spamming keyframe requests for a stream that is not active we
426 // check if we have received a packet within the last 5 seconds.
427 bool stream_is_active = last_packet_ms && now_ms - *last_packet_ms < 5000;
sprang3e86e7e2017-08-22 09:23:28 -0700428 if (!stream_is_active)
429 stats_proxy_.OnStreamInactive();
philipel3184f8e2017-05-18 08:08:53 -0700430
philipel3042c2d2017-08-18 04:55:02 -0700431 // If we recently have been receiving packets belonging to a keyframe then
432 // we assume a keyframe is currently being received.
philipel3184f8e2017-05-18 08:08:53 -0700433 bool receiving_keyframe =
434 last_keyframe_packet_ms &&
philipel3042c2d2017-08-18 04:55:02 -0700435 now_ms - *last_keyframe_packet_ms < kMaxWaitForKeyFrameMs;
philipel3184f8e2017-05-18 08:08:53 -0700436
437 if (stream_is_active && !receiving_keyframe) {
philipel3042c2d2017-08-18 04:55:02 -0700438 LOG(LS_WARNING) << "No decodable frame in " << wait_ms
philipel3184f8e2017-05-18 08:08:53 -0700439 << " ms, requesting keyframe.";
440 RequestKeyFrame();
441 }
philipelfd5a20f2016-11-15 00:57:57 -0800442 }
philipel2dfea3e2017-02-28 07:19:43 -0800443 return true;
Peter Boströmca835252016-02-11 15:59:46 +0100444}
mflodman@webrtc.orgf3973e82013-12-13 09:40:45 +0000445} // namespace internal
446} // namespace webrtc