📄 dshow.cpp
字号:
static IBaseFilter *FindCaptureDevice( vlc_object_t *p_this, string *p_devicename, list<string> *p_listdevices, vlc_bool_t b_audio ){ IBaseFilter *p_base_filter = NULL; IMoniker *p_moniker = NULL; ULONG i_fetched; HRESULT hr; /* Create the system device enumerator */ ICreateDevEnum *p_dev_enum = NULL; hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&p_dev_enum ); if( FAILED(hr) ) { msg_Err( p_this, "failed to create the device enumerator (0x%lx)", hr); return NULL; } /* Create an enumerator for the video capture devices */ IEnumMoniker *p_class_enum = NULL; if( !b_audio ) hr = p_dev_enum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &p_class_enum, 0 ); else hr = p_dev_enum->CreateClassEnumerator( CLSID_AudioInputDeviceCategory, &p_class_enum, 0 ); p_dev_enum->Release(); if( FAILED(hr) ) { msg_Err( p_this, "failed to create the class enumerator (0x%lx)", hr ); return NULL; } /* If there are no enumerators for the requested type, then * CreateClassEnumerator will succeed, but p_class_enum will be NULL */ if( p_class_enum == NULL ) { msg_Err( p_this, "no capture device was detected" ); return NULL; } /* Enumerate the devices */ /* Note that if the Next() call succeeds but there are no monikers, * it will return S_FALSE (which is not a failure). Therefore, we check * that the return code is S_OK instead of using SUCCEEDED() macro. */ while( p_class_enum->Next( 1, &p_moniker, &i_fetched ) == S_OK ) { /* Getting the property page to get the device name */ IPropertyBag *p_bag; hr = p_moniker->BindToStorage( 0, 0, IID_IPropertyBag, (void **)&p_bag ); if( SUCCEEDED(hr) ) { VARIANT var; var.vt = VT_BSTR; hr = p_bag->Read( L"FriendlyName", &var, NULL ); p_bag->Release(); if( SUCCEEDED(hr) ) { int i_convert = WideCharToMultiByte(CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), NULL, 0, NULL, NULL); char *p_buf = (char *)alloca( i_convert+1 ); p_buf[0] = 0; WideCharToMultiByte( CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), p_buf, i_convert, NULL, NULL ); SysFreeString(var.bstrVal); p_buf[i_convert] = '\0'; if( p_listdevices ) p_listdevices->push_back( p_buf ); if( p_devicename && *p_devicename == string(p_buf) ) { /* Bind Moniker to a filter object */ hr = p_moniker->BindToObject( 0, 0, IID_IBaseFilter, (void **)&p_base_filter ); if( FAILED(hr) ) { msg_Err( p_this, "couldn't bind moniker to filter " "object (0x%lx)", hr ); p_moniker->Release(); p_class_enum->Release(); return NULL; } p_moniker->Release(); p_class_enum->Release(); return p_base_filter; } } } p_moniker->Release(); } p_class_enum->Release(); return NULL;}static size_t EnumDeviceCaps( vlc_object_t *p_this, IBaseFilter *p_filter, int i_fourcc, int i_width, int i_height, int i_channels, int i_samplespersec, int i_bitspersample, AM_MEDIA_TYPE *mt, size_t mt_max ){ IEnumPins *p_enumpins; IPin *p_output_pin; IEnumMediaTypes *p_enummt; size_t mt_count = 0; LONGLONG i_AvgTimePerFrame = 0; float r_fps = var_GetFloat( p_this, "dshow-fps" ); if( r_fps ) i_AvgTimePerFrame = 10000000000LL/(LONGLONG)(r_fps*1000.0f); if( FAILED(p_filter->EnumPins( &p_enumpins )) ) { msg_Dbg( p_this, "EnumDeviceCaps failed: no pin enumeration !"); return 0; } while( S_OK == p_enumpins->Next( 1, &p_output_pin, NULL ) ) { PIN_INFO info; if( S_OK == p_output_pin->QueryPinInfo( &info ) ) { msg_Dbg( p_this, "EnumDeviceCaps: %s pin: %S", info.dir == PINDIR_INPUT ? "input" : "output", info.achName ); if( info.pFilter ) info.pFilter->Release(); } p_output_pin->Release(); } p_enumpins->Reset(); while( !mt_count && p_enumpins->Next( 1, &p_output_pin, NULL ) == S_OK ) { PIN_INFO info; if( S_OK == p_output_pin->QueryPinInfo( &info ) ) { if( info.pFilter ) info.pFilter->Release(); if( info.dir == PINDIR_INPUT ) { p_output_pin->Release(); continue; } msg_Dbg( p_this, "EnumDeviceCaps: trying pin %S", info.achName ); } AM_MEDIA_TYPE *p_mt; /* ** Configure pin with a default compatible media if possible */ IAMStreamConfig *pSC; if( SUCCEEDED(p_output_pin->QueryInterface( IID_IAMStreamConfig, (void **)&pSC )) ) { int piCount, piSize; if( SUCCEEDED(pSC->GetNumberOfCapabilities(&piCount, &piSize)) ) { BYTE *pSCC= (BYTE *)CoTaskMemAlloc(piSize); if( NULL != pSCC ) { int i_priority = -1; for( int i=0; i<piCount; ++i ) { if( SUCCEEDED(pSC->GetStreamCaps(i, &p_mt, pSCC)) ) { int i_current_fourcc = GetFourCCFromMediaType( *p_mt ); int i_current_priority = GetFourCCPriority(i_current_fourcc); if( (i_fourcc && (i_current_fourcc != i_fourcc)) || (i_priority > i_current_priority) ) { // unwanted chroma, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } if( MEDIATYPE_Video == p_mt->majortype && FORMAT_VideoInfo == p_mt->formattype ) { VIDEO_STREAM_CONFIG_CAPS *pVSCC = reinterpret_cast<VIDEO_STREAM_CONFIG_CAPS*>(pSCC); VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(p_mt->pbFormat); if( i_AvgTimePerFrame ) { if( pVSCC->MinFrameInterval > i_AvgTimePerFrame || i_AvgTimePerFrame > pVSCC->MaxFrameInterval ) { // required frame rate not compatible, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } pVih->AvgTimePerFrame = i_AvgTimePerFrame; } if( i_width ) { if( i_width % pVSCC->OutputGranularityX || pVSCC->MinOutputSize.cx > i_width || i_width > pVSCC->MaxOutputSize.cx ) { // required width not compatible, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } pVih->bmiHeader.biWidth = i_width; } if( i_height ) { if( i_height % pVSCC->OutputGranularityY || pVSCC->MinOutputSize.cy > i_height || i_height > pVSCC->MaxOutputSize.cy ) { // required height not compatible, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } pVih->bmiHeader.biHeight = i_height; } // Set the sample size and image size. // (Round the image width up to a DWORD boundary.) p_mt->lSampleSize = pVih->bmiHeader.biSizeImage = ((pVih->bmiHeader.biWidth + 3) & ~3) * pVih->bmiHeader.biHeight * (pVih->bmiHeader.biBitCount>>3); // no cropping, use full video input buffer memset(&(pVih->rcSource), 0, sizeof(RECT)); memset(&(pVih->rcTarget), 0, sizeof(RECT)); // select this format as default if( SUCCEEDED( pSC->SetFormat(p_mt) ) ) { i_priority = i_current_priority; if( i_fourcc ) // no need to check any more media types i = piCount; } } else if( p_mt->majortype == MEDIATYPE_Audio && p_mt->formattype == FORMAT_WaveFormatEx ) { AUDIO_STREAM_CONFIG_CAPS *pASCC = reinterpret_cast<AUDIO_STREAM_CONFIG_CAPS*>(pSCC); WAVEFORMATEX *pWfx = reinterpret_cast<WAVEFORMATEX*>(p_mt->pbFormat); if( i_current_fourcc && (WAVE_FORMAT_PCM == pWfx->wFormatTag) ) { int val = i_channels; if( ! val ) val = 2; if( val % pASCC->ChannelsGranularity || (unsigned int)val < pASCC->MinimumChannels || (unsigned int)val > pASCC->MaximumChannels ) { // required number channels not available, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } pWfx->nChannels = val; val = i_samplespersec; if( ! val ) val = 44100; if( val % pASCC->SampleFrequencyGranularity || (unsigned int)val < pASCC->MinimumSampleFrequency || (unsigned int)val > pASCC->MaximumSampleFrequency ) { // required sampling rate not available, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } pWfx->nSamplesPerSec = val; val = i_bitspersample; if( ! val ) { if( VLC_FOURCC('f', 'l', '3', '2') == i_current_fourcc ) val = 32; else val = 16; } if( val % pASCC->BitsPerSampleGranularity || (unsigned int)val < pASCC->MinimumBitsPerSample || (unsigned int)val > pASCC->MaximumBitsPerSample ) { // required sample size not available, try next media type FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); continue; } pWfx->wBitsPerSample = val; pWfx->nBlockAlign = (pWfx->wBitsPerSample * pWfx->nChannels)/8; pWfx->nAvgBytesPerSec = pWfx->nSamplesPerSec * pWfx->nBlockAlign; // select this format as default if( SUCCEEDED( pSC->SetFormat(p_mt) ) ) { i_priority = i_current_priority; } } } FreeMediaType( *p_mt ); CoTaskMemFree( (PVOID)p_mt ); } } CoTaskMemFree( (LPVOID)pSCC ); if( i_priority >= 0 ) msg_Dbg( p_this, "EnumDeviceCaps: input pin default format configured"); } } pSC->Release(); } /* ** Probe pin for available medias (may be a previously configured one) */ if( FAILED( p_output_pin->EnumMediaTypes( &p_enummt ) ) ) { p_output_pin->Release();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -