blob: c59af899a4bea14f3a91855dd4c84e3e633f8501 [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
pbos@webrtc.org0d852d52015-02-09 15:14:36 +000019#include "webrtc/base/checks.h"
tommidea489f2017-03-03 03:20:24 -080020#include "webrtc/base/location.h"
Peter Boström415d2cd2015-10-26 11:35:17 +010021#include "webrtc/base/logging.h"
philipelfd5a20f2016-11-15 00:57:57 -080022#include "webrtc/base/optional.h"
tommidb23ea62017-03-03 07:21:18 -080023#include "webrtc/base/trace_event.h"
deadbeefc964d0b2017-04-03 10:03:35 -070024#include "webrtc/common_types.h"
magjede69a1a92016-11-25 10:06:31 -080025#include "webrtc/common_video/h264/profile_level_id.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000026#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
solenberg3ebbcb52017-01-31 03:58:40 -080027#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
28#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
Peter Boström1d04ac62016-02-05 11:25:46 +010029#include "webrtc/modules/utility/include/process_thread.h"
philipelfd5a20f2016-11-15 00:57:57 -080030#include "webrtc/modules/video_coding/frame_object.h"
Peter Boströma4c76882016-03-03 16:29:02 +010031#include "webrtc/modules/video_coding/include/video_coding.h"
philipelfd5a20f2016-11-15 00:57:57 -080032#include "webrtc/modules/video_coding/jitter_estimator.h"
33#include "webrtc/modules/video_coding/timing.h"
sprang3911c262016-04-15 01:24:14 -070034#include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010035#include "webrtc/system_wrappers/include/clock.h"
philipelfd5a20f2016-11-15 00:57:57 -080036#include "webrtc/system_wrappers/include/field_trial.h"
Peter Boström7623ce42015-12-09 12:13:30 +010037#include "webrtc/video/call_stats.h"
sprang@webrtc.org09315702014-02-07 12:06:29 +000038#include "webrtc/video/receive_statistics_proxy.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000039#include "webrtc/video_receive_stream.h"
pbos@webrtc.org29d58392013-05-16 12:08:03 +000040
41namespace webrtc {
mflodmana20de202015-10-18 22:08:19 -070042
pbos@webrtc.org32e85282015-01-15 10:09:39 +000043std::string VideoReceiveStream::Decoder::ToString() const {
44 std::stringstream ss;
Peter Boström74f6e9e2016-04-04 17:56:10 +020045 ss << "{decoder: " << (decoder ? "(VideoDecoder)" : "nullptr");
pbos@webrtc.org32e85282015-01-15 10:09:39 +000046 ss << ", payload_type: " << payload_type;
47 ss << ", payload_name: " << payload_name;
magjed5dfac562016-11-25 03:56:37 -080048 ss << ", codec_params: {";
49 for (const auto& it : codec_params)
50 ss << it.first << ": " << it.second;
johan3859c892016-08-05 09:19:25 -070051 ss << '}';
pbos@webrtc.org32e85282015-01-15 10:09:39 +000052 ss << '}';
53
54 return ss.str();
55}
56
57std::string VideoReceiveStream::Config::ToString() const {
58 std::stringstream ss;
59 ss << "{decoders: [";
60 for (size_t i = 0; i < decoders.size(); ++i) {
61 ss << decoders[i].ToString();
62 if (i != decoders.size() - 1)
63 ss << ", ";
64 }
65 ss << ']';
66 ss << ", rtp: " << rtp.ToString();
Peter Boström74f6e9e2016-04-04 17:56:10 +020067 ss << ", renderer: " << (renderer ? "(renderer)" : "nullptr");
pbos@webrtc.org32e85282015-01-15 10:09:39 +000068 ss << ", render_delay_ms: " << render_delay_ms;
pbos8fc7fa72015-07-15 08:02:58 -070069 if (!sync_group.empty())
70 ss << ", sync_group: " << sync_group;
pbos@webrtc.org32e85282015-01-15 10:09:39 +000071 ss << ", pre_decode_callback: "
Peter Boström74f6e9e2016-04-04 17:56:10 +020072 << (pre_decode_callback ? "(EncodedFrameObserver)" : "nullptr");
pbos@webrtc.org32e85282015-01-15 10:09:39 +000073 ss << ", target_delay_ms: " << target_delay_ms;
74 ss << '}';
75
76 return ss.str();
77}
78
79std::string VideoReceiveStream::Config::Rtp::ToString() const {
80 std::stringstream ss;
81 ss << "{remote_ssrc: " << remote_ssrc;
82 ss << ", local_ssrc: " << local_ssrc;
pbosda903ea2015-10-02 02:36:56 -070083 ss << ", rtcp_mode: "
84 << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound"
85 : "RtcpMode::kReducedSize");
pbos@webrtc.org32e85282015-01-15 10:09:39 +000086 ss << ", rtcp_xr: ";
87 ss << "{receiver_reference_time_report: "
88 << (rtcp_xr.receiver_reference_time_report ? "on" : "off");
89 ss << '}';
90 ss << ", remb: " << (remb ? "on" : "off");
stefan43edf0f2015-11-20 18:05:48 -080091 ss << ", transport_cc: " << (transport_cc ? "on" : "off");
pbos@webrtc.org32e85282015-01-15 10:09:39 +000092 ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
brandtrb5f2c3f2016-10-04 23:28:39 -070093 ss << ", ulpfec: " << ulpfec.ToString();
brandtr14742122017-01-27 04:53:07 -080094 ss << ", rtx_ssrc: " << rtx_ssrc;
95 ss << ", rtx_payload_types: {";
96 for (auto& kv : rtx_payload_types) {
97 ss << kv.first << " (apt) -> " << kv.second << " (pt), ";
pbos@webrtc.org32e85282015-01-15 10:09:39 +000098 }
99 ss << '}';
100 ss << ", extensions: [";
101 for (size_t i = 0; i < extensions.size(); ++i) {
102 ss << extensions[i].ToString();
103 if (i != extensions.size() - 1)
104 ss << ", ";
105 }
106 ss << ']';
107 ss << '}';
108 return ss.str();
109}
110
asapersson2e5cfcd2016-08-11 08:41:18 -0700111std::string VideoReceiveStream::Stats::ToString(int64_t time_ms) const {
112 std::stringstream ss;
113 ss << "VideoReceiveStream stats: " << time_ms << ", {ssrc: " << ssrc << ", ";
114 ss << "total_bps: " << total_bitrate_bps << ", ";
115 ss << "width: " << width << ", ";
116 ss << "height: " << height << ", ";
117 ss << "key: " << frame_counts.key_frames << ", ";
118 ss << "delta: " << frame_counts.delta_frames << ", ";
119 ss << "network_fps: " << network_frame_rate << ", ";
120 ss << "decode_fps: " << decode_frame_rate << ", ";
121 ss << "render_fps: " << render_frame_rate << ", ";
122 ss << "decode_ms: " << decode_ms << ", ";
123 ss << "max_decode_ms: " << max_decode_ms << ", ";
124 ss << "cur_delay_ms: " << current_delay_ms << ", ";
125 ss << "targ_delay_ms: " << target_delay_ms << ", ";
126 ss << "jb_delay_ms: " << jitter_buffer_ms << ", ";
127 ss << "min_playout_delay_ms: " << min_playout_delay_ms << ", ";
128 ss << "discarded: " << discarded_packets << ", ";
129 ss << "sync_offset_ms: " << sync_offset_ms << ", ";
130 ss << "cum_loss: " << rtcp_stats.cumulative_lost << ", ";
131 ss << "max_ext_seq: " << rtcp_stats.extended_max_sequence_number << ", ";
132 ss << "nack: " << rtcp_packet_type_counts.nack_packets << ", ";
133 ss << "fir: " << rtcp_packet_type_counts.fir_packets << ", ";
134 ss << "pli: " << rtcp_packet_type_counts.pli_packets;
135 ss << '}';
136 return ss.str();
137}
138
pbos@webrtc.org776e6f22014-10-29 15:28:39 +0000139namespace {
140VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
141 VideoCodec codec;
142 memset(&codec, 0, sizeof(codec));
143
144 codec.plType = decoder.payload_type;
mflodmand1590b22015-12-09 07:07:59 -0800145 strncpy(codec.plName, decoder.payload_name.c_str(), sizeof(codec.plName));
deadbeefc964d0b2017-04-03 10:03:35 -0700146 codec.codecType =
147 PayloadNameToCodecType(decoder.payload_name).value_or(kVideoCodecGeneric);
pbos@webrtc.org776e6f22014-10-29 15:28:39 +0000148
149 if (codec.codecType == kVideoCodecVP8) {
hta257dc392016-10-25 09:05:06 -0700150 *(codec.VP8()) = VideoEncoder::GetDefaultVp8Settings();
ivica05cfcd32015-09-07 06:04:16 -0700151 } else if (codec.codecType == kVideoCodecVP9) {
hta257dc392016-10-25 09:05:06 -0700152 *(codec.VP9()) = VideoEncoder::GetDefaultVp9Settings();
pbos@webrtc.org776e6f22014-10-29 15:28:39 +0000153 } else if (codec.codecType == kVideoCodecH264) {
hta257dc392016-10-25 09:05:06 -0700154 *(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
magjede69a1a92016-11-25 10:06:31 -0800155 codec.H264()->profile =
156 H264::ParseSdpProfileLevelId(decoder.codec_params)->profile;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +0000157 }
158
159 codec.width = 320;
160 codec.height = 180;
stefanb4bc65b2016-11-02 10:10:20 -0700161 const int kDefaultStartBitrate = 300;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +0000162 codec.startBitrate = codec.minBitrate = codec.maxBitrate =
stefanb4bc65b2016-11-02 10:10:20 -0700163 kDefaultStartBitrate;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +0000164
165 return codec;
166}
167} // namespace
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000168
Peter Boströmca835252016-02-11 15:59:46 +0100169namespace internal {
tommi2e82f382016-06-21 00:26:43 -0700170
mflodman0c478b32015-10-21 15:52:16 +0200171VideoReceiveStream::VideoReceiveStream(
172 int num_cpu_cores,
nisse0245da02016-11-30 03:35:20 -0800173 PacketRouter* packet_router,
Tommi733b5472016-06-10 17:58:01 +0200174 VideoReceiveStream::Config config,
mflodman0c478b32015-10-21 15:52:16 +0200175 ProcessThread* process_thread,
Stefan Holmer58c664c2016-02-08 14:31:30 +0100176 CallStats* call_stats,
177 VieRemb* remb)
solenberg4fbae2b2015-08-28 04:07:10 -0700178 : transport_adapter_(config.rtcp_send_transport),
Tommi733b5472016-06-10 17:58:01 +0200179 config_(std::move(config)),
sprang113bdca2016-10-11 03:10:10 -0700180 num_cpu_cores_(num_cpu_cores),
Peter Boström1d04ac62016-02-05 11:25:46 +0100181 process_thread_(process_thread),
sprang@webrtc.org09315702014-02-07 12:06:29 +0000182 clock_(Clock::GetRealTimeClock()),
Peter Boströmca835252016-02-11 15:59:46 +0100183 decode_thread_(DecodeThreadFunction, this, "DecodingThread"),
Peter Boström1d04ac62016-02-05 11:25:46 +0100184 call_stats_(call_stats),
philipelfd5a20f2016-11-15 00:57:57 -0800185 timing_(new VCMTiming(clock_)),
philipel721d4022016-12-15 07:10:57 -0800186 video_receiver_(clock_, nullptr, this, timing_.get(), this, this),
187 stats_proxy_(&config_, clock_),
philipela45102f2017-02-22 05:30:39 -0800188 rtp_stream_receiver_(&transport_adapter_,
brandtrfb45c6c2017-01-27 06:47:55 -0800189 call_stats_->rtcp_rtt_stats(),
190 packet_router,
191 remb,
192 &config_,
193 &stats_proxy_,
194 process_thread_,
195 this, // NackSender
196 this, // KeyFrameRequestSender
197 this, // OnCompleteFrameCallback
198 timing_.get()),
philipela45102f2017-02-22 05:30:39 -0800199 rtp_stream_sync_(this) {
pbosa2f30de2015-10-15 05:22:13 -0700200 LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000201
Stefan Holmer58c664c2016-02-08 14:31:30 +0100202 RTC_DCHECK(process_thread_);
Stefan Holmer58c664c2016-02-08 14:31:30 +0100203 RTC_DCHECK(call_stats_);
mflodmancfc8e3b2016-05-03 21:22:04 -0700204
solenberg3ebbcb52017-01-31 03:58:40 -0800205 module_process_thread_checker_.DetachFromThread();
206
henrikg91d6ede2015-09-17 00:24:34 -0700207 RTC_DCHECK(!config_.decoders.empty());
Peter Boström521af4e2015-11-27 16:35:04 +0100208 std::set<int> decoder_payload_types;
Peter Boströmb1ae3a42016-02-15 17:52:40 +0100209 for (const Decoder& decoder : config_.decoders) {
Peter Boström795dbe42015-11-27 14:09:07 +0100210 RTC_CHECK(decoder.decoder);
Peter Boström521af4e2015-11-27 16:35:04 +0100211 RTC_CHECK(decoder_payload_types.find(decoder.payload_type) ==
212 decoder_payload_types.end())
213 << "Duplicate payload type (" << decoder.payload_type
214 << ") for different decoders.";
215 decoder_payload_types.insert(decoder.payload_type);
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000216 }
217
Peter Boström0b250722016-04-22 18:23:15 +0200218 video_receiver_.SetRenderDelay(config.render_delay_ms);
Peter Boström1d04ac62016-02-05 11:25:46 +0100219
philipela45102f2017-02-22 05:30:39 -0800220 jitter_estimator_.reset(new VCMJitterEstimator(clock_));
221 frame_buffer_.reset(new video_coding::FrameBuffer(
222 clock_, jitter_estimator_.get(), timing_.get(), &stats_proxy_));
philipelfd5a20f2016-11-15 00:57:57 -0800223
tommidea489f2017-03-03 03:20:24 -0800224 process_thread_->RegisterModule(&video_receiver_, RTC_FROM_HERE);
225 process_thread_->RegisterModule(&rtp_stream_sync_, RTC_FROM_HERE);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000226}
227
228VideoReceiveStream::~VideoReceiveStream() {
solenberg3ebbcb52017-01-31 03:58:40 -0800229 RTC_DCHECK_RUN_ON(&worker_thread_checker_);
pbosa2f30de2015-10-15 05:22:13 -0700230 LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString();
Peter Boströmca835252016-02-11 15:59:46 +0100231 Stop();
232
mflodman4cd27902016-08-05 06:28:45 -0700233 process_thread_->DeRegisterModule(&rtp_stream_sync_);
Peter Boström0b250722016-04-22 18:23:15 +0200234 process_thread_->DeRegisterModule(&video_receiver_);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000235}
236
pbos1ba8d392016-05-01 20:18:34 -0700237void VideoReceiveStream::SignalNetworkState(NetworkState state) {
solenberg3ebbcb52017-01-31 03:58:40 -0800238 RTC_DCHECK_RUN_ON(&worker_thread_checker_);
mflodmandc7d0d22016-05-06 05:32:22 -0700239 rtp_stream_receiver_.SignalNetworkState(state);
pbos1ba8d392016-05-01 20:18:34 -0700240}
241
242
243bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
244 return rtp_stream_receiver_.DeliverRtcp(packet, length);
245}
246
nisse38cc1d62017-02-13 05:59:46 -0800247void VideoReceiveStream::OnRtpPacket(const RtpPacketReceived& packet) {
248 rtp_stream_receiver_.OnRtpPacket(packet);
pbos1ba8d392016-05-01 20:18:34 -0700249}
250
brandtr4e523862016-10-18 23:50:45 -0700251bool VideoReceiveStream::OnRecoveredPacket(const uint8_t* packet,
252 size_t length) {
253 return rtp_stream_receiver_.OnRecoveredPacket(packet, length);
254}
255
solenberg3ebbcb52017-01-31 03:58:40 -0800256void VideoReceiveStream::SetSync(Syncable* audio_syncable) {
257 RTC_DCHECK_RUN_ON(&worker_thread_checker_);
258 rtp_stream_sync_.ConfigureSync(audio_syncable);
brandtr090c9402017-01-25 08:28:02 -0800259}
260
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000261void VideoReceiveStream::Start() {
solenberg3ebbcb52017-01-31 03:58:40 -0800262 RTC_DCHECK_RUN_ON(&worker_thread_checker_);
Peter Boströmca835252016-02-11 15:59:46 +0100263 if (decode_thread_.IsRunning())
264 return;
brandtrfb45c6c2017-01-27 06:47:55 -0800265
nissec69385d2017-03-09 06:13:20 -0800266 bool protected_by_fec = config_.rtp.protected_by_flexfec ||
267 rtp_stream_receiver_.IsUlpfecEnabled();
brandtrfb45c6c2017-01-27 06:47:55 -0800268
philipela45102f2017-02-22 05:30:39 -0800269 frame_buffer_->Start();
270 call_stats_->RegisterStatsObserver(&rtp_stream_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800271
philipela45102f2017-02-22 05:30:39 -0800272 if (rtp_stream_receiver_.IsRetransmissionsEnabled() && protected_by_fec) {
273 frame_buffer_->SetProtectionMode(kProtectionNackFEC);
philipelfd5a20f2016-11-15 00:57:57 -0800274 }
philipela45102f2017-02-22 05:30:39 -0800275
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000276 transport_adapter_.Enable();
tommi2e82f382016-06-21 00:26:43 -0700277 rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
278 if (config_.renderer) {
279 if (config_.disable_prerenderer_smoothing) {
280 renderer = this;
281 } else {
282 incoming_video_stream_.reset(
283 new IncomingVideoStream(config_.render_delay_ms, this));
284 renderer = incoming_video_stream_.get();
285 }
286 }
sakal55d932b2016-09-30 06:19:08 -0700287 RTC_DCHECK(renderer != nullptr);
tommi2e82f382016-06-21 00:26:43 -0700288
sprang113bdca2016-10-11 03:10:10 -0700289 for (const Decoder& decoder : config_.decoders) {
290 video_receiver_.RegisterExternalDecoder(decoder.decoder,
291 decoder.payload_type);
sprang113bdca2016-10-11 03:10:10 -0700292 VideoCodec codec = CreateDecoderVideoCodec(decoder);
johanbfb11b22017-01-25 07:37:27 -0800293 RTC_CHECK(
294 rtp_stream_receiver_.AddReceiveCodec(codec, decoder.codec_params));
sprang113bdca2016-10-11 03:10:10 -0700295 RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
296 &codec, num_cpu_cores_, false));
297 }
298
tommi2e82f382016-06-21 00:26:43 -0700299 video_stream_decoder_.reset(new VideoStreamDecoder(
300 &video_receiver_, &rtp_stream_receiver_, &rtp_stream_receiver_,
brandtrfb45c6c2017-01-27 06:47:55 -0800301 rtp_stream_receiver_.IsRetransmissionsEnabled(), protected_by_fec,
nisse76bc8e82017-02-07 09:37:41 -0800302 &stats_proxy_, renderer));
tommi2e82f382016-06-21 00:26:43 -0700303 // Register the channel to receive stats updates.
304 call_stats_->RegisterStatsObserver(video_stream_decoder_.get());
Peter Boströmca835252016-02-11 15:59:46 +0100305 // Start the decode thread
306 decode_thread_.Start();
307 decode_thread_.SetPriority(rtc::kHighestPriority);
mflodmanfa666592016-04-28 23:15:33 -0700308 rtp_stream_receiver_.StartReceive();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000309}
310
pbos@webrtc.orga5c8d2c2014-04-24 11:13:21 +0000311void VideoReceiveStream::Stop() {
solenberg3ebbcb52017-01-31 03:58:40 -0800312 RTC_DCHECK_RUN_ON(&worker_thread_checker_);
mflodmanfa666592016-04-28 23:15:33 -0700313 rtp_stream_receiver_.StopReceive();
sprang22691e02016-07-13 10:57:07 -0700314 // TriggerDecoderShutdown will release any waiting decoder thread and make it
315 // stop immediately, instead of waiting for a timeout. Needs to be called
316 // before joining the decoder thread thread.
Peter Boström0b250722016-04-22 18:23:15 +0200317 video_receiver_.TriggerDecoderShutdown();
philipelfd5a20f2016-11-15 00:57:57 -0800318
philipela45102f2017-02-22 05:30:39 -0800319 frame_buffer_->Stop();
320 call_stats_->DeregisterStatsObserver(&rtp_stream_receiver_);
philipelfd5a20f2016-11-15 00:57:57 -0800321
sprang0d348d62016-10-07 08:28:39 -0700322 if (decode_thread_.IsRunning()) {
323 decode_thread_.Stop();
324 // Deregister external decoders so they are no longer running during
325 // destruction. This effectively stops the VCM since the decoder thread is
326 // stopped, the VCM is deregistered and no asynchronous decoder threads are
327 // running.
328 for (const Decoder& decoder : config_.decoders)
329 video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
330 }
philipelfd5a20f2016-11-15 00:57:57 -0800331
tommi2e82f382016-06-21 00:26:43 -0700332 call_stats_->DeregisterStatsObserver(video_stream_decoder_.get());
333 video_stream_decoder_.reset();
334 incoming_video_stream_.reset();
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000335 transport_adapter_.Disable();
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000336}
337
sprang@webrtc.org9510e532014-02-07 15:32:45 +0000338VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
Peter Boströmf751bf82016-02-05 14:00:53 +0100339 return stats_proxy_.GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000340}
341
brandtr090c9402017-01-25 08:28:02 -0800342void VideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file,
343 size_t byte_limit) {
344 {
345 rtc::CritScope lock(&ivf_writer_lock_);
346 if (file == rtc::kInvalidPlatformFileValue) {
347 ivf_writer_.reset();
348 } else {
349 ivf_writer_ = IvfFileWriter::Wrap(rtc::File(file), byte_limit);
350 }
351 }
352
353 if (file != rtc::kInvalidPlatformFileValue) {
354 // Make a keyframe appear as early as possible in the logs, to give actually
355 // decodable output.
356 RequestKeyFrame();
357 }
358}
359
tommi2e82f382016-06-21 00:26:43 -0700360// TODO(tommi): This method grabs a lock 6 times.
Tommibd3380f2016-06-10 17:38:17 +0200361void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
asaperssonf8cdd182016-03-15 01:00:47 -0700362 int64_t sync_offset_ms;
asaperssonde9e5ff2016-11-02 07:14:03 -0700363 double estimated_freq_khz;
tommi2e82f382016-06-21 00:26:43 -0700364 // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks. One inside the
365 // function itself, another in GetChannel() and a third in
366 // GetPlayoutTimestamp. Seems excessive. Anyhow, I'm assuming the function
367 // succeeds most of the time, which leads to grabbing a fourth lock.
solenberg3ebbcb52017-01-31 03:58:40 -0800368 if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame.timestamp(),
369 video_frame.render_time_ms(),
370 &sync_offset_ms,
asaperssonde9e5ff2016-11-02 07:14:03 -0700371 &estimated_freq_khz)) {
tommi2e82f382016-06-21 00:26:43 -0700372 // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
asaperssonde9e5ff2016-11-02 07:14:03 -0700373 stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
tommi2e82f382016-06-21 00:26:43 -0700374 }
tommi2e82f382016-06-21 00:26:43 -0700375 // config_.renderer must never be null if we're getting this callback.
376 config_.renderer->OnFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000377
tommi2e82f382016-06-21 00:26:43 -0700378 // TODO(tommi): OnRenderFrame grabs a lock too.
asapersson1490f7a2016-09-23 02:09:46 -0700379 stats_proxy_.OnRenderedFrame(video_frame);
pbos@webrtc.org29d58392013-05-16 12:08:03 +0000380}
pbos@webrtc.org26c0c412014-09-03 16:17:12 +0000381
asapersson86b01602015-10-20 23:55:26 -0700382// TODO(asapersson): Consider moving callback from video_encoder.h or
383// creating a different callback.
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700384EncodedImageCallback::Result VideoReceiveStream::OnEncodedImage(
asapersson86b01602015-10-20 23:55:26 -0700385 const EncodedImage& encoded_image,
386 const CodecSpecificInfo* codec_specific_info,
387 const RTPFragmentationHeader* fragmentation) {
Peter Boströmf751bf82016-02-05 14:00:53 +0100388 stats_proxy_.OnPreDecode(encoded_image, codec_specific_info);
ilnikcb8c1462017-03-09 09:23:30 -0800389 size_t simulcast_idx = 0;
390 if (codec_specific_info->codecType == kVideoCodecVP8) {
391 simulcast_idx = codec_specific_info->codecSpecific.VP8.simulcastIdx;
392 }
asapersson86b01602015-10-20 23:55:26 -0700393 if (config_.pre_decode_callback) {
ilnikcb8c1462017-03-09 09:23:30 -0800394 config_.pre_decode_callback->EncodedFrameCallback(EncodedFrame(
395 encoded_image._buffer, encoded_image._length, encoded_image._frameType,
396 simulcast_idx, encoded_image._timeStamp));
asapersson86b01602015-10-20 23:55:26 -0700397 }
palmkviste75f2042016-09-28 06:19:48 -0700398 {
399 rtc::CritScope lock(&ivf_writer_lock_);
sprang3911c262016-04-15 01:24:14 -0700400 if (ivf_writer_.get()) {
palmkviste75f2042016-09-28 06:19:48 -0700401 RTC_DCHECK(codec_specific_info);
402 bool ok = ivf_writer_->WriteFrame(encoded_image,
403 codec_specific_info->codecType);
sprang3911c262016-04-15 01:24:14 -0700404 RTC_DCHECK(ok);
405 }
406 }
407
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700408 return Result(Result::OK, encoded_image._timeStamp);
asapersson86b01602015-10-20 23:55:26 -0700409}
410
brandtr090c9402017-01-25 08:28:02 -0800411void VideoReceiveStream::SendNack(
412 const std::vector<uint16_t>& sequence_numbers) {
413 rtp_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
414}
415
416void VideoReceiveStream::RequestKeyFrame() {
417 rtp_stream_receiver_.RequestKeyFrame();
418}
419
420void VideoReceiveStream::OnCompleteFrame(
421 std::unique_ptr<video_coding::FrameObject> frame) {
422 int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
423 if (last_continuous_pid != -1)
424 rtp_stream_receiver_.FrameContinuous(last_continuous_pid);
425}
426
solenberg3ebbcb52017-01-31 03:58:40 -0800427int VideoReceiveStream::id() const {
428 RTC_DCHECK_RUN_ON(&worker_thread_checker_);
429 return config_.rtp.remote_ssrc;
430}
431
432rtc::Optional<Syncable::Info> VideoReceiveStream::GetInfo() const {
433 RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
434 Syncable::Info info;
435
436 RtpReceiver* rtp_receiver = rtp_stream_receiver_.GetRtpReceiver();
437 RTC_DCHECK(rtp_receiver);
438 if (!rtp_receiver->Timestamp(&info.latest_received_capture_timestamp))
439 return rtc::Optional<Syncable::Info>();
440 if (!rtp_receiver->LastReceivedTimeMs(&info.latest_receive_time_ms))
441 return rtc::Optional<Syncable::Info>();
442
443 RtpRtcp* rtp_rtcp = rtp_stream_receiver_.rtp_rtcp();
444 RTC_DCHECK(rtp_rtcp);
445 if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs,
446 &info.capture_time_ntp_frac,
447 nullptr,
448 nullptr,
449 &info.capture_time_source_clock) != 0) {
450 return rtc::Optional<Syncable::Info>();
451 }
452
453 info.current_delay_ms = video_receiver_.Delay();
454 return rtc::Optional<Syncable::Info>(info);
455}
456
457uint32_t VideoReceiveStream::GetPlayoutTimestamp() const {
458 RTC_NOTREACHED();
459 return 0;
460}
461
462void VideoReceiveStream::SetMinimumPlayoutDelay(int delay_ms) {
463 RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
464 video_receiver_.SetMinimumPlayoutDelay(delay_ms);
465}
466
Peter Boströmca835252016-02-11 15:59:46 +0100467bool VideoReceiveStream::DecodeThreadFunction(void* ptr) {
philipel2dfea3e2017-02-28 07:19:43 -0800468 return static_cast<VideoReceiveStream*>(ptr)->Decode();
Peter Boströmca835252016-02-11 15:59:46 +0100469}
470
philipel2dfea3e2017-02-28 07:19:43 -0800471bool VideoReceiveStream::Decode() {
tommidb23ea62017-03-03 07:21:18 -0800472 TRACE_EVENT0("webrtc", "VideoReceiveStream::Decode");
philipela45102f2017-02-22 05:30:39 -0800473 static const int kMaxWaitForFrameMs = 3000;
474 std::unique_ptr<video_coding::FrameObject> frame;
475 video_coding::FrameBuffer::ReturnReason res =
476 frame_buffer_->NextFrame(kMaxWaitForFrameMs, &frame);
philipelfd5a20f2016-11-15 00:57:57 -0800477
tommid0a71ba2017-03-14 04:16:20 -0700478 if (res == video_coding::FrameBuffer::ReturnReason::kStopped) {
479 video_receiver_.DecodingStopped();
philipel2dfea3e2017-02-28 07:19:43 -0800480 return false;
tommid0a71ba2017-03-14 04:16:20 -0700481 }
philipelfd5a20f2016-11-15 00:57:57 -0800482
philipela45102f2017-02-22 05:30:39 -0800483 if (frame) {
484 if (video_receiver_.Decode(frame.get()) == VCM_OK)
485 rtp_stream_receiver_.FrameDecoded(frame->picture_id);
philipelfd5a20f2016-11-15 00:57:57 -0800486 } else {
philipela45102f2017-02-22 05:30:39 -0800487 LOG(LS_WARNING) << "No decodable frame in " << kMaxWaitForFrameMs
488 << " ms, requesting keyframe.";
489 RequestKeyFrame();
philipelfd5a20f2016-11-15 00:57:57 -0800490 }
philipel2dfea3e2017-02-28 07:19:43 -0800491 return true;
Peter Boströmca835252016-02-11 15:59:46 +0100492}
mflodman@webrtc.orgf3973e82013-12-13 09:40:45 +0000493} // namespace internal
494} // namespace webrtc