ChinaFFmpeg

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7252|回复: 2

windows directshow filter采集音视频数据

[复制链接]
发表于 2014-6-21 23:11:13 | 显示全部楼层 |阅读模式
       看来看去,大家都是用ds graph 来做,需要一整条链。 车门大侠说不需要render就能采集到音视频了,不管三七二十一, 狠狠的抄袭一个demo,居然真的可以了。 fuck she,
       对比一下其他的方式,比如音频的采集,玩过WaveIn 之类的api,那还得搞搞搞一段内存去接收,可能还得用上队列的形式,,,,,
       算了,总之我觉得写一个filter去连接前端的 audio capture device 或者 video capture device 是最简单的方式! 二话不说,上代码:
先声明:老衲在win7,vs2003 亲自跑过, 可以拿到音频、视频数据的。感谢大师兄, 车门大侠,感谢ffmpeg x264 28785698各位群友,
class CDumpInputPin;
class CDumpFilter;
class CaptureData;

#define BYTES_PER_LINE 20
#define FIRST_HALF_LINE TEXT  ("   %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x")
#define SECOND_HALF_LINE TEXT (" %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x")
#define PIN_COUNT 1

typedef int(*CALLBACK_CAPTURE)(byte* data, int len);
// Main filter object

class CDumpFilter : public CBaseFilter
{
public:
    // Constructor
        CDumpFilter(CaptureData *pCap,
                                LPUNKNOWN pUnk,
                CCritSec *pLock,
                HRESULT *phr);
        ~CDumpFilter();
    // Pin enumeration
    CBasePin * GetPin(int n);
    int GetPinCount();
        CaptureData* m_pCap;
};


//  Pin object

class CDumpInputPin : public CRenderedInputPin
{   
public:

    CDumpInputPin(CBaseFilter *pFilter,
                  CCritSec *pLock,
                  HRESULT *phr);

    // Do something with this media sample
    STDMETHODIMP Receive(IMediaSample *pSample);

    // Check if the pin can support this specific proposed type and format
    HRESULT CheckMediaType(const CMediaType * type);
        void SetOnRecieveCallback(CALLBACK_CAPTURE fn) { m_pfn = fn; }
private:
        CALLBACK_CAPTURE m_pfn;
};


class  __declspec(dllexport)  CaptureData
{
public:
        CaptureData(CALLBACK_CAPTURE fn, bool isaudio=true);
        ~CaptureData();
        int Start();
        int Stop();
        CDumpInputPin* m_pin[PIN_COUNT];

private:
        HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum);       
        HRESULT GetDevices(IEnumMoniker* pEnum);
        void SetAudioProperty(IPin *pin);
        void SetVideoProperty(IPin *pin);
        IGraphBuilder *m_pGraph;       
        IBaseFilter* m_pFilter;
        CDumpFilter* m_pDumpFilter;
        IMediaControl *m_pControl;
        bool m_bisaudio;
        CCritSec m_Lock;
        CALLBACK_CAPTURE m_pfn;
};



//以下是cpp文件

#include <windows.h>
#include <commdlg.h>
#include <streams.h>
#include <initguid.h>

#include "dumpuids.h"
#include "dump.h"
#include <stdio.h>
// Setup data

const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
    &MEDIATYPE_NULL,            // Major type
    &MEDIASUBTYPE_NULL          // Minor type
};

const AMOVIESETUP_PIN sudPins =
{
    L"Input",                   // Pin string name
    FALSE,                      // Is it rendered
    FALSE,                      // Is it an output
    FALSE,                      // Allowed none
    FALSE,                      // Likewise many
    &CLSID_NULL,                // Connects to filter
    L"Output",                  // Connects to pin
    1,                          // Number of types
    &sudPinTypes                // Pin information
};

const AMOVIESETUP_FILTER sudDump =
{
    &CLSID_Dump,                // Filter CLSID
    L"Dump",                    // String name
    MERIT_DO_NOT_USE,           // Filter merit
        PIN_COUNT,                  // Number pins
    &sudPins                    // Pin details
};


//
//  Object creation stuff
//
CFactoryTemplate g_Templates[]= {
    L"Dump", &CLSID_Dump, NULL, NULL, &sudDump
};
int g_cTemplates = 1;


// Constructor

CDumpFilter::CDumpFilter(CaptureData *pCap, LPUNKNOWN pUnk,
                         CCritSec *pLock,
                         HRESULT *phr) :
                                                 CBaseFilter(NAME("CDumpFilter"), pUnk, pLock, CLSID_Dump), m_pCap(pCap)
{

}

CDumpFilter::~CDumpFilter()
{
}

//
// GetPin
//
CBasePin * CDumpFilter::GetPin(int n)
{
        if (n < PIN_COUNT)
                return m_pCap->m_pin[n];
        else
                return NULL;
}


//
// GetPinCount
//
int CDumpFilter::GetPinCount()
{
    return PIN_COUNT;
}


//
//  Definition of CDumpInputPin
//
CDumpInputPin::CDumpInputPin(CBaseFilter *pFilter,
                             CCritSec *pLock,
                             HRESULT *phr)
    :CRenderedInputPin(NAME("CDumpInputPin"),
                  pFilter,                   // Filter
                  pLock,                     // Locking
                  phr,                       // Return code
                  L"Input")                 // Pin name
{
}


//
// CheckMediaType
//
// Check if the pin can support this specific proposed type and format
//
HRESULT CDumpInputPin::CheckMediaType(const CMediaType *type)
{
        return S_OK;
}


//
// Receive
//
// Do something with this media sample
//
STDMETHODIMP CDumpInputPin::Receive(IMediaSample *pSample)
{
    CheckPointer(pSample,E_POINTER);
        CheckPointer(m_pfn, E_POINTER);

    PBYTE pbData;

    HRESULT hr = pSample->GetPointer(&pbData);
    if (FAILED(hr)) {
        return hr;
    }

        m_pfn(pbData, pSample->GetActualDataLength());
        return S_OK;
}




CaptureData::CaptureData(CALLBACK_CAPTURE fn, bool isaudio)
{
        CoInitializeEx(NULL, COINIT_MULTITHREADED);
        m_bisaudio = isaudio;
        m_pfn = fn;
}

CaptureData::~CaptureData()
{       
        CoUninitialize();
}

int CaptureData::Start()
{
        int ret = 0;
        IEnumMoniker *pEnum;
        IEnumPins *pins;
        IPin* pin;
        GUID guid = m_bisaudio ? CLSID_AudioInputDeviceCategory : CLSID_VideoInputDeviceCategory;

        HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
                CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph);
        if (FAILED(hr)) {
                ret = 1;
                goto clean;
        }

        hr = EnumerateDevices(guid, &pEnum);
        if (SUCCEEDED(hr)) {       
                GetDevices(pEnum);
                pEnum->Release();
        } else {
                ret = 2;
                goto clean;
        }

        m_pDumpFilter = new CDumpFilter(this,NULL, &m_Lock, &hr);
        for (int i = 0; i < PIN_COUNT; i++) {
                m_pin[i] = new CDumpInputPin(m_pDumpFilter, &m_Lock, &hr);
                m_pin[i]->SetOnRecieveCallback(m_pfn);
        }

        m_pGraph->AddFilter((IBaseFilter*)m_pFilter, m_bisaudio?L"audio_cap": L"video_cap");
        m_pGraph->AddFilter(m_pDumpFilter, L"m_pDumpFilter");
       
        m_pFilter->EnumPins(&pins);
        while (pins->Next(1, &pin, NULL) == S_OK) {
                _PinDirection dir;
                pin->QueryDirection(&dir);
                if (dir == PINDIR_OUTPUT) {
                        break;
                } else {
                        pin->Release();
                }
        }

        if (m_bisaudio) {
                SetAudioProperty(pin);
        } else {
                SetVideoProperty(pin);
        }

        hr = m_pGraph->Connect(pin, m_pin[0]);               
        hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);               
        hr = m_pControl->Run();       
        pin->Release();
        pins->Release();
clean:

        return ret;
}

int CaptureData::Stop()
{       
        if (m_pControl) {
                m_pControl->Stop();
                m_pControl->Release();
                m_pControl = NULL;
        }

        if (m_pFilter) {       
                m_pFilter->Release();       
                m_pFilter = NULL;
        }

        if (m_pGraph) {
                m_pGraph->Release();
                m_pGraph = NULL;
        }

        if (m_pDumpFilter) {       
                m_pDumpFilter = NULL;
        }

        for (int i = 0; i < PIN_COUNT; i++) {
                delete m_pin[i];
                m_pin[i] = NULL;
        }

        return 0;
}

HRESULT CaptureData::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{
        // Create the System Device Enumerator.
        ICreateDevEnum *pDevEnum;
        HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
                CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));

        if (SUCCEEDED(hr))
        {
                // Create an enumerator for the category.
                hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
                if (hr == S_FALSE)
                {
                        hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
                }
                pDevEnum->Release();
        }
        return hr;
}

HRESULT CaptureData::GetDevices(IEnumMoniker* pEnum)
{
        HRESULT hr = 0;
        IMoniker *pMoniker = NULL;
        IBindCtx* ctx = NULL;
       
        CreateBindCtx(0, &ctx);
        while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
                hr = pMoniker->BindToObject(ctx, NULL, IID_IBaseFilter, (void**)&m_pFilter);
                pMoniker->Release();
                if (FAILED(hr)) {                       
                        goto clean;
                }
        //        break;
        }
clean:

        if (ctx)
                ctx->Release();

        return 0;
}

void CaptureData::SetAudioProperty(IPin *pin)
{       
        IAMStreamConfig* pConfig = NULL;
        AM_MEDIA_TYPE *pmt = NULL;
        WAVEFORMATEX *pWF = NULL;
        IAMBufferNegotiation *pNegotiation = NULL;
        int nBitPerSample = 16;
        int nSampleRate = 11025;
        int nChannels = 2;
        HRESULT hr;
        hr = pin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig);
        hr = pin->QueryInterface(IID_IAMBufferNegotiation, (void **)&pNegotiation);
        hr = pConfig->GetFormat(&pmt);
        if (SUCCEEDED(hr))
        {
                pWF = (WAVEFORMATEX *)pmt->pbFormat;
                pWF->wFormatTag = WAVE_FORMAT_PCM;
                pWF->nChannels = (WORD)nChannels;
                pWF->wBitsPerSample = (WORD)(nBitPerSample);
                pWF->nBlockAlign = (WORD)nChannels * (pWF->wBitsPerSample / 8);
                pWF->nSamplesPerSec = nSampleRate;
                pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec;//nSampleRate * pWF->wBitsPerSample / 8;
                // Set the new formattype for the output pin  
                hr = pConfig->SetFormat(pmt);
                DeleteMediaType(pmt);
        }
       
        ALLOCATOR_PROPERTIES prop = { 0 };
        prop.cBuffers = 6;
        prop.cbBuffer = 8192; // pWF->nAvgBytesPerSec;
        prop.cbAlign = (nBitPerSample/8) * nChannels;
        hr = pNegotiation->SuggestAllocatorProperties(&prop);
       
        pNegotiation->Release();
        pConfig->Release();
}

void CaptureData::SetVideoProperty(IPin *pin)
{
        IAMStreamConfig* pConfig = NULL;
        AM_MEDIA_TYPE *pmt = NULL;
        VIDEO_STREAM_CONFIG_CAPS scc;       
        int count = 0;
        int size = 0;

        HRESULT hr;
        hr = pin->QueryInterface(IID_IAMStreamConfig, (void**)&pConfig);
        /*
        hr = pConfig->GetNumberOfCapabilities(&count, &size);
        for (int i = 0; i < count; i++) {
                hr = pConfig->GetStreamCaps(i, &pmt, (BYTE*)&scc);
                if (SUCCEEDED(hr)) {
                        DeleteMediaType(pmt);
                }
        }
        */
        hr = pConfig->GetFormat(&pmt);
        if (SUCCEEDED(hr)) {
                VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)pmt->pbFormat;
                //pmt->subtype = MEDIASUBTYPE_YUY2;               
                pvi->bmiHeader.biWidth = 640;
                pvi->bmiHeader.biHeight = 480;
                pvi->bmiHeader.biSizeImage = 3 * pvi->bmiHeader.biWidth * pvi->bmiHeader.biHeight;               
                pvi->AvgTimePerFrame = 25;               
                hr = pConfig->SetFormat(pmt);
                DeleteMediaType(pmt);
        }

        pConfig->Release();
}
////////////////////////////////////////////////////////////////////////
//
// Exported entry points for registration and unregistration
// (in this case they only call through to default implementations).
//
////////////////////////////////////////////////////////////////////////

//
// DllRegisterSever
//
// Handle the registration of this filter
//
STDAPI DllRegisterServer()
{
    return AMovieDllRegisterServer2( TRUE );

} // DllRegisterServer


//
// DllUnregisterServer
//
STDAPI DllUnregisterServer()
{
    return AMovieDllRegisterServer2( FALSE );

} // DllUnregisterServer


//
// DllEntryPoint
//
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD  dwReason,
                      LPVOID lpReserved)
{
        return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}


回复

使用道具 举报

 楼主| 发表于 2014-6-21 23:15:03 | 显示全部楼层
怎么使用? 艹 , 就看CaptureData类吧,它是支持音频、视频采集的。
公开了3个函数,
1, 构造函数,你传一个回调给它, 通过这个回调,你就会得到数据。isaudio = true表示采集音频,false表示采集视频。
2, Start() 启动它,
3, Stop()停止它,
其他的你就不用理了,是不是很爽? 她嘛的,应该是很爽。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-6-21 23:17:06 | 显示全部楼层
以下是一个测试程序, 有bug不要找我,你修好发一份给我就行了,O(∩_∩)O哈哈~

#include "stdafx.h"
#include <tchar.h>
#define PTCHAR (TCHAR *)
#include <streams.h>

#include "../DS_Dump/dump.h"
#pragma comment(lib, "../DS_Dump/debug/dump.lib")

int callback_capture_a(byte* data, int len);
int callback_capture_v(byte* data, int len);
FILE *fpa, *fpv;

int _tmain(int argc, _TCHAR* argv[])
{
        fpa = fopen("./audio.pcm", "wb");
        fpv = fopen("./video.yuv", "wb");
        CaptureData capa(callback_capture_a, TRUE);
        CaptureData capv(callback_capture_v, FALSE);
        capa.Start();
        capv.Start();

        while (getchar() != 'q') {

        }

        capa.Stop();
        capv.Stop();
        fclose(fpa);
        fclose(fpv);
        return 0;
}

int callback_capture_a(byte* data, int len)
{
        fwrite(data, 1, len, fpa);
        printf("callback_capture_a recieve %d bytes.\n", len);
        return len;
}

int callback_capture_v(byte *data, int len)
{
        fwrite(data, 1, len, fpv);
        printf("callback_capture_v recieve %d bytes.\n", len);
        return len;
}
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|Archiver|ChinaFFmpeg

GMT+8, 2024-12-27 16:03 , Processed in 0.048074 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表