blob: 65529a880a3cbd6d9ab7d111075c7d6eafe051d6 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/video_transformation.h"
#include <math.h>
#include <stddef.h>
#include "base/logging.h"
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
namespace media {
namespace {
template <size_t decimal_bits>
double FixedToFloatingPoint(int32_t i) {
return i / static_cast<double>(1 << decimal_bits);
}
} // namespace
std::string VideoRotationToString(VideoRotation rotation) {
switch (rotation) {
case VIDEO_ROTATION_0:
return "0°";
case VIDEO_ROTATION_90:
return "90°";
case VIDEO_ROTATION_180:
return "180°";
case VIDEO_ROTATION_270:
return "270°";
}
NOTREACHED();
return "";
}
bool operator==(const struct VideoTransformation& first,
const struct VideoTransformation& second) {
return first.rotation == second.rotation && first.mirrored == second.mirrored;
}
// static
VideoTransformation VideoTransformation::FromFFmpegDisplayMatrix(
int32_t* matrix3x3) {
int32_t matrix2x2[4] = {
matrix3x3[0],
matrix3x3[1],
matrix3x3[3],
matrix3x3[4],
};
return VideoTransformation(matrix2x2);
}
VideoTransformation::VideoTransformation(int32_t matrix[4]) {
// Rotation by angle Θ is represented in the matrix as:
// [ cos(Θ), -sin(Θ)]
// [ sin(Θ), cos(Θ)]
// A vertical flip is represented by the cosine's having opposite signs
// and a horizontal flip is represented by the sine's having the same sign.
// Check the matrix for validity
if (abs(matrix[0]) != abs(matrix[3]) || abs(matrix[1]) != abs(matrix[2])) {
rotation = VIDEO_ROTATION_0;
mirrored = false;
return;
}
double angle =
acos(FixedToFloatingPoint<16>(matrix[0])) * 180 / base::kPiDouble;
double check_angle =
asin(FixedToFloatingPoint<16>(matrix[1])) * 180 / base::kPiDouble;
double offset = abs(abs(angle) - abs(check_angle));
while (offset >= 180.0)
offset -= 180.0;
if (offset > 1e-3) {
rotation = VIDEO_ROTATION_0;
mirrored = false;
return;
}
// Calculate angle offsets for rotation - rotating about the X axis
// can be expressed as a 180 degree rotation and a Y axis rotation
mirrored = false;
if (matrix[0] != matrix[3] && matrix[0] != 0) {
mirrored = !mirrored;
angle += 180;
}
if (matrix[1] == matrix[3] && matrix[1] != 0) {
mirrored = !mirrored;
}
// Normalize the angle
while (angle < 0)
angle += 360;
while (angle >= 360)
angle -= 360;
// 16 bits of fixed point decimal is enough to give 6 decimals of precision
// to cos(Θ). A delta of ±0.000001 causes acos(cos(Θ)) to differ by a minimum
// of 0.0002, which is why we only need to check that the angle is only
// accurate to within four decimal places. This is preferred to checking for
// a more precise accuracy, as the 'double' type is architecture dependent and
// there may be variance in floating point errors.
if (abs(angle - 0) < 1e-4) {
rotation = VIDEO_ROTATION_0;
} else if (abs(angle - 180) < 1e-4) {
rotation = VIDEO_ROTATION_180;
} else if (abs(angle - 90) < 1e-4) {
rotation = (check_angle > 0) ? VIDEO_ROTATION_90 : VIDEO_ROTATION_270;
} else {
rotation = VIDEO_ROTATION_0;
mirrored = false;
}
}
} // namespace media