Acquisizione di un'immagine da un pin immagine ancora
[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation anziché DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.
Alcune fotocamere possono produrre un'immagine ancora separata dal flusso di acquisizione e spesso l'immagine ancora è di qualità superiore rispetto alle immagini prodotte dal flusso di acquisizione. La fotocamera può avere un pulsante che funge da trigger hardware oppure può supportare l'attivazione del software. Una fotocamera che supporta immagini ancora espone un pin di immagine ancora, che è una categoria di pin PIN_CATEGORY_STILL.
Il modo consigliato per ottenere immagini ancora dal dispositivo consiste nell'usare le API Windows Image Acquisition (WIA). Per altre informazioni, vedere "Acquisizione immagini di Windows" nella documentazione di Platform SDK. Tuttavia, è anche possibile usare DirectShow per acquisire un'immagine.
Per attivare il pin, usare il metodo IAMVideoControl::SetMode quando il grafico è in esecuzione, come indicato di seguito:
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();
}
Eseguire una query sul filtro di acquisizione per IAMVideoControl. Se l'interfaccia è supportata, ottenere un puntatore all'interfaccia IPin del pin ancora chiamando il metodo ICaptureGraphBuilder2::FindPin , come illustrato nell'esempio precedente. Chiamare quindi IAMVideoControl::SetMode con il puntatore IPin e il flag di VideoControlFlag_Trigger.
Nota
A seconda della fotocamera, potrebbe essere necessario eseguire il rendering del pin di acquisizione (PIN_CATEGORY_CAPTURE) prima che il pin ancora si connetti.
Esempio: Uso del filtro Grabber di esempio
Un modo per acquisire l'immagine è con il filtro Sample Grabber . Sample Grabber usa una funzione di callback definita dall'applicazione per elaborare l'immagine. Per altre informazioni sul filtro Sample Grabber, vedere Uso di Sample Grabber.
Nell'esempio seguente si presuppone che il pin continui a recapitare un'immagine RGB non compressa. Definire prima di tutto una classe che implementerà l'interfaccia di callback di 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;
L'implementazione della classe è descritta brevemente.
Connettere quindi il pin ancora all'oggetto Sample Grabber e connettere il filtro Sample Grabber al filtro Renderer Null . Il renderer Null elimina semplicemente gli esempi multimediali ricevuti; il lavoro effettivo verrà eseguito all'interno del callback. L'unico motivo per il renderer Null consiste nel connettere il pin di output di Sample Grabber a qualcosa. Chiamare CoCreateInstance per creare i filtri Sample Grabber e Null Renderer e chiamare IFilterGraph::AddFilter per aggiungere entrambi i filtri al grafico:
// 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");
È possibile usare il metodo ICaptureGraphBuilder2::RenderStream per connettere tutti e tre i filtri in una chiamata al metodo, passando dal pin ancora all'oggetto Sample Grabber e dal Sample Grabber al Renderer Null:
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.
Usare ora l'interfaccia ISampleGrabber per configurare Sample Grabber in modo che bufferi esempi:
// 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);
...
Impostare l'interfaccia di callback con un puntatore all'oggetto callback:
hr = pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback method.
Ottenere il tipo di supporto usato dal pin ancora usato per connettersi con Sample Grabber:
// Store the media type for later use.
AM_MEDIA_TYPE g_StillMediaType;
hr = pSG->GetConnectedMediaType(&g_StillMediaType);
pSG->Release();
Questo tipo di supporto conterrà la struttura BITMAPINFOHEADER che definisce il formato dell'immagine ancora. Liberare il tipo di supporto prima dell'uscita dell'applicazione:
// On exit, remember to release the media type.
FreeMediaType(g_StillMediaType);
Di seguito è riportato un esempio della classe callback. Si noti che la classe implementa IUnknown, che eredita tramite l'interfaccia ISampleGrabber , ma non mantiene un conteggio dei riferimenti. Questo è sicuro perché l'applicazione crea l'oggetto nello stack e l'oggetto rimane nell'ambito durante la durata del grafico del filtro.
Tutto il lavoro si verifica nel metodo BufferCB , che viene chiamato da Sample Grabber ogni volta che ottiene un nuovo esempio. Nell'esempio seguente il metodo scrive la bitmap in un file:
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;
}
};
Argomenti correlati