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

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2010 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/media/base/videoadapter.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <cmath>
      15             : #include <cstdlib>
      16             : #include <limits>
      17             : 
      18             : #include "webrtc/base/arraysize.h"
      19             : #include "webrtc/base/checks.h"
      20             : #include "webrtc/base/logging.h"
      21             : #include "webrtc/base/optional.h"
      22             : #include "webrtc/media/base/mediaconstants.h"
      23             : #include "webrtc/media/base/videocommon.h"
      24             : 
      25             : namespace {
      26             : struct Fraction {
      27             :   int numerator;
      28             :   int denominator;
      29             : };
      30             : 
      31             : // Round |value_to_round| to a multiple of |multiple|. Prefer rounding upwards,
      32             : // but never more than |max_value|.
      33           0 : int roundUp(int value_to_round, int multiple, int max_value) {
      34             :   const int rounded_value =
      35           0 :       (value_to_round + multiple - 1) / multiple * multiple;
      36           0 :   return rounded_value <= max_value ? rounded_value
      37           0 :                                     : (max_value / multiple * multiple);
      38             : }
      39             : 
      40             : // Generates a scale factor that makes |input_num_pixels| smaller or
      41             : // larger than |target_num_pixels|, depending on the value of |step_up|.
      42           0 : Fraction FindScale(int input_num_pixels, int target_num_pixels, bool step_up) {
      43             :   // This function only makes sense for a positive target.
      44           0 :   RTC_DCHECK_GT(target_num_pixels, 0);
      45           0 :   Fraction best_scale = Fraction{1, 1};
      46           0 :   Fraction last_scale = Fraction{1, 1};
      47             :   const float target_scale =
      48           0 :       sqrt(target_num_pixels / static_cast<float>(input_num_pixels));
      49           0 :   while (best_scale.numerator > (target_scale * best_scale.denominator)) {
      50           0 :     last_scale = best_scale;
      51           0 :     if (best_scale.numerator % 3 == 0 && best_scale.denominator % 2 == 0) {
      52             :       // Multiply by 2/3
      53           0 :       best_scale.numerator /= 3;
      54           0 :       best_scale.denominator /= 2;
      55             :     } else {
      56             :       // Multiply by 3/4
      57           0 :       best_scale.numerator *= 3;
      58           0 :       best_scale.denominator *= 4;
      59             :     }
      60             :   }
      61           0 :   if (step_up)
      62           0 :     return last_scale;
      63           0 :   return best_scale;
      64             : }
      65             : }  // namespace
      66             : 
      67             : namespace cricket {
      68             : 
      69           0 : VideoAdapter::VideoAdapter(int required_resolution_alignment)
      70             :     : frames_in_(0),
      71             :       frames_out_(0),
      72             :       frames_scaled_(0),
      73             :       adaption_changes_(0),
      74             :       previous_width_(0),
      75             :       previous_height_(0),
      76             :       required_resolution_alignment_(required_resolution_alignment),
      77           0 :       resolution_request_max_pixel_count_(std::numeric_limits<int>::max()),
      78           0 :       step_up_(false) {}
      79             : 
      80           0 : VideoAdapter::VideoAdapter() : VideoAdapter(1) {}
      81             : 
      82           0 : VideoAdapter::~VideoAdapter() {}
      83             : 
      84           0 : bool VideoAdapter::KeepFrame(int64_t in_timestamp_ns) {
      85           0 :   rtc::CritScope cs(&critical_section_);
      86           0 :   if (!requested_format_ || requested_format_->interval == 0)
      87           0 :     return true;
      88             : 
      89           0 :   if (next_frame_timestamp_ns_) {
      90             :     // Time until next frame should be outputted.
      91             :     const int64_t time_until_next_frame_ns =
      92           0 :         (*next_frame_timestamp_ns_ - in_timestamp_ns);
      93             : 
      94             :     // Continue if timestamp is withing expected range.
      95           0 :     if (std::abs(time_until_next_frame_ns) < 2 * requested_format_->interval) {
      96             :       // Drop if a frame shouldn't be outputted yet.
      97           0 :       if (time_until_next_frame_ns > 0)
      98           0 :         return false;
      99             :       // Time to output new frame.
     100           0 :       *next_frame_timestamp_ns_ += requested_format_->interval;
     101           0 :       return true;
     102             :     }
     103             :   }
     104             : 
     105             :   // First timestamp received or timestamp is way outside expected range, so
     106             :   // reset. Set first timestamp target to just half the interval to prefer
     107             :   // keeping frames in case of jitter.
     108             :   next_frame_timestamp_ns_ =
     109           0 :       rtc::Optional<int64_t>(in_timestamp_ns + requested_format_->interval / 2);
     110           0 :   return true;
     111             : }
     112             : 
     113           0 : bool VideoAdapter::AdaptFrameResolution(int in_width,
     114             :                                         int in_height,
     115             :                                         int64_t in_timestamp_ns,
     116             :                                         int* cropped_width,
     117             :                                         int* cropped_height,
     118             :                                         int* out_width,
     119             :                                         int* out_height) {
     120           0 :   rtc::CritScope cs(&critical_section_);
     121           0 :   ++frames_in_;
     122             : 
     123             :   // The max output pixel count is the minimum of the requests from
     124             :   // OnOutputFormatRequest and OnResolutionRequest.
     125           0 :   int max_pixel_count = resolution_request_max_pixel_count_;
     126           0 :   if (requested_format_) {
     127             :     // TODO(kthelgason): remove the - |step_up_| hack when we change how
     128             :     // resolution is requested from VideoSourceProxy.
     129             :     // This is required because we must not scale above the requested
     130             :     // format so we subtract one when scaling up.
     131           0 :     max_pixel_count = std::min(
     132           0 :         max_pixel_count, requested_format_->width * requested_format_->height -
     133           0 :                              static_cast<int>(step_up_));
     134             :   }
     135           0 :   if (scale_) {
     136           0 :     if (max_pixel_count == std::numeric_limits<int>::max()) {
     137           0 :       max_pixel_count = in_width * in_height;
     138             :     }
     139             :     // approximates (width/scale_resolution_by_) * (height/scale_resolution_by_)
     140           0 :     max_pixel_count = (max_pixel_count / scale_resolution_by_) / scale_resolution_by_;
     141             :   }
     142             : 
     143             :   // Drop the input frame if necessary.
     144           0 :   if (max_pixel_count <= 0 || !KeepFrame(in_timestamp_ns)) {
     145             :     // Show VAdapt log every 90 frames dropped. (3 seconds)
     146           0 :     if ((frames_in_ - frames_out_) % 90 == 0) {
     147             :       // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
     148             :       // in default calls.
     149           0 :       LOG(LS_INFO) << "VAdapt Drop Frame: scaled " << frames_scaled_
     150           0 :                    << " / out " << frames_out_
     151           0 :                    << " / in " << frames_in_
     152           0 :                    << " Changes: " << adaption_changes_
     153           0 :                    << " Input: " << in_width
     154           0 :                    << "x" << in_height
     155           0 :                    << " timestamp: " << in_timestamp_ns
     156           0 :                    << " Output: i"
     157           0 :                    << (requested_format_ ? requested_format_->interval : 0);
     158             :     }
     159             : 
     160             :     // Drop frame.
     161           0 :     return false;
     162             :   }
     163             : 
     164             :   // Calculate how the input should be cropped.
     165           0 :   if (!requested_format_ ||
     166           0 :       requested_format_->width == 0 || requested_format_->height == 0) {
     167           0 :     *cropped_width = in_width;
     168           0 :     *cropped_height = in_height;
     169             :   } else {
     170             :     // Adjust |requested_format_| orientation to match input.
     171           0 :     if ((in_width > in_height) !=
     172           0 :         (requested_format_->width > requested_format_->height)) {
     173           0 :       std::swap(requested_format_->width, requested_format_->height);
     174             :     }
     175             :     const float requested_aspect =
     176           0 :       requested_format_->width /
     177           0 :       static_cast<float>(requested_format_->height);
     178           0 :     *cropped_width =
     179           0 :       std::min(in_width, static_cast<int>(in_height * requested_aspect));
     180           0 :     *cropped_height =
     181           0 :       std::min(in_height, static_cast<int>(in_width / requested_aspect));
     182             :   }
     183             :   const Fraction scale =
     184           0 :       FindScale(*cropped_width * *cropped_height, max_pixel_count, step_up_);
     185             :   // Adjust cropping slightly to get even integer output size and a perfect
     186             :   // scale factor. Make sure the resulting dimensions are aligned correctly
     187             :   // to be nice to hardware encoders.
     188           0 :   *cropped_width =
     189           0 :       roundUp(*cropped_width,
     190           0 :               scale.denominator * required_resolution_alignment_, in_width);
     191           0 :   *cropped_height =
     192           0 :       roundUp(*cropped_height,
     193           0 :               scale.denominator * required_resolution_alignment_, in_height);
     194           0 :   RTC_DCHECK_EQ(0, *cropped_width % scale.denominator);
     195           0 :   RTC_DCHECK_EQ(0, *cropped_height % scale.denominator);
     196             : 
     197             :   // Calculate final output size.
     198           0 :   *out_width = *cropped_width / scale.denominator * scale.numerator;
     199           0 :   *out_height = *cropped_height / scale.denominator * scale.numerator;
     200           0 :   RTC_DCHECK_EQ(0, *out_height % required_resolution_alignment_);
     201           0 :   RTC_DCHECK_EQ(0, *out_height % required_resolution_alignment_);
     202             : 
     203           0 :   ++frames_out_;
     204           0 :   if (scale.numerator != scale.denominator)
     205           0 :     ++frames_scaled_;
     206             : 
     207           0 :   if ((previous_width_ || scale_) && (previous_width_ != *out_width ||
     208           0 :                                       previous_height_ != *out_height)) {
     209           0 :     ++adaption_changes_;
     210           0 :     LOG(LS_INFO) << "Frame size changed: scaled " << frames_scaled_ << " / out "
     211           0 :                  << frames_out_ << " / in " << frames_in_
     212           0 :                  << " Changes: " << adaption_changes_ << " Input: " << in_width
     213           0 :                  << "x" << in_height
     214           0 :                  << " Scale: " << scale.numerator << "/" << scale.denominator
     215           0 :                  << " Output: " << *out_width << "x" << *out_height << " i"
     216           0 :                  << (requested_format_ ? requested_format_->interval : 0);
     217             :   }
     218             : 
     219           0 :   previous_width_ = *out_width;
     220           0 :   previous_height_ = *out_height;
     221             : 
     222           0 :   return true;
     223             : }
     224             : 
     225           0 : void VideoAdapter::OnOutputFormatRequest(const VideoFormat& format) {
     226           0 :   rtc::CritScope cs(&critical_section_);
     227           0 :   requested_format_ = rtc::Optional<VideoFormat>(format);
     228           0 :   next_frame_timestamp_ns_ = rtc::Optional<int64_t>();
     229           0 : }
     230             : 
     231           0 : void VideoAdapter::OnResolutionRequest(
     232             :     rtc::Optional<int> max_pixel_count,
     233             :     rtc::Optional<int> max_pixel_count_step_up) {
     234           0 :   rtc::CritScope cs(&critical_section_);
     235           0 :   resolution_request_max_pixel_count_ = max_pixel_count.value_or(
     236           0 :       max_pixel_count_step_up.value_or(std::numeric_limits<int>::max()));
     237           0 :   step_up_ = static_cast<bool>(max_pixel_count_step_up);
     238           0 : }
     239             : 
     240           0 : void VideoAdapter::OnScaleResolutionBy(
     241             :     rtc::Optional<float> scale_resolution_by) {
     242           0 :   rtc::CritScope cs(&critical_section_);
     243           0 :   scale_resolution_by_ = scale_resolution_by.value_or(1.0);
     244           0 :   RTC_DCHECK_GE(scale_resolution_by_, 1.0);
     245           0 :   scale_ = static_cast<bool>(scale_resolution_by);
     246           0 : }
     247             : 
     248             : }  // namespace cricket

Generated by: LCOV version 1.13