Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion av/audio/frame.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ cdef class AudioFrame(Frame):
cdef _init_user_attributes(self):
self.layout = get_audio_layout(0, self.ptr.channel_layout)
self.format = get_audio_format(<lib.AVSampleFormat>self.ptr.format)
self._init_planes(AudioPlane)
if self.planes is None:
self._init_planes(AudioPlane)

def __repr__(self):
return '<av.%s %d, pts=%s, %d samples at %dHz, %s, %s at 0x%x>' % (
Expand Down
37 changes: 37 additions & 0 deletions av/codec/context.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,25 @@ cdef class CodecContext(object):
break
return out

def _send_packet_and_recv_reuse(self, Packet packet):

cdef Frame frame

cdef int res
with nogil:
res = lib.avcodec_send_packet(self.ptr, &packet.struct if packet is not None else NULL)
err_check(res)

while True:
frame = self._recv_frame()
if frame:
self._setup_decoded_frame(frame, packet)
yield frame
self._next_frame = frame
else:
break
return

cdef _prepare_frames_for_encode(self, Frame frame):
return [frame]

Expand Down Expand Up @@ -357,6 +376,24 @@ cdef class CodecContext(object):
res.append(frame)
return res

def xdecode(self, packet=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).

"""

if not self.codec.ptr:
raise ValueError('cannot decode unknown codec')

self.open(strict=False)

for frame in self._send_packet_and_recv_reuse(packet):
yield frame
return

cdef _setup_decoded_frame(self, Frame frame, Packet packet):

# Propagate our manual times.
Expand Down
17 changes: 17 additions & 0 deletions av/container/input.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,23 @@ cdef class InputContainer(Container):
for frame in packet.decode():
yield frame

def xdecode(self, *args, **kwargs):
"""xdecode(streams=None, video=None, audio=None, subtitles=None, data=None)

Yields a series of :class:`.Frame` from the given set of streams::

for frame in container.decode():
# Do something with `frame`.

.. seealso:: :meth:`.StreamContainer.get` for the interpretation of
the arguments.

"""
id(kwargs) # Avoid Cython bug; see demux().
for packet in self.demux(*args, **kwargs):
for frame in packet.xdecode():
yield frame

def seek(self, offset, whence='time', backward=True, any_frame=False, stream=None):
"""Seek to a (key)frame nearsest to the given timestamp.

Expand Down
7 changes: 7 additions & 0 deletions av/packet.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ cdef class Packet(Buffer):
"""
return self._stream.decode(self)

def xdecode(self):
"""
Send the packet's data to the decoder and return a list of
:class:`.AudioFrame`, :class:`.VideoFrame` or :class:`.SubtitleSet`.
"""
return self._stream.xdecode(self)

@deprecation.method
def decode_one(self):
"""
Expand Down
7 changes: 7 additions & 0 deletions av/stream.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ cdef class Stream(object):
"""
return self.codec_context.decode(packet)

def xdecode(self, packet=None):
"""
Decode a :class:`.Packet` and return a list of :class:`.AudioFrame`
or :class:`.VideoFrame`.
"""
return self.codec_context.xdecode(packet)

@deprecation.method
def seek(self, offset, whence='time', backward=True, any_frame=False):
"""
Expand Down
3 changes: 2 additions & 1 deletion av/video/frame.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ cdef class VideoFrame(Frame):

cdef _init_user_attributes(self):
self.format = get_video_format(<lib.AVPixelFormat>self.ptr.format, self.ptr.width, self.ptr.height)
self._init_planes(VideoPlane)
if self.planes is None:
self._init_planes(VideoPlane)

def __dealloc__(self):
# The `self._buffer` member is only set if *we* allocated the buffer in `_init`,
Expand Down