You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下NDI+OpenCV Python代码运行254帧后停止求助

Windows下Python NDI接收254帧后崩溃的原因及解决办法

问题原因

  • 代码中处理视频帧时提前释放了NDI视频帧资源:在调用ndi.recv_free_video_v2(ndi_recv, vfr)之后才执行np.copy(vfr.data),此时vfr.data指向的内存已经被NDI SDK回收,属于非法内存访问。
  • Windows系统的内存保护机制比macOS更严格,这类非法访问会直接触发程序终止;而macOS的内存管理对这类问题容忍度稍高,不会立刻崩溃,但依然属于错误操作。
  • 254帧的限制是巧合,本质是非法内存访问积累到一定程度触发系统保护。

解决办法

调整视频帧处理顺序,先复制帧数据,再释放NDI帧资源。

修正后的关键代码段

if t == ndi.FRAME_TYPE_VIDEO:
    print('Video data received (%dx%d).' % (vfr.xres, vfr.yres))
    # 先复制帧数据到numpy数组
    frame = np.copy(vfr.data)
    # 再释放NDI视频帧资源
    ndi.recv_free_video_v2(ndi_recv, vfr)
    cv2.imshow('frame', frame)
    n_frames += 1
    print(n_frames)
    continue

完整修正代码

# NDI test

import sys
import numpy as np
import NDIlib as ndi
import cv2

# --------------------------------------------------------------------

def vd_main():

    if not ndi.initialize():
        print('ndi initialize failed')
        return 0

    ndi_find = ndi.find_create_v2()

    if ndi_find is None:
        print('ndi_find_create failed')
        return 0

    sources = []
    choice = 0
#  ---
    while choice < 1:
        print('looking for sources ...')
        ndi.find_wait_for_sources(ndi_find, 5000)
        sources = ndi.find_get_current_sources(ndi_find)
        print('network sources (%s found).' % len(sources))
        for i, s in enumerate(sources):
            print('%s. %s' % (i + 1, s.ndi_name))
        choice = int(input('please make your choice (or 0 to rescan, 99 to exit): '))
        if choice > 0:
            if choice > len(sources):
                if choice == 99:
                    return 0
                print('invalid choice')
                choice = 0
          #  else:
           #     break
                
    cv2.namedWindow('frame', cv2.WINDOW_NORMAL)   # create window, to use cv2 waitkey
    n_frames = 0

    ndi_recv_create = ndi.RecvCreateV3()
    ndi_recv_create.color_format = ndi.RECV_COLOR_FORMAT_BGRX_BGRA

    ndi_recv = ndi.recv_create_v3(ndi_recv_create)

    if ndi_recv is None:
        print('failed recv create v3')
        return 0

    ndi.find_destroy(ndi_find) # done finding

    choice -= 1
    ndi.recv_connect(ndi_recv, sources[choice])

    while True:
        t, vfr, a, _ = ndi.recv_capture_v2(ndi_recv, 100)

        keyp = cv2.waitKey(5)   # 5
        if keyp == ord('q'):
            break

        if t == ndi.FRAME_TYPE_NONE:
            print('No data received.')
            continue

        if t == ndi.FRAME_TYPE_VIDEO:
            print('Video data received (%dx%d).' % (vfr.xres, vfr.yres))
            # 先复制数据再释放资源
            frame = np.copy(vfr.data)
            ndi.recv_free_video_v2(ndi_recv, vfr)
            cv2.imshow('frame', frame)
            n_frames += 1
            print(n_frames)
            continue

        if t == ndi.FRAME_TYPE_AUDIO:
        #    print('Audio data received (%d samples).' % a.no_samples)
            ndi.recv_free_audio_v2(ndi_recv, a)
            continue

    ndi.recv_destroy(ndi_recv)
    ndi.destroy()
    cv2.destroyAllWindows()

    return 0

# -------------------------------------------------------------------------

if __name__ == '__main__':
    sys.exit(vd_main())

额外注意事项

  • NDI SDK的资源管理必须严格遵循“先使用,后释放”的原则,所有通过recv_capture_v2获取的帧,都要在使用完其数据后再调用对应的free接口。
  • 若后续需要对帧数据做更复杂的处理,确保所有操作都在释放帧资源前完成。

内容的提问来源于stack exchange,提问作者Franz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:33:22