buresu / ndi-python

NewTek NDI Python wrapper
MIT License
138 stars 31 forks source link

Potential for memory leak if using the examples with this implementation. #32

Open kaine-bruce-dmt opened 1 year ago

kaine-bruce-dmt commented 1 year ago

TLDR: The example code is incorrect for the current implementation and does not align with the original NDI spec. This means it is easy to create a memory leak if you're using the example code.

In the NDI SDK documentation, they specifically call NDIlib_recv_capture_v3 (or NDIlib_recv_capture_v2) with a receiver and then the pointers for each frame. You can also supply NULL if you don't want a frame.

However in the code base for ndi-python we specify ALL 3 pointers, which means we need to free all 3 of these pointers.

https://github.com/buresu/ndi-python/blob/8aad19db2bd4adde75ea5e1aef3ad83e11f08bd8/src/main.cpp#L456-L488

In the examples folder, we do not explicitly free them, so there is potential for memory leaks if this is running for a long time (I got to 10GB after 17hours while testing)

https://github.com/buresu/ndi-python/blob/8aad19db2bd4adde75ea5e1aef3ad83e11f08bd8/example/recv_cv.py#L37-L44

Suggest changing the C++ implementation, or changing the examples so that the other 2 frames are freed.

For anyone looking for a quick solution in their own code you can do something like:

(
    frame_type,
    video_frame,
    audio_frame,
    meta_frame,
) = ndi.recv_capture_v3(ndi_connection, 5000)

# As this implementation of NDI implicitly gives you ALL 3 frame types
# You must make sure you free them, else you will get a memory leak!

if frame_type == ndi.FRAME_TYPE_VIDEO:
    # do stuff
    ndi.recv_free_video_v2(ndi_connection, video_frame)

if frame_type == ndi.FRAME_TYPE_AUDIO:
     # do stuff
    ndi.recv_free_audio_v3(ndi_connection, audio_frame)

if frame_type == ndi.FRAME_TYPE_METADATA:
     # do stuff
    ndi.recv_free_metadata(ndi_connection, meta_frame)