|
| 1 | +// Copyright (c) FIRST and other WPILib contributors. |
| 2 | +// Open Source Software; you can modify and/or share it under the terms of |
| 3 | +// the WPILib BSD license file in the root directory of this project. |
| 4 | + |
| 5 | +#include "glass/camera/UsbCameraList.h" |
| 6 | + |
| 7 | +#include <cscore_cpp.h> |
| 8 | +#include <fmt/format.h> |
| 9 | +#include <imgui.h> |
| 10 | + |
| 11 | +using namespace glass; |
| 12 | + |
| 13 | +struct UsbCameraList::UsbInfoThread : public wpi::SafeThread { |
| 14 | + void Main() override; |
| 15 | + |
| 16 | + std::vector<cs::UsbCameraInfo> m_usbInfo; |
| 17 | +}; |
| 18 | + |
| 19 | +void UsbCameraList::UsbInfoThread::Main() { |
| 20 | + std::unique_lock lock{m_mutex}; |
| 21 | + while (m_active) { |
| 22 | + // enumerate without lock held |
| 23 | + lock.unlock(); |
| 24 | + CS_Status status = 0; |
| 25 | + auto usbInfo = cs::EnumerateUsbCameras(&status); |
| 26 | + |
| 27 | + lock.lock(); |
| 28 | + m_usbInfo = std::move(usbInfo); |
| 29 | + |
| 30 | + // wait for change |
| 31 | + m_cond.wait(lock); |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +UsbCameraList::UsbCameraList() : m_poller{cs::CreateListenerPoller()} { |
| 36 | + CS_Status status = 0; |
| 37 | + cs::AddPolledListener(m_poller, CS_USB_CAMERAS_CHANGED, false, &status); |
| 38 | + |
| 39 | + m_usbInfoThread.Start(); |
| 40 | +} |
| 41 | + |
| 42 | +UsbCameraList::~UsbCameraList() { |
| 43 | + cs::DestroyListenerPoller(m_poller); |
| 44 | +} |
| 45 | + |
| 46 | +std::string UsbCameraList::DisplayMenu() { |
| 47 | + std::string rv; |
| 48 | + bool any = false; |
| 49 | + if (auto thr = m_usbInfoThread.GetThread()) { |
| 50 | + // TODO: hide cameras that already exist as sources |
| 51 | + for (auto&& info : thr->m_usbInfo) { |
| 52 | + ImGui::SeparatorText(fmt::format("{} ({:04x}:{:04x})", info.name, |
| 53 | + info.vendorId, info.productId) |
| 54 | + .c_str()); |
| 55 | + if (ImGui::MenuItem(info.path.c_str())) { |
| 56 | + rv = info.path; |
| 57 | + } |
| 58 | + for (auto&& path : info.otherPaths) { |
| 59 | + if (ImGui::MenuItem(path.c_str())) { |
| 60 | + rv = info.path; |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | + any = !thr->m_usbInfo.empty(); |
| 65 | + } |
| 66 | + if (!any) { |
| 67 | + ImGui::MenuItem("(None)", nullptr, false, false); |
| 68 | + } |
| 69 | + return rv; |
| 70 | +} |
| 71 | + |
| 72 | +void UsbCameraList::Update() { |
| 73 | + bool timedOut = false; |
| 74 | + for (auto&& event : cs::PollListener(m_poller, 0, &timedOut)) { |
| 75 | + if (event.kind == cs::RawEvent::kUsbCamerasChanged) { |
| 76 | + // enumerate on separate thread |
| 77 | + if (auto thr = m_usbInfoThread.GetThread()) { |
| 78 | + thr->m_cond.notify_all(); |
| 79 | + } |
| 80 | + } |
| 81 | + } |
| 82 | +} |
0 commit comments