File: encparams.pyx

package info (click to toggle)
python-av 16.1.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,728 kB
  • sloc: python: 8,059; sh: 181; ansic: 174; makefile: 140
file content (165 lines) | stat: -rw-r--r-- 5,578 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
cimport libav as lib
from libc.stdint cimport int32_t, uint8_t

from enum import IntEnum

VideoEncParamsType = IntEnum(
    "AVVideoEncParamsType",
    {
        "NONE":  <int>lib.AV_VIDEO_ENC_PARAMS_NONE,
        "VP9":   <int>lib.AV_VIDEO_ENC_PARAMS_VP9,
        "H264":  <int>lib.AV_VIDEO_ENC_PARAMS_H264,
        "MPEG2": <int>lib.AV_VIDEO_ENC_PARAMS_MPEG2,
    },
)

cdef class VideoEncParams(SideData):
    def __repr__(self):
        return f"<av.sidedata.VideoEncParams, nb_blocks={self.nb_blocks}, codec_type={self.codec_type}, qp={self.qp}>"

    @property
    def nb_blocks(self):
        """
        Number of blocks in the array
        May be 0, in which case no per-block information is present. In this case
        the values of blocks_offset / block_size are unspecified and should not
        be accessed.
        """
        return (<lib.AVVideoEncParams*> self.ptr.data).nb_blocks

    @property
    def blocks_offset(self):
        """
        Offset in bytes from the beginning of this structure at which the array of blocks starts.
        """
        return (<lib.AVVideoEncParams*> self.ptr.data).blocks_offset

    @property
    def block_size(self):
        """
        Size of each block in bytes. May not match sizeof(AVVideoBlockParams).
        """
        return (<lib.AVVideoEncParams*> self.ptr.data).block_size

    @property
    def codec_type(self):
        """
        Type of the parameters (the codec they are used with).
        """
        cdef lib.AVVideoEncParamsType t = (<lib.AVVideoEncParams*> self.ptr.data).type
        return VideoEncParamsType(<int>t)

    @property
    def qp(self):
        """
        Base quantisation parameter for the frame. The final quantiser for a
        given block in a given plane is obtained from this value, possibly
        combined with `delta_qp` and the per-block delta in a manner
        documented for each type.
        """
        return (<lib.AVVideoEncParams*> self.ptr.data).qp
    
    @property
    def delta_qp(self):
        """
        Quantisation parameter offset from the base (per-frame) qp for a given
        plane (first index) and AC/DC coefficients (second index).
        """
        cdef lib.AVVideoEncParams *p = <lib.AVVideoEncParams*> self.ptr.data
        return [[p.delta_qp[i][j] for j in range(2)] for i in range(4)]

    def block_params(self, idx):
        """
        Get the encoding parameters for a given block
        """
        # Validate given index
        if idx < 0 or idx >= self.nb_blocks:
            raise ValueError("Expected idx in range [0, nb_blocks)")

        return VideoBlockParams(self, idx)

    def qp_map(self):
        """
        Convenience method that creates a 2-D map with the quantization parameters per macroblock.
        Only for MPEG2 and H264 encoded videos.
        """
        import numpy as np

        cdef int mb_h = (self.frame.ptr.height + 15) // 16
        cdef int mb_w = (self.frame.ptr.width + 15) // 16
        cdef int nb_mb = mb_h * mb_w
        cdef int block_idx
        cdef int y
        cdef int x
        cdef VideoBlockParams block

        # Validate number of blocks
        if self.nb_blocks != nb_mb:
            raise RuntimeError("Expected frame size to match number of blocks in side data")
        
        # Validate type
        cdef lib.AVVideoEncParamsType type = (<lib.AVVideoEncParams*> self.ptr.data).type
        if type != lib.AVVideoEncParamsType.AV_VIDEO_ENC_PARAMS_MPEG2 and type != lib.AVVideoEncParamsType.AV_VIDEO_ENC_PARAMS_H264:
            raise ValueError("Expected MPEG2 or H264")

        # Create a 2-D map with the number of macroblocks
        cdef int32_t[:, ::1] map = np.empty((mb_h, mb_w), dtype=np.int32)

        # Fill map with quantization parameter per macroblock
        for block_idx in range(nb_mb):
            block = VideoBlockParams(self, block_idx)
            y = block.src_y // 16
            x = block.src_x // 16
            map[y, x] = self.qp + block.delta_qp

        return np.asarray(map)


cdef class VideoBlockParams:
    def __init__(self, VideoEncParams video_enc_params, int idx) -> None:
        cdef uint8_t* base = <uint8_t*> video_enc_params.ptr.data
        cdef Py_ssize_t offset = video_enc_params.blocks_offset + idx * video_enc_params.block_size
        self.ptr = <lib.AVVideoBlockParams*> (base + offset)

    def __repr__(self):
        return f"<av.sidedata.VideoBlockParams, src=({self.src_x}, {self.src_y}), size={self.w}x{self.h}, delta_qp={self.delta_qp}>"

    @property
    def src_x(self):
        """
        Horizontal distance in luma pixels from the top-left corner of the visible frame
        to the top-left corner of the block.
        Can be negative if top/right padding is present on the coded frame.
        """
        return self.ptr.src_x

    @property
    def src_y(self):
        """
        Vertical distance in luma pixels from the top-left corner of the visible frame
        to the top-left corner of the block.
        Can be negative if top/right padding is present on the coded frame.
        """
        return self.ptr.src_y

    @property
    def w(self):
        """
        Width of the block in luma pixels
        """
        return self.ptr.w

    @property
    def h(self):
        """
        Height of the block in luma pixels
        """
        return self.ptr.h

    @property
    def delta_qp(self):
        """
        Difference between this block's final quantization parameter and the
        corresponding per-frame value.
        """
        return self.ptr.delta_qp