diff --git a/av/container/output.pyx b/av/container/output.pyx index 616d40ae6..fbe163bc1 100644 --- a/av/container/output.pyx +++ b/av/container/output.pyx @@ -4,9 +4,6 @@ from fractions import Fraction cimport libav as lib -from libc.string cimport memcpy -from libc.stdint cimport uint8_t - from av.codec.codec cimport Codec from av.codec.context cimport CodecContext, wrap_codec_context from av.container.streams cimport StreamContainer @@ -251,59 +248,6 @@ cdef class OutputContainer(Container): return py_stream - def add_attachment(self, file_data, filename, mimetype=None): - """Add a file as an attachment stream.""" - cdef lib.AVStream *stream - cdef size_t data_len - cdef uint8_t *attachment - cdef Stream py_stream - - if not isinstance(file_data, bytes): - raise TypeError("file_data must be bytes") - - if not filename: - raise ValueError("filename must be provided") - - # Create new stream without codec - stream = lib.avformat_new_stream(self.ptr, NULL) - if stream == NULL: - raise MemoryError("Could not allocate stream") - - try: - # Mark as attachment type - stream.codecpar.codec_type = lib.AVMEDIA_TYPE_ATTACHMENT - - # Allocate and copy attachment data - data_len = len(file_data) - attachment = lib.av_malloc(data_len) - if attachment == NULL: - raise MemoryError("Could not allocate attachment buffer") - - # Copy the data - memcpy(attachment, file_data, data_len) - - # Store attachment in codecpar extradata - stream.codecpar.extradata = attachment - stream.codecpar.extradata_size = data_len - - # Add metadata - err_check(lib.av_dict_set(&stream.metadata, "filename", filename.encode('utf-8'), 0)) - err_check(lib.av_dict_set(&stream.metadata, "mimetype", mimetype.encode('utf-8'), 0)) - - # Explicitly set time_base to avoid duration issues - stream.time_base.num = 1 - stream.time_base.den = 1 - - # Create Python stream object - py_stream = wrap_stream(self, stream, None) - self.streams.add_stream(py_stream) - - return py_stream - - except Exception: - lib.av_free(attachment) - raise - cpdef start_encoding(self): """Write the file header! Called automatically.""" diff --git a/av/stream.pyi b/av/stream.pyi index 82bb672b2..a2a2e439c 100644 --- a/av/stream.pyi +++ b/av/stream.pyi @@ -1,9 +1,31 @@ +from enum import Flag from fractions import Fraction from typing import Literal from .codec import Codec, CodecContext from .container import Container +class Disposition(Flag): + default: int + dub: int + original: int + comment: int + lyrics: int + karaoke: int + forced: int + hearing_impaired: int + visual_impaired: int + clean_effects: int + attached_pic: int + timed_thumbnails: int + non_diegetic: int + captions: int + descriptions: int + metadata: int + dependent: int + still_image: int + multilayer: int + class Stream: name: str | None container: Container @@ -20,6 +42,7 @@ class Stream: guessed_rate: Fraction | None start_time: int | None duration: int | None + disposition: Disposition frames: int language: str | None type: Literal["video", "audio", "data", "subtitle", "attachment"] diff --git a/av/stream.pyx b/av/stream.pyx index 35b85acdf..d0ecf37ad 100644 --- a/av/stream.pyx +++ b/av/stream.pyx @@ -1,6 +1,6 @@ cimport libav as lib -from enum import Enum +from enum import Flag from av.error cimport err_check from av.packet cimport Packet @@ -12,6 +12,28 @@ from av.utils cimport ( ) +class Disposition(Flag): + default = 1 << 0 + dub = 1 << 1 + original = 1 << 2 + comment = 1 << 3 + lyrics = 1 << 4 + karaoke = 1 << 5 + forced = 1 << 6 + hearing_impaired = 1 << 7 + visual_impaired = 1 << 8 + clean_effects = 1 << 9 + attached_pic = 1 << 10 + timed_thumbnails = 1 << 11 + non_diegetic = 1 << 12 + captions = 1 << 16 + descriptions = 1 << 17 + metadata = 1 << 18 + dependent = 1 << 19 + still_image = 1 << 20 + multilayer = 1 << 21 + + cdef object _cinit_bypass_sentinel = object() cdef Stream wrap_stream(Container container, lib.AVStream *c_stream, CodecContext codec_context): @@ -96,6 +118,9 @@ cdef class Stream: if name == "id": self._set_id(value) return + if name == "disposition": + self.ptr.disposition = value + return # Convenience setter for codec context properties. if self.codec_context is not None: @@ -230,6 +255,10 @@ cdef class Stream: """ return self.metadata.get("language") + @property + def disposition(self): + return Disposition(self.ptr.disposition) + @property def type(self): """ diff --git a/include/libav.pxd b/include/libav.pxd index 716a58195..568913208 100644 --- a/include/libav.pxd +++ b/include/libav.pxd @@ -23,10 +23,6 @@ include "libavfilter/buffersink.pxd" include "libavfilter/buffersrc.pxd" -cdef extern from "libavutil/mem.h": - void* av_malloc(size_t size) nogil - void av_free(void* ptr) nogil - cdef extern from "stdio.h" nogil: cdef int snprintf(char *output, int n, const char *format, ...) cdef int vsnprintf(char *output, int n, const char *format, va_list args) diff --git a/tests/test_colorspace.py b/tests/test_colorspace.py index 7574c147d..c76416c80 100644 --- a/tests/test_colorspace.py +++ b/tests/test_colorspace.py @@ -31,6 +31,8 @@ def test_sky_timelapse() -> None: ) stream = container.streams.video[0] + assert stream.disposition == av.stream.Disposition.default + assert stream.codec_context.color_range == 1 assert stream.codec_context.color_range == ColorRange.MPEG assert stream.codec_context.color_primaries == 1