Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -1,35 +1,38 @@
|
|||
import os
|
||||
from fractions import Fraction
|
||||
|
||||
import cython
|
||||
from cython.cimports import libav as lib
|
||||
from cython.cimports.av.codec.codec import Codec
|
||||
from cython.cimports.av.codec.context import CodecContext, wrap_codec_context
|
||||
from cython.cimports.av.container.streams import StreamContainer
|
||||
from cython.cimports.av.dictionary import _Dictionary
|
||||
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.stream import Stream, wrap_stream
|
||||
from cython.cimports.av.utils import dict_to_avdict, to_avrational
|
||||
|
||||
from av.dictionary import Dictionary
|
||||
|
||||
|
||||
@cython.cfunc
|
||||
def close_output(self: OutputContainer):
|
||||
self.streams = StreamContainer()
|
||||
if self._started and not self._done:
|
||||
if self._myflag & 12 == 4: # enum.started and not enum.done
|
||||
# If the underlying Python IO file was already closed (e.g. during GC
|
||||
# finalization where cycle ordering is undefined), skip the trailer.
|
||||
if self.file is not None and getattr(self.file.file, "closed", False):
|
||||
self._myflag |= 8 # enum.done = True
|
||||
return
|
||||
# We must only ever call av_write_trailer *once*, otherwise we get a
|
||||
# segmentation fault. Therefore no matter whether it succeeds or not
|
||||
# we must absolutely set self._done.
|
||||
# we must absolutely set enum.done.
|
||||
try:
|
||||
self.err_check(lib.av_write_trailer(self.ptr))
|
||||
finally:
|
||||
if self.file is None and not (self.ptr.oformat.flags & lib.AVFMT_NOFILE):
|
||||
lib.avio_closep(cython.address(self.ptr.pb))
|
||||
self._done = True
|
||||
self._myflag |= 8 # enum.done = True
|
||||
|
||||
|
||||
@cython.final
|
||||
@cython.cclass
|
||||
class OutputContainer(Container):
|
||||
def __cinit__(self, *args, **kwargs):
|
||||
|
|
@ -38,8 +41,10 @@ class OutputContainer(Container):
|
|||
with cython.nogil:
|
||||
self.packet_ptr = lib.av_packet_alloc()
|
||||
|
||||
def __dealloc__(self):
|
||||
def __del__(self):
|
||||
close_output(self)
|
||||
|
||||
def __dealloc__(self):
|
||||
with cython.nogil:
|
||||
lib.av_packet_free(cython.address(self.packet_ptr))
|
||||
|
||||
|
|
@ -90,7 +95,17 @@ class OutputContainer(Container):
|
|||
|
||||
# Some sane audio defaults
|
||||
elif codec.type == lib.AVMEDIA_TYPE_AUDIO:
|
||||
ctx.sample_fmt = codec.sample_fmts[0]
|
||||
out: cython.pointer[cython.const[cython.void]] = cython.NULL
|
||||
lib.avcodec_get_supported_config(
|
||||
cython.NULL,
|
||||
codec,
|
||||
lib.AV_CODEC_CONFIG_SAMPLE_FORMAT,
|
||||
0,
|
||||
cython.address(out),
|
||||
cython.NULL,
|
||||
)
|
||||
if out:
|
||||
ctx.sample_fmt = cython.cast(cython.pointer[lib.AVSampleFormat], out)[0]
|
||||
ctx.bit_rate = kwargs.pop("bit_rate", 0)
|
||||
ctx.bit_rate_tolerance = kwargs.pop("bit_rate_tolerance", 32000)
|
||||
try:
|
||||
|
|
@ -130,6 +145,83 @@ class OutputContainer(Container):
|
|||
|
||||
return py_stream
|
||||
|
||||
def add_mux_stream(self, codec_name: str, rate=None, **kwargs) -> Stream:
|
||||
"""add_mux_stream(codec_name, rate=None)
|
||||
|
||||
Creates a new stream for muxing pre-encoded data without creating a
|
||||
:class:`.CodecContext`. Use this when you want to mux packets that were
|
||||
already encoded externally and no encoding/decoding is needed.
|
||||
|
||||
:param codec_name: The name of a codec.
|
||||
:type codec_name: str
|
||||
:param \\**kwargs: Set attributes for the stream (e.g. ``width``, ``height``,
|
||||
``time_base``).
|
||||
:rtype: The new :class:`~av.stream.Stream`.
|
||||
|
||||
"""
|
||||
# Find the codec to get its id and type (try encoder first, then decoder).
|
||||
codec_name_bytes: bytes = codec_name.encode()
|
||||
codec: cython.pointer[cython.const[lib.AVCodec]] = (
|
||||
lib.avcodec_find_encoder_by_name(codec_name_bytes)
|
||||
)
|
||||
codec_descriptor: cython.pointer[cython.const[lib.AVCodecDescriptor]] = (
|
||||
cython.NULL
|
||||
)
|
||||
if codec == cython.NULL:
|
||||
codec = lib.avcodec_find_decoder_by_name(codec_name_bytes)
|
||||
if codec == cython.NULL:
|
||||
codec_descriptor = lib.avcodec_descriptor_get_by_name(codec_name_bytes)
|
||||
if codec_descriptor == cython.NULL:
|
||||
raise ValueError(f"Unknown codec: {codec_name!r}")
|
||||
|
||||
codec_id: lib.AVCodecID
|
||||
codec_type: lib.AVMediaType
|
||||
if codec != cython.NULL:
|
||||
codec_id = codec.id
|
||||
codec_type = codec.type
|
||||
else:
|
||||
codec_id = codec_descriptor.id
|
||||
codec_type = codec_descriptor.type
|
||||
|
||||
# Assert that this format supports the requested codec.
|
||||
if not lib.avformat_query_codec(
|
||||
self.ptr.oformat, codec_id, lib.FF_COMPLIANCE_NORMAL
|
||||
):
|
||||
raise ValueError(
|
||||
f"{self.format.name!r} format does not support {codec_name!r} codec"
|
||||
)
|
||||
|
||||
# Create stream with no codec context.
|
||||
stream: cython.pointer[lib.AVStream] = lib.avformat_new_stream(
|
||||
self.ptr, cython.NULL
|
||||
)
|
||||
if stream == cython.NULL:
|
||||
raise MemoryError("Could not allocate stream")
|
||||
|
||||
stream.codecpar.codec_id = codec_id
|
||||
stream.codecpar.codec_type = codec_type
|
||||
|
||||
if codec_type == lib.AVMEDIA_TYPE_VIDEO:
|
||||
stream.codecpar.width = kwargs.pop("width", 0)
|
||||
stream.codecpar.height = kwargs.pop("height", 0)
|
||||
if rate is not None:
|
||||
to_avrational(rate, cython.address(stream.avg_frame_rate))
|
||||
elif codec_type == lib.AVMEDIA_TYPE_AUDIO:
|
||||
if rate is not None:
|
||||
if type(rate) is int:
|
||||
stream.codecpar.sample_rate = rate
|
||||
else:
|
||||
raise TypeError("audio stream `rate` must be: int | None")
|
||||
|
||||
# Construct the user-land stream (no codec context).
|
||||
py_stream: Stream = wrap_stream(self, stream, None)
|
||||
self.streams.add_stream(py_stream)
|
||||
|
||||
for k, v in kwargs.items():
|
||||
setattr(py_stream, k, v)
|
||||
|
||||
return py_stream
|
||||
|
||||
def add_stream_from_template(
|
||||
self, template: Stream, opaque: bool | None = None, **kwargs
|
||||
):
|
||||
|
|
@ -171,6 +263,10 @@ class OutputContainer(Container):
|
|||
# Reset the codec tag assuming we are remuxing.
|
||||
ctx.codec_tag = 0
|
||||
|
||||
# Copy the template's stream time_base
|
||||
stream.time_base = template.ptr.time_base
|
||||
ctx.time_base = template.ptr.time_base
|
||||
|
||||
# Some formats want stream headers to be separate
|
||||
if self.ptr.oformat.flags & lib.AVFMT_GLOBALHEADER:
|
||||
ctx.flags |= lib.AV_CODEC_FLAG_GLOBAL_HEADER
|
||||
|
|
@ -186,6 +282,7 @@ class OutputContainer(Container):
|
|||
|
||||
# Construct the user-land stream
|
||||
py_codec_context: CodecContext = wrap_codec_context(ctx, codec, None)
|
||||
py_codec_context._ctxflags |= 1 # _template_initialized = True
|
||||
py_stream: Stream = wrap_stream(self, stream, py_codec_context)
|
||||
self.streams.add_stream(py_stream)
|
||||
|
||||
|
|
@ -278,16 +375,17 @@ class OutputContainer(Container):
|
|||
:rtype: The new :class:`~av.data.stream.DataStream`.
|
||||
"""
|
||||
codec: cython.pointer[cython.const[lib.AVCodec]] = cython.NULL
|
||||
codec_descriptor: cython.pointer[lib.AVCodecDescriptor] = cython.NULL
|
||||
codec_descriptor: cython.pointer[cython.const[lib.AVCodecDescriptor]] = (
|
||||
cython.NULL
|
||||
)
|
||||
|
||||
if codec_name is not None:
|
||||
codec = lib.avcodec_find_encoder_by_name(codec_name.encode())
|
||||
codec_name_bytes: bytes = codec_name.encode()
|
||||
codec = lib.avcodec_find_encoder_by_name(codec_name_bytes)
|
||||
if codec == cython.NULL:
|
||||
codec = lib.avcodec_find_decoder_by_name(codec_name.encode())
|
||||
codec = lib.avcodec_find_decoder_by_name(codec_name_bytes)
|
||||
if codec == cython.NULL:
|
||||
codec_descriptor = lib.avcodec_descriptor_get_by_name(
|
||||
codec_name.encode()
|
||||
)
|
||||
codec_descriptor = lib.avcodec_descriptor_get_by_name(codec_name_bytes)
|
||||
if codec_descriptor == cython.NULL:
|
||||
raise ValueError(f"Unknown data codec: {codec_name}")
|
||||
|
||||
|
|
@ -340,7 +438,7 @@ class OutputContainer(Container):
|
|||
@cython.ccall
|
||||
def start_encoding(self):
|
||||
"""Write the file header! Called automatically."""
|
||||
if self._started:
|
||||
if self._myflag & 4: # started
|
||||
return
|
||||
|
||||
# TODO: This does NOT handle options coming from 3 sources.
|
||||
|
|
@ -351,14 +449,11 @@ class OutputContainer(Container):
|
|||
# Finalize and open all streams.
|
||||
for stream in self.streams:
|
||||
ctx = stream.codec_context
|
||||
# Skip codec context handling for streams without codecs (e.g. data/attachments).
|
||||
if ctx is None:
|
||||
if stream.type not in {"data", "attachment"}:
|
||||
raise ValueError(f"Stream {stream.index} has no codec context")
|
||||
else:
|
||||
if not ctx.is_open:
|
||||
for k, v in self.options.items():
|
||||
ctx.options.setdefault(k, v)
|
||||
if ctx is not None and not ctx.is_open:
|
||||
for k, v in self.options.items():
|
||||
ctx.options.setdefault(k, v)
|
||||
|
||||
if not (ctx._ctxflags & 1): # template_initialized
|
||||
ctx.open()
|
||||
|
||||
# Track option consumption.
|
||||
|
|
@ -384,8 +479,8 @@ class OutputContainer(Container):
|
|||
errors=self.metadata_errors,
|
||||
)
|
||||
|
||||
all_options: _Dictionary = Dictionary(self.options, self.container_options)
|
||||
options: _Dictionary = all_options.copy()
|
||||
all_options: Dictionary = Dictionary(self.options, self.container_options)
|
||||
options: Dictionary = all_options.copy()
|
||||
self.err_check(lib.avformat_write_header(self.ptr, cython.address(options.ptr)))
|
||||
|
||||
# Track option usage...
|
||||
|
|
@ -403,7 +498,7 @@ class OutputContainer(Container):
|
|||
log = logging.getLogger(__name__)
|
||||
log.warning("Some options were not used: %s" % unused_options)
|
||||
|
||||
self._started = True
|
||||
self._myflag |= 4
|
||||
|
||||
@property
|
||||
def supported_codecs(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue