⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vidinput_directx.cxx

📁 opal的ptlib c++源程序 可以从官方网站上下载
💻 CXX
📖 第 1 页 / 共 3 页
字号:
/*
 * vidinput_directx.cxx
 *
 * Classes to support streaming video input (grabbing) and output.
 *
 * Portable Windows Library
 *
 * Copyright (c) 2007 Luc Saillard <luc@saillard.org>
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Portable Windows Library.
 *
 * The Initial Developer of the Original Code is Luc Saillard <luc@saillard.org>
 *
 * Contributor(s): Matthias Schneider <ma30002000@yahoo.de>
 */

#include <ptlib.h>

#ifdef P_DIRECTSHOW

#include "ptlib/msos/ptlib/vidinput_directx.h"

#ifdef P_DIRECTSHOW_LIBRARY1
#pragma comment(lib, P_DIRECTSHOW_LIBRARY1)
#endif
#ifdef P_DIRECTSHOW_LIBRARY2
#pragma comment(lib, P_DIRECTSHOW_LIBRARY2)
#endif

#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }

static HRESULT SetDevice(const PString & devName, IBaseFilter ** ppSrcFilter);
#ifndef _WIN32_WCE
static char *BSTR_to_ANSI(BSTR pSrc);
#endif
static GUID pwlib_format_to_media_format(const char *format);
static PString media_format_to_pwlib_format(const GUID guid);

#if defined(_WIN32_WCE) && !defined(HAVE_CE_SAMPLEGRABBER)
const IID IID_ISampleGrabber =		{ 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F };
const CLSID CLSID_SampleGrabber =	{ 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 };
const CLSID CLSID_NullRenderer =	{ 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 };
#endif // _WIN32_WCE

PCREATE_VIDINPUT_PLUGIN(DirectShow);


#if PTRACING
static const char *ErrorMessage(HRESULT hr)
{
#ifndef _WIN32_WCE
	static char string[1024];
    DWORD dwMsgLen;

    memset(string, 0, sizeof(string));
    dwMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
			      FORMAT_MESSAGE_IGNORE_INSERTS,
			      NULL,
			      hr,
			      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			      (LPSTR)string,
			      sizeof(string)-1,
			      NULL);
    if (dwMsgLen)
	return string;

    memset(string, 0, sizeof(string));
    dwMsgLen = AMGetErrorTextA(hr, string, sizeof(string));
    if (dwMsgLen)
	return string;
#ifdef __MINGW32__  // This function is not recognised in Windows
    snprintf(string, sizeof(string), "0x%8.8x", hr);
	return string;
#else
	return PString();
#endif
#else // _WIN32_WCE
	return PString("Error during video capture");
#endif // !_WIN32_WCE 
}
#endif // PTRACING


static void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
{
    if (pmt == NULL)
	return;

    if (pmt->cbFormat != 0)
    {
	CoTaskMemFree((PVOID)pmt->pbFormat);
        pmt->cbFormat = 0;
        pmt->pbFormat = NULL;
    }
    if (pmt->pUnk != NULL)
    {
        // Uncessessary because pUnk should not be used, but safest.
        pmt->pUnk->Release();
        pmt->pUnk = NULL;
    }

    CoTaskMemFree(pmt);
}

PVideoInputDevice_DirectShow::PVideoInputDevice_DirectShow()
{
  PTRACE(1,"PVidDirectShow\tPVideoInputDevice_DirectShow: constructor" );

#ifndef _WIN32_WCE
  CoInitialize(NULL);
#else
  CoInitializeEx(NULL,COINIT_MULTITHREADED);
#endif

  tempFrame = NULL;

  pSrcFilter = NULL;
  pGrabberFilter = NULL;
  pNullFilter = NULL;
  pGraph = NULL;
  pMC = NULL;
  pME = NULL;
  pCapture = NULL;
  pGrabber = NULL;

  isCapturingNow = PFalse;
  capturing_duration = 10000; // arbitrary large value suffices
}

PVideoInputDevice_DirectShow::~PVideoInputDevice_DirectShow()
{
  if (tempFrame != NULL)
    free(tempFrame);

  Close();
  ::CoUninitialize();
}

HRESULT PVideoInputDevice_DirectShow::Initialize_Interfaces()
{
    HRESULT hr;

    PTRACE(1,"PVidDirectShow\tInitialize_Interfaces()");

    // Create the filter graph
    hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                           IID_IGraphBuilder, (void **) &pGraph);
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to create instance FilterGraph: " << ErrorMessage(hr));
        return hr;
    }

    // Create the capture graph builder
#ifndef _WIN32_WCE
	hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC_SERVER,
                           IID_ICaptureGraphBuilder2, (void **) &pCapture);
#else
	hr = CoCreateInstance (CLSID_CaptureGraphBuilder , NULL, CLSCTX_INPROC_SERVER,
                           IID_ICaptureGraphBuilder2, (void **) &pCapture);
#endif
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to create instance CaptureGraphBuilder2: " << ErrorMessage(hr));
        return hr;
    }

    // Create the Sample Grabber Filter.
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
			  IID_IBaseFilter, (void**) &pGrabberFilter);
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to create instance SampleGrabber: " << ErrorMessage(hr));
        return hr;
    }

    // Create the Null Renderer Filter.
    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
			  IID_IBaseFilter, (void**) &pNullFilter);
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to create instance SampleGrabber: " << ErrorMessage(hr));
        return hr;
    }

    // Obtain interfaces for media control and Video Window
    hr = pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &pMC);
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to query interface MediaControl: " << ErrorMessage(hr));
        return hr;
    }

    hr = pGraph->QueryInterface(IID_IMediaEvent, (LPVOID *) &pME);
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to query interface MediaEvent: " << ErrorMessage(hr));
        return hr;
    }

    // Attach the filter graph to the capture graph
    hr = pCapture->SetFiltergraph(pGraph);
    if (FAILED(hr))
    {
        PTRACE(1,"PVidDirectShow\tFailed to set capture filter graph: " << ErrorMessage(hr));
        return hr;
    }

    //Add the filter to the graph
    hr = pGraph->AddFilter(pGrabberFilter, L"Sample Grabber");
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't add the grabber filter to the graph: " << ErrorMessage(hr));
	return hr;
    }

    // Obtain interfaces for Sample Grabber
    pGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
    hr = pGrabber->SetBufferSamples(PTrue);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tFailed to SetBufferSamples: " << ErrorMessage(hr));
	return hr;
    }

    hr = pGrabber->SetOneShot(PFalse);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tFailed to SetOneShot: " << ErrorMessage(hr));
	return hr;
    }

    //Set the Sample Grabber callback
    //0: SampleCB (the buffer is the original buffer, not a copy)
    //1: BufferCB (the buffer is a copy of the original buffer)
#if 0
    hr = pGrabber->SetCallback(this, 0);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tFailed to SetCallback: " << ErrorMessage(hr));
	return hr;
    }
#endif

    return hr;
}

PBoolean PVideoInputDevice_DirectShow::InitialiseCapture()
{
    HRESULT hr;

    PTRACE(1,"PVidDirectShow\tInitializeCapture()");

    hr = Initialize_Interfaces();
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tFailed to initialize interfaces: " << ErrorMessage(hr));
	return PFalse;
    }
    hr = SetDevice(deviceName, &pSrcFilter);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tFailed to select a device: " << ErrorMessage(hr));
	return PFalse;
    }

    // Add Capture filter to our graph.
    hr = pGraph->AddFilter(pSrcFilter, L"Video Capture");
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't add the capture filter to the graph: " << ErrorMessage(hr));
        return PFalse;
    }

    // Add the filter to our graph
    hr = pGraph->AddFilter(pNullFilter, L"Null Renderer");
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't add the grabber filter to the graph: " << ErrorMessage(hr));
	return hr;
    }

    return PTrue;
}


PStringArray PVideoInputDevice_DirectShow::GetInputDeviceNames()
{
    PStringArray devices;

    PTRACE(1,"PVidDirectShow\tGetInputDeviceNames()");

#ifndef _WIN32_WCE
    HRESULT hr;
    IMoniker *pMoniker =NULL;
    IEnumMoniker *pClassEnum = NULL;
    ULONG cFetched;

    ICreateDevEnum *pDevEnum =NULL;
	::CoInitialize(NULL);

    // Create the system device enumerator
    hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
                           IID_ICreateDevEnum, (void **) &pDevEnum);

	if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't create system enumerator. " << ErrorMessage(hr));
	::CoUninitialize();
        return devices;
    }


    // Create an enumerator for the video capture devices
    hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tGetInputDeviceNames() Couldn't create class enumerator. " << ErrorMessage(hr));
	::CoUninitialize();
        return devices;
    }

    if (pClassEnum == NULL)
    {
        PTRACE(1, "PVidDirectShow\tGetInputDeviceNames() No video capture device was detected.");
	::CoUninitialize();
        return devices;
    }

    while (hr = pClassEnum->Next(1, &pMoniker, &cFetched), hr==S_OK)
    {
	// Get the property bag
	IPropertyBag *pPropBag;

	hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
	if (FAILED(hr))
	{
	    pMoniker->Release();
	    continue;
	}

	// Find the description or friendly name.
	VARIANT DeviceName;
	DeviceName.vt = VT_BSTR;
	hr = pPropBag->Read(L"Description", &DeviceName, NULL);
	if (FAILED(hr))
	    hr = pPropBag->Read(L"FriendlyName", &DeviceName, NULL);
	if (SUCCEEDED(hr))
	{
	    char *pDeviceName = BSTR_to_ANSI(DeviceName.bstrVal);
	    if (pDeviceName)
	    {
		PTRACE(4, "PVidDirectShow\tGetInputDeviceNames() Found this capture device '"<< pDeviceName <<"'");
		devices.AppendString(pDeviceName);
		free(pDeviceName);
	    }
	}

	pPropBag->Release();
	pMoniker->Release();
	// Next Device
    }

    ::CoUninitialize();

#else // !_WIN32_WCE
	HANDLE	handle = NULL;
	char szDeviceName[8];

	DEVMGR_DEVICE_INFORMATION di;
	GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A, 0x93, 0x3E, 0x4D, 0x7E, 0x3C, 0x86 };
	// Note about the above: The driver material doesn't ship as part of the SDK. This GUID is hardcoded
	// here to be able to enumerate the camera drivers and pass the name of the driver to the video capture filter

	di.dwSize = sizeof(di);
	ZeroMemory( szDeviceName, 8 );

	handle = FindFirstDevice( DeviceSearchByGuid, &guidCamera, &di );
	if(( handle == NULL ) || ( di.hDevice == NULL ))
	{
		PTRACE(4, "PVidDirectShow\tGetInputDeviceNames() returns error: '"<< ::GetLastError() <<"'");
	}
	else
		wcstombs( szDeviceName, di.szLegacyName, 8 );

	FindClose( handle );

	PTRACE(4, "PVidDirectShow\tGetInputDeviceNames() Found this capture device '"<< szDeviceName <<"'");
	devices.AppendString(szDeviceName);
#endif

    return devices;
}

PBoolean PVideoInputDevice_DirectShow::Open(const PString & devName, PBoolean startImmediate)
{
    PTRACE(1,"PVidDirectShow\tOpen("<<devName<<"," << startImmediate<<")");

    /* FIXME: If the device is already open, close it */
    if (IsOpen())
	     return TRUE;

    deviceName = devName;

    if (!InitialiseCapture())
	return PFalse;

    ListSupportedFormats();
    GetDefaultFormat();

    if (startImmediate)
	return Start();

    return PTrue;
}

PBoolean PVideoInputDevice_DirectShow::IsOpen()
{
    PTRACE(1,"PVidDirectShow\tIsOpen()");

    return pCapture != NULL;
}

PBoolean PVideoInputDevice_DirectShow::Close()
{
    HRESULT hr;

    if (!IsOpen() || (NULL == pGrabber))
		return PFalse;

    hr = pGrabber->SetCallback(NULL, 0);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tFailed to remove the callback: " << ErrorMessage(hr));
	return hr;
    }

    if (pMC)
	pMC->StopWhenReady();

    SAFE_RELEASE(pMC);
    SAFE_RELEASE(pME);
    SAFE_RELEASE(pNullFilter)
    SAFE_RELEASE(pGrabberFilter)
    SAFE_RELEASE(pSrcFilter)
    SAFE_RELEASE(pGraph);
    SAFE_RELEASE(pCapture);
    SAFE_RELEASE(pGrabber);


    return PTrue;
}

PBoolean PVideoInputDevice_DirectShow::Start()
{
    HRESULT hr;
    long evCode;
    unsigned int count;

    PTRACE(1,"PVidDirectShow\tStart()");

    if (IsCapturing())
	return PTrue;

    // http://msdn2.microsoft.com/en-us/library/ms784859.aspx
    hr = pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
                                pSrcFilter,	/* Source Filter */
				NULL,		/* Intermediate Filter */
				pGrabberFilter	/* Sink Filter */
				);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't render the video capture stream: " << ErrorMessage(hr));
        return hr;
    }

    // Start previewing video data
    hr = pMC->Run();
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't run the graph: " << ErrorMessage(hr));
        return PFalse;
    }

    hr = pME->WaitForCompletion(INFINITE, &evCode);
    if (FAILED(hr))
    {
        PTRACE(1, "PVidDirectShow\tCouldn't wait for completion: " << ErrorMessage(hr));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -