from av.error cimport err_check from av.opaque cimport opaque_container from av.utils cimport avrational_to_fraction, to_avrational from av.sidedata.sidedata import SideDataContainer cdef class Frame: """ Base class for audio and video frames. See also :class:`~av.audio.frame.AudioFrame` and :class:`~av.video.frame.VideoFrame`. """ def __cinit__(self, *args, **kwargs): with nogil: self.ptr = lib.av_frame_alloc() def __dealloc__(self): with nogil: # This calls av_frame_unref, and then frees the pointer. # Thats it. lib.av_frame_free(&self.ptr) def __repr__(self): return f"av.{self.__class__.__name__} pts={self.pts} at 0x{id(self):x}>" cdef _copy_internal_attributes(self, Frame source, bint data_layout=True): """Mimic another frame.""" self._time_base = source._time_base lib.av_frame_copy_props(self.ptr, source.ptr) if data_layout: # TODO: Assert we don't have any data yet. self.ptr.format = source.ptr.format self.ptr.width = source.ptr.width self.ptr.height = source.ptr.height self.ptr.ch_layout = source.ptr.ch_layout cdef _init_user_attributes(self): pass # Dummy to match the API of the others. cdef _rebase_time(self, lib.AVRational dst): if not dst.num: raise ValueError("Cannot rebase to zero time.") if not self._time_base.num: self._time_base = dst return if self._time_base.num == dst.num and self._time_base.den == dst.den: return if self.ptr.pts != lib.AV_NOPTS_VALUE: self.ptr.pts = lib.av_rescale_q(self.ptr.pts, self._time_base, dst) self._time_base = dst @property def dts(self): """ The decoding timestamp copied from the :class:`~av.packet.Packet` that triggered returning this frame in :attr:`time_base` units. (if frame threading isn't used) This is also the Presentation time of this frame calculated from only :attr:`.Packet.dts` values without pts values. :type: int """ if self.ptr.pkt_dts == lib.AV_NOPTS_VALUE: return None return self.ptr.pkt_dts @dts.setter def dts(self, value): if value is None: self.ptr.pkt_dts = lib.AV_NOPTS_VALUE else: self.ptr.pkt_dts = value @property def pts(self): """ The presentation timestamp in :attr:`time_base` units for this frame. This is the time at which the frame should be shown to the user. :type: int """ if self.ptr.pts == lib.AV_NOPTS_VALUE: return None return self.ptr.pts @pts.setter def pts(self, value): if value is None: self.ptr.pts = lib.AV_NOPTS_VALUE else: self.ptr.pts = value @property def time(self): """ The presentation time in seconds for this frame. This is the time at which the frame should be shown to the user. :type: float """ if self.ptr.pts == lib.AV_NOPTS_VALUE: return None else: return float(self.ptr.pts) * self._time_base.num / self._time_base.den @property def time_base(self): """ The unit of time (in fractional seconds) in which timestamps are expressed. :type: fractions.Fraction """ if self._time_base.num: return avrational_to_fraction(&self._time_base) @time_base.setter def time_base(self, value): to_avrational(value, &self._time_base) @property def is_corrupt(self): """ Is this frame corrupt? :type: bool """ return self.ptr.decode_error_flags != 0 or bool(self.ptr.flags & lib.AV_FRAME_FLAG_CORRUPT) @property def key_frame(self): """Is this frame a key frame? Wraps :ffmpeg:`AVFrame.key_frame`. """ return bool(self.ptr.flags & lib.AV_FRAME_FLAG_KEY) @property def side_data(self): if self._side_data is None: self._side_data = SideDataContainer(self) return self._side_data def make_writable(self): """ Ensures that the frame data is writable. Copy the data to new buffer if it is not. This is a wrapper around :ffmpeg:`av_frame_make_writable`. """ cdef int ret ret = lib.av_frame_make_writable(self.ptr) err_check(ret) @property def opaque(self): if self.ptr.opaque_ref is not NULL: return opaque_container.get(<char *> self.ptr.opaque_ref.data) @opaque.setter def opaque(self, v): lib.av_buffer_unref(&self.ptr.opaque_ref) if v is None: return self.ptr.opaque_ref = opaque_container.add(v)
Memory