Freigeben über


Aufnehmen eines Bilds aus einer Standbildnadel

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde durch MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation ersetzt. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code nach Möglichkeit MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet. Microsoft schlägt vor, vorhandenen Code, der die Legacy-APIs verwendet, um nach Möglichkeit die neuen APIs zu verwenden.]

Einige Kameras können ein vom Aufnahmestream getrenntes Standbild erzeugen, und häufig ist das Standbild von höherer Qualität als die Bilder, die vom Aufnahmestream erzeugt werden. Die Kamera verfügt möglicherweise über eine Schaltfläche, die als Hardwaretrigger fungiert, oder sie unterstützt das Auslösen von Software. Eine Kamera, die Standbilder unterstützt, macht einen Standbildnadel verfügbar, bei dem es sich um eine Anheftkategorie PIN_CATEGORY_STILL handelt.

Die empfohlene Möglichkeit zum Abrufen von Standbildern vom Gerät ist die Verwendung der Windows Image Acquisition (WIA)-APIs. Weitere Informationen finden Sie unter "Windows Image Acquisition" in der Platform SDK-Dokumentation. Sie können directShow jedoch auch verwenden, um ein Bild zu erfassen.

Verwenden Sie die IAMVideoControl::SetMode-Methode , wenn das Diagramm ausgeführt wird, wie folgt, um die Anheftung auszulösen:

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();
}

Abfragen des Erfassungsfilters für IAMVideoControl. Wenn die Schnittstelle unterstützt wird, rufen Sie einen Zeiger auf die IPin-Schnittstelle des Noch-Pins ab, indem Sie die ICaptureGraphBuilder2::FindPin-Methode aufrufen, wie im vorherigen Beispiel gezeigt. Rufen Sie dann IAMVideoControl::SetMode mit dem IPin-Zeiger und dem VideoControlFlag_Trigger-Flag auf.

Hinweis

Abhängig von der Kamera müssen Sie möglicherweise den Aufnahmenadel (PIN_CATEGORY_CAPTURE) rendern, bevor der Noch-Pin verbunden wird.

 

Beispiel: Verwenden des Beispielgrabberfilters

Eine Möglichkeit zum Erfassen des Bilds ist der Filter Sample Grabber . Der Beispielgrabber verwendet eine anwendungsdefinierte Rückruffunktion, um das Image zu verarbeiten. Weitere Informationen zum Filter Sample Grabber finden Sie unter Verwenden des Beispielgrabbers.

Im folgenden Beispiel wird davon ausgegangen, dass die Noch-Pin ein unkomprimiertes RGB-Bild liefert. Definieren Sie zunächst eine Klasse, die die Rückrufschnittstelle ISampleGrabberCB des Beispielgrabber implementiert:

// 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;

Die Implementierung der -Klasse wird kurz beschrieben.

Verbinden Sie als Nächstes die Noch-Pin mit dem Beispielgrabber, und verbinden Sie den Beispielgrabber mit dem Null-Renderer-Filter . Der Null-Renderer verwirft einfach Medienbeispiele, die er empfängt. die eigentliche Arbeit wird innerhalb des Rückrufs erledigt. (Der einzige Grund für den Null-Renderer besteht darin, den Ausgabepin des Beispielgrabbers mit etwas zu verbinden.) Rufen Sie CoCreateInstance auf, um die Filter Sample Grabber und Null Renderer zu erstellen, und rufen Sie IFilterGraph::AddFilter auf, um dem Diagramm beide Filter hinzuzufügen:

// 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");

Sie können die ICaptureGraphBuilder2::RenderStream-Methode verwenden, um alle drei Filter in einem Methodenaufruf zu verbinden, von der noch-Anheftung zum Beispielgrabber und vom Sample Grabber zum 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.

Verwenden Sie nun die ISampleGrabber-Schnittstelle , um den Beispielgrabber so zu konfigurieren, dass er Beispiele puffert:

// 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);

    ...

Legen Sie die Rückrufschnittstelle mit einem Zeiger auf Ihr Rückrufobjekt fest:

hr = pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback method.

Rufen Sie den Medientyp ab, den der noch angeheftet hat, um eine Verbindung mit dem Beispielgrabber herzustellen:

// Store the media type for later use.
AM_MEDIA_TYPE g_StillMediaType;

hr = pSG->GetConnectedMediaType(&g_StillMediaType);
pSG->Release();

Dieser Medientyp enthält die BITMAPINFOHEADER-Struktur , die das Format des Standbilds definiert. Geben Sie den Medientyp frei, bevor die Anwendung beendet wird:

// On exit, remember to release the media type.
FreeMediaType(g_StillMediaType);

Im Folgenden sehen Sie ein Beispiel für die Rückrufklasse. Beachten Sie, dass die -Klasse IUnknown implementiert, das sie über die ISampleGrabber-Schnittstelle erbt, aber keine Verweisanzahl behält. Dies ist sicher, da die Anwendung das Objekt auf dem Stapel erstellt und das Objekt während der gesamten Lebensdauer des Filterdiagramms im Gültigkeitsbereich verbleibt.

Die gesamte Arbeit erfolgt in der BufferCB-Methode , die vom Sample Grabber aufgerufen wird, wenn ein neues Beispiel abgerufen wird. Im folgenden Beispiel schreibt die Methode die Bitmap in eine Datei:

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;

    }
};

Videoaufnahmeaufgaben