#if defined(ENABLE_PYTHON) #include "pyinvoker.h" #include #include #include #include #include using namespace toolkit; using namespace mediakit; template auto to_python(const T &obj) -> typename std::enable_if::value, py::capsule>::type { static auto name_str = toolkit::demangle(typeid(T).name()); auto p = new toolkit::Any(std::make_shared(obj)); return py::capsule(p, name_str.data(), [](PyObject *capsule) { auto p = reinterpret_cast(PyCapsule_GetPointer(capsule, name_str.data())); delete p; TraceL << "delete " << name_str << "(" << p << ")"; }); } template auto to_python(const T &obj) -> typename std::enable_if::value, py::capsule>::type { static auto name_str = toolkit::demangle(typeid(T).name()); auto p = new toolkit::Any(std::shared_ptr(const_cast(&obj), [](T *) {})); return py::capsule(p, name_str.data(), [](PyObject *capsule) { auto p = reinterpret_cast(PyCapsule_GetPointer(capsule, name_str.data())); delete p; TraceL << "unref " << name_str << "(" << p << ")"; }); } template T &to_native(const py::capsule &cap) { static auto name_str = toolkit::demangle(typeid(T).name()); if (std::string(cap.name()) != name_str) { throw std::runtime_error("Invalid capsule name!"); } auto any = reinterpret_cast(cap.get_pointer()); return any->get(); } mINI to_native(const py::dict &opt) { mINI ret; for (auto &item : opt) { // 转换为字符串(允许 int/float/bool 等) ret.emplace(py::str(item.first).cast(), py::str(item.second).cast()); } return ret; } PYBIND11_EMBEDDED_MODULE(mk_loader, m) { m.def("log", [](int lev, const char *file, int line, const char *func, const char *content) { py::gil_scoped_release release; LoggerWrapper::printLog(::toolkit::getLogger(), lev, file, func, line, content); }); m.def("mk_publish_auth_invoker_do", [](const py::capsule &cap, const std::string &err, const py::dict &opt) { ProtocolOption option; option.load(to_native(opt)); // 执行c++代码时释放gil锁 py::gil_scoped_release release; auto &invoker = to_native(cap); invoker(err, option); }); } namespace mediakit { inline bool set_env(const char *name, const char *value) { #if defined(_WIN32) std::string env_str = std::string(name) + "=" + value; return _putenv(env_str.c_str()) == 0; #else return setenv(name, value, 1) == 0; // overwrite = 1 #endif } bool set_python_path() { const char *env_var = std::getenv("PYTHONPATH"); if (env_var && *env_var) { PrintI("PYTHONPATH is already set to: %s", env_var); return false; } auto default_path = exeDir() + "/python"; // 1 表示覆盖已存在的值 if (!set_env("PYTHONPATH", default_path.data())) { PrintW("Failed to set PYTHONPATH"); return false; } PrintI("PYTHONPATH was not set. Set to default: %s", default_path.data()); return true; } PythonInvoker &PythonInvoker::Instance() { static std::shared_ptr instance(new PythonInvoker); return *instance; } PythonInvoker::PythonInvoker() { // 确保日志一直可用 _logger = Logger::Instance().shared_from_this(); set_python_path(); // 确保 PYTHONPATH 在第一次调用时设置 _interpreter = new py::scoped_interpreter; _rel = new py::gil_scoped_release; } PythonInvoker::~PythonInvoker() { { py::gil_scoped_acquire gil; // 加锁 if (_on_exit) { _on_exit(); } _on_exit = py::object(); _on_publish = py::object(); _module = py::module(); } delete _rel; delete _interpreter; } void PythonInvoker::load(const std::string &module_name) { try { py::gil_scoped_acquire gil; // 加锁 _module = py::module::import(module_name.c_str()); if (hasattr(_module, "on_start")) { py::object on_start = _module.attr("on_start"); if (on_start) { on_start(); } } if (hasattr(_module, "on_exit")) { _on_exit = _module.attr("on_exit"); } if (hasattr(_module, "on_publish")) { _on_publish = _module.attr("on_publish"); } } catch (py::error_already_set &e) { PrintE("Python exception:%s", e.what()); } } bool PythonInvoker::on_publish(BroadcastMediaPublishArgs) { py::gil_scoped_acquire gil; // 确保在 Python 调用期间持有 GIL if (!_on_publish) { return false; } return _on_publish(getOriginTypeString(type), to_python(args), to_python(invoker), to_python(sender)).cast(); } } // namespace mediakit #endif