Skip to content

Commit 8769d13

Browse files
committed
Wrap VideoEncParams and VideoBlockParams
1 parent 17137ed commit 8769d13

6 files changed

Lines changed: 232 additions & 0 deletions

File tree

av/sidedata/encparams.pxd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cimport libav as lib
2+
3+
from av.sidedata.sidedata cimport SideData
4+
5+
6+
cdef class VideoEncParams(SideData):
7+
pass
8+
9+
10+
cdef class VideoBlockParams:
11+
cdef lib.AVVideoBlockParams *ptr

av/sidedata/encparams.pyi

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from enum import IntEnum
2+
from typing import cast
3+
4+
import numpy as np
5+
6+
class VideoEncParamsType(IntEnum):
7+
NONE = cast(int, ...)
8+
VP9 = cast(int, ...)
9+
H264 = cast(int, ...)
10+
MPEG2 = cast(int, ...)
11+
12+
class VideoEncParams:
13+
nb_blocks: int
14+
blocks_offset: int
15+
block_size: int
16+
codec_type: VideoEncParamsType
17+
qp: int
18+
delta_qp: int
19+
def block_params(self, idx: int) -> VideoBlockParams: ...
20+
def qp_map(self) -> np.ndarray[int, int]: ...
21+
22+
class VideoBlockParams:
23+
src_x: int
24+
src_y: int
25+
w: int
26+
h: int
27+
delta_qp: int

av/sidedata/encparams.pyx

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
cimport libav as lib
2+
from libc.stdint cimport uint8_t, int32_t
3+
4+
from enum import IntEnum
5+
import numpy as np
6+
7+
8+
VideoEncParamsType = IntEnum(
9+
"AVVideoEncParamsType",
10+
{
11+
"NONE": <int>lib.AV_VIDEO_ENC_PARAMS_NONE,
12+
"VP9": <int>lib.AV_VIDEO_ENC_PARAMS_VP9,
13+
"H264": <int>lib.AV_VIDEO_ENC_PARAMS_H264,
14+
"MPEG2": <int>lib.AV_VIDEO_ENC_PARAMS_MPEG2,
15+
},
16+
)
17+
18+
cdef class VideoEncParams(SideData):
19+
def __repr__(self):
20+
return f"<av.sidedata.VideoEncParams, nb_blocks={self.nb_blocks}, codec_type={self.codec_type}, qp={self.qp}>"
21+
22+
@property
23+
def nb_blocks(self):
24+
"""
25+
Number of blocks in the array
26+
May be 0, in which case no per-block information is present. In this case
27+
the values of blocks_offset / block_size are unspecified and should not
28+
be accessed.
29+
"""
30+
return (<lib.AVVideoEncParams*> self.ptr.data).nb_blocks
31+
32+
@property
33+
def blocks_offset(self):
34+
"""
35+
Offset in bytes from the beginning of this structure at which the array of blocks starts.
36+
"""
37+
return (<lib.AVVideoEncParams*> self.ptr.data).blocks_offset
38+
39+
@property
40+
def block_size(self):
41+
"""
42+
Size of each block in bytes. May not match sizeof(AVVideoBlockParams).
43+
"""
44+
return (<lib.AVVideoEncParams*> self.ptr.data).block_size
45+
46+
@property
47+
def codec_type(self):
48+
"""
49+
Type of the parameters (the codec they are used with).
50+
"""
51+
cdef lib.AVVideoEncParamsType t = (<lib.AVVideoEncParams*> self.ptr.data).type
52+
return VideoEncParamsType(<int>t)
53+
54+
@property
55+
def qp(self):
56+
"""
57+
Base quantisation parameter for the frame. The final quantiser for a
58+
given block in a given plane is obtained from this value, possibly
59+
combined with `delta_qp` and the per-block delta in a manner
60+
documented for each type.
61+
"""
62+
return (<lib.AVVideoEncParams*> self.ptr.data).qp
63+
64+
@property
65+
def delta_qp(self):
66+
"""
67+
Quantisation parameter offset from the base (per-frame) qp for a given
68+
plane (first index) and AC/DC coefficients (second index).
69+
"""
70+
cdef lib.AVVideoEncParams *p = <lib.AVVideoEncParams*> self.ptr.data
71+
return [[p.delta_qp[i][j] for j in range(2)] for i in range(4)]
72+
73+
def block_params(self, idx):
74+
"""
75+
Get the encoding parameters for a given block
76+
"""
77+
# Validate given index
78+
if idx < 0 or idx >= self.nb_blocks:
79+
raise ValueError("Expected idx in range [0, nb_blocks)")
80+
81+
return VideoBlockParams(self, idx)
82+
83+
def qp_map(self):
84+
"""
85+
Convenience method that creates a 2-D map with the quantization parameters per macroblock.
86+
Only for MPEG2 and H264 encoded videos.
87+
"""
88+
cdef int mb_h = (self.frame.ptr.height + 15) // 16
89+
cdef int mb_w = (self.frame.ptr.width + 15) // 16
90+
cdef int nb_mb = mb_h * mb_w
91+
cdef int block_idx
92+
cdef int y
93+
cdef int x
94+
cdef VideoBlockParams block
95+
96+
# Validate number of blocks
97+
if self.nb_blocks != nb_mb:
98+
raise RuntimeError("Expected frame size to match number of blocks in side data")
99+
100+
# Validate type
101+
cdef lib.AVVideoEncParamsType type = (<lib.AVVideoEncParams*> self.ptr.data).type
102+
if type != lib.AVVideoEncParamsType.AV_VIDEO_ENC_PARAMS_MPEG2 and type != lib.AVVideoEncParamsType.AV_VIDEO_ENC_PARAMS_H264:
103+
raise ValueError("Expected MPEG2 or H264")
104+
105+
# Create a 2-D map with the number of macroblocks
106+
cdef int32_t[:, ::1] map = np.empty((mb_h, mb_w), dtype=np.int32)
107+
108+
# Fill map with quantization parameter per macroblock
109+
for block_idx in range(nb_mb):
110+
block = VideoBlockParams(self, block_idx)
111+
y = block.src_y // 16
112+
x = block.src_x // 16
113+
map[y, x] = self.qp + block.delta_qp
114+
115+
return np.asarray(map)
116+
117+
118+
cdef class VideoBlockParams:
119+
def __init__(self, VideoEncParams video_enc_params, int idx) -> None:
120+
cdef uint8_t* base = <uint8_t*> video_enc_params.ptr.data
121+
cdef Py_ssize_t offset = video_enc_params.blocks_offset + idx * video_enc_params.block_size
122+
self.ptr = <lib.AVVideoBlockParams*> (base + offset)
123+
124+
def __repr__(self):
125+
return f"<av.sidedata.VideoBlockParams, src=({self.src_x}, {self.src_y}), size={self.w}x{self.h}, delta_qp={self.delta_qp}>"
126+
127+
@property
128+
def src_x(self):
129+
"""
130+
Horizontal distance in luma pixels from the top-left corner of the visible frame
131+
to the top-left corner of the block.
132+
Can be negative if top/right padding is present on the coded frame.
133+
"""
134+
return self.ptr.src_x
135+
136+
@property
137+
def src_y(self):
138+
"""
139+
Vertical distance in luma pixels from the top-left corner of the visible frame
140+
to the top-left corner of the block.
141+
Can be negative if top/right padding is present on the coded frame.
142+
"""
143+
return self.ptr.src_y
144+
145+
@property
146+
def w(self):
147+
"""
148+
Width of the block in luma pixels
149+
"""
150+
return self.ptr.w
151+
152+
@property
153+
def h(self):
154+
"""
155+
Height of the block in luma pixels
156+
"""
157+
return self.ptr.h
158+
159+
@property
160+
def delta_qp(self):
161+
"""
162+
Difference between this block's final quantization parameter and the
163+
corresponding per-frame value.
164+
"""
165+
return self.ptr.delta_qp

av/sidedata/sidedata.pyx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ from collections.abc import Mapping
44
from enum import Enum
55

66
from av.sidedata.motionvectors import MotionVectors
7+
from av.sidedata.encparams import VideoEncParams
78

89

910
cdef object _cinit_bypass_sentinel = object()
@@ -49,6 +50,8 @@ class Type(Enum):
4950
cdef SideData wrap_side_data(Frame frame, int index):
5051
if frame.ptr.side_data[index].type == lib.AV_FRAME_DATA_MOTION_VECTORS:
5152
return MotionVectors(_cinit_bypass_sentinel, frame, index)
53+
elif frame.ptr.side_data[index].type == lib.AV_FRAME_DATA_VIDEO_ENC_PARAMS:
54+
return VideoEncParams(_cinit_bypass_sentinel, frame, index)
5255
else:
5356
return SideData(_cinit_bypass_sentinel, frame, index)
5457

include/libav.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ include "libavutil/frame.pxd"
77
include "libavutil/hwcontext.pxd"
88
include "libavutil/samplefmt.pxd"
99
include "libavutil/motion_vector.pxd"
10+
include "libavutil/video_enc_params.pxd"
1011

1112
include "libavcodec/avcodec.pxd"
1213
include "libavcodec/bsf.pxd"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from libc.stdint cimport uint32_t, int32_t
2+
from libc.stddef cimport size_t
3+
4+
5+
cdef extern from "libavutil/video_enc_params.h" nogil:
6+
cdef enum AVVideoEncParamsType:
7+
AV_VIDEO_ENC_PARAMS_NONE
8+
AV_VIDEO_ENC_PARAMS_VP9
9+
AV_VIDEO_ENC_PARAMS_H264
10+
AV_VIDEO_ENC_PARAMS_MPEG2
11+
12+
cdef struct AVVideoEncParams:
13+
uint32_t nb_blocks
14+
size_t blocks_offset
15+
size_t block_size
16+
AVVideoEncParamsType type
17+
int32_t qp
18+
int32_t delta_qp[4][2]
19+
20+
cdef struct AVVideoBlockParams:
21+
int32_t src_x
22+
int32_t src_y
23+
int32_t w
24+
int32_t h
25+
int32_t delta_qp

0 commit comments

Comments
 (0)