LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8 - vp8_impl.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 697 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 37 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 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/modules/video_coding/codecs/vp8/vp8_impl.h"
      12             : 
      13             : #include <stdlib.h>
      14             : #include <string.h>
      15             : #include <time.h>
      16             : #include <algorithm>
      17             : 
      18             : // NOTE(ajm): Path provided by gyp.
      19             : #include "libyuv/scale.h"    // NOLINT
      20             : #include "libyuv/convert.h"  // NOLINT
      21             : 
      22             : #include "webrtc/base/checks.h"
      23             : #include "webrtc/base/timeutils.h"
      24             : #include "webrtc/base/trace_event.h"
      25             : #include "webrtc/common_types.h"
      26             : #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
      27             : #include "webrtc/modules/include/module_common_types.h"
      28             : #include "webrtc/modules/video_coding/include/video_codec_interface.h"
      29             : #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
      30             : #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
      31             : #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
      32             : #include "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h"
      33             : #include "webrtc/system_wrappers/include/clock.h"
      34             : #include "webrtc/system_wrappers/include/metrics.h"
      35             : 
      36             : namespace webrtc {
      37             : namespace {
      38             : 
      39             : enum { kVp8ErrorPropagationTh = 30 };
      40             : enum { kVp832ByteAlign = 32 };
      41             : 
      42             : // VP8 denoiser states.
      43             : enum denoiserState {
      44             :   kDenoiserOff,
      45             :   kDenoiserOnYOnly,
      46             :   kDenoiserOnYUV,
      47             :   kDenoiserOnYUVAggressive,
      48             :   // Adaptive mode defaults to kDenoiserOnYUV on key frame, but may switch
      49             :   // to kDenoiserOnYUVAggressive based on a computed noise metric.
      50             :   kDenoiserOnAdaptive
      51             : };
      52             : 
      53             : // Greatest common divisior
      54           0 : int GCD(int a, int b) {
      55           0 :   int c = a % b;
      56           0 :   while (c != 0) {
      57           0 :     a = b;
      58           0 :     b = c;
      59           0 :     c = a % b;
      60             :   }
      61           0 :   return b;
      62             : }
      63             : 
      64           0 : uint32_t SumStreamMaxBitrate(int streams, const VideoCodec& codec) {
      65           0 :   uint32_t bitrate_sum = 0;
      66           0 :   for (int i = 0; i < streams; ++i) {
      67           0 :     bitrate_sum += codec.simulcastStream[i].maxBitrate;
      68             :   }
      69           0 :   return bitrate_sum;
      70             : }
      71             : 
      72           0 : int NumberOfStreams(const VideoCodec& codec) {
      73             :   int streams =
      74           0 :       codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
      75           0 :   uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
      76           0 :   if (simulcast_max_bitrate == 0) {
      77           0 :     streams = 1;
      78             :   }
      79           0 :   return streams;
      80             : }
      81             : 
      82           0 : bool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) {
      83           0 :   if (codec.width != codec.simulcastStream[num_streams - 1].width ||
      84           0 :       codec.height != codec.simulcastStream[num_streams - 1].height) {
      85           0 :     return false;
      86             :   }
      87           0 :   for (int i = 0; i < num_streams; ++i) {
      88           0 :     if (codec.width * codec.simulcastStream[i].height !=
      89           0 :         codec.height * codec.simulcastStream[i].width) {
      90           0 :       return false;
      91             :     }
      92             :   }
      93           0 :   return true;
      94             : }
      95             : 
      96           0 : int NumStreamsDisabled(const std::vector<bool>& streams) {
      97           0 :   int num_disabled = 0;
      98           0 :   for (bool stream : streams) {
      99           0 :     if (!stream)
     100           0 :       ++num_disabled;
     101             :   }
     102           0 :   return num_disabled;
     103             : }
     104             : }  // namespace
     105             : 
     106           0 : VP8Encoder* VP8Encoder::Create() {
     107           0 :   return new VP8EncoderImpl();
     108             : }
     109             : 
     110           0 : VP8Decoder* VP8Decoder::Create() {
     111           0 :   return new VP8DecoderImpl();
     112             : }
     113             : 
     114           0 : VP8EncoderImpl::VP8EncoderImpl()
     115             :     : encoded_complete_callback_(nullptr),
     116             :       inited_(false),
     117             :       timestamp_(0),
     118             :       feedback_mode_(false),
     119             :       qp_max_(56),  // Setting for max quantizer.
     120             :       cpu_speed_default_(-6),
     121             :       number_of_cores_(0),
     122             :       rc_max_intra_target_(0),
     123             :       token_partitions_(VP8_ONE_TOKENPARTITION),
     124             :       down_scale_requested_(false),
     125             :       down_scale_bitrate_(0),
     126           0 :       key_frame_request_(kMaxSimulcastStreams, false) {
     127           0 :   uint32_t seed = rtc::Time32();
     128           0 :   srand(seed);
     129             : 
     130           0 :   picture_id_.reserve(kMaxSimulcastStreams);
     131           0 :   last_key_frame_picture_id_.reserve(kMaxSimulcastStreams);
     132           0 :   temporal_layers_.reserve(kMaxSimulcastStreams);
     133           0 :   raw_images_.reserve(kMaxSimulcastStreams);
     134           0 :   encoded_images_.reserve(kMaxSimulcastStreams);
     135           0 :   send_stream_.reserve(kMaxSimulcastStreams);
     136           0 :   cpu_speed_.assign(kMaxSimulcastStreams, -6);  // Set default to -6.
     137           0 :   encoders_.reserve(kMaxSimulcastStreams);
     138           0 :   configurations_.reserve(kMaxSimulcastStreams);
     139           0 :   downsampling_factors_.reserve(kMaxSimulcastStreams);
     140           0 : }
     141             : 
     142           0 : VP8EncoderImpl::~VP8EncoderImpl() {
     143           0 :   Release();
     144           0 : }
     145             : 
     146           0 : int VP8EncoderImpl::Release() {
     147           0 :   int ret_val = WEBRTC_VIDEO_CODEC_OK;
     148             : 
     149           0 :   while (!encoded_images_.empty()) {
     150           0 :     EncodedImage& image = encoded_images_.back();
     151           0 :     delete[] image._buffer;
     152           0 :     encoded_images_.pop_back();
     153             :   }
     154           0 :   while (!encoders_.empty()) {
     155           0 :     vpx_codec_ctx_t& encoder = encoders_.back();
     156           0 :     if (vpx_codec_destroy(&encoder)) {
     157           0 :       ret_val = WEBRTC_VIDEO_CODEC_MEMORY;
     158             :     }
     159           0 :     encoders_.pop_back();
     160             :   }
     161           0 :   configurations_.clear();
     162           0 :   send_stream_.clear();
     163           0 :   cpu_speed_.clear();
     164           0 :   while (!raw_images_.empty()) {
     165           0 :     vpx_img_free(&raw_images_.back());
     166           0 :     raw_images_.pop_back();
     167             :   }
     168           0 :   while (!temporal_layers_.empty()) {
     169           0 :     delete temporal_layers_.back();
     170           0 :     temporal_layers_.pop_back();
     171             :   }
     172           0 :   inited_ = false;
     173           0 :   return ret_val;
     174             : }
     175             : 
     176           0 : int VP8EncoderImpl::SetRateAllocation(const BitrateAllocation& bitrate,
     177             :                                       uint32_t new_framerate) {
     178           0 :   if (!inited_)
     179           0 :     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
     180             : 
     181           0 :   if (encoders_[0].err)
     182           0 :     return WEBRTC_VIDEO_CODEC_ERROR;
     183             : 
     184           0 :   if (new_framerate < 1)
     185           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     186             : 
     187           0 :   if (bitrate.get_sum_bps() == 0) {
     188             :     // Encoder paused, turn off all encoding.
     189           0 :     const int num_streams = static_cast<size_t>(encoders_.size());
     190           0 :     for (int i = 0; i < num_streams; ++i)
     191           0 :       SetStreamState(false, i);
     192           0 :     return WEBRTC_VIDEO_CODEC_OK;
     193             :   }
     194             : 
     195             :   // At this point, bitrate allocation should already match codec settings.
     196           0 :   if (codec_.maxBitrate > 0)
     197           0 :     RTC_DCHECK_LE(bitrate.get_sum_kbps(), codec_.maxBitrate);
     198           0 :   RTC_DCHECK_GE(bitrate.get_sum_kbps(), codec_.minBitrate);
     199           0 :   if (codec_.numberOfSimulcastStreams > 0)
     200           0 :     RTC_DCHECK_GE(bitrate.get_sum_kbps(), codec_.simulcastStream[0].minBitrate);
     201             : 
     202           0 :   codec_.maxFramerate = new_framerate;
     203             : 
     204           0 :   if (encoders_.size() == 1) {
     205             :     // 1:1.
     206             :     // Calculate a rough limit for when to trigger a potental down scale.
     207           0 :     uint32_t k_pixels_per_frame = codec_.width * codec_.height / 1000;
     208             :     // TODO(pwestin): we currently lack CAMA, this is a temporary fix to work
     209             :     // around the current limitations.
     210             :     // Only trigger keyframes if we are allowed to scale down.
     211           0 :     if (configurations_[0].rc_resize_allowed) {
     212           0 :       if (!down_scale_requested_) {
     213           0 :         if (k_pixels_per_frame > bitrate.get_sum_kbps()) {
     214           0 :           down_scale_requested_ = true;
     215           0 :           down_scale_bitrate_ = bitrate.get_sum_kbps();
     216           0 :           key_frame_request_[0] = true;
     217             :         }
     218             :       } else {
     219           0 :         if (bitrate.get_sum_kbps() > (2 * down_scale_bitrate_) ||
     220           0 :             bitrate.get_sum_kbps() < (down_scale_bitrate_ / 2)) {
     221           0 :           down_scale_requested_ = false;
     222             :         }
     223             :       }
     224             :     }
     225             :   } else {
     226             :     // If we have more than 1 stream, reduce the qp_max for the low resolution
     227             :     // stream if frame rate is not too low. The trade-off with lower qp_max is
     228             :     // possibly more dropped frames, so we only do this if the frame rate is
     229             :     // above some threshold (base temporal layer is down to 1/4 for 3 layers).
     230             :     // We may want to condition this on bitrate later.
     231           0 :     if (new_framerate > 20) {
     232           0 :       configurations_[encoders_.size() - 1].rc_max_quantizer = 45;
     233             :     } else {
     234             :       // Go back to default value set in InitEncode.
     235           0 :       configurations_[encoders_.size() - 1].rc_max_quantizer = qp_max_;
     236             :     }
     237             :   }
     238             : 
     239           0 :   size_t stream_idx = encoders_.size() - 1;
     240           0 :   for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) {
     241             :     unsigned int target_bitrate_kbps =
     242           0 :         bitrate.GetSpatialLayerSum(stream_idx) / 1000;
     243             : 
     244           0 :     bool send_stream = target_bitrate_kbps > 0;
     245           0 :     if (send_stream || encoders_.size() > 1)
     246           0 :       SetStreamState(send_stream, stream_idx);
     247             : 
     248           0 :     configurations_[i].rc_target_bitrate = target_bitrate_kbps;
     249           0 :     temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[i]);
     250             : 
     251           0 :     if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) {
     252           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
     253             :     }
     254             :   }
     255           0 :   return WEBRTC_VIDEO_CODEC_OK;
     256             : }
     257             : 
     258           0 : const char* VP8EncoderImpl::ImplementationName() const {
     259           0 :   return "libvpx";
     260             : }
     261             : 
     262           0 : void VP8EncoderImpl::SetStreamState(bool send_stream,
     263             :                                             int stream_idx) {
     264           0 :   if (send_stream && !send_stream_[stream_idx]) {
     265             :     // Need a key frame if we have not sent this stream before.
     266           0 :     key_frame_request_[stream_idx] = true;
     267             :   }
     268           0 :   send_stream_[stream_idx] = send_stream;
     269           0 : }
     270             : 
     271           0 : void VP8EncoderImpl::SetupTemporalLayers(int num_streams,
     272             :                                          int num_temporal_layers,
     273             :                                          const VideoCodec& codec) {
     274           0 :   RTC_DCHECK(codec.VP8().tl_factory != nullptr);
     275           0 :   const TemporalLayersFactory* tl_factory = codec.VP8().tl_factory;
     276           0 :   if (num_streams == 1) {
     277           0 :     temporal_layers_.push_back(
     278           0 :         tl_factory->Create(0, num_temporal_layers, rand()));
     279             :   } else {
     280           0 :     for (int i = 0; i < num_streams; ++i) {
     281           0 :       RTC_CHECK_GT(num_temporal_layers, 0);
     282           0 :       int layers = std::max(static_cast<uint8_t>(1),
     283           0 :                             codec.simulcastStream[i].numberOfTemporalLayers);
     284           0 :       temporal_layers_.push_back(tl_factory->Create(i, layers, rand()));
     285             :     }
     286             :   }
     287           0 : }
     288             : 
     289           0 : int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
     290             :                                int number_of_cores,
     291             :                                size_t /*maxPayloadSize */) {
     292           0 :   if (inst == NULL) {
     293           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     294             :   }
     295           0 :   if (inst->maxFramerate < 1) {
     296           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     297             :   }
     298             :   // allow zero to represent an unspecified maxBitRate
     299           0 :   if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
     300           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     301             :   }
     302           0 :   if (inst->width <= 1 || inst->height <= 1) {
     303           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     304             :   }
     305           0 :   if (number_of_cores < 1) {
     306           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     307             :   }
     308           0 :   if (inst->VP8().feedbackModeOn && inst->numberOfSimulcastStreams > 1) {
     309           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     310             :   }
     311           0 :   if (inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) {
     312           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     313             :   }
     314           0 :   int retVal = Release();
     315           0 :   if (retVal < 0) {
     316           0 :     return retVal;
     317             :   }
     318             : 
     319           0 :   int number_of_streams = NumberOfStreams(*inst);
     320           0 :   bool doing_simulcast = (number_of_streams > 1);
     321             : 
     322           0 :   if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
     323           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     324             :   }
     325             : 
     326             :   int num_temporal_layers =
     327           0 :       doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers
     328           0 :                       : inst->VP8().numberOfTemporalLayers;
     329           0 :   RTC_DCHECK_GT(num_temporal_layers, 0);
     330             : 
     331           0 :   SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst);
     332             : 
     333           0 :   feedback_mode_ = inst->VP8().feedbackModeOn;
     334             : 
     335           0 :   number_of_cores_ = number_of_cores;
     336           0 :   timestamp_ = 0;
     337           0 :   codec_ = *inst;
     338             : 
     339             :   // Code expects simulcastStream resolutions to be correct, make sure they are
     340             :   // filled even when there are no simulcast layers.
     341           0 :   if (codec_.numberOfSimulcastStreams == 0) {
     342           0 :     codec_.simulcastStream[0].width = codec_.width;
     343           0 :     codec_.simulcastStream[0].height = codec_.height;
     344             :   }
     345             : 
     346           0 :   picture_id_.resize(number_of_streams);
     347           0 :   last_key_frame_picture_id_.resize(number_of_streams);
     348           0 :   encoded_images_.resize(number_of_streams);
     349           0 :   encoders_.resize(number_of_streams);
     350           0 :   configurations_.resize(number_of_streams);
     351           0 :   downsampling_factors_.resize(number_of_streams);
     352           0 :   raw_images_.resize(number_of_streams);
     353           0 :   send_stream_.resize(number_of_streams);
     354           0 :   send_stream_[0] = true;  // For non-simulcast case.
     355           0 :   cpu_speed_.resize(number_of_streams);
     356           0 :   std::fill(key_frame_request_.begin(), key_frame_request_.end(), false);
     357             : 
     358           0 :   int idx = number_of_streams - 1;
     359           0 :   for (int i = 0; i < (number_of_streams - 1); ++i, --idx) {
     360           0 :     int gcd = GCD(inst->simulcastStream[idx].width,
     361           0 :                   inst->simulcastStream[idx - 1].width);
     362           0 :     downsampling_factors_[i].num = inst->simulcastStream[idx].width / gcd;
     363           0 :     downsampling_factors_[i].den = inst->simulcastStream[idx - 1].width / gcd;
     364           0 :     send_stream_[i] = false;
     365             :   }
     366           0 :   if (number_of_streams > 1) {
     367           0 :     send_stream_[number_of_streams - 1] = false;
     368           0 :     downsampling_factors_[number_of_streams - 1].num = 1;
     369           0 :     downsampling_factors_[number_of_streams - 1].den = 1;
     370             :   }
     371           0 :   for (int i = 0; i < number_of_streams; ++i) {
     372             :     // Random start, 16 bits is enough.
     373           0 :     picture_id_[i] = static_cast<uint16_t>(rand()) & 0x7FFF;  // NOLINT
     374           0 :     last_key_frame_picture_id_[i] = -1;
     375             :     // allocate memory for encoded image
     376           0 :     if (encoded_images_[i]._buffer != NULL) {
     377           0 :       delete[] encoded_images_[i]._buffer;
     378             :     }
     379             :     // Reserve 100 extra bytes for overhead at small resolutions.
     380           0 :     encoded_images_[i]._size = CalcBufferSize(kI420, codec_.width, codec_.height)
     381           0 :                                + 100;
     382           0 :     encoded_images_[i]._buffer = new uint8_t[encoded_images_[i]._size];
     383           0 :     encoded_images_[i]._completeFrame = true;
     384             :   }
     385             :   // populate encoder configuration with default values
     386           0 :   if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &configurations_[0],
     387             :                                    0)) {
     388           0 :     return WEBRTC_VIDEO_CODEC_ERROR;
     389             :   }
     390             :   // setting the time base of the codec
     391           0 :   configurations_[0].g_timebase.num = 1;
     392           0 :   configurations_[0].g_timebase.den = 90000;
     393           0 :   configurations_[0].g_lag_in_frames = 0;  // 0- no frame lagging
     394             : 
     395             :   // Set the error resilience mode according to user settings.
     396           0 :   switch (inst->VP8().resilience) {
     397             :     case kResilienceOff:
     398           0 :       configurations_[0].g_error_resilient = 0;
     399           0 :       break;
     400             :     case kResilientStream:
     401           0 :       configurations_[0].g_error_resilient = 1;  // TODO(holmer): Replace with
     402             :       // VPX_ERROR_RESILIENT_DEFAULT when we
     403             :       // drop support for libvpx 9.6.0.
     404           0 :       break;
     405             :     case kResilientFrames:
     406           0 :       return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  // Not supported
     407             :   }
     408             : 
     409             :   // rate control settings
     410           0 :   configurations_[0].rc_dropframe_thresh = inst->VP8().frameDroppingOn ? 30 : 0;
     411           0 :   configurations_[0].rc_end_usage = VPX_CBR;
     412           0 :   configurations_[0].g_pass = VPX_RC_ONE_PASS;
     413             :   // TODO(hellner): investigate why the following two lines produce
     414             :   // automaticResizeOn value of 3 when running
     415             :   // WebRtcVideoMediaChannelTest.GetStatsMultipleSendStreams inside the talk
     416             :   // framework.
     417             :   // configurations_[0].rc_resize_allowed =
     418             :   //    inst->codecSpecific.VP8.automaticResizeOn ? 1 : 0;
     419           0 :   configurations_[0].rc_resize_allowed = 0;
     420             :   // Handle resizing outside of libvpx when doing single-stream.
     421           0 :   if (inst->VP8().automaticResizeOn && number_of_streams > 1) {
     422           0 :     configurations_[0].rc_resize_allowed = 1;
     423             :   }
     424           0 :   configurations_[0].rc_min_quantizer = 2;
     425           0 :   if (inst->qpMax >= configurations_[0].rc_min_quantizer) {
     426           0 :     qp_max_ = inst->qpMax;
     427             :   }
     428           0 :   configurations_[0].rc_max_quantizer = qp_max_;
     429           0 :   configurations_[0].rc_undershoot_pct = 100;
     430           0 :   configurations_[0].rc_overshoot_pct = 15;
     431           0 :   configurations_[0].rc_buf_initial_sz = 500;
     432           0 :   configurations_[0].rc_buf_optimal_sz = 600;
     433           0 :   configurations_[0].rc_buf_sz = 1000;
     434             : 
     435             :   // Set the maximum target size of any key-frame.
     436           0 :   rc_max_intra_target_ = MaxIntraTarget(configurations_[0].rc_buf_optimal_sz);
     437             : 
     438           0 :   if (feedback_mode_) {
     439             :     // Disable periodic key frames if we get feedback from the decoder
     440             :     // through SLI and RPSI.
     441           0 :     configurations_[0].kf_mode = VPX_KF_DISABLED;
     442           0 :   } else if (inst->VP8().keyFrameInterval > 0) {
     443           0 :     configurations_[0].kf_mode = VPX_KF_AUTO;
     444           0 :     configurations_[0].kf_max_dist = inst->VP8().keyFrameInterval;
     445             :   } else {
     446           0 :     configurations_[0].kf_mode = VPX_KF_DISABLED;
     447             :   }
     448             : 
     449             :   // Allow the user to set the complexity for the base stream.
     450           0 :   switch (inst->VP8().complexity) {
     451             :     case kComplexityHigh:
     452           0 :       cpu_speed_[0] = -5;
     453           0 :       break;
     454             :     case kComplexityHigher:
     455           0 :       cpu_speed_[0] = -4;
     456           0 :       break;
     457             :     case kComplexityMax:
     458           0 :       cpu_speed_[0] = -3;
     459           0 :       break;
     460             :     default:
     461           0 :       cpu_speed_[0] = -6;
     462           0 :       break;
     463             :   }
     464           0 :   cpu_speed_default_ = cpu_speed_[0];
     465             :   // Set encoding complexity (cpu_speed) based on resolution and/or platform.
     466           0 :   cpu_speed_[0] = SetCpuSpeed(inst->width, inst->height);
     467           0 :   for (int i = 1; i < number_of_streams; ++i) {
     468           0 :     cpu_speed_[i] =
     469           0 :         SetCpuSpeed(inst->simulcastStream[number_of_streams - 1 - i].width,
     470           0 :                     inst->simulcastStream[number_of_streams - 1 - i].height);
     471             :   }
     472           0 :   configurations_[0].g_w = inst->width;
     473           0 :   configurations_[0].g_h = inst->height;
     474             : 
     475             :   // Determine number of threads based on the image size and #cores.
     476             :   // TODO(fbarchard): Consider number of Simulcast layers.
     477           0 :   configurations_[0].g_threads = NumberOfThreads(
     478           0 :       configurations_[0].g_w, configurations_[0].g_h, number_of_cores);
     479             : 
     480             :   // Creating a wrapper to the image - setting image data to NULL.
     481             :   // Actual pointer will be set in encode. Setting align to 1, as it
     482             :   // is meaningless (no memory allocation is done here).
     483           0 :   vpx_img_wrap(&raw_images_[0], VPX_IMG_FMT_I420, inst->width, inst->height, 1,
     484           0 :                NULL);
     485             : 
     486             :   // Note the order we use is different from webm, we have lowest resolution
     487             :   // at position 0 and they have highest resolution at position 0.
     488           0 :   int stream_idx = encoders_.size() - 1;
     489           0 :   SimulcastRateAllocator init_allocator(codec_, nullptr);
     490             :   BitrateAllocation allocation = init_allocator.GetAllocation(
     491           0 :       inst->startBitrate * 1000, inst->maxFramerate);
     492           0 :   std::vector<uint32_t> stream_bitrates;
     493           0 :   for (int i = 0; i == 0 || i < inst->numberOfSimulcastStreams; ++i) {
     494           0 :     uint32_t bitrate = allocation.GetSpatialLayerSum(i) / 1000;
     495           0 :     stream_bitrates.push_back(bitrate);
     496             :   }
     497             : 
     498           0 :   configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx];
     499           0 :   temporal_layers_[stream_idx]->OnRatesUpdated(
     500           0 :       stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate);
     501           0 :   temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[0]);
     502           0 :   --stream_idx;
     503           0 :   for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) {
     504           0 :     memcpy(&configurations_[i], &configurations_[0],
     505           0 :            sizeof(configurations_[0]));
     506             : 
     507           0 :     configurations_[i].g_w = inst->simulcastStream[stream_idx].width;
     508           0 :     configurations_[i].g_h = inst->simulcastStream[stream_idx].height;
     509             : 
     510             :     // Use 1 thread for lower resolutions.
     511           0 :     configurations_[i].g_threads = 1;
     512             : 
     513             :     // Setting alignment to 32 - as that ensures at least 16 for all
     514             :     // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for
     515             :     // the y plane, but only half of it to the u and v planes.
     516           0 :     vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420,
     517           0 :                   inst->simulcastStream[stream_idx].width,
     518           0 :                   inst->simulcastStream[stream_idx].height, kVp832ByteAlign);
     519           0 :     SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
     520           0 :     configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx];
     521           0 :     temporal_layers_[stream_idx]->OnRatesUpdated(
     522           0 :         stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate);
     523           0 :     temporal_layers_[stream_idx]->UpdateConfiguration(&configurations_[i]);
     524             :   }
     525             : 
     526           0 :   rps_.Init();
     527           0 :   return InitAndSetControlSettings();
     528             : }
     529             : 
     530           0 : int VP8EncoderImpl::SetCpuSpeed(int width, int height) {
     531             : #if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || defined(ANDROID)
     532             :   // On mobile platform, use a lower speed setting for lower resolutions for
     533             :   // CPUs with 4 or more cores.
     534             :   RTC_DCHECK_GT(number_of_cores_, 0);
     535             :   if (number_of_cores_ <= 3)
     536             :     return -12;
     537             : 
     538             :   if (width * height <= 352 * 288)
     539             :     return -8;
     540             :   else if (width * height <= 640 * 480)
     541             :     return -10;
     542             :   else
     543             :     return -12;
     544             : #else
     545             :   // For non-ARM, increase encoding complexity (i.e., use lower speed setting)
     546             :   // if resolution is below CIF. Otherwise, keep the default/user setting
     547             :   // (|cpu_speed_default_|) set on InitEncode via VP8().complexity.
     548           0 :   if (width * height < 352 * 288)
     549           0 :     return (cpu_speed_default_ < -4) ? -4 : cpu_speed_default_;
     550             :   else
     551           0 :     return cpu_speed_default_;
     552             : #endif
     553             : }
     554             : 
     555           0 : int VP8EncoderImpl::NumberOfThreads(int width, int height, int cpus) {
     556             : #if defined(ANDROID)
     557             :   if (width * height >= 320 * 180) {
     558             :     if (cpus >= 4) {
     559             :       // 3 threads for CPUs with 4 and more cores since most of times only 4
     560             :       // cores will be active.
     561             :       return 3;
     562             :     } else if (cpus == 3 || cpus == 2) {
     563             :       return 2;
     564             :     } else {
     565             :       return 1;
     566             :     }
     567             :   }
     568             :   return 1;
     569             : #else
     570           0 :   if (width * height >= 1920 * 1080 && cpus > 8) {
     571           0 :     return 8;  // 8 threads for 1080p on high perf machines.
     572           0 :   } else if (width * height > 1280 * 960 && cpus >= 6) {
     573             :     // 3 threads for 1080p.
     574           0 :     return 3;
     575           0 :   } else if (width * height > 640 * 480 && cpus >= 3) {
     576             :     // 2 threads for qHD/HD.
     577           0 :     return 2;
     578             :   } else {
     579             :     // 1 thread for VGA or less.
     580           0 :     return 1;
     581             :   }
     582             : #endif
     583             : }
     584             : 
     585           0 : int VP8EncoderImpl::InitAndSetControlSettings() {
     586           0 :   vpx_codec_flags_t flags = 0;
     587           0 :   flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
     588             : 
     589           0 :   if (encoders_.size() > 1) {
     590           0 :     int error = vpx_codec_enc_init_multi(&encoders_[0], vpx_codec_vp8_cx(),
     591             :                                          &configurations_[0], encoders_.size(),
     592             :                                          flags, &downsampling_factors_[0]);
     593           0 :     if (error) {
     594           0 :       return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
     595             :     }
     596             :   } else {
     597           0 :     if (vpx_codec_enc_init(&encoders_[0], vpx_codec_vp8_cx(),
     598             :                            &configurations_[0], flags)) {
     599           0 :       return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
     600             :     }
     601             :   }
     602             :   // Enable denoising for the highest resolution stream, and for
     603             :   // the second highest resolution if we are doing more than 2
     604             :   // spatial layers/streams.
     605             :   // TODO(holmer): Investigate possibility of adding a libvpx API
     606             :   // for getting the denoised frame from the encoder and using that
     607             :   // when encoding lower resolution streams. Would it work with the
     608             :   // multi-res encoding feature?
     609           0 :   denoiserState denoiser_state = kDenoiserOnYOnly;
     610             : #if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || defined(ANDROID)
     611             :   denoiser_state = kDenoiserOnYOnly;
     612             : #else
     613           0 :   denoiser_state = kDenoiserOnAdaptive;
     614             : #endif
     615           0 :   vpx_codec_control(&encoders_[0], VP8E_SET_NOISE_SENSITIVITY,
     616           0 :                     codec_.VP8()->denoisingOn ? denoiser_state : kDenoiserOff);
     617           0 :   if (encoders_.size() > 2) {
     618           0 :     vpx_codec_control(
     619             :         &encoders_[1], VP8E_SET_NOISE_SENSITIVITY,
     620           0 :         codec_.VP8()->denoisingOn ? denoiser_state : kDenoiserOff);
     621             :   }
     622           0 :   for (size_t i = 0; i < encoders_.size(); ++i) {
     623             :     // Allow more screen content to be detected as static.
     624           0 :     vpx_codec_control(&(encoders_[i]), VP8E_SET_STATIC_THRESHOLD,
     625           0 :                       codec_.mode == kScreensharing ? 300 : 1);
     626           0 :     vpx_codec_control(&(encoders_[i]), VP8E_SET_CPUUSED, cpu_speed_[i]);
     627           0 :     vpx_codec_control(&(encoders_[i]), VP8E_SET_TOKEN_PARTITIONS,
     628           0 :                       static_cast<vp8e_token_partitions>(token_partitions_));
     629           0 :     vpx_codec_control(&(encoders_[i]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
     630           0 :                       rc_max_intra_target_);
     631             :     // VP8E_SET_SCREEN_CONTENT_MODE 2 = screen content with more aggressive
     632             :     // rate control (drop frames on large target bitrate overshoot)
     633           0 :     vpx_codec_control(&(encoders_[i]), VP8E_SET_SCREEN_CONTENT_MODE,
     634           0 :                       codec_.mode == kScreensharing ? 2 : 0);
     635             :   }
     636           0 :   inited_ = true;
     637           0 :   return WEBRTC_VIDEO_CODEC_OK;
     638             : }
     639             : 
     640           0 : uint32_t VP8EncoderImpl::MaxIntraTarget(uint32_t optimalBuffersize) {
     641             :   // Set max to the optimal buffer level (normalized by target BR),
     642             :   // and scaled by a scalePar.
     643             :   // Max target size = scalePar * optimalBufferSize * targetBR[Kbps].
     644             :   // This values is presented in percentage of perFrameBw:
     645             :   // perFrameBw = targetBR[Kbps] * 1000 / frameRate.
     646             :   // The target in % is as follows:
     647             : 
     648           0 :   float scalePar = 0.5;
     649           0 :   uint32_t targetPct = optimalBuffersize * scalePar * codec_.maxFramerate / 10;
     650             : 
     651             :   // Don't go below 3 times the per frame bandwidth.
     652           0 :   const uint32_t minIntraTh = 300;
     653           0 :   return (targetPct < minIntraTh) ? minIntraTh : targetPct;
     654             : }
     655             : 
     656           0 : int VP8EncoderImpl::Encode(const VideoFrame& frame,
     657             :                            const CodecSpecificInfo* codec_specific_info,
     658             :                            const std::vector<FrameType>* frame_types) {
     659           0 :   RTC_DCHECK_EQ(frame.width(), codec_.width);
     660           0 :   RTC_DCHECK_EQ(frame.height(), codec_.height);
     661             : 
     662           0 :   if (!inited_)
     663           0 :     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
     664           0 :   if (encoded_complete_callback_ == NULL)
     665           0 :     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
     666             : 
     667           0 :   rtc::scoped_refptr<VideoFrameBuffer> input_image = frame.video_frame_buffer();
     668             :   // Since we are extracting raw pointers from |input_image| to
     669             :   // |raw_images_[0]|, the resolution of these frames must match. Note that
     670             :   // |input_image| might be scaled from |frame|. In that case, the resolution of
     671             :   // |raw_images_[0]| should have been updated in UpdateCodecFrameSize.
     672           0 :   RTC_DCHECK_EQ(input_image->width(), raw_images_[0].d_w);
     673           0 :   RTC_DCHECK_EQ(input_image->height(), raw_images_[0].d_h);
     674             : 
     675             :   // Image in vpx_image_t format.
     676             :   // Input image is const. VP8's raw image is not defined as const.
     677           0 :   raw_images_[0].planes[VPX_PLANE_Y] =
     678           0 :       const_cast<uint8_t*>(input_image->DataY());
     679           0 :   raw_images_[0].planes[VPX_PLANE_U] =
     680           0 :       const_cast<uint8_t*>(input_image->DataU());
     681           0 :   raw_images_[0].planes[VPX_PLANE_V] =
     682           0 :       const_cast<uint8_t*>(input_image->DataV());
     683             : 
     684           0 :   raw_images_[0].stride[VPX_PLANE_Y] = input_image->StrideY();
     685           0 :   raw_images_[0].stride[VPX_PLANE_U] = input_image->StrideU();
     686           0 :   raw_images_[0].stride[VPX_PLANE_V] = input_image->StrideV();
     687             : 
     688           0 :   for (size_t i = 1; i < encoders_.size(); ++i) {
     689             :     // Scale the image down a number of times by downsampling factor
     690           0 :     libyuv::I420Scale(
     691           0 :         raw_images_[i - 1].planes[VPX_PLANE_Y],
     692           0 :         raw_images_[i - 1].stride[VPX_PLANE_Y],
     693           0 :         raw_images_[i - 1].planes[VPX_PLANE_U],
     694           0 :         raw_images_[i - 1].stride[VPX_PLANE_U],
     695           0 :         raw_images_[i - 1].planes[VPX_PLANE_V],
     696           0 :         raw_images_[i - 1].stride[VPX_PLANE_V], raw_images_[i - 1].d_w,
     697           0 :         raw_images_[i - 1].d_h, raw_images_[i].planes[VPX_PLANE_Y],
     698           0 :         raw_images_[i].stride[VPX_PLANE_Y], raw_images_[i].planes[VPX_PLANE_U],
     699           0 :         raw_images_[i].stride[VPX_PLANE_U], raw_images_[i].planes[VPX_PLANE_V],
     700           0 :         raw_images_[i].stride[VPX_PLANE_V], raw_images_[i].d_w,
     701           0 :         raw_images_[i].d_h, libyuv::kFilterBilinear);
     702             :   }
     703             :   vpx_enc_frame_flags_t flags[kMaxSimulcastStreams];
     704           0 :   for (size_t i = 0; i < encoders_.size(); ++i) {
     705           0 :     int ret = temporal_layers_[i]->EncodeFlags(frame.timestamp());
     706           0 :     if (ret < 0) {
     707             :       // Drop this frame.
     708           0 :       return WEBRTC_VIDEO_CODEC_OK;
     709             :     }
     710           0 :     flags[i] = ret;
     711             :   }
     712           0 :   bool send_key_frame = false;
     713           0 :   for (size_t i = 0; i < key_frame_request_.size() && i < send_stream_.size();
     714             :        ++i) {
     715           0 :     if (key_frame_request_[i] && send_stream_[i]) {
     716           0 :       send_key_frame = true;
     717           0 :       break;
     718             :     }
     719             :   }
     720           0 :   if (!send_key_frame && frame_types) {
     721           0 :     for (size_t i = 0; i < frame_types->size() && i < send_stream_.size();
     722             :          ++i) {
     723           0 :       if ((*frame_types)[i] == kVideoFrameKey && send_stream_[i]) {
     724           0 :         send_key_frame = true;
     725           0 :         break;
     726             :       }
     727             :     }
     728             :   }
     729             :   // The flag modification below (due to forced key frame, RPS, etc.,) for now
     730             :   // will be the same for all encoders/spatial layers.
     731             :   // TODO(marpan/holmer): Allow for key frame request to be set per encoder.
     732           0 :   bool only_predict_from_key_frame = false;
     733           0 :   if (send_key_frame) {
     734             :     // Adapt the size of the key frame when in screenshare with 1 temporal
     735             :     // layer.
     736           0 :     if (encoders_.size() == 1 && codec_.mode == kScreensharing &&
     737           0 :         codec_.VP8()->numberOfTemporalLayers <= 1) {
     738           0 :       const uint32_t forceKeyFrameIntraTh = 100;
     739           0 :       vpx_codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
     740           0 :                         forceKeyFrameIntraTh);
     741             :     }
     742             :     // Key frame request from caller.
     743             :     // Will update both golden and alt-ref.
     744           0 :     for (size_t i = 0; i < encoders_.size(); ++i) {
     745           0 :       flags[i] = VPX_EFLAG_FORCE_KF;
     746             :     }
     747           0 :     std::fill(key_frame_request_.begin(), key_frame_request_.end(), false);
     748           0 :   } else if (codec_specific_info &&
     749           0 :              codec_specific_info->codecType == kVideoCodecVP8) {
     750           0 :     if (feedback_mode_) {
     751             :       // Handle RPSI and SLI messages and set up the appropriate encode flags.
     752           0 :       bool sendRefresh = false;
     753           0 :       if (codec_specific_info->codecSpecific.VP8.hasReceivedRPSI) {
     754           0 :         rps_.ReceivedRPSI(codec_specific_info->codecSpecific.VP8.pictureIdRPSI);
     755             :       }
     756           0 :       if (codec_specific_info->codecSpecific.VP8.hasReceivedSLI) {
     757           0 :         sendRefresh = rps_.ReceivedSLI(frame.timestamp());
     758             :       }
     759           0 :       for (size_t i = 0; i < encoders_.size(); ++i) {
     760           0 :         flags[i] = rps_.EncodeFlags(picture_id_[i], sendRefresh,
     761             :                                     frame.timestamp());
     762             :       }
     763             :     } else {
     764           0 :       if (codec_specific_info->codecSpecific.VP8.hasReceivedRPSI) {
     765             :         // Is this our last key frame? If not ignore.
     766             :         // |picture_id_| is defined per spatial stream/layer, so check that
     767             :         // |RPSI| matches the last key frame from any of the spatial streams.
     768             :         // If so, then all spatial streams for this encoding will predict from
     769             :         // its long-term reference (last key frame).
     770           0 :         int RPSI = codec_specific_info->codecSpecific.VP8.pictureIdRPSI;
     771           0 :         for (size_t i = 0; i < encoders_.size(); ++i) {
     772           0 :           if (last_key_frame_picture_id_[i] == RPSI) {
     773             :             // Request for a long term reference frame.
     774             :             // Note 1: overwrites any temporal settings.
     775             :             // Note 2: VP8_EFLAG_NO_UPD_ENTROPY is not needed as that flag is
     776             :             //         set by error_resilient mode.
     777           0 :             for (size_t j = 0; j < encoders_.size(); ++j) {
     778           0 :               flags[j] = VP8_EFLAG_NO_UPD_ARF;
     779           0 :               flags[j] |= VP8_EFLAG_NO_REF_GF;
     780           0 :               flags[j] |= VP8_EFLAG_NO_REF_LAST;
     781             :             }
     782           0 :             only_predict_from_key_frame = true;
     783           0 :             break;
     784             :           }
     785             :         }
     786             :       }
     787             :     }
     788             :   }
     789             :   // Set the encoder frame flags and temporal layer_id for each spatial stream.
     790             :   // Note that |temporal_layers_| are defined starting from lowest resolution at
     791             :   // position 0 to highest resolution at position |encoders_.size() - 1|,
     792             :   // whereas |encoder_| is from highest to lowest resolution.
     793           0 :   size_t stream_idx = encoders_.size() - 1;
     794           0 :   for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) {
     795             :     // Allow the layers adapter to temporarily modify the configuration. This
     796             :     // change isn't stored in configurations_ so change will be discarded at
     797             :     // the next update.
     798             :     vpx_codec_enc_cfg_t temp_config;
     799           0 :     memcpy(&temp_config, &configurations_[i], sizeof(vpx_codec_enc_cfg_t));
     800           0 :     if (temporal_layers_[stream_idx]->UpdateConfiguration(&temp_config)) {
     801           0 :       if (vpx_codec_enc_config_set(&encoders_[i], &temp_config))
     802           0 :         return WEBRTC_VIDEO_CODEC_ERROR;
     803             :     }
     804             : 
     805           0 :     vpx_codec_control(&encoders_[i], VP8E_SET_FRAME_FLAGS, flags[stream_idx]);
     806           0 :     vpx_codec_control(&encoders_[i], VP8E_SET_TEMPORAL_LAYER_ID,
     807           0 :                       temporal_layers_[stream_idx]->CurrentLayerId());
     808             :   }
     809             :   // TODO(holmer): Ideally the duration should be the timestamp diff of this
     810             :   // frame and the next frame to be encoded, which we don't have. Instead we
     811             :   // would like to use the duration of the previous frame. Unfortunately the
     812             :   // rate control seems to be off with that setup. Using the average input
     813             :   // frame rate to calculate an average duration for now.
     814           0 :   assert(codec_.maxFramerate > 0);
     815           0 :   uint32_t duration = 90000 / codec_.maxFramerate;
     816             : 
     817             :   // Note we must pass 0 for |flags| field in encode call below since they are
     818             :   // set above in |vpx_codec_control| function for each encoder/spatial layer.
     819           0 :   int error = vpx_codec_encode(&encoders_[0], &raw_images_[0], timestamp_,
     820           0 :                                duration, 0, VPX_DL_REALTIME);
     821             :   // Reset specific intra frame thresholds, following the key frame.
     822           0 :   if (send_key_frame) {
     823           0 :     vpx_codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
     824           0 :                       rc_max_intra_target_);
     825             :   }
     826           0 :   if (error)
     827           0 :     return WEBRTC_VIDEO_CODEC_ERROR;
     828           0 :   timestamp_ += duration;
     829             :   // Examines frame timestamps only.
     830           0 :   return GetEncodedPartitions(frame, only_predict_from_key_frame);
     831             : }
     832             : 
     833             : // TODO(pbos): Make sure this works for properly for >1 encoders.
     834           0 : int VP8EncoderImpl::UpdateCodecFrameSize(int width, int height) {
     835           0 :   codec_.width = width;
     836           0 :   codec_.height = height;
     837           0 :   if (codec_.numberOfSimulcastStreams <= 1) {
     838             :     // For now scaling is only used for single-layer streams.
     839           0 :     codec_.simulcastStream[0].width = width;
     840           0 :     codec_.simulcastStream[0].height = height;
     841             :   }
     842             :   // Update the cpu_speed setting for resolution change.
     843           0 :   vpx_codec_control(&(encoders_[0]), VP8E_SET_CPUUSED,
     844           0 :                     SetCpuSpeed(codec_.width, codec_.height));
     845           0 :   raw_images_[0].w = codec_.width;
     846           0 :   raw_images_[0].h = codec_.height;
     847           0 :   raw_images_[0].d_w = codec_.width;
     848           0 :   raw_images_[0].d_h = codec_.height;
     849           0 :   vpx_img_set_rect(&raw_images_[0], 0, 0, codec_.width, codec_.height);
     850             : 
     851             :   // Update encoder context for new frame size.
     852             :   // Change of frame size will automatically trigger a key frame.
     853           0 :   configurations_[0].g_w = codec_.width;
     854           0 :   configurations_[0].g_h = codec_.height;
     855           0 :   if (vpx_codec_enc_config_set(&encoders_[0], &configurations_[0])) {
     856           0 :     return WEBRTC_VIDEO_CODEC_ERROR;
     857             :   }
     858           0 :   return WEBRTC_VIDEO_CODEC_OK;
     859             : }
     860             : 
     861           0 : void VP8EncoderImpl::PopulateCodecSpecific(
     862             :     CodecSpecificInfo* codec_specific,
     863             :     const vpx_codec_cx_pkt_t& pkt,
     864             :     int stream_idx,
     865             :     uint32_t timestamp,
     866             :     bool only_predicting_from_key_frame) {
     867           0 :   assert(codec_specific != NULL);
     868           0 :   codec_specific->codecType = kVideoCodecVP8;
     869           0 :   codec_specific->codec_name = ImplementationName();
     870           0 :   CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
     871           0 :   vp8Info->pictureId = picture_id_[stream_idx];
     872           0 :   if (pkt.data.frame.flags & VPX_FRAME_IS_KEY) {
     873           0 :     last_key_frame_picture_id_[stream_idx] = picture_id_[stream_idx];
     874             :   }
     875           0 :   vp8Info->simulcastIdx = stream_idx;
     876           0 :   vp8Info->keyIdx = kNoKeyIdx;  // TODO(hlundin) populate this
     877           0 :   vp8Info->nonReference =
     878           0 :       (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) ? true : false;
     879           0 :   bool base_layer_sync_point = (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ||
     880           0 :                                only_predicting_from_key_frame;
     881           0 :   temporal_layers_[stream_idx]->PopulateCodecSpecific(base_layer_sync_point,
     882           0 :                                                       vp8Info, timestamp);
     883             :   // Prepare next.
     884           0 :   picture_id_[stream_idx] = (picture_id_[stream_idx] + 1) & 0x7FFF;
     885           0 : }
     886             : 
     887           0 : int VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image,
     888             :                                          bool only_predicting_from_key_frame) {
     889             :   int bw_resolutions_disabled =
     890           0 :       (encoders_.size() > 1) ? NumStreamsDisabled(send_stream_) : -1;
     891             : 
     892           0 :   int stream_idx = static_cast<int>(encoders_.size()) - 1;
     893           0 :   int result = WEBRTC_VIDEO_CODEC_OK;
     894           0 :   for (size_t encoder_idx = 0; encoder_idx < encoders_.size();
     895             :        ++encoder_idx, --stream_idx) {
     896           0 :     vpx_codec_iter_t iter = NULL;
     897           0 :     int part_idx = 0;
     898           0 :     encoded_images_[encoder_idx]._length = 0;
     899           0 :     encoded_images_[encoder_idx]._frameType = kVideoFrameDelta;
     900           0 :     RTPFragmentationHeader frag_info;
     901             :     // token_partitions_ is number of bits used.
     902           0 :     frag_info.VerifyAndAllocateFragmentationHeader((1 << token_partitions_) +
     903           0 :                                                    1);
     904           0 :     CodecSpecificInfo codec_specific;
     905           0 :     const vpx_codec_cx_pkt_t* pkt = NULL;
     906           0 :     while ((pkt = vpx_codec_get_cx_data(&encoders_[encoder_idx], &iter)) !=
     907             :            NULL) {
     908           0 :       switch (pkt->kind) {
     909             :         case VPX_CODEC_CX_FRAME_PKT: {
     910           0 :           size_t length = encoded_images_[encoder_idx]._length;
     911           0 :           if (pkt->data.frame.sz + length >
     912           0 :               encoded_images_[encoder_idx]._size) {
     913           0 :             uint8_t* buffer = new uint8_t[pkt->data.frame.sz + length];
     914           0 :             memcpy(buffer, encoded_images_[encoder_idx]._buffer, length);
     915           0 :             delete[] encoded_images_[encoder_idx]._buffer;
     916           0 :             encoded_images_[encoder_idx]._buffer = buffer;
     917           0 :             encoded_images_[encoder_idx]._size = pkt->data.frame.sz + length;
     918             :           }
     919           0 :           memcpy(&encoded_images_[encoder_idx]._buffer[length],
     920           0 :                  pkt->data.frame.buf, pkt->data.frame.sz);
     921           0 :           frag_info.fragmentationOffset[part_idx] = length;
     922           0 :           frag_info.fragmentationLength[part_idx] = pkt->data.frame.sz;
     923           0 :           frag_info.fragmentationPlType[part_idx] = 0;  // not known here
     924           0 :           frag_info.fragmentationTimeDiff[part_idx] = 0;
     925           0 :           encoded_images_[encoder_idx]._length += pkt->data.frame.sz;
     926           0 :           assert(length <= encoded_images_[encoder_idx]._size);
     927           0 :           ++part_idx;
     928           0 :           break;
     929             :         }
     930             :         default:
     931           0 :           break;
     932             :       }
     933             :       // End of frame
     934           0 :       if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
     935             :         // check if encoded frame is a key frame
     936           0 :         if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
     937           0 :           encoded_images_[encoder_idx]._frameType = kVideoFrameKey;
     938           0 :           rps_.EncodedKeyFrame(picture_id_[stream_idx]);
     939             :         }
     940           0 :         PopulateCodecSpecific(&codec_specific, *pkt, stream_idx,
     941             :                               input_image.timestamp(),
     942           0 :                               only_predicting_from_key_frame);
     943           0 :         break;
     944             :       }
     945             :     }
     946           0 :     encoded_images_[encoder_idx]._timeStamp = input_image.timestamp();
     947           0 :     encoded_images_[encoder_idx].capture_time_ms_ =
     948           0 :         input_image.render_time_ms();
     949           0 :     encoded_images_[encoder_idx].rotation_ = input_image.rotation();
     950             : 
     951           0 :     int qp = -1;
     952           0 :     vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp);
     953           0 :     temporal_layers_[stream_idx]->FrameEncoded(
     954           0 :         encoded_images_[encoder_idx]._length,
     955           0 :         encoded_images_[encoder_idx]._timeStamp, qp);
     956           0 :     if (send_stream_[stream_idx]) {
     957           0 :       if (encoded_images_[encoder_idx]._length > 0) {
     958           0 :         TRACE_COUNTER_ID1("webrtc", "EncodedFrameSize", encoder_idx,
     959             :                           encoded_images_[encoder_idx]._length);
     960           0 :         encoded_images_[encoder_idx]._encodedHeight =
     961           0 :             codec_.simulcastStream[stream_idx].height;
     962           0 :         encoded_images_[encoder_idx]._encodedWidth =
     963           0 :             codec_.simulcastStream[stream_idx].width;
     964             :         // Report once per frame (lowest stream always sent).
     965           0 :         encoded_images_[encoder_idx].adapt_reason_.bw_resolutions_disabled =
     966           0 :             (stream_idx == 0) ? bw_resolutions_disabled : -1;
     967           0 :         int qp_128 = -1;
     968           0 :         vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER,
     969           0 :                           &qp_128);
     970           0 :         encoded_images_[encoder_idx].qp_ = qp_128;
     971           0 :         encoded_complete_callback_->OnEncodedImage(encoded_images_[encoder_idx],
     972           0 :                                                    &codec_specific, &frag_info);
     973           0 :       } else if (codec_.mode == kScreensharing) {
     974           0 :         result = WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT;
     975             :       }
     976             :     }
     977             :   }
     978           0 :   return result;
     979             : }
     980             : 
     981           0 : VideoEncoder::ScalingSettings VP8EncoderImpl::GetScalingSettings() const {
     982           0 :   const bool enable_scaling = encoders_.size() == 1 &&
     983           0 :                               configurations_[0].rc_dropframe_thresh > 0 &&
     984           0 :                               codec_.VP8().automaticResizeOn;
     985           0 :   return VideoEncoder::ScalingSettings(enable_scaling);
     986             : }
     987             : 
     988           0 : int VP8EncoderImpl::SetChannelParameters(uint32_t packetLoss, int64_t rtt) {
     989           0 :   rps_.SetRtt(rtt);
     990           0 :   return WEBRTC_VIDEO_CODEC_OK;
     991             : }
     992             : 
     993           0 : int VP8EncoderImpl::RegisterEncodeCompleteCallback(
     994             :     EncodedImageCallback* callback) {
     995           0 :   encoded_complete_callback_ = callback;
     996           0 :   return WEBRTC_VIDEO_CODEC_OK;
     997             : }
     998             : 
     999           0 : VP8DecoderImpl::VP8DecoderImpl()
    1000             :     : buffer_pool_(false, 300 /* max_number_of_buffers*/),
    1001             :       decode_complete_callback_(NULL),
    1002             :       inited_(false),
    1003             :       feedback_mode_(false),
    1004             :       decoder_(NULL),
    1005             :       image_format_(VPX_IMG_FMT_NONE),
    1006             :       ref_frame_(NULL),
    1007             :       propagation_cnt_(-1),
    1008             :       last_frame_width_(0),
    1009             :       last_frame_height_(0),
    1010           0 :       key_frame_required_(true) {}
    1011             : 
    1012           0 : VP8DecoderImpl::~VP8DecoderImpl() {
    1013           0 :   inited_ = true;  // in order to do the actual release
    1014           0 :   Release();
    1015           0 : }
    1016             : 
    1017           0 : int VP8DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) {
    1018           0 :   int ret_val = Release();
    1019           0 :   if (ret_val < 0) {
    1020           0 :     return ret_val;
    1021             :   }
    1022           0 :   if (decoder_ == NULL) {
    1023           0 :     decoder_ = new vpx_codec_ctx_t;
    1024           0 :     memset(decoder_, 0, sizeof(*decoder_));
    1025             :   }
    1026           0 :   if (inst && inst->codecType == kVideoCodecVP8) {
    1027           0 :     feedback_mode_ = inst->VP8().feedbackModeOn;
    1028             :   }
    1029             :   vpx_codec_dec_cfg_t cfg;
    1030             :   // Setting number of threads to a constant value (1)
    1031           0 :   cfg.threads = 1;
    1032           0 :   cfg.h = cfg.w = 0;  // set after decode
    1033             : 
    1034           0 :   vpx_codec_flags_t flags = 0;
    1035             : #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) && \
    1036             :   !defined(ANDROID)
    1037           0 :   flags = VPX_CODEC_USE_POSTPROC;
    1038             : #endif
    1039             : 
    1040           0 :   if (vpx_codec_dec_init(decoder_, vpx_codec_vp8_dx(), &cfg, flags)) {
    1041           0 :     delete decoder_;
    1042           0 :     decoder_ = nullptr;
    1043           0 :     return WEBRTC_VIDEO_CODEC_MEMORY;
    1044             :   }
    1045             : 
    1046             :   // Save VideoCodec instance for later; mainly for duplicating the decoder.
    1047           0 :   if (&codec_ != inst)
    1048           0 :     codec_ = *inst;
    1049           0 :   propagation_cnt_ = -1;
    1050             : 
    1051           0 :   inited_ = true;
    1052             : 
    1053             :   // Always start with a complete key frame.
    1054           0 :   key_frame_required_ = true;
    1055           0 :   return WEBRTC_VIDEO_CODEC_OK;
    1056             : }
    1057             : 
    1058           0 : int VP8DecoderImpl::Decode(const EncodedImage& input_image,
    1059             :                            bool missing_frames,
    1060             :                            const RTPFragmentationHeader* fragmentation,
    1061             :                            const CodecSpecificInfo* codec_specific_info,
    1062             :                            int64_t /*render_time_ms*/) {
    1063           0 :   if (!inited_) {
    1064           0 :     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    1065             :   }
    1066           0 :   if (decode_complete_callback_ == NULL) {
    1067           0 :     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    1068             :   }
    1069           0 :   if (input_image._buffer == NULL && input_image._length > 0) {
    1070             :     // Reset to avoid requesting key frames too often.
    1071           0 :     if (propagation_cnt_ > 0)
    1072           0 :       propagation_cnt_ = 0;
    1073           0 :     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    1074             :   }
    1075             : 
    1076             : #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) && \
    1077             :   !defined(ANDROID)
    1078             :   vp8_postproc_cfg_t ppcfg;
    1079             :   // MFQE enabled to reduce key frame popping.
    1080           0 :   ppcfg.post_proc_flag = VP8_MFQE | VP8_DEBLOCK;
    1081             :   // For VGA resolutions and lower, enable the demacroblocker postproc.
    1082           0 :   if (last_frame_width_ * last_frame_height_ <= 640 * 360) {
    1083           0 :     ppcfg.post_proc_flag |= VP8_DEMACROBLOCK;
    1084             :   }
    1085             :   // Strength of deblocking filter. Valid range:[0,16]
    1086           0 :   ppcfg.deblocking_level = 3;
    1087           0 :   vpx_codec_control(decoder_, VP8_SET_POSTPROC, &ppcfg);
    1088             : #endif
    1089             : 
    1090             :   // Always start with a complete key frame.
    1091           0 :   if (key_frame_required_) {
    1092           0 :     if (input_image._frameType != kVideoFrameKey)
    1093           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
    1094             :     // We have a key frame - is it complete?
    1095           0 :     if (input_image._completeFrame) {
    1096           0 :       key_frame_required_ = false;
    1097             :     } else {
    1098           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
    1099             :     }
    1100             :   }
    1101             :   // Restrict error propagation using key frame requests. Disabled when
    1102             :   // the feedback mode is enabled (RPS).
    1103             :   // Reset on a key frame refresh.
    1104           0 :   if (!feedback_mode_) {
    1105           0 :     if (input_image._frameType == kVideoFrameKey &&
    1106           0 :         input_image._completeFrame) {
    1107           0 :       propagation_cnt_ = -1;
    1108             :       // Start count on first loss.
    1109           0 :     } else if ((!input_image._completeFrame || missing_frames) &&
    1110           0 :                propagation_cnt_ == -1) {
    1111           0 :       propagation_cnt_ = 0;
    1112             :     }
    1113           0 :     if (propagation_cnt_ >= 0) {
    1114           0 :       propagation_cnt_++;
    1115             :     }
    1116             :   }
    1117             : 
    1118           0 :   vpx_codec_iter_t iter = NULL;
    1119             :   vpx_image_t* img;
    1120             :   int ret;
    1121             : 
    1122             :   // Check for missing frames.
    1123           0 :   if (missing_frames) {
    1124             :     // Call decoder with zero data length to signal missing frames.
    1125           0 :     if (vpx_codec_decode(decoder_, NULL, 0, 0, VPX_DL_REALTIME)) {
    1126             :       // Reset to avoid requesting key frames too often.
    1127           0 :       if (propagation_cnt_ > 0)
    1128           0 :         propagation_cnt_ = 0;
    1129           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
    1130             :     }
    1131           0 :     img = vpx_codec_get_frame(decoder_, &iter);
    1132           0 :     iter = NULL;
    1133             :   }
    1134             : 
    1135           0 :   uint8_t* buffer = input_image._buffer;
    1136           0 :   if (input_image._length == 0) {
    1137           0 :     buffer = NULL;  // Triggers full frame concealment.
    1138             :   }
    1139           0 :   if (vpx_codec_decode(decoder_, buffer, input_image._length, 0,
    1140             :                        VPX_DL_REALTIME)) {
    1141             :     // Reset to avoid requesting key frames too often.
    1142           0 :     if (propagation_cnt_ > 0) {
    1143           0 :       propagation_cnt_ = 0;
    1144             :     }
    1145           0 :     return WEBRTC_VIDEO_CODEC_ERROR;
    1146             :   }
    1147             : 
    1148           0 :   img = vpx_codec_get_frame(decoder_, &iter);
    1149           0 :   ret = ReturnFrame(img, input_image._timeStamp, input_image.ntp_time_ms_);
    1150           0 :   if (ret != 0) {
    1151             :     // Reset to avoid requesting key frames too often.
    1152           0 :     if (ret < 0 && propagation_cnt_ > 0)
    1153           0 :       propagation_cnt_ = 0;
    1154           0 :     return ret;
    1155             :   }
    1156           0 :   if (feedback_mode_) {
    1157             :     // Whenever we receive an incomplete key frame all reference buffers will
    1158             :     // be corrupt. If that happens we must request new key frames until we
    1159             :     // decode a complete key frame.
    1160           0 :     if (input_image._frameType == kVideoFrameKey && !input_image._completeFrame)
    1161           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
    1162             :     // Check for reference updates and last reference buffer corruption and
    1163             :     // signal successful reference propagation or frame corruption to the
    1164             :     // encoder.
    1165           0 :     int reference_updates = 0;
    1166           0 :     if (vpx_codec_control(decoder_, VP8D_GET_LAST_REF_UPDATES,
    1167             :                           &reference_updates)) {
    1168             :       // Reset to avoid requesting key frames too often.
    1169           0 :       if (propagation_cnt_ > 0) {
    1170           0 :         propagation_cnt_ = 0;
    1171             :       }
    1172           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
    1173             :     }
    1174           0 :     int corrupted = 0;
    1175           0 :     if (vpx_codec_control(decoder_, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
    1176             :       // Reset to avoid requesting key frames too often.
    1177           0 :       if (propagation_cnt_ > 0)
    1178           0 :         propagation_cnt_ = 0;
    1179           0 :       return WEBRTC_VIDEO_CODEC_ERROR;
    1180             :     }
    1181           0 :     int16_t picture_id = -1;
    1182           0 :     if (codec_specific_info) {
    1183           0 :       picture_id = codec_specific_info->codecSpecific.VP8.pictureId;
    1184             :     }
    1185           0 :     if (picture_id > -1) {
    1186           0 :       if (((reference_updates & VP8_GOLD_FRAME) ||
    1187           0 :            (reference_updates & VP8_ALTR_FRAME)) &&
    1188           0 :           !corrupted) {
    1189           0 :         decode_complete_callback_->ReceivedDecodedReferenceFrame(picture_id);
    1190             :       }
    1191           0 :       decode_complete_callback_->ReceivedDecodedFrame(picture_id);
    1192             :     }
    1193           0 :     if (corrupted) {
    1194             :       // we can decode but with artifacts
    1195           0 :       return WEBRTC_VIDEO_CODEC_REQUEST_SLI;
    1196             :     }
    1197             :   }
    1198             :   // Check Vs. threshold
    1199           0 :   if (propagation_cnt_ > kVp8ErrorPropagationTh) {
    1200             :     // Reset to avoid requesting key frames too often.
    1201           0 :     propagation_cnt_ = 0;
    1202           0 :     return WEBRTC_VIDEO_CODEC_ERROR;
    1203             :   }
    1204           0 :   return WEBRTC_VIDEO_CODEC_OK;
    1205             : }
    1206             : 
    1207           0 : int VP8DecoderImpl::ReturnFrame(const vpx_image_t* img,
    1208             :                                 uint32_t timestamp,
    1209             :                                 int64_t ntp_time_ms) {
    1210           0 :   if (img == NULL) {
    1211             :     // Decoder OK and NULL image => No show frame
    1212           0 :     return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
    1213             :   }
    1214           0 :   last_frame_width_ = img->d_w;
    1215           0 :   last_frame_height_ = img->d_h;
    1216             :   // Allocate memory for decoded image.
    1217             :   rtc::scoped_refptr<I420Buffer> buffer =
    1218           0 :       buffer_pool_.CreateBuffer(img->d_w, img->d_h);
    1219           0 :   if (!buffer.get()) {
    1220             :     // Pool has too many pending frames.
    1221           0 :     RTC_HISTOGRAM_BOOLEAN("WebRTC.Video.VP8DecoderImpl.TooManyPendingFrames",
    1222             :                           1);
    1223           0 :     return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
    1224             :   }
    1225             : 
    1226           0 :   libyuv::I420Copy(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
    1227           0 :                    img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
    1228           0 :                    img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
    1229           0 :                    buffer->MutableDataY(), buffer->StrideY(),
    1230           0 :                    buffer->MutableDataU(), buffer->StrideU(),
    1231           0 :                    buffer->MutableDataV(), buffer->StrideV(),
    1232           0 :                    img->d_w, img->d_h);
    1233             : 
    1234           0 :   VideoFrame decoded_image(buffer, timestamp, 0, kVideoRotation_0);
    1235           0 :   decoded_image.set_ntp_time_ms(ntp_time_ms);
    1236           0 :   int ret = decode_complete_callback_->Decoded(decoded_image);
    1237           0 :   if (ret != 0)
    1238           0 :     return ret;
    1239             : 
    1240             :   // Remember image format for later
    1241           0 :   image_format_ = img->fmt;
    1242           0 :   return WEBRTC_VIDEO_CODEC_OK;
    1243             : }
    1244             : 
    1245           0 : int VP8DecoderImpl::RegisterDecodeCompleteCallback(
    1246             :     DecodedImageCallback* callback) {
    1247           0 :   decode_complete_callback_ = callback;
    1248           0 :   return WEBRTC_VIDEO_CODEC_OK;
    1249             : }
    1250             : 
    1251           0 : int VP8DecoderImpl::Release() {
    1252           0 :   if (decoder_ != NULL) {
    1253           0 :     if (vpx_codec_destroy(decoder_)) {
    1254           0 :       return WEBRTC_VIDEO_CODEC_MEMORY;
    1255             :     }
    1256           0 :     delete decoder_;
    1257           0 :     decoder_ = NULL;
    1258             :   }
    1259           0 :   if (ref_frame_ != NULL) {
    1260           0 :     vpx_img_free(&ref_frame_->img);
    1261           0 :     delete ref_frame_;
    1262           0 :     ref_frame_ = NULL;
    1263             :   }
    1264           0 :   buffer_pool_.Release();
    1265           0 :   inited_ = false;
    1266           0 :   return WEBRTC_VIDEO_CODEC_OK;
    1267             : }
    1268             : 
    1269           0 : const char* VP8DecoderImpl::ImplementationName() const {
    1270           0 :   return "libvpx";
    1271             : }
    1272             : 
    1273           0 : int VP8DecoderImpl::CopyReference(VP8DecoderImpl* copy) {
    1274             :   // The type of frame to copy should be set in ref_frame_->frame_type
    1275             :   // before the call to this function.
    1276           0 :   if (vpx_codec_control(decoder_, VP8_COPY_REFERENCE, ref_frame_) !=
    1277             :       VPX_CODEC_OK) {
    1278           0 :     return -1;
    1279             :   }
    1280           0 :   if (vpx_codec_control(copy->decoder_, VP8_SET_REFERENCE, ref_frame_) !=
    1281             :       VPX_CODEC_OK) {
    1282           0 :     return -1;
    1283             :   }
    1284           0 :   return 0;
    1285             : }
    1286             : 
    1287             : }  // namespace webrtc

Generated by: LCOV version 1.13