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

/* 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>());
}