Pelco Developer Network (PDN)

calling PelcoSDK(ver 4.0 and the later) in thread led to program lockup in Endura system

Please provide additional information to this topic.

Describe the steps taken, any specific error messages recorded by Pelco SDK logging (or other debug messages), and explain in greater detail the 'lockup' that you are indicating.

Thanks!

steps and error info

User is trying to create a thread to display stream. The steps are:
1. click play button to create a thread. A handle of dialog is passed to thread;
2. thread call a play function to display stream on selected window.
if we are capturing network packageds at the same time, we will see camera has started to send stream to application. But there are errors in MPF.log:
Unknown file(0): RtlInitializeExceptionChain()
Unknown file(0): RtlInitializeExceptionChain()
[EntryPoint:039AA900]: Caught XSDK::XException thrown from [..\..\..\..\Plugins\Core\RendererD3D\Source\RenderTarget.cpp:1130]: "[CreateD3DDevice:039AA900]: Error: 0x8876086c, failed to create an d3dex device"
Exception thrown. Msg: "[CreateD3DDevice:039AA900]: Error: 0x8876086c, failed to create an d3dex device"
If user calls the play function directly instead of creating thread to call play function, the stream can be displayed normally.
Is there any suggesion?
Thanks.

Interesting.

Typically an error related to RendererD3D / D3DDevice / d3dex are all related to Direct X at the viewing client level. A requirement of using the Pelco SDK is that DirectX 9.0c must be installed (documentation here): Pelco SDK 4.2.1 Quick Start Guide.

The final part of your post does introduce some confusion, however. The error indicates that it is an issue with Rendering the video. Some possible causes could be the nature of the stream itself that the SDK is having a problem with (... maybe, formatting or stream type... though doubtful), or an issue using DirectX or the graphics on the PC from the calling thread itself.

In fact, rendering video can be problematic when working with different threads, so it is quite probable that is the crux of the problem is the threading behavior that you are describing. Streaming on one thread and then trying to render the video to another thread is what's causing the problem, no doubt there, since it works just fine when not doing that action. Trying to render video on the UI from a thread that isn't main calling thread is going to be a problem.

the following codes are taken from the test project,Could you give any advice?
The test project is only 120KB,it is under win7 (32bit)/sdk4.2.1/vc2010,Could I get your email address?

// API_ViewerDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "API_Viewer.h"
#include "API_ViewerDlg.h"
#include "afxdialogex.h"
#include "direct.h"
#include "IO.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
using namespace PelcoSDK;

#define WM_PLAY WM_USER+101

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();

// 对话框数据
enum { IDD = IDD_ABOUTBOX };

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现
protected:
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CAPI_ViewerDlg 对话框

CAPI_ViewerDlg::CAPI_ViewerDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CAPI_ViewerDlg::IDD, pParent)
, m_Radio(2)
, m_RadioChecked(1)
, m_LowBand(FALSE)
, m_WithoutAudio(FALSE)
, m_Analytics(FALSE)
, m_Time(FALSE)
, m_Motion(FALSE)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAPI_ViewerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
// DDX_Control(pDX, IDC_FASTFOWARD, m_FastFoward);
DDX_Control(pDX, IDC_COMBO_CAM, m_boxCam);
}

BEGIN_MESSAGE_MAP(CAPI_ViewerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_PLAY, &CAPI_ViewerDlg::OnBnClickedPlay)
ON_BN_CLICKED(IDC_BTN_GET, &CAPI_ViewerDlg::OnBnClickedBtnGet)
ON_CBN_SELCHANGE(IDC_COMBO_CAM, &CAPI_ViewerDlg::OnCbnSelchangeComboCam)
ON_BN_CLICKED(IDC_PLAY3, &CAPI_ViewerDlg::OnBnClickedPlay3)
ON_BN_CLICKED(IDC_STOP2, &CAPI_ViewerDlg::OnBnClickedStop2)
ON_WM_CLOSE()
END_MESSAGE_MAP()

// CAPI_ViewerDlg 消息处理程序

BOOL CAPI_ViewerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码
//CheckRadioButton(IDC_RTPLIVE,IDC_RTSPPLAY,IDC_RTPLIVE);
m_Radio=2;
n=1;

//GetDlgItem(IDC_RTPLIVE)->CheckRadioButton(IDC_RTPLIVE,IDC_RTSPPLAY,IDC_RTPLIVE);
SetDlgItemText(IDC_CAMIP,"192.168.5.192");
SetDlgItemText(IDC_CAMPORT,"80");
SetDlgItemText(IDC_CAMNUM,"1");
SetDlgItemText(IDC_STARTTIME1,"NOW");
SetDlgItemText(IDC_ENDTIME,"INFINITE");

m_pTimestampOverlay = new TimestampOverlay( OVERLAY_LOCATION_BOTTOM_LEFT,m_FontParam,DATE_FORMAT_YYYYMMDD, TIME_FORMAT_HHMMSSTT );
snapshotNum=1;

//2、获取显示窗口的句柄,或自己创建窗口
HWND _hWndParent=NULL;
_hWndParent=GetDlgItem(IDC_PLAY2)->m_hWnd;
m_pDisplay2 = new Display( _hWndParent );
pszSesId = NULL;
pszSesId2 = NULL;

loggedInSys = NULL;
m_pStream = NULL;
m_pStream2 = NULL;

m_lExit = 0;
HANDLE hThread;
DWORD dwThreadId;
m_hEventPlay = CreateEvent( NULL,FALSE,FALSE,NULL );
hThread = CreateThread( NULL,0,(LPTHREAD_START_ROUTINE)Playv,this,0,&dwThreadId);
if( hThread )
CloseHandle( hThread );

return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}

void CAPI_ViewerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。

void CAPI_ViewerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文

SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);

// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CAPI_ViewerDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}

long CAPI_ViewerDlg::GetTimeCount( char *utc )
{
int year,month,day,hour,min,sec;
CString szInfo,szTmp;
szInfo.Format( "%s",utc );
szTmp = szInfo.Left( szInfo.Find( '-') );
year = atoi(szTmp);
szTmp = szInfo.Right( szInfo.GetLength()-szInfo.Find( '-')-1 );
month = atoi( szTmp.Left( szTmp.Find( '-' ) ) );
szInfo = szTmp.Right( szTmp.GetLength()-szTmp.Find( '-')-1 );
day = atoi(szInfo.Left( szInfo.Find( 'T') ) );
szTmp = szInfo;
szInfo = szTmp.Right( szTmp.GetLength()-szTmp.Find( 'T')-1 );
hour = atoi( szInfo.Left( szInfo.Find( ':' ) ) );
szTmp = szInfo;
szInfo = szTmp.Right( szTmp.GetLength()-szTmp.Find( ':')-1 );
min = atoi( szInfo.Left( szInfo.Find( ':') ) );
szTmp = szInfo;
szInfo = szTmp.Right( szTmp.GetLength()-szTmp.Find( ':')-1 );
sec = atoi( szInfo );
CTime tm( year,month,day,hour,min,sec );
return tm.GetTime();
}

void getUTCTime( time_t ltime,PTime *ptime )
{
CTime tm = CTime(ltime);
struct tm utc;
tm.GetGmtTm( &utc );
ptime->SetHour(utc.tm_hour);
ptime->SetMinute(utc.tm_min);
ptime->SetSecond(utc.tm_sec);

ptime->SetDay(utc.tm_mday);
ptime->SetMonth((utc.tm_mon) + 1);
ptime->SetYear((utc.tm_year) + 1900);
}

void CAPI_ViewerDlg::OnBnClickedPlay()
{
// TODO: 在此添加控件通知处理程序代码
SetEvent( m_hEventPlay );
}

int CAPI_ViewerDlg::GetCameraInfo( CameraInfo *pInfo )
{
/*CFile file;
CString szFName;
szFName.Format( "CamInfo.dat" );
file.Open( szFName,CFile::modeRead );
file.Read( pInfo,sizeof( CameraInfo ) );
return 0;
*/
char szSystem[MAX_PATH];
int i = 0,code=0;
memset( szSystem,0x00,MAX_PATH );
Camera *pCam = NULL;
try
{
if( loggedInSys )
delete loggedInSys;
loggedInSys = NULL;

if( strlen(pInfo->smIP) <= 0 )
wsprintf( szSystem,"%s:%s@pelcosystem://","admin","admin" );
else
wsprintf( szSystem,"%s:%s@pelcosystem://%s:%d","admin","admin",pInfo->smIP,pInfo->smPort );
loggedInSys = new System( szSystem );
wsprintf( pInfo->smIP,"%s",loggedInSys->GetIp() );
pInfo->smPort = loggedInSys->GetPort();
DeviceCollection deviceCollection = loggedInSys->GetDeviceCollection();
for( i=0,deviceCollection.Reset();deviceCollection.MoveNext(); )
{
Device device = deviceCollection.Current();
if( device.GetDeviceType() != CAMERA )
continue;
wsprintf( pInfo->item[i].udn,"%s",device.GetUDN() );
wsprintf( pInfo->item[i].name,"%s",device.GetFriendlyName() );
wsprintf( pInfo->item[i].name,"%s",device.GetModelName() );
wsprintf( pInfo->item[i].url,"%s",device.GetIp() );
pInfo->item[i].nvr.port = device.GetPort();
pCam = new Camera( device );
m_cam.insert( PAIR( pInfo->item[i].udn,pCam ) );
i++;
}
pInfo->total = i;
if( loggedInSys )
delete loggedInSys;
code = 0;
}
catch( int &er )
{
code = er;
}
catch( Exception ex )
{
code = ex.Error();
}
catch( ... )
{
code = 99;
}
return code;
}

void CAPI_ViewerDlg::OnBnClickedBtnGet()
{
// TODO: 在此添加控件通知处理程序代码
if( !this->IsValide() )
return;
CString szInfo,szTmp;
memset( &m_CamInfo,0x00,sizeof( CameraInfo ) );
GetCameraInfo( &m_CamInfo );
for( int i=0;i 0 )
{
m_boxCam.SetCurSel(0);
szInfo.Format( "%s",m_CamInfo.item[0].url );
SetDlgItemText( IDC_CAMIP,szInfo );
szTmp.Format( "%d",m_CamInfo.item[0].nvr.port );
SetDlgItemText( IDC_CAMPORT,szTmp );
//SetDlgItemText( IDC_NVRIP,m_CamInfo.item[0].nvr.url );
//szInfo.Format( "%d",m_CamInfo.item[0].nvr.port );
//SetDlgItemText( IDC_NVRPORT,szInfo );
SetDlgItemText( IDC_CAMUUID,m_CamInfo.item[0].udn );
}
}

void CAPI_ViewerDlg::OnCbnSelchangeComboCam()
{
// TODO: 在此添加控件通知处理程序代码
int pos = m_boxCam.GetCurSel();
CString szInfo,szTmp;
szInfo.Format( "%s",m_CamInfo.item[pos].url );
SetDlgItemText( IDC_CAMIP,szInfo );
szTmp.Format( "%d",m_CamInfo.item[pos].nvr.port );
SetDlgItemText( IDC_CAMPORT,szTmp );
//SetDlgItemText( IDC_NVRIP,m_CamInfo.item[pos].nvr.url );
//szInfo.Format( "%d",m_CamInfo.item[pos].nvr.port );
//SetDlgItemText( IDC_NVRPORT,szInfo );
SetDlgItemText( IDC_CAMUUID,m_CamInfo.item[pos].udn );
}

void CAPI_ViewerDlg::OnBnClickedPlay3()
{
// TODO: 在此添加控件通知处理程序代码
GetDlgItemText(IDC_CAMIP,CamIP,15);
GetDlgItemText(IDC_CAMNUM,CamNum,2);
GetDlgItemText(IDC_CAMPORT,CamPort,6);
GetDlgItemText(IDC_STARTTIME1,StartTime,20);
GetDlgItemText(IDC_ENDTIME,EndTime,20);
GetDlgItemText(IDC_NVRIP,NvrIP,15);
GetDlgItemText(IDC_NVRNUM,NvrNum,2);
GetDlgItemText(IDC_NVRPORT,NvrPort,6);
GetDlgItemText(IDC_CAMUUID,CamUuid,50);
char lIP[50] = "rtp://192.168.0.101:7102";
OnBnClickedStop2();
Camera *pcam;
multimap< CString,Camera *>::iterator theIterator;
theIterator = m_cam.find( CamUuid );
pcam = (*theIterator).second;
switch (m_Radio){
case 2:
//如果码流被暂停,则恢复
try
{
m_pStream2 = new Stream( *pcam );
StreamConfiguration config = m_pStream2->GetConfiguration();

config.VideoFormat = kSTREAM_FORMAT_MPEG4_H264;

m_pStream2->SetConfiguration(config);
m_pStream2->AddOverlay( *m_pTimestampOverlay );
m_pDisplay2->Show( *m_pStream2 );
m_pStream2->Play( 1.0 );
m_pStream2-GotoLive();
}
catch( Exception ex )
{
AfxMessageBox( ex.Message().c_str() );
}
break;
case 3:
break;
}
//myAPIViewer.DisplayTimestampOverlay(pszSesId,true,&overlay);
}

void CAPI_ViewerDlg::OnBnClickedStop2()
{
// TODO: 在此添加控件通知处理程序代码
if( m_pStream2 == NULL )
return;
m_pStream2->Stop();
delete m_pStream2;
m_pStream2 = NULL;
}

DWORD CAPI_ViewerDlg::Playv(void* pParam)
{
CAPI_ViewerDlg *pthis = (CAPI_ViewerDlg*)pParam;
while( TRUE )
{
WaitForSingleObject( pthis->m_hEventPlay,INFINITE );
if( pthis->m_lExit )
break;
pthis->OnBnClickedPlay3();
}
return 0;
}

void CAPI_ViewerDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
InterlockedExchange( &m_lExit,1 );
SetEvent( m_hEventPlay );
CDialogEx::OnClose();
}

LRESULT CAPI_ViewerDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和/或调用基类
switch( message )
{
case WM_PLAY:
OnBnClickedPlay3();
OnBnClickedPlay();
break;
}
return CDialogEx::WindowProc(message, wParam, lParam);
}

BOOL CAPI_ViewerDlg::IsValide()
{
return TRUE;
}

Hi there,

I did receive the code that you'd sent to Andrew on Monday yesterday. I saw the post on the forums and figured the two were connected. I've already provided the information that I can at this stage; it does appear to be a threading issue when using objects from Pelco SDK on two different threads.

If you know precisely where the crash is occurring (which call specifically in the entire bit you posted), then I can try to trace down in the source what that is calling. That is a bit of a rabbit hole to travel down and I do not think that we need to that. I don't think that is going to matter - the streaming object needs to happen on the same thread as the calling actions objects from the SDK. I say this based on exactly the behavior that was described in the original post: threading doesn't work and not threading works just fine. I've heard of this before.

We prefer to handle support on the forums here so that any future questions that other development partners may have will have access to previous questions in case they are relevant.