From e4e6c34c08cd63412ed5f01e0bc430b8fe6c6a4d Mon Sep 17 00:00:00 2001 From: "Dorodnicov, Sergey" Date: Tue, 14 Aug 2018 04:51:24 -0700 Subject: [PATCH 1/3] Callback dispatcher thread for the winuvc backend (cherry picked from commit a718d7b5024965f16564e6c730b758be973826a4) # Conflicts: # src/win7/winusb_uvc/winusb_uvc.cpp --- src/types.h | 2 + src/win7/winusb_uvc/winusb_uvc.cpp | 100 +++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/types.h b/src/types.h index 8b1c83ee2d..aa7caf1d19 100644 --- a/src/types.h +++ b/src/types.h @@ -992,6 +992,8 @@ namespace librealsense int size = 0; public: + static const int CAPACITY = C; + small_heap() { for (auto i = 0; i < C; i++) diff --git a/src/win7/winusb_uvc/winusb_uvc.cpp b/src/win7/winusb_uvc/winusb_uvc.cpp index 29ef1acd2b..881d9b74bc 100644 --- a/src/win7/winusb_uvc/winusb_uvc.cpp +++ b/src/win7/winusb_uvc/winusb_uvc.cpp @@ -1,11 +1,47 @@ // winusb_uvc.cpp : Defines the entry point for the console application. // +#define NOMINMAX #include "windows.h" #include "SETUPAPI.H" #include "winusb_uvc.h" #include "libuvc/utlist.h" #include "types.h" +#include "concurrency.h" +#include "types.h" + +#include +#include +#include +#include + +// Data structures for Backend-Frontend queue: + +struct frame; +// We keep no more then 2 frames in between frontend and backend +typedef librealsense::small_heap frames_archive; +struct frame +{ + frame() {} + + // We don't want the frames to be overwritten at any point + // (deallocate resets item to "default" that we want to avoid) + frame(const frame& other) {} + frame(frame&& other) {} + frame& operator=(const frame& other) { return *this; } + + std::vector pixels; + librealsense::platform::frame_object fo; + frames_archive* owner; // Keep pointer to owner for light-deleter +}; +void cleanup_frame(frame* ptr) { + if (ptr) ptr->owner->deallocate(ptr); +}; +typedef void(*cleanup_ptr)(frame*); +// Unique_ptr is used as the simplest RAII, with static deleter +typedef std::unique_ptr frame_ptr; +typedef single_consumer_queue frames_queue; + uvc_error_t winusb_uvc_scan_streaming(winusb_uvc_device *dev, winusb_uvc_device_info_t *info, int interface_idx); uvc_error_t winusb_uvc_parse_vs(winusb_uvc_device *dev, winusb_uvc_device_info_t *info, winusb_uvc_streaming_interface_t *stream_if, const unsigned char *block, size_t block_size); @@ -753,7 +789,8 @@ void winusb_uvc_swap_buffers(winusb_uvc_stream_handle_t *strmh) { strmh->pts = 0; } -void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, uint8_t *payload, size_t payload_len) { +void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, + uint8_t *payload, size_t payload_len, frames_archive* archive, frames_queue* queue) { uint8_t header_len; uint8_t header_info; size_t data_len; @@ -829,13 +866,32 @@ void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, uint8_t *payl if ((data_len > 0) && (strmh->cur_ctrl.dwMaxVideoFrameSize == (data_len))) { // save all frame+header - memcpy(strmh->outbuf + strmh->got_bytes, payload, data_len + header_len); - strmh->got_bytes += data_len; + //memcpy(strmh->outbuf + strmh->got_bytes, payload, data_len + header_len); + //strmh->got_bytes += data_len; if (header_info & (1 << 1)) { /* The EOF bit is set, so publish the complete frame */ winusb_uvc_swap_buffers(strmh); + auto frame_p = archive->allocate(); + if (frame_p) + { + frame_ptr fp(frame_p, &cleanup_frame); + + memset(fp->pixels.data(), 0, fp->pixels.size()); + + memcpy(fp->pixels.data(), payload, data_len + header_len); + + librealsense::platform::frame_object fo{ data_len, header_len, + fp->pixels.data() + header_len , fp->pixels.data() }; + fp->fo = fo; + + queue->enqueue(std::move(fp)); + } + else + { + //std::cout << "Frame from WinUSB backend was dropped (Frontend busy)\n"; + } //printf("EndPoint 0x%X: Received Frame %d (%zd bytes): header info = %08X\n", strmh->stream_if->bEndpointAddress, strmh->seq, payload_len, payload[1]); LOG_INFO("Passing packet to user CB with size " << data_len + header_len); librealsense::platform::frame_object fo{ data_len, header_len, strmh->holdbuf + header_len , strmh->holdbuf }; @@ -851,6 +907,36 @@ void stream_thread(winusb_uvc_stream_context *strctx) PUCHAR buffer = (PUCHAR)malloc(strctx->maxPayloadTransferSize); memset(buffer, 0, sizeof(strctx->maxPayloadTransferSize)); + frames_archive archive; + std::atomic_bool keep_sending_callbacks = true; + frames_queue queue; + + // Get all pointers from archive and initialize their content + std::vector frames; + for (auto i = 0; i < frames_archive::CAPACITY; i++) + { + auto ptr = archive.allocate(); + ptr->pixels.resize(strctx->maxPayloadTransferSize, 0); + ptr->owner = &archive; + frames.push_back(ptr); + } + for (auto ptr : frames) + { + archive.deallocate(ptr); + } + + std::thread t([&]() { + while (keep_sending_callbacks) + { + frame_ptr fp(nullptr, [](frame*) {}); + if (queue.dequeue(&fp, 50)) + { + strctx->stream->user_cb(&fp->fo, strctx->stream->user_ptr); + fp.reset(); + } + } + }); + do { DWORD transferred; @@ -866,7 +952,7 @@ void stream_thread(winusb_uvc_stream_context *strctx) //printf("success : %d\n", transferred); LOG_INFO("Packet received with size " << transferred); - winusb_uvc_process_payload(strctx->stream, buffer, transferred); + winusb_uvc_process_payload(strctx->stream, buffer, lengthTransfered, &archive, &queue); } while (strctx->stream->running); // reseting pipe after use @@ -874,6 +960,12 @@ void stream_thread(winusb_uvc_stream_context *strctx) free(buffer); free(strctx); + + queue.clear(); + archive.stop_allocation(); + archive.wait_until_empty(); + keep_sending_callbacks = false; + t.join(); }; uvc_error_t winusb_uvc_stream_start( From de761ee42ca00fec619f6cec87093c504ed7571e Mon Sep 17 00:00:00 2001 From: "Dorodnicov, Sergey" Date: Tue, 14 Aug 2018 05:11:41 -0700 Subject: [PATCH 2/3] Fixing merge --- src/win7/winusb_uvc/winusb_uvc.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/win7/winusb_uvc/winusb_uvc.cpp b/src/win7/winusb_uvc/winusb_uvc.cpp index 881d9b74bc..f9e42df3f2 100644 --- a/src/win7/winusb_uvc/winusb_uvc.cpp +++ b/src/win7/winusb_uvc/winusb_uvc.cpp @@ -882,6 +882,7 @@ void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, memcpy(fp->pixels.data(), payload, data_len + header_len); + LOG_INFO("Passing packet to user CB with size " << data_len + header_len); librealsense::platform::frame_object fo{ data_len, header_len, fp->pixels.data() + header_len , fp->pixels.data() }; fp->fo = fo; @@ -893,13 +894,8 @@ void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, //std::cout << "Frame from WinUSB backend was dropped (Frontend busy)\n"; } //printf("EndPoint 0x%X: Received Frame %d (%zd bytes): header info = %08X\n", strmh->stream_if->bEndpointAddress, strmh->seq, payload_len, payload[1]); - LOG_INFO("Passing packet to user CB with size " << data_len + header_len); - librealsense::platform::frame_object fo{ data_len, header_len, strmh->holdbuf + header_len , strmh->holdbuf }; - strmh->user_cb(&fo, strmh->user_ptr); } } - - } void stream_thread(winusb_uvc_stream_context *strctx) @@ -952,7 +948,7 @@ void stream_thread(winusb_uvc_stream_context *strctx) //printf("success : %d\n", transferred); LOG_INFO("Packet received with size " << transferred); - winusb_uvc_process_payload(strctx->stream, buffer, lengthTransfered, &archive, &queue); + winusb_uvc_process_payload(strctx->stream, buffer, transferred, &archive, &queue); } while (strctx->stream->running); // reseting pipe after use From 6edcdde4bbdc7b1859f8d61947ace417db783555 Mon Sep 17 00:00:00 2001 From: "Dorodnicov, Sergey" Date: Tue, 14 Aug 2018 05:39:13 -0700 Subject: [PATCH 3/3] CR changes --- src/win7/winusb_uvc/winusb_uvc.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/win7/winusb_uvc/winusb_uvc.cpp b/src/win7/winusb_uvc/winusb_uvc.cpp index f9e42df3f2..13662e4b38 100644 --- a/src/win7/winusb_uvc/winusb_uvc.cpp +++ b/src/win7/winusb_uvc/winusb_uvc.cpp @@ -5,18 +5,13 @@ #include "SETUPAPI.H" #include "winusb_uvc.h" #include "libuvc/utlist.h" -#include "types.h" - #include "concurrency.h" #include "types.h" - #include #include #include -#include // Data structures for Backend-Frontend queue: - struct frame; // We keep no more then 2 frames in between frontend and backend typedef librealsense::small_heap frames_archive; @@ -865,10 +860,6 @@ void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, if ((data_len > 0) && (strmh->cur_ctrl.dwMaxVideoFrameSize == (data_len))) { - // save all frame+header - //memcpy(strmh->outbuf + strmh->got_bytes, payload, data_len + header_len); - //strmh->got_bytes += data_len; - if (header_info & (1 << 1)) { /* The EOF bit is set, so publish the complete frame */ winusb_uvc_swap_buffers(strmh); @@ -878,11 +869,9 @@ void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, { frame_ptr fp(frame_p, &cleanup_frame); - memset(fp->pixels.data(), 0, fp->pixels.size()); - memcpy(fp->pixels.data(), payload, data_len + header_len); - LOG_INFO("Passing packet to user CB with size " << data_len + header_len); + LOG_DEBUG("Passing packet to user CB with size " << data_len + header_len); librealsense::platform::frame_object fo{ data_len, header_len, fp->pixels.data() + header_len , fp->pixels.data() }; fp->fo = fo; @@ -891,9 +880,8 @@ void winusb_uvc_process_payload(winusb_uvc_stream_handle_t *strmh, } else { - //std::cout << "Frame from WinUSB backend was dropped (Frontend busy)\n"; + LOG_INFO("WinUSB backend is dropping a frame because librealsense wasn't fast enough"); } - //printf("EndPoint 0x%X: Received Frame %d (%zd bytes): header info = %08X\n", strmh->stream_if->bEndpointAddress, strmh->seq, payload_len, payload[1]); } } } @@ -928,13 +916,11 @@ void stream_thread(winusb_uvc_stream_context *strctx) if (queue.dequeue(&fp, 50)) { strctx->stream->user_cb(&fp->fo, strctx->stream->user_ptr); - fp.reset(); } } }); do { - DWORD transferred; if (!WinUsb_ReadPipe(strctx->stream->devh->associateHandle, strctx->endpoint, @@ -946,8 +932,7 @@ void stream_thread(winusb_uvc_stream_context *strctx) return; } - //printf("success : %d\n", transferred); - LOG_INFO("Packet received with size " << transferred); + LOG_DEBUG("Packet received with size " << transferred); winusb_uvc_process_payload(strctx->stream, buffer, transferred, &archive, &queue); } while (strctx->stream->running);