LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/video_coding - video_sender.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 193 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 18 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             : 
      12             : #include <algorithm>  // std::max
      13             : 
      14             : #include "webrtc/base/checks.h"
      15             : #include "webrtc/base/logging.h"
      16             : #include "webrtc/common_types.h"
      17             : #include "webrtc/common_video/include/video_bitrate_allocator.h"
      18             : #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
      19             : #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
      20             : #include "webrtc/modules/video_coding/include/video_codec_interface.h"
      21             : #include "webrtc/modules/video_coding/encoded_frame.h"
      22             : #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
      23             : #include "webrtc/modules/video_coding/utility/quality_scaler.h"
      24             : #include "webrtc/modules/video_coding/video_coding_impl.h"
      25             : #include "webrtc/system_wrappers/include/clock.h"
      26             : 
      27             : namespace webrtc {
      28             : namespace vcm {
      29             : 
      30           0 : VideoSender::VideoSender(Clock* clock,
      31             :                          EncodedImageCallback* post_encode_callback,
      32           0 :                          VCMSendStatisticsCallback* send_stats_callback)
      33             :     : clock_(clock),
      34             :       _encoder(nullptr),
      35           0 :       _mediaOpt(clock_),
      36             :       _encodedFrameCallback(post_encode_callback, &_mediaOpt),
      37             :       post_encode_callback_(post_encode_callback),
      38             :       send_stats_callback_(send_stats_callback),
      39             :       _codecDataBase(&_encodedFrameCallback),
      40             :       frame_dropper_enabled_(true),
      41           0 :       _sendStatsTimer(VCMProcessTimer::kDefaultProcessIntervalMs, clock_),
      42             :       current_codec_(),
      43             :       encoder_params_({BitrateAllocation(), 0, 0, 0}),
      44             :       encoder_has_internal_source_(false),
      45           0 :       next_frame_types_(1, kVideoFrameDelta) {
      46           0 :   _mediaOpt.Reset();
      47             :   // Allow VideoSender to be created on one thread but used on another, post
      48             :   // construction. This is currently how this class is being used by at least
      49             :   // one external project (diffractor).
      50           0 :   sequenced_checker_.Detach();
      51           0 : }
      52             : 
      53           0 : VideoSender::~VideoSender() {}
      54             : 
      55           0 : void VideoSender::Process() {
      56           0 :   if (_sendStatsTimer.TimeUntilProcess() == 0) {
      57             :     // |_sendStatsTimer.Processed()| must be called. Otherwise
      58             :     // VideoSender::Process() will be called in an infinite loop.
      59           0 :     _sendStatsTimer.Processed();
      60           0 :     if (send_stats_callback_) {
      61           0 :       uint32_t bitRate = _mediaOpt.SentBitRate();
      62           0 :       uint32_t frameRate = _mediaOpt.SentFrameRate();
      63           0 :       send_stats_callback_->SendStatistics(bitRate, frameRate);
      64             :     }
      65             :   }
      66           0 : }
      67             : 
      68           0 : int64_t VideoSender::TimeUntilNextProcess() {
      69           0 :   return _sendStatsTimer.TimeUntilProcess();
      70             : }
      71             : 
      72             : // Register the send codec to be used.
      73           0 : int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
      74             :                                        uint32_t numberOfCores,
      75             :                                        uint32_t maxPayloadSize) {
      76           0 :   RTC_DCHECK(sequenced_checker_.CalledSequentially());
      77           0 :   rtc::CritScope lock(&encoder_crit_);
      78           0 :   if (sendCodec == nullptr) {
      79           0 :     return VCM_PARAMETER_ERROR;
      80             :   }
      81             : 
      82             :   bool ret =
      83           0 :       _codecDataBase.SetSendCodec(sendCodec, numberOfCores, maxPayloadSize);
      84             : 
      85             :   // Update encoder regardless of result to make sure that we're not holding on
      86             :   // to a deleted instance.
      87           0 :   _encoder = _codecDataBase.GetEncoder();
      88             :   // Cache the current codec here so they can be fetched from this thread
      89             :   // without requiring the _sendCritSect lock.
      90           0 :   current_codec_ = *sendCodec;
      91             : 
      92           0 :   if (!ret) {
      93           0 :     LOG(LS_ERROR) << "Failed to initialize set encoder with payload name '"
      94           0 :                   << sendCodec->plName << "'.";
      95           0 :     return VCM_CODEC_ERROR;
      96             :   }
      97             : 
      98             :   // SetSendCodec succeeded, _encoder should be set.
      99           0 :   RTC_DCHECK(_encoder);
     100             : 
     101             :   int numLayers;
     102           0 :   if (sendCodec->codecType == kVideoCodecVP8) {
     103           0 :     numLayers = sendCodec->VP8().numberOfTemporalLayers;
     104           0 :   } else if (sendCodec->codecType == kVideoCodecVP9) {
     105           0 :     numLayers = sendCodec->VP9().numberOfTemporalLayers;
     106             :   } else {
     107           0 :     numLayers = 1;
     108             :   }
     109             : 
     110             :   // If we have screensharing and we have layers, we disable frame dropper.
     111             :   bool disable_frame_dropper =
     112           0 :       numLayers > 1 && sendCodec->mode == kScreensharing;
     113           0 :   if (disable_frame_dropper) {
     114           0 :     _mediaOpt.EnableFrameDropper(false);
     115           0 :   } else if (frame_dropper_enabled_) {
     116           0 :     _mediaOpt.EnableFrameDropper(true);
     117             :   }
     118             : 
     119             :   {
     120           0 :     rtc::CritScope cs(&params_crit_);
     121           0 :     next_frame_types_.clear();
     122           0 :     next_frame_types_.resize(VCM_MAX(sendCodec->numberOfSimulcastStreams, 1),
     123           0 :                              kVideoFrameKey);
     124             :     // Cache InternalSource() to have this available from IntraFrameRequest()
     125             :     // without having to acquire encoder_crit_ (avoid blocking on encoder use).
     126           0 :     encoder_has_internal_source_ = _encoder->InternalSource();
     127             :   }
     128             : 
     129           0 :   LOG(LS_VERBOSE) << " max bitrate " << sendCodec->maxBitrate
     130           0 :                   << " start bitrate " << sendCodec->startBitrate
     131           0 :                   << " max frame rate " << sendCodec->maxFramerate
     132           0 :                   << " max payload size " << maxPayloadSize;
     133           0 :   _mediaOpt.SetEncodingData(sendCodec->maxBitrate * 1000,
     134           0 :                             sendCodec->startBitrate * 1000, sendCodec->width,
     135           0 :                             sendCodec->height, sendCodec->maxFramerate * 1000,
     136           0 :                             sendCodec->resolution_divisor,
     137           0 :                             numLayers, maxPayloadSize);
     138           0 :   return VCM_OK;
     139             : }
     140             : 
     141             : // Register an external decoder object.
     142             : // This can not be used together with external decoder callbacks.
     143           0 : void VideoSender::RegisterExternalEncoder(VideoEncoder* externalEncoder,
     144             :                                           uint8_t payloadType,
     145             :                                           bool internalSource /*= false*/) {
     146           0 :   RTC_DCHECK(sequenced_checker_.CalledSequentially());
     147             : 
     148           0 :   rtc::CritScope lock(&encoder_crit_);
     149             : 
     150           0 :   if (externalEncoder == nullptr) {
     151           0 :     bool wasSendCodec = false;
     152           0 :     RTC_CHECK(
     153           0 :         _codecDataBase.DeregisterExternalEncoder(payloadType, &wasSendCodec));
     154           0 :     if (wasSendCodec) {
     155             :       // Make sure the VCM doesn't use the de-registered codec
     156           0 :       rtc::CritScope params_lock(&params_crit_);
     157           0 :       _encoder = nullptr;
     158           0 :       encoder_has_internal_source_ = false;
     159             :     }
     160           0 :     return;
     161             :   }
     162           0 :   _codecDataBase.RegisterExternalEncoder(externalEncoder, payloadType,
     163           0 :                                          internalSource);
     164             : }
     165             : 
     166             : // Get encode bitrate
     167           0 : int VideoSender::Bitrate(unsigned int* bitrate) const {
     168           0 :   RTC_DCHECK(sequenced_checker_.CalledSequentially());
     169             :   // Since we're running on the thread that's the only thread known to modify
     170             :   // the value of _encoder, we don't need to grab the lock here.
     171             : 
     172           0 :   if (!_encoder)
     173           0 :     return VCM_UNINITIALIZED;
     174           0 :   *bitrate = _encoder->GetEncoderParameters().target_bitrate.get_sum_bps();
     175           0 :   return 0;
     176             : }
     177             : 
     178             : // Get encode frame rate
     179           0 : int VideoSender::FrameRate(unsigned int* framerate) const {
     180           0 :   RTC_DCHECK(sequenced_checker_.CalledSequentially());
     181             :   // Since we're running on the thread that's the only thread known to modify
     182             :   // the value of _encoder, we don't need to grab the lock here.
     183             : 
     184           0 :   if (!_encoder)
     185           0 :     return VCM_UNINITIALIZED;
     186             : 
     187           0 :   *framerate = _encoder->GetEncoderParameters().input_frame_rate;
     188           0 :   return 0;
     189             : }
     190             : 
     191           0 : EncoderParameters VideoSender::UpdateEncoderParameters(
     192             :     const EncoderParameters& params,
     193             :     VideoBitrateAllocator* bitrate_allocator,
     194             :     uint32_t target_bitrate_bps) {
     195           0 :   uint32_t video_target_rate_bps = _mediaOpt.SetTargetRates(target_bitrate_bps);
     196           0 :   uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
     197           0 :   if (input_frame_rate == 0)
     198           0 :     input_frame_rate = current_codec_.maxFramerate;
     199             : 
     200           0 :   BitrateAllocation bitrate_allocation;
     201           0 :   if (bitrate_allocator) {
     202             :     bitrate_allocation = bitrate_allocator->GetAllocation(video_target_rate_bps,
     203           0 :                                                           input_frame_rate);
     204             :   } else {
     205           0 :     DefaultVideoBitrateAllocator default_allocator(current_codec_);
     206             :     bitrate_allocation = default_allocator.GetAllocation(video_target_rate_bps,
     207           0 :                                                          input_frame_rate);
     208             :   }
     209           0 :   EncoderParameters new_encoder_params = {bitrate_allocation, params.loss_rate,
     210           0 :                                           params.rtt, input_frame_rate};
     211           0 :   return new_encoder_params;
     212             : }
     213             : 
     214           0 : void VideoSender::UpdateChannelParemeters(
     215             :     VideoBitrateAllocator* bitrate_allocator,
     216             :     VideoBitrateAllocationObserver* bitrate_updated_callback) {
     217           0 :   BitrateAllocation target_rate;
     218             :   {
     219           0 :     rtc::CritScope cs(&params_crit_);
     220             :     encoder_params_ =
     221           0 :         UpdateEncoderParameters(encoder_params_, bitrate_allocator,
     222           0 :                                 encoder_params_.target_bitrate.get_sum_bps());
     223           0 :     target_rate = encoder_params_.target_bitrate;
     224             :   }
     225           0 :   if (bitrate_updated_callback)
     226           0 :     bitrate_updated_callback->OnBitrateAllocationUpdated(target_rate);
     227           0 : }
     228             : 
     229           0 : int32_t VideoSender::SetChannelParameters(
     230             :     uint32_t target_bitrate_bps,
     231             :     uint8_t loss_rate,
     232             :     int64_t rtt,
     233             :     VideoBitrateAllocator* bitrate_allocator,
     234             :     VideoBitrateAllocationObserver* bitrate_updated_callback) {
     235           0 :   EncoderParameters encoder_params;
     236           0 :   encoder_params.loss_rate = loss_rate;
     237           0 :   encoder_params.rtt = rtt;
     238           0 :   encoder_params = UpdateEncoderParameters(encoder_params, bitrate_allocator,
     239           0 :                                            target_bitrate_bps);
     240           0 :   if (bitrate_updated_callback) {
     241             :     bitrate_updated_callback->OnBitrateAllocationUpdated(
     242           0 :         encoder_params.target_bitrate);
     243             :   }
     244             : 
     245             :   bool encoder_has_internal_source;
     246             :   {
     247           0 :     rtc::CritScope cs(&params_crit_);
     248           0 :     encoder_params_ = encoder_params;
     249           0 :     encoder_has_internal_source = encoder_has_internal_source_;
     250             :   }
     251             : 
     252             :   // For encoders with internal sources, we need to tell the encoder directly,
     253             :   // instead of waiting for an AddVideoFrame that will never come (internal
     254             :   // source encoders don't get input frames).
     255           0 :   if (encoder_has_internal_source) {
     256           0 :     rtc::CritScope cs(&encoder_crit_);
     257           0 :     if (_encoder) {
     258           0 :       SetEncoderParameters(encoder_params, encoder_has_internal_source);
     259             :     }
     260             :   }
     261             : 
     262           0 :   return VCM_OK;
     263             : }
     264             : 
     265           0 : void VideoSender::SetEncoderParameters(EncoderParameters params,
     266             :                                        bool has_internal_source) {
     267             :   // |target_bitrate == 0 | means that the network is down or the send pacer is
     268             :   // full. We currently only report this if the encoder has an internal source.
     269             :   // If the encoder does not have an internal source, higher levels are expected
     270             :   // to not call AddVideoFrame. We do this since its unclear how current
     271             :   // encoder implementations behave when given a zero target bitrate.
     272             :   // TODO(perkj): Make sure all known encoder implementations handle zero
     273             :   // target bitrate and remove this check.
     274           0 :   if (!has_internal_source && params.target_bitrate.get_sum_bps() == 0)
     275           0 :     return;
     276             : 
     277           0 :   if (params.input_frame_rate == 0) {
     278             :     // No frame rate estimate available, use default.
     279           0 :     params.input_frame_rate = current_codec_.maxFramerate;
     280             :   }
     281           0 :   if (_encoder != nullptr)
     282           0 :     _encoder->SetEncoderParameters(params);
     283             : }
     284             : 
     285             : // Deprecated:
     286             : // TODO(perkj): Remove once no projects call this method. It currently do
     287             : // nothing.
     288           0 : int32_t VideoSender::RegisterProtectionCallback(
     289             :     VCMProtectionCallback* protection_callback) {
     290             :   // Deprecated:
     291             :   // TODO(perkj): Remove once no projects call this method. It currently do
     292             :   // nothing.
     293           0 :   return VCM_OK;
     294             : }
     295             : 
     296             : // Add one raw video frame to the encoder, blocking.
     297           0 : int32_t VideoSender::AddVideoFrame(const VideoFrame& videoFrame,
     298             :                                    const CodecSpecificInfo* codecSpecificInfo) {
     299           0 :   EncoderParameters encoder_params;
     300           0 :   std::vector<FrameType> next_frame_types;
     301           0 :   bool encoder_has_internal_source = false;
     302             :   {
     303           0 :     rtc::CritScope lock(&params_crit_);
     304           0 :     encoder_params = encoder_params_;
     305           0 :     next_frame_types = next_frame_types_;
     306           0 :     encoder_has_internal_source = encoder_has_internal_source_;
     307             :   }
     308           0 :   rtc::CritScope lock(&encoder_crit_);
     309           0 :   if (_encoder == nullptr)
     310           0 :     return VCM_UNINITIALIZED;
     311           0 :   SetEncoderParameters(encoder_params, encoder_has_internal_source);
     312           0 :   if (_mediaOpt.DropFrame()) {
     313           0 :     LOG(LS_VERBOSE) << "Drop Frame "
     314           0 :                     << "target bitrate "
     315           0 :                     << encoder_params.target_bitrate.get_sum_bps()
     316           0 :                     << " loss rate " << encoder_params.loss_rate << " rtt "
     317           0 :                     << encoder_params.rtt << " input frame rate "
     318           0 :                     << encoder_params.input_frame_rate;
     319           0 :     post_encode_callback_->OnDroppedFrame();
     320           0 :     return VCM_OK;
     321             :   }
     322             :   // TODO(pbos): Make sure setting send codec is synchronized with video
     323             :   // processing so frame size always matches.
     324             : #ifdef VERIFY_FRAME_SIZE_VS_DATABASE
     325             :   if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(),
     326             :                                                videoFrame.height())) {
     327             :     LOG(LS_ERROR) << "Incoming frame doesn't match set resolution. Dropping.";
     328             :     return VCM_PARAMETER_ERROR;
     329             :   }
     330             : #endif
     331           0 :   VideoFrame converted_frame = videoFrame;
     332           0 :   if (converted_frame.video_frame_buffer()->native_handle() &&
     333           0 :       !_encoder->SupportsNativeHandle()) {
     334             :     // This module only supports software encoding.
     335             :     // TODO(pbos): Offload conversion from the encoder thread.
     336             :     rtc::scoped_refptr<VideoFrameBuffer> converted_buffer(
     337           0 :         converted_frame.video_frame_buffer()->NativeToI420Buffer());
     338             : 
     339           0 :     if (!converted_buffer) {
     340           0 :       LOG(LS_ERROR) << "Frame conversion failed, dropping frame.";
     341           0 :       return VCM_PARAMETER_ERROR;
     342             :     }
     343           0 :     converted_frame = VideoFrame(converted_buffer,
     344             :                                  converted_frame.timestamp(),
     345             :                                  converted_frame.render_time_ms(),
     346           0 :                                  converted_frame.rotation());
     347             :   }
     348             :   int32_t ret =
     349           0 :       _encoder->Encode(converted_frame, codecSpecificInfo, next_frame_types);
     350           0 :   if (ret < 0) {
     351           0 :     LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret;
     352           0 :     return ret;
     353             :   }
     354             : 
     355             :   {
     356           0 :     rtc::CritScope lock(&params_crit_);
     357             :     // Change all keyframe requests to encode delta frames the next time.
     358           0 :     for (size_t i = 0; i < next_frame_types_.size(); ++i) {
     359             :       // Check for equality (same requested as before encoding) to not
     360             :       // accidentally drop a keyframe request while encoding.
     361           0 :       if (next_frame_types[i] == next_frame_types_[i])
     362           0 :         next_frame_types_[i] = kVideoFrameDelta;
     363             :     }
     364             :   }
     365           0 :   return VCM_OK;
     366             : }
     367             : 
     368           0 : int32_t VideoSender::IntraFrameRequest(size_t stream_index) {
     369             :   {
     370           0 :     rtc::CritScope lock(&params_crit_);
     371           0 :     if (stream_index >= next_frame_types_.size()) {
     372           0 :       return -1;
     373             :     }
     374           0 :     next_frame_types_[stream_index] = kVideoFrameKey;
     375           0 :     if (!encoder_has_internal_source_)
     376           0 :       return VCM_OK;
     377             :   }
     378             :   // TODO(pbos): Remove when InternalSource() is gone. Both locks have to be
     379             :   // held here for internal consistency, since _encoder could be removed while
     380             :   // not holding encoder_crit_. Checks have to be performed again since
     381             :   // params_crit_ was dropped to not cause lock-order inversions with
     382             :   // encoder_crit_.
     383           0 :   rtc::CritScope lock(&encoder_crit_);
     384           0 :   rtc::CritScope params_lock(&params_crit_);
     385           0 :   if (stream_index >= next_frame_types_.size())
     386           0 :     return -1;
     387           0 :   if (_encoder != nullptr && _encoder->InternalSource()) {
     388             :     // Try to request the frame if we have an external encoder with
     389             :     // internal source since AddVideoFrame never will be called.
     390           0 :     if (_encoder->RequestFrame(next_frame_types_) == WEBRTC_VIDEO_CODEC_OK) {
     391             :       // Try to remove just-performed keyframe request, if stream still exists.
     392           0 :       next_frame_types_[stream_index] = kVideoFrameDelta;
     393             :     }
     394             :   }
     395           0 :   return VCM_OK;
     396             : }
     397             : 
     398           0 : int32_t VideoSender::EnableFrameDropper(bool enable) {
     399           0 :   rtc::CritScope lock(&encoder_crit_);
     400           0 :   frame_dropper_enabled_ = enable;
     401           0 :   _mediaOpt.EnableFrameDropper(enable);
     402           0 :   return VCM_OK;
     403             : }
     404             : 
     405           0 : void VideoSender::SetCPULoadState(CPULoadState state) {
     406           0 :   rtc::CritScope lock(&encoder_crit_);
     407           0 :   _mediaOpt.SetCPULoadState(state);
     408           0 : }
     409             : 
     410             : }  // namespace vcm
     411             : }  // namespace webrtc

Generated by: LCOV version 1.13