1

I want to use this python module: https://python-omxplayer-wrapper.readthedocs.io/en/latest/ on my c++ app.

It is a omxplayer python wrapper and has some callback events that I want to link to my c++ class function member.

I did it with success using a static function like this:

void foo(py::object player) { 
    std::cout << "pause event callback" << std::endl; 
}

py::object mod = py::import("omxplayer.player");

OMXPlayer::pyOMXPlayer = mod.attr("OMXPlayer")(_file, args, NULL, NULL, _dbus_name, _pause);

OMXPlayer::pyOMXPlayer.attr("pauseEvent") = py::make_function( &foo );

Where OMXPlayer is my c++ class.

I tried to use boost::bind and boost::function without success.

How can use OMXPlayer::onPause() function instead of static foo function?

Edit with example:

OMXPlayer.cpp

    #include "OMXPlayer.h"
    OMXPlayer::OMXPlayer(std::string _file, 
        std::vector<std::string> _args, 
        bool _pause, 
        std::string _dbus_name){
    
    
    try{
        Py_Initialize();
        py::object mod = py::import("omxplayer.player");
        
        
        py::list args;
        for(auto const& value: _args) {
            args.append(value);
        }
        
        

        OMXPlayer::pyOMXPlayer = mod.attr("OMXPlayer")(_file, args, NULL, NULL, _dbus_name, _pause);
        
        pyOMXPlayer.attr("pauseEvent"   ) = py::make_function(&OMXPlayer::onPause);
        
        OMXPlayer::active = false;

    }
    catch(py::error_already_set){
        PyErr_Print();
    }

}


void OMXPlayer::onPause(){
    std::cout << "onPause" << std::endl;
}

void OMXPlayer::pause(){
    try{
        OMXPlayer::pyOMXPlayer.attr("pause")();
    }
    catch(py::error_already_set){
        PyErr_Print();
    }
}

OMXPlayer.h

#include <boost/python.hpp>
#include <boost/function.hpp>

#include <vector>
#include <iostream>
#include <atomic>

namespace py = boost::python;

class OMXPlayer{
    public:
        OMXPlayer(std::string _file, 
            std::vector<std::string> _args, 
            bool _pause = false, 
            std::string _dbus_name = "");
        
        void pause();
        void onPause();
};

main.cpp function:

#include "OMXPlayer.h"

int main(){
    
    OMXPlayer player1("/root/Setteventi.mp4", std::vector<std::string> {"--loop"}, false, "org.mpris.MediaPlayer2.omxplayer1");

    player1.pause();


}

You can see the python Class from here: https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/

When eventPause on python side is called it throw this:

Traceback (most recent call last):
  File "<decorator-gen-56>", line 2, in pause
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 48, in wrapped
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 550, in pause
    self.pauseEvent(self)
Boost.Python.ArgumentError: Python argument types in
    None.None(OMXPlayer)
did not match C++ signature:
    None(OMXPlayer {lvalue})
Traceback (most recent call last):
  File "<decorator-gen-56>", line 2, in pause
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 48, in wrapped
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 550, in pause
    self.pauseEvent(self)
Boost.Python.ArgumentError: Python argument types in
    None.None(OMXPlayer)
did not match C++ signature:
    None(OMXPlayer {lvalue})
8
  • 1
    From the boost docs: "If F is a pointer-to-member-function type, the target object of the function call (*this) will be taken from the first Python argument, and subsequent Python arguments will be used as the arguments to f." So, did you try to simply pass &OMXPLayer::onPause? What is the result? Show the complete example. Commented Jul 24, 2020 at 10:08
  • 1
    Yes I have already tried how you say, but it doesn't work because the function signature is different, as you can see from my edited example. Commented Jul 24, 2020 at 14:23
  • Mmm true, because python calls it with self that is a different OMXPlayer class. And if you boost::bind or std::bind the this pointer, what is the error? Commented Jul 24, 2020 at 14:32
  • I can't or I don't know how. If I just try with: pyOMXPlayer.attr("pauseEvent" ) = py::make_function( boost::bind(&OMXPlayer::onPause, this) ); It will not compile with error: /usr/include/boost/python/make_function.hpp:104:57: error: no matching function for call to ‘get_signature(boost::_bi::bind_t<void, boost::_mfi::mf0<void, OMXPlayer>, boost::_bi::list1<boost::_bi::value<OMXPlayer*> > >&)’ f,default_call_policies(), detail::get_signature(f)); make_function require a function and boost:bind return a object. Commented Jul 24, 2020 at 14:49
  • Should be more or less: py::make_function(boost::bind(&OMXPlayer::onPause, this)); Or maybe rather py::make_function(boost::bind(&OMXPlayer::onPause, this, _1)); and the signature: void onPause(py::object player) because python calls it with one argument. Or with standard library: py::make_function(std::bind(&OMXPlayer::onPause, this, std::placeholders::_1)); Sorry for not being more precise, today I don't have any good environment to try your code. Commented Jul 24, 2020 at 14:53

1 Answer 1

1

Ok, with @pptaszni help I found how to do it.

The problem was that boost could not detarmine the function signature because boost::bind return a function object.

To avoid this problem, I have to specify the signature when call make_function.

Example:

pyOMXPlayer.attr("pauseEvent") = py::make_function( boost::bind(&OMXPlayer::onPause, this, _1), py::default_call_policies(), boost::mpl::vector<void, py::object>() );

The tricky part is the last argument of py::make_function

Thanks @pptaszni

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.