Skip to content

Commit

Permalink
prevent repeating frame indices (fixes: #1158)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeSchiff committed Jan 21, 2024
1 parent 1962443 commit df6be33
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 7 deletions.
1 change: 1 addition & 0 deletions av/codec/context.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ cdef class CodecContext:
cdef _prepare_and_time_rebase_frames_for_encode(self, Frame frame)
cdef _prepare_frames_for_encode(self, Frame frame)
cdef _setup_encoded_packet(self, Packet)
cdef _correct_frame_indices(self, frame_list)
cdef _setup_decoded_frame(self, Frame, Packet)

# Implemented by base for the generic send/recv API.
Expand Down
22 changes: 16 additions & 6 deletions av/codec/context.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -513,24 +513,34 @@ cdef class CodecContext:

self.open(strict=False)

res = []
frame_list = []
for frame in self._send_packet_and_recv(packet):
if isinstance(frame, Frame):
self._setup_decoded_frame(frame, packet)
res.append(frame)
return res
frame_list.append(frame)
if packet and packet.stream and packet.stream.type != "subtitle":
self._correct_frame_indices(frame_list)
return frame_list

cdef _setup_decoded_frame(self, Frame frame, Packet packet):
cdef _correct_frame_indices(self, frame_list):
"""
All frames in the list returned by '_send_packet_and_recv' will have the same index.
This will set the correct indices.
"""
cdef Frame frame
correction = len(frame_list)
for frame in frame_list:
frame.index = self.ptr.frame_num - correction
correction -= 1

cdef _setup_decoded_frame(self, Frame frame, Packet packet):
# Propagate our manual times.
# While decoding, frame times are in stream time_base, which PyAV
# is carrying around.
# TODO: Somehow get this from the stream so we can not pass the
# packet here (because flushing packets are bogus).
frame._time_base = packet._time_base

frame.index = self.ptr.frame_number - 1

property name:
def __get__(self):
return self.codec.name
Expand Down
2 changes: 1 addition & 1 deletion include/libavcodec/avcodec.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ cdef extern from "libavcodec/avcodec.h" nogil:
int global_quality
int compression_level

int frame_number
int frame_num

int qmin
int qmax
Expand Down
19 changes: 19 additions & 0 deletions tests/test_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,22 @@ def test_decode_close_then_use(self):
getattr(container, attr)
except AssertionError:
pass

def test_decode_frame_indices(self):
for thread_type in ("NONE", "AUTO"):
for thread_count in range(4):
for skip_type in ("NONE", "NONKEY"):
frame_list = []
compare_list = []
frame_count = 0
with av.open(fate_suite("h264/interlaced_crop.mp4")) as container:
stream = container.streams.video[0]
stream.thread_type = thread_type
stream.thread_count = thread_count
stream.codec_context.skip_frame = skip_type
for packet in container.demux(stream):
for frame in packet.decode():
frame_list.append(frame.index)
compare_list.append(frame_count)
frame_count += 1
self.assertEqual(frame_list, compare_list)

0 comments on commit df6be33

Please sign in to comment.