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 Likes

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

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

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

4 Likes

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

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

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

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

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

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

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

4 Likes

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

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

2 Likes

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

2 Likes