// Copyright 2018 Slightech Co., Ltd. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "api/api.h" #ifdef WITH_BOOST_FILESYSTEM #include #include #endif #include #include #include #include "mynteye/glog_init.h" #include "mynteye/utils.h" #include "api/plugin.h" #include "api/synthetic.h" #include "device/device.h" #include "device/device_s.h" #include "internal/dl.h" #if defined(WITH_FILESYSTEM) && defined(WITH_NATIVE_FILESYSTEM) #if defined(OS_WIN) #include #endif #endif MYNTEYE_BEGIN_NAMESPACE namespace { #if defined(WITH_FILESYSTEM) #if defined(WITH_BOOST_FILESYSTEM) namespace fs = boost::filesystem; bool file_exists(const fs::path &p) { try { fs::file_status s = fs::status(p); return fs::exists(s) && fs::is_regular_file(s); } catch (fs::filesystem_error &e) { LOG(ERROR) << e.what(); return false; } } bool dir_exists(const fs::path &p) { try { fs::file_status s = fs::status(p); return fs::exists(s) && fs::is_directory(s); } catch (fs::filesystem_error &e) { LOG(ERROR) << e.what(); return false; } } #elif defined(WITH_NATIVE_FILESYSTEM) #if defined(OS_WIN) bool file_exists(const std::string &p) { DWORD attrs = GetFileAttributes(p.c_str()); return (attrs != INVALID_FILE_ATTRIBUTES) && !(attrs & FILE_ATTRIBUTE_DIRECTORY); } bool dir_exists(const std::string &p) { DWORD attrs = GetFileAttributes(p.c_str()); return (attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_DIRECTORY); } #else #error "Unsupported native filesystem" #endif #endif std::vector get_plugin_paths() { std::string info_path(MYNTEYE_SDK_INSTALL_DIR); info_path.append(OS_SEP "share" OS_SEP "mynteye" OS_SEP "build.info"); cv::FileStorage fs(info_path, cv::FileStorage::READ); if (!fs.isOpened()) { LOG(WARNING) << "build.info not found: " << info_path; return {}; } auto to_lower = [](std::string &s) { // NOLINT std::transform(s.begin(), s.end(), s.begin(), ::tolower); }; std::string host_os = fs["HOST_OS"]; to_lower(host_os); std::string host_name = fs["HOST_NAME"]; to_lower(host_name); std::string host_arch = fs["HOST_ARCH"]; to_lower(host_arch); std::string host_compiler = fs["HOST_COMPILER"]; to_lower(host_compiler); // std::string compiler_version = fs["COMPILER_VERSION"]; int compiler_version_major = fs["COMPILER_VERSION_MAJOR"]; // int compiler_version_minor = fs["COMPILER_VERSION_MINOR"]; // int compiler_version_patch = fs["COMPILER_VERSION_PATCH"]; // int compiler_version_tweak = fs["COMPILER_VERSION_TWEAK"]; std::string cuda_version = fs["CUDA_VERSION"]; // int cuda_version_major = fs["CUDA_VERSION_MAJOR"]; // int cuda_version_minor = fs["CUDA_VERSION_MINOR"]; // std::string cuda_version_string = fs["CUDA_VERSION_STRING"]; std::string opencv_version = fs["OpenCV_VERSION"]; // int opencv_version_major = fs["OpenCV_VERSION_MAJOR"]; // int opencv_version_minor = fs["OpenCV_VERSION_MINOR"]; // int opencv_version_patch = fs["OpenCV_VERSION_PATCH"]; // int opencv_version_tweak = fs["OpenCV_VERSION_TWEAK"]; // std::string opencv_version_status = fs["OpenCV_VERSION_STATUS"]; std::string opencv_with_world = fs["OpenCV_WITH_WORLD"]; to_lower(opencv_with_world); std::string mynteye_version = fs["MYNTEYE_VERSION"]; // int mynteye_version_major = fs["MYNTEYE_VERSION_MAJOR"]; // int mynteye_version_minor = fs["MYNTEYE_VERSION_MINOR"]; // int mynteye_version_patch = fs["MYNTEYE_VERSION_PATCH"]; // int mynteye_version_tweak = fs["MYNTEYE_VERSION_TWEAK"]; fs.release(); std::string lib_prefix; std::string lib_suffix; if (host_os == "linux") { if (host_compiler != "gnu" || compiler_version_major < 5) return {}; lib_prefix = "lib"; lib_suffix = ".so"; } else if (host_os == "win") { lib_prefix = ""; lib_suffix = ".dll"; } else if (host_os == "mac") { lib_prefix = "lib"; lib_suffix = ".dylib"; } else { return {}; } std::vector names; { std::vector prefixes{ // lib_prefix + "plugin_b_ocl" + ocl_version, lib_prefix + "plugin_g_cuda" + cuda_version, }; std::string opencv_name("_opencv" + opencv_version); if (opencv_with_world == "true") { opencv_name.append("-world"); } for (auto &&prefix : prefixes) { names.push_back(prefix + opencv_name + "_mynteye" + mynteye_version); names.push_back(prefix + opencv_name); names.push_back(prefix); } for (auto &&name : names) { name.append(lib_suffix); } } std::vector paths; std::vector plats; if (host_name != host_os) { plats.push_back(host_name + "-" + host_arch); } plats.push_back(host_os + "-" + host_arch); std::vector dirs{MYNTEYE_SDK_ROOT_DIR, MYNTEYE_SDK_INSTALL_DIR}; for (auto &&plat : plats) { for (auto &&dir : dirs) { auto &&plat_dir = dir + OS_SEP "plugins" + OS_SEP + plat; // VLOG(2) << "plat_dir: " << plat_dir; if (!dir_exists(plat_dir)) continue; for (auto &&name : names) { // VLOG(2) << " name: " << name; auto &&path = plat_dir + OS_SEP + name; if (!file_exists(path)) continue; paths.push_back(path); } } } return paths; } #endif } // namespace API::API(std::shared_ptr device) : device_(device) { VLOG(2) << __func__; std::dynamic_pointer_cast(device_); synthetic_.reset(new Synthetic(this)); } API::~API() { VLOG(2) << __func__; } std::shared_ptr API::Create() { return Create(device::select()); } std::shared_ptr API::Create(std::shared_ptr device) { if (!device) return nullptr; return std::make_shared(device); } std::shared_ptr API::Create(int argc, char *argv[]) { static glog_init _(argc, argv); auto &&device = device::select(); if (!device) return nullptr; return std::make_shared(device); } std::shared_ptr API::Create( int argc, char *argv[], std::shared_ptr device) { static glog_init _(argc, argv); if (!device) return nullptr; return std::make_shared(device); } Model API::GetModel() const { return device_->GetModel(); } bool API::Supports(const Stream &stream) const { return synthetic_->Supports(stream); } bool API::Supports(const Capabilities &capability) const { return device_->Supports(capability); } bool API::Supports(const Option &option) const { return device_->Supports(option); } bool API::Supports(const AddOns &addon) const { return device_->Supports(addon); } void API::SetStreamRequest( const Resolution &res, const Format &format, const FrameRate &rate) { device_->SetStreamRequest(res, format, rate); CheckImageParams(); } const std::vector &API::GetStreamRequests( const Capabilities &capability) const { return device_->GetStreamRequests(capability); } void API::ConfigStreamRequest( const Capabilities &capability, const StreamRequest &request) { device_->ConfigStreamRequest(capability, request); } std::string API::GetInfo(const Info &info) const { return device_->GetInfo(info); } Intrinsics API::GetIntrinsics(const Stream &stream) const { return device_->GetIntrinsics(stream); } Extrinsics API::GetExtrinsics(const Stream &from, const Stream &to) const { return device_->GetExtrinsics(from, to); } MotionIntrinsics API::GetMotionIntrinsics() const { return device_->GetMotionIntrinsics(); } Extrinsics API::GetMotionExtrinsics(const Stream &from) const { return device_->GetMotionExtrinsics(from); } void API::LogOptionInfos() const { device_->LogOptionInfos(); } OptionInfo API::GetOptionInfo(const Option &option) const { return device_->GetOptionInfo(option); } std::int32_t API::GetOptionValue(const Option &option) const { return device_->GetOptionValue(option); } void API::SetOptionValue(const Option &option, std::int32_t value) { device_->SetOptionValue(option, value); } bool API::RunOptionAction(const Option &option) const { return device_->RunOptionAction(option); } void API::SetStreamCallback(const Stream &stream, stream_callback_t callback) { synthetic_->SetStreamCallback(stream, callback); } void API::SetMotionCallback(motion_callback_t callback) { static auto callback_ = callback; if (callback_) { device_->SetMotionCallback( [](const device::MotionData &data) { callback_({data.imu}); }, true); } else { device_->SetMotionCallback(nullptr); } } bool API::HasStreamCallback(const Stream &stream) const { return synthetic_->HasStreamCallback(stream); } bool API::HasMotionCallback() const { return device_->HasMotionCallback(); } void API::Start(const Source &source) { if (source == Source::VIDEO_STREAMING) { #ifdef WITH_FILESYSTEM if (!synthetic_->HasPlugin()) { try { auto &&plugin_paths = get_plugin_paths(); if (plugin_paths.size() > 0) { EnablePlugin(plugin_paths[0]); } } catch (...) { LOG(WARNING) << "Incorrect yaml format: build.info"; } } #endif synthetic_->StartVideoStreaming(); } else if (source == Source::MOTION_TRACKING) { device_->StartMotionTracking(); } else if (source == Source::ALL) { Start(Source::VIDEO_STREAMING); Start(Source::MOTION_TRACKING); } else { LOG(ERROR) << "Unsupported source :("; } } void API::Stop(const Source &source) { if (source == Source::VIDEO_STREAMING) { synthetic_->StopVideoStreaming(); } else if (source == Source::MOTION_TRACKING) { device_->StopMotionTracking(); } else if (source == Source::ALL) { Stop(Source::MOTION_TRACKING); // Must stop motion tracking before video streaming and sleep a moment here std::this_thread::sleep_for(std::chrono::milliseconds(10)); Stop(Source::VIDEO_STREAMING); } else { LOG(ERROR) << "Unsupported source :("; } } void API::WaitForStreams() { synthetic_->WaitForStreams(); } void API::EnableStreamData(const Stream &stream) { synthetic_->EnableStreamData(stream); } void API::DisableStreamData(const Stream &stream) { synthetic_->DisableStreamData(stream); } api::StreamData API::GetStreamData(const Stream &stream) { return synthetic_->GetStreamData(stream); } std::vector API::GetStreamDatas(const Stream &stream) { return synthetic_->GetStreamDatas(stream); } void API::EnableMotionDatas(std::size_t max_size) { device_->EnableMotionDatas(max_size); } std::vector API::GetMotionDatas() { std::vector datas; for (auto &&data : device_->GetMotionDatas()) { datas.push_back({data.imu}); } return datas; } void API::EnablePlugin(const std::string &path) { static DL dl; CHECK(dl.Open(path.c_str())) << "Open plugin failed: " << path; plugin_version_code_t *plugin_version_code = dl.Sym("plugin_version_code"); LOG(INFO) << "Enable plugin success"; LOG(INFO) << " version code: " << plugin_version_code(); LOG(INFO) << " path: " << path; plugin_create_t *plugin_create = dl.Sym("plugin_create"); plugin_destroy_t *plugin_destroy = dl.Sym("plugin_destroy"); std::shared_ptr plugin(plugin_create(), plugin_destroy); plugin->OnCreate(this); synthetic_->SetPlugin(plugin); } std::shared_ptr API::device() { return device_; } void API::CheckImageParams() { if (device_ != nullptr) { bool in_l_ok, in_r_ok, ex_l2r_ok; device_->GetIntrinsics(Stream::LEFT, &in_l_ok); device_->GetIntrinsics(Stream::RIGHT, &in_r_ok); device_->GetExtrinsics(Stream::LEFT, Stream::RIGHT, &ex_l2r_ok); if (!in_l_ok || !in_r_ok || !ex_l2r_ok) { LOG(FATAL) << "Image params not found, but we need it to process the " "images. Please `make tools` and use `img_params_writer` " "to write the image params. If you update the SDK from " "1.x, the `SN*.conf` is the file contains them. Besides, " "you could also calibrate them by yourself. Read the guide " "doc (https://github.com/slightech/MYNT-EYE-SDK-2-Guide) " "to learn more."; } } } MYNTEYE_END_NAMESPACE