On Wed, Apr 4, 2018 at 8:30 AM, Vittorio Giovara <vittorio.giov...@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.giov...@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@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel