Skip to content

Memory Management of VideoFrame image buffers #891

@FirefoxMetzger

Description

@FirefoxMetzger

This issue started from a comment in a PR: #788 (comment)

I'm wondering about the memory ownership/management model in PyAV. For example, the following works without any complaints:

import av
import numpy as np
frame = av.VideoFrame(16, 16, "rgb24")
no_copy_array = np.frombuffer(frame.planes[0], dtype=np.uint8).reshape((16, 16, 3))
del frame  # will this be dangerous?
no_copy_array[:5, :5] = 42

However, I wonder if this is actually undefined behavior because FFmpeg/libav doesn't know about no_copy_array. Hence, when I call del frame (which internally calls av_freep) then the buffer should be freed and no_copy_array should point into unallocated memory which is undefined behavior. I suspect a similar situation would happen if the buffer came from container.decode() instead of me creating it manually (in which case the default would be that the buffer is internally ref-counted and freed by FFmpeg).

So my question is if PyAV does any explicit memory management here, and if not if it relies on python's gc or ffmpeg's gc (or a mix of the two).

Edit: I just played around with this on something more sizable (5GB worth of frames). and it correctly allocates and frees memory. This isn't a definite answer, but perhaps a first step towards it.

>>> import av
>>> import numpy as np
>>> shape = (int(1e3)*16, int(1e3)*16)     
>>> frames = [av.VideoFrame(*shape, "rgb24") for _ in range(10)]
>>> arrays = [np.frombuffer(frame.planes[0], dtype=np.uint8).reshape((*shape, 3)) for frame in frames]
>>> for array in arrays:
...     array[...] = 4
... 
>>> np.frombuffer(frames[0].planes[0], dtype=np.uint8)[:10]  # proof that buffers are shared  
array([4, 4, 4, 4, 4, 4, 4, 4, 4, 4], dtype=uint8)
>>> del frames  # buffers are always freed after the second del
>>> del arrays  # order doesn't matter here

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions