官方文档:https://docs.microsoft.com/zh-cn/windows/win32/directshow/directshow
创建CLR类库项目(CSharpDirectShow),编写托管的DirectShow类库,右键项目属性–>链接器–> 输入–>附加依赖项;添加静态库文件Strmiids.lib和Quartz.lib;
定义头文件CSharpDirectShow.h,包含头文件dshow.h,定义如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #pragma once
#include <dshow.h>
using namespace System; using namespace System::Runtime::InteropServices;
public ref class DirectShow { public: static Boolean ComInit(); static void ComUinit(); static Int32 GetVideoInputDevices([Out]array<VideoInputDsDevice^>^% devices); static Int32 GetAudioInputDevices([Out]array<AudioInputDsDevice^>^% device); };
|
其中,初始化COM库只能在STA线程调用,控制台程序直接调用会返回失败,在Winform和WPF等应用程序应该在第一次使用时初始化COM库;
当前线程初始化COM库和关闭COM库:
1 2 3 4 5 6 7 8 9 10
| Boolean DirectShow::ComInit() { HRESULT hr = CoInitialize(NULL); return hr == S_OK || hr == S_FALSE; }
void DirectShow::ComUinit() { CoUninitialize(); }
|
一、枚举视频输入设备,参考:https://docs.microsoft.com/zh-cn/windows/win32/directshow/selecting-a-capture-device
1、创建视频输入设备的枚举器IEnumMoniker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| HRESULT DirectShow::EnumerateDevices(REFGUID category, IEnumMoniker** ppEnum) { ICreateDevEnum* pDevEnum; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
if (SUCCEEDED(hr)) { hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
if (hr == S_FALSE) hr = VFW_E_NOT_FOUND;
pDevEnum->Release(); } return hr; }
Int32 DirectShow::GetVideoInputDevices([Out]array<VideoInputDsDevice^>^% devices) { devices = nullptr;
IEnumMoniker* pEnum; HRESULT hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);
if (FAILED(hr)) return hr;
hr = EnumerateVideoInputDevices(pEnum, devices); pEnum->Release(); return hr; }
|
2、调用IEnumMoniker::Next()方法枚举设备,调用IPropertyBag::Read方法读取设备属性,以获取设备的友好名称和设备标识字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| HRESULT DirectShow::EnumerateVideoInputDevices(IEnumMoniker* pEnum, [Out]array<VideoInputDsDevice^>^% devices) { HRESULT hr = S_FALSE; devices = nullptr; List<VideoInputDsDevice^>^ list = gcnew List<VideoInputDsDevice^>();
IMoniker* pMoniker; while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { IPropertyBag* pPropBag; hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag)); if (FAILED(hr)) { pMoniker->Release(); continue; }
VideoInputDsDevice^ device = gcnew VideoInputDsDevice();
VARIANT var; VariantInit(&var);
hr = pPropBag->Read(L"FriendlyName", &var, 0);
if (FAILED(hr)) hr = pPropBag->Read(L"Description", &var, 0);
if (SUCCEEDED(hr)) { device->FriendlyName = System::String(var.bstrVal).ToString(); VariantClear(&var); }
LPOLESTR pOleDisplayName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(MAX_MONIKER_NAME_LENGTH * 2)); hr = pMoniker->GetDisplayName(NULL, NULL, &pOleDisplayName);
if (SUCCEEDED(hr)) { device->MonikerName = System::String(pOleDisplayName).ToString(); array<VideoParams^>^ params; hr = EnumerateVideoParams(pMoniker, params); if (SUCCEEDED(hr)) device->Params = params; }
CoTaskMemFree(pOleDisplayName);
list->Add(device); pPropBag->Release(); pMoniker->Release(); }
devices = list->ToArray(); return S_OK; }
|
3、枚举视频输入设备的采集参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| HRESULT DirectShow::EnumerateVideoParams(IMoniker* pMoniker, [Out]array<VideoParams^>^% params) { params = nullptr; IBaseFilter* pFilter; HRESULT hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter);
if (FAILED(hr)) return hr;
IEnumPins* pinEnum; hr = pFilter->EnumPins(&pinEnum);
if (FAILED(hr)) { pFilter->Release(); return hr; }
List<VideoParams^>^ list = gcnew List<VideoParams^>(); IPin* pPins; while (pinEnum->Next(1, &pPins, NULL) == S_OK) { PIN_INFO pinInfo; hr = pPins->QueryPinInfo(&pinInfo);
if (FAILED(hr) || pinInfo.dir != PINDIR_OUTPUT) { pPins->Release(); continue; }
IEnumMediaTypes* mtEnum; hr = pPins->EnumMediaTypes(&mtEnum);
if (FAILED(hr)) { pPins->Release(); continue; }
AM_MEDIA_TYPE* mt; while (mtEnum->Next(1, &mt, NULL) == S_OK) { VideoParams^ param = nullptr; if (mt->formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER* pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt->pbFormat); param = gcnew VideoParams(); param->FrameWidth = pVih->bmiHeader.biWidth; param->FrameHeight = pVih->bmiHeader.biHeight; param->AverageFrameRate = pVih->AvgTimePerFrame == 0 ? 0 : 10000000 / pVih->AvgTimePerFrame; } else if (mt->formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2* pVih = reinterpret_cast<VIDEOINFOHEADER2*>(mt->pbFormat); param = gcnew VideoParams(); param->FrameWidth = pVih->bmiHeader.biWidth; param->FrameHeight = pVih->bmiHeader.biHeight; param->AverageFrameRate = pVih->AvgTimePerFrame == 0 ? 0 : 10000000 / pVih->AvgTimePerFrame; }
if (param && param->AverageFrameRate > 1) { Boolean isExit = false; for each (VideoParams ^ item in list) { if (item->FrameWidth == param->FrameWidth && item->FrameHeight == param->FrameHeight && item->AverageFrameRate == param->AverageFrameRate) { isExit = true; break; } } if (!isExit) list->Add(param); } } pPins->Release(); }
pFilter->Release();
params = list->ToArray(); return S_OK; }
|
调用代码及结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var ret = DirectShow.GetVideoInputDevices (out VideoInputDsDevice[] videoInputDevices);
if (ret == 0) { Console.WriteLine ("视频输入设备:");
foreach (var videoInputDevice in videoInputDevices) { Console.WriteLine ($"{videoInputDevice.FriendlyName}\t{videoInputDevice.MonikerName}");
if (videoInputDevice.Params.Length > 0) { Console.WriteLine ("像素宽度\t像素高度\t1秒平均帧数");
foreach (var param in videoInputDevice.Params) { Console.WriteLine ($"{param.FrameWidth}\t{param.FrameHeight}\t{param.AverageFrameRate}"); } }
Console.WriteLine (); } }
|
二、枚举音频输入设备,参考https://docs.microsoft.com/zh-cn/windows/win32/directshow/selecting-a-capture-device ,过程和视频一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ret = DirectShow.GetAudioInputDevices (out AudioInputDsDevice[] audioInputDevices);
if (ret == 0) { Console.WriteLine ("音频输入设备:");
foreach (var audioInputDevice in audioInputDevices) { Console.WriteLine ($"{audioInputDevice.FriendlyName}\t{audioInputDevice.MonikerName}");
if (audioInputDevice.Params.Length > 0) { Console.WriteLine ("音频格式\t通道数\t采样速率\t块对齐\t位数");
foreach (var param in audioInputDevice.Params) { Console.WriteLine ($"{param.Format}\t{param.Channels}\t{param.SampleRate}\t{param.BlockAlign}\t{param.BitsPerSample}"); } }
Console.WriteLine (); } }
|
官方文档:https://docs.microsoft.com/zh-cn/windows/win32/directshow/directshow
参考链接:https://www.cnblogs.com/pumbaa/p/14255725.html
参考代码:https://github.com/LowPlayer/CameraCapture