1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230 |
- #include "precompile.h"
- #include "videocap.h"
- #include "ListEntry.h"
- #include "qedit.h"
- #include <dshow.h> // need directshow sdk
- #include <videohorflip.h>
- #include "libyuv/convert.h"
- #include "libyuv/video_common.h"
- #include "libyuv/scale.h"
- // helper
- #define swap(t, x, y) \
- { \
- t v; \
- v = x; \
- x = y; \
- y = v; \
- }
- HRESULT get_output_mediatype(videocap *vcap);
- static void capDbg(videocap_param *cap, const char *fmt, ...)
- {
- va_list arg;
- va_start(arg, fmt);
- if (cap->dbg) {
- (*cap->dbg)(fmt, arg);
- }
- va_end(arg);
- }
- int I420DataSize(int height, int stride_y, int stride_u, int stride_v) {
- return stride_y * height + (stride_u + stride_v) * ((height + 1) / 2);
- }
- int RGB24DataSize(int height, int stride_y, int stride_u, int stride_v) {
- return stride_y * height * 2 + ((stride_u + stride_v) * ((height + 1) / 2) * 2);
- }
- static void capLogEvent(videocap_param *cap, int ilogtype, const char* strmessage)
- {
- if (cap->logevent) {
- (*cap->logevent)(cap->user_data, ilogtype, cap->dev_id, strmessage);
- }
- }
- 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->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,
- pMoniker, pdwRegister);
- pMoniker->Release();
- }
- pROT->Release();
- return hr;
- }
- static void RemoveFromRot(DWORD pdwRegister)
- {
- IRunningObjectTable *pROT;
- if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
- pROT->Revoke(pdwRegister);
- pROT->Release();
- }
- }
- 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->Release();
- pmt->pUnk = NULL;
- }
- CoTaskMemFree(pmt);
- }
- }
- static HRESULT GetUnconnectedPin(IBaseFilter *pFilter,PIN_DIRECTION PinDir,IPin **ppPin)
- {
- IEnumPins *pEnum = 0;
- IPin *pPin = 0;
- HRESULT hr = pFilter->EnumPins(&pEnum);
- *ppPin = 0;
- if (FAILED(hr))
- return hr;
- while (pEnum->Next(1, &pPin, NULL) == S_OK) {
- PIN_DIRECTION ThisPinDir;
- pPin->QueryDirection(&ThisPinDir);
- if (ThisPinDir == PinDir) {
- IPin *pTmp = 0;
- hr = pPin->ConnectedTo(&pTmp);
- if (SUCCEEDED(hr)) // Already connected, not the pin we want.
- pTmp->Release();
- else // Unconnected, this is the pin we want.
- {
- pEnum->Release();
- *ppPin = pPin;
- return S_OK;
- }
- }
- pPin->Release();
- }
- pEnum->Release();
- // 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->ConnectDirect(pOut, pIn, NULL);
- if (FAILED(hr)){
- hr = pGraph->Connect(pOut, pIn);
- }
- pIn->Release();
- 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->Release();
- 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->CreateClassEnumerator(category,
- &pEnumMoniker, 0);
- if (FAILED(hr)) {
- pDevEnum->Release();
- return hr;
- } else if (hr == S_OK) {
- pEnumMoniker->Reset();
- quit = FALSE;
- while (pEnumMoniker->Next(1, &pMoniker, NULL) == S_OK && !quit) {
- hr = OnDeviceCB(i++, pMoniker, pUserData1, pUserData2);
- quit = FAILED(hr) || (hr == S_OK);
- pMoniker->Release();
- }
- pEnumMoniker->Release();
- pDevEnum->Release();
- } else {
- if (pEnumMoniker)
- pEnumMoniker->Release();
- pDevEnum->Release();
- }
- 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->BindToStorage(NULL, NULL,
- IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr))
- return S_FALSE;
- VariantInit(&name);
- name.vt = VT_BSTR;
- hr = pPropBag->Read( L"FriendlyName", &name, NULL);
- if (FAILED(hr)) {
- pPropBag->Release();
- VariantClear(&name);
- return S_FALSE;
- }
- if (SysStringByteLen(name.bstrVal) && wcscmp(name.bstrVal, szName)==0) {
- hr = pMoniker->BindToObject(NULL, NULL,
- IID_IBaseFilter, (void**)&pBaseFilter);
- if (SUCCEEDED(hr)) {
- *(IBaseFilter**)pUserData1 = pBaseFilter;
- hr = S_OK;
- }
- }
- pPropBag->Release();
- 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->BindToObject(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->EnumFilters(&pEnumFilters);
- if (SUCCEEDED(hr)) {
- IBaseFilter *pFilter;
- pEnumFilters->Reset();
- while (pEnumFilters->Next(1, &pFilter, NULL) == S_OK) {
- pGraphBuilder->RemoveFilter(pFilter);
- pFilter->Release();
- pEnumFilters->Reset();
- }
- pEnumFilters->Release();
- }
- 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 */
- int iout_width;
- int iout_height;
- bool bloged;
- } videocap;
- HRESULT set_video_source_format(videocap *);
- void release_all_interfaces(videocap *);
- typedef struct ISampleGrabberCBImpl
- {
- struct ISampleGrabberCB *pCb;
- struct videocap* vcap;
- //struct ISampleGrabberCBVtbl vtbl;
- }ISampleGrabberCBImpl;
- class RvcSampleGrabberCB : public ISampleGrabberCB
- {
- public:
- RvcSampleGrabberCB(struct videocap* vcap);
- HRESULT STDMETHODCALLTYPE SampleCB(
- double SampleTime,
- IMediaSample *pSample);
- HRESULT STDMETHODCALLTYPE BufferCB(
- double SampleTime,
- BYTE *pBuffer,
- long BufferLen);
- HRESULT STDMETHODCALLTYPE QueryInterface(
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject);
- ULONG STDMETHODCALLTYPE AddRef( void);
- ULONG STDMETHODCALLTYPE Release( void);
- private:
- struct videocap* m_vcap;
- };
- RvcSampleGrabberCB::RvcSampleGrabberCB(struct videocap* vcap)
- {
- m_vcap = vcap;
- }
- HRESULT STDMETHODCALLTYPE RvcSampleGrabberCB::SampleCB(
- double SampleTime,
- IMediaSample *pSample)
- {
- return S_OK;
- }
- static HRESULT Handle_BGR_Frame_CallBack(videocap *vcap, BYTE *pBuffer, long BufferLen)
- {
- 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;
- if (BufferLen != oriLen)
- {
- //计算目标图像比例
- int srcH;
- float fDstScale = (float)mode_width[vcap->param.cap_mode]/(float)mode_height[vcap->param.cap_mode];
- float fSrcScale = (float)vcap->iout_width /(float)vcap->iout_height;
- if (fSrcScale != fDstScale)
- {
- //计算偏移量
- int nWidth,nHeight,nOffset=0;
- if (fSrcScale > fDstScale)
- {
- return 0;
- }
- else if (fSrcScale < fDstScale)
- {
- //高度过长
- nWidth = vcap->iout_width;
- nHeight = (int)ceil(vcap->iout_width/fDstScale);
- nOffset = (vcap->iout_height -nHeight)/2*nWidth*3;
- }
- //计算等比例变换需要的SWS
- sws=sws_getContext(nWidth,nHeight,AV_PIX_FMT_BGR24, mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode], AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- av_image_alloc(src_data, src_linesize, vcap->iout_width, vcap->iout_height, AV_PIX_FMT_BGR24, 1);
- memcpy(src_data[0],pBuffer+nOffset,nWidth*nHeight*3); //Y
- srcH = nHeight;
- }
- else
- {
- //计算等比例变换需要的SWS
- sws=sws_getContext(vcap->iout_width, vcap->iout_height, AV_PIX_FMT_BGR24, mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode], AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- av_image_alloc(src_data, src_linesize, vcap->iout_width, vcap->iout_height, AV_PIX_FMT_BGR24, 1);
- memcpy(src_data[0],pBuffer,BufferLen); //Y
- srcH = vcap->iout_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
- {
- 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] = (unsigned char*)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] = (unsigned char*)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] = (unsigned char*)buffer;
- frame.linesize[0] = linesize;
- frame.format = VIDEO_FORMAT_RGB24;
- vcap->param.on_frame(vcap->param.user_data, &frame);
- }
- }
- free(Buffertmp);
- return S_OK;
- }
- static HRESULT Handle_YUY2_Frame_CallBack(videocap *vcap, BYTE *pBuffer, long BufferLen)
- {
- float fDstScale = (float)mode_width[vcap->param.cap_mode]/(float)mode_height[vcap->param.cap_mode];
- float fSrcScale = (float)vcap->iout_width /(float)vcap->iout_height;
- int used_width = vcap->iout_width;
- int used_height = vcap->iout_height;
- if (fSrcScale < fDstScale){
- used_height = (int)ceil(vcap->iout_width /fDstScale);
- }
- else if (fSrcScale > fDstScale){
- return S_FALSE;
- }
- int stride_y = used_width;
- int stride_u = (used_width + 1)/2;
- int stride_v = (used_width + 1)/2;
- uint8_t* m_i420 = (uint8_t*)malloc(I420DataSize(used_height, stride_y, stride_u, stride_v));
- int conversionResult = libyuv::ConvertToI420(pBuffer, BufferLen,
- m_i420,
- stride_y,
- m_i420 + stride_y * used_height,
- stride_u,
- m_i420 + stride_y * used_height + stride_u * ((used_height + 1) / 2),
- stride_v,
- 0,
- (vcap->iout_height -used_height)/2, // No Cropping
- vcap->iout_width,
- vcap->iout_height,
- vcap->iout_width,
- used_height,
- libyuv::kRotate180,
- libyuv::FOURCC_YUY2
- );
- if (0 != conversionResult) {
- //capDbg(&vcap->param, "Failed to convert capture frame from type FOURCC_YUY2, conversionResult = %d, pBuffer = 0x%08x, BufferLen = %ld.", conversionResult, pBuffer, BufferLen);
- if (NULL != m_i420){
- free(m_i420);
- m_i420 = NULL;
- }
- return S_FALSE;
- }
- char*buffertmp=(char*)malloc(mode_width[vcap->param.cap_mode]*mode_height[vcap->param.cap_mode]*3);
- char*buffer = NULL;
- //是否需要做分辨率转换
- if (used_width == mode_width[vcap->param.cap_mode]){
- conversionResult = libyuv::ConvertFromI420(m_i420,
- stride_y,
- m_i420 + stride_y * mode_height[vcap->param.cap_mode],
- stride_u,
- m_i420 + stride_y * mode_height[vcap->param.cap_mode] + stride_u * ((mode_height[vcap->param.cap_mode] + 1) / 2),
- stride_v,
- (uint8_t*)buffertmp,
- mode_width[vcap->param.cap_mode] * 3,
- mode_width[vcap->param.cap_mode],
- mode_height[vcap->param.cap_mode],
- libyuv::FOURCC_24BG);
- if (conversionResult < 0) {
- //capDbg(&vcap->param, "Failed to convert capture frame from I420 to RGB24, conversionResult = %d.", conversionResult);
- if (NULL != m_i420){
- free(m_i420);
- m_i420 = NULL;
- }
- if (NULL != buffertmp){
- free(buffertmp);
- buffertmp = NULL;
- }
- return S_FALSE;
- }
- }
- else{
- int dest_stride_y = mode_width[vcap->param.cap_mode];
- int dest_stride_u = (mode_width[vcap->param.cap_mode] + 1)/2;
- int dest_stride_v = (mode_width[vcap->param.cap_mode] + 1)/2;
- uint8_t* m_desti420 = (uint8_t*)malloc(I420DataSize(mode_height[vcap->param.cap_mode], dest_stride_y, dest_stride_u, dest_stride_v));
- conversionResult = libyuv::I420Scale(m_i420, used_width,
- m_i420 + used_width * used_height, used_width / 2,
- m_i420 + used_width * used_height * 5 / 4, used_width / 2,
- used_width, used_height,
- m_desti420, mode_width[vcap->param.cap_mode],
- m_desti420 + mode_width[vcap->param.cap_mode] * mode_height[vcap->param.cap_mode], mode_width[vcap->param.cap_mode] / 2,
- m_desti420 + mode_width[vcap->param.cap_mode] * mode_height[vcap->param.cap_mode] * 5 / 4, mode_width[vcap->param.cap_mode] / 2,
- mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode],
- libyuv::kFilterNone);
- if (conversionResult < 0) {
- //capDbg(&vcap->param, "Failed to I420Scale, conversionResult = %d.", conversionResult);
- if (NULL != m_desti420){
- free(m_desti420);
- m_desti420 = NULL;
- }
- if (NULL != buffertmp){
- free(buffertmp);
- buffertmp = NULL;
- }
- if (NULL != m_i420){
- free(m_i420);
- m_i420 = NULL;
- }
- return S_FALSE;
- }
- conversionResult = libyuv::ConvertFromI420(m_desti420,
- dest_stride_y,
- m_desti420 + dest_stride_y * mode_height[vcap->param.cap_mode],
- dest_stride_u,
- m_desti420 + dest_stride_y * mode_height[vcap->param.cap_mode] + dest_stride_u * ((mode_height[vcap->param.cap_mode] + 1) / 2),
- dest_stride_v,
- (uint8_t*)buffertmp,
- mode_width[vcap->param.cap_mode] * 3,
- mode_width[vcap->param.cap_mode],
- mode_height[vcap->param.cap_mode],
- libyuv::FOURCC_24BG);
- if (NULL != m_desti420){
- free(m_desti420);
- m_desti420 = NULL;
- }
- if (conversionResult < 0) {
- //capDbg(&vcap->param, "Failed to convert capture frame from I420 to RGB24, conversionResult = %d.", conversionResult);
- if (NULL != buffertmp){
- free(buffertmp);
- buffertmp = NULL;
- }
- if (NULL != m_i420){
- free(m_i420);
- m_i420 = NULL;
- }
- return S_FALSE;
- }
- }
- buffer = buffertmp;
- if (NULL != m_i420){
- free(m_i420);
- m_i420 = NULL;
- }
- 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] = (unsigned char*)buffer;
- frame.linesize[0] = mode_width[vcap->param.cap_mode]*3;
- frame.format = VIDEO_FORMAT_RGB24;
- vcap->param.on_frame(vcap->param.user_data, &frame);
- }
- if (NULL != buffertmp){
- free(buffertmp);
- buffertmp = NULL;
- }
- return S_OK;
- }
- HRESULT STDMETHODCALLTYPE RvcSampleGrabberCB::BufferCB(
- double SampleTime,
- BYTE *pBuffer,
- long BufferLen)
- {
- if (false== m_vcap->bloged){
- get_output_mediatype(m_vcap);
- m_vcap->bloged = true;
- }
- if ((m_vcap->iout_width > 3 * mode_width[m_vcap->param.cap_mode]) && (m_vcap->iout_height > 3* mode_height[m_vcap->param.cap_mode])) {
- return S_FALSE;
- }
- if (VIDEO_FORMAT_YUY2 == m_vcap->param.cap_frame_format){
- return Handle_YUY2_Frame_CallBack(m_vcap, pBuffer, BufferLen);
- }
- else if(VIDEO_FORMAT_RGB24 == m_vcap->param.cap_frame_format){
- return Handle_BGR_Frame_CallBack(m_vcap, pBuffer, BufferLen);
- }
- else{
- return S_FALSE;
- }
- }
- HRESULT STDMETHODCALLTYPE RvcSampleGrabberCB::QueryInterface(
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
- {
- if (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;
- }
- ULONG STDMETHODCALLTYPE RvcSampleGrabberCB::AddRef( void)
- {
- return 1;
- }
- ULONG STDMETHODCALLTYPE RvcSampleGrabberCB::Release( void)
- {
- delete this;
- return 0;
- }
- static HRESULT STDMETHODCALLTYPE QueryInterface(ISampleGrabberCB * This,
- REFIID riid,
- void** ppvObject)
- {
- if (This == 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;
- int ibitcount = vcap->param.cap_frame_format == VIDEO_FORMAT_RGB24 ? 3 : 2;
- 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;
-
- if (false == vcap->bloged){
- get_output_mediatype(vcap);
- vcap->bloged = true;
- }
- if (BufferLen != oriLen)
- {
- //计算目标图像比例
- int srcH;
- float fDstScale = (float)mode_width[vcap->param.cap_mode]/(float)mode_height[vcap->param.cap_mode];
- float fSrcScale = (float)vcap->iout_width/(float)vcap->iout_height;
- if (fSrcScale != fDstScale)
- {
- //计算偏移量
- int nWidth,nHeight,nOffset=0;
- if (fSrcScale > fDstScale)
- {
- return 0;
- }
- else if (fSrcScale < fDstScale)
- {
- //高度过长
- nWidth = vcap->iout_width;
- nHeight = (int)ceil(vcap->iout_width/fDstScale);
- nOffset = (vcap->iout_height -nHeight)/2*nWidth*3;
- }
- //计算等比例变换需要的SWS
- sws=sws_getContext(nWidth,nHeight,AV_PIX_FMT_BGR24, mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode], AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- av_image_alloc(src_data, src_linesize, vcap->iout_width , vcap->iout_height, AV_PIX_FMT_BGR24, 1);
- memcpy(src_data[0],pBuffer+nOffset,nWidth*nHeight*3); //Y
- srcH = nHeight;
- }
- else
- {
- //计算等比例变换需要的SWS
- sws=sws_getContext(vcap->iout_width, vcap->iout_height,AV_PIX_FMT_BGR24, mode_width[vcap->param.cap_mode], mode_height[vcap->param.cap_mode], AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
- av_image_alloc(src_data, src_linesize, vcap->iout_width, vcap->iout_height, AV_PIX_FMT_BGR24, 1);
- memcpy(src_data[0],pBuffer,BufferLen); //Y
- srcH = vcap->iout_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
- {
- 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] = (unsigned char*)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] = (unsigned char*)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] = (unsigned char*)buffer;
- frame.linesize[0] = linesize;
- frame.format = VIDEO_FORMAT_RGB24;
- vcap->param.on_frame(vcap->param.user_data, &frame);
- }
- }
- free(Buffertmp);
- return S_OK;
- }
- 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->GetEventHandle((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->GetEvent(&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->FreeEventParams(lEventCode, lParam1, lParam2);
- }
- else
- {
- quit = 1;
- }
- }
- CloseHandle(evts[0]);
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////
- int videocap_create(videocap_t *h ,videocap_param *param)
- {
- videocap *vcap;
- //capDbg(param,"videocap_create, fps = %f.", param->fps);
- /* 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],
- AV_PIX_FMT_BGR24,
- mode_width[param->res_mode],
- mode_height[param->res_mode],
- vcap->param.frame_fmt==VIDEO_FORMAT_RGB24 ? AV_PIX_FMT_BGR24 : AV_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);
- }
- vcap->bloged = false;
- vcap->iout_width = mode_width[param->cap_mode];
- vcap->iout_height = mode_height[param->cap_mode];
- *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);
- }
- //100 to real brightness value
- static int transtorealbrightnessvalue(int ibright, int imaxbrightness, int iminbrightness)
- {
- float fvalue = ibright * (imaxbrightness - iminbrightness) / 10;
- int ivalue = fvalue;
- int ilast = ivalue % 10;
- int inum = ivalue / 10;
- if (ilast >= 5) {
- inum++;
- }
- inum += iminbrightness;
- if (inum < iminbrightness) {
- inum = iminbrightness;
- }
- if (inum > imaxbrightness) {
- inum = imaxbrightness;
- }
- return inum;
- }
- //real brightness value to [0-100]
- static int transfromrealbrightnessvalue(int ibright, int imaxbrightness, int iminbrightness)
- {
- int itotal = imaxbrightness - iminbrightness;
- int ivalue = ibright - iminbrightness;
- float fvalue = ivalue * 1000 / itotal;
- ivalue = fvalue;
- int ilast = ivalue % 10;
- int inum = ivalue / 10;
- if (ilast >= 5) {
- inum++;
- }
- return inum;
- }
- int videocap_adj_brightness(videocap_t h, int nValue)
- {
- if (NULL == h) {
- return S_FALSE;
- }
- IAMVideoProcAmp *pProcAmp = 0;
- HRESULT hr = h->sourcefilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
- if(SUCCEEDED(hr))
- {
- long Min, Max, Step, Default, Flags, Val;
- // 亮度.
- if(( nValue >= 0 )&&(nValue <= 100 ))
- {
- hr = pProcAmp->GetRange(VideoProcAmp_Brightness, &Min, &Max, &Step,
- &Default, &Flags);
- if(SUCCEEDED(hr))
- {
- Flags = VideoProcAmp_Flags_Manual;
- hr = pProcAmp->Get(VideoProcAmp_Brightness, &Val, &Flags);
- Val = transtorealbrightnessvalue((int)nValue, (int)Max, (int)Min);
- hr = pProcAmp->Set(VideoProcAmp_Brightness, Val, Flags);
- }
- }
- }
- return hr;
- }
- int videocap_set_autobrightness(videocap_t h)
- {
- if (NULL == h) {
- return S_FALSE;
- }
- IAMVideoProcAmp *pProcAmp = 0;
- HRESULT hr = h->sourcefilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
- if(SUCCEEDED(hr))
- {
- long Min, Max, Step, Default, Flags, Val;
- // 亮度.
- hr = pProcAmp->GetRange(VideoProcAmp_Brightness, &Min, &Max, &Step,
- &Default, &Flags);
- if(SUCCEEDED(hr))
- {
- Flags = VideoProcAmp_Flags_Auto;
- Val = Min + (Max-Min)/2;
- hr = pProcAmp->Set(VideoProcAmp_Brightness, Val, Flags);
- }
- }
- return hr;
- }
- int videocap_get_brightness(videocap_t h,int*nValue)
- {
- if (NULL == h) {
- return S_FALSE;
- }
- IAMVideoProcAmp *pProcAmp = 0;
- HRESULT hr = h->sourcefilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
- if(SUCCEEDED(hr))
- {
- long Min, Max, Step, Default, Flags, Val;
- // 亮度.
- hr = pProcAmp->GetRange(VideoProcAmp_Brightness, &Min, &Max, &Step, &Default, &Flags);
- if(SUCCEEDED(hr))
- {
- hr = pProcAmp->Get(VideoProcAmp_Brightness, &Val, &Flags);
- *nValue = transfromrealbrightnessvalue((int)Val, (int)Max, (int)Min);
- }
- }
- return hr;
- }
- int videocap_start(videocap_t h)
- {
- HRESULT hr = S_OK;
- 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)){
- capDbg(&h->param,"CoCreateInstance failed.");
- goto on_error;
- }
- //else{
- // capDbg(&h->param,"CoCreateInstance success, and fps = %f.", h->param.fps);
- //}
- hr = h->graphbuilder->QueryInterface(
- IID_IMediaControl, (void**)&h->mc);
- if (FAILED(hr)){
- capDbg(&h->param,"QueryInterface failed.");
- goto on_error;
- }
- hr = h->graphbuilder->QueryInterface(
- IID_IMediaEvent, (void**)&h->me);
- if (FAILED(hr)){
- capDbg(&h->param,"QueryInterface IID_IMediaEvent failed.");
- goto on_error;
- }
- #ifdef _DEBUG
- {
- IUnknown *pUnk;
- hr = h->graphbuilder->QueryInterface(
- IID_IUnknown, (void**)&pUnk);
- if (FAILED(hr)){
- goto on_error;
- }
- hr = AddToRot(pUnk, &h->dwROTRegister);
- pUnk->Release();
- 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->AddFilter(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->AddFilter(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->AddFilter(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->AddFilter(h->grabberfilter, L"grabber");
- if (FAILED(hr)){
- goto on_error;
- }
- hr = h->grabberfilter->QueryInterface(
- IID_ISampleGrabber, (void**)&h->grabber);
- if (FAILED(hr)){
- goto on_error;
- }
- {
- int ibitcount = 3;
- 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));
- if (VIDEO_FORMAT_YUY2 == h->param.cap_frame_format){
- ibitcount = 2;
- }
- memset(mt, 0, sizeof(AM_MEDIA_TYPE));
- memset(pvi, 0, sizeof(VIDEOINFOHEADER));
- mt->lSampleSize = width * height * ibitcount;
- mt->majortype = MEDIATYPE_Video;
- mt->subtype = MEDIASUBTYPE_RGB24;
- if (VIDEO_FORMAT_YUY2 == h->param.cap_frame_format){
- mt->subtype = MEDIASUBTYPE_YUY2;
- }
- 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 * ibitcount;
- pvi->bmiHeader.biBitCount = ibitcount*8;
- pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pvi->AvgTimePerFrame = (REFERENCE_TIME)(10000000 / h->param.fps);
- pvi->dwBitRate = (DWORD)(width*height*ibitcount*8*h->param.fps);
- //capDbg(&h->param,"width = %d, height = %d, BitRate = %d, fps = %f.", width, height, pvi->dwBitRate, h->param.fps);
- hr = h->grabber->SetMediaType(mt);
- FreeMediaTypeEx(mt);
- if (FAILED(hr)){
- capDbg(&h->param,"SetMediaType error, err=0x%08x", hr);
- goto on_error;
- }
- }
- h->grabber->SetOneShot(FALSE);
- {
- ISampleGrabberCB *pImpl = new RvcSampleGrabberCB(h);
- if (!pImpl)
- goto on_error;
- // 0: SampleCB
- // 1: BufferCB
- h->grabber->SetCallback( pImpl, 1);////////////////////////
- }
- if (h->param.option & VIDEOCAP_OPT_HOZFLIP) {
- h->horflipfilter = (IBaseFilter*)videohorflip_create_filter();
- if (!h->horflipfilter){
- capDbg(&h->param,"videohorflip_create_filter error");
- goto on_error;
- }
- hr = h->graphbuilder->AddFilter(h->horflipfilter, L"horflip");
- if (FAILED(hr)){
- capDbg(&h->param,"AddFilter error, err=0x%08x", 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)){
- capDbg(&h->param,"CoCreateInstance error, err=0x%08x", hr);
- goto on_error;
- }
- }
- hr = h->graphbuilder->AddFilter(h->renderfilter, L"renderfilter");
- if (FAILED(hr)){
- capDbg(&h->param,"AddFilter error, err=0x%08x", 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)) {
- char strinfo[MAX_PATH] = { 0 };
- _snprintf(strinfo, MAX_PATH, "!(h->param.option & VIDEOCAP_OPT_HOZFLIP) TryConnectFilters failed and lResult = 0x%08x.", hr);
- capDbg(&h->param, strinfo);
- capLogEvent(&h->param, 2, strinfo);
- 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)) {
- char strerror[MAX_PATH] = { 0 };
- _snprintf(strerror, MAX_PATH, "TryConnectFilters failed and lResult = 0x%08x.", hr);
- capDbg(&h->param, strerror);
- capLogEvent(&h->param, 2, strerror);
- goto on_error;
- }
- }
- if (h->param.pre_hwnd) {
- RECT rc;
- hr = h->renderfilter->QueryInterface(
- IID_IVideoWindow, (void**)&h->videowindow);
- if (FAILED(hr)){
- capDbg(&h->param,"renderfilter QueryInterface failed!");
- goto on_error;
- }
- GetClientRect(h->param.pre_hwnd, &rc);
- h->videowindow->put_Owner((OAHWND)h->param.pre_hwnd);
- h->videowindow->put_Visible(OAFALSE);
- h->videowindow->put_Left(0);
- h->videowindow->put_Top(0);
- h->videowindow->put_Height(min(h->param.pre_height, rc.bottom-rc.top));
- h->videowindow->put_Width(min(h->param.pre_width, rc.right - rc.left));
- h->videowindow->put_WindowStyle(
- WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);
- h->videowindow->put_MessageDrain((OAHWND)h->param.pre_hwnd);
- h->videowindow->put_Visible(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->Run();
- if (FAILED(hr)){
- char strmsg[MAX_PATH] = {0};
- _snprintf(strmsg, MAX_PATH, "h->mc->Run() failed and lResult = 0x%08x.", hr);
- capDbg(&h->param, strmsg);
- capLogEvent(&h->param, 2, strmsg);
- 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->Stop();
- h->me->WaitForCompletion(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->put_Visible(
- 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->get_Visible(&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->put_Width(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->put_Height(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->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, vcap->sourcefilter,
- IID_IAMStreamConfig, (void**)&config);
- if (FAILED(hr))
- return hr;
- config->GetNumberOfCapabilities(&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->GetStreamCaps(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 (vcap->param.cap_frame_format == VIDEO_FORMAT_YUY2){
- if (!IsEqualIID(pmtConfig->subtype, MEDIASUBTYPE_YUY2)){
- continue;
- }
- }
- pvi = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
- if (pvi->bmiHeader.biWidth == width && pvi->bmiHeader.biHeight == height)
- {
- pvi->AvgTimePerFrame = (REFERENCE_TIME)(10000000 / vcap->param.fps);
- hr = config->SetFormat(pmtConfig);
- if (SUCCEEDED(hr))
- {
- char *subtype_str=GuidToString(pmtConfig->subtype);
- //char strmsg[MAX_PATH] = {0};
- //_snprintf(strmsg, MAX_PATH,"[{32595559-0000-0010-8000-00AA00389B71->MEDIASUBTYPE_YUY2},{e436eb7d-524f-11ce-9f53-0020af0ba770->MEDIASUBTYPE_RGB24}]match video format is %s, width is %d, height is %d.", subtype_str, pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight);
- //capLogEvent(&vcap->param, 0, strmsg);
- free(subtype_str);
- alreadyset = TRUE;
- }
- else
- {
- alreadyset = FALSE;
- }
- }
- }
- FreeMediaTypeEx(pmtConfig);
- }
- }
- config->Release();
- capturebuilder->Release();
- return hr;
- }
- HRESULT get_output_mediatype(videocap *vcap)
- {
- AM_MEDIA_TYPE mt;
- HRESULT hr;
- VIDEOINFOHEADER *videoHeader = NULL;
- ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
- hr = vcap->grabber->GetConnectedMediaType(&mt);
- if(FAILED(hr))
- {
- capDbg(&vcap->param,"GetConnectedMediaType Failed, hr=0x%08x!",hr);
- return hr;
- }
-
- videoHeader = (VIDEOINFOHEADER*)(mt.pbFormat);
- vcap->iout_width = videoHeader->bmiHeader.biWidth;
- vcap->iout_height = videoHeader->bmiHeader.biHeight;
- if ((mode_width[vcap->param.cap_mode] != videoHeader->bmiHeader.biWidth) || (mode_height[vcap->param.cap_mode] != videoHeader->bmiHeader.biHeight)) {
- char* subtype_str = NULL;
- char strmsg[MAX_PATH * 2] = { 0 };
- subtype_str = GuidToString(mt.subtype);
- _snprintf(strmsg, MAX_PATH * 2, "grabber Format Width=%d, Height=%d, biBitCount=%d, biSizeImage=%d, biCompression=%d, biPlanes=%d, biSize=%d, subtype=%s, newPmt->lSampleSize=%d, newPmt->bFixedSizeSamples=%d, newPmt->bTemporalCompression=%d",
- 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);
- capLogEvent(&vcap->param, 1, strmsg);
- if ((mode_width[vcap->param.cap_mode] != videoHeader->bmiHeader.biWidth) && (mode_height[vcap->param.cap_mode] != videoHeader->bmiHeader.biHeight)) {
- capLogEvent(&vcap->param, 3, strmsg);
- }
- }
-
- return S_OK;
- }
- static void release_all_interfaces(videocap *h)
- {
- if (h->mc) {
- h->mc->Release();
- h->mc = NULL;
- }
- if (h->me) {
- h->me->Release();
- h->me = NULL;
- }
- if (h->videowindow) {
- h->videowindow->put_Owner((OAHWND)NULL);
- h->videowindow->Release();
- h->videowindow = NULL;
- }
- if (h->graphbuilder) {
- RemoveGraphAllFilters(h->graphbuilder);
- h->graphbuilder->Release();
- h->graphbuilder = NULL;
- }
- if (h->sourcefilter) {
- h->sourcefilter->Release();
- h->sourcefilter = NULL;
- }
- if (h->avidecfilter) {
- h->avidecfilter->Release();
- h->avidecfilter = NULL;
- }
- if (h->cpcfilter) {
- h->cpcfilter->Release();
- h->cpcfilter = NULL;
- }
- if (h->grabber) {
- h->grabber->Release();
- h->grabber = NULL;
- }
- if (h->grabberfilter) {
- h->grabberfilter->Release();
- h->grabberfilter = NULL;
- }
- if (h->horflipfilter) {
- h->horflipfilter->Release();
- h->horflipfilter = NULL;
- }
- if (h->renderfilter) {
- h->renderfilter->Release();
- 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->BindToStorage(NULL, NULL,
- IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr)) {
- buf->len = -1; /* failed */
- return hr;
- }
- VariantInit(&name);
- name.vt = VT_BSTR;
- hr = pPropBag->Read(L"FriendlyName", &name, NULL);
- if (FAILED(hr)) {
- pPropBag->Release();
- VariantClear(&name);
- buf->len = -1;
- return hr;
- }
- buf->len = SysStringByteLen(name.bstrVal) + 2;
- if (buf)
- memcpy(buf->buf, name.bstrVal, buf->len);
- pPropBag->Release();
- 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->BindToStorage(NULL, NULL,
- IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr)) {
- buf->len = -1; /* failed */
- return hr;
- }
- VariantInit(&path);
- path.vt = VT_BSTR;
- hr = pPropBag->Read(L"DevicePath", &path, NULL);
- if (FAILED(hr)) {
- pPropBag->Release();
- VariantClear(&path);
- buf->len = -1;
- return hr;
- }
- buf->len = SysStringByteLen(path.bstrVal) + 2;
- if (buf)
- memcpy(buf->buf, path.bstrVal, buf->len);
- pPropBag->Release();
- 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 HRESULT get_device_instanceid_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->BindToStorage(NULL, NULL,
- IID_IPropertyBag, (void**)&pPropBag);
- if (FAILED(hr)) {
- buf->len = -1; /* failed */
- return hr;
- }
- VariantInit(&path);
- path.vt = VT_BSTR;
- hr = pPropBag->Read(L"InstanceId", &path, NULL);
- if (FAILED(hr)) {
- pPropBag->Release();
- VariantClear(&path);
- buf->len = -1;
- return hr;
- }
- buf->len = SysStringByteLen(path.bstrVal) + 2;
- if (buf)
- memcpy(buf->buf, path.bstrVal, buf->len);
- pPropBag->Release();
- VariantClear(&path);
- return S_OK;
- }
- }
- return S_FALSE;
- }
- int videocap_get_device_instanceid(int device_id, WCHAR* buf, int len)
- {
- struct _buf x = { buf, len };
- int dev_id = device_id;
- HRESULT hr = WalkFilterCategory(CLSID_VideoInputDeviceCategory,
- &get_device_instanceid_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->FindInterface( &PIN_CATEGORY_CAPTURE,
- &MEDIATYPE_Video, pSourceFilter, IID_IAMStreamConfig, (void**)&config);
- if (FAILED(hr))
- goto on_error;
- config->GetNumberOfCapabilities( &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->GetStreamCaps(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->Release();
- 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->Release();
- if (pSourceFilter)
- pSourceFilter->Release();
- return error;
- }
- int videocap_get_mode_width(int mode)
- {
- return mode_width[mode];
- }
- int videocap_get_mode_height(int mode)
- {
- return mode_height[mode];
- }
|