|
From: libvidcap c. m. <lib...@li...> - 2007-09-17 18:57:10
|
Revision: 22
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=22&view=rev
Author: bcholew
Date: 2007-09-17 11:57:01 -0700 (Mon, 17 Sep 2007)
Log Message:
-----------
Create a thread for each DirectShowSource so that capture start/stop and source termination does not block the main thread.
Modified Paths:
--------------
trunk/src/directshow/DirectShowSource.cpp
trunk/src/directshow/DirectShowSource.h
Modified: trunk/src/directshow/DirectShowSource.cpp
===================================================================
--- trunk/src/directshow/DirectShowSource.cpp 2007-09-13 19:53:30 UTC (rev 21)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-17 18:57:01 UTC (rev 22)
@@ -51,7 +51,13 @@
pNullRenderer_(0),
pMediaControlIF_(0),
nativeMediaType_(0),
- captureIsSetup_(false)
+ captureIsSetup_(false),
+ eventInitDone_(0),
+ eventStart_(0),
+ eventStop_(0),
+ eventTerminate_(0),
+ sourceThread_(0),
+ sourceThreadID_(0)
{
if ( !dshowMgr_ )
{
@@ -153,8 +159,32 @@
// register filter graph - to monitor for errors during capture
dshowMgr_->registerSrcGraph(src->src_info.identifier, this, pMediaEventIF_);
- return;
+ if ( createEvents() )
+ {
+ log_error("failed creating events for source thread");
+ goto constructionFailure;
+ }
+ // pass instance to thread
+ sourceThread_ = CreateThread(
+ NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)(&DirectShowSource::waitForCmd),
+ this,
+ 0,
+ &sourceThreadID_);
+
+ if ( sourceThread_ != NULL )
+ {
+ // wait for signal from thread that it is ready
+ WaitForSingleObject(eventInitDone_, INFINITE);
+
+ return;
+ }
+
+ log_error("failed spinning source thread (%d)\n",
+ GetLastError());
+
constructionFailure:
if ( pMediaControlIF_ )
@@ -176,8 +206,40 @@
DirectShowSource::~DirectShowSource()
{
- stop();
+ log_info("Signaling source '%s' to terminate...\n",
+ sourceContext_->src_info.description);
+ // signal thread to shutdown
+ if ( !SetEvent(eventTerminate_) )
+ {
+ log_error("failed to signal graph monitor thread to terminate (%d)\n",
+ GetLastError());
+ return;
+ }
+
+ // wait for thread to shutdown
+ DWORD rc = WaitForSingleObject(sourceThread_, INFINITE);
+
+ if ( rc == WAIT_FAILED )
+ {
+ log_error("DirectShowSource: failed waiting for thread to return (%d)\n",
+ GetLastError());
+ }
+
+ log_info("source '%s' has terminated\n",
+ sourceContext_->src_info.description);
+
+ CloseHandle(eventInitDone_);
+ CloseHandle(eventStart_);
+ CloseHandle(eventStop_);
+ CloseHandle(eventTerminate_);
+}
+
+void
+DirectShowSource::terminate()
+{
+ doStop();
+
cleanupCaptureGraphFoo();
if ( nativeMediaType_ )
@@ -201,6 +263,154 @@
dshowMgr_->sourceReleased( getID() );
}
+int
+DirectShowSource::createEvents()
+{
+ // create an event used to signal that the thread has been created
+ eventInitDone_ = CreateEvent(
+ NULL, // default security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is clear
+ NULL // no name
+ );
+
+ if ( eventInitDone_ == NULL)
+ {
+ log_error("DirectShowSource: failed creating initDone event (%d)\n",
+ GetLastError());
+ return -1;
+ }
+
+ // create an event used to signal thread to start capture
+ eventStart_ = CreateEvent(
+ NULL, // default security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is clear
+ NULL // no name
+ );
+
+ if ( eventStart_ == NULL)
+ {
+ log_error("DirectShowSource: failed creating start event (%d)\n",
+ GetLastError());
+ CloseHandle(eventInitDone_);
+ return -1;
+ }
+
+ // create an event used to signal thread to stop capture
+ eventStop_ = CreateEvent(
+ NULL, // default security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is clear
+ NULL // no name
+ );
+
+ if ( eventStop_ == NULL)
+ {
+ log_error("DirectShowSource: failed creating stop event (%d)\n",
+ GetLastError());
+ CloseHandle(eventInitDone_);
+ CloseHandle(eventStart_);
+ return -1;
+ }
+
+ // create an event used to signal thread to terminate
+ eventTerminate_ = CreateEvent(
+ NULL, // default security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is clear
+ NULL // no name
+ );
+
+ if ( eventTerminate_ == NULL)
+ {
+ log_error("DirectShowSource: failed creating terminate event (%d)\n",
+ GetLastError());
+ CloseHandle(eventInitDone_);
+ CloseHandle(eventStart_);
+ CloseHandle(eventStop_);
+ return -1;
+ }
+
+ return 0;
+}
+
+DWORD WINAPI
+DirectShowSource::waitForCmd(LPVOID lpParam)
+{
+ // extract instance
+ DirectShowSource * pSrc = (DirectShowSource *)lpParam;
+
+ // signal to main thread that we are ready for commands
+ if ( !SetEvent(pSrc->eventInitDone_) )
+ {
+ log_error("failed to signal that source thread is ready (%d)\n",
+ GetLastError());
+ return -1;
+ }
+
+ enum { startEventIndex = 0, stopEventIndex,
+ terminateEventIndex };
+
+ size_t numHandles = terminateEventIndex + 1;
+ HANDLE * waitHandles = new HANDLE [numHandles];
+
+ // ...plus something to break-out when a handle must be
+ // added or removed, or when thread must die
+ waitHandles[startEventIndex] = pSrc->eventStart_;
+ waitHandles[stopEventIndex] = pSrc->eventStop_;
+ waitHandles[terminateEventIndex] = pSrc->eventTerminate_;
+
+ while ( true )
+ {
+ // wait until signaled to start or stop capture
+ // OR to terminate
+ DWORD rc = WaitForMultipleObjects(static_cast<DWORD>(numHandles),
+ waitHandles, false, INFINITE);
+
+ // get index of object that signaled
+ unsigned int index = rc - WAIT_OBJECT_0;
+
+ if ( rc == WAIT_FAILED )
+ {
+ log_warn("source wait failed. (0x%x)\n", GetLastError());
+ }
+ else if ( index == startEventIndex )
+ {
+ pSrc->doStart();
+
+ if ( !ResetEvent(pSrc->eventStart_) )
+ {
+ log_error("failed to reset source start event flag."
+ "Terminating.\n");
+ // terminate
+ break;
+ }
+ }
+ else if ( index == stopEventIndex )
+ {
+ pSrc->doStop();
+
+ if ( !ResetEvent(pSrc->eventStop_) )
+ {
+ log_error("failed to reset source stop event flag."
+ "Terminating.\n");
+ // terminate
+ break;
+ }
+ }
+ else if ( index == terminateEventIndex )
+ {
+ pSrc->terminate();
+ break;
+ }
+ }
+
+ delete [] waitHandles;
+
+ return 0;
+}
+
void
DirectShowSource::cleanupCaptureGraphFoo()
{
@@ -342,37 +552,61 @@
int
DirectShowSource::start()
{
- if ( setupCaptureGraphFoo() )
+ // signal to source thread to start capturing
+ if ( !SetEvent(eventStart_) )
+ {
+ log_error("failed to signal source to start (%d)\n",
+ GetLastError());
return -1;
+ }
- HRESULT hr = pMediaControlIF_->Run();
+ return 0;
+}
- if ( FAILED(hr) )
+void
+DirectShowSource::doStart()
+{
+ if ( !setupCaptureGraphFoo() )
{
- log_error("failed to run filter graph for source '%s' (%ul 0x%x)\n",
- sourceContext_->src_info.description, hr, hr);
+ HRESULT hr = pMediaControlIF_->Run();
- return -1;
+ if ( SUCCEEDED(hr) )
+ return;
+ else
+ log_error("failed to run filter graph for source '%s' (%ul 0x%x)\n",
+ sourceContext_->src_info.description, hr, hr);
}
- return 0;
+ // call capture callback - with error status
+ // (vidcap will reset capture_callback)
+ sapi_src_capture_notify(sourceContext_, 0, 0, -1);
}
int
DirectShowSource::stop()
{
+ // signal to source thread to stop capturing
+ if ( !SetEvent(eventStop_) )
+ {
+ log_error("failed to signal source to stop (%d)\n",
+ GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+DirectShowSource::doStop()
+{
if ( captureIsSetup_ )
{
HRESULT hr = pMediaControlIF_->Stop();
if ( FAILED(hr) )
{
log_error("failed to STOP the filter graph (0x%0x)\n", hr);
-
- return -1;
}
}
-
- return 0;
}
int
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-13 19:53:30 UTC (rev 21)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-17 18:57:01 UTC (rev 22)
@@ -53,6 +53,12 @@
}
private:
+ static DWORD WINAPI waitForCmd(LPVOID);
+ void terminate();
+ void doStart();
+ void doStop();
+ int createEvents();
+
int setupCaptureGraphFoo();
void cleanupCaptureGraphFoo();
bool checkFormat(const vidcap_fmt_info * fmtNominal,
@@ -97,6 +103,13 @@
IMediaControl * pMediaControlIF_;
AM_MEDIA_TYPE *nativeMediaType_;
bool captureIsSetup_;
+
+ HANDLE eventInitDone_;
+ HANDLE eventStart_;
+ HANDLE eventStop_;
+ HANDLE eventTerminate_;
+ void * sourceThread_;
+ DWORD sourceThreadID_;
};
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|