diff --git a/av/audio/stream.pyi b/av/audio/stream.pyi index cf4173759..9e972c56d 100644 --- a/av/audio/stream.pyi +++ b/av/audio/stream.pyi @@ -6,11 +6,19 @@ from av.stream import Stream from .codeccontext import AudioCodecContext from .format import AudioFormat from .frame import AudioFrame +from .layout import AudioLayout class AudioStream(Stream): - type: Literal["audio"] - format: AudioFormat codec_context: AudioCodecContext + # From codec context + frame_size: int + sample_rate: int + rate: int + channels: int + channel_layout: int + layout: AudioLayout + format: AudioFormat + type: Literal["audio"] - def encode(self, frame: AudioFrame | None = None) -> list[Packet]: ... # type: ignore[override] + def encode(self, frame: AudioFrame | None = None) -> list[Packet]: ... def decode(self, packet: Packet | None = None) -> list[AudioFrame]: ... diff --git a/av/audio/stream.pyx b/av/audio/stream.pyx index 3c6b76fcf..f6dc3b065 100644 --- a/av/audio/stream.pyx +++ b/av/audio/stream.pyx @@ -1,7 +1,36 @@ +from av.packet cimport Packet + + cdef class AudioStream(Stream): def __repr__(self): form = self.format.name if self.format else None return ( - f"" ) + + def encode(self, frame=None): + """ + Encode an :class:`.AudioFrame` and return a list of :class:`.Packet`. + + :return: :class:`list` of :class:`.Packet`. + + .. seealso:: This is mostly a passthrough to :meth:`.CodecContext.encode`. + """ + + packets = self.codec_context.encode(frame) + cdef Packet packet + for packet in packets: + packet._stream = self + packet.ptr.stream_index = self.ptr.index + + return packets + + def decode(self, packet=None): + """ + Decode a :class:`.Packet` and return a list of :class:`.AudioFrame`. + :return: :class:`list` of :class:`.AudioFrame` + .. seealso:: This is a passthrough to :meth:`.CodecContext.decode`. + """ + + return self.codec_context.decode(packet) diff --git a/av/stream.pyi b/av/stream.pyi index ffe4f8722..4c4c05030 100644 --- a/av/stream.pyi +++ b/av/stream.pyi @@ -31,5 +31,3 @@ class Stream: frames: int language: str | None type: Literal["video", "audio", "data", "subtitle", "attachment"] - - def encode(self, frame: Frame | None = None) -> list[Packet]: ... diff --git a/av/stream.pyx b/av/stream.pyx index 0ed3e50df..08744771e 100644 --- a/av/stream.pyx +++ b/av/stream.pyx @@ -146,25 +146,6 @@ cdef class Stream: # Lets just copy what we want. err_check(lib.avcodec_parameters_from_context(self.ptr.codecpar, self.codec_context.ptr)) - def encode(self, frame=None): - """ - Encode an :class:`.AudioFrame` or :class:`.VideoFrame` and return a list - of :class:`.Packet`. - - :return: :class:`list` of :class:`.Packet`. - - .. seealso:: This is mostly a passthrough to :meth:`.CodecContext.encode`. - """ - if self.codec_context is None: - raise RuntimeError("Stream.encode requires a valid CodecContext") - - packets = self.codec_context.encode(frame) - cdef Packet packet - for packet in packets: - packet._stream = self - packet.ptr.stream_index = self.ptr.index - return packets - cdef _get_side_data(self, lib.AVStream *stream): # Get DISPLAYMATRIX SideData from a lib.AVStream object. # Returns: tuple[int, dict[str, Any]] diff --git a/av/video/codeccontext.pyi b/av/video/codeccontext.pyi index a749ad3f9..4576f5155 100644 --- a/av/video/codeccontext.pyi +++ b/av/video/codeccontext.pyi @@ -4,18 +4,20 @@ from typing import Iterator, Literal from av.codec.context import CodecContext from av.packet import Packet +from .format import VideoFormat from .frame import VideoFrame class VideoCodecContext(CodecContext): + format: VideoFormat width: int height: int bits_per_codec_sample: int - pix_fmt: str + pix_fmt: str | None framerate: Fraction rate: Fraction gop_size: int - sample_aspect_ratio: Fraction - display_aspect_ratio: Fraction + sample_aspect_ratio: Fraction | None + display_aspect_ratio: Fraction | None has_b_frames: bool coded_width: int coded_height: int @@ -23,8 +25,8 @@ class VideoCodecContext(CodecContext): color_primaries: int color_trc: int colorspace: int - type: Literal["video"] + def encode(self, frame: VideoFrame | None = None) -> list[Packet]: ... def encode_lazy(self, frame: VideoFrame | None = None) -> Iterator[Packet]: ... def decode(self, packet: Packet | None = None) -> list[VideoFrame]: ... diff --git a/av/video/stream.pyi b/av/video/stream.pyi index b0266328a..7ff1a4034 100644 --- a/av/video/stream.pyi +++ b/av/video/stream.pyi @@ -9,20 +9,31 @@ from .format import VideoFormat from .frame import VideoFrame class VideoStream(Stream): - width: int - height: int - format: VideoFormat - pix_fmt: str | None - sample_aspect_ratio: Fraction | None - codec_context: VideoCodecContext - type: Literal["video"] - - # from codec context bit_rate: int | None max_bit_rate: int | None bit_rate_tolerance: int thread_count: int thread_type: Any + codec_context: VideoCodecContext + # from codec context + format: VideoFormat + width: int + height: int + bits_per_codec_sample: int + pix_fmt: str | None + framerate: Fraction + rate: Fraction + gop_size: int + sample_aspect_ratio: Fraction | None + display_aspect_ratio: Fraction | None + has_b_frames: bool + coded_width: int + coded_height: int + color_range: int + color_primaries: int + color_trc: int + colorspace: int + type: Literal["video"] - def encode(self, frame: VideoFrame | None = None) -> list[Packet]: ... # type: ignore[override] + def encode(self, frame: VideoFrame | None = None) -> list[Packet]: ... def decode(self, packet: Packet | None = None) -> list[VideoFrame]: ... diff --git a/av/video/stream.pyx b/av/video/stream.pyx index 08949be2e..b88b3919a 100644 --- a/av/video/stream.pyx +++ b/av/video/stream.pyx @@ -1,7 +1,37 @@ +from av.packet cimport Packet + + cdef class VideoStream(Stream): def __repr__(self): return ( - f"" ) + + def encode(self, frame=None): + """ + Encode an :class:`.VideoFrame` and return a list of :class:`.Packet`. + + :return: :class:`list` of :class:`.Packet`. + + .. seealso:: This is mostly a passthrough to :meth:`.CodecContext.encode`. + """ + + packets = self.codec_context.encode(frame) + cdef Packet packet + for packet in packets: + packet._stream = self + packet.ptr.stream_index = self.ptr.index + + return packets + + + def decode(self, packet=None): + """ + Decode a :class:`.Packet` and return a list of :class:`.VideoFrame`. + :return: :class:`list` of :class:`.Frame` subclasses. + .. seealso:: This is a passthrough to :meth:`.CodecContext.decode`. + """ + + return self.codec_context.decode(packet)