Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -17,8 +17,8 @@ from av.audio.stream import AudioStream
|
|||
from av.bitstream import BitStreamFilterContext, bitstream_filters_available
|
||||
from av.codec.codec import Codec, codecs_available
|
||||
from av.codec.context import CodecContext
|
||||
from av.codec.hwaccel import HWConfig
|
||||
from av.container import open
|
||||
from av.device import DeviceInfo, enumerate_input_devices, enumerate_output_devices
|
||||
from av.format import ContainerFormat, formats_available
|
||||
from av.packet import Packet
|
||||
from av.error import * # noqa: F403; This is limited to exception types.
|
||||
|
|
@ -45,6 +45,9 @@ __all__ = (
|
|||
"codecs_available",
|
||||
"CodecContext",
|
||||
"open",
|
||||
"DeviceInfo",
|
||||
"enumerate_input_devices",
|
||||
"enumerate_output_devices",
|
||||
"ContainerFormat",
|
||||
"formats_available",
|
||||
"Packet",
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
venv/lib/python3.12/site-packages/av/_core.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/_core.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
9
venv/lib/python3.12/site-packages/av/_core.pxd
Normal file
9
venv/lib/python3.12/site-packages/av/_core.pxd
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
cdef extern from "libswscale/swscale.h" nogil:
|
||||
cdef int swscale_version()
|
||||
cdef char* swscale_configuration()
|
||||
cdef char* swscale_license()
|
||||
|
||||
cdef extern from "libswresample/swresample.h" nogil:
|
||||
cdef int swresample_version()
|
||||
cdef char* swresample_configuration()
|
||||
cdef char* swresample_license()
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
cimport libav as lib
|
||||
import cython
|
||||
import cython.cimports.libav as lib
|
||||
|
||||
# Initialise libraries.
|
||||
lib.avformat_network_init()
|
||||
lib.avdevice_register_all()
|
||||
|
||||
# Exports.
|
||||
time_base = lib.AV_TIME_BASE
|
||||
|
||||
|
||||
cdef decode_version(v):
|
||||
@cython.cfunc
|
||||
def decode_version(v):
|
||||
if v < 0:
|
||||
return (-1, -1, -1)
|
||||
|
||||
cdef int major = (v >> 16) & 0xff
|
||||
cdef int minor = (v >> 8) & 0xff
|
||||
cdef int micro = (v) & 0xff
|
||||
|
||||
major: cython.int = (v >> 16) & 0xFF
|
||||
minor: cython.int = (v >> 8) & 0xFF
|
||||
micro: cython.int = (v) & 0xFF
|
||||
return (major, minor, micro)
|
||||
|
||||
|
||||
# Return an informative version string.
|
||||
# This usually is the actual release version number or a git commit
|
||||
# description. This string has no fixed format and can change any time. It
|
||||
|
|
@ -28,37 +28,37 @@ library_meta = {
|
|||
"libavutil": dict(
|
||||
version=decode_version(lib.avutil_version()),
|
||||
configuration=lib.avutil_configuration(),
|
||||
license=lib.avutil_license()
|
||||
license=lib.avutil_license(),
|
||||
),
|
||||
"libavcodec": dict(
|
||||
version=decode_version(lib.avcodec_version()),
|
||||
configuration=lib.avcodec_configuration(),
|
||||
license=lib.avcodec_license()
|
||||
license=lib.avcodec_license(),
|
||||
),
|
||||
"libavformat": dict(
|
||||
version=decode_version(lib.avformat_version()),
|
||||
configuration=lib.avformat_configuration(),
|
||||
license=lib.avformat_license()
|
||||
license=lib.avformat_license(),
|
||||
),
|
||||
"libavdevice": dict(
|
||||
version=decode_version(lib.avdevice_version()),
|
||||
configuration=lib.avdevice_configuration(),
|
||||
license=lib.avdevice_license()
|
||||
license=lib.avdevice_license(),
|
||||
),
|
||||
"libavfilter": dict(
|
||||
version=decode_version(lib.avfilter_version()),
|
||||
configuration=lib.avfilter_configuration(),
|
||||
license=lib.avfilter_license()
|
||||
license=lib.avfilter_license(),
|
||||
),
|
||||
"libswscale": dict(
|
||||
version=decode_version(lib.swscale_version()),
|
||||
configuration=lib.swscale_configuration(),
|
||||
license=lib.swscale_license()
|
||||
version=decode_version(swscale_version()),
|
||||
configuration=swscale_configuration(),
|
||||
license=swscale_license(),
|
||||
),
|
||||
"libswresample": dict(
|
||||
version=decode_version(lib.swresample_version()),
|
||||
configuration=lib.swresample_configuration(),
|
||||
license=lib.swresample_license()
|
||||
version=decode_version(swresample_version()),
|
||||
configuration=swresample_configuration(),
|
||||
license=swresample_license(),
|
||||
),
|
||||
}
|
||||
|
||||
|
|
@ -1 +1 @@
|
|||
__version__ = "16.1.0"
|
||||
__version__ = "17.1.0"
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
from .frame import AudioFrame
|
||||
from .stream import AudioStream
|
||||
from .frame import AudioFrame as AudioFrame
|
||||
from .stream import AudioStream as AudioStream
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
venv/lib/python3.12/site-packages/av/audio/codeccontext.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/codeccontext.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -7,10 +7,11 @@ from cython.cimports.av.frame import Frame
|
|||
from cython.cimports.av.packet import Packet
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioCodecContext(CodecContext):
|
||||
@cython.cfunc
|
||||
def _prepare_frames_for_encode(self, input_frame: Frame | None):
|
||||
def _prepare_frames_for_encode(self, input_frame: Frame | None) -> list:
|
||||
frame: AudioFrame | None = input_frame
|
||||
allow_var_frame_size: cython.bint = (
|
||||
self.ptr.codec.capabilities & lib.AV_CODEC_CAP_VARIABLE_FRAME_SIZE
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/audio/fifo.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/fifo.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -1,8 +1,11 @@
|
|||
from av.audio.frame cimport alloc_audio_frame
|
||||
from av.error cimport err_check
|
||||
import cython
|
||||
from cython.cimports.av.audio.frame import alloc_audio_frame
|
||||
from cython.cimports.av.error import err_check
|
||||
|
||||
|
||||
cdef class AudioFifo:
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioFifo:
|
||||
"""A simple audio sample FIFO (First In First Out) buffer."""
|
||||
|
||||
def __repr__(self):
|
||||
|
|
@ -22,7 +25,8 @@ cdef class AudioFifo:
|
|||
if self.ptr:
|
||||
lib.av_audio_fifo_free(self.ptr)
|
||||
|
||||
cpdef write(self, AudioFrame frame):
|
||||
@cython.ccall
|
||||
def write(self, frame: AudioFrame | None):
|
||||
"""write(frame)
|
||||
|
||||
Push a frame of samples into the queue.
|
||||
|
|
@ -45,7 +49,6 @@ cdef class AudioFifo:
|
|||
return
|
||||
|
||||
if not self.ptr:
|
||||
|
||||
# Hold onto a copy of the attributes of the first frame to populate
|
||||
# output frames with.
|
||||
self.template = alloc_audio_frame()
|
||||
|
|
@ -60,9 +63,10 @@ cdef class AudioFifo:
|
|||
self.pts_per_sample = 0
|
||||
|
||||
self.ptr = lib.av_audio_fifo_alloc(
|
||||
<lib.AVSampleFormat>frame.ptr.format,
|
||||
cython.cast(lib.AVSampleFormat, frame.ptr.format),
|
||||
frame.layout.nb_channels,
|
||||
frame.ptr.nb_samples * 2, # Just a default number of samples; it will adjust.
|
||||
frame.ptr.nb_samples
|
||||
* 2, # Just a default number of samples; it will adjust.
|
||||
)
|
||||
|
||||
if not self.ptr:
|
||||
|
|
@ -70,34 +74,43 @@ cdef class AudioFifo:
|
|||
|
||||
# Make sure nothing changed.
|
||||
elif (
|
||||
frame.ptr.format != self.template.ptr.format or
|
||||
# TODO: frame.ptr.ch_layout != self.template.ptr.ch_layout or
|
||||
frame.ptr.sample_rate != self.template.ptr.sample_rate or
|
||||
(frame._time_base.num and self.template._time_base.num and (
|
||||
frame._time_base.num != self.template._time_base.num or
|
||||
frame._time_base.den != self.template._time_base.den
|
||||
))
|
||||
frame.ptr.format != self.template.ptr.format
|
||||
or frame.ptr.sample_rate != self.template.ptr.sample_rate
|
||||
or (
|
||||
frame._time_base.num
|
||||
and self.template._time_base.num
|
||||
and (
|
||||
frame._time_base.num != self.template._time_base.num
|
||||
or frame._time_base.den != self.template._time_base.den
|
||||
)
|
||||
)
|
||||
):
|
||||
raise ValueError("Frame does not match AudioFifo parameters.")
|
||||
|
||||
# Assert that the PTS are what we expect.
|
||||
cdef int64_t expected_pts
|
||||
expected_pts = cython.declare(int64_t)
|
||||
if self.pts_per_sample and frame.ptr.pts != lib.AV_NOPTS_VALUE:
|
||||
expected_pts = <int64_t>(self.pts_per_sample * self.samples_written)
|
||||
expected_pts = cython.cast(
|
||||
int64_t, self.pts_per_sample * self.samples_written
|
||||
)
|
||||
if frame.ptr.pts != expected_pts:
|
||||
raise ValueError(
|
||||
"Frame.pts (%d) != expected (%d); fix or set to None." % (frame.ptr.pts, expected_pts)
|
||||
"Frame.pts (%d) != expected (%d); fix or set to None."
|
||||
% (frame.ptr.pts, expected_pts)
|
||||
)
|
||||
|
||||
err_check(lib.av_audio_fifo_write(
|
||||
self.ptr,
|
||||
<void **>frame.ptr.extended_data,
|
||||
frame.ptr.nb_samples,
|
||||
))
|
||||
err_check(
|
||||
lib.av_audio_fifo_write(
|
||||
self.ptr,
|
||||
cython.cast(cython.pointer[cython.p_void], frame.ptr.extended_data),
|
||||
frame.ptr.nb_samples,
|
||||
)
|
||||
)
|
||||
|
||||
self.samples_written += frame.ptr.nb_samples
|
||||
|
||||
cpdef read(self, int samples=0, bint partial=False):
|
||||
@cython.ccall
|
||||
def read(self, samples: cython.int = 0, partial: cython.bint = False):
|
||||
"""read(samples=0, partial=False)
|
||||
|
||||
Read samples from the queue.
|
||||
|
|
@ -115,7 +128,7 @@ cdef class AudioFifo:
|
|||
if not self.ptr:
|
||||
return
|
||||
|
||||
cdef int buffered_samples = lib.av_audio_fifo_size(self.ptr)
|
||||
buffered_samples: cython.int = lib.av_audio_fifo_size(self.ptr)
|
||||
if buffered_samples < 1:
|
||||
return
|
||||
|
||||
|
|
@ -127,31 +140,35 @@ cdef class AudioFifo:
|
|||
else:
|
||||
return
|
||||
|
||||
cdef AudioFrame frame = alloc_audio_frame()
|
||||
frame: AudioFrame = alloc_audio_frame()
|
||||
frame._copy_internal_attributes(self.template)
|
||||
frame._init(
|
||||
<lib.AVSampleFormat>self.template.ptr.format,
|
||||
<lib.AVChannelLayout>self.template.ptr.ch_layout,
|
||||
cython.cast(lib.AVSampleFormat, self.template.ptr.format),
|
||||
cython.cast(lib.AVChannelLayout, self.template.ptr.ch_layout),
|
||||
samples,
|
||||
1, # Align?
|
||||
)
|
||||
|
||||
err_check(lib.av_audio_fifo_read(
|
||||
self.ptr,
|
||||
<void **>frame.ptr.extended_data,
|
||||
samples,
|
||||
))
|
||||
err_check(
|
||||
lib.av_audio_fifo_read(
|
||||
self.ptr,
|
||||
cython.cast(cython.pointer[cython.p_void], frame.ptr.extended_data),
|
||||
samples,
|
||||
)
|
||||
)
|
||||
|
||||
if self.pts_per_sample:
|
||||
frame.ptr.pts = <uint64_t>(self.pts_per_sample * self.samples_read)
|
||||
frame.ptr.pts = cython.cast(
|
||||
uint64_t, self.pts_per_sample * self.samples_read
|
||||
)
|
||||
else:
|
||||
frame.ptr.pts = lib.AV_NOPTS_VALUE
|
||||
|
||||
self.samples_read += samples
|
||||
|
||||
return frame
|
||||
|
||||
cpdef read_many(self, int samples, bint partial=False):
|
||||
@cython.ccall
|
||||
def read_many(self, samples: cython.int, partial: cython.bint = False):
|
||||
"""read_many(samples, partial=False)
|
||||
|
||||
Read as many frames as we can.
|
||||
|
|
@ -162,8 +179,8 @@ cdef class AudioFifo:
|
|||
|
||||
"""
|
||||
|
||||
cdef AudioFrame frame
|
||||
frames = []
|
||||
frame: AudioFrame
|
||||
frames: list = []
|
||||
while True:
|
||||
frame = self.read(samples, partial=partial)
|
||||
if frame is not None:
|
||||
|
|
@ -177,18 +194,26 @@ cdef class AudioFifo:
|
|||
def format(self):
|
||||
"""The :class:`.AudioFormat` of this FIFO."""
|
||||
if not self.ptr:
|
||||
raise AttributeError(f"'{__name__}.AudioFifo' object has no attribute 'format'")
|
||||
raise AttributeError(
|
||||
f"'{__name__}.AudioFifo' object has no attribute 'format'"
|
||||
)
|
||||
return self.template.format
|
||||
|
||||
@property
|
||||
def layout(self):
|
||||
"""The :class:`.AudioLayout` of this FIFO."""
|
||||
if not self.ptr:
|
||||
raise AttributeError(f"'{__name__}.AudioFifo' object has no attribute 'layout'")
|
||||
raise AttributeError(
|
||||
f"'{__name__}.AudioFifo' object has no attribute 'layout'"
|
||||
)
|
||||
return self.template.layout
|
||||
|
||||
@property
|
||||
def sample_rate(self):
|
||||
if not self.ptr:
|
||||
raise AttributeError(f"'{__name__}.AudioFifo' object has no attribute 'sample_rate'")
|
||||
raise AttributeError(
|
||||
f"'{__name__}.AudioFifo' object has no attribute 'sample_rate'"
|
||||
)
|
||||
return self.template.sample_rate
|
||||
|
||||
@property
|
||||
BIN
venv/lib/python3.12/site-packages/av/audio/format.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/format.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -2,8 +2,10 @@ import sys
|
|||
|
||||
import cython
|
||||
|
||||
container_format_postfix: str = "le" if sys.byteorder == "little" else "be"
|
||||
_cinit_bypass_sentinel = object()
|
||||
container_format_postfix = cython.declare(
|
||||
str, "le" if sys.byteorder == "little" else "be"
|
||||
)
|
||||
_cinit_bypass_sentinel = cython.declare(object, object())
|
||||
|
||||
|
||||
@cython.cfunc
|
||||
|
|
@ -18,6 +20,7 @@ def get_audio_format(c_format: lib.AVSampleFormat) -> AudioFormat:
|
|||
return format
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioFormat:
|
||||
"""Descriptor of audio formats."""
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/audio/frame.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/frame.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -5,7 +5,7 @@ from cython.cimports.av.audio.plane import AudioPlane
|
|||
from cython.cimports.av.error import err_check
|
||||
from cython.cimports.av.utils import check_ndarray
|
||||
|
||||
_cinit_bypass_sentinel = object()
|
||||
_cinit_bypass_sentinel = cython.declare(object, object())
|
||||
|
||||
|
||||
@cython.cfunc
|
||||
|
|
@ -27,6 +27,7 @@ format_dtypes = {
|
|||
}
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioFrame(Frame):
|
||||
"""A frame of audio."""
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/audio/layout.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/layout.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -3,6 +3,5 @@ cimport libav as lib
|
|||
|
||||
cdef class AudioLayout:
|
||||
cdef lib.AVChannelLayout layout
|
||||
cdef _init(self, lib.AVChannelLayout layout)
|
||||
|
||||
cdef AudioLayout get_audio_layout(lib.AVChannelLayout c_layout)
|
||||
|
|
|
|||
109
venv/lib/python3.12/site-packages/av/audio/layout.py
Normal file
109
venv/lib/python3.12/site-packages/av/audio/layout.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
import cython
|
||||
from cython.cimports import libav as lib
|
||||
from cython.cimports.cpython.bytes import PyBytes_FromStringAndSize
|
||||
|
||||
|
||||
@dataclass
|
||||
class AudioChannel:
|
||||
name: str
|
||||
description: str
|
||||
|
||||
def __repr__(self):
|
||||
return f"<av.AudioChannel '{self.name}' ({self.description})>"
|
||||
|
||||
|
||||
_cinit_bypass_sentinel = cython.declare(object, object())
|
||||
|
||||
|
||||
@cython.cfunc
|
||||
def get_audio_layout(c_layout: lib.AVChannelLayout) -> AudioLayout:
|
||||
"""Get an AudioLayout from Cython land."""
|
||||
layout: AudioLayout = AudioLayout(_cinit_bypass_sentinel)
|
||||
layout.layout = c_layout
|
||||
return layout
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioLayout:
|
||||
def __dealloc__(self):
|
||||
lib.av_channel_layout_uninit(cython.address(self.layout))
|
||||
|
||||
def __cinit__(self, layout):
|
||||
if layout is _cinit_bypass_sentinel:
|
||||
return
|
||||
|
||||
if type(layout) is str:
|
||||
ret = lib.av_channel_layout_from_string(cython.address(c_layout), layout)
|
||||
if ret != 0:
|
||||
raise ValueError(f"Invalid layout: {layout}")
|
||||
elif isinstance(layout, AudioLayout):
|
||||
c_layout = cython.cast(AudioLayout, layout).layout
|
||||
else:
|
||||
raise TypeError(
|
||||
f"layout must be of type: string | av.AudioLayout, got {type(layout)}"
|
||||
)
|
||||
|
||||
self.layout = c_layout
|
||||
|
||||
def __repr__(self):
|
||||
return f"<av.{self.__class__.__name__} {self.name!r}>"
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, AudioLayout):
|
||||
return False
|
||||
c_other: lib.AVChannelLayout = cython.cast(AudioLayout, other).layout
|
||||
return (
|
||||
lib.av_channel_layout_compare(
|
||||
cython.address(self.layout), cython.address(c_other)
|
||||
)
|
||||
== 0
|
||||
)
|
||||
|
||||
@property
|
||||
def nb_channels(self):
|
||||
return self.layout.nb_channels
|
||||
|
||||
@property
|
||||
def channels(self):
|
||||
buf: cython.char[16]
|
||||
buf2: cython.char[128]
|
||||
|
||||
results: list = []
|
||||
for index in range(self.layout.nb_channels):
|
||||
size = lib.av_channel_name(
|
||||
buf,
|
||||
cython.sizeof(buf),
|
||||
lib.av_channel_layout_channel_from_index(
|
||||
cython.address(self.layout), index
|
||||
),
|
||||
)
|
||||
size2 = lib.av_channel_description(
|
||||
buf2,
|
||||
cython.sizeof(buf2),
|
||||
lib.av_channel_layout_channel_from_index(
|
||||
cython.address(self.layout), index
|
||||
),
|
||||
)
|
||||
results.append(
|
||||
AudioChannel(
|
||||
PyBytes_FromStringAndSize(buf, size - 1).decode("utf-8"),
|
||||
PyBytes_FromStringAndSize(buf2, size2 - 1).decode("utf-8"),
|
||||
)
|
||||
)
|
||||
|
||||
return tuple(results)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""The canonical name of the audio layout."""
|
||||
layout_name: cython.char[129]
|
||||
ret: cython.int = lib.av_channel_layout_describe(
|
||||
cython.address(self.layout), layout_name, cython.sizeof(layout_name)
|
||||
)
|
||||
if ret < 0:
|
||||
raise RuntimeError(f"Failed to get layout name: {ret}")
|
||||
|
||||
return layout_name
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
cimport libav as lib
|
||||
from cpython.bytes cimport PyBytes_FromStringAndSize
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class AudioChannel:
|
||||
name: str
|
||||
description: str
|
||||
|
||||
def __repr__(self):
|
||||
return f"<av.AudioChannel '{self.name}' ({self.description})>"
|
||||
|
||||
cdef object _cinit_bypass_sentinel
|
||||
|
||||
cdef AudioLayout get_audio_layout(lib.AVChannelLayout c_layout):
|
||||
"""Get an AudioLayout from Cython land."""
|
||||
cdef AudioLayout layout = AudioLayout.__new__(AudioLayout, _cinit_bypass_sentinel)
|
||||
layout._init(c_layout)
|
||||
return layout
|
||||
|
||||
|
||||
cdef class AudioLayout:
|
||||
def __init__(self, layout):
|
||||
if layout is _cinit_bypass_sentinel:
|
||||
return
|
||||
|
||||
if type(layout) is str:
|
||||
ret = lib.av_channel_layout_from_string(&c_layout, layout)
|
||||
if ret != 0:
|
||||
raise ValueError(f"Invalid layout: {layout}")
|
||||
elif isinstance(layout, AudioLayout):
|
||||
c_layout = (<AudioLayout>layout).layout
|
||||
else:
|
||||
raise TypeError(f"layout must be of type: string | av.AudioLayout, got {type(layout)}")
|
||||
|
||||
self._init(c_layout)
|
||||
|
||||
cdef _init(self, lib.AVChannelLayout layout):
|
||||
self.layout = layout
|
||||
|
||||
def __repr__(self):
|
||||
return f"<av.{self.__class__.__name__} {self.name!r}>"
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, AudioLayout) and self.name == other.name and self.nb_channels == other.nb_channels
|
||||
|
||||
@property
|
||||
def nb_channels(self):
|
||||
return self.layout.nb_channels
|
||||
|
||||
@property
|
||||
def channels(self):
|
||||
cdef char buf[16]
|
||||
cdef char buf2[128]
|
||||
|
||||
results = []
|
||||
|
||||
for index in range(self.layout.nb_channels):
|
||||
size = lib.av_channel_name(buf, sizeof(buf), lib.av_channel_layout_channel_from_index(&self.layout, index)) - 1
|
||||
size2 = lib.av_channel_description(buf2, sizeof(buf2), lib.av_channel_layout_channel_from_index(&self.layout, index)) - 1
|
||||
results.append(
|
||||
AudioChannel(
|
||||
PyBytes_FromStringAndSize(buf, size).decode("utf-8"),
|
||||
PyBytes_FromStringAndSize(buf2, size2).decode("utf-8"),
|
||||
)
|
||||
)
|
||||
|
||||
return tuple(results)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""The canonical name of the audio layout."""
|
||||
cdef char layout_name[128]
|
||||
cdef int ret
|
||||
|
||||
ret = lib.av_channel_layout_describe(&self.layout, layout_name, sizeof(layout_name))
|
||||
if ret < 0:
|
||||
raise RuntimeError(f"Failed to get layout name: {ret}")
|
||||
|
||||
return layout_name
|
||||
BIN
venv/lib/python3.12/site-packages/av/audio/plane.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/plane.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -2,6 +2,7 @@ import cython
|
|||
from cython.cimports.av.audio.frame import AudioFrame
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioPlane(Plane):
|
||||
def __cinit__(self, frame: AudioFrame, index: cython.int):
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/audio/resampler.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/resampler.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -1,12 +1,12 @@
|
|||
from errno import EAGAIN
|
||||
|
||||
import cython
|
||||
from cython.cimports.av.filter.context import FilterContext
|
||||
from cython.cimports.av.filter.graph import Graph
|
||||
|
||||
from av.error import FFmpegError
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioResampler:
|
||||
"""AudioResampler(format=None, layout=None, rate=None)
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/audio/stream.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/audio/stream.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -3,9 +3,12 @@ from cython.cimports.av.audio.frame import AudioFrame
|
|||
from cython.cimports.av.packet import Packet
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class AudioStream(Stream):
|
||||
def __repr__(self):
|
||||
if self.codec_context is None:
|
||||
return f"<av.AudioStream #{self.index} audio/<nocodec> at 0x{id(self):x}>"
|
||||
form = self.format.name if self.format else None
|
||||
return (
|
||||
f"<av.AudioStream #{self.index} {self.name} at {self.rate}Hz,"
|
||||
|
|
@ -13,6 +16,10 @@ class AudioStream(Stream):
|
|||
)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self.codec_context is None:
|
||||
raise AttributeError(
|
||||
f"'{type(self).__name__}' object has no attribute '{name}'"
|
||||
)
|
||||
return getattr(self.codec_context, name)
|
||||
|
||||
@cython.ccall
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/bitstream.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/bitstream.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
116
venv/lib/python3.12/site-packages/av/bitstream.py
Normal file
116
venv/lib/python3.12/site-packages/av/bitstream.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import cython
|
||||
import cython.cimports.libav as lib
|
||||
from cython.cimports.av.error import err_check
|
||||
from cython.cimports.av.packet import Packet
|
||||
from cython.cimports.av.stream import Stream
|
||||
from cython.cimports.libc.errno import EAGAIN
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class BitStreamFilterContext:
|
||||
"""
|
||||
Initializes a bitstream filter: a way to directly modify packet data.
|
||||
|
||||
Wraps :ffmpeg:`AVBSFContext`
|
||||
|
||||
:param Stream in_stream: A stream that defines the input codec for the bitfilter.
|
||||
:param Stream out_stream: A stream whose codec is overwritten using the output parameters from the bitfilter.
|
||||
"""
|
||||
|
||||
def __cinit__(
|
||||
self,
|
||||
filter_description,
|
||||
in_stream: Stream | None = None,
|
||||
out_stream: Stream | None = None,
|
||||
):
|
||||
res: cython.int
|
||||
filter_str: cython.p_char = filter_description
|
||||
|
||||
with cython.nogil:
|
||||
res = lib.av_bsf_list_parse_str(filter_str, cython.address(self.ptr))
|
||||
err_check(res)
|
||||
|
||||
if in_stream is not None:
|
||||
with cython.nogil:
|
||||
res = lib.avcodec_parameters_copy(
|
||||
self.ptr.par_in, in_stream.ptr.codecpar
|
||||
)
|
||||
err_check(res)
|
||||
|
||||
with cython.nogil:
|
||||
res = lib.av_bsf_init(self.ptr)
|
||||
err_check(res)
|
||||
|
||||
if out_stream is not None:
|
||||
with cython.nogil:
|
||||
res = lib.avcodec_parameters_copy(
|
||||
out_stream.ptr.codecpar, self.ptr.par_out
|
||||
)
|
||||
err_check(res)
|
||||
lib.avcodec_parameters_to_context(
|
||||
out_stream.codec_context.ptr, out_stream.ptr.codecpar
|
||||
)
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.ptr:
|
||||
lib.av_bsf_free(cython.address(self.ptr))
|
||||
|
||||
@cython.ccall
|
||||
def filter(self, packet: Packet | None = None):
|
||||
"""
|
||||
Processes a packet based on the filter_description set during initialization.
|
||||
Multiple packets may be created.
|
||||
|
||||
:type: list[Packet]
|
||||
"""
|
||||
res: cython.int
|
||||
new_packet: Packet
|
||||
|
||||
with cython.nogil:
|
||||
res = lib.av_bsf_send_packet(
|
||||
self.ptr, packet.ptr if packet is not None else cython.NULL
|
||||
)
|
||||
err_check(res)
|
||||
|
||||
output: list = []
|
||||
while True:
|
||||
new_packet = Packet()
|
||||
with cython.nogil:
|
||||
res = lib.av_bsf_receive_packet(self.ptr, new_packet.ptr)
|
||||
|
||||
if res == -EAGAIN or res == lib.AVERROR_EOF:
|
||||
return output
|
||||
|
||||
err_check(res)
|
||||
if res:
|
||||
return output
|
||||
|
||||
output.append(new_packet)
|
||||
|
||||
@cython.ccall
|
||||
def flush(self):
|
||||
"""
|
||||
Reset the internal state of the filter.
|
||||
Should be called e.g. when seeking.
|
||||
Can be used to make the filter usable again after draining it with EOF marker packet.
|
||||
"""
|
||||
lib.av_bsf_flush(self.ptr)
|
||||
|
||||
|
||||
@cython.cfunc
|
||||
def get_filter_names() -> set:
|
||||
names: set = set()
|
||||
ptr: cython.pointer[cython.const[lib.AVBitStreamFilter]]
|
||||
opaque: cython.p_void = cython.NULL
|
||||
while True:
|
||||
ptr = lib.av_bsf_iterate(cython.address(opaque))
|
||||
if ptr:
|
||||
names.add(ptr.name)
|
||||
else:
|
||||
break
|
||||
|
||||
return names
|
||||
|
||||
|
||||
bitstream_filters_available = get_filter_names()
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
cimport libav as lib
|
||||
from libc.errno cimport EAGAIN
|
||||
|
||||
from av.error cimport err_check
|
||||
from av.packet cimport Packet
|
||||
from av.stream cimport Stream
|
||||
|
||||
|
||||
cdef class BitStreamFilterContext:
|
||||
"""
|
||||
Initializes a bitstream filter: a way to directly modify packet data.
|
||||
|
||||
Wraps :ffmpeg:`AVBSFContext`
|
||||
|
||||
:param Stream in_stream: A stream that defines the input codec for the bitfilter.
|
||||
:param Stream out_stream: A stream whose codec is overwritten using the output parameters from the bitfilter.
|
||||
"""
|
||||
def __cinit__(self, filter_description, Stream in_stream=None, Stream out_stream=None):
|
||||
cdef int res
|
||||
cdef char *filter_str = filter_description
|
||||
|
||||
with nogil:
|
||||
res = lib.av_bsf_list_parse_str(filter_str, &self.ptr)
|
||||
err_check(res)
|
||||
|
||||
if in_stream is not None:
|
||||
with nogil:
|
||||
res = lib.avcodec_parameters_copy(self.ptr.par_in, in_stream.ptr.codecpar)
|
||||
err_check(res)
|
||||
|
||||
with nogil:
|
||||
res = lib.av_bsf_init(self.ptr)
|
||||
err_check(res)
|
||||
|
||||
if out_stream is not None:
|
||||
with nogil:
|
||||
res = lib.avcodec_parameters_copy(out_stream.ptr.codecpar, self.ptr.par_out)
|
||||
err_check(res)
|
||||
lib.avcodec_parameters_to_context(out_stream.codec_context.ptr, out_stream.ptr.codecpar)
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.ptr:
|
||||
lib.av_bsf_free(&self.ptr)
|
||||
|
||||
cpdef filter(self, Packet packet=None):
|
||||
"""
|
||||
Processes a packet based on the filter_description set during initialization.
|
||||
Multiple packets may be created.
|
||||
|
||||
:type: list[Packet]
|
||||
"""
|
||||
cdef int res
|
||||
cdef Packet new_packet
|
||||
|
||||
with nogil:
|
||||
res = lib.av_bsf_send_packet(self.ptr, packet.ptr if packet is not None else NULL)
|
||||
err_check(res)
|
||||
|
||||
output = []
|
||||
while True:
|
||||
new_packet = Packet()
|
||||
with nogil:
|
||||
res = lib.av_bsf_receive_packet(self.ptr, new_packet.ptr)
|
||||
|
||||
if res == -EAGAIN or res == lib.AVERROR_EOF:
|
||||
return output
|
||||
|
||||
err_check(res)
|
||||
if res:
|
||||
return output
|
||||
|
||||
output.append(new_packet)
|
||||
|
||||
cpdef flush(self):
|
||||
"""
|
||||
Reset the internal state of the filter.
|
||||
Should be called e.g. when seeking.
|
||||
Can be used to make the filter usable again after draining it with EOF marker packet.
|
||||
"""
|
||||
lib.av_bsf_flush(self.ptr)
|
||||
|
||||
cdef get_filter_names():
|
||||
names = set()
|
||||
cdef const lib.AVBitStreamFilter *ptr
|
||||
cdef void *opaque = NULL
|
||||
while True:
|
||||
ptr = lib.av_bsf_iterate(&opaque)
|
||||
if ptr:
|
||||
names.add(ptr.name)
|
||||
else:
|
||||
break
|
||||
|
||||
return names
|
||||
|
||||
bitstream_filters_available = get_filter_names()
|
||||
BIN
venv/lib/python3.12/site-packages/av/buffer.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/buffer.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,16 @@
|
|||
from cpython.buffer cimport Py_buffer
|
||||
|
||||
|
||||
cdef class ByteSource:
|
||||
cdef object owner
|
||||
cdef bint has_view
|
||||
cdef Py_buffer view
|
||||
cdef unsigned char *ptr
|
||||
cdef size_t length
|
||||
|
||||
cdef ByteSource bytesource(object, bint allow_none=*)
|
||||
|
||||
cdef class Buffer:
|
||||
|
||||
cdef size_t _buffer_size(self)
|
||||
cdef void* _buffer_ptr(self)
|
||||
cdef bint _buffer_writable(self)
|
||||
|
|
|
|||
100
venv/lib/python3.12/site-packages/av/buffer.py
Normal file
100
venv/lib/python3.12/site-packages/av/buffer.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import cython
|
||||
from cython.cimports.cpython import PyBUF_WRITABLE, PyBuffer_FillInfo
|
||||
from cython.cimports.cpython.buffer import (
|
||||
PyBUF_SIMPLE,
|
||||
PyBuffer_Release,
|
||||
PyObject_CheckBuffer,
|
||||
PyObject_GetBuffer,
|
||||
)
|
||||
from cython.cimports.libc.string import memcpy
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class ByteSource:
|
||||
def __cinit__(self, owner):
|
||||
self.owner = owner
|
||||
|
||||
try:
|
||||
self.ptr = owner
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
self.length = len(owner)
|
||||
return
|
||||
|
||||
if PyObject_CheckBuffer(owner):
|
||||
# Can very likely use PyBUF_ND instead of PyBUF_SIMPLE
|
||||
res = PyObject_GetBuffer(owner, cython.address(self.view), PyBUF_SIMPLE)
|
||||
if not res:
|
||||
self.has_view = True
|
||||
self.ptr = cython.cast(cython.p_uchar, self.view.buf)
|
||||
self.length = self.view.len
|
||||
return
|
||||
|
||||
raise TypeError("expected bytes, bytearray or memoryview")
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.has_view:
|
||||
PyBuffer_Release(cython.address(self.view))
|
||||
|
||||
|
||||
@cython.cfunc
|
||||
def bytesource(obj, allow_none: cython.bint = False) -> ByteSource | None:
|
||||
if allow_none and obj is None:
|
||||
return None
|
||||
elif isinstance(obj, ByteSource):
|
||||
return obj
|
||||
else:
|
||||
return ByteSource(obj)
|
||||
|
||||
|
||||
@cython.cclass
|
||||
class Buffer:
|
||||
"""A base class for PyAV objects which support the buffer protocol, such
|
||||
as :class:`.Packet` and :class:`.Plane`.
|
||||
|
||||
"""
|
||||
|
||||
@cython.cfunc
|
||||
def _buffer_size(self) -> cython.size_t:
|
||||
return 0
|
||||
|
||||
def _buffer_ptr(self) -> cython.p_void:
|
||||
return cython.NULL
|
||||
|
||||
def _buffer_writable(self) -> cython.bint:
|
||||
return True
|
||||
|
||||
def __getbuffer__(self, view: cython.pointer[Py_buffer], flags: cython.int):
|
||||
if flags & PyBUF_WRITABLE and not self._buffer_writable():
|
||||
raise ValueError("buffer is not writable")
|
||||
|
||||
PyBuffer_FillInfo(view, self, self._buffer_ptr(), self._buffer_size(), 0, flags)
|
||||
|
||||
@property
|
||||
def buffer_size(self):
|
||||
return self._buffer_size()
|
||||
|
||||
@property
|
||||
def buffer_ptr(self):
|
||||
"""The memory address of the buffer."""
|
||||
return cython.cast(cython.size_t, self._buffer_ptr())
|
||||
|
||||
def update(self, input):
|
||||
"""Replace the data in this object with the given buffer.
|
||||
|
||||
Accepts anything that supports the `buffer protocol <https://docs.python.org/3/c-api/buffer.html>`_,
|
||||
e.g. bytes, NumPy arrays, other :class:`Buffer` objects, etc..
|
||||
|
||||
"""
|
||||
if not self._buffer_writable():
|
||||
raise ValueError("buffer is not writable")
|
||||
|
||||
source: ByteSource = bytesource(input)
|
||||
size: cython.size_t = self._buffer_size()
|
||||
|
||||
if source.length != size:
|
||||
raise ValueError(f"got {source.length} bytes; need {size} bytes")
|
||||
|
||||
memcpy(self._buffer_ptr(), source.ptr, size)
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
from cpython cimport PyBUF_WRITABLE, PyBuffer_FillInfo
|
||||
from libc.string cimport memcpy
|
||||
|
||||
from av.bytesource cimport ByteSource, bytesource
|
||||
|
||||
|
||||
cdef class Buffer:
|
||||
"""A base class for PyAV objects which support the buffer protocol, such
|
||||
as :class:`.Packet` and :class:`.Plane`.
|
||||
|
||||
"""
|
||||
|
||||
cdef size_t _buffer_size(self):
|
||||
return 0
|
||||
|
||||
cdef void* _buffer_ptr(self):
|
||||
return NULL
|
||||
|
||||
cdef bint _buffer_writable(self):
|
||||
return True
|
||||
|
||||
def __getbuffer__(self, Py_buffer *view, int flags):
|
||||
if flags & PyBUF_WRITABLE and not self._buffer_writable():
|
||||
raise ValueError("buffer is not writable")
|
||||
|
||||
PyBuffer_FillInfo(view, self, self._buffer_ptr(), self._buffer_size(), 0, flags)
|
||||
|
||||
@property
|
||||
def buffer_size(self):
|
||||
"""The size of the buffer in bytes."""
|
||||
return self._buffer_size()
|
||||
|
||||
@property
|
||||
def buffer_ptr(self):
|
||||
"""The memory address of the buffer."""
|
||||
return <size_t>self._buffer_ptr()
|
||||
|
||||
def update(self, input):
|
||||
"""Replace the data in this object with the given buffer.
|
||||
|
||||
Accepts anything that supports the `buffer protocol <https://docs.python.org/3/c-api/buffer.html>`_,
|
||||
e.g. bytes, Numpy arrays, other :class:`Buffer` objects, etc..
|
||||
|
||||
"""
|
||||
if not self._buffer_writable():
|
||||
raise ValueError("buffer is not writable")
|
||||
|
||||
cdef ByteSource source = bytesource(input)
|
||||
cdef size_t size = self._buffer_size()
|
||||
|
||||
if source.length != size:
|
||||
raise ValueError(f"got {source.length} bytes; need {size} bytes")
|
||||
|
||||
memcpy(self._buffer_ptr(), source.ptr, size)
|
||||
Binary file not shown.
|
|
@ -1,14 +0,0 @@
|
|||
from cpython.buffer cimport Py_buffer
|
||||
|
||||
|
||||
cdef class ByteSource:
|
||||
|
||||
cdef object owner
|
||||
|
||||
cdef bint has_view
|
||||
cdef Py_buffer view
|
||||
|
||||
cdef unsigned char *ptr
|
||||
cdef size_t length
|
||||
|
||||
cdef ByteSource bytesource(object, bint allow_none=*)
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
from cpython.buffer cimport (
|
||||
PyBUF_SIMPLE,
|
||||
PyBuffer_Release,
|
||||
PyObject_CheckBuffer,
|
||||
PyObject_GetBuffer,
|
||||
)
|
||||
|
||||
|
||||
cdef class ByteSource:
|
||||
def __cinit__(self, owner):
|
||||
self.owner = owner
|
||||
|
||||
try:
|
||||
self.ptr = owner
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
self.length = len(owner)
|
||||
return
|
||||
|
||||
if PyObject_CheckBuffer(owner):
|
||||
# Can very likely use PyBUF_ND instead of PyBUF_SIMPLE
|
||||
res = PyObject_GetBuffer(owner, &self.view, PyBUF_SIMPLE)
|
||||
if not res:
|
||||
self.has_view = True
|
||||
self.ptr = <unsigned char *>self.view.buf
|
||||
self.length = self.view.len
|
||||
return
|
||||
|
||||
raise TypeError("expected bytes, bytearray or memoryview")
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.has_view:
|
||||
PyBuffer_Release(&self.view)
|
||||
|
||||
|
||||
cdef ByteSource bytesource(obj, bint allow_none=False):
|
||||
if allow_none and obj is None:
|
||||
return
|
||||
elif isinstance(obj, ByteSource):
|
||||
return obj
|
||||
else:
|
||||
return ByteSource(obj)
|
||||
|
|
@ -2,7 +2,6 @@ from .codec import (
|
|||
Capabilities,
|
||||
Codec,
|
||||
Properties,
|
||||
codec_descriptor,
|
||||
codecs_available,
|
||||
find_best_pix_fmt_of_list,
|
||||
)
|
||||
|
|
@ -12,7 +11,6 @@ __all__ = (
|
|||
"Capabilities",
|
||||
"Codec",
|
||||
"Properties",
|
||||
"codec_descriptor",
|
||||
"codecs_available",
|
||||
"find_best_pix_fmt_of_list",
|
||||
"CodecContext",
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
venv/lib/python3.12/site-packages/av/codec/codec.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/codec/codec.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -1,24 +1,25 @@
|
|||
cimport libav as lib
|
||||
|
||||
from av.audio.format cimport get_audio_format
|
||||
from av.codec.hwaccel cimport wrap_hwconfig
|
||||
from av.descriptor cimport wrap_avclass
|
||||
from av.utils cimport avrational_to_fraction
|
||||
from av.video.format cimport VideoFormat, get_pix_fmt, get_video_format
|
||||
|
||||
from enum import Flag, IntEnum
|
||||
from libc.stdlib cimport free, malloc
|
||||
|
||||
import cython
|
||||
from cython.cimports import libav as lib
|
||||
from cython.cimports.av.audio.format import get_audio_format
|
||||
from cython.cimports.av.codec.hwaccel import wrap_hwconfig
|
||||
from cython.cimports.av.utils import avrational_to_fraction
|
||||
from cython.cimports.av.video.format import VideoFormat, get_pix_fmt, get_video_format
|
||||
from cython.cimports.libc.stdlib import free, malloc
|
||||
|
||||
_cinit_sentinel = cython.declare(object, object())
|
||||
|
||||
|
||||
cdef object _cinit_sentinel = object()
|
||||
|
||||
cdef Codec wrap_codec(const lib.AVCodec *ptr):
|
||||
cdef Codec codec = Codec(_cinit_sentinel)
|
||||
@cython.cfunc
|
||||
def wrap_codec(ptr: cython.pointer[cython.const[lib.AVCodec]]) -> Codec:
|
||||
codec: Codec = Codec(_cinit_sentinel)
|
||||
codec.ptr = ptr
|
||||
codec.is_encoder = lib.av_codec_is_encoder(ptr)
|
||||
codec._init()
|
||||
return codec
|
||||
|
||||
|
||||
class Properties(Flag):
|
||||
NONE = 0
|
||||
INTRA_ONLY = lib.AV_CODEC_PROP_INTRA_ONLY
|
||||
|
|
@ -57,7 +58,9 @@ class UnknownCodecError(ValueError):
|
|||
pass
|
||||
|
||||
|
||||
cdef class Codec:
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class Codec:
|
||||
"""Codec(name, mode='r')
|
||||
|
||||
:param str name: The codec name.
|
||||
|
|
@ -105,7 +108,8 @@ cdef class Codec:
|
|||
if (mode == "w") != self.is_encoder:
|
||||
raise RuntimeError("Found codec does not match mode.", name, mode)
|
||||
|
||||
cdef _init(self, name=None):
|
||||
@cython.cfunc
|
||||
def _init(self, name=None):
|
||||
if not self.ptr:
|
||||
raise UnknownCodecError(name)
|
||||
|
||||
|
|
@ -124,12 +128,13 @@ cdef class Codec:
|
|||
mode = self.mode
|
||||
return f"<av.{self.__class__.__name__} {self.name} {mode=}>"
|
||||
|
||||
def create(self, kind = None):
|
||||
def create(self, kind=None):
|
||||
"""Create a :class:`.CodecContext` for this codec.
|
||||
|
||||
:param str kind: Gives a hint to static type checkers for what exact CodecContext is used.
|
||||
"""
|
||||
from .context import CodecContext
|
||||
|
||||
return CodecContext.create(self)
|
||||
|
||||
@property
|
||||
|
|
@ -141,10 +146,8 @@ cdef class Codec:
|
|||
return not self.is_encoder
|
||||
|
||||
@property
|
||||
def descriptor(self): return wrap_avclass(self.ptr.priv_class)
|
||||
|
||||
@property
|
||||
def name(self): return self.ptr.name or ""
|
||||
def name(self):
|
||||
return self.ptr.name or ""
|
||||
|
||||
@property
|
||||
def canonical_name(self):
|
||||
|
|
@ -154,7 +157,8 @@ cdef class Codec:
|
|||
return lib.avcodec_get_name(self.ptr.id)
|
||||
|
||||
@property
|
||||
def long_name(self): return self.ptr.long_name or ""
|
||||
def long_name(self):
|
||||
return self.ptr.long_name or ""
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
|
|
@ -164,79 +168,100 @@ cdef class Codec:
|
|||
E.g: ``'audio'``, ``'video'``, ``'subtitle'``.
|
||||
|
||||
"""
|
||||
return lib.av_get_media_type_string(self.ptr.type)
|
||||
media_type = lib.av_get_media_type_string(self.ptr.type)
|
||||
return "unknown" if media_type == cython.NULL else media_type
|
||||
|
||||
@property
|
||||
def id(self): return self.ptr.id
|
||||
def id(self):
|
||||
return self.ptr.id
|
||||
|
||||
@property
|
||||
def frame_rates(self):
|
||||
"""A list of supported frame rates (:class:`fractions.Fraction`), or ``None``."""
|
||||
if not self.ptr.supported_framerates:
|
||||
out: cython.pointer[cython.const[cython.void]] = cython.NULL
|
||||
num: cython.int = 0
|
||||
lib.avcodec_get_supported_config(
|
||||
cython.NULL,
|
||||
self.ptr,
|
||||
lib.AV_CODEC_CONFIG_FRAME_RATE,
|
||||
0,
|
||||
cython.address(out),
|
||||
cython.address(num),
|
||||
)
|
||||
if not out:
|
||||
return
|
||||
|
||||
ret = []
|
||||
cdef int i = 0
|
||||
while self.ptr.supported_framerates[i].denum:
|
||||
ret.append(avrational_to_fraction(&self.ptr.supported_framerates[i]))
|
||||
i += 1
|
||||
return ret
|
||||
rates = cython.cast(cython.pointer[lib.AVRational], out)
|
||||
return [avrational_to_fraction(cython.address(rates[i])) for i in range(num)]
|
||||
|
||||
@property
|
||||
def audio_rates(self):
|
||||
"""A list of supported audio sample rates (``int``), or ``None``."""
|
||||
if not self.ptr.supported_samplerates:
|
||||
out: cython.pointer[cython.const[cython.void]] = cython.NULL
|
||||
num: cython.int = 0
|
||||
lib.avcodec_get_supported_config(
|
||||
cython.NULL,
|
||||
self.ptr,
|
||||
lib.AV_CODEC_CONFIG_SAMPLE_RATE,
|
||||
0,
|
||||
cython.address(out),
|
||||
cython.address(num),
|
||||
)
|
||||
if not out:
|
||||
return
|
||||
|
||||
ret = []
|
||||
cdef int i = 0
|
||||
while self.ptr.supported_samplerates[i]:
|
||||
ret.append(self.ptr.supported_samplerates[i])
|
||||
i += 1
|
||||
return ret
|
||||
rates = cython.cast(cython.pointer[cython.int], out)
|
||||
return [rates[i] for i in range(num)]
|
||||
|
||||
@property
|
||||
def video_formats(self):
|
||||
"""A list of supported :class:`.VideoFormat`, or ``None``."""
|
||||
if not self.ptr.pix_fmts:
|
||||
out: cython.pointer[cython.const[cython.void]] = cython.NULL
|
||||
num: cython.int = 0
|
||||
lib.avcodec_get_supported_config(
|
||||
cython.NULL,
|
||||
self.ptr,
|
||||
lib.AV_CODEC_CONFIG_PIX_FORMAT,
|
||||
0,
|
||||
cython.address(out),
|
||||
cython.address(num),
|
||||
)
|
||||
if not out:
|
||||
return
|
||||
|
||||
ret = []
|
||||
cdef int i = 0
|
||||
while self.ptr.pix_fmts[i] != -1:
|
||||
ret.append(get_video_format(self.ptr.pix_fmts[i], 0, 0))
|
||||
i += 1
|
||||
return ret
|
||||
fmts = cython.cast(cython.pointer[lib.AVPixelFormat], out)
|
||||
return [get_video_format(fmts[i], 0, 0) for i in range(num)]
|
||||
|
||||
@property
|
||||
def audio_formats(self):
|
||||
"""A list of supported :class:`.AudioFormat`, or ``None``."""
|
||||
if not self.ptr.sample_fmts:
|
||||
out: cython.pointer[cython.const[cython.void]] = cython.NULL
|
||||
num: cython.int = 0
|
||||
lib.avcodec_get_supported_config(
|
||||
cython.NULL,
|
||||
self.ptr,
|
||||
lib.AV_CODEC_CONFIG_SAMPLE_FORMAT,
|
||||
0,
|
||||
cython.address(out),
|
||||
cython.address(num),
|
||||
)
|
||||
if not out:
|
||||
return
|
||||
|
||||
ret = []
|
||||
cdef int i = 0
|
||||
while self.ptr.sample_fmts[i] != -1:
|
||||
ret.append(get_audio_format(self.ptr.sample_fmts[i]))
|
||||
i += 1
|
||||
return ret
|
||||
fmts = cython.cast(cython.pointer[lib.AVSampleFormat], out)
|
||||
return [get_audio_format(fmts[i]) for i in range(num)]
|
||||
|
||||
@property
|
||||
def hardware_configs(self):
|
||||
if self._hardware_configs:
|
||||
return self._hardware_configs
|
||||
ret = []
|
||||
cdef int i = 0
|
||||
cdef const lib.AVCodecHWConfig *ptr
|
||||
ret: list = []
|
||||
i: cython.int = 0
|
||||
ptr: cython.pointer[cython.const[lib.AVCodecHWConfig]]
|
||||
while True:
|
||||
ptr = lib.avcodec_get_hw_config(self.ptr, i)
|
||||
if not ptr:
|
||||
break
|
||||
ret.append(wrap_hwconfig(ptr))
|
||||
i += 1
|
||||
ret = tuple(ret)
|
||||
self._hardware_configs = ret
|
||||
return ret
|
||||
self._hardware_configs = tuple(ret)
|
||||
return self._hardware_configs
|
||||
|
||||
@property
|
||||
def properties(self):
|
||||
|
|
@ -309,12 +334,14 @@ cdef class Codec:
|
|||
"""
|
||||
return bool(self.ptr.capabilities & lib.AV_CODEC_CAP_DELAY)
|
||||
|
||||
cdef get_codec_names():
|
||||
names = set()
|
||||
cdef const lib.AVCodec *ptr
|
||||
cdef void *opaque = NULL
|
||||
|
||||
@cython.cfunc
|
||||
def get_codec_names():
|
||||
names: cython.set = set()
|
||||
ptr = cython.declare(cython.pointer[cython.const[lib.AVCodec]])
|
||||
opaque: cython.p_void = cython.NULL
|
||||
while True:
|
||||
ptr = lib.av_codec_iterate(&opaque)
|
||||
ptr = lib.av_codec_iterate(cython.address(opaque))
|
||||
if ptr:
|
||||
names.add(ptr.name)
|
||||
else:
|
||||
|
|
@ -323,7 +350,6 @@ cdef get_codec_names():
|
|||
|
||||
|
||||
codecs_available = get_codec_names()
|
||||
codec_descriptor = wrap_avclass(lib.avcodec_get_class())
|
||||
|
||||
|
||||
def dump_codecs():
|
||||
|
|
@ -373,6 +399,7 @@ def dump_codecs():
|
|||
except Exception as e:
|
||||
print(f"...... {codec.name:<18} ERROR: {e}")
|
||||
|
||||
|
||||
def dump_hwconfigs():
|
||||
print("Hardware configs:")
|
||||
for name in sorted(codecs_available):
|
||||
|
|
@ -402,13 +429,13 @@ def find_best_pix_fmt_of_list(pix_fmts, src_pix_fmt, has_alpha=False):
|
|||
:return: (best_format, loss)
|
||||
:rtype: (VideoFormat | None, int)
|
||||
"""
|
||||
cdef lib.AVPixelFormat src
|
||||
cdef lib.AVPixelFormat best
|
||||
cdef lib.AVPixelFormat *c_list = NULL
|
||||
cdef Py_ssize_t n
|
||||
cdef Py_ssize_t i
|
||||
cdef object item
|
||||
cdef int c_loss
|
||||
src: lib.AVPixelFormat
|
||||
best: lib.AVPixelFormat
|
||||
c_list: cython.pointer[lib.AVPixelFormat] = cython.NULL
|
||||
n: cython.Py_ssize_t
|
||||
i: cython.Py_ssize_t
|
||||
item: object
|
||||
c_loss: cython.int
|
||||
|
||||
if pix_fmts is None:
|
||||
raise TypeError("pix_fmts must not be None")
|
||||
|
|
@ -418,29 +445,32 @@ def find_best_pix_fmt_of_list(pix_fmts, src_pix_fmt, has_alpha=False):
|
|||
return None, 0
|
||||
|
||||
if isinstance(src_pix_fmt, VideoFormat):
|
||||
src = (<VideoFormat>src_pix_fmt).pix_fmt
|
||||
src = cython.cast(VideoFormat, src_pix_fmt).pix_fmt
|
||||
else:
|
||||
src = get_pix_fmt(<str>src_pix_fmt)
|
||||
src = get_pix_fmt(cython.cast(str, src_pix_fmt))
|
||||
|
||||
n = len(pix_fmts)
|
||||
c_list = <lib.AVPixelFormat *>malloc((n + 1) * sizeof(lib.AVPixelFormat))
|
||||
if c_list == NULL:
|
||||
c_list = cython.cast(
|
||||
cython.pointer[lib.AVPixelFormat],
|
||||
malloc((n + 1) * cython.sizeof(lib.AVPixelFormat)),
|
||||
)
|
||||
if c_list == cython.NULL:
|
||||
raise MemoryError()
|
||||
|
||||
try:
|
||||
for i in range(n):
|
||||
item = pix_fmts[i]
|
||||
if isinstance(item, VideoFormat):
|
||||
c_list[i] = (<VideoFormat>item).pix_fmt
|
||||
c_list[i] = cython.cast(VideoFormat, item).pix_fmt
|
||||
else:
|
||||
c_list[i] = get_pix_fmt(<str>item)
|
||||
c_list[i] = get_pix_fmt(cython.cast(str, item))
|
||||
c_list[n] = lib.AV_PIX_FMT_NONE
|
||||
|
||||
c_loss = 0
|
||||
best = lib.avcodec_find_best_pix_fmt_of_list(
|
||||
c_list, src, 1 if has_alpha else 0, &c_loss
|
||||
c_list, src, 1 if has_alpha else 0, cython.address(c_loss)
|
||||
)
|
||||
return get_video_format(best, 0, 0), c_loss
|
||||
finally:
|
||||
if c_list != NULL:
|
||||
if c_list != cython.NULL:
|
||||
free(c_list)
|
||||
|
|
@ -4,7 +4,6 @@ from typing import ClassVar, Literal, Sequence, cast, overload
|
|||
|
||||
from av.audio.codeccontext import AudioCodecContext
|
||||
from av.audio.format import AudioFormat
|
||||
from av.descriptor import Descriptor
|
||||
from av.subtitles.codeccontext import SubtitleCodecContext
|
||||
from av.video.codeccontext import VideoCodecContext
|
||||
from av.video.format import VideoFormat
|
||||
|
|
@ -53,7 +52,6 @@ class Codec:
|
|||
def is_decoder(self) -> bool: ...
|
||||
@property
|
||||
def mode(self) -> Literal["r", "w"]: ...
|
||||
descriptor: Descriptor
|
||||
@property
|
||||
def name(self) -> str: ...
|
||||
@property
|
||||
|
|
@ -61,7 +59,9 @@ class Codec:
|
|||
@property
|
||||
def long_name(self) -> str: ...
|
||||
@property
|
||||
def type(self) -> Literal["video", "audio", "data", "subtitle", "attachment"]: ...
|
||||
def type(
|
||||
self,
|
||||
) -> Literal["video", "audio", "data", "subtitle", "attachment", "unknown"]: ...
|
||||
@property
|
||||
def id(self) -> int: ...
|
||||
frame_rates: list[Fraction] | None
|
||||
|
|
@ -105,10 +105,6 @@ class Codec:
|
|||
VideoCodecContext | AudioCodecContext | SubtitleCodecContext | CodecContext
|
||||
): ...
|
||||
|
||||
class codec_descriptor:
|
||||
name: str
|
||||
options: tuple[int, ...]
|
||||
|
||||
codecs_available: set[str]
|
||||
|
||||
def dump_codecs() -> None: ...
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/codec/context.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/codec/context.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
cimport libav as lib
|
||||
from libc.stdint cimport int64_t
|
||||
from libc.stdint cimport int64_t, uint8_t
|
||||
|
||||
from av.bytesource cimport ByteSource
|
||||
from av.buffer cimport ByteSource
|
||||
from av.codec.codec cimport Codec
|
||||
from av.codec.hwaccel cimport HWAccel
|
||||
from av.frame cimport Frame
|
||||
|
|
@ -11,9 +11,6 @@ from av.packet cimport Packet
|
|||
cdef class CodecContext:
|
||||
cdef lib.AVCodecContext *ptr
|
||||
|
||||
# Whether AVCodecContext.extradata should be de-allocated upon destruction.
|
||||
cdef bint extradata_set
|
||||
|
||||
# Used as a signal that this is within a stream, and also for us to access that
|
||||
# stream. This is set "manually" by the stream after constructing this object.
|
||||
cdef int stream_index
|
||||
|
|
@ -36,11 +33,15 @@ cdef class CodecContext:
|
|||
# Used by hardware-accelerated decode.
|
||||
cdef HWAccel hwaccel_ctx
|
||||
|
||||
cdef uint8_t _ctxflags # ctxEnum: template_initialized
|
||||
# True when created via add_stream_from_template(); start_encoding() skips
|
||||
# avcodec_open2() and lets encode()/decode() open the codec lazily if needed.
|
||||
|
||||
# Used by both transcode APIs to setup user-land objects.
|
||||
# TODO: Remove the `Packet` from `_setup_decoded_frame` (because flushing packets
|
||||
# are bogus). It should take all info it needs from the context and/or stream.
|
||||
cdef _prepare_and_time_rebase_frames_for_encode(self, Frame frame)
|
||||
cdef _prepare_frames_for_encode(self, Frame frame)
|
||||
cdef list _prepare_frames_for_encode(self, Frame frame)
|
||||
cdef _setup_encoded_packet(self, Packet)
|
||||
cdef _setup_decoded_frame(self, Frame, Packet)
|
||||
|
||||
|
|
@ -51,7 +52,6 @@ cdef class CodecContext:
|
|||
# send/recv buffer may be limited to a single frame. Ergo, we need to flush
|
||||
# the buffer as often as possible.
|
||||
cdef _recv_packet(self)
|
||||
cdef _send_packet_and_recv(self, Packet packet)
|
||||
cdef _recv_frame(self)
|
||||
|
||||
cdef _transfer_hwframe(self, Frame frame)
|
||||
|
|
|
|||
|
|
@ -1,36 +1,40 @@
|
|||
cimport libav as lib
|
||||
from libc.errno cimport EAGAIN
|
||||
from libc.stdint cimport uint8_t
|
||||
from libc.string cimport memcpy
|
||||
|
||||
from av.bytesource cimport ByteSource, bytesource
|
||||
from av.codec.codec cimport Codec, wrap_codec
|
||||
from av.dictionary cimport _Dictionary
|
||||
from av.error cimport err_check
|
||||
from av.packet cimport Packet
|
||||
from av.utils cimport avrational_to_fraction, to_avrational
|
||||
|
||||
from enum import Flag, IntEnum
|
||||
|
||||
from av.dictionary import Dictionary
|
||||
import cython
|
||||
from cython.cimports import libav as lib
|
||||
from cython.cimports.av.buffer import ByteSource, bytesource
|
||||
from cython.cimports.av.codec.codec import Codec, wrap_codec
|
||||
from cython.cimports.av.dictionary import Dictionary
|
||||
from cython.cimports.av.error import err_check
|
||||
from cython.cimports.av.packet import Packet
|
||||
from cython.cimports.av.utils import avrational_to_fraction, to_avrational
|
||||
from cython.cimports.libc.errno import EAGAIN
|
||||
from cython.cimports.libc.stdint import uint8_t
|
||||
from cython.cimports.libc.string import memcpy
|
||||
|
||||
_cinit_sentinel = cython.declare(object, object())
|
||||
|
||||
|
||||
cdef object _cinit_sentinel = object()
|
||||
|
||||
|
||||
cdef CodecContext wrap_codec_context(lib.AVCodecContext *c_ctx, const lib.AVCodec *c_codec, HWAccel hwaccel):
|
||||
"""Build an av.CodecContext for an existing AVCodecContext."""
|
||||
|
||||
cdef CodecContext py_ctx
|
||||
@cython.cfunc
|
||||
def wrap_codec_context(
|
||||
c_ctx: cython.pointer[lib.AVCodecContext],
|
||||
c_codec: cython.pointer[cython.const[lib.AVCodec]],
|
||||
hwaccel: HWAccel,
|
||||
) -> CodecContext:
|
||||
"""Build an bv.CodecContext for an existing AVCodecContext."""
|
||||
py_ctx: CodecContext
|
||||
|
||||
if c_ctx.codec_type == lib.AVMEDIA_TYPE_VIDEO:
|
||||
from av.video.codeccontext import VideoCodecContext
|
||||
|
||||
py_ctx = VideoCodecContext(_cinit_sentinel)
|
||||
elif c_ctx.codec_type == lib.AVMEDIA_TYPE_AUDIO:
|
||||
from av.audio.codeccontext import AudioCodecContext
|
||||
|
||||
py_ctx = AudioCodecContext(_cinit_sentinel)
|
||||
elif c_ctx.codec_type == lib.AVMEDIA_TYPE_SUBTITLE:
|
||||
from av.subtitles.codeccontext import SubtitleCodecContext
|
||||
|
||||
py_ctx = SubtitleCodecContext(_cinit_sentinel)
|
||||
else:
|
||||
py_ctx = CodecContext(_cinit_sentinel)
|
||||
|
|
@ -44,7 +48,10 @@ class ThreadType(Flag):
|
|||
NONE = 0
|
||||
FRAME: "Decode more than one frame at once" = lib.FF_THREAD_FRAME
|
||||
SLICE: "Decode more than one part of a single frame at once" = lib.FF_THREAD_SLICE
|
||||
AUTO: "Decode using both FRAME and SLICE methods." = lib.FF_THREAD_SLICE | lib.FF_THREAD_FRAME
|
||||
AUTO: "Decode using both FRAME and SLICE methods." = (
|
||||
lib.FF_THREAD_SLICE | lib.FF_THREAD_FRAME
|
||||
)
|
||||
|
||||
|
||||
class Flags(IntEnum):
|
||||
unaligned = lib.AV_CODEC_FLAG_UNALIGNED
|
||||
|
|
@ -68,6 +75,7 @@ class Flags(IntEnum):
|
|||
interlaced_me = lib.AV_CODEC_FLAG_INTERLACED_ME
|
||||
closed_gop = lib.AV_CODEC_FLAG_CLOSED_GOP
|
||||
|
||||
|
||||
class Flags2(IntEnum):
|
||||
fast = lib.AV_CODEC_FLAG2_FAST
|
||||
no_output = lib.AV_CODEC_FLAG2_NO_OUTPUT
|
||||
|
|
@ -80,11 +88,14 @@ class Flags2(IntEnum):
|
|||
ro_flush_noop = lib.AV_CODEC_FLAG2_RO_FLUSH_NOOP
|
||||
|
||||
|
||||
cdef class CodecContext:
|
||||
@cython.cclass
|
||||
class CodecContext:
|
||||
@staticmethod
|
||||
def create(codec, mode=None, hwaccel=None):
|
||||
cdef Codec cy_codec = codec if isinstance(codec, Codec) else Codec(codec, mode)
|
||||
cdef lib.AVCodecContext *c_ctx = lib.avcodec_alloc_context3(cy_codec.ptr)
|
||||
cy_codec: Codec = codec if isinstance(codec, Codec) else Codec(codec, mode)
|
||||
c_ctx: cython.pointer[lib.AVCodecContext] = lib.avcodec_alloc_context3(
|
||||
cy_codec.ptr
|
||||
)
|
||||
return wrap_codec_context(c_ctx, cy_codec.ptr, hwaccel)
|
||||
|
||||
def __cinit__(self, sentinel=None, *args, **kwargs):
|
||||
|
|
@ -95,11 +106,17 @@ cdef class CodecContext:
|
|||
self.stream_index = -1 # This is set by the container immediately.
|
||||
self.is_open = False
|
||||
|
||||
cdef _init(self, lib.AVCodecContext *ptr, const lib.AVCodec *codec, HWAccel hwaccel):
|
||||
@cython.cfunc
|
||||
def _init(
|
||||
self,
|
||||
ptr: cython.pointer[lib.AVCodecContext],
|
||||
codec: cython.pointer[cython.const[lib.AVCodec]],
|
||||
hwaccel: HWAccel,
|
||||
):
|
||||
self.ptr = ptr
|
||||
if self.ptr.codec and codec and self.ptr.codec != codec:
|
||||
raise RuntimeError("Wrapping CodecContext with mismatched codec.")
|
||||
self.codec = wrap_codec(codec if codec != NULL else self.ptr.codec)
|
||||
self.codec = wrap_codec(codec if codec != cython.NULL else self.ptr.codec)
|
||||
self.hwaccel = hwaccel
|
||||
|
||||
# Set reasonable threading defaults.
|
||||
|
|
@ -116,7 +133,7 @@ cdef class CodecContext:
|
|||
return self.ptr.flags
|
||||
|
||||
@flags.setter
|
||||
def flags(self, int value):
|
||||
def flags(self, value: cython.int):
|
||||
self.ptr.flags = value
|
||||
|
||||
@property
|
||||
|
|
@ -156,30 +173,39 @@ cdef class CodecContext:
|
|||
return self.ptr.flags2
|
||||
|
||||
@flags2.setter
|
||||
def flags2(self, int value):
|
||||
def flags2(self, value: cython.int):
|
||||
self.ptr.flags2 = value
|
||||
|
||||
@property
|
||||
def extradata(self):
|
||||
if self.ptr is NULL:
|
||||
if self.ptr is cython.NULL:
|
||||
return None
|
||||
if self.ptr.extradata_size > 0:
|
||||
return <bytes>(<uint8_t*>self.ptr.extradata)[:self.ptr.extradata_size]
|
||||
return cython.cast(
|
||||
bytes,
|
||||
cython.cast(cython.pointer[uint8_t], self.ptr.extradata)[
|
||||
: self.ptr.extradata_size
|
||||
],
|
||||
)
|
||||
return None
|
||||
|
||||
@extradata.setter
|
||||
def extradata(self, data):
|
||||
if data is None:
|
||||
lib.av_freep(&self.ptr.extradata)
|
||||
lib.av_freep(cython.address(self.ptr.extradata))
|
||||
self.ptr.extradata_size = 0
|
||||
else:
|
||||
source = bytesource(data)
|
||||
self.ptr.extradata = <uint8_t*>lib.av_realloc(self.ptr.extradata, source.length + lib.AV_INPUT_BUFFER_PADDING_SIZE)
|
||||
self.ptr.extradata = cython.cast(
|
||||
cython.pointer[uint8_t],
|
||||
lib.av_realloc(
|
||||
self.ptr.extradata, source.length + lib.AV_INPUT_BUFFER_PADDING_SIZE
|
||||
),
|
||||
)
|
||||
if not self.ptr.extradata:
|
||||
raise MemoryError("Cannot allocate extradata")
|
||||
memcpy(self.ptr.extradata, source.ptr, source.length)
|
||||
self.ptr.extradata_size = source.length
|
||||
self.extradata_set = True
|
||||
|
||||
@property
|
||||
def extradata_size(self):
|
||||
|
|
@ -187,23 +213,24 @@ cdef class CodecContext:
|
|||
|
||||
@property
|
||||
def is_encoder(self):
|
||||
if self.ptr is NULL:
|
||||
if self.ptr is cython.NULL:
|
||||
return False
|
||||
return lib.av_codec_is_encoder(self.ptr.codec)
|
||||
|
||||
@property
|
||||
def is_decoder(self):
|
||||
if self.ptr is NULL:
|
||||
if self.ptr is cython.NULL:
|
||||
return False
|
||||
return lib.av_codec_is_decoder(self.ptr.codec)
|
||||
|
||||
cpdef open(self, bint strict=True):
|
||||
@cython.ccall
|
||||
def open(self, strict: cython.bint = True):
|
||||
if self.is_open:
|
||||
if strict:
|
||||
raise ValueError("CodecContext is already open.")
|
||||
return
|
||||
|
||||
cdef _Dictionary options = Dictionary()
|
||||
options: Dictionary = Dictionary()
|
||||
options.update(self.options or {})
|
||||
|
||||
if not self.ptr.time_base.num and self.is_encoder:
|
||||
|
|
@ -217,15 +244,17 @@ cdef class CodecContext:
|
|||
self.ptr.time_base.num = 1
|
||||
self.ptr.time_base.den = lib.AV_TIME_BASE
|
||||
|
||||
err_check(lib.avcodec_open2(self.ptr, self.codec.ptr, &options.ptr), "avcodec_open2(" + self.codec.name + ")")
|
||||
err_check(
|
||||
lib.avcodec_open2(self.ptr, self.codec.ptr, cython.address(options.ptr)),
|
||||
f'avcodec_open2("{self.codec.name}", {self.options})',
|
||||
)
|
||||
self.is_open = True
|
||||
self.options = dict(options)
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.ptr and self.extradata_set:
|
||||
lib.av_freep(&self.ptr.extradata)
|
||||
if self.ptr:
|
||||
lib.avcodec_free_context(&self.ptr)
|
||||
lib.av_freep(cython.address(self.ptr.extradata))
|
||||
lib.avcodec_free_context(cython.address(self.ptr))
|
||||
if self.parser:
|
||||
lib.av_parser_close(self.parser)
|
||||
|
||||
|
|
@ -243,6 +272,10 @@ cdef class CodecContext:
|
|||
It will return all packets that are fully contained within the given
|
||||
input, and will buffer partial packets until they are complete.
|
||||
|
||||
Any timing information the parser is able to infer (``pts``, ``dts``,
|
||||
``duration``, ``pos`` and the keyframe flag) is assigned onto the
|
||||
returned packets. Fields the parser cannot determine are left unset.
|
||||
|
||||
:param ByteSource raw_input: A chunk of a byte-stream to process.
|
||||
Anything that can be turned into a :class:`.ByteSource` is fine.
|
||||
``None`` or empty inputs will flush the parser's buffers.
|
||||
|
|
@ -256,27 +289,29 @@ cdef class CodecContext:
|
|||
if not self.parser:
|
||||
raise ValueError(f"No parser for {self.codec.name}")
|
||||
|
||||
cdef ByteSource source = bytesource(raw_input, allow_none=True)
|
||||
source: ByteSource = bytesource(raw_input, allow_none=True)
|
||||
|
||||
cdef unsigned char *in_data = source.ptr if source is not None else NULL
|
||||
cdef int in_size = source.length if source is not None else 0
|
||||
in_data: cython.p_uchar = source.ptr if source is not None else cython.NULL
|
||||
in_size: cython.int = source.length if source is not None else 0
|
||||
|
||||
cdef unsigned char *out_data
|
||||
cdef int out_size
|
||||
cdef int consumed
|
||||
cdef Packet packet = None
|
||||
|
||||
packets = []
|
||||
out_data: cython.p_uchar
|
||||
out_size: cython.int
|
||||
consumed: cython.int
|
||||
packet: Packet = None
|
||||
packets: list = []
|
||||
|
||||
while True:
|
||||
with nogil:
|
||||
with cython.nogil:
|
||||
consumed = lib.av_parser_parse2(
|
||||
self.parser,
|
||||
self.ptr,
|
||||
&out_data, &out_size,
|
||||
in_data, in_size,
|
||||
lib.AV_NOPTS_VALUE, lib.AV_NOPTS_VALUE,
|
||||
0
|
||||
cython.address(out_data),
|
||||
cython.address(out_size),
|
||||
in_data,
|
||||
in_size,
|
||||
lib.AV_NOPTS_VALUE,
|
||||
lib.AV_NOPTS_VALUE,
|
||||
0,
|
||||
)
|
||||
err_check(consumed)
|
||||
|
||||
|
|
@ -296,6 +331,16 @@ cdef class CodecContext:
|
|||
packet = Packet(out_size)
|
||||
memcpy(packet.ptr.data, out_data, out_size)
|
||||
|
||||
# Propagate the timing information the parser inferred for
|
||||
# this frame onto the packet (mirrors FFmpeg's parse_packet).
|
||||
packet.ptr.pts = self.parser.pts
|
||||
packet.ptr.dts = self.parser.dts
|
||||
packet.ptr.pos = self.parser.pos
|
||||
if self.parser.duration:
|
||||
packet.ptr.duration = self.parser.duration
|
||||
if self.parser.key_frame == 1:
|
||||
packet.ptr.flags |= lib.AV_PKT_FLAG_KEY
|
||||
|
||||
packets.append(packet)
|
||||
|
||||
if not in_size:
|
||||
|
|
@ -317,12 +362,13 @@ cdef class CodecContext:
|
|||
"""
|
||||
return self.hwaccel_ctx is not None
|
||||
|
||||
def _send_frame_and_recv(self, Frame frame):
|
||||
cdef Packet packet
|
||||
|
||||
cdef int res
|
||||
with nogil:
|
||||
res = lib.avcodec_send_frame(self.ptr, frame.ptr if frame is not None else NULL)
|
||||
def _send_frame_and_recv(self, frame: Frame | None):
|
||||
packet: Packet
|
||||
res: cython.int
|
||||
with cython.nogil:
|
||||
res = lib.avcodec_send_frame(
|
||||
self.ptr, frame.ptr if frame is not None else cython.NULL
|
||||
)
|
||||
err_check(res, "avcodec_send_frame()")
|
||||
|
||||
packet = self._recv_packet()
|
||||
|
|
@ -330,65 +376,56 @@ cdef class CodecContext:
|
|||
yield packet
|
||||
packet = self._recv_packet()
|
||||
|
||||
cdef _send_packet_and_recv(self, Packet packet):
|
||||
cdef Frame frame
|
||||
|
||||
cdef int res
|
||||
with nogil:
|
||||
res = lib.avcodec_send_packet(self.ptr, packet.ptr if packet is not None else NULL)
|
||||
err_check(res, "avcodec_send_packet()")
|
||||
|
||||
out = []
|
||||
while True:
|
||||
frame = self._recv_frame()
|
||||
if frame:
|
||||
out.append(frame)
|
||||
else:
|
||||
break
|
||||
return out
|
||||
|
||||
cdef _prepare_frames_for_encode(self, Frame frame):
|
||||
@cython.cfunc
|
||||
def _prepare_frames_for_encode(self, frame: Frame | None) -> list:
|
||||
return [frame]
|
||||
|
||||
cdef Frame _alloc_next_frame(self):
|
||||
@cython.cfunc
|
||||
def _alloc_next_frame(self) -> Frame:
|
||||
raise NotImplementedError("Base CodecContext cannot decode.")
|
||||
|
||||
cdef _recv_frame(self):
|
||||
@cython.cfunc
|
||||
def _recv_frame(self):
|
||||
if not self._next_frame:
|
||||
self._next_frame = self._alloc_next_frame()
|
||||
cdef Frame frame = self._next_frame
|
||||
|
||||
cdef int res
|
||||
with nogil:
|
||||
frame: Frame = self._next_frame
|
||||
res: cython.int
|
||||
|
||||
with cython.nogil:
|
||||
res = lib.avcodec_receive_frame(self.ptr, frame.ptr)
|
||||
|
||||
if res == -EAGAIN or res == lib.AVERROR_EOF:
|
||||
return
|
||||
err_check(res, "avcodec_receive_frame()")
|
||||
|
||||
err_check(res, "avcodec_receive_frame()")
|
||||
frame = self._transfer_hwframe(frame)
|
||||
|
||||
if not res:
|
||||
self._next_frame = None
|
||||
return frame
|
||||
|
||||
cdef _transfer_hwframe(self, Frame frame):
|
||||
@cython.cfunc
|
||||
def _transfer_hwframe(self, frame: Frame):
|
||||
return frame
|
||||
|
||||
cdef _recv_packet(self):
|
||||
cdef Packet packet = Packet()
|
||||
@cython.cfunc
|
||||
def _recv_packet(self):
|
||||
packet: Packet = Packet()
|
||||
res: cython.int
|
||||
|
||||
cdef int res
|
||||
with nogil:
|
||||
with cython.nogil:
|
||||
res = lib.avcodec_receive_packet(self.ptr, packet.ptr)
|
||||
|
||||
if res == -EAGAIN or res == lib.AVERROR_EOF:
|
||||
return
|
||||
err_check(res, "avcodec_receive_packet()")
|
||||
|
||||
err_check(res, "avcodec_receive_packet()")
|
||||
if not res:
|
||||
return packet
|
||||
|
||||
cdef _prepare_and_time_rebase_frames_for_encode(self, Frame frame):
|
||||
@cython.cfunc
|
||||
def _prepare_and_time_rebase_frames_for_encode(self, frame: Frame):
|
||||
if self.ptr.codec_type not in [lib.AVMEDIA_TYPE_VIDEO, lib.AVMEDIA_TYPE_AUDIO]:
|
||||
raise NotImplementedError("Encoding is only supported for audio and video.")
|
||||
|
||||
|
|
@ -404,7 +441,8 @@ cdef class CodecContext:
|
|||
|
||||
return frames
|
||||
|
||||
cpdef encode(self, Frame frame=None):
|
||||
@cython.ccall
|
||||
def encode(self, frame: Frame | None = None):
|
||||
"""Encode a list of :class:`.Packet` from the given :class:`.Frame`."""
|
||||
res = []
|
||||
for frame in self._prepare_and_time_rebase_frames_for_encode(frame):
|
||||
|
|
@ -413,13 +451,14 @@ cdef class CodecContext:
|
|||
res.append(packet)
|
||||
return res
|
||||
|
||||
def encode_lazy(self, Frame frame=None):
|
||||
def encode_lazy(self, frame: Frame | None = None):
|
||||
for frame in self._prepare_and_time_rebase_frames_for_encode(frame):
|
||||
for packet in self._send_frame_and_recv(frame):
|
||||
self._setup_encoded_packet(packet)
|
||||
yield packet
|
||||
|
||||
cdef _setup_encoded_packet(self, Packet packet):
|
||||
@cython.cfunc
|
||||
def _setup_encoded_packet(self, packet: Packet):
|
||||
# We coerced the frame's time_base into the CodecContext's during encoding,
|
||||
# and FFmpeg copied the frame's pts/dts to the packet, so keep track of
|
||||
# this time_base in case the frame needs to be muxed to a container with
|
||||
|
|
@ -429,28 +468,45 @@ cdef class CodecContext:
|
|||
# are off!
|
||||
packet.ptr.time_base = self.ptr.time_base
|
||||
|
||||
cpdef decode(self, Packet packet=None):
|
||||
@cython.ccall
|
||||
def decode(self, packet: Packet | None = None):
|
||||
"""Decode a list of :class:`.Frame` from the given :class:`.Packet`.
|
||||
|
||||
If the packet is None, the buffers will be flushed. This is useful if
|
||||
you do not want the library to automatically re-order frames for you
|
||||
(if they are encoded with a codec that has B-frames).
|
||||
|
||||
"""
|
||||
.. warning::
|
||||
|
||||
This method is **not thread-safe**. Calling :meth:`decode` concurrently
|
||||
from multiple threads on the same :class:`CodecContext` will corrupt
|
||||
internal FFmpeg state and likely cause a crash (segfault). FFmpeg 8.1
|
||||
enforces this more strictly than earlier releases. If you need to decode
|
||||
from multiple threads, give each thread its own :class:`CodecContext`.
|
||||
|
||||
"""
|
||||
if not self.codec.ptr:
|
||||
raise ValueError("cannot decode unknown codec")
|
||||
|
||||
self.open(strict=False)
|
||||
|
||||
res = []
|
||||
for frame in self._send_packet_and_recv(packet):
|
||||
if isinstance(frame, Frame):
|
||||
self._setup_decoded_frame(frame, packet)
|
||||
res.append(frame)
|
||||
return res
|
||||
res: cython.int
|
||||
with cython.nogil:
|
||||
res = lib.avcodec_send_packet(
|
||||
self.ptr, packet.ptr if packet is not None else cython.NULL
|
||||
)
|
||||
err_check(res, "avcodec_send_packet()")
|
||||
|
||||
cpdef flush_buffers(self):
|
||||
out: list = []
|
||||
frame = self._recv_frame()
|
||||
while frame:
|
||||
self._setup_decoded_frame(frame, packet)
|
||||
out.append(frame)
|
||||
frame = self._recv_frame()
|
||||
return out
|
||||
|
||||
@cython.ccall
|
||||
def flush_buffers(self):
|
||||
"""Reset the internal codec state and discard all internal buffers.
|
||||
|
||||
Should be called before you start decoding from a new position e.g.
|
||||
|
|
@ -458,10 +514,11 @@ cdef class CodecContext:
|
|||
|
||||
"""
|
||||
if self.is_open:
|
||||
with nogil:
|
||||
with cython.nogil:
|
||||
lib.avcodec_flush_buffers(self.ptr)
|
||||
|
||||
cdef _setup_decoded_frame(self, Frame frame, Packet packet):
|
||||
@cython.cfunc
|
||||
def _setup_decoded_frame(self, frame: Frame, packet: Packet | None):
|
||||
# Propagate our manual times.
|
||||
# While decoding, frame times are in stream time_base, which PyAV
|
||||
# is carrying around.
|
||||
|
|
@ -485,15 +542,15 @@ cdef class CodecContext:
|
|||
|
||||
:type: list[str]
|
||||
"""
|
||||
ret = []
|
||||
ret: list = []
|
||||
if not self.ptr.codec or not self.codec.desc or not self.codec.desc.profiles:
|
||||
return ret
|
||||
|
||||
# Profiles are always listed in the codec descriptor, but not necessarily in
|
||||
# the codec itself. So use the descriptor here.
|
||||
desc = self.codec.desc
|
||||
cdef int i = 0
|
||||
while desc.profiles[i].profile != lib.AV_PROFILE_UNKNOWN:
|
||||
i: cython.int = 0
|
||||
while desc.profiles[i].profile != lib.AV_PROFILE_UNKNOWN:
|
||||
ret.append(desc.profiles[i].name)
|
||||
i += 1
|
||||
|
||||
|
|
@ -507,8 +564,8 @@ cdef class CodecContext:
|
|||
# Profiles are always listed in the codec descriptor, but not necessarily in
|
||||
# the codec itself. So use the descriptor here.
|
||||
desc = self.codec.desc
|
||||
cdef int i = 0
|
||||
while desc.profiles[i].profile != lib.AV_PROFILE_UNKNOWN:
|
||||
i: cython.int = 0
|
||||
while desc.profiles[i].profile != lib.AV_PROFILE_UNKNOWN:
|
||||
if desc.profiles[i].profile == self.ptr.profile:
|
||||
return desc.profiles[i].name
|
||||
i += 1
|
||||
|
|
@ -521,7 +578,7 @@ cdef class CodecContext:
|
|||
# Profiles are always listed in the codec descriptor, but not necessarily in
|
||||
# the codec itself. So use the descriptor here.
|
||||
desc = self.codec.desc
|
||||
cdef int i = 0
|
||||
i: cython.int = 0
|
||||
while desc.profiles[i].profile != lib.AV_PROFILE_UNKNOWN:
|
||||
if desc.profiles[i].name == value:
|
||||
self.ptr.profile = desc.profiles[i].profile
|
||||
|
|
@ -532,33 +589,52 @@ cdef class CodecContext:
|
|||
def time_base(self):
|
||||
if self.is_decoder:
|
||||
raise RuntimeError("Cannot access 'time_base' as a decoder")
|
||||
return avrational_to_fraction(&self.ptr.time_base)
|
||||
return avrational_to_fraction(cython.address(self.ptr.time_base))
|
||||
|
||||
@time_base.setter
|
||||
def time_base(self, value):
|
||||
if self.is_decoder:
|
||||
raise RuntimeError("Cannot access 'time_base' as a decoder")
|
||||
to_avrational(value, &self.ptr.time_base)
|
||||
to_avrational(value, cython.address(self.ptr.time_base))
|
||||
|
||||
@property
|
||||
def codec_tag(self):
|
||||
return self.ptr.codec_tag.to_bytes(4, byteorder="little", signed=False).decode(
|
||||
encoding="ascii")
|
||||
encoding="ascii"
|
||||
)
|
||||
|
||||
@codec_tag.setter
|
||||
def codec_tag(self, value):
|
||||
if isinstance(value, str) and len(value) == 4:
|
||||
self.ptr.codec_tag = int.from_bytes(value.encode(encoding="ascii"),
|
||||
byteorder="little", signed=False)
|
||||
self.ptr.codec_tag = int.from_bytes(
|
||||
value.encode(encoding="ascii"), byteorder="little", signed=False
|
||||
)
|
||||
else:
|
||||
raise ValueError("Codec tag should be a 4 character string.")
|
||||
|
||||
@property
|
||||
@cython.cdivision(True)
|
||||
def global_quality(self):
|
||||
"""Global quality for codecs which cannot change it per frame.
|
||||
|
||||
Stored internally in lambda units; this property converts to/from
|
||||
QP units using ``FF_QP2LAMBDA``.
|
||||
|
||||
Wraps :ffmpeg:`AVCodecContext.global_quality`.
|
||||
|
||||
"""
|
||||
return self.ptr.global_quality // lib.FF_QP2LAMBDA
|
||||
|
||||
@global_quality.setter
|
||||
def global_quality(self, value: cython.int):
|
||||
self.ptr.global_quality = value * lib.FF_QP2LAMBDA
|
||||
|
||||
@property
|
||||
def bit_rate(self):
|
||||
return self.ptr.bit_rate if self.ptr.bit_rate > 0 else None
|
||||
|
||||
@bit_rate.setter
|
||||
def bit_rate(self, int value):
|
||||
def bit_rate(self, value: cython.int):
|
||||
self.ptr.bit_rate = value
|
||||
|
||||
@property
|
||||
|
|
@ -573,7 +649,7 @@ cdef class CodecContext:
|
|||
self.ptr.bit_rate_tolerance
|
||||
|
||||
@bit_rate_tolerance.setter
|
||||
def bit_rate_tolerance(self, int value):
|
||||
def bit_rate_tolerance(self, value: cython.int):
|
||||
self.ptr.bit_rate_tolerance = value
|
||||
|
||||
@property
|
||||
|
|
@ -586,7 +662,7 @@ cdef class CodecContext:
|
|||
return self.ptr.thread_count
|
||||
|
||||
@thread_count.setter
|
||||
def thread_count(self, int value):
|
||||
def thread_count(self, value: cython.int):
|
||||
if self.is_open:
|
||||
raise RuntimeError("Cannot change thread_count after codec is open.")
|
||||
self.ptr.thread_count = value
|
||||
|
|
@ -62,6 +62,7 @@ class CodecContext:
|
|||
extradata: bytes | None
|
||||
time_base: Fraction
|
||||
codec_tag: str
|
||||
global_quality: int
|
||||
bit_rate: int | None
|
||||
bit_rate_tolerance: int
|
||||
thread_count: int
|
||||
|
|
|
|||
BIN
venv/lib/python3.12/site-packages/av/codec/hwaccel.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/codec/hwaccel.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
|
|
@ -5,10 +5,10 @@ from av.codec.codec cimport Codec
|
|||
|
||||
cdef class HWConfig:
|
||||
cdef object __weakref__
|
||||
cdef lib.AVCodecHWConfig *ptr
|
||||
cdef void _init(self, lib.AVCodecHWConfig *ptr)
|
||||
cdef const lib.AVCodecHWConfig *ptr
|
||||
cdef void _init(self, const lib.AVCodecHWConfig *ptr)
|
||||
|
||||
cdef HWConfig wrap_hwconfig(lib.AVCodecHWConfig *ptr)
|
||||
cdef HWConfig wrap_hwconfig(const lib.AVCodecHWConfig *ptr)
|
||||
|
||||
cdef class HWAccel:
|
||||
cdef int _device_type
|
||||
|
|
@ -16,6 +16,8 @@ cdef class HWAccel:
|
|||
cdef readonly Codec codec
|
||||
cdef readonly HWConfig config
|
||||
cdef lib.AVBufferRef *ptr
|
||||
cdef readonly int device_id
|
||||
cdef readonly bint is_hw_owned
|
||||
cdef public bint allow_software_fallback
|
||||
cdef public dict options
|
||||
cdef public int flags
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import weakref
|
||||
from enum import IntEnum
|
||||
|
||||
cimport libav as lib
|
||||
|
||||
from av.codec.codec cimport Codec
|
||||
from av.dictionary cimport _Dictionary
|
||||
from av.error cimport err_check
|
||||
from av.video.format cimport get_video_format
|
||||
|
||||
from av.dictionary import Dictionary
|
||||
import cython
|
||||
import cython.cimports.libav as lib
|
||||
from cython.cimports.av.codec.codec import Codec
|
||||
from cython.cimports.av.dictionary import Dictionary
|
||||
from cython.cimports.av.error import err_check
|
||||
from cython.cimports.av.video.format import get_video_format
|
||||
|
||||
|
||||
class HWDeviceType(IntEnum):
|
||||
|
|
@ -29,34 +27,44 @@ class HWDeviceType(IntEnum):
|
|||
ohcodec = 14
|
||||
# TODO: When ffmpeg major is changed, check this enum.
|
||||
|
||||
|
||||
class HWConfigMethod(IntEnum):
|
||||
none = 0
|
||||
hw_device_ctx = lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX # This is the only one we support.
|
||||
hw_device_ctx = (
|
||||
lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX
|
||||
) # This is the only one we support.
|
||||
hw_frame_ctx = lib.AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX
|
||||
internal = lib.AV_CODEC_HW_CONFIG_METHOD_INTERNAL
|
||||
ad_hoc = lib.AV_CODEC_HW_CONFIG_METHOD_AD_HOC
|
||||
|
||||
|
||||
cdef object _cinit_sentinel = object()
|
||||
cdef object _singletons = weakref.WeakValueDictionary()
|
||||
_cinit_sentinel = cython.declare(object, object())
|
||||
_singletons = cython.declare(object, weakref.WeakValueDictionary())
|
||||
|
||||
cdef HWConfig wrap_hwconfig(lib.AVCodecHWConfig *ptr):
|
||||
|
||||
@cython.cfunc
|
||||
def wrap_hwconfig(ptr: cython.pointer[cython.const[lib.AVCodecHWConfig]]) -> HWConfig:
|
||||
try:
|
||||
return _singletons[<int>ptr]
|
||||
return _singletons[cython.cast(cython.Py_ssize_t, ptr)]
|
||||
except KeyError:
|
||||
pass
|
||||
cdef HWConfig config = HWConfig(_cinit_sentinel)
|
||||
config: HWConfig = HWConfig(_cinit_sentinel)
|
||||
config._init(ptr)
|
||||
_singletons[<int>ptr] = config
|
||||
_singletons[cython.cast(cython.Py_ssize_t, ptr)] = config
|
||||
return config
|
||||
|
||||
|
||||
cdef class HWConfig:
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class HWConfig:
|
||||
def __init__(self, sentinel):
|
||||
if sentinel is not _cinit_sentinel:
|
||||
raise RuntimeError("Cannot instantiate CodecContext")
|
||||
|
||||
cdef void _init(self, lib.AVCodecHWConfig *ptr):
|
||||
@cython.cfunc
|
||||
def _init(
|
||||
self, ptr: cython.pointer[cython.const[lib.AVCodecHWConfig]]
|
||||
) -> cython.void:
|
||||
self.ptr = ptr
|
||||
|
||||
def __repr__(self):
|
||||
|
|
@ -64,7 +72,7 @@ cdef class HWConfig:
|
|||
f"<av.{self.__class__.__name__} "
|
||||
f"device_type={lib.av_hwdevice_get_type_name(self.device_type)} "
|
||||
f"format={self.format.name if self.format else None} "
|
||||
f"is_supported={self.is_supported} at 0x{<int>self.ptr:x}>"
|
||||
f"is_supported={self.is_supported} at 0x{cython.cast(cython.Py_ssize_t, self.ptr):x}>"
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
@ -84,21 +92,30 @@ cdef class HWConfig:
|
|||
return bool(self.ptr.methods & lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
|
||||
|
||||
|
||||
cpdef hwdevices_available():
|
||||
result = []
|
||||
|
||||
cdef lib.AVHWDeviceType x = lib.AV_HWDEVICE_TYPE_NONE
|
||||
@cython.ccall
|
||||
def hwdevices_available():
|
||||
result: list = []
|
||||
x: lib.AVHWDeviceType = lib.AV_HWDEVICE_TYPE_NONE
|
||||
while True:
|
||||
x = lib.av_hwdevice_iterate_types(x)
|
||||
if x == lib.AV_HWDEVICE_TYPE_NONE:
|
||||
break
|
||||
result.append(lib.av_hwdevice_get_type_name(HWDeviceType(x)))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
cdef class HWAccel:
|
||||
def __init__(self, device_type, device=None, allow_software_fallback=True, options=None, flags=None):
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class HWAccel:
|
||||
def __init__(
|
||||
self,
|
||||
device_type,
|
||||
device=None,
|
||||
allow_software_fallback=True,
|
||||
options=None,
|
||||
flags=None,
|
||||
is_hw_owned=False,
|
||||
):
|
||||
if isinstance(device_type, HWDeviceType):
|
||||
self._device_type = device_type
|
||||
elif isinstance(device_type, str):
|
||||
|
|
@ -108,39 +125,50 @@ cdef class HWAccel:
|
|||
else:
|
||||
raise ValueError("Unknown type for device_type")
|
||||
|
||||
self._device = device
|
||||
self.is_hw_owned = is_hw_owned
|
||||
self.device_id = 0
|
||||
if self._device_type == HWDeviceType.cuda and device:
|
||||
self.device_id = int(device)
|
||||
|
||||
self._device = None if device is None else f"{device}"
|
||||
self.allow_software_fallback = allow_software_fallback
|
||||
|
||||
self.options = {} if not options else dict(options)
|
||||
if self._device_type == HWDeviceType.cuda and self.is_hw_owned:
|
||||
self.options.setdefault("primary_ctx", "1")
|
||||
self.flags = 0 if not flags else flags
|
||||
self.ptr = NULL
|
||||
self.ptr = cython.NULL
|
||||
self.config = None
|
||||
|
||||
def _initialize_hw_context(self, Codec codec not None):
|
||||
cdef HWConfig config
|
||||
def _initialize_hw_context(self, codec: Codec):
|
||||
config: HWConfig
|
||||
for config in codec.hardware_configs:
|
||||
if not (config.ptr.methods & lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX):
|
||||
continue
|
||||
if self._device_type and config.device_type != self._device_type:
|
||||
continue
|
||||
break
|
||||
else:
|
||||
else: # nobreak
|
||||
raise NotImplementedError(f"No supported hardware config for {codec}")
|
||||
|
||||
self.config = config
|
||||
|
||||
cdef char *c_device = NULL
|
||||
c_device: cython.p_char = cython.NULL
|
||||
if self._device:
|
||||
device_bytes = self._device.encode()
|
||||
c_device = device_bytes
|
||||
cdef _Dictionary c_options = Dictionary(self.options)
|
||||
c_options: Dictionary = Dictionary(self.options)
|
||||
|
||||
err_check(
|
||||
lib.av_hwdevice_ctx_create(
|
||||
&self.ptr, config.ptr.device_type, c_device, c_options.ptr, self.flags
|
||||
cython.address(self.ptr),
|
||||
config.ptr.device_type,
|
||||
c_device,
|
||||
c_options.ptr,
|
||||
self.flags,
|
||||
)
|
||||
)
|
||||
|
||||
def create(self, Codec codec not None):
|
||||
def create(self, codec: Codec) -> HWAccel:
|
||||
"""Create a new hardware accelerator context with the given codec"""
|
||||
if self.ptr:
|
||||
raise RuntimeError("Hardware context already initialized")
|
||||
|
|
@ -149,11 +177,12 @@ cdef class HWAccel:
|
|||
device_type=self._device_type,
|
||||
device=self._device,
|
||||
allow_software_fallback=self.allow_software_fallback,
|
||||
options=self.options
|
||||
options=self.options,
|
||||
is_hw_owned=self.is_hw_owned,
|
||||
)
|
||||
ret._initialize_hw_context(codec)
|
||||
return ret
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.ptr:
|
||||
lib.av_buffer_unref(&self.ptr)
|
||||
lib.av_buffer_unref(cython.address(self.ptr))
|
||||
|
|
@ -37,13 +37,20 @@ class HWConfig:
|
|||
def is_supported(self) -> bool: ...
|
||||
|
||||
class HWAccel:
|
||||
options: dict[str, object]
|
||||
|
||||
@property
|
||||
def is_hw_owned(self) -> bool: ...
|
||||
@property
|
||||
def device_id(self) -> int: ...
|
||||
def __init__(
|
||||
self,
|
||||
device_type: str | HWDeviceType,
|
||||
device: str | None = None,
|
||||
device: str | int | None = None,
|
||||
allow_software_fallback: bool = False,
|
||||
options: dict[str, object] | None = None,
|
||||
flags: int | None = None,
|
||||
is_hw_owned: bool = False,
|
||||
) -> None: ...
|
||||
def create(self, codec: Codec) -> HWAccel: ...
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
from .core import Container, Flags, open
|
||||
from .input import InputContainer
|
||||
from .output import OutputContainer
|
||||
from .input import InputContainer as InputContainer
|
||||
from .output import OutputContainer as OutputContainer
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
venv/lib/python3.12/site-packages/av/container/core.abi3.so
Executable file
BIN
venv/lib/python3.12/site-packages/av/container/core.abi3.so
Executable file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue