Skip to content

Commit 14203e1

Browse files
committed
Expose av_display_rotation_get
1 parent 382ea86 commit 14203e1

5 files changed

Lines changed: 50 additions & 0 deletions

File tree

av/video/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from .frame import VideoFrame
22
from .stream import VideoStream
3+
from . import display

av/video/display.pyi

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from av.sidedata.sidedata import SideData
2+
3+
def get_display_rotation(matrix: SideData) -> float:
4+
"""Extract the rotation component of the `DISPLAYMATRIX` transformation matrix.
5+
6+
Args:
7+
matrix (SideData): The transformation matrix.
8+
9+
Returns:
10+
float: The angle (in degrees) by which the transformation rotates the frame
11+
counterclockwise. The angle will be in range [-180.0, 180.0].
12+
13+
Note:
14+
Floating point numbers are inherently inexact, so callers are
15+
recommended to round the return value to the nearest integer before use.
16+
"""

av/video/display.pyx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
cimport libav as lib
2+
from libc.stdint cimport int32_t
3+
4+
import numpy as np
5+
6+
from av.sidedata.sidedata import SideData
7+
from av.sidedata.sidedata import Type as SideDataType
8+
9+
10+
def get_display_rotation(matrix):
11+
if not isinstance(matrix, SideData) or matrix.type != SideDataType.DISPLAYMATRIX:
12+
raise ValueError("Matrix must be `SideData` of type `DISPLAYMATRIX`")
13+
cdef const int32_t[:] view = np.frombuffer(matrix, dtype=np.int32)
14+
if view.shape[0] != 9:
15+
raise ValueError("Matrix must be 3x3 represented as a 9-element array")
16+
return lib.av_display_rotation_get(&view[0])
17+

include/libavutil/avutil.pxd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ from libc.stdint cimport int64_t, uint8_t, uint64_t, int32_t
44
cdef extern from "libavutil/mathematics.h" nogil:
55
pass
66

7+
cdef extern from "libavutil/display.h" nogil:
8+
cdef double av_display_rotation_get(const int32_t matrix[9])
9+
710
cdef extern from "libavutil/rational.h" nogil:
811
cdef int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
912

tests/test_decode.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,16 @@ def test_flush_decoded_video_frame_count(self) -> None:
155155
output_count += 1
156156

157157
assert output_count == input_count
158+
159+
def test_no_side_data(self):
160+
container = av.open(fate_suite("h264/interlaced_crop.mp4"))
161+
frame = next(container.decode(video=0))
162+
matrix = frame.side_data.get(av.sidedata.sidedata.Type.DISPLAYMATRIX)
163+
assert matrix is None
164+
165+
def test_side_data(self):
166+
container = av.open(fate_suite("mov/displaymatrix.mov"))
167+
frame = next(container.decode(video=0))
168+
matrix = frame.side_data.get(av.sidedata.sidedata.Type.DISPLAYMATRIX)
169+
rotation = av.video.display.get_display_rotation(matrix)
170+
self.assertEqual(rotation, -90.0)

0 commit comments

Comments
 (0)