diff --git a/CMakeLists.txt b/CMakeLists.txt index 221a065..08092e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ link_directories( ) # Main executable -add_executable(${PROJECT_NAME} main.cpp csi_camera.cpp utils.cpp) +add_executable(${PROJECT_NAME} main.cpp csi_camera.cpp csi_discovery.cpp utils.cpp) target_link_libraries(${PROJECT_NAME} ${GSTREAMER_LIBRARIES} diff --git a/conanfile.py b/conanfile.py index 0123a2b..ca7ce20 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,6 +25,8 @@ class ViamCsi(ConanFile): "main.cpp", "csi_camera.cpp", "csi_camera.h", + "csi_discovery.cpp", + "csi_discovery.h", "utils.cpp", "utils.h", "constraints.h", diff --git a/csi_discovery.cpp b/csi_discovery.cpp new file mode 100644 index 0000000..6ee9c12 --- /dev/null +++ b/csi_discovery.cpp @@ -0,0 +1,98 @@ +#include "csi_discovery.h" + +#include + +#include + +#include + +#include "constraints.h" +#include "utils.h" + +using namespace viam::sdk; + +CSIDiscovery::CSIDiscovery(std::string name) : Discovery(std::move(name)) { + VIAM_RESOURCE_LOG(debug) << "Creating CSIDiscovery"; +} + +std::vector CSIDiscovery::discover_resources(const ProtoStruct& /* extra */) { + VIAM_RESOURCE_LOG(debug) << "discover_resources called"; + + std::vector out; + + auto board = get_device_type(); + const std::string subtype = (board.value == device_type::pi) ? PI_API_SUBTYPE : JETSON_API_SUBTYPE; + + GstDeviceMonitor* monitor = gst_device_monitor_new(); + GstCaps* raw = gst_caps_new_empty_simple("video/x-raw"); + gst_device_monitor_add_filter(monitor, "Video/Source", raw); + gst_caps_unref(raw); + GstCaps* nvmm = gst_caps_from_string("video/x-raw(memory:NVMM)"); + gst_device_monitor_add_filter(monitor, "Video/Source", nvmm); + gst_caps_unref(nvmm); + + if (!gst_device_monitor_start(monitor)) { + VIAM_RESOURCE_LOG(error) << "GstDeviceMonitor failed to start; returning no configs"; + gst_object_unref(monitor); + return out; + } + + GList* devices = gst_device_monitor_get_devices(monitor); + int idx = 0; + for (GList* it = devices; it != nullptr; it = it->next, idx++) { + GstDevice* dev = GST_DEVICE(it->data); + gchar* name = gst_device_get_display_name(dev); + GstCaps* caps = gst_device_get_caps(dev); + + int width = DEFAULT_INPUT_WIDTH; + int height = DEFAULT_INPUT_HEIGHT; + int fps = DEFAULT_INPUT_FRAMERATE; + + if (caps != nullptr && gst_caps_get_size(caps) > 0) { + GstStructure* s = gst_caps_get_structure(caps, 0); + gst_structure_get_int(s, "width", &width); + gst_structure_get_int(s, "height", &height); + int fps_n = 0, fps_d = 0; + if (gst_structure_get_fraction(s, "framerate", &fps_n, &fps_d) && fps_d > 0) { + fps = fps_n / fps_d; + } + } + + VIAM_RESOURCE_LOG(info) << "Discovered camera " << idx << " (" << (name ? name : "?") << "): " << width << "x" << height << "@" + << fps; + + ProtoStruct attrs{ + {"width_px", static_cast(width)}, + {"height_px", static_cast(height)}, + {"frame_rate", static_cast(fps)}, + }; + if (board.value == device_type::jetson) { + attrs["video_path"] = std::to_string(idx); + } + + const std::string config_name = + "csi" + std::to_string(idx) + "_" + std::to_string(width) + "x" + std::to_string(height) + "_" + std::to_string(fps); + + out.emplace_back("camera", config_name, "rdk", attrs, "rdk:component:camera", Model("viam", "camera", subtype)); + + if (caps != nullptr) + gst_caps_unref(caps); + if (name != nullptr) + g_free(name); + } + + g_list_free_full(devices, gst_object_unref); + gst_device_monitor_stop(monitor); + gst_object_unref(monitor); + + return out; +} + +ProtoStruct CSIDiscovery::do_command(const ProtoStruct& /* command */) { + VIAM_RESOURCE_LOG(warn) << "do_command not implemented"; + return ProtoStruct{}; +} + +ProtoStruct CSIDiscovery::get_status() { + return ProtoStruct{}; +} diff --git a/csi_discovery.h b/csi_discovery.h new file mode 100644 index 0000000..d142d16 --- /dev/null +++ b/csi_discovery.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include +#include +#include + +class CSIDiscovery : public viam::sdk::Discovery { + public: + explicit CSIDiscovery(std::string name); + + std::vector discover_resources(const viam::sdk::ProtoStruct& extra) override; + viam::sdk::ProtoStruct do_command(const viam::sdk::ProtoStruct& command) override; + viam::sdk::ProtoStruct get_status() override; +}; diff --git a/etc/run-clang-format.sh b/etc/run-clang-format.sh index b7ad854..255ca26 100755 --- a/etc/run-clang-format.sh +++ b/etc/run-clang-format.sh @@ -41,4 +41,7 @@ else fi fi -find ./ -type f \( -name \*.cpp -o -name \*.h \) | xargs "$CLANG_FORMAT" -i --style=file "$@" +find . \ + \( -path ./.conan-home -o -path ./build -o -path ./build-conan -o -path ./build-conan-test -o -path ./.venv -o -path ./venv -o -path ./bin \) -prune \ + -o -type f \( -name '*.cpp' -o -name '*.h' \) -print \ + | xargs "$CLANG_FORMAT" -i --style=file "$@" diff --git a/main.cpp b/main.cpp index bd09b2b..f1af765 100644 --- a/main.cpp +++ b/main.cpp @@ -8,9 +8,11 @@ #include #include #include +#include #include "constraints.h" #include "csi_camera.h" +#include "csi_discovery.h" #include "utils.h" using namespace viam::sdk; @@ -39,6 +41,20 @@ int main(int argc, char* argv[]) try { }); std::vector> mrs = {module_registration}; + + // Register the discovery model alongside the camera, but only on boards we actually + // know how to probe. On unknown hardware a discovery that returns nothing is just noise. + if (device.value != device_type::unknown) { + auto discovery_subtype = (device.value == device_type::pi) ? PI_API_SUBTYPE : JETSON_API_SUBTYPE; + auto discovery_registration = + std::make_shared(API::get(), + Model{API_NAMESPACE, "discovery", discovery_subtype}, + [](Dependencies, ResourceConfig resource_config) -> std::shared_ptr { + return std::make_shared(resource_config.name()); + }); + mrs.push_back(discovery_registration); + } + auto module_service = std::make_shared(argc, argv, mrs); module_service->serve();