LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/video - video_receive_stream.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 282 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 26 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       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             : 
      11             : #include "webrtc/video/video_receive_stream.h"
      12             : 
      13             : #include <stdlib.h>
      14             : 
      15             : #include <set>
      16             : #include <string>
      17             : #include <utility>
      18             : 
      19             : #include "webrtc/base/checks.h"
      20             : #include "webrtc/base/logging.h"
      21             : #include "webrtc/base/optional.h"
      22             : #include "webrtc/common_video/h264/profile_level_id.h"
      23             : #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
      24             : #include "webrtc/modules/congestion_controller/include/congestion_controller.h"
      25             : #include "webrtc/modules/utility/include/process_thread.h"
      26             : #include "webrtc/modules/video_coding/frame_object.h"
      27             : #include "webrtc/modules/video_coding/include/video_coding.h"
      28             : #include "webrtc/modules/video_coding/jitter_estimator.h"
      29             : #include "webrtc/modules/video_coding/timing.h"
      30             : #include "webrtc/modules/video_coding/utility/ivf_file_writer.h"
      31             : #include "webrtc/system_wrappers/include/clock.h"
      32             : #include "webrtc/system_wrappers/include/field_trial.h"
      33             : #include "webrtc/video/call_stats.h"
      34             : #include "webrtc/video/receive_statistics_proxy.h"
      35             : #include "webrtc/video_receive_stream.h"
      36             : #include "webrtc/voice_engine/include/voe_video_sync.h"
      37             : 
      38             : namespace webrtc {
      39             : 
      40           0 : static bool UseSendSideBwe(const VideoReceiveStream::Config& config) {
      41           0 :   if (!config.rtp.transport_cc)
      42           0 :     return false;
      43           0 :   for (const auto& extension : config.rtp.extensions) {
      44           0 :     if (extension.uri == RtpExtension::kTransportSequenceNumberUri)
      45           0 :       return true;
      46             :   }
      47           0 :   return false;
      48             : }
      49             : 
      50           0 : std::string VideoReceiveStream::Decoder::ToString() const {
      51           0 :   std::stringstream ss;
      52           0 :   ss << "{decoder: " << (decoder ? "(VideoDecoder)" : "nullptr");
      53           0 :   ss << ", payload_type: " << payload_type;
      54           0 :   ss << ", payload_name: " << payload_name;
      55           0 :   ss << ", codec_params: {";
      56           0 :   for (const auto& it : codec_params)
      57           0 :     ss << it.first << ": " << it.second;
      58           0 :   ss << '}';
      59           0 :   ss << '}';
      60             : 
      61           0 :   return ss.str();
      62             : }
      63             : 
      64           0 : std::string VideoReceiveStream::Config::ToString() const {
      65           0 :   std::stringstream ss;
      66           0 :   ss << "{decoders: [";
      67           0 :   for (size_t i = 0; i < decoders.size(); ++i) {
      68           0 :     ss << decoders[i].ToString();
      69           0 :     if (i != decoders.size() - 1)
      70           0 :       ss << ", ";
      71             :   }
      72           0 :   ss << ']';
      73           0 :   ss << ", rtp: " << rtp.ToString();
      74           0 :   ss << ", renderer: " << (renderer ? "(renderer)" : "nullptr");
      75           0 :   ss << ", render_delay_ms: " << render_delay_ms;
      76           0 :   if (!sync_group.empty())
      77           0 :     ss << ", sync_group: " << sync_group;
      78             :   ss << ", pre_decode_callback: "
      79           0 :      << (pre_decode_callback ? "(EncodedFrameObserver)" : "nullptr");
      80             :   ss << ", pre_render_callback: "
      81           0 :      << (pre_render_callback ? "(I420FrameCallback)" : "nullptr");
      82           0 :   ss << ", target_delay_ms: " << target_delay_ms;
      83           0 :   ss << '}';
      84             : 
      85           0 :   return ss.str();
      86             : }
      87             : 
      88           0 : std::string VideoReceiveStream::Config::Rtp::ToString() const {
      89           0 :   std::stringstream ss;
      90           0 :   ss << "{remote_ssrc: " << remote_ssrc;
      91           0 :   ss << ", local_ssrc: " << local_ssrc;
      92             :   ss << ", rtcp_mode: "
      93           0 :      << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound"
      94           0 :                                           : "RtcpMode::kReducedSize");
      95           0 :   ss << ", rtcp_xr: ";
      96             :   ss << "{receiver_reference_time_report: "
      97           0 :      << (rtcp_xr.receiver_reference_time_report ? "on" : "off");
      98           0 :   ss << '}';
      99           0 :   ss << ", remb: " << (remb ? "on" : "off");
     100           0 :   ss << ", transport_cc: " << (transport_cc ? "on" : "off");
     101           0 :   ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
     102           0 :   ss << ", ulpfec: " << ulpfec.ToString();
     103           0 :   ss << ", rtx: {";
     104           0 :   for (auto& kv : rtx) {
     105           0 :     ss << kv.first << " -> ";
     106           0 :     ss << "{ssrc: " << kv.second.ssrc;
     107           0 :     ss << ", payload_type: " << kv.second.payload_type;
     108           0 :     ss << '}';
     109             :   }
     110           0 :   ss << '}';
     111           0 :   ss << ", extensions: [";
     112           0 :   for (size_t i = 0; i < extensions.size(); ++i) {
     113           0 :     ss << extensions[i].ToString();
     114           0 :     if (i != extensions.size() - 1)
     115           0 :       ss << ", ";
     116             :   }
     117           0 :   ss << ']';
     118           0 :   ss << '}';
     119           0 :   return ss.str();
     120             : }
     121             : 
     122           0 : std::string VideoReceiveStream::Stats::ToString(int64_t time_ms) const {
     123           0 :   std::stringstream ss;
     124           0 :   ss << "VideoReceiveStream stats: " << time_ms << ", {ssrc: " << ssrc << ", ";
     125           0 :   ss << "total_bps: " << total_bitrate_bps << ", ";
     126           0 :   ss << "width: " << width << ", ";
     127           0 :   ss << "height: " << height << ", ";
     128           0 :   ss << "key: " << frame_counts.key_frames << ", ";
     129           0 :   ss << "delta: " << frame_counts.delta_frames << ", ";
     130           0 :   ss << "network_fps: " << network_frame_rate << ", ";
     131           0 :   ss << "decode_fps: " << decode_frame_rate << ", ";
     132           0 :   ss << "render_fps: " << render_frame_rate << ", ";
     133           0 :   ss << "decode_ms: " << decode_ms << ", ";
     134           0 :   ss << "max_decode_ms: " << max_decode_ms << ", ";
     135           0 :   ss << "cur_delay_ms: " << current_delay_ms << ", ";
     136           0 :   ss << "targ_delay_ms: " << target_delay_ms << ", ";
     137           0 :   ss << "jb_delay_ms: " << jitter_buffer_ms << ", ";
     138           0 :   ss << "min_playout_delay_ms: " << min_playout_delay_ms << ", ";
     139           0 :   ss << "discarded: " << discarded_packets << ", ";
     140           0 :   ss << "sync_offset_ms: " << sync_offset_ms << ", ";
     141           0 :   ss << "cum_loss: " << rtcp_stats.cumulative_lost << ", ";
     142           0 :   ss << "max_ext_seq: " << rtcp_stats.extended_max_sequence_number << ", ";
     143           0 :   ss << "nack: " << rtcp_packet_type_counts.nack_packets << ", ";
     144           0 :   ss << "fir: " << rtcp_packet_type_counts.fir_packets << ", ";
     145           0 :   ss << "pli: " << rtcp_packet_type_counts.pli_packets;
     146           0 :   ss << '}';
     147           0 :   return ss.str();
     148             : }
     149             : 
     150             : namespace {
     151           0 : VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
     152           0 :   VideoCodec codec;
     153           0 :   memset(&codec, 0, sizeof(codec));
     154             : 
     155           0 :   codec.plType = decoder.payload_type;
     156           0 :   strncpy(codec.plName, decoder.payload_name.c_str(), sizeof(codec.plName));
     157           0 :   if (decoder.payload_name == "VP8") {
     158           0 :     codec.codecType = kVideoCodecVP8;
     159           0 :   } else if (decoder.payload_name == "VP9") {
     160           0 :     codec.codecType = kVideoCodecVP9;
     161           0 :   } else if (decoder.payload_name == "H264") {
     162           0 :     codec.codecType = kVideoCodecH264;
     163             :   } else {
     164           0 :     codec.codecType = kVideoCodecGeneric;
     165             :   }
     166             : 
     167           0 :   if (codec.codecType == kVideoCodecVP8) {
     168           0 :     *(codec.VP8()) = VideoEncoder::GetDefaultVp8Settings();
     169           0 :   } else if (codec.codecType == kVideoCodecVP9) {
     170           0 :     *(codec.VP9()) = VideoEncoder::GetDefaultVp9Settings();
     171           0 :   } else if (codec.codecType == kVideoCodecH264) {
     172           0 :     *(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
     173           0 :     codec.H264()->profile =
     174           0 :         H264::ParseSdpProfileLevelId(decoder.codec_params)->profile;
     175             :   }
     176             : 
     177           0 :   codec.width = 320;
     178           0 :   codec.height = 180;
     179           0 :   const int kDefaultStartBitrate = 300;
     180           0 :   codec.startBitrate = codec.minBitrate = codec.maxBitrate =
     181             :       kDefaultStartBitrate;
     182             : 
     183           0 :   return codec;
     184             : }
     185             : }  // namespace
     186             : 
     187             : namespace internal {
     188             : 
     189           0 : VideoReceiveStream::VideoReceiveStream(
     190             :     int num_cpu_cores,
     191             :     CongestionController* congestion_controller,
     192             :     PacketRouter* packet_router,
     193             :     VideoReceiveStream::Config config,
     194             :     webrtc::VoiceEngine* voice_engine,
     195             :     ProcessThread* process_thread,
     196             :     CallStats* call_stats,
     197           0 :     VieRemb* remb)
     198             :     : transport_adapter_(config.rtcp_send_transport),
     199           0 :       config_(std::move(config)),
     200             :       num_cpu_cores_(num_cpu_cores),
     201             :       process_thread_(process_thread),
     202           0 :       clock_(Clock::GetRealTimeClock()),
     203             :       decode_thread_(DecodeThreadFunction, this, "DecodingThread"),
     204             :       congestion_controller_(congestion_controller),
     205             :       call_stats_(call_stats),
     206           0 :       timing_(new VCMTiming(clock_)),
     207           0 :       video_receiver_(clock_, nullptr, this, timing_.get(), this, this),
     208           0 :       stats_proxy_(&config_, clock_),
     209             :       rtp_stream_receiver_(
     210             :           &video_receiver_,
     211           0 :           congestion_controller_->GetRemoteBitrateEstimator(
     212           0 :               UseSendSideBwe(config_)),
     213             :           &transport_adapter_,
     214           0 :           call_stats_->rtcp_rtt_stats(),
     215           0 :           congestion_controller_->pacer(),
     216             :           packet_router,
     217             :           remb,
     218             :           &config_,
     219             :           &stats_proxy_,
     220           0 :           process_thread_,
     221           0 :           congestion_controller_->GetRetransmissionRateLimiter(),
     222             :           this,  // NackSender
     223             :           this,  // KeyFrameRequestSender
     224             :           this,  // OnCompleteFrameCallback
     225             :           timing_.get()),
     226             :       rtp_stream_sync_(&video_receiver_, &rtp_stream_receiver_),
     227             :       jitter_buffer_experiment_(
     228           0 :           field_trial::FindFullName("WebRTC-NewVideoJitterBuffer") ==
     229           0 :           "Enabled") {
     230           0 :   LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
     231             : 
     232           0 :   RTC_DCHECK(process_thread_);
     233           0 :   RTC_DCHECK(congestion_controller_);
     234           0 :   RTC_DCHECK(call_stats_);
     235             : 
     236           0 :   RTC_DCHECK(!config_.decoders.empty());
     237           0 :   std::set<int> decoder_payload_types;
     238           0 :   for (const Decoder& decoder : config_.decoders) {
     239           0 :     RTC_CHECK(decoder.decoder);
     240           0 :     RTC_CHECK(decoder_payload_types.find(decoder.payload_type) ==
     241             :               decoder_payload_types.end())
     242           0 :         << "Duplicate payload type (" << decoder.payload_type
     243           0 :         << ") for different decoders.";
     244           0 :     decoder_payload_types.insert(decoder.payload_type);
     245             :   }
     246             : 
     247           0 :   video_receiver_.SetRenderDelay(config.render_delay_ms);
     248             : 
     249           0 :   if (jitter_buffer_experiment_) {
     250           0 :     jitter_estimator_.reset(new VCMJitterEstimator(clock_));
     251           0 :     frame_buffer_.reset(new video_coding::FrameBuffer(
     252           0 :         clock_, jitter_estimator_.get(), timing_.get()));
     253             :   }
     254             : 
     255           0 :   process_thread_->RegisterModule(&video_receiver_);
     256           0 :   process_thread_->RegisterModule(&rtp_stream_sync_);
     257           0 : }
     258             : 
     259           0 : VideoReceiveStream::~VideoReceiveStream() {
     260           0 :   LOG(LS_INFO) << "~VideoReceiveStream: " << config_.ToString();
     261           0 :   Stop();
     262             : 
     263           0 :   process_thread_->DeRegisterModule(&rtp_stream_sync_);
     264           0 :   process_thread_->DeRegisterModule(&video_receiver_);
     265             : 
     266           0 :   congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config_))
     267           0 :       ->RemoveStream(rtp_stream_receiver_.GetRemoteSsrc());
     268           0 : }
     269             : 
     270           0 : void VideoReceiveStream::SignalNetworkState(NetworkState state) {
     271           0 :   rtp_stream_receiver_.SignalNetworkState(state);
     272           0 : }
     273             : 
     274             : 
     275           0 : bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
     276           0 :   return rtp_stream_receiver_.DeliverRtcp(packet, length);
     277             : }
     278             : 
     279           0 : bool VideoReceiveStream::DeliverRtp(const uint8_t* packet,
     280             :                                     size_t length,
     281             :                                     const PacketTime& packet_time) {
     282           0 :   return rtp_stream_receiver_.DeliverRtp(packet, length, packet_time);
     283             : }
     284             : 
     285           0 : bool VideoReceiveStream::OnRecoveredPacket(const uint8_t* packet,
     286             :                                            size_t length) {
     287           0 :   return rtp_stream_receiver_.OnRecoveredPacket(packet, length);
     288             : }
     289             : 
     290           0 : void VideoReceiveStream::Start() {
     291           0 :   if (decode_thread_.IsRunning())
     292           0 :     return;
     293           0 :   video_receiver_.Reset();
     294           0 :   if (jitter_buffer_experiment_) {
     295           0 :     frame_buffer_->Start();
     296           0 :     call_stats_->RegisterStatsObserver(&rtp_stream_receiver_);
     297             : 
     298           0 :     if (rtp_stream_receiver_.IsRetransmissionsEnabled() &&
     299           0 :         rtp_stream_receiver_.IsUlpfecEnabled()) {
     300           0 :       frame_buffer_->SetProtectionMode(kProtectionNackFEC);
     301             :     }
     302             :   }
     303           0 :   transport_adapter_.Enable();
     304           0 :   rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
     305           0 :   if (config_.renderer) {
     306           0 :     if (config_.disable_prerenderer_smoothing) {
     307           0 :       renderer = this;
     308             :     } else {
     309           0 :       incoming_video_stream_.reset(
     310           0 :           new IncomingVideoStream(config_.render_delay_ms, this));
     311           0 :       renderer = incoming_video_stream_.get();
     312             :     }
     313             :   }
     314           0 :   RTC_DCHECK(renderer != nullptr);
     315             : 
     316           0 :   for (const Decoder& decoder : config_.decoders) {
     317           0 :     video_receiver_.RegisterExternalDecoder(decoder.decoder,
     318           0 :                                             decoder.payload_type);
     319             :     // TODO(johan): make Decoder.codec_params accessible for RtpStreamReceiver
     320             :     // which holds H264SpsPpsTracker
     321           0 :     VideoCodec codec = CreateDecoderVideoCodec(decoder);
     322           0 :     RTC_CHECK(rtp_stream_receiver_.AddReceiveCodec(codec));
     323           0 :     RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
     324           0 :                              &codec, num_cpu_cores_, false));
     325             :   }
     326             : 
     327           0 :   video_stream_decoder_.reset(new VideoStreamDecoder(
     328             :       &video_receiver_, &rtp_stream_receiver_, &rtp_stream_receiver_,
     329           0 :       rtp_stream_receiver_.IsRetransmissionsEnabled(),
     330           0 :       rtp_stream_receiver_.IsUlpfecEnabled(), &stats_proxy_, renderer,
     331           0 :       config_.pre_render_callback));
     332             :   // Register the channel to receive stats updates.
     333           0 :   call_stats_->RegisterStatsObserver(video_stream_decoder_.get());
     334             :   // Start the decode thread
     335           0 :   decode_thread_.Start();
     336           0 :   decode_thread_.SetPriority(rtc::kHighestPriority);
     337           0 :   rtp_stream_receiver_.StartReceive();
     338             : }
     339             : 
     340           0 : void VideoReceiveStream::Stop() {
     341           0 :   rtp_stream_receiver_.StopReceive();
     342             :   // TriggerDecoderShutdown will release any waiting decoder thread and make it
     343             :   // stop immediately, instead of waiting for a timeout. Needs to be called
     344             :   // before joining the decoder thread thread.
     345           0 :   video_receiver_.TriggerDecoderShutdown();
     346             : 
     347           0 :   if (jitter_buffer_experiment_) {
     348           0 :     frame_buffer_->Stop();
     349           0 :     call_stats_->DeregisterStatsObserver(&rtp_stream_receiver_);
     350             :   }
     351             : 
     352           0 :   if (decode_thread_.IsRunning()) {
     353           0 :     decode_thread_.Stop();
     354             :     // Deregister external decoders so they are no longer running during
     355             :     // destruction. This effectively stops the VCM since the decoder thread is
     356             :     // stopped, the VCM is deregistered and no asynchronous decoder threads are
     357             :     // running.
     358           0 :     for (const Decoder& decoder : config_.decoders)
     359           0 :       video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
     360             :   }
     361             : 
     362           0 :   call_stats_->DeregisterStatsObserver(video_stream_decoder_.get());
     363           0 :   video_stream_decoder_.reset();
     364           0 :   incoming_video_stream_.reset();
     365           0 :   transport_adapter_.Disable();
     366           0 : }
     367             : 
     368           0 : void VideoReceiveStream::SetSyncChannel(VoiceEngine* voice_engine,
     369             :                                         int audio_channel_id) {
     370           0 :   if (voice_engine && audio_channel_id != -1) {
     371           0 :     VoEVideoSync* voe_sync_interface = VoEVideoSync::GetInterface(voice_engine);
     372           0 :     rtp_stream_sync_.ConfigureSync(audio_channel_id, voe_sync_interface);
     373           0 :     voe_sync_interface->Release();
     374             :   } else {
     375           0 :     rtp_stream_sync_.ConfigureSync(-1, nullptr);
     376             :   }
     377           0 : }
     378             : 
     379           0 : VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
     380           0 :   return stats_proxy_.GetStats();
     381             : }
     382             : 
     383             : // TODO(tommi): This method grabs a lock 6 times.
     384           0 : void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
     385             :   // TODO(tommi): OnDecodedFrame grabs a lock, incidentally the same lock
     386             :   // that OnSyncOffsetUpdated() and OnRenderedFrame() below grab.
     387           0 :   stats_proxy_.OnDecodedFrame();
     388             : 
     389             :   int64_t sync_offset_ms;
     390             :   double estimated_freq_khz;
     391             :   // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks.  One inside the
     392             :   // function itself, another in GetChannel() and a third in
     393             :   // GetPlayoutTimestamp.  Seems excessive.  Anyhow, I'm assuming the function
     394             :   // succeeds most of the time, which leads to grabbing a fourth lock.
     395           0 :   if (rtp_stream_sync_.GetStreamSyncOffsetInMs(video_frame, &sync_offset_ms,
     396             :                                                &estimated_freq_khz)) {
     397             :     // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
     398           0 :     stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms, estimated_freq_khz);
     399             :   }
     400             : 
     401             :   // config_.renderer must never be null if we're getting this callback.
     402           0 :   config_.renderer->OnFrame(video_frame);
     403             : 
     404             :   // TODO(tommi): OnRenderFrame grabs a lock too.
     405           0 :   stats_proxy_.OnRenderedFrame(video_frame);
     406           0 : }
     407             : 
     408           0 : void VideoReceiveStream::OnCompleteFrame(
     409             :     std::unique_ptr<video_coding::FrameObject> frame) {
     410           0 :   int last_continuous_pid = frame_buffer_->InsertFrame(std::move(frame));
     411           0 :   if (last_continuous_pid != -1)
     412           0 :     rtp_stream_receiver_.FrameContinuous(last_continuous_pid);
     413           0 : }
     414             : 
     415             : // TODO(asapersson): Consider moving callback from video_encoder.h or
     416             : // creating a different callback.
     417           0 : EncodedImageCallback::Result VideoReceiveStream::OnEncodedImage(
     418             :     const EncodedImage& encoded_image,
     419             :     const CodecSpecificInfo* codec_specific_info,
     420             :     const RTPFragmentationHeader* fragmentation) {
     421           0 :   stats_proxy_.OnPreDecode(encoded_image, codec_specific_info);
     422           0 :   if (config_.pre_decode_callback) {
     423           0 :     config_.pre_decode_callback->EncodedFrameCallback(
     424           0 :         EncodedFrame(encoded_image._buffer, encoded_image._length,
     425           0 :                      encoded_image._frameType));
     426             :   }
     427             :   {
     428           0 :     rtc::CritScope lock(&ivf_writer_lock_);
     429           0 :     if (ivf_writer_.get()) {
     430           0 :       RTC_DCHECK(codec_specific_info);
     431           0 :       bool ok = ivf_writer_->WriteFrame(encoded_image,
     432           0 :                                         codec_specific_info->codecType);
     433           0 :       RTC_DCHECK(ok);
     434             :     }
     435             :   }
     436             : 
     437           0 :   return Result(Result::OK, encoded_image._timeStamp);
     438             : }
     439             : 
     440           0 : bool VideoReceiveStream::DecodeThreadFunction(void* ptr) {
     441           0 :   static_cast<VideoReceiveStream*>(ptr)->Decode();
     442           0 :   return true;
     443             : }
     444             : 
     445           0 : void VideoReceiveStream::Decode() {
     446             :   static const int kMaxDecodeWaitTimeMs = 50;
     447           0 :   if (jitter_buffer_experiment_) {
     448             :     static const int kMaxWaitForFrameMs = 3000;
     449           0 :     std::unique_ptr<video_coding::FrameObject> frame;
     450             :     video_coding::FrameBuffer::ReturnReason res =
     451           0 :         frame_buffer_->NextFrame(kMaxWaitForFrameMs, &frame);
     452             : 
     453           0 :     if (res == video_coding::FrameBuffer::ReturnReason::kStopped)
     454           0 :       return;
     455             : 
     456           0 :     if (frame) {
     457           0 :       if (video_receiver_.Decode(frame.get()) == VCM_OK)
     458           0 :         rtp_stream_receiver_.FrameDecoded(frame->picture_id);
     459             :     } else {
     460           0 :       LOG(LS_WARNING) << "No decodable frame in " << kMaxWaitForFrameMs
     461           0 :                       << " ms, requesting keyframe.";
     462           0 :       RequestKeyFrame();
     463             :     }
     464             :   } else {
     465           0 :     video_receiver_.Decode(kMaxDecodeWaitTimeMs);
     466             :   }
     467             : }
     468             : 
     469           0 : void VideoReceiveStream::SendNack(
     470             :     const std::vector<uint16_t>& sequence_numbers) {
     471           0 :   rtp_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
     472           0 : }
     473             : 
     474           0 : void VideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file,
     475             :                                                      size_t byte_limit) {
     476             :   {
     477           0 :     rtc::CritScope lock(&ivf_writer_lock_);
     478           0 :     if (file == rtc::kInvalidPlatformFileValue) {
     479           0 :       ivf_writer_.reset();
     480             :     } else {
     481           0 :       ivf_writer_ = IvfFileWriter::Wrap(rtc::File(file), byte_limit);
     482             :     }
     483             :   }
     484             : 
     485           0 :   if (file != rtc::kInvalidPlatformFileValue) {
     486             :     // Make a keyframe appear as early as possible in the logs, to give actually
     487             :     // decodable output.
     488           0 :     RequestKeyFrame();
     489             :   }
     490           0 : }
     491             : 
     492           0 : void VideoReceiveStream::RequestKeyFrame() {
     493           0 :   rtp_stream_receiver_.RequestKeyFrame();
     494           0 : }
     495             : 
     496             : bool
     497           0 : VideoReceiveStream::GetRemoteRTCPSenderInfo(RTCPSenderInfo* sender_info) const {
     498           0 :   return -1 != rtp_stream_receiver_.rtp_rtcp()->RemoteRTCPStat(sender_info);
     499             : }
     500             : 
     501             : }  // namespace internal
     502             : }  // namespace webrtc

Generated by: LCOV version 1.13