blob: d5a9d8823774705a5af3997f38ded8feac422010 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/video_aspect_ratio.h"
#include <cmath>
#include <limits>
namespace media {
VideoAspectRatio::VideoAspectRatio(Type type, int width, int height) {
type_ = type;
aspect_ratio_ = height ? static_cast<double>(width) / height : 0.0;
}
// static
VideoAspectRatio VideoAspectRatio::PAR(int width, int height) {
return VideoAspectRatio(Type::kPixel, width, height);
}
// static
VideoAspectRatio VideoAspectRatio::DAR(int width, int height) {
return VideoAspectRatio(Type::kDisplay, width, height);
}
VideoAspectRatio::VideoAspectRatio(const gfx::Rect& visible_rect,
const gfx::Size& natural_size) {
// The size of a pixel is:
// (natural_width / visible_width) by (natural_height / visible_height).
// Both are multiplied by (visible_width * visible_height) to avoid division.
// WARNING: Cast before multiply is necessary to prevent overflow.
double w = static_cast<double>(visible_rect.height()) * natural_size.width();
double h = static_cast<double>(visible_rect.width()) * natural_size.height();
type_ = Type::kPixel;
aspect_ratio_ = h != 0.0 ? w / h : 0.0;
}
bool VideoAspectRatio::IsValid() const {
return std::isfinite(aspect_ratio_) && aspect_ratio_ > 0.0;
}
gfx::Size VideoAspectRatio::GetNaturalSize(
const gfx::Rect& visible_rect) const {
if (!IsValid() || visible_rect.IsEmpty())
return visible_rect.size();
// Cast up front to simplify expressions.
// WARNING: Some aspect ratios can result in sizes that exceed INT_MAX.
double w = visible_rect.width();
double h = visible_rect.height();
switch (type_) {
case Type::kDisplay:
if (aspect_ratio_ >= w / h) {
// Display aspect is wider, grow width.
w = h * aspect_ratio_;
} else {
// Display aspect is narrower, grow height.
h = w / aspect_ratio_;
}
break;
case Type::kPixel:
if (aspect_ratio_ >= 1.0) {
// Wide pixels, grow width.
w = w * aspect_ratio_;
} else {
// Narrow pixels, grow height.
h = h / aspect_ratio_;
}
break;
}
// A valid natural size is positive (at least 1 after truncation) and fits in
// an int. Underflow should only be possible if the input sizes were already
// invalid, because the mutations above only increase the size.
w = std::round(w);
h = std::round(h);
if (w < 1.0 || w > std::numeric_limits<int>::max() || h < 1.0 ||
h > std::numeric_limits<int>::max()) {
return visible_rect.size();
}
return gfx::Size(static_cast<int>(w), static_cast<int>(h));
}
} // namespace media