DirectShow: webcam de prévisualisation et capture d'image
Après avoir regardé une question très semblable et de voir presque à l'identique le code, j'ai décidé de poser cette question séparément. Je veux montrer un aperçu de la vidéo de la webcam du flux vidéo vers la fenêtre par défaut utilise DirectShow, et je veux aussi la possibilité de "prendre une photo" de la diffusion de la vidéo à un moment donné.
J'ai commencé avec le DirectShow exemples sur MSDN, ainsi que la AMCap exemple de code, et qui ont quelque chose à mon avis, devrait l'aperçu de la partie, mais ne le fait pas. Je n'ai trouvé aucun exemple de capture d'une image à partir d'un flux vidéo à l'exception de l'aide SampleGrabber, qui est obsolète et donc j'essaie de ne pas l'utiliser.
Ci-dessous mon code, ligne par ligne. Notez que la plupart du code de EnumerateCameras est commenté. Ce code aurait été pour les attacher à une autre fenêtre, je ne veux pas faire. Dans la documentation MSDN, il est dit explicitement que le VMR_7 crée sa propre fenêtre pour afficher le flux vidéo. Je n'ai pas d'erreurs dans mon application, mais cette fenêtre n'apparaît jamais.
Ma question alors est: est-ce Que je fais mal? Sinon, si vous connaissez un exemple simple de ce que je suis en train de faire, de me lier à lui. AMCap est pas un exemple simple, pour référence.
REMARQUE: InitalizeVMR est pour l'exécution dans la fenêtre de l'état, qui est mon but ultime (l'intégration dans un DirectX jeu). Pour l'instant, cependant, j'ai juste envie de s'exécuter dans le mode le plus simple possible.
EDIT: La première partie de cette question, c'est de la prévisualisation de la caméra de flux, est résolu. Je suis maintenant à la recherche d'une alternative à l'obsolète SampleGrabber classe afin que je puisse prendre une photo à tout moment et d'enregistrer dans un fichier.
EDIT: Après avoir cherché pendant près d'une heure sur google, le consensus général semble être que vous AVEZ à utiliser ISampleGrabber. S'il vous plaît laissez-moi savoir si vous trouvez quelque chose de différent.
Test de code (main.cpp):
CWebcam* camera = new CWebcam();
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
MessageBox(NULL, L"text", L"caption", NULL);
if (SUCCEEDED(hr))
{
camera->Create();
camera->EnumerateCameras();
camera->StartCamera();
}
int d;
cin >> d;
Webcam.cpp:
#include "Webcam.h"
CWebcam::CWebcam() {
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
//m_pTexInst = nullptr;
//m_pTexRes = nullptr;
}
CWebcam::~CWebcam() {
CoUninitialize();
m_pDeviceMonikers->Release();
m_pMediaController->Release();
}
BOOL CWebcam::Create() {
InitCaptureGraphBuilder(&m_pFilterGraph, &m_pCaptureGraph);
hr = m_pFilterGraph->QueryInterface(IID_IMediaControl, (void **)&m_pMediaController);
return TRUE;
}
void CWebcam::Destroy() {
}
void CWebcam::EnumerateCameras() {
HRESULT hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &m_pDeviceMonikers);
if (SUCCEEDED(hr))
{
//DisplayDeviceInformation(m_pDeviceMonikers);
//m_pDeviceMonikers->Release();
IMoniker *pMoniker = NULL;
if(m_pDeviceMonikers->Next(1, &pMoniker, NULL) == S_OK)
{
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pCameraFilter);
if (SUCCEEDED(hr))
{
hr = m_pFilterGraph->AddFilter(m_pCameraFilter, L"Capture Filter");
}
}
//connect the output pin to the video renderer
if(SUCCEEDED(hr))
{
hr = m_pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
m_pCameraFilter, NULL, NULL);
}
//InitializeVMR(hwnd, m_pFilterGraph, &m_pVMRControl, 1, FALSE);
//get the video window that will be displayed from the filter graph
IVideoWindow *pVideoWindow = NULL;
hr = m_pFilterGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideoWindow);
/*if(hr != NOERROR)
{
printf("This graph cannot preview properly");
}
else
{
//get the video stream configurations
hr = m_pCaptureGraph->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, m_pCameraFilter,
IID_IAMStreamConfig, (void **)&m_pVideoStreamConfig);
//Find out if this is a DV stream
AM_MEDIA_TYPE *pMediaTypeDV;
//fake window handle
HWND window = NULL;
if(m_pVideoStreamConfig && SUCCEEDED(m_pVideoStreamConfig->GetFormat(&pMediaTypeDV)))
{
if(pMediaTypeDV->formattype == FORMAT_DvInfo)
{
//in this case we want to set the size of the parent window to that of
//current DV resolution.
//We get that resolution from the IVideoWindow.
IBasicVideo* pBasivVideo;
//If we got here, gcap.pVW is not NULL
//ASSERT(pVideoWindow != NULL);
hr = pVideoWindow->QueryInterface(IID_IBasicVideo, (void**)&pBasivVideo);
/*if(SUCCEEDED(hr))
{
HRESULT hr1, hr2;
long lWidth, lHeight;
hr1 = pBasivVideo->get_VideoHeight(&lHeight);
hr2 = pBasivVideo->get_VideoWidth(&lWidth);
if(SUCCEEDED(hr1) && SUCCEEDED(hr2))
{
ResizeWindow(lWidth, abs(lHeight));
}
}
}
}
RECT rc;
pVideoWindow->put_Owner((OAHWND)window); //We own the window now
pVideoWindow->put_WindowStyle(WS_CHILD); //you are now a child
GetClientRect(window, &rc);
pVideoWindow->SetWindowPosition(0, 0, rc.right, rc.bottom); //be this big
pVideoWindow->put_Visible(OATRUE);
}*/
}
}
BOOL CWebcam::StartCamera() {
if(m_bIsStreaming == FALSE)
{
m_bIsStreaming = TRUE;
hr = m_pMediaController->Run();
if(FAILED(hr))
{
//stop parts that ran
m_pMediaController->Stop();
return FALSE;
}
return TRUE;
}
return FALSE;
}
void CWebcam::EndCamera() {
if(m_bIsStreaming)
{
hr = m_pMediaController->Stop();
m_bIsStreaming = FALSE;
//invalidate client rect as well so that it must redraw
}
}
BOOL CWebcam::CaptureToTexture() {
return TRUE;
}
HRESULT CWebcam::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
}
HRESULT CWebcam::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
//Create the System Device Enumerator.
ICreateDevEnum *pSystemDeviceEnumerator;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSystemDeviceEnumerator));
if (SUCCEEDED(hr))
{
//Create an enumerator for the category.
hr = pSystemDeviceEnumerator->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE)
{
hr = VFW_E_NOT_FOUND; //The category is empty. Treat as an error.
}
pSystemDeviceEnumerator->Release();
}
return hr;
}
void CWebcam::DisplayDeviceInformation(IEnumMoniker *pEnum)
{
IMoniker *pMoniker = NULL;
int counter = 0;
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);
//Get description or friendly name.
hr = pPropBag->Read(L"Description", &var, 0);
if (FAILED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &var, 0);
}
if (SUCCEEDED(hr))
{
printf("%d: %S\n", counter, var.bstrVal);
VariantClear(&var);
}
hr = pPropBag->Write(L"FriendlyName", &var);
//WaveInID applies only to audio capture devices.
hr = pPropBag->Read(L"WaveInID", &var, 0);
if (SUCCEEDED(hr))
{
printf("%d: WaveIn ID: %d\n", counter, var.lVal);
VariantClear(&var);
}
hr = pPropBag->Read(L"DevicePath", &var, 0);
if (SUCCEEDED(hr))
{
//The device path is not intended for display.
printf("%d: Device path: %S\n", counter, var.bstrVal);
VariantClear(&var);
}
pPropBag->Release();
pMoniker->Release();
counter++;
}
}
HRESULT CWebcam::InitializeVMR(
HWND hwndApp, //Application window.
IGraphBuilder* pFG, //Pointer to the Filter Graph Manager.
IVMRWindowlessControl** ppWc, //Receives the interface.
DWORD dwNumStreams, //Number of streams to use.
BOOL fBlendAppImage //Are we alpha-blending a bitmap?
)
{
IBaseFilter* pVmr = NULL;
IVMRWindowlessControl* pWc = NULL;
*ppWc = NULL;
//Create the VMR and add it to the filter graph.
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
if (FAILED(hr))
{
return hr;
}
hr = pFG->AddFilter(pVmr, L"Video Mixing Renderer");
if (FAILED(hr))
{
pVmr->Release();
return hr;
}
//Set the rendering mode and number of streams.
IVMRFilterConfig* pConfig;
hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
if (SUCCEEDED(hr))
{
pConfig->SetRenderingMode(VMRMode_Windowless);
//Set the VMR-7 to mixing mode if you want more than one video
//stream, or you want to mix a static bitmap over the video.
//(The VMR-9 defaults to mixing mode with four inputs.)
if (dwNumStreams > 1 || fBlendAppImage)
{
pConfig->SetNumberOfStreams(dwNumStreams);
}
pConfig->Release();
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
if (SUCCEEDED(hr))
{
pWc->SetVideoClippingWindow(hwndApp);
*ppWc = pWc; //The caller must release this interface.
}
}
pVmr->Release();
//Now the VMR can be connected to other filters.
return hr;
}
OriginalL'auteur Darkhydro | 2011-09-26
Vous devez vous connecter pour publier un commentaire.
En mode sans fenêtre VMR ne serait pas de créer une fenêtre séparée. Depuis le début de l'initialisation pour widnowless la mode, vous devez suivre SetVideoClippingWindow avec IVMRWindowlessControl::SetVideoPosition appel pour fournir la position à l'intérieur de la fenêtre, voir VMR Mode sans Fenêtre sur MSDN.
Un autre exemple extrait de code pour vous: http://www.assembla.com/code/roatl-utilities/subversion/nodes/trunk/FullScreenWindowlessVmrSample01/MainDialog.h#ln188
J'ai vérifié votre code une fois de plus, et que faites-vous après StartCamera retourne? Vous devez avoir un message en boucle, de sorte que le filtre graphique pourrait envoyer ses messages, il pourrait être l'envoi. Faites-vous quelque chose de ce genre? Peut-être vous avez besoin d'un autre MessageBox après StartCamera pour vérifier si c'est le problème.
Je ne savais pas que je devais traiter les messages Windows pour le mode fenêtré (compatibilité). Je ne suis pas de traitement de tous les messages de windows pour le moment. Quel est le traitement que je dois faire, ou puis-je juste une simple boucle de message et de ne rien faire avec les messages?
Vous avez juste besoin d'un message régulier de la boucle, de sorte que les messages postés sont expédiés. C'est ce que je voulais dire en mettant un MessageBox - puisqu'il pompe les messages avec une seule ligne de code.
Malade de l'essayer et reeport bientôt de retour. Merci
OriginalL'auteur Roman R.