Skip to content
Merged
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
14 changes: 14 additions & 0 deletions av/codec/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ def parse(self, raw_input=None):
It will return all packets that are fully contained within the given
input, and will buffer partial packets until they are complete.

Any timing information the parser is able to infer (``pts``, ``dts``,
``duration``, ``pos`` and the keyframe flag) is assigned onto the
returned packets. Fields the parser cannot determine are left unset.

:param ByteSource raw_input: A chunk of a byte-stream to process.
Anything that can be turned into a :class:`.ByteSource` is fine.
``None`` or empty inputs will flush the parser's buffers.
Expand Down Expand Up @@ -327,6 +331,16 @@ def parse(self, raw_input=None):
packet = Packet(out_size)
memcpy(packet.ptr.data, out_data, out_size)

# Propagate the timing information the parser inferred for
# this frame onto the packet (mirrors FFmpeg's parse_packet).
packet.ptr.pts = self.parser.pts
packet.ptr.dts = self.parser.dts
packet.ptr.pos = self.parser.pos
if self.parser.duration:
packet.ptr.duration = self.parser.duration
if self.parser.key_frame == 1:
packet.ptr.flags |= lib.AV_PKT_FLAG_KEY

packets.append(packet)

if not in_size:
Expand Down
8 changes: 7 additions & 1 deletion include/avcodec.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,13 @@ cdef extern from "libavcodec/avcodec.h" nogil:
int codec_ids[5]

cdef struct AVCodecParserContext:
pass
int64_t pts
int64_t dts
int64_t pos
int64_t last_pos
int64_t offset
int duration
int key_frame

cdef AVCodecParserContext *av_parser_init(int codec_id)
cdef int av_parser_parse2(
Expand Down
16 changes: 16 additions & 0 deletions tests/test_codec_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,22 @@ def _assert_parse(self, codec_name: str, path: str) -> None:
assert len(parsed_source) == len(full_source)
assert full_source == parsed_source

def test_parse_assigns_packet_timing(self) -> None:
# Regression test for #1919: the parser-inferred timing information
# should be propagated onto the returned packets.
path = fate_suite("mpeg2/mpeg2_field_encoding.ts")
full_source = b"".join(bytes(p) for p in av.open(path).demux(video=0))

ctx = Codec("mpeg2video").create()
packets = []
for i in range(0, len(full_source), 4096):
packets.extend(ctx.parse(full_source[i : i + 4096]))
packets.extend(ctx.parse())

# The parser is able to determine the byte position for this stream,
# so at least some packets should carry it through.
assert any(p.pos is not None for p in packets)


class TestEncoding(TestCase):
def test_encoding_png(self) -> None:
Expand Down
Loading