Skip to content

Commit

Permalink
Expose av_display_rotation_get
Browse files Browse the repository at this point in the history
  • Loading branch information
lgeiger committed Dec 5, 2024
1 parent 382ea86 commit 14203e1
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 0 deletions.
1 change: 1 addition & 0 deletions av/video/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .frame import VideoFrame
from .stream import VideoStream
from . import display
16 changes: 16 additions & 0 deletions av/video/display.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from av.sidedata.sidedata import SideData

def get_display_rotation(matrix: SideData) -> float:
"""Extract the rotation component of the `DISPLAYMATRIX` transformation matrix.
Args:
matrix (SideData): The transformation matrix.
Returns:
float: The angle (in degrees) by which the transformation rotates the frame
counterclockwise. The angle will be in range [-180.0, 180.0].
Note:
Floating point numbers are inherently inexact, so callers are
recommended to round the return value to the nearest integer before use.
"""
17 changes: 17 additions & 0 deletions av/video/display.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cimport libav as lib
from libc.stdint cimport int32_t

import numpy as np

from av.sidedata.sidedata import SideData
from av.sidedata.sidedata import Type as SideDataType


def get_display_rotation(matrix):
if not isinstance(matrix, SideData) or matrix.type != SideDataType.DISPLAYMATRIX:
raise ValueError("Matrix must be `SideData` of type `DISPLAYMATRIX`")
cdef const int32_t[:] view = np.frombuffer(matrix, dtype=np.int32)
if view.shape[0] != 9:
raise ValueError("Matrix must be 3x3 represented as a 9-element array")
return lib.av_display_rotation_get(&view[0])

3 changes: 3 additions & 0 deletions include/libavutil/avutil.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ from libc.stdint cimport int64_t, uint8_t, uint64_t, int32_t
cdef extern from "libavutil/mathematics.h" nogil:
pass

cdef extern from "libavutil/display.h" nogil:
cdef double av_display_rotation_get(const int32_t matrix[9])

cdef extern from "libavutil/rational.h" nogil:
cdef int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)

Expand Down
13 changes: 13 additions & 0 deletions tests/test_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,16 @@ def test_flush_decoded_video_frame_count(self) -> None:
output_count += 1

assert output_count == input_count

def test_no_side_data(self):
container = av.open(fate_suite("h264/interlaced_crop.mp4"))
frame = next(container.decode(video=0))
matrix = frame.side_data.get(av.sidedata.sidedata.Type.DISPLAYMATRIX)
assert matrix is None

def test_side_data(self):
container = av.open(fate_suite("mov/displaymatrix.mov"))
frame = next(container.decode(video=0))
matrix = frame.side_data.get(av.sidedata.sidedata.Type.DISPLAYMATRIX)
rotation = av.video.display.get_display_rotation(matrix)
self.assertEqual(rotation, -90.0)

0 comments on commit 14203e1

Please sign in to comment.