add some log

This commit is contained in:
kalman 2018-05-05 20:52:36 +08:00
parent 8d017f5e2d
commit ff33770ca4

View File

@ -49,9 +49,10 @@
MYNTEYE_BEGIN_NAMESPACE MYNTEYE_BEGIN_NAMESPACE
namespace uvc { namespace uvc
{
const std::map<uint32_t, uint32_t> fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */ const std::map<uint32_t, uint32_t> fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */
#define LOG_ERROR(severity, str) \ #define LOG_ERROR(severity, str) \
do { \ do { \
@ -82,35 +83,48 @@ struct throw_error {
template<class T> class com_ptr template<class T> class com_ptr
{ {
T * p; T * p;
void ref(T * new_p) void ref(T * new_p) {
{
if(p == new_p) return; if(p == new_p) return;
unref(); unref();
p = new_p; p = new_p;
if(p) p->AddRef(); if(p) p->AddRef();
} }
void unref() void unref() {
{ if(p) {
if(p)
{
p->Release(); p->Release();
p = nullptr; p = nullptr;
} }
} }
public: public:
com_ptr() : p() {} com_ptr() : p() {}
com_ptr(T * p) : com_ptr() { ref(p); } com_ptr(T * p) : com_ptr() {
ref(p);
}
com_ptr(const com_ptr & r) : com_ptr(r.p) {} com_ptr(const com_ptr & r) : com_ptr(r.p) {}
~com_ptr() { unref(); } ~com_ptr() {
unref();
}
operator T * () const { return p; } operator T * () const {
T & operator * () const { return *p; } return p;
T * operator -> () const { return p; } }
T & operator * () const {
return *p;
}
T * operator -> () const {
return p;
}
T ** operator & () { unref(); return &p; } T ** operator & () {
com_ptr & operator = (const com_ptr & r) { ref(r.p); return *this; } unref();
}; return &p;
}
com_ptr & operator = (const com_ptr & r) {
ref(r.p);
return *this;
}
};
static std::string win_to_utf(const WCHAR * s) static std::string win_to_utf(const WCHAR * s)
{ {
@ -120,120 +134,105 @@ static std::string win_to_utf(const WCHAR * s)
len = WideCharToMultiByte(CP_UTF8, 0, s, -1, &buffer[0], (int)buffer.size()+1, NULL, NULL); len = WideCharToMultiByte(CP_UTF8, 0, s, -1, &buffer[0], (int)buffer.size()+1, NULL, NULL);
if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError();
return buffer; return buffer;
} }
static void check(const char *call, HRESULT hr) { static void check(const char *call, HRESULT hr)
{
if (FAILED(hr)) { if (FAILED(hr)) {
std::cout << call << "(...) returned 0x" << std::hex << (uint32_t)hr << std::endl;
throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr;
} }
std::cout << call << " SUCCESSED " << std::endl;
} }
std::vector<std::string> tokenize(std::string string, char separator) std::vector<std::string> tokenize(std::string string, char separator)
{ {
std::vector<std::string> tokens; std::vector<std::string> tokens;
std::string::size_type i1 = 0; std::string::size_type i1 = 0;
while(true) while(true) {
{ auto i2 = string.find(separator, i1);
auto i2 = string.find(separator, i1); if(i2 == std::string::npos) {
if(i2 == std::string::npos) tokens.push_back(string.substr(i1));
{ return tokens;
tokens.push_back(string.substr(i1));
return tokens;
}
tokens.push_back(string.substr(i1, i2-i1));
i1 = i2+1;
} }
tokens.push_back(string.substr(i1, i2-i1));
i1 = i2+1;
}
} }
bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & path) bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & path)
{ {
auto name = path; auto name = path;
std::transform(begin(name), end(name), begin(name), ::tolower); std::transform(begin(name), end(name), begin(name), ::tolower);
auto tokens = tokenize(name, '#'); auto tokens = tokenize(name, '#');
if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device
if(tokens.size() < 3) if(tokens.size() < 3) {
{ LOG_ERROR(WARNING,"malformed usb device path: " << name);
//LOG_ERROR("malformed usb device path: " + name); return false;
return false; }
}
auto ids = tokenize(tokens[1], '&'); auto ids = tokenize(tokens[1], '&');
if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) {
{ LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]);
//LOG_ERROR("malformed vid string: " + tokens[1]); return false;
return false; }
}
if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) {
{ LOG_ERROR(WARNING,"malformed pid string: " << tokens[1]);
//LOG_ERROR("malformed pid string: " + tokens[1]); return false;
return false; }
}
if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) {
{ LOG_ERROR(WARNING,"malformed mi string: " << tokens[1]);
//LOG_ERROR("malformed mi string: " + tokens[1]); return false;
return false; }
}
ids = tokenize(tokens[2], '&'); ids = tokenize(tokens[2], '&');
if(ids.size() < 2) if(ids.size() < 2) {
{ LOG_ERROR(WARNING,"malformed id string: " << tokens[2]);
//LOG_ERROR("malformed id string: " + tokens[2]); return false;
return false; }
} unique_id = ids[1];
unique_id = ids[1]; return true;
return true;
} }
bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & device_id) bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & device_id)
{ {
auto name = device_id; auto name = device_id;
std::transform(begin(name), end(name), begin(name), ::tolower); std::transform(begin(name), end(name), begin(name), ::tolower);
auto tokens = tokenize(name, '\\'); auto tokens = tokenize(name, '\\');
if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device
auto ids = tokenize(tokens[1], '&'); auto ids = tokenize(tokens[1], '&');
if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) {
{ LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]);
//LOG_ERROR("malformed vid string: " + tokens[1]); return false;
return false; }
}
if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid)) if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid)) {
{ LOG_ERROR(WARNING,"malformed pid string: " << tokens[1]);
//LOG_ERROR("malformed pid string: " + tokens[1]); return false;
return false; }
}
if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi)) if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi)) {
{ LOG_ERROR(WARNING,"malformed mi string: " << tokens[1]);
//LOG_ERROR("malformed mi string: " + tokens[1]); return false;
return false; }
}
ids = tokenize(tokens[2], '&'); ids = tokenize(tokens[2], '&');
if (ids.size() < 2) if (ids.size() < 2) {
{ LOG_ERROR(WARNING,"malformed id string: " + tokens[2]);
//LOG_ERROR("malformed id string: " + tokens[2]); return false;
return false; }
} unique_id = ids[1];
unique_id = ids[1]; return true;
return true;
} }
struct context struct context {
{ context() {
context()
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET); MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
} }
~context() ~context() {
{
MFShutdown(); MFShutdown();
CoUninitialize(); CoUninitialize();
} }
@ -247,22 +246,24 @@ class reader_callback : public IMFSourceReaderCallback
public: public:
reader_callback(std::weak_ptr<device> owner) : owner(owner), ref_count() {} reader_callback(std::weak_ptr<device> owner) : owner(owner), ref_count() {}
bool is_streaming() const { return streaming; } bool is_streaming() const {
void on_start() { streaming = true; } return streaming;
}
void on_start() {
streaming = true;
}
#pragma warning( push ) #pragma warning( push )
#pragma warning( disable: 4838 ) #pragma warning( disable: 4838 )
// Implement IUnknown // Implement IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override {
{
static const QITAB table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}}; static const QITAB table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}};
return QISearch(this, table, riid, ppvObject); return QISearch(this, table, riid, ppvObject);
} }
#pragma warning( pop ) #pragma warning( pop )
ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&ref_count); } ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&ref_count); }
ULONG STDMETHODCALLTYPE Release() override ULONG STDMETHODCALLTYPE Release() override {
{
ULONG count = InterlockedDecrement(&ref_count); ULONG count = InterlockedDecrement(&ref_count);
if(count == 0) delete this; if(count == 0) delete this;
return count; return count;
@ -289,11 +290,12 @@ struct device {
com_ptr<IMFSourceReader> mf_source_reader; com_ptr<IMFSourceReader> mf_source_reader;
video_channel_callback callback = nullptr; video_channel_callback callback = nullptr;
device(std::shared_ptr<context> parent, int vid, int pid, std::string unique_id, std::string name) : parent(move(parent)), vid(vid), pid(pid), name(name) device(std::shared_ptr<context> parent, int vid, int pid, std::string unique_id, std::string name) : parent(move(parent)), vid(vid), pid(pid), unique_id(move(unique_id)), name(name)
{ {}
}
~device() { stop_streaming(); } ~device() {
stop_streaming();
}
IKsControl * get_ks_control(const uvc::xu & xu) { IKsControl * get_ks_control(const uvc::xu & xu) {
@ -308,7 +310,6 @@ struct device {
GUID node_type; GUID node_type;
check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type)); check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type));
std::cout << "node_type" << node_type.Data1 << "," << node_type.Data2 << "," <<node_type.Data3 << "," << node_type.Data4 << "," <<std::endl;
//const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0x6BDD1FC6, 0X810F, 0x11D0, {0xBE, 0xC7 ,0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F}}; //const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0x6BDD1FC6, 0X810F, 0x11D0, {0xBE, 0xC7 ,0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F}};
//if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node; //if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node;
@ -320,23 +321,19 @@ struct device {
VLOG(2) << "Obtained KS control node" << xu.node; VLOG(2) << "Obtained KS control node" << xu.node;
return ks_controls[xu.node] = ks_control; return ks_controls[xu.node] = ks_control;
} }
void start_streaming() void start_streaming() {
{ if(mf_source_reader) {
if(mf_source_reader)
{
reader_callback->on_start(); reader_callback->on_start();
check("IMFSourceReader::ReadSample", mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL)); check("IMFSourceReader::ReadSample", mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL));
} }
} }
void stop_streaming() void stop_streaming() {
{
if(mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM); if(mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
while(true) while(true) {
{ bool is_streaming = reader_callback->is_streaming();
bool is_streaming = reader_callback->is_streaming();
if(is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10)); if(is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10));
else break; else break;
} }
@ -345,82 +342,80 @@ struct device {
am_camera_control = nullptr; am_camera_control = nullptr;
am_video_proc_amp = nullptr; am_video_proc_amp = nullptr;
ks_controls.clear(); ks_controls.clear();
if(mf_media_source) if(mf_media_source) {
{
mf_media_source = nullptr; mf_media_source = nullptr;
check("IMFActivate::ShutdownObject", mf_activate->ShutdownObject()); check("IMFActivate::ShutdownObject", mf_activate->ShutdownObject());
} }
callback = {}; callback = {};
} }
com_ptr<IMFMediaSource> get_media_source() com_ptr<IMFMediaSource> get_media_source() {
{ if(!mf_media_source) {
if(!mf_media_source)
{
check("IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (void **)&mf_media_source)); check("IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (void **)&mf_media_source));
if (mf_media_source) if (mf_media_source) {
{
check("IMFMediaSource::QueryInterface", mf_media_source->QueryInterface(__uuidof(IAMCameraControl), (void **)&am_camera_control)); check("IMFMediaSource::QueryInterface", mf_media_source->QueryInterface(__uuidof(IAMCameraControl), (void **)&am_camera_control));
if (SUCCEEDED(mf_media_source->QueryInterface(__uuidof(IAMVideoProcAmp), (void **)&am_video_proc_amp))); if (SUCCEEDED(mf_media_source->QueryInterface(__uuidof(IAMVideoProcAmp), (void **)&am_video_proc_amp)));
} } else throw_error() << "Invalid media source";
else throw_error() << "Invalid media source";
} }
return mf_media_source; return mf_media_source;
} }
}; };
HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample)
{ {
if(auto owner_ptr = owner.lock()) if(auto owner_ptr = owner.lock()) {
{ if(sample) {
if(sample)
{
std::cout << "sample is not null" << std::endl;
com_ptr<IMFMediaBuffer> buffer = NULL; com_ptr<IMFMediaBuffer> buffer = NULL;
if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) {
{ BYTE * byte_buffer;
std::cout << "SUCCEEDED(sample->GetBufferByIndex(0, &buffer))" << std::endl; DWORD max_length, current_length;
BYTE * byte_buffer; DWORD max_length, current_length; if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, &current_length))) {
if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, &current_length))) auto continuation = [buffer, this]() {
{
auto continuation = [buffer, this]()
{
buffer->Unlock(); buffer->Unlock();
}; };
owner_ptr->callback(byte_buffer); owner_ptr->callback(byte_buffer);
std::cout << "owner_ptr->callback(byte_buffer);" << std::endl;
} }
} }
} }
if (auto owner_ptr_new = owner.lock()) if (auto owner_ptr_new = owner.lock()) {
{
auto hr = owner_ptr_new->mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL); auto hr = owner_ptr_new->mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL);
switch (hr) switch (hr) {
{ case S_OK:
case S_OK: break; break;
case MF_E_INVALIDREQUEST: LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST"); break; case MF_E_INVALIDREQUEST:
case MF_E_INVALIDSTREAMNUMBER: LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER"); break; LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST");
case MF_E_NOTACCEPTING: LOG_ERROR(WARNING,"ReadSample returned MF_E_NOTACCEPTING"); break; break;
case E_INVALIDARG: LOG_ERROR(WARNING,"ReadSample returned E_INVALIDARG"); break; case MF_E_INVALIDSTREAMNUMBER:
case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: LOG_ERROR(WARNING,"ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"); break; LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER");
default: LOG_ERROR(WARNING,"ReadSample returned HRESULT " << std::hex << (uint32_t)hr); break; break;
case MF_E_NOTACCEPTING:
LOG_ERROR(WARNING,"ReadSample returned MF_E_NOTACCEPTING");
break;
case E_INVALIDARG:
LOG_ERROR(WARNING,"ReadSample returned E_INVALIDARG");
break;
case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED:
LOG_ERROR(WARNING,"ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED");
break;
default:
LOG_ERROR(WARNING,"ReadSample returned HRESULT " << std::hex << (uint32_t)hr);
break;
} }
if (hr != S_OK) streaming = false; if (hr != S_OK) streaming = false;
} }
} }
return S_OK; return S_OK;
} }
std::shared_ptr<context> create_context() { std::shared_ptr<context> create_context()
{
return std::make_shared<context>(); return std::make_shared<context>();
} }
std::vector<std::shared_ptr<device>> query_devices( std::vector<std::shared_ptr<device>> query_devices(std::shared_ptr<context> context)
std::shared_ptr<context> context) { {
IMFAttributes *pAttributes = NULL; IMFAttributes *pAttributes = NULL;
check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1));
check("IMFAttributes::SetGUID",pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); check("IMFAttributes::SetGUID",pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID));
@ -429,7 +424,7 @@ std::vector<std::shared_ptr<device>> query_devices(
UINT32 numDevices; UINT32 numDevices;
check("MFEnumDeviceSources",MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices)); check("MFEnumDeviceSources",MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices));
std::vector<std::shared_ptr<device>> devices; std::vector<std::shared_ptr<device>> devices;
for (UINT32 i = 0; i < numDevices; ++i) { for (UINT32 i = 0; i < numDevices; ++i) {
com_ptr<IMFActivate> pDevice; com_ptr<IMFActivate> pDevice;
*&pDevice = ppDevices[i]; *&pDevice = ppDevices[i];
@ -439,8 +434,8 @@ std::vector<std::shared_ptr<device>> query_devices(
UINT32 length; UINT32 length;
pDevice->GetAllocatedString( pDevice->GetAllocatedString(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wchar_dev_name, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wchar_dev_name,
&length); &length);
auto dev_name = win_to_utf(wchar_dev_name); auto dev_name = win_to_utf(wchar_dev_name);
CoTaskMemFree(wchar_dev_name); CoTaskMemFree(wchar_dev_name);
@ -448,18 +443,17 @@ std::vector<std::shared_ptr<device>> query_devices(
auto name = win_to_utf(wchar_name); // Device description name auto name = win_to_utf(wchar_name); // Device description name
CoTaskMemFree(wchar_name); CoTaskMemFree(wchar_name);
int vid, pid, mi; std::string unique_id; int vid, pid, mi;
std::string unique_id;
if (!parse_usb_path(vid, pid, mi, unique_id, dev_name)) continue; if (!parse_usb_path(vid, pid, mi, unique_id, dev_name)) continue;
std::shared_ptr<device> dev; std::shared_ptr<device> dev;
for(auto & d : devices) for(auto & d : devices) {
{
if(d->vid == vid && d->pid == pid && d->unique_id == unique_id) if(d->vid == vid && d->pid == pid && d->unique_id == unique_id)
dev = d; dev = d;
} }
if(!dev) if(!dev) {
{
try { try {
dev = std::make_shared<device>(context, vid, pid, unique_id, name); dev = std::make_shared<device>(context, vid, pid, unique_id, name);
devices.push_back(dev); devices.push_back(dev);
@ -470,33 +464,38 @@ std::vector<std::shared_ptr<device>> query_devices(
} }
dev->reader_callback = new reader_callback(dev); dev->reader_callback = new reader_callback(dev);
dev->mf_activate = pDevice; dev->mf_activate = pDevice;
dev->vid = vid; dev->vid = vid;
dev->pid = pid; dev->pid = pid;
} }
CoTaskMemFree(ppDevices); CoTaskMemFree(ppDevices);
return devices; return devices;
} }
int get_vendor_id(const device &device) { int get_vendor_id(const device &device)
{
return device.vid; return device.vid;
} }
int get_product_id(const device &device) { int get_product_id(const device &device)
{
return device.pid; return device.pid;
} }
std::string get_name(const device &device) { std::string get_name(const device &device)
{
return device.name; return device.name;
} }
std::string get_video_name(const device &device) { std::string get_video_name(const device &device)
{
return device.name; return device.name;
} }
static long get_cid(Option option) { static long get_cid(Option option)
{
switch (option) { switch (option) {
case Option::GAIN: case Option::GAIN:
return VideoProcAmp_Gain; return VideoProcAmp_Gain;
@ -510,8 +509,9 @@ static long get_cid(Option option) {
} }
bool pu_control_range( bool pu_control_range(
const device &device, Option option, int32_t *min, int32_t *max, const device &device, Option option, int32_t *min, int32_t *max,
int32_t *def) { int32_t *def)
{
const_cast<uvc::device &>(device).get_media_source(); const_cast<uvc::device &>(device).get_media_source();
long minVal=0, maxVal=0, steppingDelta=0, defVal=0, capsFlag=0; long minVal=0, maxVal=0, steppingDelta=0, defVal=0, capsFlag=0;
check("IAMVideoProcAmp::GetRange", const_cast<uvc::device &>(device).am_video_proc_amp->GetRange(get_cid(option), &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag)); check("IAMVideoProcAmp::GetRange", const_cast<uvc::device &>(device).am_video_proc_amp->GetRange(get_cid(option), &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag));
@ -521,19 +521,22 @@ bool pu_control_range(
return true; return true;
} }
void get_pu_control(const device &device, long property, int32_t *value) { void get_pu_control(const device &device, long property, int32_t *value)
{
long data, flags=0; long data, flags=0;
check("IAMVideoProcAmp::Get", const_cast<uvc::device &>(device).am_video_proc_amp->Get(property, &data, &flags)); check("IAMVideoProcAmp::Get", const_cast<uvc::device &>(device).am_video_proc_amp->Get(property, &data, &flags));
*value = data; *value = data;
} }
void set_pu_control(const device &device, long property, int32_t *value) { void set_pu_control(const device &device, long property, int32_t *value)
{
long data = *value; long data = *value;
check("IAMVideoProcAmp::Set", const_cast<uvc::device &>(device).am_video_proc_amp->Set(property, data, VideoProcAmp_Flags_Auto)); check("IAMVideoProcAmp::Set", const_cast<uvc::device &>(device).am_video_proc_amp->Set(property, data, VideoProcAmp_Flags_Auto));
} }
bool pu_control_query( bool pu_control_query(
const device &device, Option option, pu_query query, int32_t *value) { const device &device, Option option, pu_query query, int32_t *value)
{
CHECK_NOTNULL(value); CHECK_NOTNULL(value);
const_cast<uvc::device &>(device).get_media_source(); const_cast<uvc::device &>(device).get_media_source();
switch (query) { switch (query) {
@ -551,108 +554,106 @@ bool pu_control_query(
void get_extension_control_range(const device &device, const xu &xu, uint8_t selector, xu_query query, uint8_t *data) void get_extension_control_range(const device &device, const xu &xu, uint8_t selector, xu_query query, uint8_t *data)
{ {
CHECK_NOTNULL(data); CHECK_NOTNULL(data);
int offset = 0; int offset = 0;
auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu); auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
/* get step, min and max values*/ /* get step, min and max values*/
KSP_NODE node; KSP_NODE node;
memset(&node, 0, sizeof(KSP_NODE)); memset(&node, 0, sizeof(KSP_NODE));
node.Property.Set = reinterpret_cast<const GUID &>(xu.id); node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
node.Property.Id = selector; node.Property.Id = selector;
node.NodeId = xu.node; node.NodeId = xu.node;
switch (query) { switch (query) {
case XU_QUERY_MIN: case XU_QUERY_MIN:
offset = 1; offset = 1;
node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY; node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
break; break;
case XU_QUERY_MAX: case XU_QUERY_MAX:
offset = 2; offset = 2;
node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY; node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
break; break;
case XU_QUERY_DEF: case XU_QUERY_DEF:
offset = 0; offset = 0;
node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY; node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY;
break; break;
default: default:
LOG(ERROR) << "xu request code is unaccepted"; LOG(ERROR) << "xu request code is unaccepted";
break; break;
} }
KSPROPERTY_DESCRIPTION description; KSPROPERTY_DESCRIPTION description;
unsigned long bytes_received = 0; unsigned long bytes_received = 0;
std::cout << "query" << std::endl; check("IKsControl::KsProperty", ks_control->KsProperty(
check("IKsControl::KsProperty", ks_control->KsProperty( (PKSPROPERTY)&node,
(PKSPROPERTY)&node, sizeof(node),
sizeof(node), &description,
&description, sizeof(KSPROPERTY_DESCRIPTION),
sizeof(KSPROPERTY_DESCRIPTION), &bytes_received));
&bytes_received));
unsigned long size = description.DescriptionSize; unsigned long size = description.DescriptionSize;
std::vector<BYTE> buffer((long)size); std::vector<BYTE> buffer((long)size);
check("IKsControl::KsProperty", ks_control->KsProperty( check("IKsControl::KsProperty", ks_control->KsProperty(
(PKSPROPERTY)&node, (PKSPROPERTY)&node,
sizeof(node), sizeof(node),
buffer.data(), buffer.data(),
size, size,
&bytes_received)); &bytes_received));
if (bytes_received != size) { throw std::runtime_error("wrong data"); } if (bytes_received != size) {
throw std::runtime_error("wrong data");
}
BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
* data = (uint8_t)*(pRangeValues + offset); * data = (uint8_t)*(pRangeValues + offset);
} }
bool xu_control_query( bool xu_control_query(
const device &device, const xu &xu, uint8_t selector, xu_query query, const device &device, const xu &xu, uint8_t selector, xu_query query,
uint16_t size, uint8_t *data) { uint16_t size, uint8_t *data)
CHECK_NOTNULL(data); {
int offset = 0; CHECK_NOTNULL(data);
int range_offset = sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); int offset = 0;
int range_offset = sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu); auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
KSP_NODE node; KSP_NODE node;
memset(&node, 0, sizeof(KSP_NODE)); memset(&node, 0, sizeof(KSP_NODE));
node.Property.Set = reinterpret_cast<const GUID &>(xu.id); node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
node.Property.Id = selector; node.Property.Id = selector;
node.NodeId = xu.node; node.NodeId = xu.node;
unsigned long bytes_received = 0; unsigned long bytes_received = 0;
std::cout << "selector: " << selector << std::endl; switch (query) {
switch (query) { case XU_QUERY_SET:
case XU_QUERY_SET: node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
std::cout << "XU_QUERY_SET" << std::endl; break;
node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; case XU_QUERY_GET:
break; node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
case XU_QUERY_GET: break;
std::cout << "XU_QUERY_GET" << std::endl; case XU_QUERY_MIN:
node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; case XU_QUERY_MAX:
break; case XU_QUERY_DEF:
case XU_QUERY_MIN: get_extension_control_range(device, xu, selector, query, data);
case XU_QUERY_MAX: return true;
case XU_QUERY_DEF: default:
get_extension_control_range(device, xu, selector, query, data); return false;
return true; }
default: check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), reinterpret_cast<void *>(data), size, &bytes_received));
LOG(ERROR) << "xu range query request code is unaccepted"; if (bytes_received != size) {
return false; throw_error() << "wrong data";
} }
std::cout << "set & get" << std::endl;
check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), reinterpret_cast<void *>(data), size, &bytes_received));
if (bytes_received != size) { throw_error() << "wrong data"; }
*data = (int)*(data+offset); *data = (int)*(data+offset);
return true; return true;
} }
void set_device_mode(device & device, int width, int height, int fourcc, int fps, video_channel_callback callback) void set_device_mode(device & device, int width, int height, int fourcc, int fps, video_channel_callback callback)
{ {
if(!device.mf_source_reader) if(!device.mf_source_reader) {
{
com_ptr<IMFAttributes> pAttributes; com_ptr<IMFAttributes> pAttributes;
check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1));
check("IMFAttributes::SetUnknown", pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, static_cast<IUnknown *>(device.reader_callback))); check("IMFAttributes::SetUnknown", pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, static_cast<IUnknown *>(device.reader_callback)));
@ -661,33 +662,39 @@ void set_device_mode(device & device, int width, int height, int fourcc, int fps
if (fourcc_map.count(fourcc)) fourcc = fourcc_map.at(fourcc); if (fourcc_map.count(fourcc)) fourcc = fourcc_map.at(fourcc);
for (DWORD j = 0; ; j++) for (DWORD j = 0; ; j++) {
{
com_ptr<IMFMediaType> media_type; com_ptr<IMFMediaType> media_type;
HRESULT hr = device.mf_source_reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, j, &media_type); HRESULT hr = device.mf_source_reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, j, &media_type);
if (hr == MF_E_NO_MORE_TYPES) break; if (hr == MF_E_NO_MORE_TYPES) break;
check("IMFSourceReader::GetNativeMediaType", hr); check("IMFSourceReader::GetNativeMediaType", hr);
UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom; GUID subtype; UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom;
GUID subtype;
check("MFGetAttributeSize", MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &uvc_width, &uvc_height)); check("MFGetAttributeSize", MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &uvc_width, &uvc_height));
if(uvc_width != width || uvc_height != height) continue; if(uvc_width != width || uvc_height != height) continue;
check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype)); check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype));
if(subtype.Data1 != fourcc) continue; if(subtype.Data1 != fourcc) continue;
check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom)); check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom));
if(uvc_fps_denom == 0) continue; if(uvc_fps_denom == 0) continue;
check("IMFSourceReader::SetCurrentMediaType", device.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type)); check("IMFSourceReader::SetCurrentMediaType", device.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type));
device.callback = callback; device.callback = callback;
return; return;
} }
throw_error() << "no matching media type for pixel format " << std::hex << fourcc; throw_error() << "no matching media type for pixel format " << std::hex << fourcc;
} }
void start_streaming(device & device, int num_transfer_bufs) { device.start_streaming(); } void start_streaming(device & device, int num_transfer_bufs)
void stop_streaming(device & device) { device.stop_streaming(); } {
device.start_streaming();
}
void stop_streaming(device & device)
{
device.stop_streaming();
}
} // namespace uvc } // namespace uvc