add dshow api.
This commit is contained in:
parent
28f2f60532
commit
ce673bf330
@ -119,12 +119,15 @@ QStringList Application::availableSerialPorts() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList Application::availableUsbVideoCameras() const {
|
||||
QStringList ret;
|
||||
QVariantList Application::availableUsbVideoCameras() const {
|
||||
QVariantList ret;
|
||||
DeviceDiscovery d;
|
||||
auto devices = d.devices();
|
||||
auto devices = d.getDevices();
|
||||
for (auto &device : devices) {
|
||||
ret << QString::fromStdString(device);
|
||||
QVariantMap item;
|
||||
item.insert("name", QString::fromStdString(device.friendlyName));
|
||||
item.insert("path", QString::fromStdString(device.alternativeName));
|
||||
ret << item;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
int exec();
|
||||
static Application *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
|
||||
Q_INVOKABLE QStringList availableSerialPorts() const;
|
||||
Q_INVOKABLE QStringList availableUsbVideoCameras() const;
|
||||
Q_INVOKABLE QVariantList availableUsbVideoCameras() const;
|
||||
Q_INVOKABLE bool open(const QString &portName, int baudRate);
|
||||
Q_INVOKABLE bool openUVC(const QString &deviceName);
|
||||
Q_INVOKABLE void close();
|
||||
|
@ -32,7 +32,7 @@ bool VideoPlayer::open(const std::string &deviceName) {
|
||||
#ifdef WIN32
|
||||
constexpr auto format = "dshow";
|
||||
std::ostringstream oss;
|
||||
oss << "video=" << deviceName;
|
||||
oss << "video=@device_pnp_" << deviceName;
|
||||
auto device = oss.str();
|
||||
#else
|
||||
constexpr auto format = "v4l2";
|
||||
@ -41,7 +41,10 @@ bool VideoPlayer::open(const std::string &deviceName) {
|
||||
auto inputFormat = av_find_input_format(format);
|
||||
|
||||
AVDictionary *dictionary = nullptr;
|
||||
// clang-format off
|
||||
// ffplay -f dshow -i video="@device_pnp_\\?\usb#vid_3346&pid_0001&mi_00#6&6ff22b9&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
|
||||
// ffmpeg -f dshow -list_options true -i video="UVC Camera"
|
||||
// clang-format on
|
||||
av_dict_set(&dictionary, "video_size", "800*600", 0);
|
||||
|
||||
int status = avformat_open_input(&m_formatContext, device.c_str(), inputFormat, &dictionary);
|
||||
|
@ -57,6 +57,7 @@ RowLayout {
|
||||
}
|
||||
ComboBox {
|
||||
id: uvcs
|
||||
textRole: "name"
|
||||
enabled: !App.uvcOpened
|
||||
implicitWidth: 150
|
||||
}
|
||||
@ -67,8 +68,7 @@ RowLayout {
|
||||
}
|
||||
Button {
|
||||
text: App.uvcOpened ? "关闭" : "连接"
|
||||
onClicked: App.uvcOpened ? App.closeUVC() : App.openUVC(
|
||||
uvcs.currentText)
|
||||
onClicked: App.uvcOpened ? App.closeUVC() : App.openUVC(uvcs.currentValue.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,6 @@ target_include_directories(Peripheral
|
||||
target_link_libraries(Peripheral
|
||||
PUBLIC Universal
|
||||
PRIVATE Encrypt
|
||||
$<$<PLATFORM_ID:Windows>:Mfreadwrite Mf mfplat mfuuid>
|
||||
$<$<PLATFORM_ID:Windows>:Mfreadwrite Mf mfplat mfuuid strmiids comsuppw>
|
||||
PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort
|
||||
)
|
||||
|
@ -1,13 +1,15 @@
|
||||
#include "DeviceDiscovery.h"
|
||||
#include "BoostLog.h"
|
||||
#include "StringUtility.h"
|
||||
#include <boost/scope/scope_exit.hpp>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#ifdef WIN32
|
||||
#include <comutil.h>
|
||||
#include <dshow.h>
|
||||
#include <mfapi.h>
|
||||
#include <mfcaptureengine.h>
|
||||
#include <strmif.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <linux/videodev2.h>
|
||||
@ -27,6 +29,23 @@ DeviceDiscovery::DeviceDiscovery() {
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
void DeleteMediaType(AM_MEDIA_TYPE *pmt) {
|
||||
if (pmt != nullptr) {
|
||||
if (pmt->cbFormat != 0) {
|
||||
CoTaskMemFree((PVOID)pmt->pbFormat);
|
||||
pmt->cbFormat = 0;
|
||||
pmt->pbFormat = nullptr;
|
||||
}
|
||||
if (pmt->pUnk != nullptr) {
|
||||
// Unecessary because pUnk should not be used, but safest.
|
||||
pmt->pUnk->Release();
|
||||
pmt->pUnk = nullptr;
|
||||
}
|
||||
CoTaskMemFree((PVOID)pmt);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string deviceName(IMFActivate *device) {
|
||||
std::string ret;
|
||||
WCHAR *friendlyName = nullptr;
|
||||
@ -34,7 +53,7 @@ static std::string deviceName(IMFActivate *device) {
|
||||
auto result = device->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &friendlyName, &nameLength);
|
||||
|
||||
if (SUCCEEDED(result)) {
|
||||
ret = Amass::StringUtility::wstringToString(std::wstring(friendlyName, nameLength));
|
||||
ret = _com_util::ConvertBSTRToString(friendlyName);
|
||||
}
|
||||
if (friendlyName != nullptr) {
|
||||
CoTaskMemFree(friendlyName);
|
||||
@ -160,6 +179,110 @@ std::vector<std::string> DeviceDiscovery::devices() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<DeviceDiscovery::Device> DeviceDiscovery::getDevices() {
|
||||
std::vector<Device> devices;
|
||||
ICreateDevEnum *pDevEnum = nullptr;
|
||||
IEnumMoniker *pEnum = nullptr;
|
||||
|
||||
HRESULT hr =
|
||||
CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pDevEnum);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return devices;
|
||||
}
|
||||
|
||||
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
|
||||
if (hr != S_OK) {
|
||||
pDevEnum->Release();
|
||||
return devices;
|
||||
}
|
||||
|
||||
IMoniker *pMoniker = nullptr;
|
||||
while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
|
||||
Device info;
|
||||
GetDeviceNames(pMoniker, info);
|
||||
|
||||
IBaseFilter *pFilter;
|
||||
hr = pMoniker->BindToObject(nullptr, nullptr, IID_IBaseFilter, (void **)&pFilter);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IEnumPins *pEnumPins;
|
||||
hr = pFilter->EnumPins(&pEnumPins);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IPin *pPin;
|
||||
while (pEnumPins->Next(1, &pPin, nullptr) == S_OK) {
|
||||
PIN_DIRECTION pinDir;
|
||||
pPin->QueryDirection(&pinDir);
|
||||
if (pinDir == PINDIR_OUTPUT) {
|
||||
GetSupportedResolutions(pPin, info.resolutions);
|
||||
}
|
||||
pPin->Release();
|
||||
}
|
||||
pEnumPins->Release();
|
||||
}
|
||||
pFilter->Release();
|
||||
}
|
||||
devices.push_back(info);
|
||||
pMoniker->Release();
|
||||
}
|
||||
pEnum->Release();
|
||||
pDevEnum->Release();
|
||||
return devices;
|
||||
}
|
||||
|
||||
bool DeviceDiscovery::SetResolution(const std::string &deviceName, int width, int height) {
|
||||
ICreateDevEnum *pDevEnum = nullptr;
|
||||
IEnumMoniker *pEnum = nullptr;
|
||||
|
||||
HRESULT hr =
|
||||
CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pDevEnum);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
|
||||
if (hr != S_OK) {
|
||||
pDevEnum->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
IMoniker *pMoniker = nullptr;
|
||||
while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
|
||||
IPropertyBag *pPropBag;
|
||||
hr = pMoniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, (void **)&pPropBag);
|
||||
if (SUCCEEDED(hr)) {
|
||||
VARIANT varName;
|
||||
VariantInit(&varName);
|
||||
hr = pPropBag->Read(L"FriendlyName", &varName, nullptr);
|
||||
if (SUCCEEDED(hr)) {
|
||||
std::string currentName = _com_util::ConvertBSTRToString(varName.bstrVal);
|
||||
if (currentName == deviceName) {
|
||||
IBaseFilter *pFilter;
|
||||
hr = pMoniker->BindToObject(nullptr, nullptr, IID_IBaseFilter, (void **)&pFilter);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SetPinResolution(pFilter, width, height)) {
|
||||
pFilter->Release();
|
||||
VariantClear(&varName);
|
||||
pPropBag->Release();
|
||||
pMoniker->Release();
|
||||
pEnum->Release();
|
||||
pDevEnum->Release();
|
||||
return true;
|
||||
}
|
||||
pFilter->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
VariantClear(&varName);
|
||||
pPropBag->Release();
|
||||
}
|
||||
pMoniker->Release();
|
||||
}
|
||||
pEnum->Release();
|
||||
pDevEnum->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
DeviceDiscovery::Resolutions DeviceDiscovery::deviceResolutions(const std::shared_ptr<Device> &source) {
|
||||
DeviceDiscovery::Resolutions ret;
|
||||
HRESULT result = S_OK;
|
||||
@ -182,6 +305,89 @@ DeviceDiscovery::Resolutions DeviceDiscovery::deviceResolutions(const std::share
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DeviceDiscovery::GetDeviceNames(IMoniker *pMoniker, Device &info) {
|
||||
IPropertyBag *pPropBag;
|
||||
HRESULT hr = pMoniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, (void **)&pPropBag);
|
||||
if (SUCCEEDED(hr)) {
|
||||
VARIANT varName;
|
||||
VariantInit(&varName);
|
||||
hr = pPropBag->Read(L"FriendlyName", &varName, nullptr);
|
||||
if (SUCCEEDED(hr)) {
|
||||
|
||||
info.friendlyName = _com_util::ConvertBSTRToString(varName.bstrVal);
|
||||
}
|
||||
VariantClear(&varName);
|
||||
|
||||
hr = pPropBag->Read(L"DevicePath", &varName, nullptr);
|
||||
if (SUCCEEDED(hr)) {
|
||||
info.alternativeName = _com_util::ConvertBSTRToString(varName.bstrVal);
|
||||
}
|
||||
VariantClear(&varName);
|
||||
|
||||
pPropBag->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceDiscovery::GetSupportedResolutions(IPin *pPin, std::vector<std::pair<int, int>> &resolutions) {
|
||||
IEnumMediaTypes *pEnumMediaTypes = nullptr;
|
||||
HRESULT hr = pPin->EnumMediaTypes(&pEnumMediaTypes);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AM_MEDIA_TYPE *pMediaType = nullptr;
|
||||
while (pEnumMediaTypes->Next(1, &pMediaType, nullptr) == S_OK) {
|
||||
if (pMediaType->formattype == FORMAT_VideoInfo) {
|
||||
VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER *>(pMediaType->pbFormat);
|
||||
int width = pVih->bmiHeader.biWidth;
|
||||
int height = pVih->bmiHeader.biHeight;
|
||||
resolutions.emplace_back(width, height);
|
||||
}
|
||||
DeleteMediaType(pMediaType);
|
||||
}
|
||||
pEnumMediaTypes->Release();
|
||||
}
|
||||
|
||||
bool DeviceDiscovery::SetPinResolution(IBaseFilter *pFilter, int width, int height) {
|
||||
IEnumPins *pEnumPins;
|
||||
HRESULT hr = pFilter->EnumPins(&pEnumPins);
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IPin *pPin;
|
||||
bool success = false;
|
||||
while (pEnumPins->Next(1, &pPin, nullptr) == S_OK) {
|
||||
PIN_DIRECTION pinDir;
|
||||
pPin->QueryDirection(&pinDir);
|
||||
if (pinDir == PINDIR_OUTPUT) {
|
||||
IEnumMediaTypes *pEnumMediaTypes = nullptr;
|
||||
hr = pPin->EnumMediaTypes(&pEnumMediaTypes);
|
||||
if (SUCCEEDED(hr)) {
|
||||
AM_MEDIA_TYPE *pMediaType = nullptr;
|
||||
while (pEnumMediaTypes->Next(1, &pMediaType, nullptr) == S_OK) {
|
||||
if (pMediaType->formattype == FORMAT_VideoInfo) {
|
||||
VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER *>(pMediaType->pbFormat);
|
||||
if (pVih->bmiHeader.biWidth == width && pVih->bmiHeader.biHeight == height) {
|
||||
hr = pPin->QueryAccept(pMediaType);
|
||||
if (hr == S_OK) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
DeleteMediaType(pMediaType);
|
||||
if (success) break;
|
||||
}
|
||||
pEnumMediaTypes->Release();
|
||||
}
|
||||
}
|
||||
pPin->Release();
|
||||
if (success) break;
|
||||
}
|
||||
pEnumPins->Release();
|
||||
return success;
|
||||
}
|
||||
|
||||
DeviceDiscovery::Device::Device(IMFMediaSource *source) : source(source) {
|
||||
source->AddRef();
|
||||
auto result = MFCreateSourceReaderFromMediaSource(source, nullptr, &reader);
|
||||
|
@ -8,6 +8,9 @@
|
||||
#ifdef WIN32
|
||||
#include <mfidl.h>
|
||||
#include <mfreadwrite.h>
|
||||
|
||||
class IPin;
|
||||
class IBaseFilter;
|
||||
#endif
|
||||
|
||||
class DeviceDiscovery {
|
||||
@ -15,25 +18,34 @@ class DeviceDiscovery {
|
||||
|
||||
public:
|
||||
constexpr static auto DeviceName = "UVC Camera";
|
||||
using Resolution = std::pair<int32_t, int32_t>;
|
||||
using Resolutions = std::vector<Resolution>;
|
||||
struct Device {
|
||||
Device() = default;
|
||||
std::string friendlyName;
|
||||
std::string alternativeName;
|
||||
Resolutions resolutions;
|
||||
~Device();
|
||||
#ifdef WIN32
|
||||
Device(IMFMediaSource *source);
|
||||
IMFMediaSource *source = nullptr;
|
||||
IMFSourceReader *reader = nullptr;
|
||||
#else
|
||||
std::string name;
|
||||
#endif
|
||||
};
|
||||
|
||||
using Resolution = std::pair<int32_t, int32_t>;
|
||||
using Resolutions = std::vector<Resolution>;
|
||||
DeviceDiscovery();
|
||||
std::shared_ptr<Device> find(const std::string &deviceName, std::error_code &error);
|
||||
void enterOtaMode(const std::shared_ptr<Device> &device, std::error_code &error);
|
||||
std::vector<std::string> devices();
|
||||
std::vector<Device> getDevices();
|
||||
bool SetResolution(const std::string &deviceName, int width, int height);
|
||||
|
||||
protected:
|
||||
Resolutions deviceResolutions(const std::shared_ptr<Device> &source);
|
||||
#ifdef WIN32
|
||||
void GetDeviceNames(IMoniker *pMoniker, Device &info);
|
||||
void GetSupportedResolutions(IPin *pPin, std::vector<std::pair<int, int>> &resolutions);
|
||||
bool SetPinResolution(IBaseFilter *pFilter, int width, int height);
|
||||
#endif
|
||||
};
|
||||
#endif // __DEVICEDISCOVERY_H__
|
||||
|
Loading…
Reference in New Issue
Block a user