frame.to_ndarray(format='rgba')
can cause a crash
#1510
Replies: 8 comments
-
None of my media players would play anything beyond 23 frames. I even tried playing 026.webm using ffplay from the latest commit in master (9949c1dd78) and it still only played 23 frames. Since PyAV uses ffmpeg as its source of truth, iterating over 23 frames is the correct behavior. I can verify those crashes on Windows, but since it appears that ffmpeg library is crashing, rather than PyAV itself, I don't think there is anything we can do. |
Beta Was this translation helpful? Give feedback.
-
Actually I counted the number of frames by I checked again using The code I given should iterate all frames, including non-keyframes, right?
But it does not crash if I invoke ffmpeg from command line, so could this mean a problem with how pyav is binding to ffmpeg? |
Beta Was this translation helpful? Give feedback.
-
That command, When I ran that command, I did get 152 frames, however, each of those frames are repeated 5-8 times. When I run the equivalent for PyAV, it only makes the 23 unique frames. I believe that PyAV has the correct behavior here. If ffmpeg 5.1 or ffmpeg 6.0 cli crash when running on this input, then there is certainly nothing PyAV can do, at least until PyAV drops support for ffmpeg 5.x. |
Beta Was this translation helpful? Give feedback.
-
Got it. Should we report the crash in Windows and Linux to ffmpeg? I am not sure how to report though as the problem is within the library, not the command itself. |
Beta Was this translation helpful? Give feedback.
-
I end up with this working code: import av
from av.codec.context import CodecContext
in_f = '026.webm'
frames = []
context = CodecContext.create('libvpx-vp9', 'r')
with av.open(in_f) as container:
for packet in container.demux(stream):
for frame in context.decode(packet):
if frame.width % 2 != 0:
width = frame.width - 1
else:
width = frame.width
if frame.height % 2 != 0:
height = frame.height - 1
else:
height = frame.height
# print(frame.format.name) # yuva420p
frame = frame.reformat(width=width, height=height, format='yuva420p', dst_colorspace=1)
y = useful_array(frame.planes[0]).reshape(height, width)
u = useful_array(frame.planes[1]).reshape(height // 2, width // 2)
v = useful_array(frame.planes[2]).reshape(height // 2, width // 2)
a = useful_array(frame.planes[3]).reshape(height, width)
u = u.repeat(2, axis=0).repeat(2, axis=1)
v = v.repeat(2, axis=0).repeat(2, axis=1)
y = y.reshape((y.shape[0], y.shape[1], 1))
u = u.reshape((u.shape[0], u.shape[1], 1))
v = v.reshape((v.shape[0], v.shape[1], 1))
a = a.reshape((a.shape[0], a.shape[1], 1))
yuv_array = np.concatenate((y, u, v), axis=2)
yuv_array = yuv_array.astype(np.float32)
yuv_array[:, :, 0] = yuv_array[:, :, 0].clip(16, 235).astype(yuv_array.dtype) - 16
yuv_array[:, :, 1:] = yuv_array[:, :, 1:].clip(16, 240).astype(yuv_array.dtype) - 128
convert = np.array([#[1.164, 0.000, 1.793],[1.164, -0.213, -0.533],[1.164, 2.112, 0.000]
[1.164, 0.000, 2.018], [1.164, -0.813, -0.391],[1.164, 1.596, 0.000]
])
rgb_array = np.matmul(yuv_array, convert.T).clip(0,255).astype('uint8')
rgba_array = np.concatenate((rgb_array, a), axis=2)
frames.append(rgba_array) After some testing, I think the crash in second case occurs in this line in |
Beta Was this translation helpful? Give feedback.
-
I am currently experiencing the same problem. A crash occurs while translating yuva to rgba. The first frame is converted without a problem, but it crashes immediately on the next frame. State management issue in codec context? |
Beta Was this translation helpful? Give feedback.
-
To pinpoint the error, it's reformatting YUVA420P format to RGBA frames, then one frame of that reformat gets garbage collected, and then the next YUVA420P reformat back to RGBA frames crashes. In other words, it seems that the YUVA420P to RGBA converted frames are not being freed properly (or duplicate freed). I'm not sure if this is exactly the same issue. Below is the code to reproduce this.
This problem does not occur when the width of the VideoFrame is divided by 16.
I don't have any knowledge of video encoding and decoding, so I can't fix this, but I've tried to reproduce the error in more detail because I'd like to see this resolved. |
Beta Was this translation helpful? Give feedback.
-
After playing around with different build environments, I found that the issue occurs when SSSE3 is enabled (building with the --disable-ssse3 option does not cause this issue). I googled it and found the following issues. If this issue is not directly reflected in FFMPEG, it seems that the only way to avoid the error is to add appropriate padding. |
Beta Was this translation helpful? Give feedback.
-
Overview
I am trying to process the following file:
026.webm
The webm file should contain 152 frames, however pyav can only read 23 frames:
Moreover, the following code cause crash:
The following code also cause crash:
The crash message on Linux:
Note that the problem of not reading all frames is present on Windows, MacOS (arm64) and Arch Linux. The crash occurs on Windows and Arch Linux only, the crash does not occur on macOS arm64.
Using ffmpeg on command line is able to demux and convert the webm file normally.
Expected behavior
All frames of webm file successfully are read without crash
Actual behavior
Not all frames of webm file are successfully read or/and crash
Versions
Tested on Windows, MacOS arm64 Sonoma, Arch Linux.
Both
av
andpyav
(Contains newer version of pyav) wheels from pypi were testedResearch
I have done the following:
Beta Was this translation helpful? Give feedback.
All reactions