Skip to content

Commit 49c0605

Browse files
committed
Use IntEnums for codec flags
1 parent 92f547b commit 49c0605

5 files changed

Lines changed: 121 additions & 197 deletions

File tree

av/codec/codec.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ cdef class Codec:
117117
if self.is_encoder and lib.av_codec_is_decoder(self.ptr):
118118
raise RuntimeError("%s is both encoder and decoder.")
119119

120-
def create(self, str kind = None):
120+
def create(self, kind = None):
121121
"""Create a :class:`.CodecContext` for this codec.
122122
123123
:param str kind: Gives a hint to static type checkers for what exact CodecContext is used.

av/codec/context.pyi

Lines changed: 35 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from enum import Enum, Flag
1+
from enum import Flag, IntEnum
22
from fractions import Fraction
33
from typing import ClassVar, Literal
44

5-
from av.enum import EnumFlag, EnumItem
65
from av.packet import Packet
76

87
from .codec import Codec
@@ -15,38 +14,39 @@ class ThreadType(Flag):
1514
def __get__(self, i: object | None, owner: type | None = None) -> ThreadType: ...
1615
def __set__(self, instance: object, value: int | str | ThreadType) -> None: ...
1716

18-
class Flags(EnumFlag):
19-
NONE: int
20-
UNALIGNED: int
21-
QSCALE: int
22-
# 4MV
23-
OUTPUT_CORRUPT: int
24-
QPEL: int
25-
DROPCHANGED: int
26-
PASS1: int
27-
PASS2: int
28-
LOOP_FILTER: int
29-
GRAY: int
30-
PSNR: int
31-
INTERLACED_DCT: int
32-
LOW_DELAY: int
33-
GLOBAL_HEADER: int
34-
BITEXACT: int
35-
AC_PRED: int
36-
INTERLACED_ME: int
37-
CLOSED_GOP: int
17+
class Flags(IntEnum):
18+
unaligned: int
19+
qscale: int
20+
four_mv: int
21+
output_corrupt: int
22+
qpel: int
23+
drop_changed: int
24+
recon_frame: int
25+
copy_opaque: int
26+
frame_duration: int
27+
pass1: int
28+
pass2: int
29+
loop_filter: int
30+
gray: int
31+
psnr: int
32+
interlaced_dct: int
33+
low_delay: int
34+
global_header: int
35+
bitexact: int
36+
ac_pred: int
37+
interlaced_me: int
38+
closed_gop: int
3839

39-
class Flags2(EnumFlag):
40-
NONE: int
41-
FAST: int
42-
NO_OUTPUT: int
43-
LOCAL_HEADER: int
44-
CHUNKS: int
45-
IGNORE_CROP: int
46-
SHOW_ALL: int
47-
EXPORT_MVS: int
48-
SKIP_MANUAL: int
49-
RO_FLUSH_NOOP: int
40+
class Flags2(IntEnum):
41+
fast: int
42+
no_output: int
43+
local_header: int
44+
chunks: int
45+
ignore_crop: int
46+
show_all: int
47+
export_mvs: int
48+
skip_manual: int
49+
ro_flush_noop: int
5050

5151
class CodecContext:
5252
name: str
@@ -65,30 +65,10 @@ class CodecContext:
6565
skip_frame: Literal[
6666
"NONE", "DEFAULT", "NONREF", "BIDIR", "NONINTRA", "NONKEY", "ALL"
6767
]
68-
69-
# flags
70-
unaligned: bool
68+
flags: int
7169
qscale: bool
72-
four_mv: bool
73-
output_corrupt: bool
74-
qpel: bool
75-
drop_changed: bool
76-
recon_frame: bool
7770
copy_opaque: bool
78-
frame_duration: bool
79-
pass1: bool
80-
pass2: bool
81-
loop_filter: bool
82-
gray: bool
83-
psnr: bool
84-
interlaced_dct: bool
85-
low_delay: bool
86-
global_header: bool
87-
bitexact: bool
88-
ac_pred: bool
89-
interlaced_me: bool
90-
closed_gop: bool
91-
71+
flags2: int
9272
@property
9373
def is_open(self) -> bool: ...
9474
@property

av/codec/context.pyx

Lines changed: 79 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ from libc.string cimport memcpy
66
from av.bytesource cimport ByteSource, bytesource
77
from av.codec.codec cimport Codec, wrap_codec
88
from av.dictionary cimport _Dictionary
9-
from av.enum cimport define_enum
109
from av.error cimport err_check
1110
from av.packet cimport Packet
1211
from av.utils cimport avrational_to_fraction, to_avrational
1312

14-
from enum import Enum, Flag
13+
from enum import Flag, IntEnum
1514

1615
from av.dictionary import Dictionary
1716

@@ -47,65 +46,39 @@ class ThreadType(Flag):
4746
SLICE: "Decode more than one part of a single frame at once" = lib.FF_THREAD_SLICE
4847
AUTO: "Decode using both FRAME and SLICE methods." = lib.FF_THREAD_SLICE | lib.FF_THREAD_FRAME
4948

50-
51-
Flags = define_enum("Flags", __name__, (
52-
("NONE", 0),
53-
("UNALIGNED", lib.AV_CODEC_FLAG_UNALIGNED,
54-
"Allow decoders to produce frames with data planes that are not aligned to CPU requirements (e.g. due to cropping)."
55-
),
56-
("QSCALE", lib.AV_CODEC_FLAG_QSCALE, "Use fixed qscale."),
57-
("4MV", lib.AV_CODEC_FLAG_4MV, "4 MV per MB allowed / advanced prediction for H.263."),
58-
("OUTPUT_CORRUPT", lib.AV_CODEC_FLAG_OUTPUT_CORRUPT, "Output even those frames that might be corrupted."),
59-
("QPEL", lib.AV_CODEC_FLAG_QPEL, "Use qpel MC."),
60-
("DROPCHANGED", 1 << 5,
61-
"Don't output frames whose parameters differ from first decoded frame in stream."
62-
),
63-
("RECON_FRAME", lib.AV_CODEC_FLAG_RECON_FRAME, "Request the encoder to output reconstructed frames, i.e. frames that would be produced by decoding the encoded bistream."),
64-
("COPY_OPAQUE", lib.AV_CODEC_FLAG_COPY_OPAQUE,
65-
"""Request the decoder to propagate each packet's AVPacket.opaque and AVPacket.opaque_ref
66-
to its corresponding output AVFrame. Request the encoder to propagate each frame's
67-
AVFrame.opaque and AVFrame.opaque_ref values to its corresponding output AVPacket."""),
68-
("FRAME_DURATION", lib.AV_CODEC_FLAG_FRAME_DURATION,
69-
"""Signal to the encoder that the values of AVFrame.duration are valid and should be
70-
used (typically for transferring them to output packets)."""),
71-
("PASS1", lib.AV_CODEC_FLAG_PASS1, "Use internal 2pass ratecontrol in first pass mode."),
72-
("PASS2", lib.AV_CODEC_FLAG_PASS2, "Use internal 2pass ratecontrol in second pass mode."),
73-
("LOOP_FILTER", lib.AV_CODEC_FLAG_LOOP_FILTER, "loop filter."),
74-
("GRAY", lib.AV_CODEC_FLAG_GRAY, "Only decode/encode grayscale."),
75-
("PSNR", lib.AV_CODEC_FLAG_PSNR, "error[?] variables will be set during encoding."),
76-
("INTERLACED_DCT", lib.AV_CODEC_FLAG_INTERLACED_DCT, "Use interlaced DCT."),
77-
("LOW_DELAY", lib.AV_CODEC_FLAG_LOW_DELAY, "Force low delay."),
78-
("GLOBAL_HEADER", lib.AV_CODEC_FLAG_GLOBAL_HEADER,
79-
"Place global headers in extradata instead of every keyframe."
80-
),
81-
("BITEXACT", lib.AV_CODEC_FLAG_BITEXACT, "Use only bitexact stuff (except (I)DCT)."),
82-
("AC_PRED", lib.AV_CODEC_FLAG_AC_PRED, "H.263 advanced intra coding / MPEG-4 AC prediction"),
83-
("INTERLACED_ME", lib.AV_CODEC_FLAG_INTERLACED_ME, "Interlaced motion estimation"),
84-
("CLOSED_GOP", lib.AV_CODEC_FLAG_CLOSED_GOP),
85-
), is_flags=True)
86-
87-
Flags2 = define_enum("Flags2", __name__, (
88-
("NONE", 0),
89-
("FAST", lib.AV_CODEC_FLAG2_FAST,
90-
"""Allow non spec compliant speedup tricks."""),
91-
("NO_OUTPUT", lib.AV_CODEC_FLAG2_NO_OUTPUT,
92-
"""Skip bitstream encoding."""),
93-
("LOCAL_HEADER", lib.AV_CODEC_FLAG2_LOCAL_HEADER,
94-
"""Place global headers at every keyframe instead of in extradata."""),
95-
("CHUNKS", lib.AV_CODEC_FLAG2_CHUNKS,
96-
"""Input bitstream might be truncated at a packet boundaries
97-
instead of only at frame boundaries."""),
98-
("IGNORE_CROP", lib.AV_CODEC_FLAG2_IGNORE_CROP,
99-
"""Discard cropping information from SPS."""),
100-
("SHOW_ALL", lib.AV_CODEC_FLAG2_SHOW_ALL,
101-
"""Show all frames before the first keyframe"""),
102-
("EXPORT_MVS", lib.AV_CODEC_FLAG2_EXPORT_MVS,
103-
"""Export motion vectors through frame side data"""),
104-
("SKIP_MANUAL", lib.AV_CODEC_FLAG2_SKIP_MANUAL,
105-
"""Do not skip samples and export skip information as frame side data"""),
106-
("RO_FLUSH_NOOP", lib.AV_CODEC_FLAG2_RO_FLUSH_NOOP,
107-
"""Do not reset ASS ReadOrder field on flush (subtitles decoding)"""),
108-
), is_flags=True)
49+
class Flags(IntEnum):
50+
unaligned = lib.AV_CODEC_FLAG_UNALIGNED
51+
qscale = lib.AV_CODEC_FLAG_QSCALE
52+
four_mv = lib.AV_CODEC_FLAG_4MV
53+
output_corrupt = lib.AV_CODEC_FLAG_OUTPUT_CORRUPT
54+
qpel = lib.AV_CODEC_FLAG_QPEL
55+
drop_changed = 1 << 5
56+
recon_frame = lib.AV_CODEC_FLAG_RECON_FRAME
57+
copy_opaque = lib.AV_CODEC_FLAG_COPY_OPAQUE
58+
frame_duration = lib.AV_CODEC_FLAG_FRAME_DURATION
59+
pass1 = lib.AV_CODEC_FLAG_PASS1
60+
pass2 = lib.AV_CODEC_FLAG_PASS2
61+
loop_filter = lib.AV_CODEC_FLAG_LOOP_FILTER
62+
gray = lib.AV_CODEC_FLAG_GRAY
63+
psnr = lib.AV_CODEC_FLAG_PSNR
64+
interlaced_dct = lib.AV_CODEC_FLAG_INTERLACED_DCT
65+
low_delay = lib.AV_CODEC_FLAG_LOW_DELAY
66+
global_header = lib.AV_CODEC_FLAG_GLOBAL_HEADER
67+
bitexact = lib.AV_CODEC_FLAG_BITEXACT
68+
ac_pred = lib.AV_CODEC_FLAG_AC_PRED
69+
interlaced_me = lib.AV_CODEC_FLAG_INTERLACED_ME
70+
closed_gop = lib.AV_CODEC_FLAG_CLOSED_GOP
71+
72+
class Flags2(IntEnum):
73+
fast = lib.AV_CODEC_FLAG2_FAST
74+
no_output = lib.AV_CODEC_FLAG2_NO_OUTPUT
75+
local_header = lib.AV_CODEC_FLAG2_LOCAL_HEADER
76+
chunks = lib.AV_CODEC_FLAG2_CHUNKS
77+
ignore_crop = lib.AV_CODEC_FLAG2_IGNORE_CROP
78+
show_all = lib.AV_CODEC_FLAG2_SHOW_ALL
79+
export_mvs = lib.AV_CODEC_FLAG2_EXPORT_MVS
80+
skip_manual = lib.AV_CODEC_FLAG2_SKIP_MANUAL
81+
ro_flush_noop = lib.AV_CODEC_FLAG2_RO_FLUSH_NOOP
10982

11083

11184
cdef class CodecContext:
@@ -133,53 +106,59 @@ cdef class CodecContext:
133106
self.ptr.thread_count = 0 # use as many threads as there are CPUs.
134107
self.ptr.thread_type = 0x02 # thread within a frame. Does not change the API.
135108

136-
def _get_flags(self):
109+
@property
110+
def flags(self):
111+
"""
112+
Get and set the flags bitmask of CodecContext.
113+
114+
:rtype: int
115+
"""
137116
return self.ptr.flags
138117

139-
def _set_flags(self, value):
118+
@flags.setter
119+
def flags(self, int value):
140120
self.ptr.flags = value
141121

142-
flags = Flags.property(_get_flags, _set_flags, "Flag property of :class:`.Flags`.")
143-
144-
unaligned = flags.flag_property("UNALIGNED")
145-
qscale = flags.flag_property("QSCALE")
146-
four_mv = flags.flag_property("4MV")
147-
output_corrupt = flags.flag_property("OUTPUT_CORRUPT")
148-
qpel = flags.flag_property("QPEL")
149-
drop_changed = flags.flag_property("DROPCHANGED")
150-
recon_frame = flags.flag_property("RECON_FRAME")
151-
copy_opaque = flags.flag_property("COPY_OPAQUE")
152-
frame_duration = flags.flag_property("FRAME_DURATION")
153-
pass1 = flags.flag_property("PASS1")
154-
pass2 = flags.flag_property("PASS2")
155-
loop_filter = flags.flag_property("LOOP_FILTER")
156-
gray = flags.flag_property("GRAY")
157-
psnr = flags.flag_property("PSNR")
158-
interlaced_dct = flags.flag_property("INTERLACED_DCT")
159-
low_delay = flags.flag_property("LOW_DELAY")
160-
global_header = flags.flag_property("GLOBAL_HEADER")
161-
bitexact = flags.flag_property("BITEXACT")
162-
ac_pred = flags.flag_property("AC_PRED")
163-
interlaced_me = flags.flag_property("INTERLACED_ME")
164-
closed_gop = flags.flag_property("CLOSED_GOP")
165-
166-
def _get_flags2(self):
122+
@property
123+
def qscale(self):
124+
"""
125+
Use fixed qscale.
126+
127+
:rtype: bool
128+
"""
129+
return bool(self.ptr.flags & lib.AV_CODEC_FLAG_QSCALE)
130+
131+
@qscale.setter
132+
def qscale(self, value):
133+
if value:
134+
self.ptr.flags |= lib.AV_CODEC_FLAG_QSCALE
135+
else:
136+
self.ptr.flags &= ~lib.AV_CODEC_FLAG_QSCALE
137+
138+
@property
139+
def copy_opaque(self):
140+
return bool(self.ptr.flags & lib.AV_CODEC_FLAG_COPY_OPAQUE)
141+
142+
@copy_opaque.setter
143+
def copy_opaque(self, value):
144+
if value:
145+
self.ptr.flags |= lib.AV_CODEC_FLAG_COPY_OPAQUE
146+
else:
147+
self.ptr.flags &= ~lib.AV_CODEC_FLAG_COPY_OPAQUE
148+
149+
@property
150+
def flags2(self):
151+
"""
152+
Get and set the flags2 bitmask of CodecContext.
153+
154+
:rtype: int
155+
"""
167156
return self.ptr.flags2
168157

169-
def _set_flags2(self, value):
158+
@flags2.setter
159+
def flags2(self, int value):
170160
self.ptr.flags2 = value
171161

172-
flags2 = Flags2.property(_get_flags2, _set_flags2, "Flag property of :class:`.Flags2`.")
173-
fast = flags2.flag_property("FAST")
174-
no_output = flags2.flag_property("NO_OUTPUT")
175-
local_header = flags2.flag_property("LOCAL_HEADER")
176-
chunks = flags2.flag_property("CHUNKS")
177-
ignore_crop = flags2.flag_property("IGNORE_CROP")
178-
show_all = flags2.flag_property("SHOW_ALL")
179-
export_mvs = flags2.flag_property("EXPORT_MVS")
180-
skip_manual = flags2.flag_property("SKIP_MANUAL")
181-
ro_flush_noop = flags2.flag_property("RO_FLUSH_NOOP")
182-
183162
@property
184163
def extradata(self):
185164
if self.ptr is NULL:

av/enum.pyx

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -198,46 +198,6 @@ cdef class EnumItem:
198198

199199

200200
cdef class EnumFlag(EnumItem):
201-
202-
"""
203-
Flags are sets of boolean attributes, which the FFmpeg API represents as individual
204-
bits in a larger integer which you manipulate with the bitwise operators.
205-
We associate names with each flag that are easier to operate with.
206-
207-
Consider :data:`CodecContextFlags`, whis is the type of the :attr:`CodecContext.flags`
208-
attribute, and the set of boolean properties::
209-
210-
>>> fh = av.open(video_path)
211-
>>> cc = fh.streams.video[0].codec_context
212-
213-
>>> cc.flags
214-
<av.codec.context.Flags:NONE(0x0)>
215-
216-
>>> # You can set flags via bitwise operations with the objects, names, or values:
217-
>>> cc.flags |= cc.flags.OUTPUT_CORRUPT
218-
>>> cc.flags |= 'GLOBAL_HEADER'
219-
>>> cc.flags
220-
<av.codec.context.Flags:OUTPUT_CORRUPT|GLOBAL_HEADER(0x400008)>
221-
222-
>>> # You can test flags via bitwise operations with objects, names, or values:
223-
>>> bool(cc.flags & cc.flags.OUTPUT_CORRUPT)
224-
True
225-
>>> bool(cc.flags & 'QSCALE')
226-
False
227-
228-
>>> # There are boolean properties for each flag:
229-
>>> cc.output_corrupt
230-
True
231-
>>> cc.qscale
232-
False
233-
234-
>>> # You can set them:
235-
>>> cc.qscale = True
236-
>>> cc.flags
237-
<av.codec.context.Flags:QSCALE|OUTPUT_CORRUPT|GLOBAL_HEADER(0x40000a)>
238-
239-
"""
240-
241201
cdef readonly tuple flags
242202

243203
def __cinit__(self, sentinel, name, value, doc=None):

tests/test_videoframe.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ def assertPixelValue16(plane, expected, byteorder: str) -> None:
3131
def test_opaque() -> None:
3232
with av.open(fate_suite("h264/interlaced_crop.mp4")) as container:
3333
video_stream = container.streams.video[0]
34-
video_stream.codec_context.copy_opaque = True
34+
35+
ctx = video_stream.codec_context
36+
ctx.flags |= av.codec.context.Flags.copy_opaque
37+
38+
assert video_stream.codec_context.copy_opaque
39+
3540
for packet_idx, packet in enumerate(container.demux()):
3641
packet.opaque = (time.time(), packet_idx)
3742
for frame in packet.decode():

0 commit comments

Comments
 (0)