Fix capture video stream in uvc-wmf
This commit is contained in:
parent
ca0ae22aea
commit
58fdc4c01b
|
@ -14,8 +14,17 @@
|
|||
|
||||
struct frame {
|
||||
const void *data = nullptr;
|
||||
std::function<void()> continuation = nullptr;
|
||||
frame() {
|
||||
// VLOG(2) << __func__;
|
||||
}
|
||||
~frame() {
|
||||
// VLOG(2) << __func__;
|
||||
data = nullptr;
|
||||
if (continuation) {
|
||||
continuation();
|
||||
continuation = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -28,7 +37,11 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
auto context = uvc::create_context();
|
||||
auto devices = uvc::query_devices(context);
|
||||
LOG_IF(FATAL, devices.size() <= 0) << "No devices :(";
|
||||
if (devices.size() <= 0) {
|
||||
LOG(ERROR) << "No devices :(";
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (auto &&device : devices) {
|
||||
auto vid = uvc::get_vendor_id(*device);
|
||||
// auto pid = uvc::get_product_id(*device);
|
||||
|
@ -41,7 +54,10 @@ int main(int argc, char *argv[]) {
|
|||
// std::string dashes(80, '-');
|
||||
|
||||
size_t n = mynteye_devices.size();
|
||||
LOG_IF(FATAL, n <= 0) << "No MYNT EYE devices :(";
|
||||
if (n <= 0) {
|
||||
LOG(ERROR) << "No MYNT EYE devices :(";
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(INFO) << "MYNT EYE devices: ";
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
|
@ -74,18 +90,21 @@ int main(int argc, char *argv[]) {
|
|||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
|
||||
std::vector<frame> frames;
|
||||
const auto frame_ready = [&frames]() { return !frames.empty(); };
|
||||
const auto frame_empty = [&frames]() { return frames.empty(); };
|
||||
std::shared_ptr<frame> frame = nullptr;
|
||||
const auto frame_ready = [&frame]() { return frame != nullptr; };
|
||||
const auto frame_empty = [&frame]() { return frame == nullptr; };
|
||||
|
||||
uvc::set_device_mode(
|
||||
*device, 752, 480, static_cast<int>(Format::YUYV), 25,
|
||||
[&mtx, &cv, &frames, &frame_ready](const void *data) {
|
||||
[&mtx, &cv, &frame, &frame_ready](
|
||||
const void *data, std::function<void()> continuation) {
|
||||
// reinterpret_cast<const std::uint8_t *>(data);
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
frame frame;
|
||||
frame.data = data; // not copy
|
||||
frames.push_back(frame);
|
||||
if (frame == nullptr) {
|
||||
frame = std::make_shared<struct frame>();
|
||||
}
|
||||
frame->data = data; // not copy here
|
||||
frame->continuation = continuation;
|
||||
if (frame_ready())
|
||||
cv.notify_one();
|
||||
});
|
||||
|
@ -106,13 +125,12 @@ int main(int argc, char *argv[]) {
|
|||
throw std::runtime_error("Timeout waiting for frame.");
|
||||
}
|
||||
|
||||
auto frame = frames.back(); // only last one is valid
|
||||
|
||||
cv::Mat img(480, 752, CV_8UC2, const_cast<void *>(frame.data));
|
||||
// only lastest frame is valid
|
||||
cv::Mat img(480, 752, CV_8UC2, const_cast<void *>(frame->data));
|
||||
cv::cvtColor(img, img, cv::COLOR_YUV2BGR_YUY2);
|
||||
cv::imshow("frame", img);
|
||||
|
||||
frames.clear();
|
||||
frame = nullptr;
|
||||
|
||||
char key = static_cast<char>(cv::waitKey(1));
|
||||
if (key == 27 || key == 'q' || key == 'Q') { // ESC/Q
|
||||
|
|
|
@ -376,7 +376,7 @@ void Device::StartVideoStreaming() {
|
|||
uvc::set_device_mode(
|
||||
*device_, stream_request.width, stream_request.height,
|
||||
static_cast<int>(stream_request.format), stream_request.fps,
|
||||
[this](const void *data) {
|
||||
[this](const void *data, std::function<void()> continuation) {
|
||||
// drop the first stereo stream data
|
||||
static std::uint8_t drop_count = 1;
|
||||
if (drop_count > 0) {
|
||||
|
@ -385,6 +385,7 @@ void Device::StartVideoStreaming() {
|
|||
}
|
||||
std::lock_guard<std::mutex> _(mtx_streams_);
|
||||
streams_->PushStream(Capabilities::STEREO, data);
|
||||
continuation();
|
||||
if (HasStreamCallback(Stream::LEFT)) {
|
||||
auto &&stream_datas = streams_->stream_datas(Stream::LEFT);
|
||||
if (stream_datas.size() > 0) {
|
||||
|
|
|
@ -49,15 +49,12 @@
|
|||
|
||||
MYNTEYE_BEGIN_NAMESPACE
|
||||
|
||||
namespace uvc
|
||||
{
|
||||
namespace uvc {
|
||||
|
||||
const std::map<uint32_t, uint32_t> fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */
|
||||
|
||||
#define LOG_ERROR(severity, str) \
|
||||
do { \
|
||||
LOG(severity) << str << " error " << errno << ", " << strerror(errno); \
|
||||
} while (0)
|
||||
const std::map<uint32_t, uint32_t> fourcc_map = {
|
||||
{ 0x56595559, 0x32595559 }, // 'VYUY' => '2YUY'
|
||||
{ 0x59555956, 0x59555932 } // 'YUYV' => 'YUY2'
|
||||
};
|
||||
|
||||
struct throw_error {
|
||||
throw_error() = default;
|
||||
|
@ -68,7 +65,6 @@ struct throw_error {
|
|||
|
||||
~throw_error() noexcept(false) {
|
||||
throw std::runtime_error(ss.str());
|
||||
// throw device_error(ss.str());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -80,8 +76,16 @@ struct throw_error {
|
|||
std::ostringstream ss;
|
||||
};
|
||||
|
||||
template<class T> class com_ptr
|
||||
{
|
||||
static void check(const char *call, HRESULT hr) {
|
||||
if (FAILED(hr)) {
|
||||
throw_error() << call << "(...) returned 0x" << std::hex
|
||||
<< static_cast<uint32_t>(hr);
|
||||
} else {
|
||||
LOG(INFO) << call << " SUCCESSED";
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> class com_ptr {
|
||||
T * p;
|
||||
void ref(T * new_p) {
|
||||
if(p == new_p) return;
|
||||
|
@ -136,14 +140,6 @@ static std::string win_to_utf(const WCHAR * s)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
static void check(const char *call, HRESULT hr)
|
||||
{
|
||||
if (FAILED(hr)) {
|
||||
throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr;
|
||||
}
|
||||
LOG(INFO) << call << " SUCCESSED";
|
||||
}
|
||||
|
||||
std::vector<std::string> tokenize(std::string string, char separator)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
|
@ -178,29 +174,29 @@ bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, con
|
|||
auto tokens = tokenize(name, '#');
|
||||
if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device
|
||||
if(tokens.size() < 3) {
|
||||
LOG_ERROR(WARNING,"malformed usb device path: " << name);
|
||||
LOG(ERROR) << "malformed usb device path: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
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)) {
|
||||
LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]);
|
||||
LOG(ERROR) << "malformed vid string: " << tokens[1];
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ids = tokenize(tokens[2], '&');
|
||||
if(ids.size() < 2) {
|
||||
LOG_ERROR(WARNING,"malformed id string: " << tokens[2]);
|
||||
LOG(ERROR) << "malformed id string: " << tokens[2];
|
||||
return false;
|
||||
}
|
||||
unique_id = ids[1];
|
||||
|
@ -216,23 +212,23 @@ bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string &
|
|||
|
||||
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)) {
|
||||
LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]);
|
||||
LOG(ERROR) << "malformed vid string: " << tokens[1];
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ids = tokenize(tokens[2], '&');
|
||||
if (ids.size() < 2) {
|
||||
LOG_ERROR(WARNING,"malformed id string: " + tokens[2]);
|
||||
LOG(ERROR) << "malformed id string: " + tokens[2];
|
||||
return false;
|
||||
}
|
||||
unique_id = ids[1];
|
||||
|
@ -303,8 +299,9 @@ struct device {
|
|||
com_ptr<IMFSourceReader> mf_source_reader;
|
||||
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), unique_id(move(unique_id)), 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();
|
||||
|
@ -312,7 +309,6 @@ struct device {
|
|||
|
||||
|
||||
IKsControl * get_ks_control(const uvc::xu & xu) {
|
||||
|
||||
auto it = ks_controls.find(xu.node);
|
||||
if(it != end(ks_controls)) return it->second;
|
||||
|
||||
|
@ -353,8 +349,8 @@ struct device {
|
|||
}
|
||||
|
||||
void stop_streaming() {
|
||||
|
||||
if (mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
|
||||
|
||||
while (true) {
|
||||
bool is_streaming = reader_callback->is_streaming();
|
||||
if (is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
@ -397,7 +393,7 @@ HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWO
|
|||
auto continuation = [buffer, this]() {
|
||||
buffer->Unlock();
|
||||
};
|
||||
owner_ptr->callback(byte_buffer);
|
||||
owner_ptr->callback(byte_buffer, continuation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -405,26 +401,13 @@ HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWO
|
|||
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);
|
||||
switch (hr) {
|
||||
case S_OK:
|
||||
break;
|
||||
case MF_E_INVALIDREQUEST:
|
||||
LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST");
|
||||
break;
|
||||
case MF_E_INVALIDSTREAMNUMBER:
|
||||
LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER");
|
||||
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;
|
||||
case S_OK: break;
|
||||
case MF_E_INVALIDREQUEST: LOG(ERROR) << "ReadSample returned MF_E_INVALIDREQUEST"; break;
|
||||
case MF_E_INVALIDSTREAMNUMBER: LOG(ERROR) << "ReadSample returned MF_E_INVALIDSTREAMNUMBER"; break;
|
||||
case MF_E_NOTACCEPTING: LOG(ERROR) << "ReadSample returned MF_E_NOTACCEPTING"; break;
|
||||
case E_INVALIDARG: LOG(ERROR) << "ReadSample returned E_INVALIDARG"; break;
|
||||
case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: LOG(ERROR) << "ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"; break;
|
||||
default: LOG(ERROR) << "ReadSample returned HRESULT " << std::hex << (uint32_t)hr; break;
|
||||
}
|
||||
if (hr != S_OK) streaming = false;
|
||||
}
|
||||
|
@ -441,7 +424,8 @@ std::vector<std::shared_ptr<device>> query_devices(std::shared_ptr<context> cont
|
|||
{
|
||||
IMFAttributes *pAttributes = NULL;
|
||||
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));
|
||||
|
||||
IMFActivate **ppDevices;
|
||||
UINT32 numDevices;
|
||||
|
@ -490,7 +474,6 @@ std::vector<std::shared_ptr<device>> query_devices(std::shared_ptr<context> cont
|
|||
dev->mf_activate = pDevice;
|
||||
dev->vid = vid;
|
||||
dev->pid = pid;
|
||||
|
||||
}
|
||||
|
||||
CoTaskMemFree(ppDevices);
|
||||
|
@ -707,6 +690,8 @@ void set_device_mode(device & device, int width, int height, int fourcc, int fps
|
|||
|
||||
check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom));
|
||||
if (uvc_fps_denom == 0) continue;
|
||||
//int uvc_fps = uvc_fps_num / uvc_fps_denom;
|
||||
//LOG(INFO) << "uvc_fps: " << uvc_fps;
|
||||
|
||||
check("IMFSourceReader::SetCurrentMediaType", device.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type));
|
||||
|
||||
|
|
|
@ -23,7 +23,11 @@ typedef enum pu_query {
|
|||
PU_QUERY_LAST
|
||||
} pu_query;
|
||||
|
||||
struct guid { uint32_t data1; uint16_t data2, data3; uint8_t data4[8]; };
|
||||
struct MYNTEYE_API guid {
|
||||
uint32_t data1;
|
||||
uint16_t data2, data3;
|
||||
uint8_t data4[8];
|
||||
};
|
||||
|
||||
// Extension Unit
|
||||
struct MYNTEYE_API xu {
|
||||
|
@ -73,7 +77,8 @@ MYNTEYE_API bool xu_control_query(
|
|||
uint16_t size, uint8_t *data);
|
||||
|
||||
// Control streaming
|
||||
typedef std::function<void(const void *frame)> video_channel_callback;
|
||||
typedef std::function<void(const void *frame,
|
||||
std::function<void()> continuation)> video_channel_callback;
|
||||
|
||||
MYNTEYE_API void set_device_mode(
|
||||
device &device, int width, int height, int fourcc, int fps, // NOLINT
|
||||
|
|
Loading…
Reference in New Issue
Block a user