winvideods.c

来自「mediastreamer2是开源的网络传输媒体流的库」· C语言 代码 · 共 1,534 行 · 第 1/3 页

C
1,534
字号
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#define UNICODE
#define AYMERIC_TEST
#define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA

#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/msticker.h"
#include "mediastreamer2/msv4l.h"
#include "mediastreamer2/mswebcam.h"

#include "nowebcam.h"
#include <ffmpeg/avcodec.h>

#include <dshow.h>
#include <dmodshow.h>
#include <dmoreg.h>

#include <streams.h>
#include <initguid.h>
#include "dxfilter.h"
EXTERN_C const CLSID CLSID_NullRenderer;

HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister);
void RemoveGraphFromRot(DWORD pdwRegister);

typedef struct V4wState{

	char dev[512];
	int devidx;

	IGraphBuilder *m_pGraph;
	ICaptureGraphBuilder2 *m_pBuilder;
	IMediaControl *m_pControl;
	CDXFilter *m_pDXFilter;
	IBaseFilter *m_pIDXFilter;	
	IBaseFilter *m_pNullRenderer;
	IBaseFilter *m_pDeviceFilter;
	DWORD rotregvalue;

	MSVideoSize vsize;
	int pix_fmt;
	mblk_t *mire[10];
	char nowebcamimage[256];
	queue_t rq;
	ms_mutex_t mutex;
	int frame_ind;
	int frame_max;
	float fps;
	float start_time;
	int frame_count;
}V4wState;

static V4wState *s_callback=NULL;

static void dummy(void*p){
}

HRESULT ( Callback)(IMediaSample* pSample, REFERENCE_TIME* sTime, REFERENCE_TIME* eTime, BOOL changed)
{
	BYTE *byte_buf=NULL;
	mblk_t *buf;

	V4wState *s = s_callback;
	if (s==NULL)
		return S_OK;

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

	int size = pSample->GetActualDataLength();
	if (size>+1000)
	{
		buf=allocb(size,0);
		memcpy(buf->b_wptr, byte_buf, size);
		if (s->pix_fmt==MS_RGB24)
		{
			/* Conversion from top down bottom up (BGR to RGB and flip) */
 			unsigned long Index,nPixels;
			unsigned char *blue;
			unsigned char tmp;
			short iPixelSize;

			blue=buf->b_wptr;

			nPixels=s->vsize.width*s->vsize.height;
			iPixelSize=24/8;
		 
			for(Index=0;Index!=nPixels;Index++)  // For each pixel
			{
				tmp=*blue;
				*blue=*(blue+2);
				*(blue+2)=tmp;
				blue+=iPixelSize;
			}
 
			unsigned char *pLine1, *pLine2;
			int iLineLen,iIndex;

			iLineLen=s->vsize.width*iPixelSize;
			pLine1=buf->b_wptr;
			pLine2=&(buf->b_wptr)[iLineLen * (s->vsize.height - 1)];

			for( ;pLine1<pLine2;pLine2-=(iLineLen*2))
			{
				for(iIndex=0;iIndex!=iLineLen;pLine1++,pLine2++,iIndex++)
				{
					tmp=*pLine1;
					*pLine1=*pLine2;
					*pLine2=tmp;       
				}
			}
		}
		buf->b_wptr+=size;  
		
		ms_mutex_lock(&s->mutex);
		putq(&s->rq, buf);
		ms_mutex_unlock(&s->mutex);

	}
	return S_OK;
}

HRESULT GetPinCategory(IPin *pPin, GUID *pPinCategory)
{
    HRESULT hr;
    IKsPropertySet *pKs;
    hr = pPin->QueryInterface(IID_IKsPropertySet, (void **)&pKs);
    if (FAILED(hr))
    {
        // The pin does not support IKsPropertySet.
        return hr;
    }
    // Try to retrieve the pin category.
    DWORD cbReturned;
    hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, 
        pPinCategory, sizeof(GUID), &cbReturned);

    // If this succeeded, pPinCategory now contains the category GUID.

    pKs->Release();
    return hr;
}

int try_format(V4wState *s, int format, GUID *pPinCategory)
{
    HRESULT hr=S_OK;
    IEnumPins *pEnum=0;
    ULONG ulFound;
    IPin *pPin;

	GUID guid_format;
	DWORD biCompression;
	DWORD biBitCount;

	// Verify input
    if (!s->m_pDeviceFilter)
        return -1;

	if (format == MS_YUV420P)
		guid_format = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0'));
	else if (format == MS_YUYV)
		guid_format = MEDIASUBTYPE_YUYV;
	else if (format == MS_UYVY)
		guid_format = MEDIASUBTYPE_UYVY;
	else if (format == MS_RGB24)
		guid_format = MEDIASUBTYPE_RGB24;
	else if (format == MS_YUY2)
		guid_format = MEDIASUBTYPE_YUY2;

	if (format == MS_YUV420P)
		biCompression = MAKEFOURCC('I','4','2','0');
	else if (format == MS_YUYV)
		biCompression = MAKEFOURCC('Y','U','Y','V');
	else if (format == MS_UYVY)
		biCompression = MAKEFOURCC('U','Y','V','Y');
	else if (format == MS_RGB24)
		biCompression = BI_RGB;
	else if (format == MS_YUY2)
		biCompression = MAKEFOURCC('Y','U','Y','2');
	
	if (format == MS_YUV420P)
		biBitCount = 12;
	else if (format == MS_YUYV)
		biBitCount = 16;
	else if (format == MS_UYVY)
		biBitCount = 16;
	else if (format == MS_RGB24)
		biBitCount = 24;
	else if (format == MS_YUY2)
		biBitCount = 16;
	
    // Get pin enumerator
	hr = s->m_pDeviceFilter->EnumPins(&pEnum);
    if(FAILED(hr)) 
        return -1;

    pEnum->Reset();

    // Count every pin on the filter
    while(S_OK == pEnum->Next(1, &pPin, &ulFound))
    {
        PIN_DIRECTION pindir = (PIN_DIRECTION) 3;

        hr = pPin->QueryDirection(&pindir);

        if(pindir != PINDIR_INPUT)
		{
			IEnumMediaTypes *ppEnum;
	    ULONG ulFound2;

      GetPinCategory(pPin, pPinCategory);
      if (*pPinCategory!=PIN_CATEGORY_CAPTURE
        && *pPinCategory!=PIN_CATEGORY_PREVIEW)
        continue;

      hr = pPin->EnumMediaTypes(&ppEnum);
			if(FAILED(hr)) 
				continue;

			AM_MEDIA_TYPE *ppMediaTypes;
			while(S_OK == ppEnum->Next(1, &ppMediaTypes, &ulFound2))
			{
				if (ppMediaTypes->formattype != FORMAT_VideoInfo)
					continue;
				if (ppMediaTypes->majortype != MEDIATYPE_Video)
					continue;
				if (ppMediaTypes->subtype != guid_format)
					continue;
				VIDEOINFO *pvi = (VIDEOINFO *)ppMediaTypes->pbFormat;
				if (pvi->bmiHeader.biCompression!=biCompression)
					continue;
				if (pvi->bmiHeader.biBitCount!=biBitCount)
					continue;

        pPin->Release();
			  pEnum->Release();
				return 0;
			}
		}

        pPin->Release();
    }

    pEnum->Release();
    return -1;
}

int try_format_size(V4wState *s, int format, int width, int height, GUID *pPinCategory)
{
    HRESULT hr=S_OK;
    IEnumPins *pEnum=0;
    ULONG ulFound;
    IPin *pPin;

	GUID guid_format;
	DWORD biCompression;
	DWORD biBitCount;

	// Verify input
    if (!s->m_pDeviceFilter)
        return -1;

	if (format == MS_YUV420P)
		guid_format = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0'));
	else if (format == MS_YUYV)
		guid_format = MEDIASUBTYPE_YUYV;
	else if (format == MS_UYVY)
		guid_format = MEDIASUBTYPE_UYVY;
	else if (format == MS_RGB24)
		guid_format = MEDIASUBTYPE_RGB24;
	else if (format == MS_YUY2)
		guid_format = MEDIASUBTYPE_YUY2;

	if (format == MS_YUV420P)
		biCompression = MAKEFOURCC('I','4','2','0');
	else if (format == MS_YUYV)
		biCompression = MAKEFOURCC('Y','U','Y','V');
	else if (format == MS_UYVY)
		biCompression = MAKEFOURCC('U','Y','V','Y');
	else if (format == MS_RGB24)
		biCompression = BI_RGB;
	else if (format == MS_YUY2)
		biCompression = MAKEFOURCC('Y','U','Y','2');
	
	if (format == MS_YUV420P)
		biBitCount = 12;
	else if (format == MS_YUYV)
		biBitCount = 16;
	else if (format == MS_UYVY)
		biBitCount = 16;
	else if (format == MS_RGB24)
		biBitCount = 24;
	else if (format == MS_YUY2)
		biBitCount = 16;

    // Get pin enumerator
	hr = s->m_pDeviceFilter->EnumPins(&pEnum);
    if(FAILED(hr)) 
        return -1;

    pEnum->Reset();

    // Count every pin on the filter
    while(S_OK == pEnum->Next(1, &pPin, &ulFound))
    {
        PIN_DIRECTION pindir = (PIN_DIRECTION) 3;

        hr = pPin->QueryDirection(&pindir);

        if(pindir != PINDIR_INPUT)
		{
			IEnumMediaTypes *ppEnum;
		    ULONG ulFound2;
			hr = pPin->EnumMediaTypes(&ppEnum);
			if(FAILED(hr)) 
				continue;

      GUID pCurrentPinCategory;
      GetPinCategory(pPin, &pCurrentPinCategory);
      if (*pPinCategory!=pCurrentPinCategory)
        continue;

			AM_MEDIA_TYPE *ppMediaTypes;
			while(S_OK == ppEnum->Next(1, &ppMediaTypes, &ulFound2))
			{
				if (ppMediaTypes->formattype != FORMAT_VideoInfo)
					continue;
				if (ppMediaTypes->majortype != MEDIATYPE_Video)
					continue;
				if (ppMediaTypes->subtype != guid_format)
					continue;
				VIDEOINFO *pvi = (VIDEOINFO *)ppMediaTypes->pbFormat;
				if (pvi->bmiHeader.biCompression!=biCompression)
					continue;
				if (pvi->bmiHeader.biBitCount!=biBitCount)
					continue;
				if (pvi->bmiHeader.biHeight!=height)
					continue;
				if (pvi->bmiHeader.biWidth!=width)
					continue;

				s->vsize.width = width;
				s->vsize.height = height;

				pPin->Release();
			    pEnum->Release();
				return 0;
			}
		}

        pPin->Release();
    } 

    pEnum->Release();
    return -1;
}

static int v4w_configure_videodevice(V4wState *s)
{
	// Initialize COM
	CoInitialize(NULL);

	// get a Graph
	HRESULT hr= CoCreateInstance (CLSID_FilterGraph,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IGraphBuilder, //IID_IBaseFilter,
                          (void **)&s->m_pGraph);
	if(FAILED(hr))
	{
		return -1;
	}

	// get a CaptureGraphBuilder2
	hr= CoCreateInstance (CLSID_CaptureGraphBuilder2,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_ICaptureGraphBuilder2, //IID_IBaseFilter,
                          (void **)&s->m_pBuilder);
	if(FAILED(hr))
	{
		return -2;
	}

	// connect capture graph builder with the graph
	s->m_pBuilder->SetFiltergraph(s->m_pGraph);

	// get mediacontrol so we can start and stop the filter graph
	hr=s->m_pGraph->QueryInterface (IID_IMediaControl, (void **)&s->m_pControl);
	if(FAILED(hr))
	{
		return -3;
	}


#ifdef _DEBUG
	HANDLE m_hLogFile=CreateFile(L"DShowGraphLog.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	if(m_hLogFile!=INVALID_HANDLE_VALUE)
	{
		hr=s->m_pGraph->SetLogFile((DWORD_PTR)m_hLogFile);
		/* ASSERT(SUCCEEDED(hr)); */
	}
	
	//AddGraphToRot(s->m_pGraph, &s->rotregvalue);
#endif

	ICreateDevEnum *pCreateDevEnum = NULL;
	IEnumMoniker *pEnumMoniker = NULL;
	IMoniker *pMoniker = NULL;

	ULONG nFetched = 0;

	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, 
		IID_ICreateDevEnum, (PVOID *)&pCreateDevEnum);
	if(FAILED(hr))
	{
		return -4;
	}

	hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
		&pEnumMoniker, 0);
	if (FAILED(hr) || pEnumMoniker == NULL) {
		//printf("no device\n");
		return -5;
	}

	pEnumMoniker->Reset();

	int pos=0;
  while(S_OK == pEnumMoniker->Next(1, &pMoniker, &nFetched) )
  {
    IPropertyBag *pBag;    hr = pMoniker->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag );    if( hr != S_OK )       continue;     if (s->dev[0]=='\0')      break;    VARIANT var;    VariantInit(&var);    hr = pBag->Read( L"FriendlyName", &var, NULL );     if( hr != S_OK )    {      pMoniker->Release();      continue;    }    //USES_CONVERSION;    char szName[256];    WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1,szName,256,0,0);    VariantClear(&var);     if (strcmp(szName, s->dev)==0)      break;    pMoniker->Release();    pBag->Release();    pMoniker=NULL;    pBag=NULL;	}

	if(pMoniker==NULL)
  {
	  int pos=0;
    while(S_OK == pEnumMoniker->Next(1, &pMoniker, &nFetched) )
    {
      IPropertyBag *pBag;      hr = pMoniker->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag );      if( hr != S_OK )         continue;     }	}

	if(pMoniker==NULL)
	{
		return -6;
	}

	hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&s->m_pDeviceFilter );
	if(FAILED(hr))
	{
		return -7;
	}

	s->m_pGraph->AddFilter(s->m_pDeviceFilter, L"Device Filter");

	pMoniker->Release();
	pEnumMoniker->Release();
	pCreateDevEnum->Release();

⌨️ 快捷键说明

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