|
From: libvidcap c. m. <lib...@li...> - 2007-09-07 21:19:30
|
Revision: 5
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=5&view=rev
Author: bcholew
Date: 2007-09-07 14:19:26 -0700 (Fri, 07 Sep 2007)
Log Message:
-----------
Implement DirectShow-specific format-validating functionality used at acquisition and bind times. At bind time, we now hold on to the media type for use at capture start time.
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-06 15:39:40 UTC (rev 4)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-07 21:19:26 UTC (rev 5)
@@ -50,6 +50,7 @@
pSampleGrabberIF_(0),
pNullRenderer_(0),
pMediaControlIF_(0),
+ nativeMediaType_(0),
pIntermediateFilter_(0),
intermediateMediaType_(0),
stoppingCapture_(false)
@@ -193,6 +194,9 @@
dshowMgr_->unregisterSrcGraph(pMediaEventIF_);
+ if ( nativeMediaType_ )
+ dshowMgr_->freeMediaType(*nativeMediaType_);
+
// These below were initialized in constructor
pMediaEventIF_->Release();
@@ -574,7 +578,7 @@
}
// Get the appropriate source media type
- AM_MEDIA_TYPE * pAmMediaType = getMediaType(pSourceOutPin_);
+ AM_MEDIA_TYPE * pAmMediaType = nativeMediaType_;
if ( !pAmMediaType )
{
log_error("failed to match media type\n");
@@ -584,9 +588,13 @@
// set the frame rate
VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) pAmMediaType->pbFormat;
vih->AvgTimePerFrame = 10000000 *
- sourceContext_->fmt_nominal.fps_denominator /
- sourceContext_->fmt_nominal.fps_numerator;
+ sourceContext_->fmt_native.fps_denominator /
+ sourceContext_->fmt_native.fps_numerator;
+ // set the dimensions
+ vih->bmiHeader.biWidth = sourceContext_->fmt_native.width;
+ vih->bmiHeader.biHeight = sourceContext_->fmt_native.height;
+
// set the stream's media type
hr = pStreamConfig_->SetFormat(pAmMediaType);
if ( FAILED(hr) )
@@ -606,6 +614,7 @@
}
else
{
+ //FIXME: do at bind time
hr = pSampleGrabberIF_->SetMediaType(pAmMediaType);
}
if ( FAILED(hr) )
@@ -745,7 +754,8 @@
pNullRenderer_->Release();
pNullRenderer_ = 0;
bail_4:
- dshowMgr_->freeMediaType(*pAmMediaType);
+ // free this at next bind time, and in destructor
+ //dshowMgr_->freeMediaType(*pAmMediaType);
bail_3:
pSampleGrabberIF_->Release();
pSampleGrabberIF_ = 0;
@@ -804,8 +814,174 @@
}
int
-DirectShowSource::bindFormat(const vidcap_fmt_info * fmtInfo)
+DirectShowSource::bindFormat(const vidcap_fmt_info * fmtNominal)
{
+ // If we've already got one, free it
+ if ( nativeMediaType_ )
+ dshowMgr_->freeMediaType(*nativeMediaType_);
+
+ bool needsFpsEnforcement = false;
+ bool needsFmtConv = false;
+
+ int iCount = 0, iSize = 0;
+ HRESULT hr = pStreamConfig_->GetNumberOfCapabilities(&iCount, &iSize);
+
+ // Check the size to make sure we pass in the correct structure.
+ if (iSize != sizeof(VIDEO_STREAM_CONFIG_CAPS) )
+ {
+ log_error("capabilities struct is wrong size (%d not %d)\n",
+ iSize, sizeof(VIDEO_STREAM_CONFIG_CAPS));
+ return 1;
+ }
+
+ struct formatProperties
+ {
+ bool isSufficient;
+ bool needsFmtConversion;
+ bool needsFpsEnforcement;
+ AM_MEDIA_TYPE *mediaFormat;
+ };
+
+ struct formatProperties * candidateFmtProps =
+ new struct formatProperties [iCount];
+
+ // these will be filled-in by checkFormat()
+ vidcap_fmt_info * fmtNative = new vidcap_fmt_info [iCount];
+
+ // enumerate each NATIVE source format
+ bool itCanWork = false;
+ for (int iFormat = 0; iFormat < iCount; ++iFormat )
+ {
+ candidateFmtProps[iFormat].isSufficient = false;
+ candidateFmtProps[iFormat].needsFmtConversion = false;
+ candidateFmtProps[iFormat].needsFpsEnforcement = false;
+ candidateFmtProps[iFormat].mediaFormat = 0;
+
+ // evaluate each native source format
+ if ( checkFormat(fmtNominal, &fmtNative[iFormat], iFormat,
+ &(candidateFmtProps[iFormat].needsFmtConversion),
+ &(candidateFmtProps[iFormat].needsFpsEnforcement),
+ &(candidateFmtProps[iFormat].mediaFormat)) )
+ {
+ candidateFmtProps[iFormat].isSufficient = true;
+ itCanWork = true;
+ }
+ }
+
+ // NOTE: Will need to free unselected mediaFormats
+ // before returning, but hold onto the best
+ // (if any) candidate format
+
+ // Can ANY of this source's native formats
+ // satisfy the requested format (to be bound)?
+ if ( !itCanWork )
+ {
+ goto freeThenReturn;
+ }
+
+ // evaluate the possibilities
+
+ int bestFmtNum = -1;
+
+ // any that work without mods?
+ for ( int iFmt = 0; iFmt < iCount; ++iFmt )
+ {
+ if ( candidateFmtProps[iFmt].isSufficient &&
+ !candidateFmtProps[iFmt].needsFmtConversion &&
+ !candidateFmtProps[iFmt].needsFpsEnforcement )
+ {
+ // found a perfect match!
+ log_info("bindFormat: found a 'perfect' match (fmt #%d)\n", iFmt);
+
+ bestFmtNum = iFmt;
+ goto freeThenReturn;
+ }
+ }
+
+ // any that work without format conversion? but with framerate conversion?
+ for ( int iFmt = 0; iFmt < iCount; ++iFmt )
+ {
+ if ( candidateFmtProps[iFmt].isSufficient &&
+ !candidateFmtProps[iFmt].needsFmtConversion &&
+ candidateFmtProps[iFmt].needsFpsEnforcement )
+ {
+ // found an okay match
+ log_info("bindFormat: found an 'okay' match (fmt #%d)\n", iFmt);
+
+ bestFmtNum = iFmt;
+ goto freeThenReturn;
+ }
+ }
+
+ // any that work with format conversion? but without framerate conversion?
+ for ( int iFmt = 0; iFmt < iCount; ++iFmt )
+ {
+ if ( candidateFmtProps[iFmt].isSufficient &&
+ candidateFmtProps[iFmt].needsFmtConversion &&
+ !candidateFmtProps[iFmt].needsFpsEnforcement )
+ {
+ // found a so-so match
+ log_info("bindFormat: found a 'so-so' match (fmt #%d)\n", iFmt);
+
+ bestFmtNum = iFmt;
+ goto freeThenReturn;
+ }
+ }
+
+ // any that work with both caveats?
+ for ( int iFmt = 0; iFmt < iCount; ++iFmt )
+ {
+ if ( candidateFmtProps[iFmt].isSufficient &&
+ candidateFmtProps[iFmt].needsFmtConversion &&
+ candidateFmtProps[iFmt].needsFpsEnforcement )
+ {
+ // found a poor match
+ log_info("bindFormat: found a poor match (fmt #%d)\n", iFmt);
+
+ bestFmtNum = iFmt;
+ goto freeThenReturn;
+ }
+ }
+
+ log_error("bindFormat: coding ERROR\n");
+ itCanWork = false;
+
+freeThenReturn:
+
+ // Free all sufficient candidates (unless it's the the CHOSEN one)
+ for ( int iFmt = 0; iFmt < iCount; ++iFmt )
+ {
+ if ( candidateFmtProps[iFmt].isSufficient )
+ {
+ // NOT the chosen one?
+ if ( !itCanWork || iFmt != bestFmtNum )
+ dshowMgr_->freeMediaType(*candidateFmtProps[iFmt].mediaFormat);
+ }
+ }
+
+ // Can bind succeed?
+ if ( itCanWork )
+ {
+ // take note of native media type, fps, dimensions
+ nativeMediaType_ = candidateFmtProps[bestFmtNum].mediaFormat;
+ sourceContext_->fmt_native.fps_numerator =
+ fmtNative[bestFmtNum].fps_numerator;
+ sourceContext_->fmt_native.fps_denominator =
+ fmtNative[bestFmtNum].fps_denominator;
+ sourceContext_->fmt_native.width = fmtNative[bestFmtNum].width;
+ sourceContext_->fmt_native.height = fmtNative[bestFmtNum].height;
+ sourceContext_->fmt_native.fourcc = fmtNative[bestFmtNum].fourcc;
+
+ //FIXME: use these values NOW, instead of waiting for
+ // capture to start()
+ }
+
+ delete [] candidateFmtProps;
+ delete [] fmtNative;
+
+ if ( !itCanWork )
+ return 1;
+
return 0;
}
@@ -813,12 +989,173 @@
DirectShowSource::validateFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative) const
{
- // TODO: actually validate
+ bool needsFpsEnforcement = false;
+ bool needsFmtConv = false;
- return false;
+ int iCount = 0, iSize = 0;
+ HRESULT hr = pStreamConfig_->GetNumberOfCapabilities(&iCount, &iSize);
+
+ // Check the size to make sure we pass in the correct structure.
+ if (iSize != sizeof(VIDEO_STREAM_CONFIG_CAPS) )
+ {
+ log_error("capabilities struct is wrong size (%d not %d)\n",
+ iSize, sizeof(VIDEO_STREAM_CONFIG_CAPS));
+ return 0;
+ }
+
+ // enumerate each NATIVE format for this source
+ bool itWorks = false;
+ for (int iFormat = 0; iFormat < iCount; iFormat++)
+ {
+ AM_MEDIA_TYPE *mediaFormat = 0;
+
+ itWorks = checkFormat(fmtNominal, fmtNative, iFormat,
+ &needsFpsEnforcement, &needsFmtConv,
+ &mediaFormat);
+
+ if ( itWorks )
+ {
+ dshowMgr_->freeMediaType(*mediaFormat);
+ return 1;
+ }
+ }
+
+ return 0;
}
-//FIXME: should this be generic?
+// Evaluate one of perhaps several native formats for
+// suitability for providing the nominal format.
+// Fill-in output parameter 'mediaFormat'.
+bool
+DirectShowSource::checkFormat(const vidcap_fmt_info * fmtNominal,
+ vidcap_fmt_info * fmtNative,
+ int formatNum,
+ bool *needsFramerateEnforcing, bool *needsFormatConversion,
+ AM_MEDIA_TYPE **mediaFormat) const
+{
+ // get video stream capabilities structure #(formatNum)
+ VIDEO_STREAM_CONFIG_CAPS scc;
+ AM_MEDIA_TYPE *pMediaType;
+ HRESULT hr = pStreamConfig_->GetStreamCaps(formatNum, &pMediaType,
+ (BYTE*)&scc);
+
+ if (FAILED(hr))
+ {
+ log_warn("checkFormat: failed getting stream capabilities [%d] (%d)\n",
+ formatNum + 1, hr);
+ return false;
+ }
+
+ // check resolution
+ if ( fmtNominal->width < scc.MinOutputSize.cx ||
+ fmtNominal->height < scc.MinOutputSize.cy ||
+ fmtNominal->width > scc.MaxOutputSize.cx ||
+ fmtNominal->height > scc.MaxOutputSize.cy )
+ {
+ dshowMgr_->freeMediaType(*pMediaType);
+ return false;
+ }
+
+ bool matchesWidth = false;
+ for (int width = scc.MinOutputSize.cx; width <= scc.MaxOutputSize.cx;
+ width += scc.OutputGranularityX)
+ {
+ if ( width == fmtNominal->width )
+ matchesWidth = true;
+ }
+
+ bool matchesHeight = false;
+ for (int height = scc.MinOutputSize.cy; height <= scc.MaxOutputSize.cy;
+ height += scc.OutputGranularityY)
+ {
+ if ( height == fmtNominal->height )
+ matchesHeight = true;
+ }
+
+ if ( !matchesWidth || !matchesHeight )
+ {
+ dshowMgr_->freeMediaType(*pMediaType);
+ return false;
+ }
+
+ // calculate range of supported frame rates
+ double fpsMin = static_cast<double>( 1000000000 / scc.MaxFrameInterval)
+ / 100.0;
+ double fpsMax = static_cast<double>( 1000000000 / scc.MinFrameInterval)
+ / 100.0;
+
+ double fps = static_cast<double>(fmtNominal->fps_numerator) /
+ static_cast<double>(fmtNominal->fps_denominator);
+
+ // check framerate
+ if ( fps > fpsMax )
+ {
+ dshowMgr_->freeMediaType(*pMediaType);
+ return false;
+ }
+
+ if ( fps < fpsMin )
+ *needsFramerateEnforcing = true;
+
+ // check media type
+
+ int nativeFourcc = 0;
+ if ( mapDirectShowMediaTypeToVidcapFourcc(
+ pMediaType->subtype.Data1, nativeFourcc) )
+ {
+ dshowMgr_->freeMediaType(*pMediaType);
+ return false;
+ }
+
+ *needsFormatConversion = ( nativeFourcc != fmtNominal->fourcc );
+
+ if ( *needsFormatConversion &&
+ (conv_conversion_func_get(nativeFourcc, fmtNominal->fourcc) == 0) )
+ {
+ dshowMgr_->freeMediaType(*pMediaType);
+ return false;
+ }
+
+ // it's suitable. fill-in the native format values
+
+ fmtNative->width = fmtNominal->width;
+ fmtNative->height = fmtNominal->height;
+
+ if ( *needsFormatConversion )
+ fmtNative->fourcc = nativeFourcc;
+ else
+ fmtNative->fourcc = fmtNominal->fourcc;
+
+ if ( *needsFramerateEnforcing )
+ {
+ //FIXME: Use float. Drop numerator/denominator business.
+ fmtNative->fps_numerator = (int)fpsMax;
+ fmtNative->fps_denominator = 1;
+ }
+ else
+ {
+ fmtNative->fps_numerator = fmtNominal->fps_numerator;
+ fmtNative->fps_denominator = fmtNominal->fps_denominator;
+ }
+
+ /*
+ log_info("cf: can be satisfied with NATIVE format #%d: "
+ "'%s' %dx%d %d/%d fps\n",
+ formatNum,
+ vidcap_fourcc_string_get(fmtNative->fourcc),
+ fmtNative->width, fmtNative->height,
+ fmtNative->fps_numerator,
+ fmtNative->fps_denominator);
+ */
+
+ // return this suitable media type
+ *mediaFormat = pMediaType;
+
+ //FIXME: adjust framerate and dimensions now - not at capture start time
+
+ return true;
+}
+
void
DirectShowSource::cancelCallbacks()
{
@@ -838,11 +1175,7 @@
LeaveCriticalSection(&captureMutex_);
- log_info("cancelled source's capture callbacks\n");
-
stop();
-
- log_info("cancelled source's capture callbacks and stopped capture\n");
}
// Fake out interface queries
@@ -969,7 +1302,7 @@
{
switch ( data )
{
- case 0xe436eb7e: // MEDIASUBTYPE_RGB32.Data1
+ case 0xe436eb7e:
fourcc = VIDCAP_FOURCC_RGB32;
break;
case 0x30323449: // I420
@@ -989,7 +1322,7 @@
fourcc = VIDCAP_FOURCC_YVU9;
break;
default:
- log_warn("failed to map 0x%08x to fourcc\n", data);
+ log_warn("failed to map 0x%08x to vidcap fourcc\n", data);
return -1;
}
@@ -1002,7 +1335,7 @@
switch ( fourcc )
{
case VIDCAP_FOURCC_RGB32:
- data = 0xe436eb7e; // MEDIASUBTYPE_RGB32.Data1
+ data = 0xe436eb7e;
break;
case VIDCAP_FOURCC_I420:
data = 0x30323449; // '024I' aka I420
@@ -1011,7 +1344,7 @@
data = 0x32595559;
break;
default:
- log_warn("failed to map '%s' to DS media type\n",
+ log_warn("failed to map '%s' to DShow media type\n",
vidcap_fourcc_string_get(fourcc));
return -1;
}
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-06 15:39:40 UTC (rev 4)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-07 21:19:26 UTC (rev 5)
@@ -55,7 +55,13 @@
private:
bool canConvertToRGB32();
+ bool checkFormat(const vidcap_fmt_info * fmtNominal,
+ vidcap_fmt_info * fmtNative,
+ int formatNum,
+ bool *needsFramerateEnforcing, bool *needsFormatConversion,
+ AM_MEDIA_TYPE **candidateMediaFormat) const;
+ // NOTE: this will soon be obsolete
AM_MEDIA_TYPE * getMediaType( CComPtr< IPin > pPin) const;
void printMediaFormatType(AM_MEDIA_TYPE *pMedia);
@@ -95,8 +101,11 @@
IMediaControl * pMediaControlIF_;
+ AM_MEDIA_TYPE *nativeMediaType_;
+
// when necessary to convert source output format
- IBaseFilter *pIntermediateFilter_;
+ //NOTE: these two will soon be obsolete
+ IBaseFilter *pIntermediateFilter_;
DWORD intermediateMediaType_;
CRITICAL_SECTION captureMutex_;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-07 21:53:32
|
Revision: 9
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=9&view=rev
Author: bcholew
Date: 2007-09-07 14:53:30 -0700 (Fri, 07 Sep 2007)
Log Message:
-----------
Removed unused code: functions canConvertToRGB32(), getMediaType(), buildFormatList(), and member variables pSourceOutPin_, pIntermediateFilter_ and intermediateMediaType_.
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-07 21:33:40 UTC (rev 8)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-07 21:53:30 UTC (rev 9)
@@ -51,8 +51,6 @@
pNullRenderer_(0),
pMediaControlIF_(0),
nativeMediaType_(0),
- pIntermediateFilter_(0),
- intermediateMediaType_(0),
stoppingCapture_(false)
{
if ( !dshowMgr_ )
@@ -93,14 +91,6 @@
goto constructionFailure;
}
-#if 0
- if ( !buildFormatList(pBindCtx, pMoniker) )
- {
- log_warn("Failed building format list for '%s'.\n", getID());
- goto constructionFailure;
- }
-#else
-
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
NULL,
CLSCTX_INPROC_SERVER,
@@ -125,18 +115,7 @@
pCapGraphBuilder_->Release();
goto constructionFailure;
}
-#endif
- // FIXME: does this really need to be a member? Maybe should be in start().
- pSourceOutPin_ = dshowMgr_->getOutPin( pSource_, 0 );
-
- if ( !pSourceOutPin_ )
- {
- log_error("Failed getting source output pin\n");
- goto constructionFailure;
- }
-
-
hr = CoCreateInstance(CLSID_FilterGraph,
0,
CLSCTX_INPROC_SERVER,
@@ -202,8 +181,6 @@
pFilterGraph_->Release();
- pSourceOutPin_.Release();
-
pSource_->Release();
pStreamConfig_->Release();
@@ -215,316 +192,7 @@
DeleteCriticalSection(&captureMutex_);
}
-#if 0
int
-DirectShowSource::buildFormatList(IBindCtx * pBindCtx, IMoniker * pMoniker)
-{
- HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_ICaptureGraphBuilder2,
- (void **)&pCapGraphBuilder_);
-
- if ( FAILED(hr) )
- {
- log_error("failed creating capture graph builder (%d)\n", hr);
- return 0;
- }
-
- hr = pCapGraphBuilder_->FindInterface(&PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video,
- pSource_,
- IID_IAMStreamConfig,
- (void **)&pStreamConfig_);
- if( FAILED(hr) )
- {
- log_error("failed getting stream config "
- "while building format list (%d)\n", hr);
- pCapGraphBuilder_->Release();
- return 0;
- }
-
- int iCount = 0, iSize = 0;
- hr = pStreamConfig_->GetNumberOfCapabilities(&iCount, &iSize);
-
- // Check the size to make sure we pass in the correct structure.
- if (iSize != sizeof(VIDEO_STREAM_CONFIG_CAPS) )
- {
- log_error("capabilities struct is wrong size (%d not %d)\n",
- iSize, sizeof(VIDEO_STREAM_CONFIG_CAPS));
- pStreamConfig_->Release();
- pCapGraphBuilder_->Release();
- return 0;
- }
-
- // enumerate each source format
- for (int iFormat = 0; iFormat < iCount; iFormat++)
- {
- // get the video stream capabilities structure
- VIDEO_STREAM_CONFIG_CAPS scc;
- AM_MEDIA_TYPE *pMediaType;
- hr = pStreamConfig_->GetStreamCaps(iFormat, &pMediaType,
- (BYTE*)&scc);
-
- if (FAILED(hr))
- {
- log_warn("failed getting stream capabilities [%d of %d] (%d)\n",
- iFormat+1, iCount, hr);
- continue;
- }
-
- int fourcc;
-
- if ( mapDirectShowMediaTypeToVidcapFourcc(
- pMediaType->subtype.Data1, fourcc) )
- continue;
-
- // calculate range of supported frame rates
- double fpsMin = static_cast<double>( 1000000000 / scc.MaxFrameInterval)
- / 100.0;
- double fpsMax = static_cast<double>( 1000000000 / scc.MinFrameInterval)
- / 100.0;
-
- // enumerate a format for each frame rate
- for ( int i = 0; i < hot_fps_list_len; ++i )
- {
- int hot_fps_num = hot_fps_list[i].fps_numerator;
- int hot_fps_den = hot_fps_list[i].fps_denominator;
- double fps = static_cast<double>(hot_fps_num) /
- static_cast<double>(hot_fps_den);
-
- if ( fps < fpsMin || fps > fpsMax )
- continue;
-
- for ( int j = 0; j < hot_resolution_list_len; ++j )
- {
- vidcap_fmt_info * fmt;
-
- const int hot_width =
- hot_resolution_list[j].width;
- const int hot_height =
- hot_resolution_list[j].height;
-
- if ( hot_width < scc.MinOutputSize.cx ||
- hot_height < scc.MinOutputSize.cy ||
- hot_width > scc.MaxOutputSize.cx ||
- hot_height > scc.MaxOutputSize.cy )
- {
- continue;
- }
-
- fmtListLen_++;
- pFmtList_ = static_cast<vidcap_fmt_info *>(
- realloc(pFmtList_,
- fmtListLen_ *
- sizeof(vidcap_fmt_info)));
-
- if ( !pFmtList_ )
- {
- log_error("failed reallocating format list\n");
-
- dshowMgr_->freeMediaType(*pMediaType);
- pStreamConfig_->Release();
- pCapGraphBuilder_->Release();
- return 0;
- }
-
- fmt = &pFmtList_[fmtListLen_ - 1];
-
- fmt->width = hot_width;
- fmt->height = hot_height;
- fmt->fourcc = fourcc;
- fmt->fps_numerator = hot_fps_num;
- fmt->fps_denominator = hot_fps_den;
-
- // TODO: revisit OutputGranularity if a device
- // is found that uses it
- }
- }
-
- dshowMgr_->freeMediaType(*pMediaType);
- }
-
- return fmtListLen_;
-}
-#endif
-
-bool
-DirectShowSource::canConvertToRGB32()
-{
- if ( pIntermediateFilter_ )
- pIntermediateFilter_->Release();
-
- // used if format conversion is necessary
- intermediateMediaType_ = 0;
- pIntermediateFilter_ = 0;
-
- IFilterMapper2 *pMapper = NULL;
- IEnumMoniker *pEnum = NULL;
-
- HRESULT hr;
- hr = CoCreateInstance(CLSID_FilterMapper2,
- NULL,
- CLSCTX_INPROC,
- IID_IFilterMapper2,
- (void **) &pMapper);
-
- if (FAILED(hr))
- {
- log_error("failed to create FilterMapper2 (%d)\n", hr);
- return false;
- }
-
- // search for a filter to convert to RGB32
-
- GUID arrayInTypes[2];
- GUID arrayOutTypes[2];
- memset(&arrayInTypes[1], 0, sizeof(arrayInTypes[1]));
- memset(&arrayOutTypes[1], 0, sizeof(arrayOutTypes[1]));
-
- CComPtr< IEnumMediaTypes > pMediaEnum;
- hr = pSourceOutPin_->EnumMediaTypes(&pMediaEnum);
- if ( FAILED(hr) )
- {
- log_error("failed creating media type enumerator (rc=%d)\n", hr);
- pMapper->Release();
- return false;
- }
-
- // enumerate all media types of source
- ULONG ulFound;
- AM_MEDIA_TYPE * pMedia;
- while ( S_OK == pMediaEnum->Next(1, &pMedia, &ulFound) )
- {
- VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *)pMedia->pbFormat;
-
- // find entry that matches desired format
- if ( vih->bmiHeader.biWidth != sourceContext_->fmt_nominal.width ||
- vih->bmiHeader.biHeight != sourceContext_->fmt_nominal.height )
- {
- // invalid dimensions
- dshowMgr_->freeMediaType(*pMedia);
- continue;
- }
-
- arrayInTypes[0] = pMedia->majortype;
- arrayInTypes[1] = pMedia->subtype;
-
- arrayOutTypes[0] = MEDIATYPE_Video;
- arrayOutTypes[1] = MEDIASUBTYPE_RGB32;
-
-#if 0
- log_info("considering input format %c%c%c%c\n",
- (arrayInTypes[1].Data1 >> 0) & 0xff,
- (arrayInTypes[1].Data1 >> 8) & 0xff,
- (arrayInTypes[1].Data1 >> 16) & 0xff,
- (arrayInTypes[1].Data1 >> 24) & 0xff);
-#endif
-
- IEnumMoniker *pFilterEnum = NULL;
- hr = pMapper->EnumMatchingFilters(
- &pFilterEnum,
- 0, // Reserved.
- TRUE, // Use exact match?
- MERIT_DO_NOT_USE+1, // Minimum merit.
- TRUE, // At least one input pin?
-
- 1, // # of major type/subtype pairs for input
- arrayInTypes, // Array of major/subtype pairs for input
-
- NULL, // Input medium.
- NULL, // Input pin category.
- FALSE, // Must be a renderer?
- TRUE, // At least one output pin?
-
- 1, // # of major type/subtype pairs for output
- arrayOutTypes, // Array of major/subtype pairs for output
-
- NULL, // Output medium.
- NULL); // Output pin category.
-
- // Enumerate the filter monikers
- IMoniker *pMoniker;
- ULONG cFetched;
- while ( pFilterEnum->Next(1, &pMoniker, &cFetched) == S_OK )
- {
- IPropertyBag *pPropBag = NULL;
- hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
- (void **)&pPropBag);
-
- if ( FAILED(hr) )
- {
- log_warn("Couldn't bind to storage for this matching filter\n");
- pMoniker->Release();
- continue;
- }
-
- // Get the friendly name of the filter
- VARIANT varName;
- VariantInit(&varName);
- hr = pPropBag->Read(L"FriendlyName", &varName, 0);
- if ( SUCCEEDED(hr) )
- {
- char * pszFriendlyName =
- _com_util::ConvertBSTRToString(
- varName.bstrVal);
-
- log_info("conversion filter '%s' should work\n",
- pszFriendlyName);
-
- delete [] pszFriendlyName;
- }
- VariantClear(&varName);
-
- // Create an instance of the filter
- hr = pMoniker->BindToObject(NULL,
- NULL,
- IID_IBaseFilter,
- (void**)&pIntermediateFilter_);
-
- if (FAILED(hr))
- {
- //FIXME: name it
- log_warn("failed to instantiate conversion filter (%d)\n",
- hr);
-
- pPropBag->Release();
- pMoniker->Release();
- pIntermediateFilter_ = 0;
- continue;
- }
-
- // TODO:
- // get output pin of intermediate filter?
- // get it's media type?
-
- intermediateMediaType_ = arrayInTypes[1].Data1;
-
- pPropBag->Release();
- pMoniker->Release();
- pFilterEnum->Release();
- dshowMgr_->freeMediaType(*pMedia);
- pMediaEnum.Release();
- pMapper->Release();
-
- return true;
- }
-
- // cleanup
- pFilterEnum->Release();
- dshowMgr_->freeMediaType(*pMedia);
-
- // failed to find filter suitable to convert this media type to RGB32
- }
-
- pMediaEnum.Release();
- pMapper->Release();
-
- // Can't build filter graph to convert this source's output to RGB32
- return false;
-}
-
-int
DirectShowSource::start()
{
HRESULT hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
@@ -604,19 +272,8 @@
}
// Set sample grabber's media type to match that of the source
- // OR the conversion filter
- if ( intermediateMediaType_ )
- {
- //FIXME: Shouldn't this be necessary?
- pAmMediaType->subtype.Data1 = intermediateMediaType_;
- //hr = pSampleGrabberIF_->SetMediaType(pAmMediaType);
- hr = pSampleGrabberIF_->SetMediaType(NULL);
- }
- else
- {
- //FIXME: do at bind time
- hr = pSampleGrabberIF_->SetMediaType(pAmMediaType);
- }
+ //FIXME: do at bind time
+ hr = pSampleGrabberIF_->SetMediaType(pAmMediaType);
if ( FAILED(hr) )
{
log_error("failed to set grabber media type (%d)\n", hr);
@@ -658,81 +315,17 @@
goto bail_5;
}
- if ( pIntermediateFilter_ )
+ hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
+ &MEDIATYPE_Video,
+ pSource_,
+ pSampleGrabber_,
+ pNullRenderer_);
+ if ( FAILED(hr) )
{
- hr = pFilterGraph_->AddFilter(pIntermediateFilter_,
- L"ConversionFilter");
- if ( FAILED(hr) )
- {
- log_error("failed to add conversion filter (%d)\n", hr);
- goto bail_5;
- }
-
- hr = pCapGraphBuilder_->RenderStream(NULL, //&PIN_CATEGORY_CAPTURE,
- NULL, //&MEDIATYPE_Video,
- pSource_,
- pIntermediateFilter_,
- pSampleGrabber_);
- if ( FAILED(hr) )
- {
- log_error("failed to connect source, conversion filter, "
- "sample grabber (%lu 0x%x)\n", hr, hr);
- switch ( hr )
- {
- case VFW_S_NOPREVIEWPIN:
- log_error("VFW_S_NOPREVIEWPIN\n");
- break;
-
- case E_FAIL:
- log_error("E_FAIL\n");
- break;
-
- case E_POINTER:
- log_error("E_POINTER\n");
- break;
-
- case VFW_E_NOT_IN_GRAPH:
- log_error("VFW_E_NOT_IN_GRAPH\n");
- break;
-
- case E_INVALIDARG:
- log_error("E_INVALIDARG\n");
- break;
-
- default:
- log_error("default\n");
- break;
- }
- goto bail_5;
- }
-
- hr = pCapGraphBuilder_->RenderStream(
- NULL, //&PIN_CATEGORY_CAPTURE,
- NULL, //&MEDIATYPE_Video,
- pSampleGrabber_,
- NULL,
- pNullRenderer_);
- if ( FAILED(hr) )
- {
- log_error("failed to connect grabber and null renderer (%d)\n",
- hr);
- goto bail_5;
- }
+ log_error("failed to connect source, grabber "
+ "and null renderer (%d)\n", hr);
+ goto bail_5;
}
- else
- {
- hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video,
- pSource_,
- pSampleGrabber_,
- pNullRenderer_);
- if ( FAILED(hr) )
- {
- log_error("failed to connect source, grabber "
- "and null renderer (%d)\n", hr);
- goto bail_5;
- }
- }
hr = pMediaControlIF_->Run();
@@ -786,10 +379,6 @@
log_error("failed to STOP the filter graph (%ul)\n", hr);
}
- if ( pIntermediateFilter_ )
- pIntermediateFilter_->Release();
- pIntermediateFilter_ = 0;
-
if ( pNullRenderer_ )
pNullRenderer_->Release();
pNullRenderer_ = 0;
@@ -1217,86 +806,6 @@
return ret;
}
-//FIXME: Is there a better way to get the media type
-// from the width, height and fourcc?
-AM_MEDIA_TYPE *
-DirectShowSource::getMediaType( CComPtr< IPin > pPin) const
-{
- CComPtr< IEnumMediaTypes > pEnum;
-
- HRESULT hr = pPin->EnumMediaTypes(&pEnum);
-
- if ( FAILED(hr) )
- {
- log_error("failed creating media type enumerator (rc=%d)\n", hr);
- return NULL;
- }
-
- ULONG ulFound;
- AM_MEDIA_TYPE * pMedia;
- DWORD boundMediaType;
-
- if ( mapVidcapFourccToDirectShowMediaType(
- sourceContext_->fmt_nominal.fourcc,
- boundMediaType) )
- return NULL;
-
- int requiredMediaType = intermediateMediaType_ ?
- intermediateMediaType_ : boundMediaType;
-
- while ( S_OK == pEnum->Next(1, &pMedia, &ulFound) )
- {
- //printMediaFormatType(pMedia);
-
- VIDEOINFOHEADER * vih =
- (VIDEOINFOHEADER *) pMedia->pbFormat;
- int thisFourcc;
-
- if ( mapDirectShowMediaTypeToVidcapFourcc(pMedia->subtype.Data1,
- thisFourcc) )
- continue;
-
- // find entry that matches desired format
- if ( vih->bmiHeader.biWidth ==
- sourceContext_->fmt_nominal.width &&
- vih->bmiHeader.biHeight ==
- sourceContext_->fmt_nominal.height &&
- (thisFourcc ==
- sourceContext_->fmt_nominal.fourcc ||
- pMedia->subtype.Data1 == requiredMediaType) )
- {
- return pMedia;
- }
-
- dshowMgr_->freeMediaType(*pMedia);
- }
-
- return NULL;
-}
-
-void
-DirectShowSource::printMediaFormatType(AM_MEDIA_TYPE *pMedia)
-{
- if ( pMedia->formattype == FORMAT_DvInfo )
- log_info("FORMAT_DvInfo\n");
- else if ( pMedia->formattype == FORMAT_MPEG2Video )
- log_info("FORMAT_MPEG2Video\n");
- else if ( pMedia->formattype == FORMAT_MPEGStreams )
- log_info("FORMAT_MPEGStreams\n");
- else if ( pMedia->formattype == FORMAT_MPEGVideo )
- log_info("FORMAT_MPEGVideo\n");
- else if ( pMedia->formattype == FORMAT_None )
- log_info("FORMAT_None\n");
- else if ( pMedia->formattype == FORMAT_VideoInfo )
- log_info("FORMAT_VideoInfo\n");
- else if ( pMedia->formattype == FORMAT_VideoInfo2 )
- log_info("FORMAT_VideoInfo2\n");
- else if ( pMedia->formattype == FORMAT_WaveFormatEx )
- log_info("FORMAT_WaveFormatEx\n");
- else
- log_info("unknown\n");
-}
-
int
DirectShowSource::mapDirectShowMediaTypeToVidcapFourcc(DWORD data, int & fourcc)
{
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-07 21:33:40 UTC (rev 8)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-07 21:53:30 UTC (rev 9)
@@ -54,17 +54,12 @@
}
private:
- bool canConvertToRGB32();
bool checkFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative,
int formatNum,
bool *needsFramerateEnforcing, bool *needsFormatConversion,
AM_MEDIA_TYPE **candidateMediaFormat) const;
- // NOTE: this will soon be obsolete
- AM_MEDIA_TYPE * getMediaType( CComPtr< IPin > pPin) const;
- void printMediaFormatType(AM_MEDIA_TYPE *pMedia);
-
// Fake out COM reference counting
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
@@ -90,7 +85,6 @@
DShowSrcManager * dshowMgr_;
IBaseFilter * pSource_;
- CComPtr<IPin> pSourceOutPin_; // TODO: remove CComPtr
ICaptureGraphBuilder2 *pCapGraphBuilder_;
IAMStreamConfig * pStreamConfig_;
IGraphBuilder *pFilterGraph_;
@@ -103,11 +97,6 @@
AM_MEDIA_TYPE *nativeMediaType_;
- // when necessary to convert source output format
- //NOTE: these two will soon be obsolete
- IBaseFilter *pIntermediateFilter_;
- DWORD intermediateMediaType_;
-
CRITICAL_SECTION captureMutex_;
bool stoppingCapture_;
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-11 13:29:48
|
Revision: 12
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=12&view=rev
Author: bcholew
Date: 2007-09-11 06:29:44 -0700 (Tue, 11 Sep 2007)
Log Message:
-----------
Re-org validateFormat() to be sure to return the best native format for a given nominal format. Tidy up.
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-11 13:15:47 UTC (rev 11)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-11 13:29:44 UTC (rev 12)
@@ -372,12 +372,63 @@
}
int
+DirectShowSource::validateFormat(const vidcap_fmt_info * fmtNominal,
+ vidcap_fmt_info * fmtNative) const
+{
+ AM_MEDIA_TYPE *mediaFormat;
+
+ if ( !findBestFormat(fmtNominal, fmtNative, &mediaFormat) )
+ return 0;
+
+ dshowMgr_->freeMediaType(*mediaFormat);
+ return 1;
+}
+
+int
DirectShowSource::bindFormat(const vidcap_fmt_info * fmtNominal)
{
+ vidcap_fmt_info fmtNative;
+
// If we've already got one, free it
if ( nativeMediaType_ )
+ {
dshowMgr_->freeMediaType(*nativeMediaType_);
+ nativeMediaType_ = 0;
+ }
+ if ( !findBestFormat(fmtNominal, &fmtNative, &nativeMediaType_) )
+ return 1;
+
+ // set the framerate
+ VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) nativeMediaType_->pbFormat;
+ vih->AvgTimePerFrame = 10000000 *
+ fmtNative.fps_denominator /
+ fmtNative.fps_numerator;
+
+ // set the dimensions
+ vih->bmiHeader.biWidth = fmtNative.width;
+ vih->bmiHeader.biHeight = fmtNative.height;
+
+ // set the stream's media type
+ HRESULT hr = pStreamConfig_->SetFormat(nativeMediaType_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed setting stream format (%d)\n", hr);
+
+ dshowMgr_->freeMediaType(*nativeMediaType_);
+ nativeMediaType_ = 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+bool
+DirectShowSource::findBestFormat(const vidcap_fmt_info * fmtNominal,
+ vidcap_fmt_info * fmtNative, AM_MEDIA_TYPE **mediaFormat) const
+
+{
bool needsFpsEnforcement = false;
bool needsFmtConv = false;
@@ -389,7 +440,7 @@
{
log_error("capabilities struct is wrong size (%d not %d)\n",
iSize, sizeof(VIDEO_STREAM_CONFIG_CAPS));
- return 1;
+ return false;
}
struct formatProperties
@@ -400,12 +451,11 @@
AM_MEDIA_TYPE *mediaFormat;
};
+ // these will be filled-in by checkFormat()
struct formatProperties * candidateFmtProps =
new struct formatProperties [iCount];
+ vidcap_fmt_info * fmtsNative = new vidcap_fmt_info [iCount];
- // these will be filled-in by checkFormat()
- vidcap_fmt_info * fmtNative = new vidcap_fmt_info [iCount];
-
// enumerate each NATIVE source format
bool itCanWork = false;
for (int iFormat = 0; iFormat < iCount; ++iFormat )
@@ -416,7 +466,7 @@
candidateFmtProps[iFormat].mediaFormat = 0;
// evaluate each native source format
- if ( checkFormat(fmtNominal, &fmtNative[iFormat], iFormat,
+ if ( checkFormat(fmtNominal, &fmtsNative[iFormat], iFormat,
&(candidateFmtProps[iFormat].needsFmtConversion),
&(candidateFmtProps[iFormat].needsFpsEnforcement),
&(candidateFmtProps[iFormat].mediaFormat)) )
@@ -426,10 +476,6 @@
}
}
- // NOTE: Will need to free unselected mediaFormats
- // before returning, but hold onto the best
- // (if any) candidate format
-
// Can ANY of this source's native formats
// satisfy the requested format (to be bound)?
if ( !itCanWork )
@@ -448,9 +494,7 @@
!candidateFmtProps[iFmt].needsFmtConversion &&
!candidateFmtProps[iFmt].needsFpsEnforcement )
{
- // found a perfect match!
- log_info("bindFormat: found a 'perfect' match (fmt #%d)\n", iFmt);
-
+ // found a perfect match
bestFmtNum = iFmt;
goto freeThenReturn;
}
@@ -464,8 +508,6 @@
candidateFmtProps[iFmt].needsFpsEnforcement )
{
// found an okay match
- log_info("bindFormat: found an 'okay' match (fmt #%d)\n", iFmt);
-
bestFmtNum = iFmt;
goto freeThenReturn;
}
@@ -479,29 +521,23 @@
!candidateFmtProps[iFmt].needsFpsEnforcement )
{
// found a so-so match
- log_info("bindFormat: found a 'so-so' match (fmt #%d)\n", iFmt);
-
bestFmtNum = iFmt;
goto freeThenReturn;
}
}
- // any that work with both caveats?
+ // any that work at all (with both conversions)?
for ( int iFmt = 0; iFmt < iCount; ++iFmt )
{
- if ( candidateFmtProps[iFmt].isSufficient &&
- candidateFmtProps[iFmt].needsFmtConversion &&
- candidateFmtProps[iFmt].needsFpsEnforcement )
+ if ( candidateFmtProps[iFmt].isSufficient )
{
// found a poor match
- log_info("bindFormat: found a poor match (fmt #%d)\n", iFmt);
-
bestFmtNum = iFmt;
goto freeThenReturn;
}
}
- log_error("bindFormat: coding ERROR\n");
+ log_error("findBestFormat: coding ERROR\n");
itCanWork = false;
freeThenReturn:
@@ -520,84 +556,24 @@
// Can bind succeed?
if ( itCanWork )
{
- // take note of native media type, fps, dimensions
- nativeMediaType_ = candidateFmtProps[bestFmtNum].mediaFormat;
+ // take note of native media type, fps, dimensions, fourcc
+ *mediaFormat = candidateFmtProps[bestFmtNum].mediaFormat;
- // set the frame rate
- VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) nativeMediaType_->pbFormat;
- vih->AvgTimePerFrame = 10000000 *
- fmtNative[bestFmtNum].fps_denominator /
- fmtNative[bestFmtNum].fps_numerator;
-
- // set the dimensions
- vih->bmiHeader.biWidth = fmtNative[bestFmtNum].width;
- vih->bmiHeader.biHeight = fmtNative[bestFmtNum].height;
-
- // set the stream's media type
- hr = pStreamConfig_->SetFormat(nativeMediaType_);
- if ( FAILED(hr) )
- {
- log_error("failed setting stream format (%d)\n", hr);
- itCanWork = false;
- }
-
- // FIXME: is this necessary?
- sourceContext_->fmt_native.fps_numerator =
- fmtNative[bestFmtNum].fps_numerator;
- sourceContext_->fmt_native.fps_denominator =
- fmtNative[bestFmtNum].fps_denominator;
- sourceContext_->fmt_native.width = fmtNative[bestFmtNum].width;
- sourceContext_->fmt_native.height = fmtNative[bestFmtNum].height;
- sourceContext_->fmt_native.fourcc = fmtNative[bestFmtNum].fourcc;
+ fmtNative->fps_numerator =
+ fmtsNative[bestFmtNum].fps_numerator;
+ fmtNative->fps_denominator =
+ fmtsNative[bestFmtNum].fps_denominator;
+ fmtNative->width = fmtsNative[bestFmtNum].width;
+ fmtNative->height = fmtsNative[bestFmtNum].height;
+ fmtNative->fourcc = fmtsNative[bestFmtNum].fourcc;
}
delete [] candidateFmtProps;
- delete [] fmtNative;
+ delete [] fmtsNative;
- if ( !itCanWork )
- return 1;
-
- return 0;
+ return itCanWork;
}
-bool
-DirectShowSource::validateFormat(const vidcap_fmt_info * fmtNominal,
- vidcap_fmt_info * fmtNative) const
-{
- bool needsFpsEnforcement = false;
- bool needsFmtConv = false;
-
- int iCount = 0, iSize = 0;
- HRESULT hr = pStreamConfig_->GetNumberOfCapabilities(&iCount, &iSize);
-
- // Check the size to make sure we pass in the correct structure.
- if (iSize != sizeof(VIDEO_STREAM_CONFIG_CAPS) )
- {
- log_error("capabilities struct is wrong size (%d not %d)\n",
- iSize, sizeof(VIDEO_STREAM_CONFIG_CAPS));
- return 0;
- }
-
- // enumerate each NATIVE format for this source
- bool itWorks = false;
- for (int iFormat = 0; iFormat < iCount; iFormat++)
- {
- AM_MEDIA_TYPE *mediaFormat = 0;
-
- itWorks = checkFormat(fmtNominal, fmtNative, iFormat,
- &needsFpsEnforcement, &needsFmtConv,
- &mediaFormat);
-
- if ( itWorks )
- {
- dshowMgr_->freeMediaType(*mediaFormat);
- return 1;
- }
- }
-
- return 0;
-}
-
// Evaluate one of perhaps several native formats for
// suitability for providing the nominal format.
// Fill-in output parameter 'mediaFormat'.
@@ -698,12 +674,10 @@
dshowMgr_->freeMediaType(*pMediaType);
return false;
}
-
- fmtNative->fourcc = nativeFourcc;
}
- else
- fmtNative->fourcc = fmtNominal->fourcc;
+ fmtNative->fourcc = nativeFourcc;
+
fmtNative->width = fmtNominal->width;
fmtNative->height = fmtNominal->height;
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-11 13:15:47 UTC (rev 11)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-11 13:29:44 UTC (rev 12)
@@ -42,7 +42,7 @@
int start();
int stop();
int bindFormat(const vidcap_fmt_info * fmtInfo);
- bool validateFormat(const vidcap_fmt_info * fmtNominal,
+ int validateFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative) const;
void cancelCallbacks();
@@ -60,6 +60,9 @@
bool *needsFramerateEnforcing, bool *needsFormatConversion,
AM_MEDIA_TYPE **candidateMediaFormat) const;
+ bool findBestFormat(const vidcap_fmt_info * fmtNominal,
+ vidcap_fmt_info * fmtNative, AM_MEDIA_TYPE **mediaFormat) const;
+
// Fake out COM reference counting
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-12 13:58:09
|
Revision: 16
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=16&view=rev
Author: bcholew
Date: 2007-09-12 06:57:59 -0700 (Wed, 12 Sep 2007)
Log Message:
-----------
Rename sourceIDs_ to acquiredSourceIDs_. Constify scan(), getJustCapDevice(), sprintDeviceInfo(), getOutPin(), getPin(), and getDeviceInfo(). Privatize getOutPin(). Remove getInPin(). Move freeMediaType() to DirectShowSource. Tidy up.
Modified Paths:
--------------
trunk/src/directshow/DShowSrcManager.cpp
trunk/src/directshow/DShowSrcManager.h
trunk/src/directshow/DirectShowSource.cpp
trunk/src/directshow/DirectShowSource.h
Modified: trunk/src/directshow/DShowSrcManager.cpp
===================================================================
--- trunk/src/directshow/DShowSrcManager.cpp 2007-09-11 18:43:51 UTC (rev 15)
+++ trunk/src/directshow/DShowSrcManager.cpp 2007-09-12 13:57:59 UTC (rev 16)
@@ -58,7 +58,8 @@
{
delete graphMon_;
- sourceIDs_.erase( sourceIDs_.begin(), sourceIDs_.end() );
+ acquiredSourceIDs_.erase( acquiredSourceIDs_.begin(),
+ acquiredSourceIDs_.end() );
srcGraphList_.erase( srcGraphList_.begin(), srcGraphList_.end() );
CoUninitialize();
@@ -157,7 +158,7 @@
}
int
-DShowSrcManager::scan(struct sapi_src_list * srcList)
+DShowSrcManager::scan(struct sapi_src_list * srcList) const
{
//FIXME: consider multiple sources per device
@@ -254,9 +255,9 @@
DShowSrcManager::okayToBuildSource(const char *id)
{
// Enforce exclusive access to a source
- for ( unsigned int i = 0; i < sourceIDs_.size(); i++ )
+ for ( unsigned int i = 0; i < acquiredSourceIDs_.size(); i++ )
{
- if ( !strcmp(sourceIDs_[i], id) )
+ if ( !strcmp(acquiredSourceIDs_[i], id) )
{
// a source with this id already exists - and was acquired
log_warn("source already acquired: '%s'\n", id);
@@ -265,20 +266,20 @@
}
// add source to collection
- sourceIDs_.push_back(id);
+ acquiredSourceIDs_.push_back(id);
return true;
}
void DShowSrcManager::sourceReleased(const char *id)
{
- for ( unsigned int i = 0; i < sourceIDs_.size(); i++ )
+ for ( unsigned int i = 0; i < acquiredSourceIDs_.size(); i++ )
{
- if ( !strcmp(sourceIDs_[i], id) )
+ if ( !strcmp(acquiredSourceIDs_[i], id) )
{
// found source with matching id
- sourceIDs_.erase( sourceIDs_.begin() + i );
+ acquiredSourceIDs_.erase( acquiredSourceIDs_.begin() + i );
return;
}
@@ -287,30 +288,10 @@
log_warn("couldn't find source '%s' to release\n", id);
}
-IPin *
-DShowSrcManager::getOutPin( IBaseFilter * pFilter, int nPin )
-{
- CComPtr<IPin> pComPin = 0;
-
- getPin(pFilter, PINDIR_OUTPUT, nPin, &pComPin);
-
- return pComPin;
-}
-
-void
-DShowSrcManager::freeMediaType(AM_MEDIA_TYPE& mt)
-{
- if ( mt.cbFormat != 0 )
- CoTaskMemFree((PVOID)mt.pbFormat);
-
- if ( mt.pUnk != NULL )
- mt.pUnk->Release();
-}
-
bool
DShowSrcManager::getJustCapDevice(const char *devLongName,
IBindCtx **ppBindCtx,
- IMoniker **ppMoniker)
+ IMoniker **ppMoniker) const
{
HRESULT hr;
@@ -395,7 +376,7 @@
void
DShowSrcManager::sprintDeviceInfo(IMoniker * pM, IBindCtx * pbc,
- char* idBuff, char *descBuff, int buffsSize)
+ char* idBuff, char *descBuff, int buffsSize) const
{
USES_CONVERSION;
@@ -454,16 +435,18 @@
}
IPin *
-DShowSrcManager::getInPin( IBaseFilter * pFilter, int nPin )
+DShowSrcManager::getOutPin( IBaseFilter * pFilter, int nPin ) const
{
CComPtr<IPin> pComPin = 0;
- getPin(pFilter, PINDIR_INPUT, nPin, &pComPin);
+
+ getPin(pFilter, PINDIR_OUTPUT, nPin, &pComPin);
+
return pComPin;
}
HRESULT
DShowSrcManager::getPin( IBaseFilter * pFilter, PIN_DIRECTION dirrequired,
- int iNum, IPin **ppPin)
+ int iNum, IPin **ppPin) const
{
*ppPin = NULL;
@@ -505,7 +488,7 @@
// Allocates and returns the friendlyName and displayName for a device
int
DShowSrcManager::getDeviceInfo(IMoniker * pM, IBindCtx * pbc,
- char** easyName, char **longName)
+ char** easyName, char **longName) const
{
USES_CONVERSION;
Modified: trunk/src/directshow/DShowSrcManager.h
===================================================================
--- trunk/src/directshow/DShowSrcManager.h 2007-09-11 18:43:51 UTC (rev 15)
+++ trunk/src/directshow/DShowSrcManager.h 2007-09-12 13:57:59 UTC (rev 16)
@@ -38,7 +38,7 @@
public:
static DShowSrcManager * instance();
- int scan(struct sapi_src_list *);
+ int scan(struct sapi_src_list *) const;
// for device event notifications (additions and removals)
int registerNotifyCallback(void *);
@@ -51,12 +51,9 @@
typedef bool (*cancelCallbackFunc)(IMediaEventEx *, void *);
static bool cancelSrcCaptureCallback(IMediaEventEx *, void *);
- IPin * getOutPin( IBaseFilter *, int);
- IPin * getInPin( IBaseFilter *, int);
- void freeMediaType(AM_MEDIA_TYPE& mt);
bool getJustCapDevice(const char *devLongName,
IBindCtx **ppBindCtx,
- IMoniker **ppMoniker);
+ IMoniker **ppMoniker) const;
bool okayToBuildSource(const char *);
void sourceReleased(const char *id);
void release();
@@ -64,7 +61,7 @@
private:
static DShowSrcManager *instance_;
int numRefs_;
- std::vector<const char *> sourceIDs_;
+ std::vector<const char *> acquiredSourceIDs_;
DevMonitor devMon_;
GraphMonitor *graphMon_;
@@ -79,10 +76,11 @@
std::vector<srcGraphContext *> srcGraphList_;
private:
- HRESULT getPin( IBaseFilter *, PIN_DIRECTION, int, IPin **);
+ IPin * getOutPin( IBaseFilter *, int) const;
+ HRESULT getPin( IBaseFilter *, PIN_DIRECTION, int, IPin **) const;
int getDeviceInfo(IMoniker * pM, IBindCtx * pbc,
- char** easyName, char **longName);
- void sprintDeviceInfo(IMoniker *, IBindCtx *, char *, char *, int);
+ char** easyName, char **longName) const;
+ void sprintDeviceInfo(IMoniker *, IBindCtx *, char *, char *, int) const;
};
#endif
Modified: trunk/src/directshow/DirectShowSource.cpp
===================================================================
--- trunk/src/directshow/DirectShowSource.cpp 2007-09-11 18:43:51 UTC (rev 15)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-12 13:57:59 UTC (rev 16)
@@ -173,7 +173,7 @@
dshowMgr_->unregisterSrcGraph(pMediaEventIF_);
if ( nativeMediaType_ )
- dshowMgr_->freeMediaType(*nativeMediaType_);
+ freeMediaType(*nativeMediaType_);
// These below were initialized in constructor
pMediaEventIF_->Release();
@@ -380,7 +380,7 @@
if ( !findBestFormat(fmtNominal, fmtNative, &mediaFormat) )
return 0;
- dshowMgr_->freeMediaType(*mediaFormat);
+ freeMediaType(*mediaFormat);
return 1;
}
@@ -392,7 +392,7 @@
// If we've already got one, free it
if ( nativeMediaType_ )
{
- dshowMgr_->freeMediaType(*nativeMediaType_);
+ freeMediaType(*nativeMediaType_);
nativeMediaType_ = 0;
}
@@ -415,7 +415,7 @@
{
log_error("failed setting stream format (%d)\n", hr);
- dshowMgr_->freeMediaType(*nativeMediaType_);
+ freeMediaType(*nativeMediaType_);
nativeMediaType_ = 0;
return 1;
@@ -549,7 +549,7 @@
{
// NOT the chosen one?
if ( !itCanWork || iFmt != bestFmtNum )
- dshowMgr_->freeMediaType(*candidateFmtProps[iFmt].mediaFormat);
+ freeMediaType(*candidateFmtProps[iFmt].mediaFormat);
}
}
@@ -604,7 +604,7 @@
fmtNominal->width > scc.MaxOutputSize.cx ||
fmtNominal->height > scc.MaxOutputSize.cy )
{
- dshowMgr_->freeMediaType(*pMediaType);
+ freeMediaType(*pMediaType);
return false;
}
@@ -632,7 +632,7 @@
if ( !matchesWidth || !matchesHeight )
{
- dshowMgr_->freeMediaType(*pMediaType);
+ freeMediaType(*pMediaType);
return false;
}
@@ -648,7 +648,7 @@
// check framerate
if ( fps > fpsMax )
{
- dshowMgr_->freeMediaType(*pMediaType);
+ freeMediaType(*pMediaType);
return false;
}
@@ -661,7 +661,7 @@
if ( mapDirectShowMediaTypeToVidcapFourcc(
pMediaType->subtype.Data1, nativeFourcc) )
{
- dshowMgr_->freeMediaType(*pMediaType);
+ freeMediaType(*pMediaType);
return false;
}
@@ -671,7 +671,7 @@
{
if ( conv_conversion_func_get(nativeFourcc, fmtNominal->fourcc) == 0 )
{
- dshowMgr_->freeMediaType(*pMediaType);
+ freeMediaType(*pMediaType);
return false;
}
}
@@ -700,6 +700,16 @@
}
void
+DirectShowSource::freeMediaType(AM_MEDIA_TYPE &mediaType) const
+{
+ if ( mediaType.cbFormat != 0 )
+ CoTaskMemFree((PVOID)mediaType.pbFormat);
+
+ if ( mediaType.pUnk != NULL )
+ mediaType.pUnk->Release();
+}
+
+void
DirectShowSource::cancelCallbacks()
{
// serialize with normal capture callbacks
@@ -721,7 +731,6 @@
stop();
}
-// Fake out interface queries
STDMETHODIMP
DirectShowSource::QueryInterface(REFIID riid, void ** ppv)
{
@@ -737,8 +746,7 @@
return E_NOINTERFACE;
}
-// The sample grabber is calling us back on its deliver thread.
-// This is NOT the main app thread!
+// The sample grabber calls us back from its deliver thread
STDMETHODIMP
DirectShowSource::BufferCB( double dblSampleTime, BYTE * pBuff, long buffSize )
{
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-11 18:43:51 UTC (rev 15)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-12 13:57:59 UTC (rev 16)
@@ -47,8 +47,7 @@
void cancelCallbacks();
- const char *
- getID() const
+ const char * getID() const
{
return sourceContext_->src_info.identifier;
}
@@ -63,21 +62,21 @@
bool findBestFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative, AM_MEDIA_TYPE **mediaFormat) const;
- // Fake out COM reference counting
+ void freeMediaType(AM_MEDIA_TYPE &) const;
+
+ // Fake out COM
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
+ STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
- // Fake out interface querying
- STDMETHODIMP
- QueryInterface(REFIID riid, void ** ppv);
+ // Not used
+ STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample )
+ {
+ return S_OK;
+ }
- // We don't implement this one
+ // The sample grabber calls us back from its deliver thread
STDMETHODIMP
- SampleCB( double SampleTime, IMediaSample * pSample ) { return S_OK; }
-
- // The sample grabber is calling us back on its deliver thread.
- // This is NOT the main app thread
- STDMETHODIMP
BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize );
static int mapDirectShowMediaTypeToVidcapFourcc(DWORD data, int & fourcc);
@@ -85,7 +84,6 @@
private:
struct sapi_src_context * sourceContext_;
DShowSrcManager * dshowMgr_;
-
IBaseFilter * pSource_;
ICaptureGraphBuilder2 *pCapGraphBuilder_;
IAMStreamConfig * pStreamConfig_;
@@ -94,11 +92,8 @@
IBaseFilter * pSampleGrabber_;
ISampleGrabber * pSampleGrabberIF_;
IBaseFilter * pNullRenderer_;
-
IMediaControl * pMediaControlIF_;
-
AM_MEDIA_TYPE *nativeMediaType_;
-
CRITICAL_SECTION captureMutex_;
bool stoppingCapture_;
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-13 13:05:23
|
Revision: 18
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=18&view=rev
Author: bcholew
Date: 2007-09-13 06:05:21 -0700 (Thu, 13 Sep 2007)
Log Message:
-----------
When cancelling capture callbacks, stop() capture before calling final callback. This removes the need for a mutex to protect capture_callback from simultaneous access by cancelCallbacks() and an actual capture callback ( BufferCB() ).
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-12 18:05:45 UTC (rev 17)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-13 13:05:21 UTC (rev 18)
@@ -50,8 +50,7 @@
pSampleGrabberIF_(0),
pNullRenderer_(0),
pMediaControlIF_(0),
- nativeMediaType_(0),
- stoppingCapture_(false)
+ nativeMediaType_(0)
{
if ( !dshowMgr_ )
{
@@ -146,8 +145,6 @@
// FIXME: Is this too early? Should we only do it during captures?
dshowMgr_->registerSrcGraph(this, pMediaEventIF_);
- InitializeCriticalSection(&captureMutex_);
-
return;
constructionFailure:
@@ -189,8 +186,6 @@
pCapGraphBuilder_->Release();
dshowMgr_->sourceReleased( getID() );
-
- DeleteCriticalSection(&captureMutex_);
}
void
@@ -336,10 +331,8 @@
pSampleGrabber_->Release();
pSampleGrabber_ = 0;
bail_1:
- EnterCriticalSection(&captureMutex_);
pMediaControlIF_->Release();
pMediaControlIF_ = 0;
- LeaveCriticalSection(&captureMutex_);
return -1;
}
@@ -367,10 +360,7 @@
DirectShowSource::stop()
{
int ret = 0;
- stoppingCapture_ = true;
- EnterCriticalSection(&captureMutex_);
-
if ( pMediaControlIF_ )
{
HRESULT hr = pMediaControlIF_->Stop();
@@ -382,10 +372,6 @@
}
}
- LeaveCriticalSection(&captureMutex_);
-
- stoppingCapture_ = false;
-
return ret;
}
@@ -732,23 +718,18 @@
void
DirectShowSource::cancelCallbacks()
{
- // serialize with normal capture callbacks
- EnterCriticalSection(&captureMutex_);
-
- // only cancel callbacks once (unless re-registered)
+ // have capture callbacks already been cancelled?
if ( !sourceContext_->capture_callback )
- {
- LeaveCriticalSection(&captureMutex_);
return;
- }
- // call capture callback - but let the
+ // stop callbacks BEFORE thinking of
+ // touching sourceContext_->capture_callback
+ stop();
+
+ // call capture callback - but let vidcap and the
// app know that this is the last time
+ // (vidcap will reset capture_callback)
sapi_src_capture_notify(sourceContext_, 0, 0, -1);
-
- LeaveCriticalSection(&captureMutex_);
-
- stop();
}
STDMETHODIMP
@@ -770,22 +751,12 @@
STDMETHODIMP
DirectShowSource::BufferCB( double dblSampleTime, BYTE * pBuff, long buffSize )
{
- // prevent deadlock while stopping
- if ( stoppingCapture_ )
- return 0;
-
- EnterCriticalSection(&captureMutex_);
-
if ( !sourceContext_->capture_callback )
return 0;
- int ret = sapi_src_capture_notify(sourceContext_,
+ return sapi_src_capture_notify(sourceContext_,
reinterpret_cast<const char *>(pBuff),
static_cast<int>(buffSize), 0);
-
- LeaveCriticalSection(&captureMutex_);
-
- return ret;
}
int
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-12 18:05:45 UTC (rev 17)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-13 13:05:21 UTC (rev 18)
@@ -96,8 +96,6 @@
IBaseFilter * pNullRenderer_;
IMediaControl * pMediaControlIF_;
AM_MEDIA_TYPE *nativeMediaType_;
- CRITICAL_SECTION captureMutex_;
- bool stoppingCapture_;
};
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-13 19:54:29
|
Revision: 21
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=21&view=rev
Author: bcholew
Date: 2007-09-13 12:53:30 -0700 (Thu, 13 Sep 2007)
Log Message:
-----------
Employ static mutex to prevent source destruction while it's capture callbacks are being cancelled by monitor thread (because of device removal). Consolidate acquiredSourceIDs_ into list of srcGraphContext structures. Consolidate unregisterSrcGraph() functionality into sourceRelease(). Move initialization of pMediaControlIF_ to source constructor (and Release to destructor). Use flag captureIsSetup_ to denote when capture graph foo has been setup for a source and given format (instead of pMediaControlIF_).
Modified Paths:
--------------
trunk/src/directshow/DShowSrcManager.cpp
trunk/src/directshow/DShowSrcManager.h
trunk/src/directshow/DirectShowSource.cpp
trunk/src/directshow/DirectShowSource.h
Modified: trunk/src/directshow/DShowSrcManager.cpp
===================================================================
--- trunk/src/directshow/DShowSrcManager.cpp 2007-09-13 19:25:43 UTC (rev 20)
+++ trunk/src/directshow/DShowSrcManager.cpp 2007-09-13 19:53:30 UTC (rev 21)
@@ -38,10 +38,14 @@
#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);
@@ -58,11 +62,11 @@
{
delete graphMon_;
- acquiredSourceIDs_.erase( acquiredSourceIDs_.begin(),
- acquiredSourceIDs_.end() );
srcGraphList_.erase( srcGraphList_.begin(), srcGraphList_.end() );
CoUninitialize();
+
+ DeleteCriticalSection(&sourceDestructionMutex_);
}
DShowSrcManager *
@@ -94,49 +98,42 @@
}
void
-DShowSrcManager::registerSrcGraph(void *src, IMediaEventEx *pME)
+DShowSrcManager::registerSrcGraph(const char *id, void *src, IMediaEventEx *pME)
{
- // create a context with all relevant info
- srcGraphContext *pSrcGraphContext = new srcGraphContext();
- pSrcGraphContext->pME = pME;
- pSrcGraphContext->pSrc = src;
-
- // add source graph context to list
- srcGraphList_.push_back(pSrcGraphContext);
-
- // request that GraphMonitor monitor the graph for errors
- graphMon_->addGraph(pME);
-}
-
-void
-DShowSrcManager::unregisterSrcGraph(IMediaEventEx *pME)
-{
- // find appropriate source in list
+ // find appropriate source id in list
for ( unsigned int i = 0; i < srcGraphList_.size(); i++ )
{
- // found matching MediaEvent interface?
- if ( srcGraphList_[i]->pME == pME )
+ // found matching id?
+ if ( srcGraphList_[i]->sourceId == id )
{
- // remove entry from srcGraphList_
- srcGraphContext *pSrcGraphContext = srcGraphList_[i];
-
- srcGraphList_.erase( srcGraphList_.begin() + i );
-
- delete pSrcGraphContext;
-
- // request that GraphMonitor stop monitoring the graph for errors
- graphMon_->removeGraph(pME);
- return;
+ // fill-in relevant info
+ srcGraphList_[i]->pSrc = src;
+ srcGraphList_[i]->pME = pME;
+
+ // request that GraphMonitor monitor the graph for errors
+ graphMon_->addGraph(pME);
}
}
- log_warn("failed to find source to unregister for monitoring\n");
}
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++ )
{
@@ -144,17 +141,18 @@
if ( self->srcGraphList_[i]->pME == pME )
{
// Found source to cancel callbacks for
- // Call canceller
DirectShowSource * pSrc =
static_cast<DirectShowSource *>(self->srcGraphList_[i]->pSrc);
// cancel the source's callback
pSrc->cancelCallbacks();
- return true;
+ ret = true;
+ break;
}
}
+ LeaveCriticalSection(&sourceDestructionMutex_);
- return false;
+ return ret;
}
int
@@ -254,10 +252,10 @@
bool
DShowSrcManager::okayToBuildSource(const char *id)
{
- // Enforce exclusive access to a source
- for ( unsigned int i = 0; i < acquiredSourceIDs_.size(); i++ )
+ // find appropriate source in list
+ for ( unsigned int i = 0; i < srcGraphList_.size(); i++ )
{
- if ( !strcmp(acquiredSourceIDs_[i], id) )
+ if ( !strcmp(srcGraphList_[i]->sourceId, id) )
{
// a source with this id already exists - and was acquired
log_warn("source already acquired: '%s'\n", id);
@@ -265,26 +263,49 @@
}
}
+ srcGraphContext *pSrcGraphContext = new srcGraphContext();
+ pSrcGraphContext->sourceId = id;
+
+ // these will be filled in later by registerSrcGraph()
+ pSrcGraphContext->pME = 0;
+ pSrcGraphContext->pSrc = 0;
+
// add source to collection
- acquiredSourceIDs_.push_back(id);
+ srcGraphList_.push_back(pSrcGraphContext);
return true;
}
void DShowSrcManager::sourceReleased(const char *id)
{
- for ( unsigned int i = 0; i < acquiredSourceIDs_.size(); i++ )
+ // NOTE: see note in function cancelSrcCaptureCallback()
+ EnterCriticalSection(&sourceDestructionMutex_);
+
+ // find appropriate source id in list
+ for ( unsigned int i = 0; i < srcGraphList_.size(); i++ )
{
- if ( !strcmp(acquiredSourceIDs_[i], id) )
+ // found matching source id?
+ if ( srcGraphList_[i]->sourceId == id )
{
// found source with matching id
- acquiredSourceIDs_.erase( acquiredSourceIDs_.begin() + i );
+ // remove entry from srcGraphList_
+ srcGraphContext *pSrcGraphContext = srcGraphList_[i];
+ 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);
}
Modified: trunk/src/directshow/DShowSrcManager.h
===================================================================
--- trunk/src/directshow/DShowSrcManager.h 2007-09-13 19:25:43 UTC (rev 20)
+++ trunk/src/directshow/DShowSrcManager.h 2007-09-13 19:53:30 UTC (rev 21)
@@ -44,8 +44,7 @@
int registerNotifyCallback(void *);
// to monitor for graph errors during capture
- void registerSrcGraph(void *, IMediaEventEx *);
- void unregisterSrcGraph(IMediaEventEx *pME);
+ void registerSrcGraph(const char *, void *, IMediaEventEx *);
// graphMon_ callback to request capture abort
typedef bool (*cancelCallbackFunc)(IMediaEventEx *, void *);
@@ -61,7 +60,6 @@
private:
static DShowSrcManager *instance_;
int numRefs_;
- std::vector<const char *> acquiredSourceIDs_;
DevMonitor devMon_;
GraphMonitor *graphMon_;
@@ -70,11 +68,17 @@
{
IMediaEventEx * pME;
void * pSrc;
+ const char * sourceId;
};
- // list of sources and their filter graphs
+ // list of acquired sources, their filter graphs, 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-13 19:25:43 UTC (rev 20)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-13 19:53:30 UTC (rev 21)
@@ -50,7 +50,8 @@
pSampleGrabberIF_(0),
pNullRenderer_(0),
pMediaControlIF_(0),
- nativeMediaType_(0)
+ nativeMediaType_(0),
+ captureIsSetup_(false)
{
if ( !dshowMgr_ )
{
@@ -141,14 +142,24 @@
goto constructionFailure;
}
+ hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
+ (void **)&pMediaControlIF_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed getting Media Control interface (%d)\n", hr);
+ goto constructionFailure;
+ }
+
// register filter graph - to monitor for errors during capture
- // FIXME: Is this too early? Should we only do it during captures?
- dshowMgr_->registerSrcGraph(this, pMediaEventIF_);
+ dshowMgr_->registerSrcGraph(src->src_info.identifier, this, pMediaEventIF_);
return;
constructionFailure:
+ if ( pMediaControlIF_ )
+ pMediaControlIF_->Release();
+
if ( pFilterGraph_ )
pFilterGraph_->Release();
@@ -169,12 +180,14 @@
cleanupCaptureGraphFoo();
- dshowMgr_->unregisterSrcGraph(pMediaEventIF_);
-
if ( nativeMediaType_ )
freeMediaType(*nativeMediaType_);
// These below were initialized in constructor
+ if ( pMediaControlIF_ )
+ pMediaControlIF_->Release();
+ pMediaControlIF_ = 0;
+
pMediaEventIF_->Release();
pFilterGraph_->Release();
@@ -203,25 +216,15 @@
pSampleGrabber_->Release();
pSampleGrabber_ = 0;
- if ( pMediaControlIF_ )
- pMediaControlIF_->Release();
- pMediaControlIF_ = 0;
+ captureIsSetup_ = false;
}
int
DirectShowSource::setupCaptureGraphFoo()
{
- if ( !pMediaControlIF_ )
+ if ( !captureIsSetup_ )
{
- HRESULT hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
- (void **)&pMediaControlIF_);
- if ( FAILED(hr) )
- {
- log_error("failed getting Media Control interface (%d)\n", hr);
- return -1;
- }
-
- hr = CoCreateInstance(CLSID_SampleGrabber,
+ HRESULT hr = CoCreateInstance(CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
@@ -229,7 +232,7 @@
if ( FAILED(hr) )
{
log_error("failed creating Sample Grabber (%d)\n", hr);
- goto bail_1;
+ return -1;
}
hr = pSampleGrabber_->QueryInterface(IID_ISampleGrabber,
@@ -237,7 +240,7 @@
if ( FAILED(hr) )
{
log_error("failed getting ISampleGrabber interface (%d)\n", hr);
- goto bail_2;
+ goto bail_1;
}
// Capture more than once
@@ -245,14 +248,14 @@
if ( FAILED(hr) )
{
log_error("failed SetOneShot (%d)\n", hr);
- goto bail_3;
+ goto bail_2;
}
hr = pSampleGrabberIF_->SetBufferSamples(FALSE);
if ( FAILED(hr) )
{
log_error("failed SetBufferSamples (%d)\n", hr);
- goto bail_3;
+ goto bail_2;
}
// set which callback type and function to use
@@ -260,7 +263,7 @@
if ( FAILED(hr) )
{
log_error("failed to set callback (%d)\n", hr);
- goto bail_3;
+ goto bail_2;
}
// Set sample grabber's media type to match that of the source
@@ -268,7 +271,7 @@
if ( FAILED(hr) )
{
log_error("failed to set grabber media type (%d)\n", hr);
- goto bail_3;
+ goto bail_2;
}
hr = CoCreateInstance(CLSID_NullRenderer,
@@ -280,7 +283,7 @@
if ( FAILED(hr) )
{
log_error("failed creating a NULL renderer (%d)\n", hr);
- goto bail_3;
+ goto bail_2;
}
//FIXME: use actual device name
@@ -288,7 +291,7 @@
if ( FAILED(hr) )
{
log_error("failed to add source (%d)\n", hr);
- goto bail_4;
+ goto bail_3;
}
hr = pFilterGraph_->AddFilter(pSampleGrabber_, L"Sample Grabber");
@@ -296,14 +299,14 @@
{
log_error("failed to add Sample Grabber to filter graph (%d)\n",
hr);
- goto bail_4;
+ goto bail_3;
}
hr = pFilterGraph_->AddFilter(pNullRenderer_, L"NullRenderer");
if ( FAILED(hr) )
{
log_error("failed to add null renderer (%d)\n", hr);
- goto bail_4;
+ goto bail_3;
}
hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
@@ -315,24 +318,23 @@
{
log_error("failed to connect source, grabber "
"and null renderer (%d)\n", hr);
- goto bail_4;
+ goto bail_3;
}
+
+ captureIsSetup_ = true;
}
return 0;
-bail_4:
+bail_3:
pNullRenderer_->Release();
pNullRenderer_ = 0;
-bail_3:
+bail_2:
pSampleGrabberIF_->Release();
pSampleGrabberIF_ = 0;
-bail_2:
+bail_1:
pSampleGrabber_->Release();
pSampleGrabber_ = 0;
-bail_1:
- pMediaControlIF_->Release();
- pMediaControlIF_ = 0;
return -1;
}
@@ -359,20 +361,18 @@
int
DirectShowSource::stop()
{
- int ret = 0;
-
- if ( pMediaControlIF_ )
+ if ( captureIsSetup_ )
{
HRESULT hr = pMediaControlIF_->Stop();
if ( FAILED(hr) )
{
log_error("failed to STOP the filter graph (0x%0x)\n", hr);
- ret = -1;
+ return -1;
}
}
- return ret;
+ return 0;
}
int
@@ -718,11 +718,11 @@
void
DirectShowSource::cancelCallbacks()
{
- // have capture callbacks already been cancelled?
+ // have buffer callbacks already been cancelled?
if ( !sourceContext_->capture_callback )
return;
- // stop callbacks BEFORE thinking of
+ // stop callbacks before thinking of
// touching sourceContext_->capture_callback
stop();
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-13 19:25:43 UTC (rev 20)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-13 19:53:30 UTC (rev 21)
@@ -96,6 +96,7 @@
IBaseFilter * pNullRenderer_;
IMediaControl * pMediaControlIF_;
AM_MEDIA_TYPE *nativeMediaType_;
+ bool captureIsSetup_;
};
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
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.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-20 17:51:52
|
Revision: 26
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=26&view=rev
Author: bcholew
Date: 2007-09-20 10:51:50 -0700 (Thu, 20 Sep 2007)
Log Message:
-----------
ove AddFilter() of pSource_ and pNullRenderer to construction time. This simplifies the code, and has the added benefit of reducing the memory leak that exists when using the MS LifeCam NX-6000 in scenarios that re-bind a source. Move setting of pStreamConfig_'s format from bind time (in main thread) to capture start time (in source thread). This keeps the main thread running smoothly if/when this operation blocks for a while. Return failure at bind time if we fail to remove the sample grabber from the filter graph. Rename a flag.
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-18 18:38:47 UTC (rev 25)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-20 17:51:50 UTC (rev 26)
@@ -51,7 +51,7 @@
pNullRenderer_(0),
pMediaControlIF_(0),
nativeMediaType_(0),
- captureIsSetup_(false),
+ graphIsSetup_(false),
eventInitDone_(0),
eventStart_(0),
eventStop_(0),
@@ -287,6 +287,20 @@
return -1;
}
+ hr = pFilterGraph_->AddFilter(pSource_, L"Source Device");
+ if ( FAILED(hr) )
+ {
+ log_error("failed to add source (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pFilterGraph_->AddFilter(pNullRenderer_, L"NullRenderer");
+ if ( FAILED(hr) )
+ {
+ log_error("failed to add null renderer (%d)\n", hr);
+ return -1;
+ }
+
return 0;
}
@@ -466,47 +480,45 @@
return 0;
}
-void
+int
DirectShowSource::resetCapGraphFoo()
{
- if ( captureIsSetup_ )
+ if ( graphIsSetup_ )
{
- // some or all of this appears to be necessary to allow
- // subsequent captures with a different media type
- HRESULT hr = pFilterGraph_->RemoveFilter(pSource_);
- if ( FAILED(hr) )
- log_error("failed to remove source (%d)\n", hr);
+ graphIsSetup_ = false;
- hr = pFilterGraph_->RemoveFilter(pSampleGrabber_);
+ // necessary to allow subsequent calls to RenderStream()
+ // (like after rebinding) to succeed
+ HRESULT hr = pFilterGraph_->RemoveFilter(pSampleGrabber_);
if ( FAILED(hr) )
- log_error("failed to remove Sample Grabber (%d)\n",
- hr);
-
- hr = pFilterGraph_->RemoveFilter(pNullRenderer_);
- if ( FAILED(hr) )
- log_error("failed to remove null renderer (%d)\n", hr);
-
- captureIsSetup_ = false;
+ {
+ log_error("failed to remove Sample Grabber (%d)\n", hr);
+ return 1;
+ }
}
+
+ return 0;
}
int
DirectShowSource::setupCapGraphFoo()
{
- if ( !captureIsSetup_ )
+ if ( !graphIsSetup_ )
{
- // Set sample grabber's media type to match that of the source
- HRESULT hr = pSampleGrabberIF_->SetMediaType(nativeMediaType_);
+ // set the stream's media type
+ HRESULT hr = pStreamConfig_->SetFormat(nativeMediaType_);
if ( FAILED(hr) )
{
- log_error("failed to set grabber media type (%d)\n", hr);
+ log_error("failed setting stream format (%d)\n", hr);
+
return -1;
}
- hr = pFilterGraph_->AddFilter(pSource_, L"Source Device");
+ // Set sample grabber's media type
+ hr = pSampleGrabberIF_->SetMediaType(nativeMediaType_);
if ( FAILED(hr) )
{
- log_error("failed to add source (%d)\n", hr);
+ log_error("failed to set grabber media type (%d)\n", hr);
return -1;
}
@@ -517,13 +529,6 @@
return -1;
}
- hr = pFilterGraph_->AddFilter(pNullRenderer_, L"NullRenderer");
- if ( FAILED(hr) )
- {
- log_error("failed to add null renderer (%d)\n", hr);
- return -1;
- }
-
hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video,
pSource_,
@@ -536,7 +541,7 @@
return -1;
}
- captureIsSetup_ = true;
+ graphIsSetup_ = true;
}
return 0;
@@ -577,7 +582,6 @@
if ( !setupCapGraphFoo() )
{
HRESULT hr = pMediaControlIF_->Run();
-
if ( SUCCEEDED(hr) )
return;
else
@@ -593,7 +597,7 @@
int
DirectShowSource::stop()
{
- // signal to source thread to stop capturing
+ // signal to source thread to stop capturing
if ( !SetEvent(eventStop_) )
{
log_error("failed to signal source to stop (%d)\n",
@@ -607,7 +611,7 @@
void
DirectShowSource::doStop()
{
- if ( captureIsSetup_ )
+ if ( graphIsSetup_ )
{
HRESULT hr = pMediaControlIF_->Stop();
if ( FAILED(hr) )
@@ -655,21 +659,7 @@
vih->bmiHeader.biWidth = fmtNative.width;
vih->bmiHeader.biHeight = fmtNative.height;
- resetCapGraphFoo();
-
- // set the stream's media type
- HRESULT hr = pStreamConfig_->SetFormat(nativeMediaType_);
- if ( FAILED(hr) )
- {
- log_error("failed setting stream format (%d)\n", hr);
-
- freeMediaType(*nativeMediaType_);
- nativeMediaType_ = 0;
-
- return 1;
- }
-
- return 0;
+ return resetCapGraphFoo();
}
bool
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-18 18:38:47 UTC (rev 25)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-20 17:51:50 UTC (rev 26)
@@ -62,7 +62,7 @@
int createCapGraphFoo();
void destroyCapGraphFoo();
int setupCapGraphFoo();
- void resetCapGraphFoo();
+ int resetCapGraphFoo();
bool checkFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative,
int formatNum,
@@ -104,7 +104,7 @@
IBaseFilter * pNullRenderer_;
IMediaControl * pMediaControlIF_;
AM_MEDIA_TYPE *nativeMediaType_;
- bool captureIsSetup_;
+ bool graphIsSetup_;
HANDLE eventInitDone_;
HANDLE eventStart_;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-28 21:21:03
|
Revision: 35
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=35&view=rev
Author: bcholew
Date: 2007-09-28 14:20:58 -0700 (Fri, 28 Sep 2007)
Log Message:
-----------
Make capture stop synchronous. Move callback cancellation to source thread. Enforce state to prevent loss of rapid start/stop command events. Synchronize main, capture and source threads to prevent callbacks after capture stop. Give terminate command highest priority in source thread processing - followed by callback cancellation. Reduce chance of blocking indefinitely when attempting to start capture while source is being removed. No longer necessary to reset capture graph foo following a bind. If reset of capture graph foo fails, repeat graph stop attempt immediately.
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-28 17:44:03 UTC (rev 34)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-28 21:20:58 UTC (rev 35)
@@ -56,8 +56,15 @@
eventStart_(0),
eventStop_(0),
eventTerminate_(0),
+ eventCancel_(0),
sourceThread_(0),
- sourceThreadID_(0)
+ sourceThreadID_(0),
+ okToSendStart_(true),
+ okToSendStop_(true),
+ allowCallbacks_(false),
+ callbackInProgress_(false),
+ callbackCancellationInProgress_(false),
+ captureStopped_(true)
{
if ( !dshowMgr_ )
{
@@ -401,6 +408,25 @@
return -1;
}
+ // create an event used to signal thread to cancel capture
+ eventCancel_ = CreateEvent(
+ NULL, // default security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is clear
+ NULL // no name
+ );
+
+ if ( eventCancel_ == NULL)
+ {
+ log_error("DirectShowSource: failed creating cancel event (%d)\n",
+ GetLastError());
+ CloseHandle(eventInitDone_);
+ CloseHandle(eventStart_);
+ CloseHandle(eventStop_);
+ CloseHandle(eventTerminate_);
+ return -1;
+ }
+
return 0;
}
@@ -418,14 +444,13 @@
return -1;
}
- enum { startEventIndex = 0, stopEventIndex,
+ enum { cancelEventIndex = 0, startEventIndex, 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[cancelEventIndex] = pSrc->eventCancel_;
waitHandles[startEventIndex] = pSrc->eventStart_;
waitHandles[stopEventIndex] = pSrc->eventStop_;
waitHandles[terminateEventIndex] = pSrc->eventTerminate_;
@@ -444,10 +469,29 @@
{
log_warn("source wait failed. (0x%x)\n", GetLastError());
}
+ else if ( index == terminateEventIndex )
+ {
+ // give terminate the highest priority
+
+ pSrc->terminate();
+ break;
+ }
+ else if ( index == cancelEventIndex )
+ {
+ // give cancel a higher priority than start/stop
+
+ if ( !ResetEvent(pSrc->eventCancel_) )
+ {
+ log_error("failed to reset source start event flag."
+ "Terminating.\n");
+ // terminate
+ break;
+ }
+
+ pSrc->doCancelCallbacks();
+ }
else if ( index == startEventIndex )
{
- pSrc->doStart();
-
if ( !ResetEvent(pSrc->eventStart_) )
{
log_error("failed to reset source start event flag."
@@ -455,11 +499,13 @@
// terminate
break;
}
+
+ pSrc->okToSendStop_ = true;
+
+ pSrc->doStart();
}
else if ( index == stopEventIndex )
{
- pSrc->doStop();
-
if ( !ResetEvent(pSrc->eventStop_) )
{
log_error("failed to reset source stop event flag."
@@ -467,12 +513,11 @@
// terminate
break;
}
+
+ pSrc->okToSendStart_ = true;
+
+ pSrc->doStop();
}
- else if ( index == terminateEventIndex )
- {
- pSrc->terminate();
- break;
- }
}
delete [] waitHandles;
@@ -491,11 +536,32 @@
if ( FAILED(hr) )
{
log_error("failed to remove Sample Grabber (%d)\n", hr);
+
+ //FIXME: is this still necessary? Does it still work?
if ( hr == VFW_E_NOT_STOPPED )
{
- log_error("Capture wasn't stopped. "
- "Repeating STOP request...\n");
- stop();
+ log_error("Capture wasn't stopped. Repeating STOP...\n");
+
+ HRESULT hr = pMediaControlIF_->Stop();
+ if ( FAILED(hr) )
+ {
+ log_error("failed in 2nd STOP attempt (0x%0x)\n", hr);
+ }
+ else
+ {
+ HRESULT hr = pFilterGraph_->RemoveFilter(pSampleGrabber_);
+ if ( FAILED(hr) )
+ {
+ // this is silly
+ log_error("failed twice to remove sample grabber (%d)",
+ hr);
+ }
+ else
+ {
+ graphIsSetup_ = false;
+ return 0;
+ }
+ }
}
else
{
@@ -575,7 +641,12 @@
int
DirectShowSource::start()
{
- // signal to source thread to start capturing
+ if ( !okToSendStart_ )
+ return -1;
+
+ okToSendStart_ = false;
+
+ // signal source thread to start capturing
if ( !SetEvent(eventStart_) )
{
log_error("failed to signal source to start (%d)\n",
@@ -591,36 +662,66 @@
{
if ( !setupCapGraphFoo() )
{
+ allowCallbacks_ = true;
+
HRESULT hr = pMediaControlIF_->Run();
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);
+
+ log_error("failed to run filter graph for source '%s' (%ul 0x%x)\n",
+ sourceContext_->src_info.description, hr, hr);
}
+ else
+ okToSendStart_ = true;
- // call capture callback - with error status
- // (vidcap will reset capture_callback)
+ allowCallbacks_ = false;
+
+ // final capture callback - with error status
sapi_src_capture_notify(sourceContext_, 0, 0, -1);
}
+// NOTE: This function will block until capture is
+// completely stopped.
+// Even when returning failure, it guarantees
+// no more callbacks will occur
int
DirectShowSource::stop()
{
- // signal to source thread to stop capturing
+ while ( !okToSendStop_ )
+ Sleep(10);
+
+ okToSendStop_ = false;
+
+ captureStopped_ = false;
+
+ // signal source thread to stop capturing
if ( !SetEvent(eventStop_) )
{
log_error("failed to signal source to stop (%d)\n",
GetLastError());
+
+ // Need to ensure no more callbacks arrive
+ // Do this the hard way
+ allowCallbacks_ = false;
+ while ( callbackInProgress_ || callbackCancellationInProgress_ )
+ Sleep(10);
+
return -1;
}
+ // wait for source thread to indicate that capture has stopped
+ // guaranteeing no more callbacks will occur after this returns
+ while ( !captureStopped_ )
+ Sleep(10);
+
return 0;
}
void
DirectShowSource::doStop()
{
+ allowCallbacks_ = false;
+
if ( graphIsSetup_ )
{
HRESULT hr = pMediaControlIF_->Stop();
@@ -628,7 +729,24 @@
{
log_error("failed to STOP the filter graph (0x%0x)\n", hr);
}
+
+ // If source was removed while not capturing (following a stop),
+ // graph's Run() could block forever. The RenderStream(), however,
+ // would fail. Therefore, call resetCapGraphFoo() whenever
+ // stopping, to force RenderStream() to validate setup before
+ // any start (and reduce likelihood of Run() blocking forever).
+ //
+ // And if source is effectively removed after
+ // RenderStream(), but before graph's Run()?
+ resetCapGraphFoo();
}
+
+ // make sure we're not in a callback
+ while ( callbackInProgress_ )
+ Sleep(10);
+
+ // signal back to main thread that capture has stopped
+ captureStopped_ = true;
}
int
@@ -669,7 +787,7 @@
vih->bmiHeader.biWidth = fmtNative.width;
vih->bmiHeader.biHeight = fmtNative.height;
- return resetCapGraphFoo();
+ return 0;
}
bool
@@ -960,18 +1078,53 @@
void
DirectShowSource::cancelCallbacks()
{
- // have buffer callbacks already been cancelled?
- if ( !sourceContext_->capture_callback )
+ // signal source thread to cancel capturing
+ if ( !SetEvent(eventCancel_) )
+ {
+ log_error("failed to signal source to cancel (%d)\n",
+ GetLastError());
+
+ // Need to ensure app is notified
+ // Do it the hard way
+
+ // prevent future callbacks
+ allowCallbacks_ = false;
+
+ // wait for current callback to finish
+ while ( callbackInProgress_ )
+ Sleep(10);
+
+ // final capture callback - with error status
+ sapi_src_capture_notify(sourceContext_, 0, 0, -1);
+ }
+}
+
+void
+DirectShowSource::doCancelCallbacks()
+{
+ callbackCancellationInProgress_ = true;
+
+ // has capture been stopped already?
+ if ( !allowCallbacks_ )
+ {
+ callbackCancellationInProgress_ = false;
return;
+ }
- // stop callbacks before thinking of
- // touching sourceContext_->capture_callback
- stop();
+ // prevent future callbacks
+ allowCallbacks_ = false;
- // call capture callback - but let vidcap and the
- // app know that this is the last time
- // (vidcap will reset capture_callback)
+ // block until current callback is not in progress
+ while ( callbackInProgress_ )
+ Sleep(10);
+
+ // stop callbacks before sending final callback
+ doStop();
+
+ // final capture callback - with error status
sapi_src_capture_notify(sourceContext_, 0, 0, -1);
+
+ callbackCancellationInProgress_ = false;
}
STDMETHODIMP
@@ -989,16 +1142,27 @@
return E_NOINTERFACE;
}
-// The sample grabber calls us back from its deliver thread
+// The sample grabber calls this from its deliver thread
+// NOTE: This function must not block, else it will cause a
+// graph's Stop() to block - which could result in a deadlock
STDMETHODIMP
DirectShowSource::BufferCB( double dblSampleTime, BYTE * pBuff, long buffSize )
{
- if ( !sourceContext_->capture_callback )
+ callbackInProgress_ = true;
+
+ if ( !allowCallbacks_ )
+ {
+ callbackInProgress_ = false;
return 0;
+ }
- return sapi_src_capture_notify(sourceContext_,
+ int ret = sapi_src_capture_notify(sourceContext_,
reinterpret_cast<const char *>(pBuff),
static_cast<int>(buffSize), 0);
+
+ callbackInProgress_ = false;
+
+ return ret;
}
int
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-28 17:44:03 UTC (rev 34)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-28 21:20:58 UTC (rev 35)
@@ -41,12 +41,11 @@
int start();
int stop();
+ void cancelCallbacks();
int bindFormat(const vidcap_fmt_info * fmtInfo);
int validateFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative) const;
- void cancelCallbacks();
-
const char * getID() const
{
return sourceContext_->src_info.identifier;
@@ -57,6 +56,7 @@
void terminate();
void doStart();
void doStop();
+ void doCancelCallbacks();
int createEvents();
int createCapGraphFoo();
@@ -110,8 +110,16 @@
HANDLE eventStart_;
HANDLE eventStop_;
HANDLE eventTerminate_;
+ HANDLE eventCancel_;
void * sourceThread_;
DWORD sourceThreadID_;
+
+ bool okToSendStart_;
+ bool okToSendStop_;
+ bool allowCallbacks_;
+ bool callbackInProgress_;
+ bool callbackCancellationInProgress_;
+ bool captureStopped_;
};
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-10-01 21:47:33
|
Revision: 39
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=39&view=rev
Author: bcholew
Date: 2007-10-01 14:47:31 -0700 (Mon, 01 Oct 2007)
Log Message:
-----------
Remove function sprintDeviceInfo(), in favor of function getDeviceInfo(). Alter DShowSrcManager::scan() to use getDeviceInfo(). Move function getJustCapDevice from DShowSrcManager to DirectShowSource. Move getDeviceInfo from DShowSrcManager to new base class DirectShowObject. Derive DirectShowSource and DShowSrcManager from this new class. Remove references to DShowSrcMgr in DirectShowSource.
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/SourceStateMachine.cpp
Added Paths:
-----------
trunk/src/directshow/DirectShowObject.cpp
trunk/src/directshow/DirectShowObject.h
Modified: trunk/src/directshow/DShowSrcManager.cpp
===================================================================
--- trunk/src/directshow/DShowSrcManager.cpp 2007-10-01 19:42:06 UTC (rev 38)
+++ trunk/src/directshow/DShowSrcManager.cpp 2007-10-01 21:47:31 UTC (rev 39)
@@ -158,12 +158,19 @@
srcInfo = &srcList->list[newListLen - 1];
- //FIXME: rename to getDeviceId()
- sprintDeviceInfo(pM, pbc,
- srcInfo->identifier, srcInfo->description,
- min(sizeof(srcInfo->identifier),
- sizeof(srcInfo->description)));
+ // get device description and ID
+ char *tempDesc;
+ char *tempID;
+ getDeviceInfo(pM, pbc, &tempDesc, &tempID);
+ sprintf_s(srcInfo->description, sizeof(srcInfo->description),
+ "%s", tempDesc);
+ sprintf_s(srcInfo->identifier, sizeof(srcInfo->identifier),
+ "%s", tempID);
+
+ free(tempID);
+ free(tempDesc);
+
clean_continue:
if ( pCaptureFilter )
pCaptureFilter->Release();
@@ -233,150 +240,7 @@
log_warn("couldn't find source '%s' to release\n", id);
}
-bool
-DShowSrcManager::getJustCapDevice(const char *devLongName,
- IBindCtx **ppBindCtx,
- IMoniker **ppMoniker) const
-{
- HRESULT hr;
- // Create an enumerator
- CComPtr<ICreateDevEnum> pCreateDevEnum;
-
- pCreateDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum);
-
- if ( !pCreateDevEnum )
- {
- log_error("failed creating device enumerator - to get a source\n");
- return false;
- }
-
- // Enumerate video capture devices
- CComPtr<IEnumMoniker> pEm;
-
- pCreateDevEnum->CreateClassEnumerator(
- CLSID_VideoInputDeviceCategory, &pEm, 0);
-
- if ( !pEm )
- {
- log_error("failed creating enumerator moniker\n");
- return false;
- }
-
- pEm->Reset();
-
- ULONG ulFetched;
- IMoniker * pM;
-
- // Iterate over all video capture devices
- int i=0;
- while ( pEm->Next(1, &pM, &ulFetched) == S_OK )
- {
- IBindCtx *pbc;
-
- hr = CreateBindCtx(0, &pbc);
-
- if ( FAILED(hr) )
- {
- log_error("failed CreateBindCtx\n");
- pM->Release();
- return false;
- }
-
- // Get the device names
- char *shortName;
- char *longName;
- if ( getDeviceInfo(pM, pbc, &shortName, &longName) )
- {
- log_warn("failed to get device info.\n");
- pbc->Release();
- continue;
- }
-
- // Compare with the desired dev name
- if ( !strcmp(longName, devLongName) )
- {
- // Got the correct device
- *ppMoniker = pM;
- *ppBindCtx = pbc;
-
- free(shortName);
- free(longName);
- return true;
- }
-
- // Wrong device. Cleanup and try again
- free(shortName);
- free(longName);
-
- pbc->Release();
- }
-
- pM->Release();
-
- return false;
-}
-
-void
-DShowSrcManager::sprintDeviceInfo(IMoniker * pM, IBindCtx * pbc,
- char* idBuff, char *descBuff, int buffsSize) const
-{
- USES_CONVERSION;
-
- HRESULT hr;
-
- CComPtr< IMalloc > pMalloc;
-
- hr = CoGetMalloc(1, &pMalloc);
-
- if ( FAILED(hr) )
- {
- log_error("failed CoGetMalloc\n");
- return;
- }
-
- LPOLESTR pDisplayName;
-
- hr = pM->GetDisplayName(pbc, 0, &pDisplayName);
-
- if ( FAILED(hr) )
- {
- log_warn("failed GetDisplayName\n");
- return;
- }
-
- // This gets stack memory, no dealloc needed.
- char * pszDisplayName = OLE2A(pDisplayName);
-
- pMalloc->Free(pDisplayName);
-
- CComPtr< IPropertyBag > pPropBag;
-
- hr = pM->BindToStorage(pbc, 0, IID_IPropertyBag,
- (void **)&pPropBag);
-
- if ( FAILED(hr) )
- {
- log_error("failed getting video device property bag\n");
- return;
- }
-
- VARIANT v;
- VariantInit(&v);
-
- char * pszFriendlyName = 0;
-
- hr = pPropBag->Read(L"FriendlyName", &v, 0);
-
- if ( SUCCEEDED(hr) )
- pszFriendlyName = _com_util::ConvertBSTRToString(v.bstrVal);
-
- sprintf_s(descBuff, buffsSize, "%s", pszFriendlyName);
- sprintf_s(idBuff, buffsSize, "%s", pszDisplayName);
-
- delete [] pszFriendlyName;
-}
-
IPin *
DShowSrcManager::getOutPin( IBaseFilter * pFilter, int nPin ) const
{
@@ -428,68 +292,3 @@
return hr;
}
-// Allocates and returns the friendlyName and displayName for a device
-int
-DShowSrcManager::getDeviceInfo(IMoniker * pM, IBindCtx * pbc,
- char** easyName, char **longName) const
-{
- USES_CONVERSION;
-
- HRESULT hr;
-
- CComPtr< IMalloc > pMalloc;
-
- hr = CoGetMalloc(1, &pMalloc);
-
- if ( FAILED(hr) )
- {
- log_error("failed CoGetMalloc\n");
- return 1;
- }
-
- LPOLESTR pDisplayName;
-
- hr = pM->GetDisplayName(pbc, 0, &pDisplayName);
-
- if ( FAILED(hr) )
- {
- log_warn("failed GetDisplayName\n");
- return 1;
- }
-
- // This gets stack memory, no dealloc needed.
- char * pszDisplayName = OLE2A(pDisplayName);
-
- // Allocate a copy of this long name
- *longName = _strdup(pszDisplayName);
-
- pMalloc->Free(pDisplayName);
-
- CComPtr< IPropertyBag > pPropBag;
-
- hr = pM->BindToStorage(pbc, 0, IID_IPropertyBag,
- (void **)&pPropBag);
-
- if ( FAILED(hr) )
- {
- log_warn("failed getting video device property bag\n");
- return 1;
- }
-
- VARIANT v;
- VariantInit(&v);
-
- char * pszFriendlyName = 0;
-
- hr = pPropBag->Read(L"FriendlyName", &v, 0);
-
- if ( SUCCEEDED(hr) )
- pszFriendlyName =
- _com_util::ConvertBSTRToString(v.bstrVal);
-
- // Allocate a copy of this short name
- *easyName = _strdup(pszFriendlyName);
-
- delete [] pszFriendlyName;
- return 0;
-}
Modified: trunk/src/directshow/DShowSrcManager.h
===================================================================
--- trunk/src/directshow/DShowSrcManager.h 2007-10-01 19:42:06 UTC (rev 38)
+++ trunk/src/directshow/DShowSrcManager.h 2007-10-01 21:47:31 UTC (rev 39)
@@ -26,9 +26,10 @@
#define _DSHOWSRCMANAGER_H_
#include <vector>
+#include "DirectShowObject.h"
#include "DevMonitor.h"
-class DShowSrcManager
+class DShowSrcManager : public DirectShowObject
{
protected:
@@ -42,9 +43,6 @@
// for device event notifications (additions and removals)
int registerNotifyCallback(void *);
- bool getJustCapDevice(const char *devLongName,
- IBindCtx **ppBindCtx,
- IMoniker **ppMoniker) const;
bool okayToBuildSource(const char *);
void sourceReleased(const char *id);
void release();
@@ -67,9 +65,6 @@
private:
IPin * getOutPin( IBaseFilter *, int) const;
HRESULT getPin( IBaseFilter *, PIN_DIRECTION, int, IPin **) const;
- int getDeviceInfo(IMoniker * pM, IBindCtx * pbc,
- char** easyName, char **longName) const;
- void sprintDeviceInfo(IMoniker *, IBindCtx *, char *, char *, int) const;
};
#endif
Added: trunk/src/directshow/DirectShowObject.cpp
===================================================================
--- trunk/src/directshow/DirectShowObject.cpp (rev 0)
+++ trunk/src/directshow/DirectShowObject.cpp 2007-10-01 21:47:31 UTC (rev 39)
@@ -0,0 +1,97 @@
+//
+// 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/>.
+//
+
+#include <windows.h>
+#include <atlbase.h>
+#include <comutil.h>
+
+#include "DirectShowObject.h"
+#include "logging.h"
+
+// Allocates and returns the description and ID for a given device
+int
+DirectShowObject::getDeviceInfo(IMoniker * pM, IBindCtx * pbc,
+ char ** description, char **ID) const
+{
+ USES_CONVERSION;
+
+ HRESULT hr;
+
+ CComPtr< IMalloc > pMalloc;
+
+ hr = CoGetMalloc(1, &pMalloc);
+
+ if ( FAILED(hr) )
+ {
+ log_error("failed CoGetMalloc\n");
+ return 1;
+ }
+
+ LPOLESTR pDisplayName;
+
+ hr = pM->GetDisplayName(pbc, 0, &pDisplayName);
+
+ if ( FAILED(hr) )
+ {
+ log_warn("failed GetDisplayName\n");
+ return 1;
+ }
+
+ // This gets stack memory, no dealloc needed.
+ char * pszDisplayName = OLE2A(pDisplayName);
+
+ // Allocate a copy of this identifier
+ *ID = _strdup(pszDisplayName);
+
+ pMalloc->Free(pDisplayName);
+
+ CComPtr< IPropertyBag > pPropBag;
+
+ hr = pM->BindToStorage(pbc, 0, IID_IPropertyBag,
+ (void **)&pPropBag);
+
+ if ( FAILED(hr) )
+ {
+ log_warn("failed getting video device property bag\n");
+ return 1;
+ }
+
+ VARIANT v;
+ VariantInit(&v);
+
+ char * pszFriendlyName = 0;
+
+ hr = pPropBag->Read(L"FriendlyName", &v, 0);
+
+ if ( SUCCEEDED(hr) )
+ pszFriendlyName =
+ _com_util::ConvertBSTRToString(v.bstrVal);
+
+ // Allocate a copy of this description
+ *description = _strdup(pszFriendlyName);
+
+ delete [] pszFriendlyName;
+ return 0;
+}
+
Added: trunk/src/directshow/DirectShowObject.h
===================================================================
--- trunk/src/directshow/DirectShowObject.h (rev 0)
+++ trunk/src/directshow/DirectShowObject.h 2007-10-01 21:47:31 UTC (rev 39)
@@ -0,0 +1,41 @@
+//
+// 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 _DIRECTSHOWOBJECT_H_
+#define _DIRECTSHOWOBJECT_H_
+
+class DirectShowObject
+{
+
+public:
+ DirectShowObject() { };
+ ~DirectShowObject() { };
+
+protected:
+ int getDeviceInfo(IMoniker * pM, IBindCtx * pbc,
+ char ** descr, char **ID) const;
+};
+
+#endif
+
Modified: trunk/src/directshow/DirectShowSource.cpp
===================================================================
--- trunk/src/directshow/DirectShowSource.cpp 2007-10-01 19:42:06 UTC (rev 38)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-10-01 21:47:31 UTC (rev 39)
@@ -37,9 +37,8 @@
#include "DirectShowSource.h"
DirectShowSource::DirectShowSource(struct sapi_src_context *src,
- DShowSrcManager *mgr, bufferCallbackFunc cbFunc, cancelCaptureFunc cancelCaptureCB, void * parent)
+ bufferCallbackFunc cbFunc, cancelCaptureFunc cancelCaptureCB, void * parent)
: sourceContext_(src),
- dshowMgr_(mgr),
bufferCB_(cbFunc),
cancelCaptureCB_(cancelCaptureCB),
parent_(parent),
@@ -61,8 +60,7 @@
IMoniker * pMoniker = 0;
// Get the capture device - identified by it's long display name
- if ( !dshowMgr_->getJustCapDevice(getID(), &pBindCtx, &pMoniker) )
- {
+ if ( !getCaptureDevice(getID(), &pBindCtx, &pMoniker) ){
log_warn("Failed to get device '%s'.\n", getID());
throw std::runtime_error("failed to get device");
}
@@ -280,9 +278,6 @@
if ( pCapGraphBuilder_ )
pCapGraphBuilder_->Release();
-
- if ( graphHandle_ )
- CloseHandle(graphHandle_);
}
int
@@ -1111,3 +1106,86 @@
}
}
+bool
+DirectShowSource::getCaptureDevice(const char *devLongName,
+ IBindCtx **ppBindCtx,
+ IMoniker **ppMoniker) const
+{
+ HRESULT hr;
+
+ // Create an enumerator
+ CComPtr<ICreateDevEnum> pCreateDevEnum;
+
+ pCreateDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum);
+
+ if ( !pCreateDevEnum )
+ {
+ log_error("failed creating device enumerator - to get a source\n");
+ return false;
+ }
+
+ // Enumerate video capture devices
+ CComPtr<IEnumMoniker> pEm;
+
+ pCreateDevEnum->CreateClassEnumerator(
+ CLSID_VideoInputDeviceCategory, &pEm, 0);
+
+ if ( !pEm )
+ {
+ log_error("failed creating enumerator moniker\n");
+ return false;
+ }
+
+ pEm->Reset();
+
+ ULONG ulFetched;
+ IMoniker * pM;
+
+ // Iterate over all video capture devices
+ int i=0;
+ while ( pEm->Next(1, &pM, &ulFetched) == S_OK )
+ {
+ IBindCtx *pbc;
+
+ hr = CreateBindCtx(0, &pbc);
+
+ if ( FAILED(hr) )
+ {
+ log_error("failed CreateBindCtx\n");
+ pM->Release();
+ return false;
+ }
+
+ // Get the device names
+ char *shortName;
+ char *longName;
+ if ( getDeviceInfo(pM, pbc, &shortName, &longName) )
+ {
+ log_warn("failed to get device info.\n");
+ pbc->Release();
+ continue;
+ }
+
+ // Compare with the desired dev name
+ if ( !strcmp(longName, devLongName) )
+ {
+ // Got the correct device
+ *ppMoniker = pM;
+ *ppBindCtx = pbc;
+
+ free(shortName);
+ free(longName);
+ return true;
+ }
+
+ // Wrong device. Cleanup and try again
+ free(shortName);
+ free(longName);
+
+ pbc->Release();
+ }
+
+ pM->Release();
+
+ return false;
+}
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-10-01 19:42:06 UTC (rev 38)
+++ trunk/src/directshow/DirectShowSource.h 2007-10-01 21:47:31 UTC (rev 39)
@@ -34,14 +34,14 @@
#include "sapi_context.h"
#include "GraphMonitor.h"
-class DirectShowSource : public ISampleGrabberCB
+class DirectShowSource : public ISampleGrabberCB, public DirectShowObject
{
public:
typedef int (*bufferCallbackFunc)(double, BYTE *, long, void *);
typedef void (*cancelCaptureFunc)(void *);
- DirectShowSource(struct sapi_src_context *, DShowSrcManager *,
+ DirectShowSource(struct sapi_src_context *,
bufferCallbackFunc, cancelCaptureFunc, void *);
~DirectShowSource();
@@ -69,11 +69,12 @@
int formatNum,
bool *needsFramerateEnforcing, bool *needsFormatConversion,
AM_MEDIA_TYPE **candidateMediaFormat) const;
-
bool findBestFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative, AM_MEDIA_TYPE **mediaFormat) const;
-
void freeMediaType(AM_MEDIA_TYPE &) const;
+ bool getCaptureDevice(const char *devLongName,
+ IBindCtx **ppBindCtx,
+ IMoniker **ppMoniker) const;
// Fake out COM
STDMETHODIMP_(ULONG) AddRef() { return 2; }
Modified: trunk/src/directshow/GraphMonitor.cpp
===================================================================
--- trunk/src/directshow/GraphMonitor.cpp 2007-10-01 19:42:06 UTC (rev 38)
+++ trunk/src/directshow/GraphMonitor.cpp 2007-10-01 21:47:31 UTC (rev 39)
@@ -85,7 +85,6 @@
}
DWORD rc = WaitForSingleObject(initDoneEvent_, INFINITE);
- //FIXME: consider a timeout
return;
@@ -144,7 +143,6 @@
DWORD rc = WaitForMultipleObjects(static_cast<DWORD>(numHandles),
waitHandles, false, INFINITE);
-
// get index of object that signaled
unsigned int index = rc - WAIT_OBJECT_0;
Modified: trunk/src/directshow/SourceStateMachine.cpp
===================================================================
--- trunk/src/directshow/SourceStateMachine.cpp 2007-10-01 19:42:06 UTC (rev 38)
+++ trunk/src/directshow/SourceStateMachine.cpp 2007-10-01 21:47:31 UTC (rev 39)
@@ -70,7 +70,6 @@
try
{
src_ = new DirectShowSource(src,
- mgr,
(bufferCallbackFunc)&SourceStateMachine::bufferCB,
(cancelCaptureFunc)&SourceStateMachine::cancelCaptureCB,
this);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. <lib...@li...> - 2007-12-03 14:09:59
|
Revision: 73
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=73&view=rev
Author: bcholew
Date: 2007-12-03 06:09:55 -0800 (Mon, 03 Dec 2007)
Log Message:
-----------
Use abstracted thread and mutex functions in directshow sapi.
Modified Paths:
--------------
trunk/src/directshow/DevMonitor.cpp
trunk/src/directshow/DevMonitor.h
trunk/src/directshow/GraphMonitor.cpp
trunk/src/directshow/GraphMonitor.h
trunk/src/directshow/SourceStateMachine.cpp
trunk/src/directshow/SourceStateMachine.h
Modified: trunk/src/directshow/DevMonitor.cpp
===================================================================
--- trunk/src/directshow/DevMonitor.cpp 2007-12-03 14:09:08 UTC (rev 72)
+++ trunk/src/directshow/DevMonitor.cpp 2007-12-03 14:09:55 UTC (rev 73)
@@ -39,7 +39,7 @@
szWindowClass_(0),
sapiCtx_(0)
{
- InitializeCriticalSection(®istrationMutex_);
+ vc_mutex_init(®istrationMutex_);
// create an event used to signal that the thread has been created
initDoneEvent_ = CreateEvent(
@@ -86,15 +86,9 @@
}
// pass instance to thread
- devMonitorThread_ = CreateThread(
- NULL,
- 0,
- (LPTHREAD_START_ROUTINE)(&DevMonitor::monitorDevices),
- this,
- 0,
- &devMonitorThreadID_);
-
- if ( devMonitorThread_ == NULL )
+ if ( vc_create_thread(&devMonitorThread_,
+ &DevMonitor::monitorDevices,
+ this, &devMonitorThreadID_) )
{
log_error("DevMonitor: failed spinning DevMonitor thread (%d)\n",
GetLastError());
@@ -131,7 +125,7 @@
return;
}
- DWORD rc = WaitForSingleObject(devMonitorThread_, INFINITE);
+ DWORD rc = WaitForSingleObject((HANDLE)devMonitorThread_, INFINITE);
if ( rc == WAIT_FAILED )
{
@@ -145,7 +139,7 @@
GetLastError());
}
- DeleteCriticalSection(®istrationMutex_);
+ vc_mutex_destroy(®istrationMutex_);
}
LRESULT CALLBACK
@@ -181,13 +175,13 @@
return 0;
}
-DWORD WINAPI
-DevMonitor::monitorDevices(LPVOID lpParam)
+unsigned int
+DevMonitor::monitorDevices(void * param)
{
//FIXME: move window creation to constructor
// extract instance
- DevMonitor * pDevMon = (DevMonitor *)lpParam;
+ DevMonitor * pDevMon = (DevMonitor *)param;
// Create a window, so main thread can communicate with us
pDevMon->windowHandle_ = CreateWindow(
@@ -285,7 +279,7 @@
}
log_info("[[ Device event: %s ]]\n", str.c_str());
- EnterCriticalSection(&pDevMon->registrationMutex_);
+ vc_mutex_lock(&pDevMon->registrationMutex_);
if ( sapiCtx &&
sapiCtx->notify_callback )
@@ -302,7 +296,7 @@
log_info("[[ no user-defined handler registered ]]\n");
}
- LeaveCriticalSection(&pDevMon->registrationMutex_);
+ vc_mutex_unlock(&pDevMon->registrationMutex_);
default:
str.assign("");
@@ -321,11 +315,11 @@
if ( !sapiCtx )
return -1;
- EnterCriticalSection(®istrationMutex_);
+ vc_mutex_lock(®istrationMutex_);
sapiCtx_ = sapiCtx;
- LeaveCriticalSection(®istrationMutex_);
+ vc_mutex_unlock(®istrationMutex_);
return 0;
}
Modified: trunk/src/directshow/DevMonitor.h
===================================================================
--- trunk/src/directshow/DevMonitor.h 2007-12-03 14:09:08 UTC (rev 72)
+++ trunk/src/directshow/DevMonitor.h 2007-12-03 14:09:55 UTC (rev 73)
@@ -36,26 +36,23 @@
int registerCallback(void *);
private:
- static LRESULT __stdcall
- processWindowsMsgs(HWND, UINT, WPARAM, LPARAM);
+ static LRESULT __stdcall processWindowsMsgs(HWND, UINT, WPARAM, LPARAM);
+ static unsigned int STDCALL monitorDevices(void * lpParam);
- static DWORD WINAPI
- monitorDevices(LPVOID lpParam);
-
private:
HANDLE initDoneEvent_;
enum threadStatusEnum { initializing=0, initFailed, initDone };
threadStatusEnum threadStatus_;
HWND windowHandle_;
- void * devMonitorThread_;
- DWORD devMonitorThreadID_;
+ vc_thread devMonitorThread_;
+ unsigned int devMonitorThreadID_;
TCHAR * szTitle_;
TCHAR * szWindowClass_;
void * sapiCtx_;
- CRITICAL_SECTION registrationMutex_;
+ vc_mutex registrationMutex_;
};
#endif
Modified: trunk/src/directshow/GraphMonitor.cpp
===================================================================
--- trunk/src/directshow/GraphMonitor.cpp 2007-12-03 14:09:08 UTC (rev 72)
+++ trunk/src/directshow/GraphMonitor.cpp 2007-12-03 14:09:55 UTC (rev 73)
@@ -68,15 +68,9 @@
}
// create thread, pass instance
- graphMonitorThread_ = CreateThread(
- NULL,
- 0,
- (LPTHREAD_START_ROUTINE)(&GraphMonitor::monitorGraph),
- this,
- 0,
- &graphMonitorThreadID_);
-
- if ( graphMonitorThread_ == NULL )
+ if ( vc_create_thread(&graphMonitorThread_,
+ &GraphMonitor::monitorGraph,
+ this, &graphMonitorThreadID_) )
{
log_error("GraphMonitor: failed spinning GraphMonitor thread (%d)\n",
GetLastError());
@@ -99,7 +93,7 @@
}
// wait for thread to shutdown
- DWORD rc = WaitForSingleObject(graphMonitorThread_, INFINITE);
+ DWORD rc = WaitForSingleObject((HANDLE)graphMonitorThread_, INFINITE);
if ( rc == WAIT_FAILED )
{
@@ -110,11 +104,11 @@
log_info("graph monitor thread destroyed\n");
}
-DWORD WINAPI
-GraphMonitor::monitorGraph(LPVOID lpParam)
+unsigned int
+GraphMonitor::monitorGraph(void * param)
{
// extract instance
- GraphMonitor * pGraphMon = (GraphMonitor *)lpParam;
+ GraphMonitor * pGraphMon = (GraphMonitor *)param;
// signal that thread is ready
if ( !SetEvent(pGraphMon->initDoneEvent_) )
Modified: trunk/src/directshow/GraphMonitor.h
===================================================================
--- trunk/src/directshow/GraphMonitor.h 2007-12-03 14:09:08 UTC (rev 72)
+++ trunk/src/directshow/GraphMonitor.h 2007-12-03 14:09:55 UTC (rev 73)
@@ -25,7 +25,7 @@
#ifndef _GRAPHMONITOR_H_
#define _GRAPHMONITOR_H_
-#include <windows.h>
+#include "os_funcs.h"
class GraphMonitor
{
@@ -37,7 +37,7 @@
~GraphMonitor();
private:
- static DWORD WINAPI monitorGraph(LPVOID lpParam);
+ static unsigned int STDCALL monitorGraph(void * param);
private:
HANDLE *graphHandle_;
@@ -47,8 +47,8 @@
HANDLE initDoneEvent_;
HANDLE terminateEvent_;
- void * graphMonitorThread_;
- DWORD graphMonitorThreadID_;
+ vc_thread graphMonitorThread_;
+ unsigned int graphMonitorThreadID_;
};
#endif
Modified: trunk/src/directshow/SourceStateMachine.cpp
===================================================================
--- trunk/src/directshow/SourceStateMachine.cpp 2007-12-03 14:09:08 UTC (rev 72)
+++ trunk/src/directshow/SourceStateMachine.cpp 2007-12-03 14:09:55 UTC (rev 73)
@@ -85,15 +85,9 @@
}
// pass instance to thread
- sourceThread_ = CreateThread(
- NULL,
- 0,
- (LPTHREAD_START_ROUTINE)(&SourceStateMachine::waitForCmd),
- this,
- 0,
- &sourceThreadID_);
-
- if ( sourceThread_ != NULL )
+ if ( !vc_create_thread(&sourceThread_,
+ &SourceStateMachine::waitForCmd,
+ this, &sourceThreadID_) )
{
// wait for signal from thread that it is ready
WaitForSingleObject(eventInitDone_, INFINITE);
@@ -123,7 +117,7 @@
}
// wait for thread to shutdown
- DWORD rc = WaitForSingleObject(sourceThread_, INFINITE);
+ DWORD rc = WaitForSingleObject((HANDLE)sourceThread_, INFINITE);
if ( rc == WAIT_FAILED )
{
@@ -231,11 +225,11 @@
return 0;
}
-DWORD WINAPI
-SourceStateMachine::waitForCmd(LPVOID lpParam)
+unsigned int
+SourceStateMachine::waitForCmd(void *param)
{
// extract instance
- SourceStateMachine * pSrc = (SourceStateMachine *)lpParam;
+ SourceStateMachine * pSrc = (SourceStateMachine *)param;
// signal to main thread that we are ready for commands
if ( !SetEvent(pSrc->eventInitDone_) )
Modified: trunk/src/directshow/SourceStateMachine.h
===================================================================
--- trunk/src/directshow/SourceStateMachine.h 2007-12-03 14:09:08 UTC (rev 72)
+++ trunk/src/directshow/SourceStateMachine.h 2007-12-03 14:09:55 UTC (rev 73)
@@ -47,7 +47,7 @@
}
private:
- static DWORD WINAPI waitForCmd(LPVOID);
+ static unsigned int STDCALL waitForCmd(void *);
void terminate();
void doStart();
void doStop();
@@ -70,8 +70,8 @@
HANDLE eventStop_;
HANDLE eventTerminate_;
HANDLE eventCancel_;
- void * sourceThread_;
- DWORD sourceThreadID_;
+ vc_thread sourceThread_;
+ unsigned int sourceThreadID_;
bool okToSendStart_;
bool okToSendStop_;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. <lib...@li...> - 2007-12-12 19:45:51
|
Revision: 80
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=80&view=rev
Author: bcholew
Date: 2007-12-12 11:45:41 -0800 (Wed, 12 Dec 2007)
Log Message:
-----------
remove unnecessary includes
Modified Paths:
--------------
trunk/src/directshow/DirectShowSource.cpp
trunk/src/directshow/DirectShowSource.h
Modified: trunk/src/directshow/DirectShowSource.cpp
===================================================================
--- trunk/src/directshow/DirectShowSource.cpp 2007-12-04 21:34:32 UTC (rev 79)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-12-12 19:45:41 UTC (rev 80)
@@ -27,7 +27,6 @@
#include <cstdio>
#include <cwchar>
#include <atlbase.h>
-#include <qedit.h>
#include <comutil.h>
#include <vidcap/converters.h>
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-12-04 21:34:32 UTC (rev 79)
+++ trunk/src/directshow/DirectShowSource.h 2007-12-12 19:45:41 UTC (rev 80)
@@ -26,7 +26,6 @@
#define _DIRECTSHOWSOURCE_H_
#include <stdexcept>
-#include <atlbase.h>
#include <qedit.h>
#include <DShow.h>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-12 18:05:47
|
Revision: 17
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=17&view=rev
Author: bcholew
Date: 2007-09-12 11:05:45 -0700 (Wed, 12 Sep 2007)
Log Message:
-----------
Add functions to setup and cleanup capture graph foo. Cleanup capture graph foo at bind time and in destructor. Only setup capture graph foo at capture start time if it's not already been done.
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-12 13:57:59 UTC (rev 16)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-12 18:05:45 UTC (rev 17)
@@ -170,6 +170,8 @@
{
stop();
+ cleanupCaptureGraphFoo();
+
dshowMgr_->unregisterSrcGraph(pMediaEventIF_);
if ( nativeMediaType_ )
@@ -191,130 +193,139 @@
DeleteCriticalSection(&captureMutex_);
}
-int
-DirectShowSource::start()
+void
+DirectShowSource::cleanupCaptureGraphFoo()
{
- HRESULT hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
- (void **)&pMediaControlIF_);
- if ( FAILED(hr) )
- {
- log_error("failed getting Media Control interface (%d)\n", hr);
- return -1;
- }
+ if ( pNullRenderer_ )
+ pNullRenderer_->Release();
+ pNullRenderer_ = 0;
- hr = CoCreateInstance(CLSID_SampleGrabber,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- (void **)&pSampleGrabber_);
- if ( FAILED(hr) )
- {
- log_error("failed creating Sample Grabber (%d)\n", hr);
- goto bail_1;
- }
+ if ( pSampleGrabberIF_ )
+ pSampleGrabberIF_->Release();
+ pSampleGrabberIF_ = 0;
- hr = pSampleGrabber_->QueryInterface(IID_ISampleGrabber,
- (void**)&pSampleGrabberIF_);
- if ( FAILED(hr) )
- {
- log_error("failed getting ISampleGrabber interface (%d)\n", hr);
- goto bail_2;
- }
+ if ( pSampleGrabber_ )
+ pSampleGrabber_->Release();
+ pSampleGrabber_ = 0;
- // Capture more than once
- hr = pSampleGrabberIF_->SetOneShot(FALSE);
- if ( FAILED(hr) )
- {
- log_error("failed SetOneShot (%d)\n", hr);
- goto bail_3;
- }
+ if ( pMediaControlIF_ )
+ pMediaControlIF_->Release();
+ pMediaControlIF_ = 0;
+}
- hr = pSampleGrabberIF_->SetBufferSamples(FALSE);
- if ( FAILED(hr) )
+int
+DirectShowSource::setupCaptureGraphFoo()
+{
+ if ( !pMediaControlIF_ )
{
- log_error("failed SetBufferSamples (%d)\n", hr);
- goto bail_3;
- }
+ HRESULT hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
+ (void **)&pMediaControlIF_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed getting Media Control interface (%d)\n", hr);
+ return -1;
+ }
- // set which callback type and function to use
- hr = pSampleGrabberIF_->SetCallback( this, 1 );
- if ( FAILED(hr) )
- {
- log_error("failed to set callback (%d)\n", hr);
- goto bail_3;
- }
+ hr = CoCreateInstance(CLSID_SampleGrabber,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter,
+ (void **)&pSampleGrabber_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed creating Sample Grabber (%d)\n", hr);
+ goto bail_1;
+ }
- // Set sample grabber's media type to match that of the source
- hr = pSampleGrabberIF_->SetMediaType(nativeMediaType_);
- if ( FAILED(hr) )
- {
- log_error("failed to set grabber media type (%d)\n", hr);
- goto bail_3;
- }
+ hr = pSampleGrabber_->QueryInterface(IID_ISampleGrabber,
+ (void**)&pSampleGrabberIF_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed getting ISampleGrabber interface (%d)\n", hr);
+ goto bail_2;
+ }
- hr = CoCreateInstance(CLSID_NullRenderer,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- (void **)&pNullRenderer_);
+ // Capture more than once
+ hr = pSampleGrabberIF_->SetOneShot(FALSE);
+ if ( FAILED(hr) )
+ {
+ log_error("failed SetOneShot (%d)\n", hr);
+ goto bail_3;
+ }
- if ( FAILED(hr) )
- {
- log_error("failed creating a NULL renderer (%d)\n", hr);
- goto bail_3;
- }
+ hr = pSampleGrabberIF_->SetBufferSamples(FALSE);
+ if ( FAILED(hr) )
+ {
+ log_error("failed SetBufferSamples (%d)\n", hr);
+ goto bail_3;
+ }
- //FIXME: use actual device name
- hr = pFilterGraph_->AddFilter(pSource_, L"Source Device");
- if ( FAILED(hr) )
- {
- log_error("failed to add source (%d)\n", hr);
- goto bail_4;
- }
+ // set which callback type and function to use
+ hr = pSampleGrabberIF_->SetCallback( this, 1 );
+ if ( FAILED(hr) )
+ {
+ log_error("failed to set callback (%d)\n", hr);
+ goto bail_3;
+ }
- hr = pFilterGraph_->AddFilter(pSampleGrabber_, L"Sample Grabber");
- if ( FAILED(hr) )
- {
- log_error("failed to add Sample Grabber to filter graph (%d)\n",
- hr);
- goto bail_4;
- }
+ // Set sample grabber's media type to match that of the source
+ hr = pSampleGrabberIF_->SetMediaType(nativeMediaType_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed to set grabber media type (%d)\n", hr);
+ goto bail_3;
+ }
- hr = pFilterGraph_->AddFilter(pNullRenderer_, L"NullRenderer");
- if ( FAILED(hr) )
- {
- log_error("failed to add null renderer (%d)\n", hr);
- goto bail_4;
- }
+ hr = CoCreateInstance(CLSID_NullRenderer,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter,
+ (void **)&pNullRenderer_);
- hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video,
- pSource_,
- pSampleGrabber_,
- pNullRenderer_);
- if ( FAILED(hr) )
- {
- log_error("failed to connect source, grabber "
- "and null renderer (%d)\n", hr);
- goto bail_4;
- }
+ if ( FAILED(hr) )
+ {
+ log_error("failed creating a NULL renderer (%d)\n", hr);
+ goto bail_3;
+ }
- hr = pMediaControlIF_->Run();
+ //FIXME: use actual device name
+ hr = pFilterGraph_->AddFilter(pSource_, L"Source Device");
+ if ( FAILED(hr) )
+ {
+ log_error("failed to add source (%d)\n", hr);
+ goto bail_4;
+ }
- if ( SUCCEEDED(hr) )
- {
- return 0;
- }
+ hr = pFilterGraph_->AddFilter(pSampleGrabber_, L"Sample Grabber");
+ if ( FAILED(hr) )
+ {
+ log_error("failed to add Sample Grabber to filter graph (%d)\n",
+ hr);
+ goto bail_4;
+ }
- log_error("failed to run filter graph for source '%s' (%ul 0x%x)\n",
- sourceContext_->src_info.description, hr, hr);
+ hr = pFilterGraph_->AddFilter(pNullRenderer_, L"NullRenderer");
+ if ( FAILED(hr) )
+ {
+ log_error("failed to add null renderer (%d)\n", hr);
+ goto bail_4;
+ }
- hr = pMediaControlIF_->Stop();
- if ( FAILED(hr) )
- {
- log_error("failed to STOP filter graph (%ul)\n", hr);
+ hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
+ &MEDIATYPE_Video,
+ pSource_,
+ pSampleGrabber_,
+ pNullRenderer_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed to connect source, grabber "
+ "and null renderer (%d)\n", hr);
+ goto bail_4;
+ }
}
+ return 0;
+
bail_4:
pNullRenderer_->Release();
pNullRenderer_ = 0;
@@ -334,8 +345,28 @@
}
int
+DirectShowSource::start()
+{
+ if ( setupCaptureGraphFoo() )
+ return -1;
+
+ HRESULT hr = pMediaControlIF_->Run();
+
+ if ( FAILED(hr) )
+ {
+ log_error("failed to run filter graph for source '%s' (%ul 0x%x)\n",
+ sourceContext_->src_info.description, hr, hr);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int
DirectShowSource::stop()
{
+ int ret = 0;
stoppingCapture_ = true;
EnterCriticalSection(&captureMutex_);
@@ -345,30 +376,17 @@
HRESULT hr = pMediaControlIF_->Stop();
if ( FAILED(hr) )
{
- log_error("failed to STOP the filter graph (%ul)\n", hr);
+ log_error("failed to STOP the filter graph (0x%0x)\n", hr);
+
+ ret = -1;
}
-
- if ( pNullRenderer_ )
- pNullRenderer_->Release();
- pNullRenderer_ = 0;
-
- if ( pSampleGrabberIF_ )
- pSampleGrabberIF_->Release();
- pSampleGrabberIF_ = 0;
-
- if ( pSampleGrabber_ )
- pSampleGrabber_->Release();
- pSampleGrabber_ = 0;
-
- pMediaControlIF_->Release();
- pMediaControlIF_ = 0;
}
LeaveCriticalSection(&captureMutex_);
stoppingCapture_ = false;
- return 0;
+ return ret;
}
int
@@ -409,6 +427,8 @@
vih->bmiHeader.biWidth = fmtNative.width;
vih->bmiHeader.biHeight = fmtNative.height;
+ cleanupCaptureGraphFoo();
+
// set the stream's media type
HRESULT hr = pStreamConfig_->SetFormat(nativeMediaType_);
if ( FAILED(hr) )
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-12 13:57:59 UTC (rev 16)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-12 18:05:45 UTC (rev 17)
@@ -53,6 +53,8 @@
}
private:
+ int setupCaptureGraphFoo();
+ void cleanupCaptureGraphFoo();
bool checkFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative,
int formatNum,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: libvidcap c. m. <lib...@li...> - 2007-09-18 17:15:04
|
Revision: 23
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=23&view=rev
Author: bcholew
Date: 2007-09-18 10:14:56 -0700 (Tue, 18 Sep 2007)
Log Message:
-----------
Move setup of sampleGrabber_, pSampleGrabberIF_, nullRenderer_ to construction time. Consolidate most of the capture graph tinkering to four functions. Allow subsequent captures with different formats to succeed - by removing filters from capture graph when resetting capture graph foo. Rename and move some functions.
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-17 18:57:01 UTC (rev 22)
+++ trunk/src/directshow/DirectShowSource.cpp 2007-09-18 17:14:56 UTC (rev 23)
@@ -97,65 +97,9 @@
goto constructionFailure;
}
- hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_ICaptureGraphBuilder2,
- (void **)&pCapGraphBuilder_);
-
- if ( FAILED(hr) )
- {
- log_error("failed creating capture graph builder (%d)\n", hr);
+ if ( createCapGraphFoo() )
goto constructionFailure;
- }
- hr = pCapGraphBuilder_->FindInterface(&PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video,
- pSource_,
- IID_IAMStreamConfig,
- (void **)&pStreamConfig_);
- if( FAILED(hr) )
- {
- log_error("failed getting stream config "
- "while building format list (%d)\n", hr);
- pCapGraphBuilder_->Release();
- goto constructionFailure;
- }
-
- hr = CoCreateInstance(CLSID_FilterGraph,
- 0,
- CLSCTX_INPROC_SERVER,
- IID_IGraphBuilder,
- (void **)&pFilterGraph_);
- if ( FAILED(hr) )
- {
- log_error("failed creating the filter graph (%d)\n", hr);
- goto constructionFailure;
- }
-
- hr = pCapGraphBuilder_->SetFiltergraph(pFilterGraph_);
- if ( FAILED(hr) )
- {
- log_error("failed setting the filter graph (%d)\n", hr);
- goto constructionFailure;
- }
-
- hr = pFilterGraph_->QueryInterface(IID_IMediaEventEx,
- (void **)&pMediaEventIF_);
- if ( FAILED(hr) )
- {
- log_error("failed getting IMediaEventEx interface (%d)\n", hr);
- goto constructionFailure;
- }
-
- hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
- (void **)&pMediaControlIF_);
- if ( FAILED(hr) )
- {
- log_error("failed getting Media Control interface (%d)\n", hr);
- goto constructionFailure;
- }
-
// register filter graph - to monitor for errors during capture
dshowMgr_->registerSrcGraph(src->src_info.identifier, this, pMediaEventIF_);
@@ -187,12 +131,8 @@
constructionFailure:
- if ( pMediaControlIF_ )
- pMediaControlIF_->Release();
+ destroyCapGraphFoo();
- if ( pFilterGraph_ )
- pFilterGraph_->Release();
-
if ( pSource_ )
pSource_->Release();
@@ -235,32 +175,147 @@
CloseHandle(eventTerminate_);
}
+int
+DirectShowSource::createCapGraphFoo()
+{
+ HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_ICaptureGraphBuilder2,
+ (void **)&pCapGraphBuilder_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed creating capture graph builder (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pCapGraphBuilder_->FindInterface(&PIN_CATEGORY_CAPTURE,
+ &MEDIATYPE_Video,
+ pSource_,
+ IID_IAMStreamConfig,
+ (void **)&pStreamConfig_);
+ if( FAILED(hr) )
+ {
+ log_error("failed getting stream config (%d)\n", hr);
+ return -1;
+ }
+
+ hr = CoCreateInstance(CLSID_FilterGraph,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_IGraphBuilder,
+ (void **)&pFilterGraph_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed creating the filter graph (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pCapGraphBuilder_->SetFiltergraph(pFilterGraph_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed setting the filter graph (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pFilterGraph_->QueryInterface(IID_IMediaEventEx,
+ (void **)&pMediaEventIF_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed getting IMediaEventEx interface (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pFilterGraph_->QueryInterface(IID_IMediaControl,
+ (void **)&pMediaControlIF_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed getting Media Control interface (%d)\n", hr);
+ return -1;
+ }
+
+ hr = CoCreateInstance(CLSID_NullRenderer,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter,
+ (void **)&pNullRenderer_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed creating a NULL renderer (%d)\n", hr);
+ return -1;
+ }
+
+ hr = CoCreateInstance(CLSID_SampleGrabber,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IBaseFilter,
+ (void **)&pSampleGrabber_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed creating Sample Grabber (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pSampleGrabber_->QueryInterface(IID_ISampleGrabber,
+ (void**)&pSampleGrabberIF_);
+ if ( FAILED(hr) )
+ {
+ log_error("failed getting ISampleGrabber interface (%d)\n", hr);
+ return -1;
+ }
+
+ // Capture more than once
+ hr = pSampleGrabberIF_->SetOneShot(FALSE);
+ if ( FAILED(hr) )
+ {
+ log_error("failed SetOneShot (%d)\n", hr);
+ return -1;
+ }
+
+ hr = pSampleGrabberIF_->SetBufferSamples(FALSE);
+ if ( FAILED(hr) )
+ {
+ log_error("failed SetBufferSamples (%d)\n", hr);
+ return -1;
+ }
+
+ // set which callback type and function to use
+ hr = pSampleGrabberIF_->SetCallback( this, 1 );
+ if ( FAILED(hr) )
+ {
+ log_error("failed to set callback (%d)\n", hr);
+ return -1;
+ }
+
+ return 0;
+}
+
void
-DirectShowSource::terminate()
+DirectShowSource::destroyCapGraphFoo()
{
- doStop();
+ if ( pNullRenderer_ )
+ pNullRenderer_->Release();
- cleanupCaptureGraphFoo();
+ if ( pSampleGrabberIF_ )
+ pSampleGrabberIF_->Release();
- if ( nativeMediaType_ )
- freeMediaType(*nativeMediaType_);
+ if ( pSampleGrabber_ )
+ pSampleGrabber_->Release();
- // These below were initialized in constructor
if ( pMediaControlIF_ )
pMediaControlIF_->Release();
- pMediaControlIF_ = 0;
- pMediaEventIF_->Release();
+ if ( pMediaEventIF_ )
+ pMediaEventIF_->Release();
- pFilterGraph_->Release();
+ if ( pFilterGraph_ )
+ pFilterGraph_->Release();
- pSource_->Release();
+ if ( pStreamConfig_ )
+ pStreamConfig_->Release();
- pStreamConfig_->Release();
-
- pCapGraphBuilder_->Release();
-
- dshowMgr_->sourceReleased( getID() );
+ if ( pCapGraphBuilder_ )
+ pCapGraphBuilder_->Release();
}
int
@@ -412,111 +467,61 @@
}
void
-DirectShowSource::cleanupCaptureGraphFoo()
+DirectShowSource::resetCapGraphFoo()
{
- if ( pNullRenderer_ )
- pNullRenderer_->Release();
- pNullRenderer_ = 0;
+ if ( captureIsSetup_ )
+ {
+ // some or all of this appears to be necessary to allow
+ // subsequent captures with a different media type
+ HRESULT hr = pFilterGraph_->RemoveFilter(pSource_);
+ if ( FAILED(hr) )
+ log_error("failed to remove source (%d)\n", hr);
- if ( pSampleGrabberIF_ )
- pSampleGrabberIF_->Release();
- pSampleGrabberIF_ = 0;
+ hr = pFilterGraph_->RemoveFilter(pSampleGrabber_);
+ if ( FAILED(hr) )
+ log_error("failed to remove Sample Grabber (%d)\n",
+ hr);
- if ( pSampleGrabber_ )
- pSampleGrabber_->Release();
- pSampleGrabber_ = 0;
+ hr = pFilterGraph_->RemoveFilter(pNullRenderer_);
+ if ( FAILED(hr) )
+ log_error("failed to remove null renderer (%d)\n", hr);
- captureIsSetup_ = false;
+ captureIsSetup_ = false;
+ }
}
int
-DirectShowSource::setupCaptureGraphFoo()
+DirectShowSource::setupCapGraphFoo()
{
- if ( !captureIsSetup_ )
+ if ( !captureIsSetup_ )
{
- HRESULT hr = CoCreateInstance(CLSID_SampleGrabber,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- (void **)&pSampleGrabber_);
- if ( FAILED(hr) )
- {
- log_error("failed creating Sample Grabber (%d)\n", hr);
- return -1;
- }
-
- hr = pSampleGrabber_->QueryInterface(IID_ISampleGrabber,
- (void**)&pSampleGrabberIF_);
- if ( FAILED(hr) )
- {
- log_error("failed getting ISampleGrabber interface (%d)\n", hr);
- goto bail_1;
- }
-
- // Capture more than once
- hr = pSampleGrabberIF_->SetOneShot(FALSE);
- if ( FAILED(hr) )
- {
- log_error("failed SetOneShot (%d)\n", hr);
- goto bail_2;
- }
-
- hr = pSampleGrabberIF_->SetBufferSamples(FALSE);
- if ( FAILED(hr) )
- {
- log_error("failed SetBufferSamples (%d)\n", hr);
- goto bail_2;
- }
-
- // set which callback type and function to use
- hr = pSampleGrabberIF_->SetCallback( this, 1 );
- if ( FAILED(hr) )
- {
- log_error("failed to set callback (%d)\n", hr);
- goto bail_2;
- }
-
// Set sample grabber's media type to match that of the source
- hr = pSampleGrabberIF_->SetMediaType(nativeMediaType_);
+ HRESULT hr = pSampleGrabberIF_->SetMediaType(nativeMediaType_);
if ( FAILED(hr) )
{
log_error("failed to set grabber media type (%d)\n", hr);
- goto bail_2;
+ return -1;
}
- hr = CoCreateInstance(CLSID_NullRenderer,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IBaseFilter,
- (void **)&pNullRenderer_);
-
- if ( FAILED(hr) )
- {
- log_error("failed creating a NULL renderer (%d)\n", hr);
- goto bail_2;
- }
-
- //FIXME: use actual device name
hr = pFilterGraph_->AddFilter(pSource_, L"Source Device");
if ( FAILED(hr) )
{
log_error("failed to add source (%d)\n", hr);
- goto bail_3;
+ return -1;
}
hr = pFilterGraph_->AddFilter(pSampleGrabber_, L"Sample Grabber");
if ( FAILED(hr) )
{
- log_error("failed to add Sample Grabber to filter graph (%d)\n",
- hr);
- goto bail_3;
+ log_error("failed to add Sample Grabber (%d)\n", hr);
+ return -1;
}
hr = pFilterGraph_->AddFilter(pNullRenderer_, L"NullRenderer");
if ( FAILED(hr) )
{
log_error("failed to add null renderer (%d)\n", hr);
- goto bail_3;
+ return -1;
}
hr = pCapGraphBuilder_->RenderStream(&PIN_CATEGORY_CAPTURE,
@@ -528,25 +533,28 @@
{
log_error("failed to connect source, grabber "
"and null renderer (%d)\n", hr);
- goto bail_3;
+ return -1;
}
captureIsSetup_ = true;
}
return 0;
+}
-bail_3:
- pNullRenderer_->Release();
- pNullRenderer_ = 0;
-bail_2:
- pSampleGrabberIF_->Release();
- pSampleGrabberIF_ = 0;
-bail_1:
- pSampleGrabber_->Release();
- pSampleGrabber_ = 0;
+void
+DirectShowSource::terminate()
+{
+ doStop();
- return -1;
+ if ( nativeMediaType_ )
+ freeMediaType(*nativeMediaType_);
+
+ destroyCapGraphFoo();
+
+ pSource_->Release();
+
+ dshowMgr_->sourceReleased( getID() );
}
int
@@ -566,7 +574,7 @@
void
DirectShowSource::doStart()
{
- if ( !setupCaptureGraphFoo() )
+ if ( !setupCapGraphFoo() )
{
HRESULT hr = pMediaControlIF_->Run();
@@ -647,7 +655,7 @@
vih->bmiHeader.biWidth = fmtNative.width;
vih->bmiHeader.biHeight = fmtNative.height;
- cleanupCaptureGraphFoo();
+ resetCapGraphFoo();
// set the stream's media type
HRESULT hr = pStreamConfig_->SetFormat(nativeMediaType_);
Modified: trunk/src/directshow/DirectShowSource.h
===================================================================
--- trunk/src/directshow/DirectShowSource.h 2007-09-17 18:57:01 UTC (rev 22)
+++ trunk/src/directshow/DirectShowSource.h 2007-09-18 17:14:56 UTC (rev 23)
@@ -59,8 +59,10 @@
void doStop();
int createEvents();
- int setupCaptureGraphFoo();
- void cleanupCaptureGraphFoo();
+ int createCapGraphFoo();
+ void destroyCapGraphFoo();
+ int setupCapGraphFoo();
+ void resetCapGraphFoo();
bool checkFormat(const vidcap_fmt_info * fmtNominal,
vidcap_fmt_info * fmtNative,
int formatNum,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
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...
[truncated message content] |
|
From: libvidcap c. <lib...@li...> - 2008-04-28 19:17:51
|
Revision: 94
http://libvidcap.svn.sourceforge.net/libvidcap/?rev=94&view=rev
Author: bcholew
Date: 2008-04-28 12:16:42 -0700 (Mon, 28 Apr 2008)
Log Message:
-----------
fix to detect video device insertion/removal on Vista
Modified Paths:
--------------
trunk/src/directshow/DevMonitor.cpp
trunk/src/directshow/DevMonitor.h
Modified: trunk/src/directshow/DevMonitor.cpp
===================================================================
--- trunk/src/directshow/DevMonitor.cpp 2008-04-04 15:20:27 UTC (rev 93)
+++ trunk/src/directshow/DevMonitor.cpp 2008-04-28 19:16:42 UTC (rev 94)
@@ -26,7 +26,6 @@
#include <dbt.h>
#include <process.h>
#include <string>
-#include "sapi_context.h"
#include "DevMonitor.h"
#include "logging.h"
@@ -148,6 +147,9 @@
WPARAM wParam,
LPARAM lParam)
{
+ static DevMonitor *pDevMon = 0;
+ LPCREATESTRUCT lpcstr = 0;
+
switch (message)
{
case WM_CLOSE:
@@ -168,6 +170,19 @@
PostQuitMessage(0);
break;
+ case WM_CREATE:
+ // hold on to context for use when WM_DEVICECHANGE occurs
+ lpcstr = (LPCREATESTRUCT)lParam;
+ pDevMon = (DevMonitor *)lpcstr->lpCreateParams;
+ break;
+
+ case WM_DEVICECHANGE:
+ if ( !pDevMon )
+ log_error("Got WM_DEVICECHANGE event, but have no context!\n");
+ else
+ pDevMon->handleDeviceChange(wParam);
+ break;
+
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
@@ -175,6 +190,77 @@
return 0;
}
+void
+DevMonitor::handleDeviceChange(WPARAM wParam)
+{
+ std::string str;
+
+ switch (wParam)
+ {
+ case DBT_CONFIGCHANGECANCELED:
+ str.assign("DBT_CONFIGCHANGECANCELED");
+ break;
+ case DBT_CONFIGCHANGED:
+ str.assign("DBT_CONFIGCHANGED");
+ break;
+ case DBT_CUSTOMEVENT:
+ str.assign("DBT_CUSTOMEVENT");
+ break;
+ case DBT_DEVICEARRIVAL:
+ str.assign("DBT_DEVICEARRIVAL");
+ break;
+ case DBT_DEVICEQUERYREMOVE:
+ str.assign("DBT_DEVICEQUERYREMOVE");
+ break;
+ case DBT_DEVICEQUERYREMOVEFAILED:
+ str.assign("DBT_DEVICEQUERYREMOVEFAILED");
+ break;
+ case DBT_DEVICEREMOVECOMPLETE:
+ str.assign("DBT_DEVICEREMOVECOMPLETE");
+ break;
+ case DBT_DEVICEREMOVEPENDING:
+ str.assign("DBT_DEVICEREMOVEPENDING");
+ break;
+ case DBT_DEVICETYPESPECIFIC:
+ str.assign("DBT_DEVICETYPESPECIFIC");
+ break;
+ case DBT_DEVNODES_CHANGED:
+ str.assign("DBT_DEVNODES_CHANGED");
+ break;
+ case DBT_QUERYCHANGECONFIG:
+ str.assign("DBT_QUERYCHANGECONFIG");
+ break;
+ case DBT_USERDEFINED:
+ str.assign("DBT_USERDEFINED");
+ break;
+ default:
+ str.assign("default");
+ break;
+ }
+
+ log_info("[[ Device event: %s ]]\n", str.c_str());
+
+ vc_mutex_lock(®istrationMutex_);
+
+ if ( sapiCtx_ &&
+ sapiCtx_->notify_callback )
+ {
+ // TODO: If the user returns non-zero from
+ // their callback, maybe that should have
+ // some semantic meaning. For example, maybe
+ // that should be a way that the user can
+ // cancel further notification callbacks.
+ sapiCtx_->notify_callback(sapiCtx_, sapiCtx_->notify_data);
+ }
+ else
+ {
+ log_info("[[ no user-defined handler registered ]]\n");
+ }
+
+ vc_mutex_unlock(®istrationMutex_);
+
+}
+
unsigned int
DevMonitor::monitorDevices(void * param)
{
@@ -183,7 +269,8 @@
// extract instance
DevMonitor * pDevMon = (DevMonitor *)param;
- // Create a window, so main thread can communicate with us
+ // Create a window, so we can receive device events.
+ // Pass context for delivery via WM_CREATE event
pDevMon->windowHandle_ = CreateWindow(
pDevMon->szWindowClass_,
pDevMon->szTitle_,
@@ -195,7 +282,7 @@
NULL,
NULL,
(HINSTANCE)0,
- NULL);
+ param);
if ( !pDevMon->windowHandle_ )
{
@@ -225,83 +312,18 @@
// Main message loop
// Breaks out when PostQuitMessage() is called
MSG msg;
- while (GetMessage(&msg, NULL, 0, 0))
+ int ret;
+ while ( (ret = GetMessage(&msg, NULL, 0, 0)) != 0 )
{
- std::string str;
-
- sapi_context * sapiCtx =
- static_cast<sapi_context *>(pDevMon->sapiCtx_);
-
- switch (msg.message)
+ if ( ret == -1 )
{
- case WM_DEVICECHANGE:
- switch(msg.wParam)
- {
- case DBT_CONFIGCHANGECANCELED:
- str.assign("DBT_CONFIGCHANGECANCELED");
+ log_error("[[ GetMessage() returned error. [%d] ]]\n",
+ GetLastError());
break;
- case DBT_CONFIGCHANGED:
- str.assign("DBT_CONFIGCHANGED");
- break;
- case DBT_CUSTOMEVENT:
- str.assign("DBT_CUSTOMEVENT");
- break;
- case DBT_DEVICEARRIVAL:
- str.assign("DBT_DEVICEARRIVAL");
- break;
- case DBT_DEVICEQUERYREMOVE:
- str.assign("DBT_DEVICEQUERYREMOVE");
- break;
- case DBT_DEVICEQUERYREMOVEFAILED:
- str.assign("DBT_DEVICEQUERYREMOVEFAILED");
- break;
- case DBT_DEVICEREMOVECOMPLETE:
- str.assign("DBT_DEVICEREMOVECOMPLETE");
- break;
- case DBT_DEVICEREMOVEPENDING:
- str.assign("DBT_DEVICEREMOVEPENDING");
- break;
- case DBT_DEVICETYPESPECIFIC:
- str.assign("DBT_DEVICETYPESPECIFIC");
- break;
- case DBT_DEVNODES_CHANGED:
- str.assign("DBT_DEVNODES_CHANGED");
- break;
- case DBT_QUERYCHANGECONFIG:
- str.assign("DBT_QUERYCHANGECONFIG");
- break;
- case DBT_USERDEFINED:
- str.assign("DBT_USERDEFINED");
- break;
- default:
- str.assign("default");
- break;
}
- log_info("[[ Device event: %s ]]\n", str.c_str());
-
- vc_mutex_lock(&pDevMon->registrationMutex_);
-
- if ( sapiCtx &&
- sapiCtx->notify_callback )
- {
- // TODO: If the user returns non-zero from
- // their callback, maybe that should have
- // some semantic meaning. For example, maybe
- // that should be a way that the user can
- // cancel further notification callbacks.
- sapiCtx->notify_callback(sapiCtx, sapiCtx->notify_data);
- }
else
{
- log_info("[[ no user-defined handler registered ]]\n");
- }
-
- vc_mutex_unlock(&pDevMon->registrationMutex_);
-
- default:
- str.assign("");
DispatchMessage(&msg);
- break;
}
}
@@ -317,7 +339,7 @@
vc_mutex_lock(®istrationMutex_);
- sapiCtx_ = sapiCtx;
+ sapiCtx_ = static_cast<sapi_context *>(sapiCtx);
vc_mutex_unlock(®istrationMutex_);
Modified: trunk/src/directshow/DevMonitor.h
===================================================================
--- trunk/src/directshow/DevMonitor.h 2008-04-04 15:20:27 UTC (rev 93)
+++ trunk/src/directshow/DevMonitor.h 2008-04-28 19:16:42 UTC (rev 94)
@@ -26,6 +26,7 @@
#define _DEVMONITOR_H_
#include <vidcap/vidcap.h>
+#include "sapi_context.h"
class DevMonitor
{
@@ -38,6 +39,7 @@
private:
static LRESULT __stdcall processWindowsMsgs(HWND, UINT, WPARAM, LPARAM);
static unsigned int STDCALL monitorDevices(void * lpParam);
+ void handleDeviceChange(WPARAM wParam);
private:
HANDLE initDoneEvent_;
@@ -50,7 +52,7 @@
TCHAR * szTitle_;
TCHAR * szWindowClass_;
- void * sapiCtx_;
+ sapi_context * sapiCtx_;
vc_mutex registrationMutex_;
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|