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
相关产品推荐
相关产品推荐

