blob: a89e3ce36649d5421dde69b41bcaf6e589cd80cb [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"
nisseca5706d2017-09-11 02:32:16 -070021#include "webrtc/call/rtx_receive_stream.h"
deadbeefc964d0b2017-04-03 10:03:35 -070022#include "webrtc/common_types.h"
magjede69a1a92016-11-25 10:06:31 -080023#include "webrtc/common_video/h264/profile_level_id.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000024#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
solenberg3ebbcb52017-01-31 03:58:40 -080025#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
26#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
Peter Boström1d04ac62016-02-05 11:25:46 +010027#include "webrtc/modules/utility/include/process_thread.h"
philipelfd5a20f2016-11-15 00:57:57 -080028#include "webrtc/modules/video_coding/frame_object.h"
Peter Boströma4c76882016-03-03 16:29:02 +010029#include "webrtc/modules/video_coding/include/video_coding.h"
philipelfd5a20f2016-11-15 00:57:57 -080030#include "webrtc/modules/video_coding/jitter_estimator.h"
31#include "webrtc/modules/video_coding/timing.h"
sprang3911c262016-04-15 01:24:14 -070032#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020033#include "webrtc/rtc_base/checks.h"
34#include "webrtc/rtc_base/location.h"
35#include "webrtc/rtc_base/logging.h"
nisseca5706d2017-09-11 02:32:16 -070036#include "webrtc/rtc_base/ptr_util.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020037#include "webrtc/rtc_base/trace_event.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010038#include "webrtc/system_wrappers/include/clock.h"
philipelfd5a20f2016-11-15 00:57:57 -080039#include "webrtc/system_wrappers/include/field_trial.h"
Peter Boström7623ce42015-12-09 12:13:30 +010040#include "webrtc/video/call_stats.h"
sprang@webrtc.org09315702014-02-07 12:06:29 +000041#include "webrtc/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_);
philipelfd5a20f2016-11-15 00:57:57 -0800179
nisseb1f2ff92017-06-09 04:01:55 -0700180 if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
181 protected_by_fec) {
philipela45102f2017-02-22 05:30:39 -0800182 frame_buffer_->SetProtectionMode(kProtectionNackFEC);
philipelfd5a20f2016-11-15 00:57:57 -0800183 }
philipela45102f2017-02-22 05:30:39 -0800184
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000185 transport_adapter_.Enable();
tommi2e82f382016-06-21 00:26:43 -0700186 rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
187 if (config_.renderer) {
188 if (config_.disable_prerenderer_smoothing) {
189 renderer = this;
190 } else {
191 incoming_video_stream_.reset(
192 new IncomingVideoStream(config_.render_delay_ms, this));
193 renderer = incoming_video_stream_.get();
194 }
195 }
sakal55d932b2016-09-30 06:19:08 -0700196 RTC_DCHECK(renderer != nullptr);
tommi2e82f382016-06-21 00:26:43 -0700197
sprang113bdca2016-10-11 03:10:10 -0700198 for (const Decoder& decoder : config_.decoders) {
199 video_receiver_.RegisterExternalDecoder(decoder.decoder,
200 decoder.payload_type);
sprang113bdca2016-10-11 03:10:10 -0700201 VideoCodec codec = CreateDecoderVideoCodec(decoder);
nisseb1f2ff92017-06-09 04:01:55 -0700202 RTC_CHECK(rtp_video_stream_receiver_.AddReceiveCodec(codec,
203 decoder.codec_params));
sprang113bdca2016-10-11 03:10:10 -0700204 RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
205 &codec, num_cpu_cores_, false));
206 }
207
tommi2e82f382016-06-21 00:26:43 -0700208 video_stream_decoder_.reset(new VideoStreamDecoder(
nisseb1f2ff92017-06-09 04:01:55 -0700209 &video_receiver_, &rtp_video_stream_receiver_,
210 &rtp_video_stream_receiver_,
211 rtp_video_stream_receiver_.IsRetransmissionsEnabled(), protected_by_fec,
nisse76bc8e82017-02-07 09:37:41 -0800212 &stats_proxy_, renderer));
tommi2e82f382016-06-21 00:26:43 -0700213 // Register the channel to receive stats updates.
214 call_stats_->RegisterStatsObserver(video_stream_decoder_.get());
tommic8ece432017-06-20 02:44:38 -0700215
216 process_thread_->RegisterModule(&video_receiver_, RTC_FROM_HERE);
217
Peter Boströmca835252016-02-11 15:59:46 +0100218 // Start the decode thread
219 decode_thread_.Start();
nisseb1f2ff92017-06-09 04:01:55 -0700220 rtp_video_stream_receiver_.StartReceive();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000221}
222
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000223void VideoReceiveStream::Stop() {
eladalona28122f2017-08-18 04:02:48 -0700224 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
nisseb1f2ff92017-06-09 04:01:55 -0700225 rtp_video_stream_receiver_.StopReceive();
philipelfd5a20f2016-11-15 00:57:57 -0800226
philipela45102f2017-02-22 05:30:39 -0800227 frame_buffer_->Stop();
nisseb1f2ff92017-06-09 04:01:55 -0700228 call_stats_->DeregisterStatsObserver(&rtp_video_stream_receiver_);
tommic8ece432017-06-20 02:44:38 -0700229 process_thread_->DeRegisterModule(&video_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800230
sprang0d348d62016-10-07 08:28:39 -0700231 if (decode_thread_.IsRunning()) {
tommic8ece432017-06-20 02:44:38 -0700232 // TriggerDecoderShutdown will release any waiting decoder thread and make
233 // it stop immediately, instead of waiting for a timeout. Needs to be called
234 // before joining the decoder thread.
235 video_receiver_.TriggerDecoderShutdown();
236
sprang0d348d62016-10-07 08:28:39 -0700237 decode_thread_.Stop();
238 // Deregister external decoders so they are no longer running during
239 // destruction. This effectively stops the VCM since the decoder thread is
240 // stopped, the VCM is deregistered and no asynchronous decoder threads are
241 // running.
242 for (const Decoder& decoder : config_.decoders)
243 video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
244 }
philipelfd5a20f2016-11-15 00:57:57 -0800245
tommi2e82f382016-06-21 00:26:43 -0700246 call_stats_->DeregisterStatsObserver(video_stream_decoder_.get());
247 video_stream_decoder_.reset();
248 incoming_video_stream_.reset();
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000249 transport_adapter_.Disable();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000250}
251
sprang@webrtc.org9510e532014-02-07 15:32:45 +0000252VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
Peter Boströmf751bf82016-02-05 14:00:53 +0100253 return stats_proxy_.GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000254}
255
brandtr090c9402017-01-25 08:28:02 -0800256void VideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file,
257 size_t byte_limit) {
258 {
259 rtc::CritScope lock(&ivf_writer_lock_);
260 if (file == rtc::kInvalidPlatformFileValue) {
261 ivf_writer_.reset();
262 } else {
263 ivf_writer_ = IvfFileWriter::Wrap(rtc::File(file), byte_limit);
264 }
265 }
266
267 if (file != rtc::kInvalidPlatformFileValue) {
268 // Make a keyframe appear as early as possible in the logs, to give actually
269 // decodable output.
270 RequestKeyFrame();
271 }
272}
273
eladalonc0d481a2017-08-02 07:39:07 -0700274void VideoReceiveStream::AddSecondarySink(RtpPacketSinkInterface* sink) {
275 rtp_video_stream_receiver_.AddSecondarySink(sink);
276}
277
278void VideoReceiveStream::RemoveSecondarySink(
279 const RtpPacketSinkInterface* sink) {
280 rtp_video_stream_receiver_.RemoveSecondarySink(sink);
281}
282
tommi2e82f382016-06-21 00:26:43 -0700283// TODO(tommi): This method grabs a lock 6 times.
Tommibd3380f2016-06-10 17:38:17 +0200284void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
asaperssonf8cdd182016-03-15 01:00:47 -0700285 int64_t sync_offset_ms;
asaperssonde9e5ff2016-11-02 07:14:03 -0700286 double estimated_freq_khz;
tommi2e82f382016-06-21 00:26:43 -0700287 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the
288 // function itself, another in GetChannel() and a third in
289 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function
290 // succeeds most of the time, which leads to grabbing a fourth lock.
solenberg3ebbcb52017-01-31 03:58:40 -0800291 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame.timestamp(),
292 video_frame.render_time_ms(),
293 &sync_offset_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700294 &estimated_freq_khz)) {
tommi2e82f382016-06-21 00:26:43 -0700295 // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
asaperssonde9e5ff2016-11-02 07:14:03 -0700296 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
tommi2e82f382016-06-21 00:26:43 -0700297 }
tommi2e82f382016-06-21 00:26:43 -0700298 // config_.renderer must never be null if we're getting this callback.
299 config_.renderer->OnFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000300
tommi2e82f382016-06-21 00:26:43 -0700301 // TODO(tommi): OnRenderFrame grabs a lock too.
asapersson1490f7a2016-09-23 02:09:46 -0700302 stats_proxy_.OnRenderedFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000303}
pbos@webrtc.org26c0c412014-09-03 16:17:12 +0000304
asapersson86b01602015-10-20 23:55:26 -0700305// TODO(asapersson): Consider moving callback from video_encoder.h or
306// creating a different callback.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700307EncodedImageCallback::Result VideoReceiveStream::OnEncodedImage(
asapersson86b01602015-10-20 23:55:26 -0700308 const EncodedImage& encoded_image,
309 const CodecSpecificInfo* codec_specific_info,
310 const RTPFragmentationHeader* fragmentation) {
Peter Boströmf751bf82016-02-05 14:00:53 +0100311 stats_proxy_.OnPreDecode(encoded_image, codec_specific_info);
ilnikcb8c1462017-03-09 09:23:30 -0800312 size_t simulcast_idx = 0;
313 if (codec_specific_info->codecType == kVideoCodecVP8) {
314 simulcast_idx = codec_specific_info->codecSpecific.VP8.simulcastIdx;
315 }
asapersson86b01602015-10-20 23:55:26 -0700316 if (config_.pre_decode_callback) {
ilnikcb8c1462017-03-09 09:23:30 -0800317 config_.pre_decode_callback->EncodedFrameCallback(EncodedFrame(
318 encoded_image._buffer, encoded_image._length, encoded_image._frameType,
319 simulcast_idx, encoded_image._timeStamp));
asapersson86b01602015-10-20 23:55:26 -0700320 }
palmkviste75f2042016-09-28 06:19:48 -0700321 {
322 rtc::CritScope lock(&ivf_writer_lock_);
sprang3911c262016-04-15 01:24:14 -0700323 if (ivf_writer_.get()) {
palmkviste75f2042016-09-28 06:19:48 -0700324 RTC_DCHECK(codec_specific_info);
325 bool ok = ivf_writer_->WriteFrame(encoded_image,
326 codec_specific_info->codecType);
sprang3911c262016-04-15 01:24:14 -0700327 RTC_DCHECK(ok);
328 }
329 }
330
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700331 return Result(Result::OK, encoded_image._timeStamp);
asapersson86b01602015-10-20 23:55:26 -0700332}
333
brandtr090c9402017-01-25 08:28:02 -0800334void VideoReceiveStream::SendNack(
335 const std::vector<uint16_t>& sequence_numbers) {
nisseb1f2ff92017-06-09 04:01:55 -0700336 rtp_video_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
brandtr090c9402017-01-25 08:28:02 -0800337}
338
339void VideoReceiveStream::RequestKeyFrame() {
nisseb1f2ff92017-06-09 04:01:55 -0700340 rtp_video_stream_receiver_.RequestKeyFrame();
brandtr090c9402017-01-25 08:28:02 -0800341}
342
343void VideoReceiveStream::OnCompleteFrame(
344 std::unique_ptr<video_coding::FrameObject> frame) {
345 int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
346 if (last_continuous_pid != -1)
nisseb1f2ff92017-06-09 04:01:55 -0700347 rtp_video_stream_receiver_.FrameContinuous(last_continuous_pid);
brandtr090c9402017-01-25 08:28:02 -0800348}
349
solenberg3ebbcb52017-01-31 03:58:40 -0800350int VideoReceiveStream::id() const {
eladalona28122f2017-08-18 04:02:48 -0700351 RTC_DCHECK_CALLED_SEQUENTIALLY(&worker_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800352 return config_.rtp.remote_ssrc;
353}
354
355rtc::Optional<Syncable::Info> VideoReceiveStream::GetInfo() const {
eladalona28122f2017-08-18 04:02:48 -0700356 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800357 Syncable::Info info;
358
nisseb1f2ff92017-06-09 04:01:55 -0700359 RtpReceiver* rtp_receiver = rtp_video_stream_receiver_.GetRtpReceiver();
solenberg3ebbcb52017-01-31 03:58:40 -0800360 RTC_DCHECK(rtp_receiver);
361 if (!rtp_receiver->Timestamp(&info.latest_received_capture_timestamp))
362 return rtc::Optional<Syncable::Info>();
363 if (!rtp_receiver->LastReceivedTimeMs(&info.latest_receive_time_ms))
364 return rtc::Optional<Syncable::Info>();
365
nisseb1f2ff92017-06-09 04:01:55 -0700366 RtpRtcp* rtp_rtcp = rtp_video_stream_receiver_.rtp_rtcp();
solenberg3ebbcb52017-01-31 03:58:40 -0800367 RTC_DCHECK(rtp_rtcp);
368 if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs,
369 &info.capture_time_ntp_frac,
370 nullptr,
371 nullptr,
372 &info.capture_time_source_clock) != 0) {
373 return rtc::Optional<Syncable::Info>();
374 }
375
376 info.current_delay_ms = video_receiver_.Delay();
377 return rtc::Optional<Syncable::Info>(info);
378}
379
380uint32_t VideoReceiveStream::GetPlayoutTimestamp() const {
381 RTC_NOTREACHED();
382 return 0;
383}
384
385void VideoReceiveStream::SetMinimumPlayoutDelay(int delay_ms) {
eladalona28122f2017-08-18 04:02:48 -0700386 RTC_DCHECK_CALLED_SEQUENTIALLY(&module_process_sequence_checker_);
solenberg3ebbcb52017-01-31 03:58:40 -0800387 video_receiver_.SetMinimumPlayoutDelay(delay_ms);
388}
389
tommic8ece432017-06-20 02:44:38 -0700390void VideoReceiveStream::DecodeThreadFunction(void* ptr) {
391 while (static_cast<VideoReceiveStream*>(ptr)->Decode()) {
392 }
Peter Boströmca835252016-02-11 15:59:46 +0100393}
394
philipel2dfea3e2017-02-28 07:19:43 -0800395bool VideoReceiveStream::Decode() {
tommidb23ea62017-03-03 07:21:18 -0800396 TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
philipela45102f2017-02-22 05:30:39 -0800397 static const int kMaxWaitForFrameMs = 3000;
philipel3042c2d2017-08-18 04:55:02 -0700398 static const int kMaxWaitForKeyFrameMs = 200;
399
400 int wait_ms = keyframe_required_ ? kMaxWaitForKeyFrameMs : kMaxWaitForFrameMs;
philipela45102f2017-02-22 05:30:39 -0800401 std::unique_ptr<video_coding::FrameObject> frame;
philipel3042c2d2017-08-18 04:55:02 -0700402 // TODO(philipel): Call NextFrame with |keyframe_required| argument when
403 // downstream project has been fixed.
guidouc3372582017-04-04 07:16:21 -0700404 video_coding::FrameBuffer::ReturnReason res =
philipel3042c2d2017-08-18 04:55:02 -0700405 frame_buffer_->NextFrame(wait_ms, &frame);
philipelfd5a20f2016-11-15 00:57:57 -0800406
guidouc3372582017-04-04 07:16:21 -0700407 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) {
408 video_receiver_.DecodingStopped();
philipel2dfea3e2017-02-28 07:19:43 -0800409 return false;
guidouc3372582017-04-04 07:16:21 -0700410 }
philipelfd5a20f2016-11-15 00:57:57 -0800411
philipela45102f2017-02-22 05:30:39 -0800412 if (frame) {
tommic8ece432017-06-20 02:44:38 -0700413 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kFrameFound);
philipel3042c2d2017-08-18 04:55:02 -0700414 if (video_receiver_.Decode(frame.get()) == VCM_OK) {
415 keyframe_required_ = false;
416 frame_decoded_ = true;
nisseb1f2ff92017-06-09 04:01:55 -0700417 rtp_video_stream_receiver_.FrameDecoded(frame->picture_id);
philipel3042c2d2017-08-18 04:55:02 -0700418 } else if (!keyframe_required_ || !frame_decoded_) {
419 keyframe_required_ = true;
420 // TODO(philipel): Remove this keyframe request when downstream project
421 // has been fixed.
422 RequestKeyFrame();
423 }
philipelfd5a20f2016-11-15 00:57:57 -0800424 } else {
tommic8ece432017-06-20 02:44:38 -0700425 RTC_DCHECK_EQ(res, video_coding::FrameBuffer::ReturnReason::kTimeout);
philipel3184f8e2017-05-18 08:08:53 -0700426 int64_t now_ms = clock_->TimeInMilliseconds();
427 rtc::Optional<int64_t> last_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700428 rtp_video_stream_receiver_.LastReceivedPacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700429 rtc::Optional<int64_t> last_keyframe_packet_ms =
nisseb1f2ff92017-06-09 04:01:55 -0700430 rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
philipel3184f8e2017-05-18 08:08:53 -0700431
432 // To avoid spamming keyframe requests for a stream that is not active we
433 // check if we have received a packet within the last 5 seconds.
434 bool stream_is_active = last_packet_ms && now_ms - *last_packet_ms < 5000;
sprang3e86e7e2017-08-22 09:23:28 -0700435 if (!stream_is_active)
436 stats_proxy_.OnStreamInactive();
philipel3184f8e2017-05-18 08:08:53 -0700437
philipel3042c2d2017-08-18 04:55:02 -0700438 // If we recently have been receiving packets belonging to a keyframe then
439 // we assume a keyframe is currently being received.
philipel3184f8e2017-05-18 08:08:53 -0700440 bool receiving_keyframe =
441 last_keyframe_packet_ms &&
philipel3042c2d2017-08-18 04:55:02 -0700442 now_ms - *last_keyframe_packet_ms < kMaxWaitForKeyFrameMs;
philipel3184f8e2017-05-18 08:08:53 -0700443
444 if (stream_is_active && !receiving_keyframe) {
philipel3042c2d2017-08-18 04:55:02 -0700445 LOG(LS_WARNING) << "No decodable frame in " << wait_ms
philipel3184f8e2017-05-18 08:08:53 -0700446 << " ms, requesting keyframe.";
447 RequestKeyFrame();
448 }
philipelfd5a20f2016-11-15 00:57:57 -0800449 }
philipel2dfea3e2017-02-28 07:19:43 -0800450 return true;
Peter Boströmca835252016-02-11 15:59:46 +0100451}
mflodman@webrtc.orgf3973e82013-12-13 09:40:45 +0000452} // namespace internal
453} // namespace webrtc