📄 winvideods.c
字号:
/*
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"
#include <qedit.h>
//#include <atlbase.h>
//#include <atlcom.h>
HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister);
void RemoveGraphFromRot(DWORD pdwRegister);
typedef struct V4wState{
char dev[512];
int devidx;
//CComPtr<IGraphBuilder> m_pGraph;
//CComPtr<ICaptureGraphBuilder2> m_pBuilder;
//CComPtr<IMediaControl> m_pControl;
IGraphBuilder *m_pGraph;
ICaptureGraphBuilder2 *m_pBuilder;
IMediaControl *m_pControl;
CDXFilter *m_pDXFilter;
//CComPtr<IBaseFilter> m_pIDXFilter;
//CComPtr<IBaseFilter> m_pNullRenderer;
//CComPtr<IBaseFilter> m_pDeviceFilter;
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;
bool_t running;
}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_open_videodevice(V4wState *s)
{
// Initialize COM
CoInitialize(NULL);
// get a Graph
//HRESULT hr=s->m_pGraph.CoCreateInstance(CLSID_FilterGraph);
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=s->m_pBuilder.CoCreateInstance(CLSID_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(&(s->m_pControl));
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) )
{
if (pos>=s->devidx)
break;
pos++;
pMoniker->Release();
pMoniker=NULL;
}
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();
GUID pPinCategory;
if (try_format(s, s->pix_fmt, &pPinCategory)==0)
s->pix_fmt = s->pix_fmt;
else if (try_format(s,MS_YUV420P, &pPinCategory)==0)
s->pix_fmt = MS_YUV420P;
else if (try_format(s,MS_YUY2, &pPinCategory)==0)
s->pix_fmt = MS_YUY2;
else if (try_format(s,MS_YUYV, &pPinCategory)==0)
s->pix_fmt = MS_YUYV;
else if (try_format(s,MS_UYVY, &pPinCategory)==0)
s->pix_fmt = MS_UYVY;
else if (try_format(s,MS_RGB24, &pPinCategory)==0)
s->pix_fmt = MS_RGB24;
else
{
ms_error("Unsupported video pixel format.");
return -8;
}
if (s->pix_fmt == MS_YUV420P)
ms_message("Driver supports YUV420P, using that format.");
else if (s->pix_fmt == MS_YUY2)
ms_message("Driver supports YUY2 (UYVY), using that format.");
else if (s->pix_fmt == MS_YUYV)
ms_message("Driver supports YUV422, using that format.");
else if (s->pix_fmt == MS_UYVY)
ms_message("Driver supports UYVY, using that format.");
else if (s->pix_fmt == MS_RGB24)
ms_message("Driver supports RGB24, using that format.");
if (try_format_size(s, s->pix_fmt, s->vsize.width, s->vsize.height, &pPinCategory)==0)
ms_message("Selected Size: %ix%i.", s->vsize.width, s->vsize.height);
else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H, &pPinCategory)==0)
ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H);
else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H, &pPinCategory)==0)
ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H);
else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H, &pPinCategory)==0)
ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H);
else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H, &pPinCategory)==0)
ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H);
else if (try_format_size(s, s->pix_fmt, MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H, &pPinCategory)==0)
ms_message("Selected Size: %ix%i.", MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H);
else
{
ms_error("No supported size found for format.");
/* size not supported? */
return -9;
}
// get DXFilter
s->m_pDXFilter = new CDXFilter(NULL, &hr, FALSE);
if(s->m_pDXFilter==NULL)
{
return -10;
}
s->m_pDXFilter->AddRef();
CMediaType mt;
mt.SetType(&MEDIATYPE_Video);
GUID m = MEDIASUBTYPE_RGB24;
if (s->pix_fmt == MS_YUV420P)
m = (GUID)FOURCCMap(MAKEFOURCC('I','4','2','0'));
else if (s->pix_fmt == MS_YUY2)
m = MEDIASUBTYPE_YUY2;
else if (s->pix_fmt == MS_YUYV)
m = MEDIASUBTYPE_YUYV;
else if (s->pix_fmt == MS_UYVY)
m = MEDIASUBTYPE_UYVY;
else if (s->pix_fmt == MS_RGB24)
m = MEDIASUBTYPE_RGB24;
mt.SetSubtype(&m);
mt.formattype = FORMAT_VideoInfo;
mt.SetTemporalCompression(FALSE);
VIDEOINFO *pvi = (VIDEOINFO *)
mt.AllocFormatBuffer(sizeof(VIDEOINFO));
if (NULL == pvi)
return -11;
ZeroMemory(pvi, sizeof(VIDEOINFO));
if (s->pix_fmt == MS_YUV420P)
pvi->bmiHeader.biCompression = MAKEFOURCC('I','4','2','0');
else if (s->pix_fmt == MS_YUY2)
pvi->bmiHeader.biCompression = MAKEFOURCC('Y','U','Y','2');
else if (s->pix_fmt == MS_YUYV)
pvi->bmiHeader.biCompression = MAKEFOURCC('Y','U','Y','V');
else if (s->pix_fmt == MS_UYVY)
pvi->bmiHeader.biCompression = MAKEFOURCC('U','Y','V','Y');
else if (s->pix_fmt == MS_RGB24)
pvi->bmiHeader.biCompression = BI_RGB;
if (s->pix_fmt == MS_YUV420P)
pvi->bmiHeader.biBitCount = 12;
else if (s->pix_fmt == MS_YUY2)
pvi->bmiHeader.biBitCount = 16;
else if (s->pix_fmt == MS_YUYV)
pvi->bmiHeader.biBitCount = 16;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -