views:

154

answers:

2

Actually, it only fails the second time it's called. I'm using a windowless control to play video content, where the video being played could change while the control is still on screen. Once the graph is built the first time, we switch media by stopping playback, replacing the SOURCE filter, and running the graph again. This works fine under Vista, but when running on XP, the second call to Run() returns E_UNEXPECTED.

The initialization goes something like this:

// Get the interface for DirectShow's GraphBuilder
mGB.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);

// Create the Video Mixing Renderer and add it to the graph
ATL::CComPtr<IBaseFilter> pVmr;
pVmr.CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC);
mGB->AddFilter(pVmr, L"Video Mixing Renderer 9");

// Set the rendering mode and number of streams
ATL::CComPtr<IVMRFilterConfig9> pConfig;
pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
pConfig->SetRenderingMode(VMR9Mode_Windowless);
pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&mWC);

And here's what we do when we decide to play a movie. RenderFileToVideoRenderer is borrowed from dshowutil.h in the DirectShow samples area.

// Release the source filter, if it exists, so we can replace it.
IBaseFilter *pSource = NULL;
if (SUCCEEDED(mpGB->FindFilterByName(L"SOURCE", &pSource)) && pSource)
{
 mpGB->RemoveFilter(pSource);
 pSource->Release();
 pSource = NULL;
}

// Render the file.
hr = RenderFileToVideoRenderer(mpGB, mPlayPath.c_str(), FALSE);

// QueryInterface for DirectShow interfaces
hr = mpGB->QueryInterface(&mMC);
hr = mpGB->QueryInterface(&mME);
hr = mpGB->QueryInterface(&mMS);

// Read the default video size
hr = mpWC->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
if (hr != E_NOINTERFACE)
{
 if (FAILED(hr))
 {
  return hr;
 }

 // Play video at native resolution, anchored at top-left corner.
 RECT r;
 r.left = 0;
 r.top = 0;
 r.right = lWidth;
 r.bottom = lHeight;
 hr = mpWC->SetVideoPosition(NULL, &r);
}

// Run the graph to play the media file
if (mMC)
{
 hr = mMC->Run();
 if (FAILED(hr))
 {
  // We get here the second time this code is executed.
  return hr;
 }
 mState = Running;
}

if (mME)
{
 mME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
}

Anybody know what's going on here?

A: 
  1. Try calling IMediaControl::StopWhenReady before removing the source filter.
  2. When are you calling QueryInterface directly? you can use CComQIPtr<> to warp the QI for you. This way you won't have to call Release as it will be called automatically.
    The syntax look like this: CComPtr<IMediaControl> mediaControl = pGraph;
  3. In FindFilterByName() instead of passing live pointer pass a CComPtr, again so you won't have to call release explicitly.
Shay Erlichmen
1. We're already calling IMediaControl::Stop before removing the source filter, and calling IMediaControl::GetState tells me the play state is State_Stopped. Any other ideas?2/3. Good suggestions, this cleans up the code quite a bit.
Ben Straub
A: 

Never got a resolution on this. The production solution was to just call IGraphBuilder::Release and rebuild the entire graph from scratch. There's a CPU spike and a slight redraw delay when switching videos, but it's less pronounced than we'd feared.

Ben Straub