Skip to content

Commit

Permalink
Add VideoFrame.rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
lgeiger authored Dec 9, 2024
1 parent 6839e9f commit 6eaf701
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 2 deletions.
2 changes: 2 additions & 0 deletions av/sidedata/sidedata.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ cdef class SideData(Buffer):

cdef SideData wrap_side_data(Frame frame, int index)

cdef int get_display_rotation(Frame frame)

cdef class _SideDataContainer:
cdef Frame frame

Expand Down
12 changes: 10 additions & 2 deletions av/sidedata/sidedata.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from libc.stdint cimport int32_t

from collections.abc import Mapping
from enum import Enum

Expand Down Expand Up @@ -45,13 +47,19 @@ class Type(Enum):


cdef SideData wrap_side_data(Frame frame, int index):
cdef lib.AVFrameSideDataType type_ = frame.ptr.side_data[index].type
if type_ == lib.AV_FRAME_DATA_MOTION_VECTORS:
if frame.ptr.side_data[index].type == lib.AV_FRAME_DATA_MOTION_VECTORS:
return MotionVectors(_cinit_bypass_sentinel, frame, index)
else:
return SideData(_cinit_bypass_sentinel, frame, index)


cdef int get_display_rotation(Frame frame):
for i in range(frame.ptr.nb_side_data):
if frame.ptr.side_data[i].type == lib.AV_FRAME_DATA_DISPLAYMATRIX:
return int(lib.av_display_rotation_get(<const int32_t *>frame.ptr.side_data[i].data))
return 0


cdef class SideData(Buffer):
def __init__(self, sentinel, Frame frame, int index):
if sentinel is not _cinit_bypass_sentinel:
Expand Down
2 changes: 2 additions & 0 deletions av/video/frame.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class VideoFrame(Frame):
def height(self) -> int: ...
@property
def interlaced_frame(self) -> bool: ...
@property
def rotation(self) -> int: ...
def __init__(
self, width: int = 0, height: int = 0, format: str = "yuv420p"
) -> None: ...
Expand Down
11 changes: 11 additions & 0 deletions av/video/frame.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ from enum import IntEnum
from libc.stdint cimport uint8_t

from av.error cimport err_check
from av.sidedata.sidedata cimport get_display_rotation
from av.utils cimport check_ndarray
from av.video.format cimport get_pix_fmt, get_video_format
from av.video.plane cimport VideoPlane
Expand Down Expand Up @@ -172,6 +173,16 @@ cdef class VideoFrame(Frame):
"""Height of the image, in pixels."""
return self.ptr.height

@property
def rotation(self):
"""The rotation component of the `DISPLAYMATRIX` transformation matrix.
Returns:
int: The angle (in degrees) by which the transformation rotates the frame
counterclockwise. The angle will be in range [-180, 180].
"""
return get_display_rotation(self)

@property
def interlaced_frame(self):
"""Is this frame an interlaced or progressive?"""
Expand Down
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
10 changes: 10 additions & 0 deletions tests/test_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,13 @@ def test_flush_decoded_video_frame_count(self) -> None:
output_count += 1

assert output_count == input_count

def test_no_side_data(self) -> None:
container = av.open(fate_suite("h264/interlaced_crop.mp4"))
frame = next(container.decode(video=0))
assert frame.rotation == 0

def test_side_data(self) -> None:
container = av.open(fate_suite("mov/displaymatrix.mov"))
frame = next(container.decode(video=0))
assert frame.rotation == -90

0 comments on commit 6eaf701

Please sign in to comment.