123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767 |
- #include "precompile.h"
- #include "videocap.h"
- #include "ListEntry.h"
- #include "qedit.h"
- #include <dshow.h> // need directshow sdk
- //#include "SpBase.h"
- #include <videohorflip.h>
- #define av_always_inline __inline
- #define inline __inline
- #include <libswscale\swscale.h>
- #include <libavcodec\avcodec.h>
- #include "libavutil/imgutils.h"
- #include "video_common/ffmpeg_api_adapter.h"
- //#pragma comment(lib, "strmiids.lib")
- //#pragma comment(lib, "..\\ffmpeg\\libswscale.lib")
- ////////////////////////////////////////////////////////////////////////////////////////
- // helper
- #define swap(t, x, y) \
- { \
- t v; \
- v = x; \
- x = y; \
- y = v; \
- }
- int g_width= 640;
- int g_height= 360;
- static void i420_flip_vertical(video_frame *frame)
- {
- if (frame->format == VIDEO_FORMAT_I420) {
- frame->data[0] = frame->data[0] + frame->linesize[0]*(frame->height-1);
- frame->data[1] = frame->data[1] + frame->linesize[1]*((frame->height>>1)-1);
- frame->data[2] = frame->data[2] + frame->linesize[2]*((frame->height>>1)-1);
- frame->linesize[0] = -frame->linesize[0];
- frame->linesize[1] = -frame->linesize[1];
- frame->linesize[2] = -frame->linesize[2];
- swap(unsigned char*, frame->data[1], frame->data[2]);
- swap(int, frame->linesize[1], frame->linesize[2]);
- }
- }
- static HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
- {
- IMoniker * pMoniker;
- IRunningObjectTable *pROT;
- WCHAR wsz[256];
- HRESULT hr;
- if (FAILED(GetRunningObjectTable(0, &pROT))) {
- return E_FAIL;
- }
- wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
- hr = CreateItemMoniker(L"!", wsz, &pMoniker);
- if (SUCCEEDED(hr)) {
- pROT->lpVtbl->Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,
- pMoniker, pdwRegister);
- pMoniker->lpVtbl->Release(pMoniker);
- }
- pROT->lpVtbl->Release(pROT);
- return hr;
- }
- static void RemoveFromRot(DWORD pdwRegister)
- {
- IRunningObjectTable *pROT;
- if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
- pROT->lpVtbl->Revoke(pROT, pdwRegister);
- pROT->lpVtbl->Release(pROT);
- }
- }
- static char* GuidToString(const GUID guid)
- {
- int buf_len=64;
- char *buf =(char *)malloc(buf_len);
- _snprintf(
- buf,
- buf_len,
- "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
- guid.Data1, guid.Data2, guid.Data3,
- guid.Data4[0], guid.Data4[1],
- guid.Data4[2], guid.Data4[3],
- guid.Data4[4], guid.Data4[5],
- guid.Data4[6], guid.Data4[7]);
- //printf("%s\n",buf);
- return buf;
- }
- static void FreeMediaTypeEx(AM_MEDIA_TYPE *pmt)
- {
- if (pmt) {
- if (pmt->cbFormat) {
- CoTaskMemFree((PVOID)pmt->pbFormat);
- pmt->cbFormat = 0;
- pmt->pbFormat = NULL;
- }
- if (pmt->pUnk) {
- pmt->pUnk->lpVtbl->Release(pmt->pUnk);
- pmt->pUnk = NULL;
- }
- CoTaskMemFree(pmt);
- }
- }
- static HRESULT GetUnconnectedPin(IBaseFilter *pFilter,PIN_DIRECTION PinDir,IPin **ppPin)
- {
- IEnumPins *pEnum = 0;
- IPin *pPin = 0;
- HRESULT hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
- *ppPin = 0;
- if (FAILED(hr))
- return hr;
- while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, NULL) == S_OK) {
- PIN_DIRECTION ThisPinDir;
- pPin->lpVtbl->QueryDirection(pPin, &ThisPinDir);
- if (ThisPinDir == PinDir) {
- IPin *pTmp = 0;
- hr = pPin->lpVtbl->ConnectedTo(pPin, &pTmp);
- if (SUCCEEDED(hr)) // Already connected, not the pin we want.
- pTmp->lpVtbl->Release(pTmp);
- else // Unconnected, this is the pin we want.
- {
- pEnum->lpVtbl->Release(pEnum);
- *ppPin = pPin;
- return S_OK;
- }
- }
- pPin->lpVtbl->Release(pPin);
- }
- pEnum->lpVtbl->Release(pEnum);
- // Did not find a matching pin.
- return E_FAIL;
- }
- static HRESULT ConnectFilters1(IGraphBuilder *pGraph, // Filter Graph Manager.
- IPin *pOut, // Output pin on the upstream filter.
- IBaseFilter *pDest) // Downstream filter.
- {
- IPin *pIn;
- HRESULT hr;
- if ((pGraph == NULL) || (pOut == NULL) || (pDest == NULL))
- {
- return E_POINTER;
- }
- // Find an input pin on the downstream filter.
- pIn = 0;
- hr = GetUnconnectedPin(pDest, PINDIR_INPUT, &pIn);
- if (FAILED(hr))
- {
- return hr;
- }
- // Try to connect them.
- hr = pGraph->lpVtbl->ConnectDirect(pGraph, pOut, pIn, NULL);
- if (FAILED(hr)){
- hr = pGraph->lpVtbl->Connect(pGraph, pOut, pIn);
- }
- pIn->lpVtbl->Release(pIn);
- return hr;
- }
- static HRESULT ConnectFilters2(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest)
- {
- IPin *pOut;
- HRESULT hr;
- if ((pGraph == NULL) || (pSrc == NULL) || (pDest == NULL))
- return E_POINTER;
- // Find an output pin on the first filter.
- pOut = 0;
- hr = GetUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);
- if (FAILED(hr))
- return hr;
- hr = ConnectFilters1(pGraph, pOut, pDest);
- pOut->lpVtbl->Release(pOut);
- return hr;
- }
- static HRESULT WalkFilterCategory(REFCLSID category,
- HRESULT (*OnDeviceCB)(int index,IMoniker *pMoniker,VOID *pUserData1,VOID *pUserData2),
- VOID * pUserData1,
- VOID* pUserData2)
- {
- HRESULT hr;
- ICreateDevEnum *pDevEnum = NULL;
- IEnumMoniker *pEnumMoniker = NULL;
- IMoniker *pMoniker = NULL;
- BOOL quit;
- int i = 0;
- if (!OnDeviceCB)
- return E_INVALIDARG;
- hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
- &IID_ICreateDevEnum, (void**)&pDevEnum);
- if (FAILED(hr))
- return hr;
- hr = pDevEnum->lpVtbl->CreateClassEnumerator(pDevEnum, category,
- &pEnumMoniker, 0);
- if (FAILED(hr)) {
- pDevEnum->lpVtbl->Release(pDevEnum);
- return hr;
- } else if (hr == S_OK) {
- pEnumMoniker->lpVtbl->Reset(pEnumMoniker);
- quit = FALSE;
- while (pEnumMoniker->lpVtbl->Next(pEnumMoniker, 1, &pMoniker, NULL) == S_OK && !quit) {
- hr = OnDeviceCB(i++, pMoniker, pUserData1, pUserData2);
- quit = FAILED(hr) || (hr == S_OK);
- pMoniker->lpVtbl->Release(pMoniker);
- }
- pEnumMoniker->lpVtbl->Release(pEnumMoniker);
- pDevEnum->lpVtbl->Release(pDevEnum);
- } else {
- if (pEnumMoniker)
- pEnumMoniker->lpVtbl->Release(pEnumMoniker);
- pDevEnum->lpVtbl->Release(pDevEnum);
- }
- return hr;
- }
- static HRESULT CreateFilterByFriendlyNameCB(int index, IMoniker *pMoniker, void *pUserData1, void *pUserData2)
- {
- HRESULT hr;
- IBaseFilter *pBaseFilter = NULL;
- WCHAR *szName = (WCHAR*)pUserData2;
- if (pMoniker) {
- IPropertyBag *pPropBag;
- VARIANT name;
- hr = pMoniker->lpVtbl->BindToStorage(pMoniker, NULL, NULL,
- &IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr))
- return S_FALSE;
- VariantInit(&name);
- name.vt = VT_BSTR;
- hr = pPropBag->lpVtbl->Read(pPropBag, L"FriendlyName", &name, NULL);
- if (FAILED(hr)) {
- pPropBag->lpVtbl->Release(pPropBag);
- VariantClear(&name);
- return S_FALSE;
- }
- if (SysStringByteLen(name.bstrVal) && wcscmp(name.bstrVal, szName)==0) {
- hr = pMoniker->lpVtbl->BindToObject(pMoniker, NULL, NULL,
- &IID_IBaseFilter, (void**)&pBaseFilter);
- if (SUCCEEDED(hr)) {
- *(IBaseFilter**)pUserData1 = pBaseFilter;
- hr = S_OK;
- }
- }
- pPropBag->lpVtbl->Release(pPropBag);
- VariantClear(&name);
- } else {
- hr = E_POINTER;
- }
- return hr;
- }
- static HRESULT CreateFilterByFriendlyName(REFCLSID category, void **ppBaseFilter, WCHAR* szName)
- {
- HRESULT hr = WalkFilterCategory(category,
- &CreateFilterByFriendlyNameCB, ppBaseFilter, szName);
- return hr == S_FALSE ? E_NOINTERFACE : hr;
- }
- static HRESULT CreateFilterByIndexCB(int index, IMoniker *pMoniker, void *pUserData1, void *pUserData2)
- {
- HRESULT hr;
- IBaseFilter *pBaseFilter = NULL;
- int *pidx = (int*)pUserData2;
- if (pMoniker && index == *pidx) {
- hr = pMoniker->lpVtbl->BindToObject(pMoniker, NULL, NULL,
- &IID_IBaseFilter, (void**)&pBaseFilter);
- if (FAILED(hr))
- return hr;
- *(IBaseFilter**)pUserData1 = pBaseFilter;
- return S_OK;
- }
- return S_FALSE;
- }
- static HRESULT CreateFilterByIndex(REFCLSID category,
- void **ppBaseFilter,
- int idx)
- {
- HRESULT hr = WalkFilterCategory(category, &CreateFilterByIndexCB,
- ppBaseFilter, &idx);
- return hr == S_FALSE ? E_NOINTERFACE : hr;
- }
- static HRESULT RemoveGraphAllFilters(IGraphBuilder *pGraphBuilder)
- {
- HRESULT hr;
- IEnumFilters *pEnumFilters;
- if (!pGraphBuilder)
- return E_POINTER;
- hr = pGraphBuilder->lpVtbl->EnumFilters(pGraphBuilder, &pEnumFilters);
- if (SUCCEEDED(hr)) {
- IBaseFilter *pFilter;
- pEnumFilters->lpVtbl->Reset(pEnumFilters);
- while (pEnumFilters->lpVtbl->Next(pEnumFilters, 1, &pFilter, NULL) == S_OK) {
- pGraphBuilder->lpVtbl->RemoveFilter(pGraphBuilder, pFilter);
- pFilter->lpVtbl->Release(pFilter);
- pEnumFilters->lpVtbl->Reset(pEnumFilters);
- }
- pEnumFilters->lpVtbl->Release(pEnumFilters);
- }
- return hr;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
- static const int mode_width[VIDEOCAP_MAX_MODE] = {
- VIDEOCAP_SQCIF_WIDTH,VIDEOCAP_QQVGA_WIDTH,
- VIDEOCAP_QCIF_WIDTH,VIDEOCAP_QVGA_WIDTH,
- VIDEOCAP_CIF_WIDTH,VIDEOCAP_VGA_WIDTH,
- VIDEOCAP_4CIF_WIDTH,VIDEOCAP_SVGA_WIDTH,
- VIDEOCAP_NHD_WIDTH,VIDEOCAP_SXGA_WIDTH,
- VIDEOCAP_720P_WIDTH,VIDEOCAP_1080P_WIDTH,
- };
- static const int mode_height[VIDEOCAP_MAX_MODE] = {
- VIDEOCAP_SQCIF_HEIGHT,VIDEOCAP_QQVGA_HEIGHT,
- VIDEOCAP_QCIF_HEIGHT,VIDEOCAP_QVGA_HEIGHT,
- VIDEOCAP_CIF_HEIGHT,VIDEOCAP_VGA_HEIGHT,
- VIDEOCAP_4CIF_HEIGHT,VIDEOCAP_SVGA_HEIGHT,
- VIDEOCAP_NHD_HEIGHT,VIDEOCAP_SXGA_HEIGHT,
- VIDEOCAP_720P_HEIGHT,VIDEOCAP_1080P_HEIGHT,
- };
- typedef struct async_cap_t
- {
- LIST_ENTRY entry;
- HANDLE evt;
- int result;
- video_frame *ref_cap_frame;
- }async_cap_t;
- /**
- * we use DirectShow to capture video frames
- */
- typedef struct videocap
- {
- IBaseFilter *sourcefilter;
- IBaseFilter *cpcfilter; // color space converter if necessary
- IBaseFilter *avidecfilter;
- IBaseFilter *grabberfilter;
- IBaseFilter *horflipfilter;
- IBaseFilter *renderfilter;
- ISampleGrabber *grabber;
- IGraphBuilder *graphbuilder;
- IMediaControl *mc;
- IMediaEvent *me;
- IVideoWindow *videowindow;
- #ifdef _DEBUG
- DWORD dwROTRegister; // register RunningObjectTable
- #endif
- videocap_param param;
- int running;
- HANDLE thread_background;
- HANDLE evt_thread_exit;
- int cap_index;
- CRITICAL_SECTION cap_cs;
- video_frame cap_frame;
- CRITICAL_SECTION async_cap_cs;
- LIST_ENTRY async_cap_list;
- LONG grab_cb_count;
- CRITICAL_SECTION res_cs;
- video_frame res_frame;
- struct SwsContext *sws_context; /* for image scaling and format converting */
- } videocap;
- HRESULT set_video_source_format(videocap *);
- void release_all_interfaces(videocap *);
- typedef struct ISampleGrabberCBImpl
- {
- struct ISampleGrabberCBVtbl *lpVtbl;
- struct videocap* vcap;
- struct ISampleGrabberCBVtbl vtbl;
- }ISampleGrabberCBImpl;
- static HRESULT STDMETHODCALLTYPE QueryInterface(ISampleGrabberCB * This,
- REFIID riid,
- void** ppvObject)
- {
- if (This == NULL || riid == NULL || ppvObject == NULL || *ppvObject == NULL)
- return E_POINTER;
- if (IsEqualIID(riid, &IID_IUnknown)) {
- *ppvObject = (void*)This;
- return S_OK;
- } else if (IsEqualIID(riid, &IID_ISampleGrabberCB)) {
- *ppvObject = (void*)This;
- return S_OK;
- }
- return E_NOTIMPL;
- }
- static ULONG STDMETHODCALLTYPE AddRef(ISampleGrabberCB * This)
- {
- return 1;
- }
- static ULONG STDMETHODCALLTYPE Release(ISampleGrabberCB * This)
- {
- free(This);
- return 0;
- }
- static HRESULT STDMETHODCALLTYPE SampleCB(ISampleGrabberCB * This, double SampleTime,IMediaSample *pSample)
- {
- return E_NOTIMPL;
- }
- static HRESULT STDMETHODCALLTYPE BufferCB(ISampleGrabberCB * This, double SampleTime,BYTE *pBuffer,long BufferLen)
- {
- ISampleGrabberCBImpl *pImpl = (ISampleGrabberCBImpl *)This;
- videocap *vcap = pImpl->vcap;
- int linesize = BufferLen / mode_height[vcap->param.cap_mode];
- struct SwsContext *sws;
- char*Buffertmp=(char*)malloc(mode_width[vcap->param.cap_mode]*mode_height[vcap->param.cap_mode]*3);
- uint8_t *src_data[4];
- int src_linesize[4];
- unsigned char *dst[4] = {(unsigned char*)Buffertmp,NULL,NULL,NULL};
- int dst_linesize[4] = {mode_width[vcap->param.cap_mode]*3,0,0,0};
- char*buffer;
- int oriLen = mode_height[vcap->param.cap_mode]*mode_width[vcap->param.cap_mode]*3;
- get_output_mediatype(vcap);
- //MFLog(LM_SYSTEM,(LB,"BufferLen=%d,w=%d,h=%d, g_width=%d,g_height=%d",BufferLen,mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode],g_width,g_height));
- if (BufferLen != oriLen)
- {
- //计算目标图像比例
- int srcH;
- //float fDstScale = (float)(mode_width[vcap->param.cap_mode]/mode_height[vcap->param.cap_mode]);
- float fDstScale = (float)mode_width[vcap->param.cap_mode]/(float)mode_height[vcap->param.cap_mode];
- float fSrcScale = (float)g_width/(float)g_height;
- //MFLog(LM_SYSTEM,(LB,"fDstScale=%f, fSrcScale=%f", fDstScale, fSrcScale));
- if (fSrcScale!=fDstScale)
- {
- //计算偏移量
- int nWidth,nHeight,nOffset=0;
- if (fSrcScale > fDstScale)
- {
- //宽度过大
- //nHeight = g_height;
- //nWidth = g_height*fDstScale;
- //nOffset = (g_height-nHeight)/2*nWidth*3;
- //MFLog(LM_SYSTEM,(LB,"too width"));
- return 0;
- }
- else if (fSrcScale < fDstScale)
- {
- //高度过长
- nWidth = g_width;
- nHeight = (int)ceil(g_width/fDstScale);
- nOffset = (g_height-nHeight)/2*nWidth*3;
- //MFLog(LM_SYSTEM,(LB,"too height,nWidth=%d,nHeight=%d,nOffset=%d",nWidth,nHeight,nOffset));
- }
- //计算等比例变换需要的SWS
- sws=sws_getContext(nWidth,nHeight,PIX_FMT_BGR24, mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode], PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- av_image_alloc(src_data, src_linesize,g_width,g_height, PIX_FMT_BGR24, 1);
- memcpy(src_data[0],pBuffer+nOffset,nWidth*nHeight*3); //Y
- srcH = nHeight;
- }
- else
- {
- //MFLog(LM_SYSTEM,(LB,"need scale"));
- //计算等比例变换需要的SWS
- sws=sws_getContext(g_width,g_height,PIX_FMT_BGR24, mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode], PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- av_image_alloc(src_data, src_linesize,g_width,g_height, PIX_FMT_BGR24, 1);
- memcpy(src_data[0],pBuffer,BufferLen); //Y
- srcH = g_height;
- }
- //分辨率转换
- sws_scale(sws, src_data, src_linesize, 0, srcH, dst, dst_linesize);
- sws_freeContext(sws);
- av_freep(&src_data[0]);
- buffer = Buffertmp;
- BufferLen = mode_width[vcap->param.cap_mode]*mode_height[vcap->param.cap_mode]*3;
- }
- else
- {
- //MFLog(LM_SYSTEM,(LB,"normal"));
- buffer = (char*)pBuffer;
- }
- linesize = BufferLen / mode_height[vcap->param.cap_mode];
- if (vcap->param.option & VIDEOCAP_OPT_ENABLE_GRAB)
- {
- if (vcap->cap_index++%3 == 0)
- { /* 3 is grabbing interval */
- EnterCriticalSection(&vcap->cap_cs);
- //memcpy(vcap->cap_frame.data[0], pBuffer, BufferLen);
- memcpy(vcap->cap_frame.data[0], buffer, BufferLen);
- LeaveCriticalSection(&vcap->cap_cs);
- }
- }
- if (vcap->grab_cb_count)
- {
- if (vcap->param.on_grab)
- {
- video_frame frm = {0};
- frm.data[0] = buffer;
- frm.linesize[0] = linesize;
- frm.width = mode_width[vcap->param.cap_mode];
- frm.height = mode_height[vcap->param.cap_mode];
- frm.format = VIDEO_FORMAT_RGB24;
- vcap->param.on_grab(vcap->param.user_data, &frm);
- }
- InterlockedDecrement(&vcap->grab_cb_count);
- }
- if (vcap->param.option & VIDEOCAP_OPT_ENABLE_ASYNC_GRAB)
- {
- async_cap_t *pos, *n;
- EnterCriticalSection(&vcap->async_cap_cs);
- ListEntry_ForEachSafe(pos, n, &vcap->async_cap_list, async_cap_t, entry)
- {
- ListEntry_DeleteNode(&pos->entry);
- pos->result = 0;
- memcpy(pos->ref_cap_frame->data[0], buffer, BufferLen);
- SetEvent(pos->evt);
- }
- LeaveCriticalSection(&vcap->async_cap_cs);
- }
- if (vcap->param.on_frame_raw)
- {
- video_frame frm = {0};
- frm.data[0] = buffer;
- frm.linesize[0] = linesize;
- frm.width = mode_width[vcap->param.cap_mode];
- frm.height = mode_height[vcap->param.cap_mode];
- frm.format = VIDEO_FORMAT_RGB24;
- vcap->param.on_frame_raw(vcap->param.user_data, &frm);
- }
- if (vcap->param.option & VIDEOCAP_OPT_EANBLE_RESIZE)
- { /* user enable resizing */
- unsigned char *src_data[4];
- int src_linesize[4] = {linesize, 0, 0, 0};
- src_data[0] = (unsigned char*)buffer;
- src_data[1] = NULL;
- src_data[2] = NULL;
- src_data[3] = NULL;
- EnterCriticalSection(&vcap->res_cs);
- if (vcap->param.option & VIDEOCAP_OPT_ENABLE_FLIP)
- {
- src_data[0] += (mode_height[vcap->param.cap_mode]-1)*src_linesize[0];
- src_linesize[0] = -src_linesize[0];
- sws_scale(vcap->sws_context, src_data, src_linesize, 0, mode_height[vcap->param.cap_mode], vcap->res_frame.data, vcap->res_frame.linesize);
- }
- else
- {
- sws_scale(vcap->sws_context, src_data, src_linesize,
- 0, mode_height[vcap->param.cap_mode], vcap->res_frame.data, vcap->res_frame.linesize);
- }
- if (vcap->param.on_frame)
- {
- vcap->param.on_frame(vcap->param.user_data, &vcap->res_frame);
- }
- LeaveCriticalSection(&vcap->res_cs);
- }
- else
- {
- if (vcap->param.on_frame)
- {
- video_frame frame;
- memset(&frame, 0, sizeof(video_frame));
- frame.width = mode_width[vcap->param.cap_mode];
- frame.height = mode_height[vcap->param.cap_mode];
- frame.data[0] = buffer;
- frame.linesize[0] = linesize;
- frame.format = VIDEO_FORMAT_RGB24;
- vcap->param.on_frame(vcap->param.user_data, &frame);
- //MFLog(LM_SYSTEM,(LB,"normal"));
- }
- }
- free(Buffertmp);
- return S_OK;
- }
- static ISampleGrabberCB* CreateISampleGrabberCBImpl(videocap *vcap)
- {
- ISampleGrabberCBImpl *pImpl =
- (ISampleGrabberCBImpl*)malloc(sizeof(ISampleGrabberCBImpl));
- if (pImpl) {
- pImpl->lpVtbl = &pImpl->vtbl;
- pImpl->lpVtbl->QueryInterface = &QueryInterface;
- pImpl->lpVtbl->AddRef = &AddRef;
- pImpl->lpVtbl->Release = &Release;
- pImpl->lpVtbl->BufferCB = &BufferCB;
- pImpl->lpVtbl->SampleCB = &SampleCB;
- pImpl->vcap = vcap;
- }
- return (ISampleGrabberCB*)pImpl;
- }
- static HRESULT TryConnectFilters(IGraphBuilder *pGraphBuilder, int cnt, IBaseFilter *pFilters[])
- {
- HRESULT hr = S_OK;
- int i;
- if (!pGraphBuilder)
- return E_POINTER;
- if (cnt == 0)
- return S_OK;
- if (!pFilters)
- return E_POINTER;
- for (i = 1; i < cnt; ++i)
- {
- IBaseFilter *src = pFilters[i-1];
- IBaseFilter *dst = pFilters[i];
- if (!src || !dst)
- return E_POINTER;
- hr = ConnectFilters2(pGraphBuilder, src, dst);
-
- if (FAILED(hr))
- {
- return hr;
- }
- }
- return hr;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
- /* used for device lost event listenning */
- static DWORD WINAPI BackgroundThread(LPVOID *param)
- {
- struct videocap *vcap = (struct videocap *)param;
- int quit = 0;
- HANDLE t;
- HANDLE evts[2] = {0};
- HANDLE hProcess = GetCurrentProcess();
- HRESULT hr;
- hr = vcap->me->lpVtbl->GetEventHandle(vcap->me, (OAEVENT*)&t);
- if (FAILED(hr))
- return 0;
- if (DuplicateHandle(hProcess, t, hProcess, &evts[0], DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_SAME_ACCESS) == FALSE)
- return 0;
- evts[1] = vcap->evt_thread_exit;
- while (!quit)
- {
- DWORD dwResult = WaitForMultipleObjects(2, evts, FALSE, INFINITE) - WAIT_OBJECT_0;
- if (0 == dwResult)
- {
- long lEventCode;
- LONG_PTR lParam1;
- LONG_PTR lParam2;
- vcap->me->lpVtbl->GetEvent(vcap->me, &lEventCode, &lParam1, &lParam2, INFINITE);
- if (lEventCode == EC_DEVICE_LOST || lEventCode == EC_ERRORABORT)
- {
- if (vcap->param.on_device_lost)
- (*vcap->param.on_device_lost)(vcap->param.user_data);
- quit = 1;
- }
- vcap->me->lpVtbl->FreeEventParams(vcap->me, lEventCode, lParam1, lParam2);
- }
- else
- {
- quit = 1;
- }
- }
- CloseHandle(evts[0]);
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
- int videocap_create(videocap_t *h ,videocap_param *param)
- {
- videocap *vcap;
- //RvcLog_init("./videoframework",1);
- /* check param */
- if (!param)
- return -1;
- if (param->cap_mode < 0 || param->cap_mode >= VIDEOCAP_MAX_MODE)
- return -1;
- if (param->frame_fmt != VIDEO_FORMAT_I420 && param->frame_fmt != VIDEO_FORMAT_RGB24)
- return -1;
- if (param->fps < 1.0 ||
- param->fps > 100.0)
- return -1;
- if (param->pre_hwnd)
- {
- if (!IsWindow(param->pre_hwnd))
- return -1;
- if (param->pre_width < 0)
- return -1;
- if (param->pre_height < 0)
- return -1;
- }
- if (param->dev_id < 0)
- return -1;
- if (param->frame_fmt == VIDEO_FORMAT_I420 && !(param->option&VIDEOCAP_OPT_EANBLE_RESIZE)) {
- param->res_mode = param->cap_mode;
- param->option |= VIDEOCAP_OPT_EANBLE_RESIZE;
- }
- if (param->option & VIDEOCAP_OPT_EANBLE_RESIZE) {
- if (param->res_mode < VIDEOCAP_FRAME_SQCIF || param->res_mode > VIDEOCAP_FRAME_SVGA)
- return -1;
- }
- vcap = (videocap*)malloc(sizeof(videocap));
- if (!vcap)
- return -1;
- ZeroMemory((void*)vcap, sizeof(videocap));
- memcpy(&vcap->param, param, sizeof(videocap_param));
- if (param->option & VIDEOCAP_OPT_ENABLE_GRAB) {
- int width = mode_width[param->cap_mode];
- int height = mode_height[param->cap_mode];
- if (video_frame_alloc(width, height, VIDEO_FORMAT_RGB24, &vcap->cap_frame) != 0) {
- free(vcap);
- return -1;
- }
- video_frame_fill_black(&vcap->cap_frame);
- InitializeCriticalSection(&vcap->cap_cs);
- }
- if (param->option & VIDEOCAP_OPT_ENABLE_ASYNC_GRAB) {
- InitializeCriticalSection(&vcap->async_cap_cs);
- }
- if (param->option & VIDEOCAP_OPT_EANBLE_RESIZE) {
- int width = mode_width[param->res_mode];
- int height = mode_height[param->res_mode];
- if (video_frame_alloc(width, height, param->frame_fmt, &vcap->res_frame) != 0) {
- if (param->option & VIDEOCAP_OPT_ENABLE_GRAB) {
- DeleteCriticalSection(&vcap->cap_cs);
- video_frame_free(&vcap->cap_frame);
- }
- free(vcap);
- return -1;
- }
- video_frame_fill_black(&vcap->res_frame);
- vcap->sws_context = sws_getContext(mode_width[param->cap_mode],
- mode_height[param->cap_mode],
- PIX_FMT_BGR24,
- mode_width[param->res_mode],
- mode_height[param->res_mode],
- vcap->param.frame_fmt==VIDEO_FORMAT_RGB24 ? PIX_FMT_BGR24 : PIX_FMT_YUV420P,
- SWS_FAST_BILINEAR,
- NULL,
- NULL,
- NULL);
- if (!vcap->sws_context) {
- video_frame_free(&vcap->res_frame);
- if (param->option & VIDEOCAP_OPT_ENABLE_GRAB) {
- DeleteCriticalSection(&vcap->cap_cs);
- video_frame_free(&vcap->cap_frame);
- }
- free(vcap);
- return -1;
- }
- InitializeCriticalSection(&vcap->res_cs);
- }
- *h = vcap;
- return 0;
- }
- void videocap_destroy(videocap_t h)
- {
- if (h->param.option & VIDEOCAP_OPT_ENABLE_GRAB) {
- DeleteCriticalSection(&h->cap_cs);
- video_frame_free(&h->cap_frame);
- }
- if (h->param.option & VIDEOCAP_OPT_ENABLE_ASYNC_GRAB) {
- DeleteCriticalSection(&h->async_cap_cs);
- }
- if (h->param.option & VIDEOCAP_OPT_EANBLE_RESIZE) {
- sws_freeContext(h->sws_context);
- DeleteCriticalSection(&h->res_cs);
- video_frame_free(&h->res_frame);
- }
- free(h);
- }
- int videocap_adj_brightness(videocap_t h, int nValue)
- {
- IAMVideoProcAmp *pProcAmp = 0;
- HRESULT hr = h->sourcefilter->lpVtbl->QueryInterface(h->sourcefilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp);
- if(SUCCEEDED(hr))
- {
- long Min, Max, Step, Default, Flags, Val;
- // 亮度.
- if(( nValue > 0 )&&(nValue < 100 ))
- {
- hr = pProcAmp->lpVtbl->GetRange(pProcAmp, VideoProcAmp_Brightness, &Min, &Max, &Step,
- &Default, &Flags);
- if(SUCCEEDED(hr))
- {
- Flags = VideoProcAmp_Flags_Manual;
- hr = pProcAmp->lpVtbl->Get(pProcAmp,VideoProcAmp_Brightness, &Val, &Flags);
- Val = ((Max-Min)*nValue/100)+Min;
- if (Val>Max)
- {
- Val = Max;
- }
- else if (Val<Min)
- {
- Val = Min;
- }
- hr = pProcAmp->lpVtbl->Set(pProcAmp,VideoProcAmp_Brightness, Val, Flags);
- }
- }
- }
- return hr;
- }
- int videocap_set_autobrightness(videocap_t h)
- {
- IAMVideoProcAmp *pProcAmp = 0;
- HRESULT hr = h->sourcefilter->lpVtbl->QueryInterface(h->sourcefilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp);
- if(SUCCEEDED(hr))
- {
- long Min, Max, Step, Default, Flags, Val;
- // 亮度.
- hr = pProcAmp->lpVtbl->GetRange(pProcAmp, VideoProcAmp_Brightness, &Min, &Max, &Step,
- &Default, &Flags);
- if(SUCCEEDED(hr))
- {
- Flags = VideoProcAmp_Flags_Auto;
- Val = Min + (Max-Min)/2;
- hr = pProcAmp->lpVtbl->Set(pProcAmp,VideoProcAmp_Brightness, Val, Flags);
- }
- }
- return hr;
- }
- int videocap_get_brightness(videocap_t h,int*nValue)
- {
- IAMVideoProcAmp *pProcAmp = 0;
- HRESULT hr = h->sourcefilter->lpVtbl->QueryInterface(h->sourcefilter, &IID_IAMVideoProcAmp, (void**)&pProcAmp);
- if(SUCCEEDED(hr))
- {
- long Min, Max, Step, Default, Flags, Val;
- // 亮度.
- hr = pProcAmp->lpVtbl->GetRange(pProcAmp, VideoProcAmp_Brightness, &Min, &Max, &Step,
- &Default, &Flags);
- if(SUCCEEDED(hr))
- {
- hr = pProcAmp->lpVtbl->Get(pProcAmp,VideoProcAmp_Brightness, &Val, &Flags);
- *nValue = (Val-Min)*100/(Max-Min);
- }
- }
- return hr;
- }
- int videocap_start(videocap_t h)
- {
- HRESULT hr;
- if (!h)
- return VIDEOCAP_ERROR;
- h->grab_cb_count = 0;
- ListEntry_InitHead(&h->async_cap_list);
- // create filter graph
- hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
- &IID_IGraphBuilder, (void**)&h->graphbuilder);
- if (FAILED(hr))
- {
- //Dbg("CoCreateInstance failed.");
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->QueryInterface(h->graphbuilder,
- &IID_IMediaControl, (void**)&h->mc);
- if (FAILED(hr))
- {
- //Dbg("QueryInterface failed.");
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->QueryInterface(h->graphbuilder,
- &IID_IMediaEvent, (void**)&h->me);
- if (FAILED(hr))
- {
- //Dbg("QueryInterface IID_IMediaEvent failed.");
- goto on_error;
- }
- #ifdef _DEBUG
- {
- IUnknown *pUnk;
- hr = h->graphbuilder->lpVtbl->QueryInterface(h->graphbuilder,
- &IID_IUnknown, (void**)&pUnk);
- if (FAILED(hr))
- goto on_error;
- hr = AddToRot(pUnk, &h->dwROTRegister);
- pUnk->lpVtbl->Release(pUnk);
- if (FAILED(hr))
- goto on_error;
- }
- #endif
- /* create video source filter and add to graph */
- hr = CreateFilterByIndex(&CLSID_VideoInputDeviceCategory,
- (void**)&h->sourcefilter, h->param.dev_id);
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->AddFilter(h->graphbuilder, h->sourcefilter, L"videosource");
- if (FAILED(hr))
- goto on_error;
- hr = set_video_source_format((videocap*)h);
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = CoCreateInstance(&CLSID_Colour, NULL, CLSCTX_INPROC_SERVER,
- &IID_IBaseFilter, (void**) &h->cpcfilter);
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->AddFilter(h->graphbuilder, h->cpcfilter, L"cpcfilter");
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = CoCreateInstance(&CLSID_AVIDec, NULL, CLSCTX_INPROC_SERVER,
- &IID_IBaseFilter, (void**) &h->avidecfilter);
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->AddFilter(h->graphbuilder, h->avidecfilter, L"avidecfilter");
- if (FAILED(hr))
- {
- goto on_error;
- }
- // create grabber filter and add to graph
- hr = CoCreateInstance(&CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
- &IID_IBaseFilter, (void**) &h->grabberfilter);
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->AddFilter(h->graphbuilder, h->grabberfilter, L"grabber");
- if (FAILED(hr))
- {
- goto on_error;
- }
- hr = h->grabberfilter->lpVtbl->QueryInterface(h->grabberfilter,
- &IID_ISampleGrabber, (void**)&h->grabber);
- if (FAILED(hr))
- {
- goto on_error;
- }
- if (1)
- {
- int width = mode_width[h->param.cap_mode];
- int height = mode_height[h->param.cap_mode];
- AM_MEDIA_TYPE *mt = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
- VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER*)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
- memset(mt, 0, sizeof(AM_MEDIA_TYPE));
- memset(pvi, 0, sizeof(VIDEOINFOHEADER));
- mt->lSampleSize = width * height * 3;
- mt->majortype = MEDIATYPE_Video;
- mt->subtype = MEDIASUBTYPE_RGB24;
- mt->formattype = FORMAT_VideoInfo;
- mt->bFixedSizeSamples = TRUE;
- mt->bTemporalCompression = FALSE;
- mt->cbFormat = sizeof(VIDEOINFOHEADER);
- mt->pbFormat = (BYTE*)pvi;
- pvi->bmiHeader.biWidth = width;
- pvi->bmiHeader.biHeight = height;
- pvi->bmiHeader.biSizeImage = width * height * 3;
- pvi->bmiHeader.biBitCount = 24;
- pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pvi->AvgTimePerFrame = (REFERENCE_TIME)(10000000 / h->param.fps);
- pvi->dwBitRate = (DWORD)(width*height*24*h->param.fps);
- hr = h->grabber->lpVtbl->SetMediaType(h->grabber, mt);
- FreeMediaTypeEx(mt);
- if (FAILED(hr))
- {
- //Dbg("SetMediaType error, err=%08xd", hr);
- goto on_error;
- }
- }
-
- h->grabber->lpVtbl->SetOneShot(h->grabber, FALSE);
- {
- ISampleGrabberCB *pImpl = CreateISampleGrabberCBImpl(h);
- if (!pImpl)
- goto on_error;
- // 0: SampleCB
- // 1: BufferCB
- h->grabber->lpVtbl->SetCallback(h->grabber, pImpl, 1);////////////////////////
- }
- if (h->param.option & VIDEOCAP_OPT_HOZFLIP) {
- h->horflipfilter = (IBaseFilter*)videohorflip_create_filter();
- if (!h->horflipfilter)
- goto on_error;
- hr = h->graphbuilder->lpVtbl->AddFilter(h->graphbuilder, h->horflipfilter, L"horflip");
- if (FAILED(hr))
- {
- goto on_error;
- }
- }
- // create render filter and add to graph
- {
- hr = CoCreateInstance(h->param.pre_hwnd ? &CLSID_VideoRendererDefault : &CLSID_NullRenderer,
- NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void**) &h->renderfilter);
- if (FAILED(hr))
- goto on_error;
- }
- hr = h->graphbuilder->lpVtbl->AddFilter(h->graphbuilder, h->renderfilter, L"renderfilter");
- if (FAILED(hr))
- {
- goto on_error;
- }
- // try connect filters
- if (!(h->param.option & VIDEOCAP_OPT_HOZFLIP)) {
- IBaseFilter *Filter1[] = {h->sourcefilter, h->grabberfilter, h->renderfilter};
- IBaseFilter *Filter2[] = {h->sourcefilter, h->cpcfilter, h->grabberfilter, h->renderfilter};
- IBaseFilter *Filter3[] = {h->sourcefilter, h->avidecfilter, h->grabberfilter, h->renderfilter};
- IBaseFilter *Filter4[] = {h->sourcefilter, h->avidecfilter, h->cpcfilter, h->grabberfilter, h->renderfilter};
- struct {
- int cnt;
- IBaseFilter **Filters;
- } tpl[] = {
- {ARRAYSIZE(Filter1), Filter1},
- {ARRAYSIZE(Filter2), Filter2},
- {ARRAYSIZE(Filter3), Filter3},
- {ARRAYSIZE(Filter4), Filter4},
- };
- int i;
- for (i = 0; i < ARRAYSIZE(tpl); ++i) {
- Sleep(50);
- hr = TryConnectFilters(h->graphbuilder, tpl[i].cnt, tpl[i].Filters);
- if (SUCCEEDED(hr)) {
- break;
- }
- }
- if (i == ARRAYSIZE(tpl)) {
- goto on_error;
- }
- } else {
- IBaseFilter *Filter1[] = {h->sourcefilter, h->grabberfilter, h->horflipfilter, h->renderfilter};
- IBaseFilter *Filter2[] = {h->sourcefilter, h->cpcfilter, h->grabberfilter, h->horflipfilter, h->renderfilter};
- IBaseFilter *Filter3[] = {h->sourcefilter, h->avidecfilter, h->grabberfilter, h->horflipfilter, h->renderfilter};
- IBaseFilter *Filter4[] = {h->sourcefilter, h->avidecfilter, h->cpcfilter, h->grabberfilter, h->horflipfilter, h->renderfilter};
- struct {
- int cnt;
- IBaseFilter **Filters;
- } tpl[] = {
- {ARRAYSIZE(Filter1), Filter1},
- {ARRAYSIZE(Filter2), Filter2},
- {ARRAYSIZE(Filter3), Filter3},
- {ARRAYSIZE(Filter4), Filter4},
- };
- int i;
- for (i = 0; i < ARRAYSIZE(tpl); ++i) {
- Sleep(50);
- hr = TryConnectFilters(h->graphbuilder, tpl[i].cnt, tpl[i].Filters);
- if (SUCCEEDED(hr)) {
- break;
- }
- }
- if (i == ARRAYSIZE(tpl)) {
- goto on_error;
- }
- }
- if (h->param.pre_hwnd) {
- RECT rc;
- hr = h->renderfilter->lpVtbl->QueryInterface(h->renderfilter,
- &IID_IVideoWindow, (void**)&h->videowindow);
- if (FAILED(hr))
- {
- goto on_error;
- }
- GetClientRect(h->param.pre_hwnd, &rc);
- h->videowindow->lpVtbl->put_Owner(h->videowindow, (OAHWND)h->param.pre_hwnd);
- h->videowindow->lpVtbl->put_Visible(h->videowindow, OAFALSE);
- h->videowindow->lpVtbl->put_Left(h->videowindow, 0);
- h->videowindow->lpVtbl->put_Top(h->videowindow, 0);
- h->videowindow->lpVtbl->put_Height(h->videowindow, min(h->param.pre_height, rc.bottom-rc.top));
- h->videowindow->lpVtbl->put_Width(h->videowindow, min(h->param.pre_width, rc.right - rc.left));
- h->videowindow->lpVtbl->put_WindowStyle(h->videowindow,
- WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);
- h->videowindow->lpVtbl->put_MessageDrain(h->videowindow, (OAHWND)h->param.pre_hwnd);
- h->videowindow->lpVtbl->put_Visible(h->videowindow, OATRUE);
- }
- if (h->param.on_device_lost) {
- h->thread_background = CreateThread(NULL, 0, &BackgroundThread, h, 0, 0);
- h->evt_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL);
- }
- hr = h->mc->lpVtbl->Run(h->mc);
- if (FAILED(hr))
- {
- goto on_error;
- }
- h->running = TRUE;
- return VIDEOCAP_OK;
- on_error:
- release_all_interfaces(h);
- return VIDEOCAP_ERROR;
- }
- int videocap_stop(videocap_t h)
- {
- long code;
-
- if (!h->running)
- return -1;
- if (h->param.on_device_lost) {
- SetEvent(h->evt_thread_exit);
- WaitForSingleObject(h->thread_background, INFINITE);
- CloseHandle(h->thread_background);
- h->thread_background = NULL;
- CloseHandle(h->evt_thread_exit);
- h->evt_thread_exit = NULL;
- }
- h->mc->lpVtbl->Stop(h->mc);
- h->me->lpVtbl->WaitForCompletion(h->me, INFINITE, &code);
- h->running = 0;
- if (h->param.option & VIDEOCAP_OPT_ENABLE_ASYNC_GRAB) {
- EnterCriticalSection(&h->async_cap_cs);
- {
- async_cap_t *pos, *n;
- ListEntry_ForEachSafe(pos, n, &h->async_cap_list, async_cap_t, entry) {
- ListEntry_DeleteNode(&pos->entry);
- pos->result = -1; // cancel
- SetEvent(pos->evt);
- }
- }
- LeaveCriticalSection(&h->async_cap_cs);
- }
- #ifdef _DEBUG
- RemoveFromRot(h->dwROTRegister);
- h->dwROTRegister = 0;
- #endif
- release_all_interfaces(h);
- return VIDEOCAP_OK;
- }
- int videocap_grab(videocap_t h, video_frame *frame)
- {
- int ret;
- if (!h)
- return -1;
- if (!h->running)
- return -1;
- if (!(h->param.option & VIDEOCAP_OPT_ENABLE_GRAB)) /* initialize without grabbing option */
- return -1;
- EnterCriticalSection(&h->cap_cs);
- ret = video_frame_copy(frame, &h->cap_frame);
- LeaveCriticalSection(&h->cap_cs);
- return ret;
- }
- int videocap_async_grab(videocap_t h, video_frame *frame)
- {
- async_cap_t *ac;
- if (!h)
- return -1;
- if (!h->running)
- return -1;
- if (!(h->param.option & VIDEOCAP_OPT_ENABLE_ASYNC_GRAB)) /* initialize without grabbing option */
- return -1;
- ac = (async_cap_t*)malloc(sizeof(async_cap_t));
- ac->evt = CreateEvent(NULL, FALSE, FALSE, NULL);
- ac->ref_cap_frame = frame;
- EnterCriticalSection(&h->async_cap_cs);
- ListEntry_AddTail(&h->async_cap_list, &ac->entry);
- LeaveCriticalSection(&h->async_cap_cs);
- WaitForSingleObject(ac->evt, INFINITE);
- CloseHandle(ac->evt);
- free(ac);
- return 0;
- }
- int videocap_incrment_grab_cb(videocap_t h)
- {
- if (!h)
- return -1;
- if (!h->running)
- return -1;
- InterlockedIncrement(&h->grab_cb_count);
- return 0;
- }
- int videocap_get_frame(videocap_t h, video_frame *frame)
- {
- int ret;
- if (!h)
- return -1;
- if (!(h->param.option & VIDEOCAP_OPT_EANBLE_RESIZE))
- return -1;
- if (!h->running)
- return -1;
- EnterCriticalSection(&h->res_cs);
- ret = video_frame_copy(frame, &h->res_frame);
- LeaveCriticalSection(&h->res_cs);
- return ret;
- }
- int videocap_is_running(videocap_t h, BOOL *state)
- {
- if (!h)
- return VIDEOCAP_ERROR;
- return h->running;
- }
- int videocap_set_preview_wnd_visible(videocap_t h, BOOL visible)
- {
- if (!h || !h->videowindow)
- return VIDEOCAP_ERROR;
- h->videowindow->lpVtbl->put_Visible(h->videowindow,
- visible ? OATRUE : OAFALSE);
- return VIDEOCAP_OK;
- }
- int videocap_get_preview_wnd_visible(videocap_t h, BOOL *visible)
- {
- long l = OAFALSE;
- if (!h || !h->videowindow)
- return VIDEOCAP_ERROR;
- h->videowindow->lpVtbl->get_Visible(h->videowindow, &l);
- *visible = l ? TRUE : FALSE;
- return VIDEOCAP_OK;
- }
- int videocap_set_preview_wnd_width(videocap_t h, int width)
- {
- if (!h)
- return -1;
- if (!h->param.pre_hwnd)
- return -1;
- h->videowindow->lpVtbl->put_Width(h->videowindow, width);
- return 0;
- }
- int videocap_set_preview_wnd_height(videocap_t h, int height)
- {
- if (!h)
- return -1;
- if (!h->param.pre_hwnd)
- return -1;
- h->videowindow->lpVtbl->put_Height(h->videowindow, height);
- return 0;
- }
- static HRESULT set_video_source_format(videocap *vcap)
- {
- HRESULT hr;
- IAMStreamConfig *config;
- ICaptureGraphBuilder2 *capturebuilder;
- VIDEOINFOHEADER *pvi;
- int i, count, size = 0;
- BOOL alreadyset = FALSE;
- // create capture builder
- hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
- &IID_ICaptureGraphBuilder2, (void**)&capturebuilder);
- if (FAILED(hr))
- return hr;
- hr = capturebuilder->lpVtbl->FindInterface(capturebuilder,
- &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, vcap->sourcefilter,
- &IID_IAMStreamConfig, (void**)&config);
- if (FAILED(hr))
- return hr;
- config->lpVtbl->GetNumberOfCapabilities(config, &count, &size);
- if (size == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
- int width = mode_width[vcap->param.cap_mode];
- int height = mode_height[vcap->param.cap_mode];
- for (i = 0; i < count && !alreadyset; ++i)
- {
- VIDEO_STREAM_CONFIG_CAPS scc;
- AM_MEDIA_TYPE *pmtConfig;
- hr = config->lpVtbl->GetStreamCaps(config, i, &pmtConfig, (BYTE*)&scc);
- if (FAILED(hr))
- continue;
- if (IsEqualIID(&pmtConfig->majortype, &MEDIATYPE_Video) &&
- IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo) &&
- (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) &&
- pmtConfig->pbFormat != NULL)
- {
- pvi = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
- if (pvi->bmiHeader.biWidth == width && pvi->bmiHeader.biHeight == height)
- {
- pvi->AvgTimePerFrame = (REFERENCE_TIME)(10000000 / vcap->param.fps);
- hr = config->lpVtbl->SetFormat(config, pmtConfig);
- if (SUCCEEDED(hr))
- {
- char *subtype_str=GuidToString(pmtConfig->subtype);
- alreadyset = TRUE;
- }
- else
- {
- alreadyset = FALSE;
- }
- }
- }
- FreeMediaTypeEx(pmtConfig);
- }
- }
- config->lpVtbl->Release(config);
- capturebuilder->lpVtbl->Release(capturebuilder);
- return hr;
- }
- static HRESULT get_output_mediatype(videocap *vcap)
- {
- AM_MEDIA_TYPE mt;
- HRESULT hr;
- VIDEOINFOHEADER *videoHeader = NULL;
- char *subtype_str = NULL;
- ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
- hr = vcap->grabber->lpVtbl->GetConnectedMediaType(vcap->grabber, &mt);
- if(FAILED(hr))
- {
- printf("GetConnectedMediaType Failed, hr=%08X! \n",hr);
- return hr;
- }
-
- videoHeader = (VIDEOINFOHEADER*)(mt.pbFormat);
- g_width = videoHeader->bmiHeader.biWidth;
- g_height = videoHeader->bmiHeader.biHeight;
- subtype_str=GuidToString(mt.subtype);
- printf("grabber Format Width=%d, Height=%d, biBitCount=%d, biSizeImage=%d, biCompression=%d, biPlanes=%d,biSize=%d,subtype=%s\n,newPmt->lSampleSize=%d, newPmt->bFixedSizeSamples=%d, newPmt->bTemporalCompression=%d\n",
- videoHeader->bmiHeader.biWidth,
- videoHeader->bmiHeader.biHeight,
- videoHeader->bmiHeader.biBitCount,
- videoHeader->bmiHeader.biSizeImage,
- videoHeader->bmiHeader.biCompression,
- videoHeader->bmiHeader.biPlanes,
- videoHeader->bmiHeader.biSize,
- subtype_str,
- mt.lSampleSize,
- mt.bFixedSizeSamples,
- mt.bTemporalCompression);
- return S_OK;
- }
- static void release_all_interfaces(videocap *h)
- {
- if (h->mc) {
- h->mc->lpVtbl->Release(h->mc);
- h->mc = NULL;
- }
- if (h->me) {
- h->me->lpVtbl->Release(h->me);
- h->me = NULL;
- }
- if (h->videowindow) {
- h->videowindow->lpVtbl->put_Owner(h->videowindow, (OAHWND)NULL);
- h->videowindow->lpVtbl->Release(h->videowindow);
- h->videowindow = NULL;
- }
- if (h->graphbuilder) {
- RemoveGraphAllFilters(h->graphbuilder);
- h->graphbuilder->lpVtbl->Release(h->graphbuilder);
- h->graphbuilder = NULL;
- }
- if (h->sourcefilter) {
- h->sourcefilter->lpVtbl->Release(h->sourcefilter);
- h->sourcefilter = NULL;
- }
- if (h->avidecfilter) {
- h->avidecfilter->lpVtbl->Release(h->avidecfilter);
- h->avidecfilter = NULL;
- }
- if (h->cpcfilter) {
- h->cpcfilter->lpVtbl->Release(h->cpcfilter);
- h->cpcfilter = NULL;
- }
- if (h->grabber) {
- h->grabber->lpVtbl->Release(h->grabber);
- h->grabber = NULL;
- }
- if (h->grabberfilter) {
- h->grabberfilter->lpVtbl->Release(h->grabberfilter);
- h->grabberfilter = NULL;
- }
- if (h->horflipfilter) {
- h->horflipfilter->lpVtbl->Release(h->horflipfilter);
- h->horflipfilter = NULL;
- }
- if (h->renderfilter) {
- h->renderfilter->lpVtbl->Release(h->renderfilter);
- h->renderfilter = NULL;
- }
- }
- ////////////////////////////////////////////////////////////
- static HRESULT get_device_count_cb(int index, IMoniker *pMoniker, void *pUserData1, void *pUserData2)
- {
- if (pMoniker)
- ++*(int*)pUserData1;
- return S_FALSE;
- }
- int videocap_get_device_count()
- {
- int count = 0;
- HRESULT hr = WalkFilterCategory(&CLSID_VideoInputDeviceCategory,
- &get_device_count_cb, &count, NULL);
- return SUCCEEDED(hr) ? count : 0;
- }
- struct _buf {
- WCHAR *buf;
- int len;
- };
- static HRESULT get_device_name_cb(int index, IMoniker *pMoniker, void *pUserData1, void *pUserData2)
- {
- if (pMoniker) {
- int *p_id = (int*)pUserData1;
- struct _buf *buf = (struct _buf*)pUserData2;
- HRESULT hr;
- if (index == *p_id) {
- IPropertyBag *pPropBag;
- VARIANT name;
- hr = pMoniker->lpVtbl->BindToStorage(pMoniker, NULL, NULL,
- &IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr)) {
- buf->len = -1; /* failed */
- return hr;
- }
- VariantInit(&name);
- name.vt = VT_BSTR;
- hr = pPropBag->lpVtbl->Read(pPropBag, L"FriendlyName", &name, NULL);
- if (FAILED(hr)) {
- pPropBag->lpVtbl->Release(pPropBag);
- VariantClear(&name);
- buf->len = -1;
- return hr;
- }
- buf->len = SysStringByteLen(name.bstrVal) + 2;
- if (buf)
- memcpy(buf->buf, name.bstrVal, buf->len);
- pPropBag->lpVtbl->Release(pPropBag);
- VariantClear(&name);
- return S_OK;
- }
- }
- return S_FALSE;
- }
- int videocap_get_device_name(int device_id, WCHAR *buf, int len)
- {
- struct _buf x = {buf, len};
- int dev_id = device_id;
- HRESULT hr = WalkFilterCategory(&CLSID_VideoInputDeviceCategory,
- &get_device_name_cb, &dev_id, &x);
- if (hr == S_OK)
- return x.len;
- return -1;
- }
- static HRESULT get_device_path_cb(int index, IMoniker *pMoniker, void *pUserData1, void *pUserData2)
- {
- if (pMoniker) {
- int *p_id = (int*)pUserData1;
- struct _buf *buf = (struct _buf*)pUserData2;
- HRESULT hr;
- if (index == *p_id) {
- IPropertyBag *pPropBag;
- VARIANT path;
- hr = pMoniker->lpVtbl->BindToStorage(pMoniker, NULL, NULL,
- &IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr)) {
- buf->len = -1; /* failed */
- return hr;
- }
- VariantInit(&path);
- path.vt = VT_BSTR;
- hr = pPropBag->lpVtbl->Read(pPropBag, L"DevicePath", &path, NULL);
- if (FAILED(hr)) {
- pPropBag->lpVtbl->Release(pPropBag);
- VariantClear(&path);
- buf->len = -1;
- return hr;
- }
- buf->len = SysStringByteLen(path.bstrVal) + 2;
- if (buf)
- memcpy(buf->buf, path.bstrVal, buf->len);
- pPropBag->lpVtbl->Release(pPropBag);
- VariantClear(&path);
- return S_OK;
- }
- }
- return S_FALSE;
- }
- int videocap_get_device_path(int device_id, WCHAR *buf, int len)
- {
- struct _buf x = {buf, len};
- int dev_id = device_id;
- HRESULT hr = WalkFilterCategory(&CLSID_VideoInputDeviceCategory,
- &get_device_path_cb, &dev_id, &x);
- if (hr == S_OK)
- return x.len;
- return -1;
- }
- static int is_support(int min, int max, int granularity, int x)
- {
- if (x < min || x > max)
- return 0;
- if (x == min || x == max)
- return 1;
- if (granularity == 0)
- return 0;
- if ((x-min)/granularity*granularity != (x-min))
- return 0;
- if ((max-x)/granularity*granularity != (max-x))
- return 0;
- return 1;
- }
- static int is_support_size(VIDEO_STREAM_CONFIG_CAPS *pscc, int width, int height)
- {
- return is_support(pscc->MinOutputSize.cx, pscc->MaxOutputSize.cx, pscc->OutputGranularityX, width) &&
- is_support(pscc->MinOutputSize.cy, pscc->MaxOutputSize.cy, pscc->OutputGranularityY, height);
- }
- int videocap_get_device_cap(int device_id, videocap_device_cap *cap)
- {
- int error = -1, i, count, size = 0, j;
- HRESULT hr;
- ICaptureGraphBuilder2 *pBuilder = NULL;
- IBaseFilter *pSourceFilter = NULL;
- IAMStreamConfig *config = NULL;
- videocap_device_cap tmp_cap = {0};
- if (!cap)
- return error;
- hr = CreateFilterByIndex(&CLSID_VideoInputDeviceCategory, (void**)&pSourceFilter, device_id);
- if (FAILED(hr))
- return error;
- hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
- &IID_ICaptureGraphBuilder2, (void**)&pBuilder);
- if (FAILED(hr))
- return error;
- ZeroMemory(cap, sizeof(videocap_device_cap));
- hr = pBuilder->lpVtbl->FindInterface(pBuilder, &PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video, pSourceFilter, &IID_IAMStreamConfig, (void**)&config);
- if (FAILED(hr))
- goto on_error;
- config->lpVtbl->GetNumberOfCapabilities(config, &count, &size);
- if (size == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
- for (i = 0; i < count; ++i) {
- VIDEO_STREAM_CONFIG_CAPS scc;
- AM_MEDIA_TYPE *pmtConfig;
- VIDEOINFOHEADER *pvi = NULL;
- hr = config->lpVtbl->GetStreamCaps(config, i, &pmtConfig, (BYTE*)&scc);
- if (FAILED(hr))
- continue;
- if (IsEqualIID(&pmtConfig->majortype, &MEDIATYPE_Video) &&
- IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo) &&
- (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) &&
- pmtConfig->pbFormat != NULL) {
- if (IsEqualIID(&pmtConfig->subtype, &MEDIASUBTYPE_RGB24)) {
- for (j = 0; j < VIDEOCAP_MAX_MODE; ++j) {
- if (is_support_size(&scc, mode_width[j], mode_height[j])) {
- tmp_cap.mode[j] = 1;
- tmp_cap.min_frame_interval[j] = (int)scc.MinFrameInterval;
- tmp_cap.max_frame_interval[j] = (int)scc.MaxFrameInterval;
- }
- }
- }
- }
- FreeMediaTypeEx(pmtConfig);
- }
- }
- config->lpVtbl->Release(config);
- for (i = 0, j = 0; i < VIDEOCAP_MAX_MODE; ++i) {
- if (tmp_cap.mode[i]) {
- cap->mode[j] = i;
- cap->min_frame_interval[j] = cap->min_frame_interval[i];
- cap->max_frame_interval[j] = cap->max_frame_interval[i];
- j++;
- }
- }
- cap->mode_cnt = j;
- error = 0;
- on_error:
- if (pBuilder)
- pBuilder->lpVtbl->Release(pBuilder);
- if (pSourceFilter)
- pSourceFilter->lpVtbl->Release(pSourceFilter);
- return error;
- }
- int videocap_get_mode_width(int mode)
- {
- return mode_width[mode];
- }
- int videocap_get_mode_height(int mode)
- {
- return mode_height[mode];
- }
- void YUV2RGB(byte *pYUV, byte *pRGB)
- {
- byte y, u, v;
- y = *pYUV;
- pYUV++;
- u = *pYUV;
- pYUV++;
- v = *pYUV;
- //r
- *pRGB = 1.0*y+1.772*(u-128);
- if (*pRGB<0) *pRGB = 0;
- if(*pRGB>255) *pRGB = 255;
- //G
- pRGB++;
- *pRGB =1.0*y - 0.34413*(u-128) - 0.71414*(v-128);
- if (*pRGB<0) *pRGB = 0;
- if(*pRGB>255) *pRGB = 255;
- //b
- pRGB++;
- *pRGB = 1.0*y+1.402*(v-128);
- if (*pRGB<0) *pRGB = 0;
- if(*pRGB>255) *pRGB = 255;
- pYUV++;
- y = *pYUV;
- pYUV++;
- u = *pYUV;
- pYUV++;
- v = *pYUV;
- //r
- pRGB++;
- *pRGB = 1.0*y+1.772*(u-128);
- if (*pRGB<0) *pRGB = 0;
- if(*pRGB>255) *pRGB = 255;
- //G
- pRGB++;
- *pRGB =1.0*y - 0.34413*(u-128) - 0.71414*(v-128);
- if (*pRGB<0) *pRGB = 0;
- if(*pRGB>255) *pRGB = 255;
- //b
- pRGB++;
- *pRGB = 1.0*y+1.402*(v-128);
- if (*pRGB<0)
- *pRGB = 0;
- if(*pRGB>255)
- *pRGB = 255;
- }
- int Yuv2RgbFrame(BYTE* pYUVBuf, BYTE* pRGBBuf, int cx, int cy)
- {
- int i = 0;
- int j=0;
- BYTE* pYUV = pYUVBuf;
- BYTE* pRGB = pRGBBuf;
- BYTE YUV[6];
- BYTE RGB[6];
- memset(YUV,0,6);
- memset(RGB,0,6);
- for ( i = 0;i<cy;i++)
- {
- for ( j=0; j<cx;j+=2)
- {
- //yuy2(yuyv)-->yuv444(yuvyuv)-->rgb24
- YUV[0] = *pYUV;
- pYUV++;
- YUV[1] = *pYUV;
- pYUV+=2;
- YUV[2] = *pYUV;
- pYUV--;
- YUV[3] = *pYUV;
- pYUV--;
- YUV[4] = *pYUV;
- pYUV+=2;
- YUV[5] = *pYUV;
- pYUV++;
- YUV2RGB(YUV,RGB);
- memcpy(pRGB + ((cy-i-1)*cx + j)*3 ,RGB,6);
- }
- }
- return 0;
- }
- int yuv422_to_rgb24(unsigned char*yuv422,unsigned char*rgb24,int width,int height)
- {
- int x,y;
- uint8_t*yuv444;
- yuv444 = (uint8_t*) malloc(sizeof(uint8_t) * width * height * 3);
- for(x = 0,y = 0;x < width*height*2,y < width*height*3;x+=4,y+=6)
- {
- yuv444[y] = yuv422[x];
- yuv444[y+1] = yuv422[x+1];
- yuv444[y+2] = yuv422[x+3];
- yuv444[y+3] = yuv422[x+2];
- yuv444[y+4] = yuv422[x+1];
- yuv444[y+5] = yuv422[x+3];
- }
- for(x = 0;x < width*height*3;x+=3)
- {
- rgb24[x+2] = yuv444[x] + 1.402*(yuv444[x+2] - 128);
- rgb24[x+1] = yuv444[x]-0.34414*(yuv444[x+1]-128)-0.71414*(yuv444[x+2]-128);
- rgb24[x] = yuv444[x] + 1.772*(yuv444[x+1] - 128);
- if(rgb24[x]>255)
- rgb24[x]=255;
- if(rgb24[x]<0)
- rgb24[x]=0;
- if(rgb24[x+1]>255)
- rgb24[x+1]=255;
- if(rgb24[x+1]<0)
- rgb24[x+1]=0;
- if(rgb24[x+2]>255)
- rgb24[x+2]=255;
- if(rgb24[x+2]<0)
- rgb24[x+2]=0;
- }
- free(yuv444);
- return 0;
- }
- ////////////////////////////////////////////////////////////
|