// 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 #include #include "base/logging.h" #include "base/notreached.h" #include "base/strings/string_number_conversions.h" namespace media { namespace { template double FixedToFloatingPoint(int32_t i) { return i / static_cast(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