Wpf 기반의 VMS 클라이언트 개발에 관련하여 RTSP 영상 스트리밍 기술 문의합니다.

안녕하세요.

현재 WPF 기반으로 VMS 서버와 클라이언트를 개발하고 있습니다.

VMS는 Video Management System으로 아마 이 질문을 보고 들어오신 분은 어떤 프로그램인지 다 아실 겁니다.


대략 이런 프로그램이라고 보시면 됩니다.(iSpy란 프로그램 예시)

현재 저희가 개발한 기반은 Gst Sharp이라는 소스를 이용해서 구현하였고, gstreamer-d3d11-overlay 라는 소스를 기반으로 rstp영상 view를 구현하였습니다.
문제는 현재 이 테스트 프로그램에서 많은 영상을 시현하게 되면, 혹은 영상을 켜고 끄는 작업을 하게 되면, Access Violation 이란 예외가 나오면서 프로그램이 죽는 현상이 있습니다. 이런 문제를 해결하기 위해서 어떤 조치를 취해야되는지 알 수 있을 까요?

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5783 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5786 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5785 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5788 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5787 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5790 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5789 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5792 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.869: Source ID 5791 was not found when attempting to remove it

(VMS.Test.Client.exe:1732): GLib-CRITICAL **: 14:34:23.870: Source ID 5793 was not found when attempting to remove it
'[스레드 소멸됨]' (14064) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (8800) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (3344) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (13556) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (13604) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (15384) 스레드가 종료되었습니다(코드: 0 (0x0)).

(VMS.Test.Client.exe:1732): GStreamer-CRITICAL **: 14:34:26.080: gst_mini_object_unref: assertion 'GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) > 0' failed
'[스레드 소멸됨]' (14048) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (21696) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (4604) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (26148) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (24232) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (1364) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (24992) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (4644) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (16856) 스레드가 종료되었습니다(코드: 0 (0x0)).
'[스레드 소멸됨]' (17284) 스레드가 종료되었습니다(코드: 0 (0x0)).

(VMS.Test.Client.exe:1732): GStreamer-CRITICAL **: 14:34:27.371: gst_caps_is_empty: assertion 'GST_IS_CAPS (caps)' failed

(VMS.Test.Client.exe:1732): GStreamer-CRITICAL **: 14:34:27.371: gst_caps_is_any: assertion 'GST_IS_CAPS (caps)' failed

(VMS.Test.Client.exe:1732): GStreamer-CRITICAL **: 14:34:27.371: gst_caps_is_fixed: assertion 'GST_IS_CAPS (caps)' failed
'[1732] VMS.Test.Client.exe' 프로그램이 종료되었습니다(코드: 3221225477 (0xc0000005) 'Access violation').

이런 내용을 내뱉으면서 죽네요…

혹시 관련 프로젝트에 대해서 경험이 있으시면 조언 부탁드립니다.

감사합니다.

3개의 좋아요

이것만큼 WPF가 안맞는 분야가 찾기도 어려울건데요.
WPF가 화면 뿌려주는 쪽으로는 제약조건이 꽤나 있거든요.
여하튼 그건 별개로 말씀 드리자면 위의 프로그램은 화면을 뿌릴 공간을 만들고 각 카메라 입력을 컨트롤만 하고요.
실제 화면에 뿌리는건 별도의 프로그램으로 처리를 합니다.
제가 잠깐 몸담았던곳은 메인컨트롤러 외에 카메라 하나당 프로그램 하나가 돌아갔습니다.

이유는 글에도 적으신 것 처럼 매우 다양한 문제가 발생을 하는데. 그걸 단일 프로그램에서 쓰래드로 처리할 경우 카메라 하나의 문제가 전체 문제로 확대될 수 있어서입니다.
특히 카메라가 갑자기 통신이 안될 경우에 socket api에서 지연이 발생하는데. 타임아웃 떨어질때까지 물고있는데. 이게 단일 프로그램이면 다같이 영향을 받을 수 있습니다. 물론 저수준제어를 하면 해결이 되겠지만… 라이브러리를 가져다 쓰는 상황에서 힘들죠.
또는 사용하는 라이브러리에서 문제가 발생할 수 있는데. 이 경우에도 다같이 죽습니다. 그래서 이런 프로그램은 문제 생길만한 것 들은 아예 따로 실행 되도록 만듭니다.

추가) 다시보니 채널수가 많지 않네요. 제가 얘기한 경우는 적어도 32채널 이상일 경우로 생각 하시면 될 것 같습니다.

4개의 좋아요

보통 FFmpeg나 DirectX와 같은 Native Library를 사용하는 경우 객체 lifecycle 관리를 철저하게 해줘야 합니다.

일반적인 룰이라면 아래와 같은데요.

  • 참조하는 리소스의 해제는 반드시 생성 했던 과정의 역순으로
  • 계층 구조가 있는 객체의 경우 부모/자식 관계에 대한 명시적인 참조 해제 및 리소스 해제

gst_object_unref라는 함수는 GStreamer라이브러리에서 사용되는 모든 객체의 lifecycle과 관련된 기본 함수일 것이며 reference count가 0인 객체를 대상으로 해당 함수가 호출된 것 처럼 보입니다.

AcccessViolation이 발생한 것은 아마 의도치 않게 Dispose 또는 Release 계열의 함수가 두 번 호출이 되었거나 의도치 않은 참조 해제로 GC가 발생해 Native Object가 이미 없어져 버렸기 때문일 가능성이 큽니다.

그리고 관련 객체의 생성 및 해제는 async/await를 잘 활용하셔서 항상 메인 스레이드에 일어나도록 적절히 Task를 분리해주면 좋습니다.

추가로 혼합 모드에서 디버그(관리 및 네이티브 코드)를 사용하면 어디서 오류가 발생했는지 확인하는데 도움이 될 수도 있습니다.

4개의 좋아요

답글 감사드립니다.
기존에 .netframework기반에서 .NET 기반으로 (Gstreamer-Sharp이 .NET기반인 관계로) 변경했더니 스트리밍 성능이 더 나빠지네요…

일단 Async-Await 및 Task 관리는 유의해서 해보겟습니다.

2개의 좋아요

감사합니다. 이건 테스트 프로그램이라서 화면 갯수가 좀 적네요…

2개의 좋아요