[FFmpeg-devel] [PATCH] display: Add AVDisplayOrientation API

Sasi Inguva isasi at google.com
Thu Apr 5 08:44:04 EEST 2018


On Wed, Apr 4, 2018 at 8:30 AM, Vittorio Giovara <vittorio.giovara at gmail.com
> wrote:

> 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 <vittorio.giovara at gmail.com>
> ---
> 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?
>
i am more used to counter-clockwise angle representation just like
zero-indexing, but either way is fine with me.


> 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 <string.h>
>  #include <math.h>
>
> +#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);
> +    }
>
The order of the FLIP and rotation are important. While computing flip , we
are assuming that FLIP is applied first, and then rotation. So while
showing the name also, flip should be shown first and then rotation.

> +    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 <stdint.h>
> +#include <stddef.h>
>
>  /**
>   * @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. */
>
Comment should also state that FLIP should be applied before rotation.


> +    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);
>  /**
>   * @}
>   * @}
> --
> 2.16.2
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>


More information about the ffmpeg-devel mailing list