Windows Media Foundation - Capture Camera video as raw RBG32 - c++

I am stacking with this code for more that a week :)
I've changed the sample code included with Windows SDK (CWavSink) which is a custom wave sink to record a PCM data to wav file.
I've made some changes to use that sample as a video sink to record the video stream from a web cam on Windows 8.
I was managed to get the video frames from the IMFSample but the problems I have is:
When record the captured frames to test file then try to convert it to avi or any other format using ffmpeg the output has wrong colors and the video is not played OK.
What ever I set for the width and height I always get the frames as 320X240.
Sample buffer is always 600kb which contains 2 frames (I am setting it to get one frame as the sample size)
I've tried to change the format from RGB32 to H263 but it seems that the setting was ignored and I get RGB32 always.
I am appreciating any help on that
Here is my code
#include "pch.h"
#include "VideoSink.h"
#pragma warning( push )
#pragma warning( disable : 4355 ) // 'this' used in base member initializer list
using namespace VideoRecorder;
const DWORD VIDEO_SINK_STREAM_ID = 1;
HRESULT ValidateVideoFormat(const WAVEFORMATEX *pWav, DWORD cbSize);
HRESULT CreateRawVideoType(
UINT32 frameRate, // Samples per second
UINT32 width, // Bits per sample
UINT32 hieght, // Number of channels
IMFMediaType **ppType // Receives a pointer to the media type.
);
IFACEMETHODIMP CVideoSink::Initialize()
{
IMFByteStream *pStream = nullptr;
HRESULT hr = S_OK;
if (SUCCEEDED(hr))
{
hr = this->Initialize(pStream);
}
return hr;
}
CVideoSink::CVideoSink() :
m_nRefCount(1), m_IsShutdown(FALSE), m_pStream(NULL), m_pClock(NULL)
{
}
CVideoSink::~CVideoSink()
{
TRACE((L"~CVideoSink\n"));
assert(m_IsShutdown);
}
IFACEMETHODIMP CVideoSink::GetCharacteristics(DWORD *pdwCharacteristics)
{
AutoLock lock(m_critSec);
if (pdwCharacteristics == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*pdwCharacteristics = MEDIASINK_FIXED_STREAMS | MEDIASINK_RATELESS;
}
return hr;
}
IFACEMETHODIMP CVideoSink::AddStreamSink(
DWORD dwStreamSinkIdentifier,
IMFMediaType *pMediaType,
IMFStreamSink **ppStreamSink)
{
return MF_E_STREAMSINKS_FIXED;
}
IFACEMETHODIMP CVideoSink::RemoveStreamSink(DWORD dwStreamSinkIdentifier)
{
return MF_E_STREAMSINKS_FIXED;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkCount(DWORD *pcStreamSinkCount)
{
AutoLock lock(m_critSec);
if (pcStreamSinkCount == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*pcStreamSinkCount = 1; // Fixed number of streams.
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkByIndex(
DWORD dwIndex,
IMFStreamSink **ppStreamSink)
{
AutoLock lock(m_critSec);
if (ppStreamSink == NULL)
{
return E_INVALIDARG;
}
// Fixed stream: Index 0.
if (dwIndex > 0)
{
return MF_E_INVALIDINDEX;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*ppStreamSink = m_pStream;
(*ppStreamSink)->AddRef();
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkById(
DWORD dwStreamSinkIdentifier,
IMFStreamSink **ppStreamSink)
{
AutoLock lock(m_critSec);
if (ppStreamSink == NULL)
{
return E_INVALIDARG;
}
// Fixed stream ID.
if (dwStreamSinkIdentifier != VIDEO_SINK_STREAM_ID)
{
return MF_E_INVALIDSTREAMNUMBER;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*ppStreamSink = m_pStream;
(*ppStreamSink)->AddRef();
}
return hr;
}
IFACEMETHODIMP CVideoSink::SetPresentationClock(IMFPresentationClock *pPresentationClock)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
// If we already have a clock, remove ourselves from that clock's
// state notifications.
if (SUCCEEDED(hr))
{
if (m_pClock)
{
hr = m_pClock->RemoveClockStateSink(this);
}
}
// Register ourselves to get state notifications from the new clock.
if (SUCCEEDED(hr))
{
if (pPresentationClock)
{
hr = pPresentationClock->AddClockStateSink(this);
}
}
if (SUCCEEDED(hr))
{
// Release the pointer to the old clock.
// Store the pointer to the new clock.
SAFE_RELEASE(m_pClock);
m_pClock = pPresentationClock;
if (m_pClock)
{
m_pClock->AddRef();
}
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetPresentationClock(IMFPresentationClock **ppPresentationClock)
{
AutoLock lock(m_critSec);
if (ppPresentationClock == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
if (m_pClock == NULL)
{
hr = MF_E_NO_CLOCK; // There is no presentation clock.
}
else
{
// Return the pointer to the caller.
*ppPresentationClock = m_pClock;
(*ppPresentationClock)->AddRef();
}
}
return hr;
}
IFACEMETHODIMP CVideoSink::Shutdown()
{
TRACE((L"CVideoSink::Shutdown\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Shutdown();
SAFE_RELEASE(m_pClock);
SAFE_RELEASE(m_pStream);
m_IsShutdown = true;
}
return hr;
}
IFACEMETHODIMP CVideoSink::BeginFinalize(
IMFAsyncCallback *pCallback,
IUnknown *punkState)
{
TRACE((L"CVideoSink::BeginFinalize\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
// Tell the stream to finalize.
if (SUCCEEDED(hr))
{
hr = m_pStream->Finalize(pCallback, punkState);
}
return hr;
}
IFACEMETHODIMP CVideoSink::EndFinalize(IMFAsyncResult *pResult)
{
TRACE((L"CVideoSink::EndFinalize\n"));
HRESULT hr = S_OK;
// Return the status code from the async result.
if (pResult == NULL)
{
hr = E_INVALIDARG;
}
else
{
hr = pResult->GetStatus();
}
return hr;
}
HRESULT CVideoSink::OnClockStart(
/* [in] */ MFTIME hnsSystemTime,
/* [in] */ LONGLONG llClockStartOffset)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Start(llClockStartOffset);
}
return hr;
}
HRESULT CVideoSink::OnClockStop(
/* [in] */ MFTIME hnsSystemTime)
{
TRACE((L"CVideoSink::OnClockStop\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Stop();
}
return hr;
}
HRESULT CVideoSink::OnClockPause(
/* [in] */ MFTIME hnsSystemTime)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Pause();
}
return hr;
}
HRESULT CVideoSink::OnClockRestart(
/* [in] */ MFTIME hnsSystemTime)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Restart();
}
return hr;
}
HRESULT CVideoSink::OnClockSetRate(
/* [in] */ MFTIME hnsSystemTime,
/* [in] */ float flRate)
{
return S_OK;
}
HRESULT CVideoSink::Initialize(IMFByteStream *pByteStream)
{
HRESULT hr = S_OK;
m_pStream = new CVideoStream();
if (m_pStream == NULL)
{
hr = E_OUTOFMEMORY;
}
IMFMediaTypeHandler* typeHandler;
IMFMediaType* type;
// Initialize the stream.
if (SUCCEEDED(hr))
{
hr = m_pStream->Initialize(this, pByteStream);
}
return hr;
}
I will add the second part as another post ( sorry it is long code :) )
# not allowed :) get it from here https://github.com/Felixsoft/VideoSink

Related

IMFTransform::ProcessInput() "The buffer was too small to carry out the requested action."

I am trying to encode a texture with IMFTransform to H264. I can write and encode textures no problem to a file with SinkWriter and play the video and everything, works great. But I am trying to learn how to use IMFTransform so I can access the encoded IMFSamples themselves.
Unfortunately, I didn't end up getting too far because ProcessInput is failing with "The buffer was too small to carry out the requested action." as the HRESULT.
I have no clue which "buffer" it is referring to, and doing a search of that error turns up absolutely no results. No other calls return a bad HRESULT except ProcessInput(), and SinkWriter works fine. So I have absolutely ZERO clue what the problem is.
#include "main.h"
#include "WinDesktopDup.h"
#include <iostream>
#include <wmcodecdsp.h>
WinDesktopDup dup;
void SetupDpiAwareness()
{
if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
printf("SetProcessDpiAwarenessContext failed\n");
}
const UINT32 VIDEO_WIDTH = 3840;
const UINT32 VIDEO_HEIGHT = 2160;
const UINT32 VIDEO_FPS = 120;
const UINT64 VIDEO_FRAME_DURATION = 10 * 1000 * 1000 / VIDEO_FPS;
const UINT32 VIDEO_BIT_RATE = 800000;
const GUID VIDEO_ENCODING_FORMAT = MFVideoFormat_H264;
const GUID VIDEO_INPUT_FORMAT = MFVideoFormat_ARGB32;
const UINT32 VIDEO_PELS = VIDEO_WIDTH * VIDEO_HEIGHT;
const UINT32 VIDEO_FRAME_COUNT = 20 * VIDEO_FPS;
template <class T>
void SafeRelease(T** ppT) {
if (*ppT) {
(*ppT)->Release();
*ppT = NULL;
}
}
bool usingEncoder;
IMFMediaType* pMediaTypeOut = NULL;
IMFMediaType* pMediaTypeIn = NULL;
HRESULT SetMediaType()
{
// Set the output media type.
HRESULT hr = MFCreateMediaType(&pMediaTypeOut);
if (!SUCCEEDED(hr)) { printf("MFCreateMediaType failed\n"); }
hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (!SUCCEEDED(hr)) { printf("SetGUID failed\n"); }
hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT);
if (!SUCCEEDED(hr)) { printf("SetGUID (2) failed\n"); }
hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, VIDEO_BIT_RATE);
if (!SUCCEEDED(hr)) { printf("SetUINT32 (3) failed\n"); }
hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
if (!SUCCEEDED(hr)) { printf("SetUINT32 (4) failed\n"); }
hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
if (!SUCCEEDED(hr)) { printf("MFSetAttributeSize failed\n"); }
hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
if (!SUCCEEDED(hr)) { printf("MFSetAttributeRatio failed\n"); }
hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
if (!SUCCEEDED(hr)) { printf("MFSetAttributeRatio (2) failed\n"); }
// Set the input media type.
hr = MFCreateMediaType(&pMediaTypeIn);
if (!SUCCEEDED(hr)) { printf("MFCreateMediaType failed\n"); }
hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (!SUCCEEDED(hr)) { printf("SetGUID (3) failed\n"); }
hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT);
if (!SUCCEEDED(hr)) { printf("SetGUID (4) failed\n"); }
hr = pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
if (!SUCCEEDED(hr)) { printf("SetUINT32 (5) failed\n"); }
hr = MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
if (!SUCCEEDED(hr)) { printf("MFSetAttributeSize (2) failed\n"); }
hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
if (!SUCCEEDED(hr)) { printf("MFSetAttributeRatio (3) failed\n"); }
hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
if (!SUCCEEDED(hr)) { printf("MFSetAttributeRatio (4) failed\n"); }
return hr;
}
HRESULT InitializeSinkWriter(IMFSinkWriter** ppWriter, DWORD* pStreamIndex)
{
IMFDXGIDeviceManager* pDeviceManager = NULL;
UINT resetToken;
IMFAttributes* attributes;
*ppWriter = NULL;
*pStreamIndex = NULL;
IMFSinkWriter* pSinkWriter = NULL;
DWORD streamIndex;
HRESULT hr = MFCreateDXGIDeviceManager(&resetToken, &pDeviceManager);
if (!SUCCEEDED(hr)) { printf("MFCreateDXGIDeviceManager failed\n"); }
hr = pDeviceManager->ResetDevice(dup.D3DDevice, resetToken);
if (!SUCCEEDED(hr)) { printf("ResetDevice failed\n"); }
hr = MFCreateAttributes(&attributes, 3);
if (!SUCCEEDED(hr)) { printf("MFCreateAttributes failed\n"); }
hr = attributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 1);
if (!SUCCEEDED(hr)) { printf("SetUINT32 failed\n"); }
hr = attributes->SetUINT32(MF_LOW_LATENCY, 1);
if (!SUCCEEDED(hr)) { printf("SetUINT32 (2) failed\n"); }
hr = attributes->SetUnknown(MF_SINK_WRITER_D3D_MANAGER, pDeviceManager);
if (!SUCCEEDED(hr)) { printf("SetUnknown failed\n"); }
hr = MFCreateSinkWriterFromURL(L"output.mp4", NULL, attributes, &pSinkWriter);
if (!SUCCEEDED(hr)) { printf("MFCreateSinkWriterFromURL failed\n"); }
hr = pSinkWriter->AddStream(pMediaTypeOut, &streamIndex);
if (!SUCCEEDED(hr)) { printf("AddStream failed\n"); }
hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaTypeIn, NULL);
if (!SUCCEEDED(hr)) { printf("SetInputMediaType failed\n"); }
// Tell the sink writer to start accepting data.
hr = pSinkWriter->BeginWriting();
if (!SUCCEEDED(hr)) { printf("BeginWriting failed\n"); }
// Return the pointer to the caller.
*ppWriter = pSinkWriter;
(*ppWriter)->AddRef();
*pStreamIndex = streamIndex;
SafeRelease(&pSinkWriter);
SafeRelease(&pMediaTypeOut);
SafeRelease(&pMediaTypeIn);
return hr;
}
IUnknown* _transformUnk;
IMFTransform* pMFTransform;
HRESULT InitializeEncoder(DWORD* pStreamIndex)
{
HRESULT hr = CoCreateInstance(CLSID_CMSH264EncoderMFT, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&_transformUnk);
if (!SUCCEEDED(hr)) { printf("CoCreateInstance failed\n"); }
hr = _transformUnk->QueryInterface(IID_PPV_ARGS(&pMFTransform));
if (!SUCCEEDED(hr)) { printf("QueryInterface failed\n"); }
hr = pMFTransform->SetOutputType(0, pMediaTypeOut, 0);
if (!SUCCEEDED(hr)) { printf("SetOutputType failed\n"); }
hr = pMFTransform->SetInputType(0, pMediaTypeIn, 0);
if (!SUCCEEDED(hr)) { printf("SetInputType failed\n"); }
DWORD mftStatus = 0;
hr = pMFTransform->GetInputStatus(0, &mftStatus);
if (!SUCCEEDED(hr)) { printf("GetInputStatus failed\n"); }
if (MFT_INPUT_STATUS_ACCEPT_DATA != mftStatus)
printf("MFT_INPUT_STATUS_ACCEPT_DATA\n");
hr = pMFTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
if (!SUCCEEDED(hr)) { printf("MFT_MESSAGE_NOTIFY_BEGIN_STREAMING failed\n"); }
hr = pMFTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL);
if (!SUCCEEDED(hr)) { printf("MFT_MESSAGE_NOTIFY_START_OF_STREAM failed\n"); }
SafeRelease(&pSinkWriter);
SafeRelease(&pMediaTypeOut);
SafeRelease(&pMediaTypeIn);
return hr;
}
ID3D11Texture2D* texture;
HRESULT WriteFrame(IMFSinkWriter* pWriter, DWORD streamIndex, const LONGLONG& rtStart)
{
IMFSample* pSample = NULL;
IMFMediaBuffer* pBuffer = NULL;
HRESULT hr;
hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), texture, 0, false, &pBuffer);
if (!SUCCEEDED(hr)) { printf("MFCreateDXGISurfaceBuffer failed\n"); }
DWORD len;
hr = ((IMF2DBuffer*)pBuffer)->GetContiguousLength(&len);
if (!SUCCEEDED(hr)) { printf("GetContiguousLength failed\n"); }
hr = pBuffer->SetCurrentLength(len);
if (!SUCCEEDED(hr)) { printf("SetCurrentLength failed\n"); }
// Create a media sample and add the buffer to the sample.
hr = MFCreateSample(&pSample);
if (!SUCCEEDED(hr)) { printf("MFCreateSample failed\n"); }
hr = pSample->AddBuffer(pBuffer);
if (!SUCCEEDED(hr)) { printf("AddBuffer failed\n"); }
// Set the time stamp and the duration.
hr = pSample->SetSampleTime(rtStart);
if (!SUCCEEDED(hr)) { printf("SetSampleTime failed\n"); }
hr = pSample->SetSampleDuration(VIDEO_FRAME_DURATION);
if (!SUCCEEDED(hr)) { printf("SetSampleDuration failed\n"); }
// Send the sample to the Sink Writer or Encoder.
if (!usingEncoder)
{
hr = pWriter->WriteSample(streamIndex, pSample);
if (!SUCCEEDED(hr)) { printf("WriteSample failed\n"); }
}
else
{
hr = pMFTransform->ProcessInput(0, pSample, 0);
if (!SUCCEEDED(hr)) { printf("ProcessInput failed\n"); }
}
SafeRelease(&pSample);
SafeRelease(&pBuffer);
return hr;
}
int APIENTRY main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
SetupDpiAwareness();
auto err = dup.Initialize();
// Initialize MF
CoInitializeEx(0, COINIT_APARTMENTTHREADED); // Need to call this once when a thread is using COM or it wont work
MFStartup(MF_VERSION); // Need to call this too for Media Foundation related memes
IMFSinkWriter* pSinkWriter = NULL;
DWORD stream = 0;
LONGLONG rtStart = 0;
usingEncoder = true; // True if we want to encode with IMFTransform, false if we want to write with SinkWriter
HRESULT hr = SetMediaType();
if (!SUCCEEDED(hr)) { printf("SetMediaType failed\n"); }
if (!usingEncoder)
{
hr = InitializeSinkWriter(&pSinkWriter, &stream);
if (!SUCCEEDED(hr)) { printf("InitializeSinkWriter failed\n"); }
}
else
{
hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV); // Using MFVideoFormat_ARGB32 causes SetInputType() to fail
hr = InitializeEncoder(&stream);
if (!SUCCEEDED(hr)) { printf("InitializeEncoder failed\n"); }
}
const int CAPTURE_LENGTH = 10;
int total_frames = VIDEO_FPS * CAPTURE_LENGTH;
for (int i = 0; i < 1; i++)
{
texture = dup.CaptureNext();
if (texture != nullptr)
{
hr = WriteFrame(pSinkWriter, stream, rtStart);
if (!SUCCEEDED(hr))
printf("WriteFrame failed\n");
rtStart += VIDEO_FRAME_DURATION;
texture->Release();
}
else
{
i--;
}
}
if (FAILED(hr))
{
std::cout << "Failure" << std::endl;
}
if (SUCCEEDED(hr)) {
hr = pSinkWriter->Finalize();
}
SafeRelease(&pSinkWriter);
MFShutdown();
CoUninitialize();
}
Here’s documentation for the Microsoft’s software CPU-based h.264 encoder you’re using in your code.
It does not support MFVideoFormat_ARGB32 on input. It doesn’t support any RGB formats at all. That transform only supports YUV formats for the input video.
BTW, if you replace the MFT with a hardware encoder, they’re very likely to expose same set of features as the Microsoft’s software one, I don’t think they support RGB. And, because all hardware transforms are asynchronous, you gonna need slightly different workflow to drive them directly.
The reason sink writer works OK, it creates and hosts 2 MFTs under the hood, the format converter from RGB to YUV, another one is the encoder.
You have following options.
Use another MFT to convert RGBA to NV12 before passing frames to the encoder.
Do that conversation yourself with pixel shaders (render a textured quad into 2 planes of NV12 texture using 2 different pixel shaders), or with a single compute shader (dispatch 1 thread for every 2x2 block of the video, write 6 bytes for every block, 4 into R8_UNORM output texture with brightness, other 2 bytes into R8G8_UNORM output texture with color data).
Use a sink writer, but create it with MFCreateSinkWriterFromMediaSink API instead of MFCreateSinkWriterFromURL. Implement IMFMediaSink COM interface, also IMFStreamSink for it’s video stream, and the framework will call IMFStreamSink.ProcessSample giving you encoded video samples in system memory as soon as they’re available.

Failed to get IAMStreamConfig interface

I could capture the image from webcam and save it as bitmap by using sampleGrabber. And I know I could use the IAMStreamConfig interface to GetFormat and SetFormat the video resolution. My question is, I using FindInterface() to get IAMStreamConfig* but always failed.Is it because I place it in a wrong place or something else I didn't notice. I placed it before RenderStream. Here are some code below, thanks for your patient and help!
INT USBDeviceApp::GetInterfaces()
{
HRESULT hr;
hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **) &pGraphBuilder);
if (FAILED(hr))
return hr;
hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &pCaptureGraphBuilder2);
if (FAILED(hr))
return hr;
hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(LPVOID *)
&pMediaControl);
if (FAILED(hr))
return hr;
hr = pGraphBuilder->QueryInterface(IID_IVideoWindow, (LPVOID *)
&pVideoWindow);
if(FAILED(hr))
{
return hr;
}
hr = pGraphBuilder->QueryInterface(IID_IMediaEvent,(LPVOID *)
&pMediaEvent);
if(FAILED(hr))
{
return hr;
}
// ------------------------
// Create the Sample Grabber.
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGrabberF);
if (FAILED(hr))
{
return hr;
}
hr = pGrabberF->QueryInterface(IID_ISampleGrabber,
(void**)&pSampleGrabber);
if(FAILED(hr))
{
AfxMessageBox(_T("Error SampleGrabber QueryInterface"));
}
return 1;
}
INT USBDeviceApp::InitMonikers()
{
HRESULT hr;
ULONG cFetched;
ICreateDevEnum *pCreateDevEnum;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (FAILED(hr))
{
return hr;
}
IEnumMoniker *pEnumMoniker;
hr = pCreateDevEnum->
CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEnumMoniker, 0);
if (FAILED(hr) || !pEnumMoniker)
{
return -1;
}
hr = pEnumMoniker->Next(1, &pMonikerVideo, &cFetched);
if (S_OK == hr)
{
hr = pMonikerVideo->BindToObject(0,0,IID_IBaseFilter,
(void**)&pVideoCaptureFilter);
if (FAILED(hr))
{
return hr;
}
}
pEnumMoniker->Release();
return 1;
}
INT USBDeviceApp::CaptureVideo()
{
HRESULT hr = CoInitialize(NULL);
hr = GetInterfaces();
if (FAILED(hr))
{
AfxMessageBox(_T("Failed to get video interfaces!"));
return hr;
}
hr = pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder);
if (FAILED(hr))
{
AfxMessageBox(_T("Failed to attach the filter graph to the capture graph!"));
return hr;
}
//IAMStreamConfig *pConfig
hr = pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
pVideoCaptureFilter,IID_IAMStreamConfig, (void **)&pConfig);
if (FAILED(hr))
{
AfxMessageBox(_T("Couldn't initialize IAMStreamConfig!"));
}
else
{////
int iCount = 0,iSize = 0;
hr = pConfig->GetNumberOfCapabilities(&iCount,&iSize);
if(iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
{
for(int iFormat = 0;iFormat < iCount;iFormat++)
{
VIDEO_STREAM_CONFIG_CAPS scc;
AM_MEDIA_TYPE *pmtConfig;
hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
if(hr)
{
if((pmtConfig->majortype == MEDIATYPE_Video) &&
(pmtConfig->subtype == MEDIASUBTYPE_RGB24) &&
(pmtConfig->formattype == FORMAT_VideoInfo) &&
(pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&
(pmtConfig->pbFormat != NULL))
{
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
pVih->bmiHeader.biWidth = 1280;
pVih->bmiHeader.biHeight = 720;
pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader);
hr = pConfig->SetFormat(pmtConfi);
}
DeleteMediaType(pmtConfig);
}
}
}
}////
hr = InitMonikers();
if(FAILED(hr))
{
return hr;
}
hr = pGraphBuilder->AddFilter(pVideoCaptureFilter, L"Video Capture");
if (FAILED(hr))
{
pVideoCaptureFilter->Release();
return hr;
}
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pSampleGrabber->SetMediaType(&mt);
hr = pSampleGrabber->SetOneShot(FALSE);
hr = pSampleGrabber->SetBufferSamples(TRUE);
hr = pGraphBuilder->AddFilter(pGrabberF, L"Sample Grabber");
if (FAILED(hr))
{
return hr;
}
hr = pCaptureGraphBuilder2->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pVideoCaptureFilter, pGrabberF, 0 );
if (FAILED(hr))
{
pVideoCaptureFilter->Release();
return hr;
}
hr = pSampleGrabber->GetConnectedMediaType( &mt );
if(FAILED( hr ))
{
return -1;
}
VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
pVih = (VIDEOINFOHEADER*) mt.pbFormat;
CSampleGrabberCB *CB = new CSampleGrabberCB() ;
if(!FAILED( hr ))
{
CB->Width = vih->bmiHeader.biWidth;
CB->Height = vih->bmiHeader.biHeight;
FreeMediaType( mt );
}
hr = pSampleGrabber->SetCallback( CB, 1 );
pVideoCaptureFilter->Release();
this->SetUpVideoWindow();
hr = pMediaControl->Run();
if (FAILED(hr))
{
return hr;
}
return hr;
}
hr = pCaptureGraphBuilder2->FindInterface()
always failed to get the IAMStreamConfig interface, I really don't know why. Can someone help me, thanks so much!
Your API call below
pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
pVideoCaptureFilter,IID_IAMStreamConfig, (void **) &pConfig);
applies several restrictions to the search, including pin category: you are looking for a preview pin. For example, the graph below features three video capture devices and none of them has the dedicated preview pin: preview pin is optional.
You need to take this into account and either relax the search criteria or I would rather suggest that you locate the pin of your interest directly on the capture filter. Then you will set it and and connect it with downstream peer filters. FindInterface is powerful but it also adds chances to get into confusion.

Directshow cant start capture twice

I am trying to follow through the DirectShow examples on the windows dev center to make my own application that can capture screen and audio to video: Capturing Video to an AVI File
The first time capture starts all is ok, but at the second nothing happens, the file with video not appearing. Is it possible that I forgot to uninitialize sometfing?
UPDATE
The problem seems not to be in missing releasing. The second time stream writes the file 1.avi is creating but it empty and when the pMediaControl->Stop(); is done it automatically deletes
UPDATE2
At the second time I found that:
hr = pBuild->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video, // Media type.
pCap, // Capture filter.
NULL, // Intermediate filter (optional).
pMux); // Mux or file sink filter.
returns E_INVALIDARG. So I added (using this):
if (a == 1) {
CComPtr<IPin> sourcePin;
CComPtr<IPin> dumpPin;
sourcePin = GetPin(pMux, PINDIR_OUTPUT);
dumpPin = GetPin(pCap, PINDIR_INPUT);
hr = ppGraph->Connect(sourcePin, dumpPin);
}
And I found thaht on the second time the dumpPin value is NULL .The hr = ppGraph->AddFilter(pCap, L"Capture Filter"); runs ok. Where can I dig next to find error?
(code is updated)
My code:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <dshow.h>
#include <atlbase.h>
#include <dshow.h>
#include <vector>
#include <string>
#pragma comment(lib, "strmiids")
IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir)
{
BOOL bFound = FALSE;
IEnumPins *pEnum;
IPin *pPin;
pFilter->EnumPins(&pEnum);
while (pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION PinDirThis;
pPin->QueryDirection(&PinDirThis);
if (bFound = (PinDir == PinDirThis))
break;
pPin->Release();
}
pEnum->Release();
return (bFound ? pPin : 0);
}
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
// Create the System Device Enumerator.
ICreateDevEnum *pDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the category.
hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; // The category is empty. Treat as an error.
}
pDevEnum->Release();
}
return hr;
}
HRESULT InitCaptureGraphBuilder(
IGraphBuilder **ppGraph, // Receives the pointer.
ICaptureGraphBuilder2 **ppBuild // Receives the pointer.
)
{
if (!ppGraph || !ppBuild)
{
return E_POINTER;
}
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuild = NULL;
// Create the Capture Graph Builder.
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild);
if (SUCCEEDED(hr))
{
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
if (SUCCEEDED(hr))
{
// Initialize the Capture Graph Builder.
pBuild->SetFiltergraph(pGraph);
// Return both interface pointers to the caller.
*ppBuild = pBuild;
*ppGraph = pGraph; // The caller must release both interfaces.
return S_OK;
}
else
{
pBuild->Release();
}
}
return hr; // Failed
}
struct Capture {
IPropertyBag *pPropBag;
IGraphBuilder *ppGraph;
IBaseFilter *pCap;
ICaptureGraphBuilder2 *pBuild;
};
void DisplayDeviceInformation(IEnumMoniker *pEnum,int a)
{
IMoniker *pMoniker = NULL;
std::vector<Capture> captures;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
{
IPropertyBag *pPropBag;
HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (FAILED(hr))
{
pMoniker->Release();
continue;
}
VARIANT var;
VariantInit(&var);
hr = pPropBag->Read(L"DevicePath", &var, 0);
if (SUCCEEDED(hr))
{
// The device path is not intended for display.
printf("Device path: %S\n", var.bstrVal);
VariantClear(&var);
}
IGraphBuilder *ppGraph;
ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder
hr = InitCaptureGraphBuilder(&ppGraph, &pBuild);
IBaseFilter *pCap; // Video capture filter.
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{
std::wstring name = std::wstring(L"C:\\a\\") + std::to_wstring(a) + std::wstring(L".avi");
const wchar_t *cname = name.c_str();
hr = ppGraph->AddFilter(pCap, L"Capture Filter");
if (SUCCEEDED(hr)) {
IBaseFilter *pMux;
hr = pBuild->SetOutputFileName(
&MEDIASUBTYPE_Avi, // Specifies AVI for the target file.
cname, // File name.
&pMux, // Receives a pointer to the mux.
NULL); // (Optional) Receives a pointer to the file sink.
if (a == 1) {
CComPtr<IPin> sourcePin;
CComPtr<IPin> dumpPin;
sourcePin = GetPin(pMux, PINDIR_OUTPUT);
dumpPin = GetPin(pCap, PINDIR_INPUT);
hr = ppGraph->Connect(sourcePin, dumpPin);
}
hr = pBuild->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video, // Media type.
pCap, // Capture filter.
NULL, // Intermediate filter (optional).
pMux); // Mux or file sink filter.
// Release the mux filter.
pMux->Release();
IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
pConfigMux->SetMasterStream(0);
pConfigMux->Release();
}
IConfigInterleaving *pInterleave = NULL;
hr = pMux->QueryInterface(IID_IConfigInterleaving, (void**)&pInterleave);
if (SUCCEEDED(hr))
{
pInterleave->put_Mode(INTERLEAVE_CAPTURE);
pInterleave->Release();
}
pMux->Release();
}
}
Capture capt;
capt.ppGraph = ppGraph;
capt.pPropBag = pPropBag;
capt.pCap = pCap;
capt.pBuild = pBuild;
captures.push_back(capt);
}
for (auto cap : captures)
{
IMediaControl* pMediaControl;
cap.ppGraph->QueryInterface(&pMediaControl);
pMediaControl->Run();
}
Sleep(5000);
for (auto cap : captures)
{
IMediaControl* pMediaControl;
cap.ppGraph->QueryInterface(&pMediaControl);
pMediaControl->Stop();
pMediaControl->Release();
cap.pCap->Release();
cap.ppGraph->Release();
cap.pBuild->Release();
cap.pPropBag->Release();
}
pMoniker->Release();
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
for (int a = 0; a <= 1; a++) {
if (SUCCEEDED(hr))
{
IEnumMoniker *pEnum;
hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
if (SUCCEEDED(hr))
{
DisplayDeviceInformation(pEnum,a);
pEnum->Release();
}
}
}
if (SUCCEEDED(hr))
{
CoUninitialize();
}
int i;
std::cin >> i;
return 0;
}
You might need to Release ppGraph, pBuild, pMediaControl and pCap at the end of DisplayDeviceInformation function and pMux at the end of the cycle. It will be better to use some sort of smart pointers instead.
I didn't figure out how too resolve this, so I just used spawn of external process.

using GetEditBoxText in IFileSaveDialog

The folowing code is a part of my application.
I want to get a value from file save dialog using a editbox.
So i use AddEditBox function and GetEditBoxText to return value.
I enter "2000.0" in the editbox but the rturn value is Empty.
what is the problem?
wstring GetSaveFileForMakeDif(double & MinDistance) {
const DWORD CONTROL_GROUP = 5001;
const DWORD CONTROL_LABEL = 5002;
const DWORD CONTROL_EDITBOX_MINDIST = 5003;
wstring ret(L"");
HRESULT hr = S_FALSE;
IFileDialogCustomize *pfdc = NULL;
// Create a new common open file dialog.
IFileSaveDialog *pfd = NULL;
hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
DWORD dwOptions;
hr = pfd->GetOptions(&dwOptions);
// Set the title of the dialog.
if (SUCCEEDED(hr)) {
hr = pfd->SetTitle(L"Select Files");
hr = pfd->SetFileName(L"outputfile");
hr = pfd->SetDefaultExtension(L"txt");
}
// Set up the customization.
hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
if (SUCCEEDED(hr))
{
hr = pfdc->StartVisualGroup(CONTROL_GROUP, L"");
if (SUCCEEDED(hr))
hr = pfdc->AddText(CONTROL_LABEL, L"Min Distance:");
if (SUCCEEDED(hr))
hr = pfdc->AddEditBox(CONTROL_EDITBOX_MINDIST, L"2000.0");
pfdc->EndVisualGroup();
}
// Show the open file dialog.
if (SUCCEEDED(hr))
{
hr = pfd->Show(hMainWindow);
if (SUCCEEDED(hr))
{
IShellItem *psi = NULL;
hr = pfd->GetResult(&psi);
wchar_t *pszPath = new wchar_t[MAX_PATH];
psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr))
{
ret = pszPath;
wchar_t * txt = NULL;
hr = pfdc->GetEditBoxText(CONTROL_EDITBOX_MINDIST, &txt);
//txt return L""
MinDistance = _wtof(txt);
}
}
}
pfd->Release();
}
pfdc->Release();
return ret;
};
Event handling is needed to catch the values before the dialog closes.
There is a complete MSDN example available here:
Common File Dialog Sample
At the moment the download link does not seem to be available. The example below shows how to catch the event in OnFileOk
Note that you need CoTaskMemFree to release memory which had been allocated by GetEditBoxText
#include <windows.h>
#include <shobjidl.h>
#include <shlwapi.h>
#include <new>
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "Shlwapi.lib")
// Controls
#define CONTROL_GROUP 2000
#define CONTROL_LABEL 5002
#define CONTROL_EDITBOX_MINDIST 5003
class CDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents
{
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) {
static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release() {
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog *pfd);
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK; };
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
IFACEMETHODIMP OnTypeChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
// IFileDialogControlEvents methods
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize *, DWORD, DWORD) { return S_OK; };
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1) { };
private:
~CDialogEventHandler() { };
long _cRef;
};
// Instance creation helper
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
{
*ppv = NULL;
CDialogEventHandler *pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
//EDIT BEGIN ***************************
// IFileDialogEvents methods
IFACEMETHODIMP CDialogEventHandler::OnFileOk(IFileDialog *fileDialog)
{
IFileDialogCustomize *fileCustomize = NULL;
fileDialog->QueryInterface(IID_PPV_ARGS(&fileCustomize));
wchar_t *buf;
fileCustomize->GetEditBoxText(IDC_EDTI1, &buf);
MessageBox(0, buf, 0, 0);
CoTaskMemFree(buf);
fileCustomize->Release();
return S_OK;
}
//EDIT END *****************************
// This code snippet demonstrates how to add custom controls in the Common File Dialog.
HRESULT AddCustomControls()
{
// CoCreate the File Open Dialog object.
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents *pfde = NULL;
DWORD dwCookie = 0;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// Set up a Customization.
IFileDialogCustomize *pfdc = NULL;
if (SUCCEEDED(pfd->QueryInterface(IID_PPV_ARGS(&pfdc))))
{
pfdc->StartVisualGroup(CONTROL_GROUP, L"");
pfdc->AddText(CONTROL_LABEL, L"Min Distance:");
pfdc->AddEditBox(CONTROL_EDITBOX_MINDIST, L"2000.0");
pfdc->EndVisualGroup();
pfdc->Release();
}
else
{
// Unadvise here in case we encounter failures before we get a chance to show the dialog.
pfd->Unadvise(dwCookie);
}
}
pfde->Release();
}
if (SUCCEEDED(hr))
{
// Now show the dialog.
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// You can add your own code here to handle the results.
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfd->Release();
}
return hr;
}
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
AddCustomControls();
CoUninitialize();
return 0;
}

C++ MFC create IShellItem from CLSID (GUID)

I have to create a ShellItem to Windows Help and Windows Run...
I have this
Help and Support {2559a1f1-21d7-11d4-bdaf-00c04f60b9f0}
Run {2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}
from http://www.sevenforums.com/tutorials/110919-clsid-key-list-windows-7-a.html
I've tried
IShellFolder* desk = NULL;
HRESULT hr =SHGetDesktopFolder(&desk);
LPITEMIDLIST pidl2=NULL;
ULONG cbEaten;
DWORD dwAttribs = 0 ;
hr = desk->ParseDisplayName(NULL,
NULL,
L"::{2559A1F1-21D7-11D4-BDAF-00C04F60B9F0}",
&cbEaten, // This can be NULL
&pidl2,
&dwAttribs);
It returns OK but Null as pidl2
could you guys give me some help?
ParseDisplayName should be able to parse it if you pass "shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}" but I guess that is not really what you want.
ParseDisplayName is able to parse some ::{clsid} paths but I think it is restricted to a very limited set of CSIDL_* special folders. SHSimpleIDListFromPath was able to parse it.
If you really want to parse it with ParseDisplayName you can try to emulate SHSimpleIDListFromPath:
class EmptyFileSystemBindData : public IFileSystemBindData {
public:
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown || riid == IID_IFileSystemBindData) {
*ppv = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
*ppv = NULL; return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP SetFindData(const WIN32_FIND_DATAW *pfd)
{
return S_OK;
}
STDMETHODIMP GetFindData(WIN32_FIND_DATAW *pfd)
{
ZeroMemory(pfd,sizeof(WIN32_FIND_DATAW));
return S_OK;
}
};
LPITEMIDLIST pidl2=NULL;
HRESULT hr;
IShellFolder*psf;
IBindCtx*pbc;
hr = CreateBindCtx(0,&pbc);
EmptyFileSystemBindData efsbd;
if (SUCCEEDED(hr))
{
BIND_OPTS bo = {sizeof(bo)};
bo.grfMode = STGM_CREATE;
hr = pbc->RegisterObjectParam(STR_FILE_SYS_BIND_DATA,&efsbd);
if (SUCCEEDED(hr) && 0==pbc->SetBindOptions(&bo))
{
hr = SHGetDesktopFolder(&psf);
if (SUCCEEDED(hr))
{
hr = psf->ParseDisplayName(0,pbc,L"::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}",0,&pidl2,0);
if (SUCCEEDED(hr))
{
OutputDebugStringA("parsed ok\n");
ILFree(pidl2);
}
psf->Release();
}
}
pbc->Release();
}