|
From: libvidcap c. m. <lib...@li...> - 2007-10-01 16:58:21
|
Revision: 36
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=36&view=rev
Author: bcholew
Date: 2007-10-01 09:58:11 -0700 (Mon, 01 Oct 2007)
Log Message:
-----------
Simplify things: move from one graphMonitor (owned by source manager) monitoring every source, to a graphMonitor per source. No longer need LocklessQueue class. Move processing of graph events from graphMonitor to source.
Modified Paths:
--------------
trunk/src/directshow/DShowSrcManager.cpp
trunk/src/directshow/DShowSrcManager.h
trunk/src/directshow/DirectShowSource.cpp
trunk/src/directshow/DirectShowSource.h
trunk/src/directshow/GraphMonitor.cpp
trunk/src/directshow/GraphMonitor.h
Removed Paths:
-------------
trunk/src/directshow/LocklessQueue.h
Modified: trunk/src/directshow/DShowSrcManager.cpp
===================================================================
--- trunk/src/directshow/DShowSrcManager.cpp 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/DShowSrcManager.cpp 2007-10-01 16:58:11 UTC (rev 36)
@@ -38,18 +38,10 @@
#include "DirectShowSource.h"
DShowSrcManager * DShowSrcManager::instance_ = 0;
-CRITICAL_SECTION DShowSrcManager::sourceDestructionMutex_;
DShowSrcManager::DShowSrcManager()
: numRefs_(0)
{
- // one mutex for all graphMonitors
- InitializeCriticalSection(&sourceDestructionMutex_);
-
- graphMon_ = new GraphMonitor(
- (cancelCallbackFunc)&DShowSrcManager::cancelSrcCaptureCallback,
- this);
-
HRESULT hr = CoInitialize(NULL);
if ( FAILED(hr) )
@@ -60,13 +52,9 @@
DShowSrcManager::~DShowSrcManager()
{
- delete graphMon_;
-
srcGraphList_.erase( srcGraphList_.begin(), srcGraphList_.end() );
CoUninitialize();
-
- DeleteCriticalSection(&sourceDestructionMutex_);
}
DShowSrcManager *
@@ -97,64 +85,6 @@
return devMon_.registerCallback(static_cast<sapi_context *>(sapiCtx));
}
-void
-DShowSrcManager::registerSrcGraph(const char *id, void *src, IMediaEventEx *pME)
-{
- // find appropriate source id in list
- for ( unsigned int i = 0; i < srcGraphList_.size(); i++ )
- {
- // found matching id?
- if ( srcGraphList_[i]->sourceId == id )
- {
- // fill-in relevant info
- srcGraphList_[i]->pSrc = src;
- srcGraphList_[i]->pME = pME;
-
- // request that GraphMonitor monitor the graph for errors
- graphMon_->addGraph(pME);
- }
- }
-}
-
-bool
-DShowSrcManager::cancelSrcCaptureCallback(IMediaEventEx *pME, void *ctx)
-{
- bool ret = false;
- DShowSrcManager *self = static_cast<DShowSrcManager *>(ctx);
-
- // NOTE: A source removal can be detected by both DevMonitor thread,
- // and GraphMonitor thread. This can lead to cancellation of
- // capture callbacks at the same time that the application
- // is attempting to destroy the source.
- //
- // GraphMon -> cancelSrcCaptureCallback (this code) cancels callbacks
- // DevMonitor -> app -> source destructor calls sourceReleased()
- //
- // Grab mutex to prevent concurrent access from this function and
- // sourceReleased()
- EnterCriticalSection(&sourceDestructionMutex_);
-
- // find appropriate source in list
- for ( unsigned int i = 0; i < self->srcGraphList_.size(); i++ )
- {
- // found matching MediaEvent interface?
- if ( self->srcGraphList_[i]->pME == pME )
- {
- // Found source to cancel callbacks for
- DirectShowSource * pSrc =
- static_cast<DirectShowSource *>(self->srcGraphList_[i]->pSrc);
-
- // cancel the source's callback
- pSrc->cancelCallbacks();
- ret = true;
- break;
- }
- }
- LeaveCriticalSection(&sourceDestructionMutex_);
-
- return ret;
-}
-
int
DShowSrcManager::scan(struct sapi_src_list * srcList) const
{
@@ -267,7 +197,6 @@
pSrcGraphContext->sourceId = id;
// these will be filled in later by registerSrcGraph()
- pSrcGraphContext->pME = 0;
pSrcGraphContext->pSrc = 0;
// add source to collection
@@ -279,7 +208,6 @@
void DShowSrcManager::sourceReleased(const char *id)
{
// NOTE: see note in function cancelSrcCaptureCallback()
- EnterCriticalSection(&sourceDestructionMutex_);
// find appropriate source id in list
for ( unsigned int i = 0; i < srcGraphList_.size(); i++ )
@@ -295,17 +223,13 @@
srcGraphList_.erase( srcGraphList_.begin() + i );
// request that GraphMonitor stop monitoring the graph for errors
- graphMon_->removeGraph(pSrcGraphContext->pME);
delete pSrcGraphContext;
- LeaveCriticalSection(&sourceDestructionMutex_);
return;
}
}
- LeaveCriticalSection(&sourceDestructionMutex_);
-
log_warn("couldn't find source '%s' to release\n", id);
}
@@ -393,8 +317,6 @@
return false;
}
-///// Private functions /////
-
void
DShowSrcManager::sprintDeviceInfo(IMoniker * pM, IBindCtx * pbc,
char* idBuff, char *descBuff, int buffsSize) const
Modified: trunk/src/directshow/DShowSrcManager.h
===================================================================
--- trunk/src/directshow/DShowSrcManager.h 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/DShowSrcManager.h 2007-10-01 16:58:11 UTC (rev 36)
@@ -27,7 +27,6 @@
#include <vector>
#include "DevMonitor.h"
-#include "GraphMonitor.h"
class DShowSrcManager
{
@@ -43,13 +42,6 @@
// for device event notifications (additions and removals)
int registerNotifyCallback(void *);
- // to monitor for graph errors during capture
- void registerSrcGraph(const char *, void *, IMediaEventEx *);
-
- // graphMon_ callback to request capture abort
- typedef bool (*cancelCallbackFunc)(IMediaEventEx *, void *);
- static bool cancelSrcCaptureCallback(IMediaEventEx *, void *);
-
bool getJustCapDevice(const char *devLongName,
IBindCtx **ppBindCtx,
IMoniker **ppMoniker) const;
@@ -62,23 +54,16 @@
int numRefs_;
DevMonitor devMon_;
- GraphMonitor *graphMon_;
struct srcGraphContext
{
- IMediaEventEx * pME;
void * pSrc;
const char * sourceId;
};
- // list of acquired sources, their filter graphs, and IDs
+ // list of acquired sources and IDs
std::vector<srcGraphContext *> srcGraphList_;
- // prevent DevMonitor -> app -> src destructor from destroying
- // source while GraphMon -> cancelSrcCaptureCallback
- // is in the midst of cancelling callbacks
- static CRITICAL_SECTION sourceDestructionMutex_;
-
private:
IPin * getOutPin( IBaseFilter *, int) const;
HRESULT getPin( IBaseFilter *, PIN_DIRECTION, int, IPin **) const;
Modified: trunk/src/directshow/DirectShowSource.cpp
===================================================================
--- trunk/src/directshow/DirectShowSource.cpp 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-10-01 16:58:11 UTC (rev 36)
@@ -29,7 +29,6 @@
#include <atlbase.h>
#include <qedit.h>
#include <comutil.h>
-#include <DShow.h>
#include <vidcap/converters.h>
#include "hotlist.h"
@@ -41,6 +40,7 @@
DShowSrcManager *mgr)
: sourceContext_(src),
dshowMgr_(mgr),
+ graphMon_(0),
pSource_(0),
pCapGraphBuilder_(0),
pStreamConfig_(0),
@@ -51,6 +51,7 @@
pNullRenderer_(0),
pMediaControlIF_(0),
nativeMediaType_(0),
+ graphHandle_(0),
graphIsSetup_(false),
eventInitDone_(0),
eventStart_(0),
@@ -107,8 +108,17 @@
if ( createCapGraphFoo() )
goto constructionFailure;
- // register filter graph - to monitor for errors during capture
- dshowMgr_->registerSrcGraph(src->src_info.identifier, this, pMediaEventIF_);
+ try
+ {
+ graphMon_ = new GraphMonitor(graphHandle_,
+ (graphEventCBFunc)&DirectShowSource::processGraphEvent,
+ this);
+ }
+ catch (std::runtime_error &)
+ {
+ log_error("failed to create graph monitor for source\n");
+ goto constructionFailure;
+ }
if ( createEvents() )
{
@@ -308,6 +318,13 @@
return -1;
}
+ hr = pMediaEventIF_->GetEventHandle((OAEVENT *)&graphHandle_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed to get handle for filter graph\n");
+ return -1;
+ }
+
return 0;
}
@@ -337,6 +354,9 @@
if ( pCapGraphBuilder_ )
pCapGraphBuilder_->Release();
+
+ if ( graphHandle_ )
+ CloseHandle(graphHandle_);
}
int
@@ -434,7 +454,7 @@
DirectShowSource::waitForCmd(LPVOID lpParam)
{
// extract instance
- DirectShowSource * pSrc = (DirectShowSource *)lpParam;
+ DirectShowSource * pSrc = static_cast<DirectShowSource *>(lpParam);
// signal to main thread that we are ready for commands
if ( !SetEvent(pSrc->eventInitDone_) )
@@ -1196,3 +1216,306 @@
return 0;
}
+
+// Direct Show filter graph has signaled an event
+// Device may have been removed
+// Error may have occurred
+void
+DirectShowSource::processGraphEvent(void *context)
+{
+ DirectShowSource * pSrc = static_cast<DirectShowSource *>(context);
+
+ HRESULT hr;
+ long evCode, param1, param2;
+ hr = pSrc->pMediaEventIF_->GetEvent(&evCode, ¶m1, ¶m2, 0);
+
+ if ( SUCCEEDED(hr) )
+ {
+ // Event codes taken from:
+ // http://msdn2.microsoft.com/en-us/library/ms783649.aspx
+ // Embedded reference not used:
+ // http://msdn2.microsoft.com/en-us/library/aa921722.aspx
+
+ std::string str;
+
+ switch(evCode)
+ {
+ case EC_DEVICE_LOST:
+ if ( (int)param2 == 0 )
+ {
+ str.assign("EC_DEVICE_LOST\n");
+ log_info("device removal detected\n");
+
+ // shutdown capture
+ pSrc->cancelCallbacks();
+ }
+ else
+ {
+ str.assign("EC_DEVICE_LOST - (device re-inserted)\n");
+ }
+ break;
+
+ case EC_ACTIVATE:
+ str.assign("EC_ACTIVATE\n");
+ break;
+
+/* case EC_BANDWIDTHCHANGE:
+ str.assign("EC_BANDWIDTHCHANGE\n");
+ break;
+*/
+ case EC_BUFFERING_DATA:
+ str.assign("EC_BUFFERING_DATA\n");
+ break;
+
+ case EC_BUILT:
+ str.assign("EC_BUILT\n");
+ break;
+
+ case EC_CLOCK_CHANGED:
+ str.assign("EC_CLOCK_CHANGED\n");
+ break;
+
+ case EC_CLOCK_UNSET:
+ str.assign("EC_CLOCK_UNSET\n");
+ break;
+
+ case EC_CODECAPI_EVENT:
+ str.assign("EC_CODECAPI_EVENT\n");
+ break;
+
+ case EC_COMPLETE:
+ str.assign("EC_COMPLETE\n");
+ break;
+
+/* case EC_CONTENTPROPERTY_CHANGED:
+ str.assign("EC_CONTENTPROPERTY_CHANGED\n");
+ break;
+*/
+ case EC_DISPLAY_CHANGED:
+ str.assign("EC_DISPLAY_CHANGED\n");
+ break;
+
+ case EC_END_OF_SEGMENT:
+ str.assign("EC_END_OF_SEGMENT\n");
+ break;
+
+/* case EC_EOS_SOON:
+ str.assign("EC_EOS_SOON\n");
+ break;
+*/
+ case EC_ERROR_STILLPLAYING:
+ str.assign("EC_ERROR_STILLPLAYING\n");
+ break;
+
+ case EC_ERRORABORT:
+ str.assign("EC_ERRORABORT\n");
+
+ log_info("graph monitor stopping capture...\n");
+
+ // shutdown capture
+ pSrc->cancelCallbacks();
+
+ break;
+
+/* case EC_ERRORABORTEX:
+ str.assign("EC_ERRORABORTEX\n");
+ break;
+*/
+ case EC_EXTDEVICE_MODE_CHANGE:
+ str.assign("EC_EXTDEVICE_MODE_CHANGE\n");
+ break;
+
+/* case EC_FILE_CLOSED:
+ str.assign("EC_FILE_CLOSED\n");
+ break;
+*/
+ case EC_FULLSCREEN_LOST:
+ str.assign("EC_FULLSCREEN_LOST\n");
+ break;
+
+ case EC_GRAPH_CHANGED:
+ str.assign("EC_GRAPH_CHANGED\n");
+ break;
+
+ case EC_LENGTH_CHANGED:
+ str.assign("EC_LENGTH_CHANGED\n");
+ break;
+
+/* case EC_LOADSTATUS:
+ str.assign("EC_LOADSTATUS\n");
+ break;
+*/
+/* case EC_MARKER_HIT:
+ str.assign("EC_MARKER_HIT\n");
+ break;
+*/
+ case EC_NEED_RESTART:
+ str.assign("EC_NEED_RESTART\n");
+ break;
+
+/* case EC_NEW_PIN:
+ str.assign("EC_NEW_PIN\n");
+ break;
+*/
+ case EC_NOTIFY_WINDOW:
+ str.assign("EC_NOTIFY_WINDOW\n");
+ break;
+
+ case EC_OLE_EVENT:
+ str.assign("EC_OLE_EVENT\n");
+ break;
+
+ case EC_OPENING_FILE:
+ str.assign("EC_OPENING_FILE\n");
+ break;
+
+ case EC_PALETTE_CHANGED:
+ str.assign("EC_PALETTE_CHANGED\n");
+ break;
+
+ case EC_PAUSED:
+ str.assign("EC_PAUSED\n");
+ break;
+
+/* case EC_PLEASE_REOPEN:
+ str.assign("EC_PLEASE_REOPEN\n");
+ break;
+*/
+ case EC_PREPROCESS_COMPLETE:
+ str.assign("EC_PREPROCESS_COMPLETE\n");
+ break;
+
+/* case EC_PROCESSING_LATENCY:
+ str.assign("EC_PROCESSING_LATENCY\n");
+ break;
+*/
+ case EC_QUALITY_CHANGE:
+ str.assign("EC_QUALITY_CHANGE\n");
+ break;
+
+/* case EC_RENDER_FINISHED:
+ str.assign("EC_RENDER_FINISHED\n");
+ break;
+*/
+ case EC_REPAINT:
+ str.assign("EC_REPAINT\n");
+ break;
+
+/* case EC_SAMPLE_LATENCY:
+ str.assign("EC_SAMPLE_LATENCY\n");
+ break;
+
+ case EC_SAMPLE_NEEDED:
+ str.assign("EC_SAMPLE_NEEDED\n");
+ break;
+
+ case EC_SCRUB_TIME:
+ str.assign("EC_SCRUB_TIME\n");
+ break;
+*/
+ case EC_SEGMENT_STARTED:
+ str.assign("EC_SEGMENT_STARTED\n");
+ break;
+
+ case EC_SHUTTING_DOWN:
+ str.assign("EC_SHUTTING_DOWN\n");
+ break;
+
+ case EC_SNDDEV_IN_ERROR:
+ str.assign("EC_SNDDEV_IN_ERROR\n");
+ break;
+
+ case EC_SNDDEV_OUT_ERROR:
+ str.assign("EC_SNDDEV_OUT_ERROR\n");
+ break;
+
+ case EC_STARVATION:
+ str.assign("EC_STARVATION\n");
+ break;
+
+ case EC_STATE_CHANGE:
+ str.assign("EC_STATE_CHANGE\n");
+ break;
+
+/* case EC_STATUS:
+ str.assign("EC_STATUS\n");
+ break;
+*/
+ case EC_STEP_COMPLETE:
+ str.assign("EC_STEP_COMPLETE\n");
+ break;
+
+ case EC_STREAM_CONTROL_STARTED:
+ str.assign("EC_STREAM_CONTROL_STARTED\n");
+ break;
+
+ case EC_STREAM_CONTROL_STOPPED:
+ str.assign("EC_STREAM_CONTROL_STOPPED\n");
+ break;
+
+ case EC_STREAM_ERROR_STILLPLAYING:
+ str.assign("EC_STREAM_ERROR_STILLPLAYING\n");
+ break;
+
+ case EC_STREAM_ERROR_STOPPED:
+ str.assign("EC_STREAM_ERROR_STOPPED\n");
+ break;
+
+ case EC_TIMECODE_AVAILABLE:
+ str.assign("EC_TIMECODE_AVAILABLE\n");
+ break;
+
+ case EC_UNBUILT:
+ str.assign("EC_UNBUILT\n");
+ break;
+
+ case EC_USERABORT:
+ str.assign("EC_USERABORT\n");
+ break;
+
+ case EC_VIDEO_SIZE_CHANGED:
+ str.assign("EC_VIDEO_SIZE_CHANGED\n");
+ break;
+
+/* case EC_VIDEOFRAMEREADY:
+ str.assign("EC_VIDEOFRAMEREADY\n");
+ break;
+*/
+ case EC_VMR_RECONNECTION_FAILED:
+ str.assign("EC_VMR_RECONNECTION_FAILED\n");
+ break;
+
+ case EC_VMR_RENDERDEVICE_SET:
+ str.assign("EC_VMR_RENDERDEVICE_SET\n");
+ break;
+
+ case EC_VMR_SURFACE_FLIPPED:
+ str.assign("EC_VMR_SURFACE_FLIPPED\n");
+ break;
+
+ case EC_WINDOW_DESTROYED:
+ str.assign("EC_WINDOW_DESTROYED\n");
+ break;
+
+ case EC_WMT_EVENT:
+ str.assign("EC_WMT_EVENT\n");
+ break;
+
+ case EC_WMT_INDEX_EVENT:
+ str.assign("EC_WMT_INDEX_EVENT\n");
+ break;
+
+ default:
+ str.assign("unknown graph event code (%ld)\n", evCode);
+ break;
+ }
+
+ log_info("graph processed event: %s", str.c_str());
+
+ hr = pSrc->pMediaEventIF_->FreeEventParams(evCode, param1, param2);
+ }
+ else
+ {
+ log_error("failed getting event for a graph\n");
+ }
+}
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/DirectShowSource.h 2007-10-01 16:58:11 UTC (rev 36)
@@ -28,9 +28,11 @@
#include <stdexcept>
#include <atlbase.h>
#include <qedit.h>
+#include <DShow.h>
#include "DShowSrcManager.h"
#include "sapi_context.h"
+#include "GraphMonitor.h"
class DirectShowSource : public ISampleGrabberCB
{
@@ -46,6 +48,9 @@
int validateFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative) const;
+ typedef void (*graphEventCBFunc)(void *);
+ static void processGraphEvent(void *);
+
const char * getID() const
{
return sourceContext_->src_info.identifier;
@@ -94,6 +99,8 @@
private:
struct sapi_src_context * sourceContext_;
DShowSrcManager * dshowMgr_;
+ GraphMonitor *graphMon_;
+
IBaseFilter * pSource_;
ICaptureGraphBuilder2 *pCapGraphBuilder_;
IAMStreamConfig * pStreamConfig_;
@@ -104,6 +111,7 @@
IBaseFilter * pNullRenderer_;
IMediaControl * pMediaControlIF_;
AM_MEDIA_TYPE *nativeMediaType_;
+ HANDLE *graphHandle_;
bool graphIsSetup_;
HANDLE eventInitDone_;
Modified: trunk/src/directshow/GraphMonitor.cpp
===================================================================
--- trunk/src/directshow/GraphMonitor.cpp 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/GraphMonitor.cpp 2007-10-01 16:58:11 UTC (rev 36)
@@ -25,33 +25,20 @@
// This thread will monitor a DirectShow filter graph for a capture device.
// If the device is removed or encounters an error, the capture callback will
// be called with a special status code, indicating it's the last callback
-#include <sstream>
+
+#include <stdexcept>
#include "GraphMonitor.h"
#include "logging.h"
-GraphMonitor::GraphMonitor(cancelCallbackFunc cb, void * parentCtx)
- : cancelCBFunc_(cb),
+GraphMonitor::GraphMonitor(HANDLE *graphHandle,
+ graphEventCBFunc cb, void * parentCtx)
+ : graphHandle_(graphHandle),
+ processGraphEvent_(cb),
parentContext_(parentCtx),
graphMonitorThread_(0),
graphMonitorThreadID_(0)
{
// create an event used to wake up thread
- // when graphs must be added or removed
- // FIXME: how does one free these events?
- listEvent_ = CreateEvent(
- NULL, // default security attributes
- TRUE, // manual-reset event
- FALSE, // initial state is clear
- NULL // no name
- );
-
- if ( listEvent_ == NULL)
- {
- log_error("CreateEvent failed (%d)\n", GetLastError());
- throw std::runtime_error("GraphMonitor: failed creating list event");
- }
-
- // create an event used to wake up thread
// when thread must terminate
terminateEvent_ = CreateEvent(
NULL, // default security attributes
@@ -84,7 +71,7 @@
graphMonitorThread_ = CreateThread(
NULL,
0,
- (LPTHREAD_START_ROUTINE)(&GraphMonitor::monitorGraphs),
+ (LPTHREAD_START_ROUTINE)(&GraphMonitor::monitorGraph),
this,
0,
&graphMonitorThreadID_);
@@ -123,148 +110,11 @@
GetLastError());
}
- for ( unsigned int i = 0; i < graphContextList_.size(); i++ )
- {
- graphContextList_.erase( graphContextList_.begin() + i );
- }
-
- const graphListEvent * pListEvent;
- while ( graphListEventQueue_.dequeue(&pListEvent) )
- {
- delete pListEvent;
- }
-
log_info("graph monitor thread destroyed\n");
}
-// graph removals and additions dequeued by graph monitor thread
-void
-GraphMonitor::processListEvent()
-{
- const graphListEvent * pListEvent;
-
- // take event off queue
- // either add or remove graph
- if ( !graphListEventQueue_.dequeue(&pListEvent) )
- {
- log_info("failed to dequeue a graph list event\n");
- return;
- }
-
- // get the Media Event interface
- IMediaEventEx *pME = pListEvent->graph;
-
- switch ( pListEvent->eventType )
- {
- case graphListEvent::add:
- {
- // get event handle, on which we can wait
- HANDLE *hEvent = new HANDLE;
- HRESULT hr = pME->GetEventHandle((OAEVENT *)&hEvent);
- if ( FAILED(hr) )
- {
- log_warn("failed to get handle for filter graph\n");
- break;
- }
-
- // create a context with all relevant info
- graphContext *pGraphContext = new graphContext();
- pGraphContext->pME = pME;
- pGraphContext->waitHandle = hEvent;
-
- // add graph context to list
- log_info("adding device #%d to graphMonitor list\n",
- graphContextList_.size());
-
- graphContextList_.push_back(pGraphContext);
- }
- break;
-
- case graphListEvent::remove:
- {
- // remove from vector
- int i = findContext(pME);
- if ( i >= 0 )
- {
- graphContext *pGraphContext = graphContextList_[i];
-
- graphContextList_.erase( graphContextList_.begin() + i );
-
- std::ostringstream strm;
- strm << "removed device #" << i <<
- " from graphMonitor list";
-
- if ( (unsigned int)i < graphContextList_.size() )
- strm << " (device numbers " << i + 1 <<
- "+ will slide down 1 slot)";
-
- log_info("%s\n", strm.str().c_str());
-
- delete pGraphContext;
-
- //FIXME: how does one free the waitHandle?
- return;
- }
- log_warn("failed to find MediaEvent interface to remove\n");
- }
- break;
-
- default:
- log_error("got a graph list UNKNOWN event\n");
- break;
- }
-
- delete pListEvent;
-}
-
-// graph addition enqueued by main thread
-void
-GraphMonitor::addGraph(IMediaEventEx *pME)
-{
- graphListEvent * pListEvent = new graphListEvent;
-
- pListEvent->eventType = graphListEvent::add;
- pListEvent->graph = pME;
-
- // queue-up graph to be added,
- if ( !graphListEventQueue_.enqueue(pListEvent) )
- {
- log_warn("failed to add graph to event queue\n");
- }
-
- // signal thread to wake up and add it
- if ( !SetEvent(listEvent_) )
- {
- log_error("failed to signal graph monitor thread of new graph (%d)\n",
- GetLastError());
- }
-}
-
-// graph removal enqueued by main thread
-void
-GraphMonitor::removeGraph(IMediaEventEx *pME)
-{
- graphListEvent * pListEvent = new graphListEvent;
-
- pListEvent->eventType = graphListEvent::remove;
- pListEvent->graph = pME;
-
- // queue-up graph to be removed,
- if ( !graphListEventQueue_.enqueue(pListEvent) )
- {
- log_warn("failed to add graph to the event queue\n");
- }
-
- // signal thread to wake up and remove it
- if ( !SetEvent(listEvent_) )
- {
- log_error("failed to signal graph monitor thread to "
- "remove graph (%d)\n", GetLastError());
- }
-}
-
DWORD WINAPI
-GraphMonitor::monitorGraphs(LPVOID lpParam)
+GraphMonitor::monitorGraph(LPVOID lpParam)
{
// extract instance
GraphMonitor * pGraphMon = (GraphMonitor *)lpParam;
@@ -277,69 +127,41 @@
return -1;
}
- while ( true )
- {
- // Setup array of handles to wait on...
- enum { terminateIndex = 0, listEventIndex, graphEventIndex_0 };
- size_t numHandles = pGraphMon->graphContextList_.size() +
- graphEventIndex_0;
- HANDLE * waitHandles = new HANDLE [numHandles];
+ // Setup array of handles to wait on...
+ enum { terminateIndex = 0, graphEventIndex };
+ const size_t numHandles = graphEventIndex + 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[listEventIndex] = pGraphMon->listEvent_;
- waitHandles[terminateIndex] = pGraphMon->terminateEvent_;
+ waitHandles[terminateIndex] = pGraphMon->terminateEvent_;
- // complete the array of handles
- for ( unsigned int i = 0; i < pGraphMon->graphContextList_.size(); i++ )
- {
- waitHandles[i + graphEventIndex_0] =
- pGraphMon->graphContextList_[i]->waitHandle;
- }
+ // complete the array of handles
+ waitHandles[graphEventIndex] = pGraphMon->graphHandle_;
- // wait until a graph signals an event OR
- // a graph is added or removed OR
+ while ( true )
+ {
+ // wait until the graph signals an event OR
// the thread must die
DWORD rc = WaitForMultipleObjects(static_cast<DWORD>(numHandles),
waitHandles, false, INFINITE);
- delete [] waitHandles;
// get index of object that signaled
unsigned int index = rc - WAIT_OBJECT_0;
- // get index of graph that MAY have had an event
- unsigned int handleIndex = index - graphEventIndex_0;
-
if ( rc == WAIT_FAILED )
{
log_warn("graph monitor wait failed. (0x%x)\n", GetLastError());
}
- else if ( index == listEventIndex )
- {
- // process addition or removal of a graph
- pGraphMon->processListEvent();
- if ( !ResetEvent(pGraphMon->listEvent_) )
- {
- log_error("failed to reset graph monitor eventFlag."
- "Terminating.\n");
-
- // terminate
- break;
- }
- }
else if ( index == terminateIndex )
{
// terminate
break;
}
- // check if it was a filter graph handle that signaled
- else if ( 0 <= handleIndex &&
- handleIndex < pGraphMon->graphContextList_.size() )
+ // check if it was the filter graph handle that signaled
+ else if ( index == graphEventIndex )
{
- // handle event of appropriate graph
- pGraphMon->processGraphEvent(
- pGraphMon->graphContextList_[handleIndex]->pME);
+ // have parent handle the graph event
+ pGraphMon->processGraphEvent_(pGraphMon->parentContext_);
}
else
{
@@ -347,325 +169,7 @@
}
}
+ delete [] waitHandles;
+
return 0;
}
-
-// Direct Show filter graph has signaled an event
-// Device may have been removed
-// Error may have occurred
-void
-GraphMonitor::processGraphEvent(IMediaEventEx *pME)
-{
- HRESULT hr;
- long evCode, param1, param2;
- hr = pME->GetEvent(&evCode, ¶m1, ¶m2, 0);
-
- if ( SUCCEEDED(hr) )
- {
- // Event codes taken from:
- // http://msdn2.microsoft.com/en-us/library/ms783649.aspx
- // Embedded reference not used:
- // http://msdn2.microsoft.com/en-us/library/aa921722.aspx
-
- std::string str;
-
- switch(evCode)
- {
- case EC_DEVICE_LOST:
- if ( (int)param2 == 0 )
- {
- str.assign("EC_DEVICE_LOST\n");
- log_info("device removal detected\n");
-
- // shutdown capture
- if ( !cancelCBFunc_(pME, parentContext_) )
- log_warn("failed to find graph for final callback\n");
- }
- else
- {
- str.assign("EC_DEVICE_LOST - (device re-inserted)\n");
- }
- break;
-
- case EC_ACTIVATE:
- str.assign("EC_ACTIVATE\n");
- break;
-
-/* case EC_BANDWIDTHCHANGE:
- str.assign("EC_BANDWIDTHCHANGE\n");
- break;
-*/
- case EC_BUFFERING_DATA:
- str.assign("EC_BUFFERING_DATA\n");
- break;
-
- case EC_BUILT:
- str.assign("EC_BUILT\n");
- break;
-
- case EC_CLOCK_CHANGED:
- str.assign("EC_CLOCK_CHANGED\n");
- break;
-
- case EC_CLOCK_UNSET:
- str.assign("EC_CLOCK_UNSET\n");
- break;
-
- case EC_CODECAPI_EVENT:
- str.assign("EC_CODECAPI_EVENT\n");
- break;
-
- case EC_COMPLETE:
- str.assign("EC_COMPLETE\n");
- break;
-
-/* case EC_CONTENTPROPERTY_CHANGED:
- str.assign("EC_CONTENTPROPERTY_CHANGED\n");
- break;
-*/
- case EC_DISPLAY_CHANGED:
- str.assign("EC_DISPLAY_CHANGED\n");
- break;
-
- case EC_END_OF_SEGMENT:
- str.assign("EC_END_OF_SEGMENT\n");
- break;
-
-/* case EC_EOS_SOON:
- str.assign("EC_EOS_SOON\n");
- break;
-*/
- case EC_ERROR_STILLPLAYING:
- str.assign("EC_ERROR_STILLPLAYING\n");
- break;
-
- case EC_ERRORABORT:
- str.assign("EC_ERRORABORT\n");
-
- log_info("graph monitor stopping capture...\n");
-
- // shutdown capture
- if ( !cancelCBFunc_(pME, parentContext_) )
- log_warn("failed to find graph for the final callback\n");
-
- break;
-
-/* case EC_ERRORABORTEX:
- str.assign("EC_ERRORABORTEX\n");
- break;
-*/
- case EC_EXTDEVICE_MODE_CHANGE:
- str.assign("EC_EXTDEVICE_MODE_CHANGE\n");
- break;
-
-/* case EC_FILE_CLOSED:
- str.assign("EC_FILE_CLOSED\n");
- break;
-*/
- case EC_FULLSCREEN_LOST:
- str.assign("EC_FULLSCREEN_LOST\n");
- break;
-
- case EC_GRAPH_CHANGED:
- str.assign("EC_GRAPH_CHANGED\n");
- break;
-
- case EC_LENGTH_CHANGED:
- str.assign("EC_LENGTH_CHANGED\n");
- break;
-
-/* case EC_LOADSTATUS:
- str.assign("EC_LOADSTATUS\n");
- break;
-*/
-/* case EC_MARKER_HIT:
- str.assign("EC_MARKER_HIT\n");
- break;
-*/
- case EC_NEED_RESTART:
- str.assign("EC_NEED_RESTART\n");
- break;
-
-/* case EC_NEW_PIN:
- str.assign("EC_NEW_PIN\n");
- break;
-*/
- case EC_NOTIFY_WINDOW:
- str.assign("EC_NOTIFY_WINDOW\n");
- break;
-
- case EC_OLE_EVENT:
- str.assign("EC_OLE_EVENT\n");
- break;
-
- case EC_OPENING_FILE:
- str.assign("EC_OPENING_FILE\n");
- break;
-
- case EC_PALETTE_CHANGED:
- str.assign("EC_PALETTE_CHANGED\n");
- break;
-
- case EC_PAUSED:
- str.assign("EC_PAUSED\n");
- break;
-
-/* case EC_PLEASE_REOPEN:
- str.assign("EC_PLEASE_REOPEN\n");
- break;
-*/
- case EC_PREPROCESS_COMPLETE:
- str.assign("EC_PREPROCESS_COMPLETE\n");
- break;
-
-/* case EC_PROCESSING_LATENCY:
- str.assign("EC_PROCESSING_LATENCY\n");
- break;
-*/
- case EC_QUALITY_CHANGE:
- str.assign("EC_QUALITY_CHANGE\n");
- break;
-
-/* case EC_RENDER_FINISHED:
- str.assign("EC_RENDER_FINISHED\n");
- break;
-*/
- case EC_REPAINT:
- str.assign("EC_REPAINT\n");
- break;
-
-/* case EC_SAMPLE_LATENCY:
- str.assign("EC_SAMPLE_LATENCY\n");
- break;
-
- case EC_SAMPLE_NEEDED:
- str.assign("EC_SAMPLE_NEEDED\n");
- break;
-
- case EC_SCRUB_TIME:
- str.assign("EC_SCRUB_TIME\n");
- break;
-*/
- case EC_SEGMENT_STARTED:
- str.assign("EC_SEGMENT_STARTED\n");
- break;
-
- case EC_SHUTTING_DOWN:
- str.assign("EC_SHUTTING_DOWN\n");
- break;
-
- case EC_SNDDEV_IN_ERROR:
- str.assign("EC_SNDDEV_IN_ERROR\n");
- break;
-
- case EC_SNDDEV_OUT_ERROR:
- str.assign("EC_SNDDEV_OUT_ERROR\n");
- break;
-
- case EC_STARVATION:
- str.assign("EC_STARVATION\n");
- break;
-
- case EC_STATE_CHANGE:
- str.assign("EC_STATE_CHANGE\n");
- break;
-
-/* case EC_STATUS:
- str.assign("EC_STATUS\n");
- break;
-*/
- case EC_STEP_COMPLETE:
- str.assign("EC_STEP_COMPLETE\n");
- break;
-
- case EC_STREAM_CONTROL_STARTED:
- str.assign("EC_STREAM_CONTROL_STARTED\n");
- break;
-
- case EC_STREAM_CONTROL_STOPPED:
- str.assign("EC_STREAM_CONTROL_STOPPED\n");
- break;
-
- case EC_STREAM_ERROR_STILLPLAYING:
- str.assign("EC_STREAM_ERROR_STILLPLAYING\n");
- break;
-
- case EC_STREAM_ERROR_STOPPED:
- str.assign("EC_STREAM_ERROR_STOPPED\n");
- break;
-
- case EC_TIMECODE_AVAILABLE:
- str.assign("EC_TIMECODE_AVAILABLE\n");
- break;
-
- case EC_UNBUILT:
- str.assign("EC_UNBUILT\n");
- break;
-
- case EC_USERABORT:
- str.assign("EC_USERABORT\n");
- break;
-
- case EC_VIDEO_SIZE_CHANGED:
- str.assign("EC_VIDEO_SIZE_CHANGED\n");
- break;
-
-/* case EC_VIDEOFRAMEREADY:
- str.assign("EC_VIDEOFRAMEREADY\n");
- break;
-*/
- case EC_VMR_RECONNECTION_FAILED:
- str.assign("EC_VMR_RECONNECTION_FAILED\n");
- break;
-
- case EC_VMR_RENDERDEVICE_SET:
- str.assign("EC_VMR_RENDERDEVICE_SET\n");
- break;
-
- case EC_VMR_SURFACE_FLIPPED:
- str.assign("EC_VMR_SURFACE_FLIPPED\n");
- break;
-
- case EC_WINDOW_DESTROYED:
- str.assign("EC_WINDOW_DESTROYED\n");
- break;
-
- case EC_WMT_EVENT:
- str.assign("EC_WMT_EVENT\n");
- break;
-
- case EC_WMT_INDEX_EVENT:
- str.assign("EC_WMT_INDEX_EVENT\n");
- break;
-
- default:
- str.assign("unknown graph event code (%ld)\n", evCode);
- break;
- }
-
- log_info("graph #%d processed event: %s",
- findContext(pME), str.c_str());
-
- hr = pME->FreeEventParams(evCode, param1, param2);
- }
- else
- {
- log_error("failed getting event for a graph\n");
- }
-}
-
-int
-GraphMonitor::findContext(IMediaEventEx *pME)
-{
- for ( unsigned int i = 0; i < graphContextList_.size(); i++ )
- {
- // found matching MediaEvent interface?
- if ( graphContextList_[i]->pME == pME )
- {
- return i;
- }
- }
-
- // failed to find MediaEvent interface
- return -1;
-}
Modified: trunk/src/directshow/GraphMonitor.h
===================================================================
--- trunk/src/directshow/GraphMonitor.h 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/GraphMonitor.h 2007-10-01 16:58:11 UTC (rev 36)
@@ -26,53 +26,27 @@
#define _GRAPHMONITOR_H_
#include <windows.h>
-#include <DShow.h>
-#include <vector>
-#include "LocklessQueue.h"
class GraphMonitor
{
public:
- typedef bool (*cancelCallbackFunc)(IMediaEventEx *, void *);
+ typedef void (*graphEventCBFunc)(void *);
- GraphMonitor(cancelCallbackFunc, void *);
+ GraphMonitor(HANDLE *, graphEventCBFunc, void *);
~GraphMonitor();
- void addGraph(IMediaEventEx *);
- void removeGraph(IMediaEventEx *);
private:
- static DWORD WINAPI monitorGraphs(LPVOID lpParam);
- void processListEvent();
- void processGraphEvent(IMediaEventEx *);
- int findContext(IMediaEventEx *);
+ static DWORD WINAPI monitorGraph(LPVOID lpParam);
private:
+ HANDLE *graphHandle_;
void * parentContext_;
- cancelCallbackFunc cancelCBFunc_;
+ graphEventCBFunc processGraphEvent_;
+
HANDLE initDoneEvent_;
- HANDLE listEvent_;
HANDLE terminateEvent_;
- struct graphContext
- {
- IMediaEventEx * pME;
- HANDLE * waitHandle;
- };
-
- // used to generate array of handles on which to wait
- std::vector<graphContext *> graphContextList_;
-
- struct graphListEvent
- {
- enum graphListEventType { add = 0, remove } eventType;
- IMediaEventEx * graph;
- };
-
- // enqueued by main thread
- // dequeued by graph monitor thread
- LocklessQueue<graphListEvent> graphListEventQueue_;
-
void * graphMonitorThread_;
DWORD graphMonitorThreadID_;
};
Deleted: trunk/src/directshow/LocklessQueue.h
===================================================================
--- trunk/src/directshow/LocklessQueue.h 2007-09-28 21:20:58 UTC (rev 35)
+++ trunk/src/directshow/LocklessQueue.h 2007-10-01 16:58:11 UTC (rev 36)
@@ -1,89 +0,0 @@
-//
-// libvidcap - a cross-platform video capture library
-//
-// Copyright 2007 Wimba, Inc.
-//
-// Contributors:
-// Peter Grayson <jpg...@gm...>
-// Bill Cholewka <bc...@gm...>
-//
-// libvidcap is free software; you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation; either version 2.1 of
-// the License, or (at your option) any later version.
-//
-// libvidcap is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this program. If not, see
-// <http://www.gnu.org/licenses/>.
-//
-
-#ifndef __LOCKLESSQUEUE_H__
-#define __LOCKLESSQUEUE_H__
-
-template<typename T>
-class LocklessQueue
-{
-public:
- LocklessQueue(int size = 512)
- : max_(size),
- head_(0),
- tail_(0)
- {
- pData_ = new const T * [max_];
- };
-
- ~LocklessQueue()
- {
- delete[] pData_;
- };
-
- bool enqueue(const T *buffer)
- {
- // take note of future head value
- unsigned int nextHead = (head_ + 1) % max_;
-
- // safe to push?
- if ( nextHead == tail_ )
- return false;
-
- // push the data
- pData_[head_] = buffer;
-
- // NOW advance the head
- head_ = nextHead;
-
- return true;
- };
-
- bool dequeue(const T **pBuffer)
- {
- if ( head_ == tail_ )
- return false;
-
- // take note of future tail value
- unsigned int next = (tail_ + 1) % max_;
-
- // get data
- *pBuffer = pData_[tail_];
-
- // NOW advance the tail
- tail_ = next;
-
- return true;
- };
-
-private:
- const int max_;
-
- volatile unsigned int head_;
- volatile unsigned int tail_;
-
- const T ** pData_;
-};
-
-#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|