DirectShow在调用Stop的时候出错

Ginie 2011-08-10 06:43:53
程序加了一个压缩的Filter,这个Filter也没做什么很多事,就是枚举出系统的压缩器,然后选中ffdshow video encoder绑定进行压缩,我单独写了个压缩已经生成好了的AVI文件,这个就没问题,但是我把这个压缩器加进来让它实时压缩采集的视频,就会在m_pMC->Stop();这里出错,报内存不可读的错误,Call stack信息为
FFDSHOW! 086cbf78()
FFDSHOW! 086c97ed()
QUARTZ! 7cfa8523()
CCaptureVideo::CaptureImagesToAVI(CString {"D:\data\0000173_wqwqwq\20110810183804.avi"}) line 157 + 20 bytes
CTHIRD::OnCapture() line 111

我不加压缩这块,就预览和采集已经实现,程序没问题,我在程序开启的时候在OnInitDialog中调用压缩Filter,Filter代码如下

//枚举压缩器
////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT hr;
ICreateDevEnum *pSysDevEnum = NULL; //创建枚举器指针
pCompress = NULL;

hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum); //创建枚举器

// Obtain a class enumerator for the video compressor category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0); //返回枚举参数

if (hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) //开始枚举压缩器
{
IPropertyBag *pPropBag;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);

// To retrieve the friendly name of the filter, do the following:
VARIANT varName;
VariantInit(&varName);

hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
CString str(varName.bstrVal);
SysFreeString(varName.bstrVal);
if(str == "ffdshow video encoder")
{
hr = pMoniker->BindToObject(0,0,IID_IBaseFilter,(void**)&pCompress);
pMoniker->Release();
break;
}

}
VariantClear(&varName);

}
pEnumCat->Release();
pMoniker->Release();
m_pGB->AddFilter(pCompress,L"Compressor"); //添加过滤器
HRESULT ret =NULL;
IPin * pSourceOut = NULL;
IPin* pCompressIn,* pCompressOut=NULL;
IAMVideoCompression * pAMCompress = NULL; //压缩参数设置
pCompressIn = FindPin(pCompress,PINDIR_INPUT) ; //查找输入引脚
pCompressOut = FindPin(pCompress,PINDIR_OUTPUT); //查找输出引脚

pCompressOut->QueryInterface(IID_IAMVideoCompression,(void**)&pAMCompress);

}

pSysDevEnum->Release();

然后在点击采集按钮的时候进行实时采集压缩,代码如下

HRESULT hr=0;
if(m_pMC)
{
m_pMC->Stop(); ////////////////////此处出现问题 }

hr = m_pCapture->SetOutputFileName( &MEDIASUBTYPE_Avi,inFileName.AllocSysString(), &pMux, NULL );

//渲染媒体,链接所有滤波器
m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pCompress,pMux);
HRESULT ret = pMux->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
pMux->Release();
m_pMC->Run();//回复视频
return hr;

就在上面的m_pMC->Stop();处出问题
我在GraphEdit里配置图表没有问题

为什么会出现这种情况啊,请高手帮帮忙,谢谢了,实在是急死了都
...全文
1087 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
shudaosheng 2011-11-08
  • 打赏
  • 举报
回复
衣衣你好,我现在做的东西和你的差不多,但还不清楚,能不能交流下啊,谢谢,我qq498343936
ArcRain 2011-08-11
  • 打赏
  • 举报
回复
检查下Graph里的Filter是否都正确的释放了。

//Remove Filter From Graph
Stop();
if(m_pGraph != NULL)
{
IEnumFilters * pEnum = NULL;
HRESULT hr = m_pGraph->EnumFilters(&pEnum);
if (SUCCEEDED(hr))
{
IBaseFilter *pFilter = NULL;
while (S_OK == pEnum->Next(1, &pFilter, NULL))
{
m_pGraph->RemoveFilter(pFilter);
pEnum->Reset();
SafeRelease(pFilter);
}
}
SafeRelease(pEnum);
}
Ginie 2011-08-11
  • 打赏
  • 举报
回复
最后一个艰难问题了,麻烦大家帮帮忙呀
Ginie 2011-08-11
  • 打赏
  • 举报
回复
我发现问题在哪了,是我匹配错了,在我的编码器里我安装完FFDSHOW后有两个,一个是ffdshow video encoder,一个是ffdshow Video Codec,应该是选下面这个,开始我一直选的是上面这个,所以就出问题了,但是现在还有个问题,我录制压缩完后,点击退出会弹出内存读取错误的问题,调用堆栈信息为
FF_VFW! 02b018c5()
FF_VFW! 02b03ef5()
FF_VFW! 02b03fbb()
WINMM! 76b131e9()
WINMM! 76b13138()
WINMM! 76b13999()
WINMM! 76b138f4()
WINMM! 76b138a5()
MSVFW32! 73b43b42()
MSVFW32! 73b4467f()
MSVFW32! 73b44623()
NTDLL! 7c92118a()
NTDLL! 7c9424ca()
KERNEL32! 7c81caae()
KERNEL32! 7c81cb26()
doexit(int 0, int 0, int 0) line 392
exit(int 0) line 279 + 13 bytes
youyifirst 2011-08-11
  • 打赏
  • 举报
回复
不懂,帮顶
Ginie 2011-08-11
  • 打赏
  • 举报
回复
程序跳到汇编这里
086CBF78 cmp dword ptr [eax+58h],ebx
就出问题的
Ginie 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 delphigis 的回复:]
directshow自身所带的线程死锁问题,产生此问题的原因和在线程里使用sendmessage差不多,即在关闭某个线程时会有一定概率死锁

解决的办法是自己创建个全局变量 控制一下

BOOL g_IsStartDShow = FALSE;

m_pMC-> Run();
g_IsStartDShow = TRUE;

所有你重写的函数里第一行
if(……
[/Quote]
可是我换成Microsoft MPEG-4 Video Codec V2就可以,一点问题也没有呢,一换成ffdshow video encoder然后调用压缩过滤器就出问题,但是在graphEdit里用又是没问题的
Ginie 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 dream238 的回复:]
引用 10 楼 g6785654 的回复:

引用 9 楼 dream238 的回复:
如果换回原来的MPEG-4 Encoder是好的,不排除是第三方Filter的问题,可以尝试更新FFDShow的Encoder版本或者找其他网上能使用的其他Filter。

可是我用GraphEdit运行就行呀,应该没道理在程序中就不行啊


使用第三方的Encoder风险就在于调用方法上可能无……
[/Quote]
替换了还是不行,它在上面的stop就停止了

directshow自身所带的线程死锁问题,产生此问题的原因和在线程里使用sendmessage差不多,即在关闭某个线程时会有一定概率死锁

解决的办法是自己创建个全局变量 控制一下

BOOL g_IsStartDShow = FALSE;

m_pMC-> Run();
g_IsStartDShow = TRUE;
这个办法也不行呢,也还是会出现那个问题的
First-chance exception in VCCapture.exe (FFDSHOW.AX): 0xC0000005: Access Violation.
百事烟 2011-08-11
  • 打赏
  • 举报
回复
directshow自身所带的线程死锁问题,产生此问题的原因和在线程里使用sendmessage差不多,即在关闭某个线程时会有一定概率死锁

解决的办法是自己创建个全局变量 控制一下

BOOL g_IsStartDShow = FALSE;

m_pMC->Run();
g_IsStartDShow = TRUE;

所有你重写的函数里第一行
if(!g_IsStartDShow) return;


if(m_pMC)
{
g_IsStartDShow = FALSE;
//这里看情况加sleep效果更好
m_pMC->Stop();
}
ArcRain 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 g6785654 的回复:]

引用 9 楼 dream238 的回复:
如果换回原来的MPEG-4 Encoder是好的,不排除是第三方Filter的问题,可以尝试更新FFDShow的Encoder版本或者找其他网上能使用的其他Filter。

可是我用GraphEdit运行就行呀,应该没道理在程序中就不行啊
[/Quote]

使用第三方的Encoder风险就在于调用方法上可能无文档可循,常规方法可能又有问题。
所以如果代码流程按照常规来做是好的,那么出现问题时就比较麻烦了。

又看了下,
hr = m_pCapture->SetOutputFileName( &MEDIASUBTYPE_Avi,inFileName.AllocSysString(), &pMux, NULL );
这里inFileName.AllocSysString()替换为普通的路径字符串试试。

Ginie 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 dream238 的回复:]
如果换回原来的MPEG-4 Encoder是好的,不排除是第三方Filter的问题,可以尝试更新FFDShow的Encoder版本或者找其他网上能使用的其他Filter。
[/Quote]
可是我用GraphEdit运行就行呀,应该没道理在程序中就不行啊
ArcRain 2011-08-11
  • 打赏
  • 举报
回复
如果换回原来的MPEG-4 Encoder是好的,不排除是第三方Filter的问题,可以尝试更新FFDShow的Encoder版本或者找其他网上能使用的其他Filter。
Ginie 2011-08-11
  • 打赏
  • 举报
回复
而且程序一运行到m_pMC->Stop()这里出现的错误提示是First-chance exception in VCCapture.exe (FFDSHOW.AX): 0xC0000005: Access Violation.
Ginie 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 dream238 的回复:]
由于采集和预览都在一个Graph中,因此开始采集时,需要先关掉预览。
预览时,你的Smart Tee可以不连下游后续采集相关的Filter,只有当需要采集的时候,才停止Graph,连上采集的后续Filter.
[/Quote]
我程序里没有手动写Smart Tree,不是会智能的生成么。我贴出我几个重要的方法来,麻烦你帮我看下,是不是逻辑有问题
我的变量

public:
IBaseFilter *pMux ,*pWriter,*pCompress; //过滤器

HWND m_hWnd;
IGraphBuilder *m_pGB;
ICaptureGraphBuilder2* m_pCapture;
IBaseFilter* m_pBF;
IMediaControl* m_pMC;
IVideoWindow* m_pVW;
ISampleGrabber* m_pGrabber;
int m_IMonikerNum;
IMoniker *rgpmVideo[10];
IMoniker *pMoniker; //监视器
IMediaSeeking *pSeek;
IMediaEventEx *pEvent;

在OnInitDialog方法里调用预览

HRESULT CCaptureVideo::Init(int iDeviceID, HWND hWnd)
{
HRESULT hr;
hr = InitCaptureGraphBuilder();
if (FAILED(hr))
{
AfxMessageBox("Failed to get video interfaces!");
return hr;
}
// if(MakeEncoder())
// {
// hr = m_pGB->AddFilter(pEncoderFilter, L"EncodeFilter");
// }
// Bind Device Filter. We know the device because the id was passed in
if(!BindFilter(iDeviceID, &m_pBF))return S_FALSE;
hr = m_pGB->AddFilter(m_pBF, L"Capture Filter");
// hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
// m_pBF, NULL, NULL);
// create a sample grabber

// hr = m_pGrabber.CoCreateInstance( CLSID_SampleGrabber );
hr = CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_ISampleGrabber, (void**)&m_pGrabber );
if( !m_pGrabber )
{
AfxMessageBox("Fail to create SampleGrabber, maybe qedit.dll is not registered?");
return hr;
}

CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabBase( m_pGrabber );

//设置视频格式
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
mt.bTemporalCompression = TRUE;
hr = m_pGrabber->SetMediaType(&mt);
if( FAILED( hr ) )
{
AfxMessageBox("Fail to set media type!");
return hr;
}
hr = m_pGB->AddFilter( pGrabBase, L"Grabber" );
// hr = m_pGB->AddFilter(pEncoderFilter,L"EncodeFilter");
if( FAILED( hr ) )
{
AfxMessageBox("Fail to put sample grabber in graph");
return hr;
}
// try to render preview/capture pin
hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
if( FAILED( hr ) )
{
hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pGrabBase,NULL);
// hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pEncoderFilter,pMux);
}
if( FAILED( hr ) )
{
AfxMessageBox("Can’t build the graph");
return hr;
}

hr = m_pGrabber->GetConnectedMediaType( &mt );
if ( FAILED( hr) )
{
AfxMessageBox("Failt to read the connected media type");
return hr;
}
m_pVW->put_MessageDrain((OAHWND)m_hWnd);
VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
mCB.lWidth = vih->bmiHeader.biWidth;
mCB.lHeight = vih->bmiHeader.biHeight;
FreeMediaType(mt);
hr = m_pGrabber->SetBufferSamples( FALSE );
hr = m_pGrabber->SetOneShot( FALSE );
hr = m_pGrabber->SetCallback( &mCB, 1 );
//设置视频捕捉窗口
m_hWnd = hWnd ;
SetupVideoWindow();
hr = m_pMC->Run();//开始视频预览
if(FAILED(hr))
{
AfxMessageBox("Couldn't run the graph!");
return hr;
}
return S_OK;
}

预览中的初始化图表的InitCaptureGraphBuilder()方法如下

HRESULT CCaptureVideo::InitCaptureGraphBuilder()
{
m_pGB = NULL;
HRESULT hr;
// 创建IGraphBuilder接口
hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB);
// 创建ICaptureGraphBuilder2接口
hr = CoCreateInstance (CLSID_CaptureGraphBuilder2,NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &m_pCapture);
if (FAILED(hr))
return hr;
m_pCapture->SetFiltergraph(m_pGB);
hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
if (FAILED(hr))return hr;
hr = m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *) &m_pVW);
if (FAILED(hr))return hr;
return hr;
}

这两方法可以实现预览,然后我在Init方法后面继续调用压缩Filter,这个方法也写在OnInitDialog中,不过在Init方法后面

void CCaptureVideo::MakeEncoder()
{
//枚举压缩器
////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT hr;
ICreateDevEnum *pSysDevEnum = NULL; //创建枚举器指针
pCompress = NULL;

hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum); //创建枚举器

// Obtain a class enumerator for the video compressor category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0); //返回枚举参数

if (hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) //开始枚举压缩器
{
IPropertyBag *pPropBag;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);

// To retrieve the friendly name of the filter, do the following:
VARIANT varName;
VariantInit(&varName);

hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
CString str(varName.bstrVal);
SysFreeString(varName.bstrVal);
if(str == "ffdshow video encoder")
{
hr = pMoniker->BindToObject(0,0,IID_IBaseFilter,(void**)&pCompress);
pMoniker->Release();
break;
}

}
VariantClear(&varName);

}
pEnumCat->Release();
pMoniker->Release();
m_pGB->AddFilter(pCompress,L"Compressor"); //添加过滤器
HRESULT ret =NULL;
IPin * pSourceOut = NULL;
IPin* pCompressIn,* pCompressOut=NULL;
IAMVideoCompression * pAMCompress = NULL; //压缩参数设置
pCompressIn = FindPin(pCompress,PINDIR_INPUT) ; //查找输入引脚
pCompressOut = FindPin(pCompress,PINDIR_OUTPUT); //查找输出引脚

pCompressOut->QueryInterface(IID_IAMVideoCompression,(void**)&pAMCompress);

}

pSysDevEnum->Release();

}

最后在点击录制按钮的时候调用保存方法

HRESULT CCaptureVideo::CaptureImagesToAVI(CString inFileName)
{

HRESULT hr=0;
if(m_pMC)
{
m_pMC->Stop();
}

//先停止视频//设置文件名,注意第二个参数的类型
hr = m_pCapture->SetOutputFileName( &MEDIASUBTYPE_Avi,inFileName.AllocSysString(), &pMux, NULL );

//渲染媒体,链接所有滤波器
// hr = m_pCapture->RenderStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pBF, NULL, pMux );
// hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pEncoderFilter,pMux);
m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,m_pBF,pCompress,pMux);
HRESULT ret = pMux->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
pMux->Release();
m_pMC->Run();//回复视频
return hr;
}

麻烦你了,代码可能有点乱,辛苦了
Ginie 2011-08-11
  • 打赏
  • 举报
回复
我发现只要是用了m_pMC->Stop()的地方都会出问题的。但是如果我不调用压缩Filter,然后在录制那个按钮那里的代码改成hr = m_pCapture->RenderStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pBF, NULL, pMux )这样就可以,但是这样就不能进行压缩了,可是那个压缩的filter原先都是好的,我就是把 if(str == "ffdshow video encoder")从MPEG4改成了ffdshow video encoder后就会这样,但是我在GraphEdit中这样做的图表有可以正常运行,好奇怪
ArcRain 2011-08-11
  • 打赏
  • 举报
回复
由于采集和预览都在一个Graph中,因此开始采集时,需要先关掉预览。
预览时,你的Smart Tee可以不连下游后续采集相关的Filter,只有当需要采集的时候,才停止Graph,连上采集的后续Filter.
Ginie 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 dream238 的回复:]
如果是第一次开始采集,尝试不 m_pMC->Stop();看看(因为刚建好图,肯定是stop的),会不会有问题。
[/Quote]
dream238,你终于来了,我的是开始先预览,前面我搭建了预览的Filter,里面有 hr = m_pMC->Run();//开始视频预览开启预览的,后面点击开始采集按钮的时候是不是要先关掉预览的呀??我去掉m_pMC->Stop()这句话后,它就不会采集,直到我点击停止的时候才会生成一个0KB的文件
ArcRain 2011-08-11
  • 打赏
  • 举报
回复
如果是第一次开始采集,尝试不 m_pMC->Stop();看看(因为刚建好图,肯定是stop的),会不会有问题。
Ginie 2011-08-11
  • 打赏
  • 举报
回复
天那,来人啊!顶一下。
Ginie 2011-08-11
  • 打赏
  • 举报
回复
OK了,谢谢两位的帮忙
加载更多回复(2)

16,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧