Aracılığıyla paylaş


Örnek Yakalayıcıyı Kullanma

[DirectShow bu sayfayla ilişkilendirilmiş özellik eski bir özelliktir. Yerine MediaPlayer, IMFMediaEngineve Media Foundation 'de Ses/Video Yakalamaalmıştır. Bu özellikler Windows 10 ve Windows 11 için iyileştirilmiştir. Microsoft, mümkün olduğunda, yeni kodun DirectShowyerine MediaPlayer, IMFMediaEngine ve Media Foundation'daki Audio/Video Capture kullanmasını şiddetle önerir. Microsoft, mümkünse yeni API'leri kullanmak için eski API'leri kullanan mevcut kodun yeniden yazılmasını önerir.]

[Bu API desteklenmez ve gelecekte değiştirilebilir veya kullanılamayabilir.]

Sample Grabber filtresi, filtre grafiğinden geçerken akıştan medya örnekleri almak için kullanılabilecek bir dönüştürme filtresidir.

Bir video dosyasından bit eşlem almak istiyorsanız, Medya Algılayıcısı (MediaDet) nesnesini kullanmak daha kolaydır. Ayrıntılar için bkz. Afiş Çerçevesini Yakalama. Bununla birlikte, Sample Grabber daha esnektir çünkü neredeyse tüm medya türleriyle çalışır (bkz. ISampleGrabber::SetMediaType birkaç özel durum için) ve uygulama için daha fazla denetim sunar.

Filtre Grafı Yöneticisi'ni oluşturma

Başlamak için Filtre Graf Yöneticisi oluşturun ve IMediaControl ile IMediaEventEx arabirimlerini sorgulayın.

    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEventEx *pEvent = NULL;


    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, 
        CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pGraph));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
    if (FAILED(hr))
    {
        goto done;
    }

Filtre Grafı'na Örnek Yakalayıcı ekleme

Örnek Kavrayıcı filtresinin bir örneğini oluşturun ve filtre grafiğine ekleyin. ISampleGrabber arabirimi için Örnek Kavrayıcı filtresini sorgula.

    IBaseFilter *pGrabberF = NULL;
    ISampleGrabber *pGrabber = NULL;


    // Create the Sample Grabber filter.
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pGrabberF));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pGrabber));
    if (FAILED(hr))
    {
        goto done;
    }

Medya Türünü Ayarlama

Sample Grabber'ı ilk oluşturduğunuzda tercih edilen medya türü yoktur. Bu, grafikteki hemen her filtreye bağlanabileceğiniz, ancak aldığı verilerin türü üzerinde hiçbir denetiminiz olmayacağı anlamına gelir. Bu nedenle grafiğin geri kalanını oluşturmadan önce, ISampleGrabber::SetMediaType yöntemini çağırarak Sample Grabber için bir medya türü ayarlamanız gerekir.

Örnek Yakalayıcı bağlandığında, bu medya türünü diğer filtre tarafından sunulan medya türüyle karşılaştırır. Denetleyebilen tek alanlar ana tür, alt tür ve biçim türüdür. Bunlardan herhangi biri için GUID_NULL değeri "herhangi bir değeri kabul et" anlamına gelir. Çoğu zaman ana türü ve alt türü ayarlamak istersiniz. Örneğin, aşağıdaki kod sıkıştırılmamış 24 bit RGB videosunu belirtir:

    AM_MEDIA_TYPE mt;
    ZeroMemory(&mt, sizeof(mt));
    mt.majortype = MEDIATYPE_Video;
    mt.subtype = MEDIASUBTYPE_RGB24;

    hr = pGrabber->SetMediaType(&mt);
    if (FAILED(hr))
    {
        goto done;
    }

Filtre Grafı Oluşturma

Artık filtre grafiğinin geri kalanını oluşturabilirsiniz. Örnek Yakalayıcı yalnızca belirttiğiniz medya türünü kullanarak bağlanacağından, grafiği oluştururken Filter Graph Manager'ın Intelligent Connect mekanizmalarından yararlanmanızı sağlar.

Örneğin, sıkıştırılmamış video belirttiyseniz, Örnek Kaplayıcı'ya bir kaynak filtre bağlayabilirsiniz ve Filtre Grafı Yöneticisi dosya ayrıştırıcısını ve kod çözücüsünü otomatik olarak ekler. Aşağıdaki örnek, İki Filtreyi Bağlalistesinde yer alan ConnectFilters yardımcı işlevini kullanır:

    IBaseFilter *pSourceF = NULL;
    IEnumPins *pEnum = NULL;
    IPin *pPin = NULL;


    hr = pGraph->AddSourceFilter(pszVideoFile, L"Source", &pSourceF);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pSourceF->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        goto done;
    }

    while (S_OK == pEnum->Next(1, &pPin, NULL))
    {
        hr = ConnectFilters(pGraph, pPin, pGrabberF);
        SafeRelease(&pPin);
        if (SUCCEEDED(hr))
        {
            break;
        }
    }

    if (FAILED(hr))
    {
        goto done;
    }

Örnek Kavrayıcı bir dönüşüm filtresidir, bu nedenle çıkış pini başka bir filtreye bağlanmalıdır. Genellikle, örnekleri işiniz bittikten sonra atmak isteyebilirsiniz. Bu durumda, Sample Grabber'ı aldığı verileri atacak olan Null Renderer Filtresi'e bağlayın.

Aşağıdaki örnek, Sample Grabber'ı Null İşleyici filtresine bağlar:

    IBaseFilter *pNullF = NULL;


    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, 
        IID_PPV_ARGS(&pNullF));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->AddFilter(pNullF, L"Null Filter");
    if (FAILED(hr))
    {
        goto done;
    }

    hr = ConnectFilters(pGraph, pGrabberF, pNullF);
    if (FAILED(hr))
    {
        goto done;
    }

Örnek Kavrayıcı'nın bir video kod çözücü ile video işleyicisi arasına yerleştirilmesinin işleme performansını önemli ölçüde kötü hale getirebileceğini unutmayın. Sample Grabber bir yerinde dönüştürme filtresidir; bu da çıkış arabelleğinin giriş arabelleğiyle aynı olduğu anlamına gelir. Video işleme için çıkış arabelleği, ana bellekteki okuma işlemleriyle karşılaştırıldığında, okuma işlemlerinin çok daha yavaş olduğu grafik kartında yer alacaktır.

Grafı Çalıştırma

Sample Grabber iki moddan birinde çalışır:

  • Arabelleğe alma modu, her örneğin bir kopyasını yapar ve bu kopyayı aşağı akışa teslim eder.
  • Geri çağırma modu, her örnekte uygulama tanımlı bir geri çağırma işlevi çağırır.

Bu makalede arabelleğe alma modu açıklanmaktadır. (Geri çağırma modunu kullanmadan önce geri çağırma işlevinin oldukça sınırlı olması gerektiğini unutmayın. Aksi takdirde, performansı önemli ölçüde azaltabilir ve hatta kilitlenmelere neden olabilir. Daha fazla bilgi için bkz. ISampleGrabber::SetCallback.) Arabelleğe alma modunu etkinleştirmek için ISampleGrabber::SetBufferSamples yöntemini TRUE değeriyle çağırın.

İsteğe bağlı olarak ISampleGrabber::SetOneShot yöntemini TRUE değeriyle çağırın. Bu, Sample Grabber'ın ilk medya örneğini aldıktan sonra durmasına neden olur. Bu, akıştan tek bir çerçeve almak istediğinizde kullanışlıdır. İstediğiniz zamanı arayın, grafiği çalıştırın ve EC_COMPLETE olayını bekleyin. Çerçeve doğruluk düzeyinin kaynağa bağlı olduğunu unutmayın. Örneğin, bir MPEG dosyasını ararken genellikle çerçeveye tam olarak uymayabilir.

Grafiği mümkün olan en hızlı şekilde çalıştırmak için, Grafik saatiniayarlama bölümünde açıklandığı gibi grafik saatini kapatın.

Aşağıdaki örnek tek seferlik modu ve arabelleğe alma modunu etkinleştirir, filtre grafiğini çalıştırır ve tamamlanmasını bekler.

    hr = pGrabber->SetOneShot(TRUE);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGrabber->SetBufferSamples(TRUE);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pControl->Run();
    if (FAILED(hr))
    {
        goto done;
    }

    long evCode;
    hr = pEvent->WaitForCompletion(INFINITE, &evCode);

Örneği Alma

Arabelleğe alma modunda, Sample Grabber her örneğin bir kopyasını depolar. ISampleGrabber::GetCurrentBuffer yöntemi arabelleği çağıran tarafından ayrılan bir diziye kopyalar. Gereken dizinin boyutunu belirlemek için, önce dizi adresi için NULL işaretçisiyle GetCurrentBuffer çağırın. Ardından diziyi ayırın ve arabelleği kopyalamak için metodu ikinci kez çağırın. Aşağıdaki örnekte bu adımlar gösterilmektedir.

    // Find the required buffer size.
    long cbBuffer;
    hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

    pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
    if (!pBuffer) 
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
    if (FAILED(hr))
    {
        goto done;
    }

Arabellekteki verilerin tam biçimini bilmeniz gerekir. Bu bilgileri almak için ISampleGrabber::GetConnectedMediaType yöntemini çağırın. Bu yöntem, formatla birlikte AM_MEDIA_TYPE yapısını doldurur.

Sıkıştırılmamış bir video akışı için biçim bilgileri VIDEOINFOHEADER yapısında yer alır. Aşağıdaki örnekte sıkıştırılmamış bir video akışı için biçim bilgilerinin nasıl alınılabileceği gösterilmektedir.

    // Examine the format block.
    if ((mt.formattype == FORMAT_VideoInfo) && 
        (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
        (mt.pbFormat != NULL)) 
    {
        VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;

        hr = WriteBitmap(pszBitmapFile, &pVih->bmiHeader, 
            mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer);
    }
    else 
    {
        // Invalid format.
        hr = VFW_E_INVALIDMEDIATYPE; 
    }

Not

Sample Grabber VIDEOINFOHEADER2desteklemez.

 

Örnek Kod

Önceki örneklerin tam kodu aşağıda verilmiştir.

Not

Bu örnekte, arabirim işaretçilerini serbest bırakmak için SafeRelease işlevi kullanılır.

 

#include <windows.h>
#include <dshow.h>
#include "qedit.h"

template <class T> void SafeRelease(T **ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = NULL;
    }
}



HRESULT WriteBitmap(PCWSTR, BITMAPINFOHEADER*, size_t, BYTE*, size_t);

HRESULT GrabVideoBitmap(PCWSTR pszVideoFile, PCWSTR pszBitmapFile)
{
    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEventEx *pEvent = NULL;
    IBaseFilter *pGrabberF = NULL;
    ISampleGrabber *pGrabber = NULL;
    IBaseFilter *pSourceF = NULL;
    IEnumPins *pEnum = NULL;
    IPin *pPin = NULL;
    IBaseFilter *pNullF = NULL;

    BYTE *pBuffer = NULL;

    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, 
        CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pGraph));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
    if (FAILED(hr))
    {
        goto done;
    }

    // Create the Sample Grabber filter.
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&pGrabberF));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pGrabber));
    if (FAILED(hr))
    {
        goto done;
    }

    AM_MEDIA_TYPE mt;
    ZeroMemory(&mt, sizeof(mt));
    mt.majortype = MEDIATYPE_Video;
    mt.subtype = MEDIASUBTYPE_RGB24;

    hr = pGrabber->SetMediaType(&mt);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->AddSourceFilter(pszVideoFile, L"Source", &pSourceF);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pSourceF->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        goto done;
    }

    while (S_OK == pEnum->Next(1, &pPin, NULL))
    {
        hr = ConnectFilters(pGraph, pPin, pGrabberF);
        SafeRelease(&pPin);
        if (SUCCEEDED(hr))
        {
            break;
        }
    }

    if (FAILED(hr))
    {
        goto done;
    }

    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, 
        IID_PPV_ARGS(&pNullF));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGraph->AddFilter(pNullF, L"Null Filter");
    if (FAILED(hr))
    {
        goto done;
    }

    hr = ConnectFilters(pGraph, pGrabberF, pNullF);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGrabber->SetOneShot(TRUE);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGrabber->SetBufferSamples(TRUE);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pControl->Run();
    if (FAILED(hr))
    {
        goto done;
    }

    long evCode;
    hr = pEvent->WaitForCompletion(INFINITE, &evCode);

    // Find the required buffer size.
    long cbBuffer;
    hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

    pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
    if (!pBuffer) 
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pGrabber->GetConnectedMediaType(&mt);
    if (FAILED(hr))
    {
        goto done;
    }

    // Examine the format block.
    if ((mt.formattype == FORMAT_VideoInfo) && 
        (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
        (mt.pbFormat != NULL)) 
    {
        VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;

        hr = WriteBitmap(pszBitmapFile, &pVih->bmiHeader, 
            mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer);
    }
    else 
    {
        // Invalid format.
        hr = VFW_E_INVALIDMEDIATYPE; 
    }

    FreeMediaType(mt);

done:
    CoTaskMemFree(pBuffer);
    SafeRelease(&pPin);
    SafeRelease(&pEnum);
    SafeRelease(&pNullF);
    SafeRelease(&pSourceF);
    SafeRelease(&pGrabber);
    SafeRelease(&pGrabberF);
    SafeRelease(&pControl);
    SafeRelease(&pEvent);
    SafeRelease(&pGraph);
    return hr;
};

// Writes a bitmap file
//  pszFileName:  Output file name.
//  pBMI:         Bitmap format information (including pallete).
//  cbBMI:        Size of the BITMAPINFOHEADER, including palette, if present.
//  pData:        Pointer to the bitmap bits.
//  cbData        Size of the bitmap, in bytes.

HRESULT WriteBitmap(PCWSTR pszFileName, BITMAPINFOHEADER *pBMI, size_t cbBMI,
    BYTE *pData, size_t cbData)
{
    HANDLE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, 
        CREATE_ALWAYS, 0, NULL);
    if (hFile == NULL)
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    BITMAPFILEHEADER bmf = { };

    bmf.bfType = &#39;MB&#39;;
    bmf.bfSize = cbBMI+ cbData + sizeof(bmf); 
    bmf.bfOffBits = sizeof(bmf) + cbBMI; 

    DWORD cbWritten = 0;
    BOOL result = WriteFile(hFile, &bmf, sizeof(bmf), &cbWritten, NULL);
    if (result)
    {
        result = WriteFile(hFile, pBMI, cbBMI, &cbWritten, NULL);
    }
    if (result)
    {
        result = WriteFile(hFile, pData, cbData, &cbWritten, NULL);
    }

    HRESULT hr = result ? S_OK : HRESULT_FROM_WIN32(GetLastError());

    CloseHandle(hFile);

    return hr;
}

DirectShow Düzenleme Hizmetlerini Kullanarak