You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
5.5 KiB
129 lines
5.5 KiB
/* License: Apache 2.0. See LICENSE file in root directory.
|
|
Copyright(c) 2017 Intel Corporation. All Rights Reserved. */
|
|
|
|
#include "pyrealsense2.h"
|
|
#include <librealsense2/rs.hpp>
|
|
#include <librealsense2/hpp/rs_export.hpp>
|
|
#include <src/types.h>
|
|
|
|
PYBIND11_MODULE(NAME, m) {
|
|
m.doc() = R"pbdoc(
|
|
LibrealsenseTM Python Bindings
|
|
==============================
|
|
Library for accessing Intel RealSenseTM cameras
|
|
)pbdoc";
|
|
m.attr("__version__") = RS2_API_VERSION_STR;
|
|
m.attr("__full_version__") = RS2_API_FULL_VERSION_STR;
|
|
|
|
init_c_files(m);
|
|
init_types(m);
|
|
init_frame(m);
|
|
init_options(m);
|
|
init_processing(m);
|
|
init_sensor(m);
|
|
init_device(m);
|
|
init_record_playback(m);
|
|
init_context(m);
|
|
init_pipeline(m);
|
|
init_internal(m); // must be run after init_frame()
|
|
init_export(m);
|
|
init_advanced_mode(m);
|
|
init_serializable_device(m);
|
|
init_util(m);
|
|
|
|
/** rs_export.hpp **/
|
|
py::class_<rs2::save_to_ply, rs2::filter>(m, "save_to_ply")
|
|
.def(py::init<std::string, rs2::pointcloud>(), "filename"_a = "RealSense Pointcloud ", "pc"_a = rs2::pointcloud())
|
|
.def_property_readonly_static("option_ignore_color", [](py::object) { return rs2::save_to_ply::OPTION_IGNORE_COLOR; })
|
|
.def_property_readonly_static("option_ply_mesh", [](py::object) { return rs2::save_to_ply::OPTION_PLY_MESH; })
|
|
.def_property_readonly_static("option_ply_binary", [](py::object) { return rs2::save_to_ply::OPTION_PLY_BINARY; })
|
|
.def_property_readonly_static("option_ply_normals", [](py::object) { return rs2::save_to_ply::OPTION_PLY_NORMALS; })
|
|
.def_property_readonly_static("option_ply_threshold", [](py::object) { return rs2::save_to_ply::OPTION_PLY_THRESHOLD; });
|
|
|
|
m.def("log_to_console", &rs2::log_to_console, "min_severity"_a);
|
|
m.def("log_to_file", &rs2::log_to_file, "min_severity"_a, "file_path"_a);
|
|
m.def("reset_logger", &rs2::reset_logger);
|
|
m.def("enable_rolling_log_file", &rs2::enable_rolling_log_file, "max_size"_a);
|
|
|
|
// Access to log_message is only from a callback (see log_to_callback below) and so already
|
|
// should have the GIL acquired
|
|
py::class_<rs2::log_message> log_message(m, "log_message");
|
|
log_message.def("line_number", &rs2::log_message::line_number)
|
|
.def("filename", &rs2::log_message::filename)
|
|
.def("raw", &rs2::log_message::raw)
|
|
.def("full", &rs2::log_message::full)
|
|
.def("__str__", &rs2::log_message::raw)
|
|
.def("__repr__", &rs2::log_message::full);
|
|
|
|
// We want to enable Python callbacks for logging, but need to be careful:
|
|
// The machanism used by librealsense keeps a pointer to an object that is then released
|
|
// on destruction/exit. Usually this works fine, except that here, with Python and its GIL,
|
|
// Pybind tries to acquire the GIL when the thread state is no longer valid and we get
|
|
// into an infinite wait.
|
|
#if 0
|
|
m.def( "log_to_callback",
|
|
[]( rs2_log_severity min_severity, std::function< void( rs2_log_severity, rs2::log_message ) > callback )
|
|
{
|
|
py::gil_scoped_release gil;
|
|
rs2::log_to_callback( min_severity,
|
|
[callback]( rs2_log_severity severity, rs2::log_message const & msg ) noexcept
|
|
{
|
|
py::gil_scoped_acquire gil;
|
|
callback( severity, msg );
|
|
} );
|
|
} );
|
|
#else
|
|
// Instead, as a workaround, we override the usual mechanism to intentionally not free up
|
|
// if we see the Python thread state isn't valid (see release() below):
|
|
class py_log_callback : public rs2::log_callback
|
|
{
|
|
typedef rs2::log_callback super;
|
|
|
|
public:
|
|
py_log_callback( log_fn && on_log )
|
|
: super( std::move( on_log ) )
|
|
{
|
|
}
|
|
|
|
void on_log( rs2_log_severity severity, rs2_log_message const & msg ) noexcept override
|
|
{
|
|
try
|
|
{
|
|
// We're not being called from Python but instead are calling it,
|
|
// we need to acquire it to not have issues with other threads...
|
|
py::gil_scoped_acquire gil;
|
|
super::on_log( severity, msg );
|
|
}
|
|
catch( std::exception const & e )
|
|
{
|
|
std::cerr << "EXCEPTION in " SNAME ".log_to_callback: " << e.what() << std::endl;
|
|
}
|
|
catch( ... )
|
|
{
|
|
std::cerr << "UNKNOWN EXCEPTION in " SNAME ".log_to_callback" << std::endl;
|
|
}
|
|
}
|
|
|
|
void release() override
|
|
{
|
|
// When we exit() python, we get here with an invalid thread-state and the delete
|
|
// locks the thread indefinitely!
|
|
if( PyGILState_GetThisThreadState() )
|
|
super::release();
|
|
}
|
|
};
|
|
m.def( "log_to_callback",
|
|
[]( rs2_log_severity min_severity, py_log_callback::log_fn callback )
|
|
{
|
|
rs2_error * e = nullptr;
|
|
py::gil_scoped_release gil;
|
|
rs2_log_to_callback_cpp( min_severity, new py_log_callback( std::move( callback ) ), &e );
|
|
rs2::error::handle( e );
|
|
} );
|
|
#endif
|
|
|
|
// A call to rs.log() will cause a callback to get called! We should already own the GIL, but
|
|
// release it just in case to let others do their thing...
|
|
m.def("log", &rs2::log, "severity"_a, "message"_a, py::call_guard<py::gil_scoped_release>());
|
|
}
|