Captura de una imagen a partir de un pin de imagen fija
[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.
Algunas cámaras pueden producir una imagen fija independiente de la secuencia de captura y, a menudo, la imagen fija es de mayor calidad que las imágenes generadas por la secuencia de captura. La cámara puede tener un botón que actúa como un desencadenador de hardware o puede admitir el desencadenador de software. Una cámara que admita imágenes fijas expondrá un pin de imagen todavía, que es la categoría de patillas PIN_CATEGORY_STILL.
La manera recomendada de obtener imágenes fijas del dispositivo es usar las API de adquisición de imágenes de Windows (WIA). Para obtener más información, consulte "Adquisición de imágenes de Windows" en la documentación del SDK de plataforma. Sin embargo, también puede usar DirectShow para capturar una imagen.
Para desencadenar el anclaje, use el método IAMVideoControl::SetMode cuando se ejecute el grafo, como se indica a continuación:
IAMVideoControl *pAMVidControl = NULL;
hr = pControl->Run(); // Run the graph.
if (FAILED(hr))
{
// Handle error.
}
hr = pCap->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl);
if (SUCCEEDED(hr))
{
// Find the still pin.
IPin *pPin = NULL;
// pBuild is an ICaptureGraphBuilder2 pointer.
hr = pBuild->FindPin(
pCap, // Filter.
PINDIR_OUTPUT, // Look for an output pin.
&PIN_CATEGORY_STILL, // Pin category.
NULL, // Media type (don't care).
FALSE, // Pin must be unconnected.
0, // Get the 0'th pin.
&pPin // Receives a pointer to thepin.
);
if (SUCCEEDED(hr))
{
hr = pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);
pPin->Release();
}
pAMVidControl->Release();
}
Consulte el filtro de captura para IAMVideoControl. Si se admite la interfaz, obtenga un puntero a la interfaz IPin del pin todavía llamando al método ICaptureGraphBuilder2::FindPin , como se muestra en el ejemplo anterior. A continuación, llame a IAMVideoControl::SetMode con el puntero IPin y la marca VideoControlFlag_Trigger.
Nota:
En función de la cámara, es posible que tenga que representar el pin de captura (PIN_CATEGORY_CAPTURE) antes de que se conecte la patilla fija.
Ejemplo: Uso del filtro de captura de ejemplo
Una manera de capturar la imagen es con el filtro Sample Grabber . Sample Grabber usa una función de devolución de llamada definida por la aplicación para procesar la imagen. Para obtener más información sobre el filtro Sample Grabber, vea Using the Sample Grabber.
En el ejemplo siguiente se da por hecho que el anclaje sigue entregando una imagen RGB sin comprimir. En primer lugar, defina una clase que implementará la interfaz de devolución de llamada de Sample Grabber, ISampleGrabberCB:
// Class to hold the callback function for the Sample Grabber filter.
class SampleGrabberCallback : public ISampleGrabberCB
{
// Implementation is described later.
}
// Global instance of the class.
SampleGrabberCallback g_StillCapCB;
La implementación de la clase se describe en breve.
A continuación, conecte el anclaje todavía a Sample Grabber y conecte sample Grabber al filtro Representador nulo . El representador null simplemente descarta las muestras multimedia que recibe; el trabajo real se realizará dentro de la devolución de llamada. (El único motivo por el que el representador null es conectar el pin de salida de Sample Grabber a algo). Llame a CoCreateInstance para crear los filtros Sample Grabber y Null Renderer y llame a IFilterGraph::AddFilter para agregar ambos filtros al grafo:
// Add the Sample Grabber filter to the graph.
IBaseFilter *pSG_Filter;
hr = CoCreateInstance(
CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pSG_Filter
);
hr = pGraph->AddFilter(pSG_Filter, L"SampleGrab");
// Add the Null Renderer filter to the graph.
IBaseFilter *pNull;
hr = CoCreateInstance(
CLSID_NullRenderer,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pNull
);
hr = pGraph->AddFilter(pNull, L"NullRender");
Puede usar el método ICaptureGraphBuilder2::RenderStream para conectar los tres filtros de una llamada de método, pasando desde la anclar a Sample Grabber y desde sample Grabber a null Renderer:
hr = pBuild->RenderStream(
&PIN_CATEGORY_STILL, // Connect this pin ...
&MEDIATYPE_Video, // with this media type ...
pCap, // on this filter ...
pSG_Filter, // to the Sample Grabber ...
pNull); // ... and finally to the Null Renderer.
Ahora, use la interfaz ISampleGrabber para configurar sample Grabber para que almacene en búfer ejemplos:
// Configure the Sample Grabber.
ISampleGrabber *pSG = NULL;
hr = pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG);
if (SUCCEEDED(hr))
{
hr = pSG->SetOneShot(FALSE);
hr = pSG->SetBufferSamples(TRUE);
...
Establezca la interfaz de devolución de llamada con un puntero al objeto de devolución de llamada:
hr = pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback method.
Obtenga el tipo de medio que el pin que se sigue usando para conectarse con sample Grabber:
// Store the media type for later use.
AM_MEDIA_TYPE g_StillMediaType;
hr = pSG->GetConnectedMediaType(&g_StillMediaType);
pSG->Release();
Este tipo de medio contendrá la estructura BITMAPINFOHEADER que define el formato de la imagen fija. Libere el tipo de medio antes de que se cierre la aplicación:
// On exit, remember to release the media type.
FreeMediaType(g_StillMediaType);
Lo siguiente es un ejemplo de la clase de devolución de llamada. Tenga en cuenta que la clase implementa IUnknown, que hereda a través de la interfaz ISampleGrabber , pero no mantiene un recuento de referencias. Esto es seguro porque la aplicación crea el objeto en la pila y el objeto permanece en el ámbito durante toda la duración del gráfico de filtros.
Todo el trabajo se produce en el método BufferCB , al que llama sample Grabber cada vez que obtiene un nuevo ejemplo. En el ejemplo siguiente, el método escribe el mapa de bits en un archivo:
class SampleGrabberCallback : public ISampleGrabberCB
{
public:
// Fake referance counting.
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 2; }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
{
if (NULL == ppvObject) return E_POINTER;
if (riid == __uuidof(IUnknown))
{
*ppvObject = static_cast<IUnknown*>(this);
return S_OK;
}
if (riid == __uuidof(ISampleGrabberCB))
{
*ppvObject = static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
return E_NOTIMPL;
}
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)
{
return E_NOTIMPL;
}
STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen)
{
if ((g_StillMediaType.majortype != MEDIATYPE_Video) ||
(g_StillMediaType.formattype != FORMAT_VideoInfo) ||
(g_StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER)) ||
(g_StillMediaType.pbFormat == NULL))
{
return VFW_E_INVALIDMEDIATYPE;
}
HANDLE hf = CreateFile("C:\\Example.bmp", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hf == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
long cbBitmapInfoSize = g_StillMediaType.cbFormat - SIZE_PREHEADER;
VIDEOINFOHEADER *pVideoHeader =
(VIDEOINFOHEADER*)g_StillMediaType.pbFormat;
BITMAPFILEHEADER bfh;
ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 'MB'; // Little-endian for "BM".
bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;
bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;
// Write the file header.
DWORD dwWritten = 0;
WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL);
WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );
CloseHandle( hf );
return S_OK;
}
};
Temas relacionados