Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading