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);
+    }
+    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. */
+    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);
 /**
  * @}
  * @}
