From patchwork Wed Apr 4 15:30:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vittorio Giovara X-Patchwork-Id: 8329 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.1.70 with SMTP id c67csp5018269jad; Wed, 4 Apr 2018 08:37:04 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+/SaPUPAbgk8Q2R6FoHweeh30vbpcKdTaw4ANFKOITIBH14YGH1ur6v82zK/waGazXrrkD X-Received: by 10.28.87.73 with SMTP id l70mr8421660wmb.123.1522856224091; Wed, 04 Apr 2018 08:37:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522856224; cv=none; d=google.com; s=arc-20160816; b=hin7MslE6WeYgWKFDWJP0saNaDZvY0cubPI391KyC3/Qg+uyFsYnOyjPbsO7I1luPi PHVMqE86lCxEo+QCOzPpYCKkzViB4DCXnJ1KBulIzCs0HRfym8rYVVFmnbchzs0LNBD4 aFZaoAXFN7CEmjEWS/BVE06UGPIStzv37S5MkyX9JYRc/XoGjRD4qdcn4OQ0zNkd76RZ m5aiHC5cTlVmO0sD54sJjsr8UvYt0hMypyOfDawK8sV/spKkt40q+4MoMXdM/aU2HCY0 MyX/cr26C2z/H3hb6QGxgnYdBtIEqyVjDZoJctyDC/aENhsDo9YZJ9EY81rrb1+xYWC9 0UOw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to:arc-authentication-results; bh=HOw+2K/vn/3uaAwehSji/9+BIUZfXl9P5iLpbJzRQQU=; b=lGiBGs/gu7nKb8DVYMSgMbXbktawB5NLBsh0kuqMCNROFUBFnNrZ9H2Kk5rozPpx/A 5QQQN+ScA/2kEgpiz/P+5WHGrRiv6F6ldOqwzJzhBlH0SO33plLP2GgdcZvpb8tZV8S5 KmpxzCBMhWCWijd+nNQv+VHe/viL68rlZEmlePD1mbIL0Kwm4vHA+jWqwJF24+rRBJ5M YmiK08tknfQ4tn/+mT1mVKggkA1YH2WAIuacbLYBvwgC9ml1GbQ0EtqjjTY3QaImWcss 3g3Zt+7XzTt9Fj1Qrc6E/bWQzYcqKqheDeNRbaZBHHc984v88A0KojaMFZSII+xbhk6c jqfA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=hP9iwzIB; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id f6si2214385wre.431.2018.04.04.08.37.03; Wed, 04 Apr 2018 08:37:04 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=hP9iwzIB; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 743D668996D; Wed, 4 Apr 2018 18:36:40 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt0-f171.google.com (mail-qt0-f171.google.com [209.85.216.171]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BCDD5689734 for ; Wed, 4 Apr 2018 18:36:33 +0300 (EEST) Received: by mail-qt0-f171.google.com with SMTP id l18so23563080qtj.1 for ; Wed, 04 Apr 2018 08:36:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=ECL/G5zb40h+kXaILFfutjTm+JToFGJ8iLRI5u/RrwE=; b=hP9iwzIBKv/K8hvN7Hyb537QDWEv75hi2vyAgQhY1lnJbLEYUyj5xj7fAhV9seyBry YipIEWx7yju+4ltl+Dpubwg9lkDRMgGGI/VMe17fynKhtAgZlbuYKaONNOXJtcy5L4Vd rI2nWbcN2cOeU0jO/sx8+50yeOBz8AhitHk3FyCKHAQaaNzuHQqngOg2E6cJJRx9tIM0 DP2lOj1UwGdM7AGeixCHpsLAhz7dRiIJ29TPILAFLrvDwxuc7cd6NJJBd+JTM59tm8wA Fa8dFiALjKrWijGXKPoOSuP+G/0TpwuWCo3wa+ySNW9VrDvZVfeiLnc96tI+V3ty7Qev uOlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=ECL/G5zb40h+kXaILFfutjTm+JToFGJ8iLRI5u/RrwE=; b=VmyC+fzbD0YA5x2fR1iNeD0HhV3mYsuU7bmql3q0af/KDo3DnVX1qauMvIPeRUyYOg 0+dS6SgJBK1CMdWVmsPkqD8hgrYyezbOO7dcjLdugD3ptgq+YI2SDRl/3CKP7SEKsJHQ /hrROJKCSsveZxKCQ10s12JkfFDa+akcleLTrg9yn8CFwOfH2rynkSsmAn86APbLCVMg po2LsmWHRfHBPe4rCUSc/CENcv0iUAcgDCzp1yCmuQtXbzaSNRpHxTdK9OzT1memlWGU tslHpDAl8/LGravTjI4fT5FSJOXarXuae5I6feD7Ol1mkTq3nppoGVEboX7XRQPU2RmG Gjcw== X-Gm-Message-State: ALQs6tCC3BujCoQSNDFLo8sQVG0CDeJ8kmTqf9Qd4CVm+9y/vmy0qe7A xZOIyzRur3j00wUT7LZ65RCTQA== X-Received: by 10.237.45.68 with SMTP id h62mr27996271qtd.179.1522855827428; Wed, 04 Apr 2018 08:30:27 -0700 (PDT) Received: from vimacbookpro.vimeo.iac.corp (93-36-167-184.ip61.fastwebnet.it. [93.36.167.184]) by smtp.gmail.com with ESMTPSA id z50sm4500844qtj.92.2018.04.04.08.30.26 for (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 04 Apr 2018 08:30:26 -0700 (PDT) From: Vittorio Giovara To: ffmpeg-devel@ffmpeg.org Date: Wed, 4 Apr 2018 17:30:24 +0200 Message-Id: <20180404153024.56015-1-vittorio.giovara@gmail.com> X-Mailer: git-send-email 2.16.2 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] display: Add AVDisplayOrientation API X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" The transformation operations that can be described by a display matrix are not limited to pure rotation, but include horizontal and vertical flip, as well as transpose and antitranspose. Unfortunately the current API can only return a rotation angle in degrees, and is not designed to detect flip operations or a combination of rotation and flip. So implement an additional API to analyze the display matrix and return the most common rotation operations (multiples of 90º) as well flips or a combination thereof. This function returns a bitfield mask composed of AVDisplayOrientation elements that describe which rendering operations should be performed on the frame. The existing API is still available and useful in case of custom rotations. Signed-off-by: Vittorio Giovara --- Note: the new operations describe a clockwise rotation, while the old API provided a counterclockwise rotation. I always felt this was a mistake as it's counterintuitive and suprising to new users, so I didn't want to cargo-cult it to a new API. What do people think about it? See also https://github.com/FFMS/ffms2/issues/317 for flipped samples, code, and additional discussion. Missing changelog entry and version bump. Vittorio libavutil/display.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/display.h | 53 ++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/libavutil/display.c b/libavutil/display.c index f7500948ff..839961ec20 100644 --- a/libavutil/display.c +++ b/libavutil/display.c @@ -22,6 +22,7 @@ #include #include +#include "avstring.h" #include "display.h" #include "mathematics.h" @@ -73,3 +74,94 @@ void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip) for (i = 0; i < 9; i++) matrix[i] *= flip[i % 3]; } + +uint32_t av_display_orientation_get(int32_t matrix_src[9]) +{ + int32_t matrix[9]; + uint32_t orientation = 0; + int64_t det = (int64_t)matrix_src[0] * matrix_src[4] - (int64_t)matrix_src[1] * matrix_src[3]; + + /* Duplicate matrix so that the input one is not modified in case of flip. */ + memcpy(matrix, matrix_src, sizeof(*matrix_src) * 9); + + if (det < 0) { + /* Always assume an horizontal flip for simplicity, it can be + * changed later if rotation is 180º. */ + orientation = AV_FLIP_HORIZONTAL; + av_display_matrix_flip(matrix, 1, 0); + } + + if (matrix[1] == (1 << 16) && matrix[3] == -(1 << 16)) { + orientation |= AV_ROTATION_90; + } else if (matrix[0] == -(1 << 16) && matrix[4] == -(1 << 16)) { + if (det < 0) + orientation = AV_FLIP_VERTICAL; + else + orientation |= AV_ROTATION_180; + } else if (matrix[1] == -(1 << 16) && matrix[3] == (1 << 16)) { + orientation |= AV_ROTATION_270; + } else if (matrix[0] == (1 << 16) && matrix[4] == (1 << 16)) { + orientation |= AV_IDENTITY; + } else { + orientation |= AV_ROTATION_CUSTOM; + } + + return orientation; +} + +void av_display_orientation_set(int32_t matrix[9], uint32_t orientation, double angle) +{ + int hflip = !!(orientation & AV_FLIP_HORIZONTAL); + int vflip = !!(orientation & AV_FLIP_VERTICAL); + + memset(matrix, 0, sizeof(*matrix) * 9); + matrix[8] = 1 << 30; + + if (orientation & AV_IDENTITY) { + matrix[0] = 1 << 16; + matrix[4] = 1 << 16; + } else if (orientation & AV_ROTATION_90) { + matrix[1] = 1 << 16; + matrix[3] = -(1 << 16); + } else if (orientation & AV_ROTATION_180) { + matrix[0] = -(1 << 16); + matrix[4] = -(1 << 16); + } else if (orientation & AV_ROTATION_270) { + matrix[1] = -(1 << 16); + matrix[3] = 1 << 16; + } else if (orientation & AV_ROTATION_CUSTOM) { + av_display_rotation_set(matrix, angle); + } + + av_display_matrix_flip(matrix, hflip, vflip); +} + +void av_display_orientation_name(uint32_t orientation, char *buf, size_t buf_size) +{ + if (orientation == 0) { + av_strlcpy(buf, "identity", buf_size); + return; + } + + if (orientation & AV_ROTATION_90) + av_strlcpy(buf, "rotation_90", buf_size); + else if (orientation & AV_ROTATION_180) + av_strlcpy(buf, "rotation_180", buf_size); + else if (orientation & AV_ROTATION_270) + av_strlcpy(buf, "rotation_270", buf_size); + else if (orientation & AV_ROTATION_CUSTOM) + av_strlcpy(buf, "rotation_custom", buf_size); + else + buf[0] = '\0'; + + if (orientation & AV_FLIP_HORIZONTAL) { + if (buf[0] != '\0') + av_strlcat(buf, "+", buf_size); + av_strlcat(buf, "hflip", buf_size); + } + if (orientation & AV_FLIP_VERTICAL) { + if (buf[0] != '\0') + av_strlcat(buf, "+", buf_size); + av_strlcat(buf, "vflip", buf_size); + } +} diff --git a/libavutil/display.h b/libavutil/display.h index 2d869fcd16..a057453b20 100644 --- a/libavutil/display.h +++ b/libavutil/display.h @@ -27,6 +27,7 @@ #define AVUTIL_DISPLAY_H #include +#include /** * @addtogroup lavu_video @@ -105,6 +106,58 @@ void av_display_rotation_set(int32_t matrix[9], double angle); */ void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); +enum AVDisplayOrientation { + /** There is no orientation operation to be performed on the frame. */ + AV_IDENTITY = 0, + /** Apply a 90º clockwise rotation on the frame. */ + AV_ROTATION_90 = 1 << 0, + /** Apply a 180º clockwise rotation on the frame. */ + AV_ROTATION_180 = 1 << 1, + /** Apply a 270º clockwise rotation on the frame. */ + AV_ROTATION_270 = 1 << 2, + /** + * Apply a custom rotation on the frame. Users may inspect the input matrix + * with av_display_rotation_get() to know the degree amount. + * + * @note av_display_rotation_get() returns a counterclockwise angle. + */ + AV_ROTATION_CUSTOM = 1 << 3, + /** Apply a horizontal flip on the frame. */ + AV_FLIP_HORIZONTAL = 1 << 4, + /** Apply a vertical flip on the frame. */ + AV_FLIP_VERTICAL = 1 << 5, +}; + +/** + * Return a mask composed of AVDisplayOrientation elements describing the list + * of operations to be performed on the rendered video frame from a given + * transformation matrix. + * + * @param matrix an allocated transformation matrix + * @return a set of AVDisplayOrientation operations + */ +uint32_t av_display_orientation_get(int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a set of AVDisplayOrientation + * operations. If a custom rotation is desired, it is possible to set the rotation + * angle as optional parameter. + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param orientation a set of AVDisplayOrientation operations + * @param angle counterclockwise rotation angle in degrees + */ +void av_display_orientation_set(int32_t matrix[9], uint32_t orientation, double angle); + +/** + * Return a human readable description of the input AVDisplayOrientation set. + * + * @param orientation a set of AVDisplayOrientation operations + * @param buf a user-allocated buffer that will contain the returned string + * @param buf_size size in bytes of the buffer + */ +void av_display_orientation_name(uint32_t orientation, char *buf, size_t size); /** * @} * @}