C ++如何使用lambdas将ffmpeg的av_log_set_callback()设置为成员函数? [英] c++ how to use lambdas to set ffmpeg's av_log_set_callback() to a member function?

查看:82
本文介绍了C ++如何使用lambdas将ffmpeg的av_log_set_callback()设置为成员函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究如何使用lambda作为回调,但是我的语法似乎并不正确.我正在通过Visual Studio 2013社区使用C ++,我很确定可以支持这种类型的lambda使用.我正在开发基于FFMPEG libav库的视频库.

I've been researching how to use lambdas as callbacks, but I do not seem to be getting my syntax correct. I am working in C++ via Visual Studio 2013 Community, & I am pretty sure this type of lambda use is supported. I am working on a video library which is based on the FFMPEG libav libraries.

基本问题是提供给FFMPEG libav库客户端的日志记录回调.它具有以下调用结构:

The basic issue is the logging callback provided to library clients of FFMPEG's libav. It has this calling structure:

void logging_callback( void *ptr, int level, const char *fmt, va_list vargs  );

这对于C来说很好,对于C ++而言,当日志记录回调是一个静态成员函数时也很好,但是我想安装一个类成员函数,根据C ++的调用性质,它需要 this 参数方法功能.

This is fine for C or fine for C++ when the logging callback is a static member function, but I want to install a class member function, which needs the this parameter per the C++ nature of calling method functions.

到目前为止,我的状态如下:(删除了不相关的部分)

What I have so far looks like: (unrelated portions removed)

class my_libav
{ 
   // logging messages callback for use by library client, any log messages generated 
   // by the library will be sent thru this to the lib client's logic:
   typedef void(*STREAM_LOGGING_CALLBACK_CB) (std::string msg, void* p_object);

   // my lib's logger has a void* param so clients can redirect to member functs easier
   void SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger, void* p_object);

   // member function to be installed as FFMPEG's av_log_set_callback():
   void RedirectLoggingOutputs( void *ptr, int level, const char *fmt, va_list vargs );

   STREAM_LOGGING_CALLBACK_CB  mp_stream_logging_callback; // client's callback
   void*                       mp_stream_logging_object;   // client's data

};

void my_libav::SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger, void* p_object)
{
  mp_stream_logging_callback = p_stream_logger;
  mp_stream_logging_object = p_object;
}

void my_libav::RedirectLoggingOutputs(void *ptr, int level, const char *fmt, va_list vargs )
{
  // logic that resolves the message and sends through client's callback
  // installed int mp_stream_logging_callback
}

my_libav::my_libav()
{
  // this is the old static member function I deleted:
  // av_log_set_callback( &my_libav::logging_callback );

  // I tried using std::bind & placeholders, but this syntax is wrong too:
  // namespace ph = std::placeholders;
  // auto callback = std::bind( &my_libav::RedirectLoggingOutputs, this, ph::_1, ph::_2, ph::_3, ph::_4 );
  // 
  // av_log_set_callback( callback ); // <- 'callback' is not the correct type

  // this is my try at a lambda. I know that the *this* cannot be 
  // in the capture, but I don't know the right syntax to work around 
  // this issue:
  std::function<void(void *ptr, int level, const char *fmt, va_list vargs )> 
        f2 = [this](void *ptr, int level, const char *fmt, va_list vargs ){
                        RedirectLoggingOutputs( ptr, level, fmt, vargs ); };

    av_log_set_callback( f2 ); // <- 'f2' is not the correct type, how to fix? 

我要修复的语法在最后4行中.正确的格式是什么?

The syntax I am trying to fix is in the last 4 lines. What is the correct form?

推荐答案

FFMPEG是C风格的库.您不能使用捕获 lambda或 std :: function 来获取C样式的函数指针.因此,在这种情况下,您必须为 av_log_set_callback()回调使用独立的函数或静态类方法.

FFMPEG is a C style library. You can't use a capturing lambda, or a std::function, where a C-style function pointer is expected. So, in this situation, you will have to stick with using a standalone function, or a static class method, for your av_log_set_callback() callback.

av_log_set_callback()不允许您将用户定义的值传递给回调,并且一次只能激活1个回调.由于您要在回调中使用类的 this 指针,因此一次只能使用一个类的实例,并且必须使用全局变量来传递指向回调的指针.

av_log_set_callback() does not allow you to pass a user-defined value to the callback, and you can only have 1 callback active at a time. Since you want to use your class's this pointer with your callback, you will be able to use only 1 instance of your class at a time, and you will have to use a global variable to pass your this pointer to your callback.

尝试这样的事情:

class my_libav
{ 
public:
    typedef void (*STREAM_LOGGING_CALLBACK_CB)(std::string msg, void* p_object);

    my_libav();
    my_libav(const my_libav &) = delete;
    ~my_libav();
    my_libav& operator=(const my_libav &) = delete;

    void SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger, void* p_object);

private:
    STREAM_LOGGING_CALLBACK_CB  mp_stream_logging_callback = nullptr;
    void*                       mp_stream_logging_object = nullptr;

    static void RedirectLoggingOutputs( void *ptr, int level, const char *fmt, va_list vargs );
};

static my_libav *g_mylibav = nullptr;

my_libav::my_libav()
{
    if (g_mylibav) throw std::runtime_error("Only 1 instance of my_libav is allowed at a time!");
    g_mylibav = this;
    av_log_set_callback( &my_libav::RedirectLoggingOutputs );
}

my_libav::~my_libav()
{
    av_log_set_callback( nullptr );
    g_mylibav = nullptr;
}

void my_libav::SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger, void* p_object)
{
    mp_stream_logging_callback = p_stream_logger;
    mp_stream_logging_object = p_object;
}

void my_libav::RedirectLoggingOutputs(void *ptr, int level, const char *fmt, va_list vargs )
{
    std::string msg;
    ...
    if (g_mylibav->mp_stream_logging_callback)
        g_mylibav->mp_stream_logging_callback(msg, g_mylibav->mp_stream_logging_object);
}

或者,使用单例模式来确保仅存在1个实例:

Or, use a singleton pattern to ensure only 1 instance exists:

class my_libav
{ 
public:
    typedef void (*STREAM_LOGGING_CALLBACK_CB)(std::string msg, void* p_object);

    ~my_libav();    

    static my_libav& getInstance();

    void SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger, void* p_object);

private:
    STREAM_LOGGING_CALLBACK_CB  mp_stream_logging_callback = nullptr;
    void*                       mp_stream_logging_object = nullptr;

    my_libav();
    my_libav(const my_libav &) = delete;
    my_libav& operator=(const my_libav &) = delete;

    static void RedirectLoggingOutputs( void *ptr, int level, const char *fmt, va_list vargs );
};

static my_libav *g_mylibav = nullptr;

my_libav::my_libav()
{
    g_mylibav = this;
    av_log_set_callback( &my_libav::RedirectLoggingOutputs );
}

my_libav::~my_libav()
{
    av_log_set_callback( nullptr );
    g_mylibav = nullptr;
}

my_libav& my_libav::getInstance()
{
    static my_libav inst;
    return inst;
}

void my_libav::SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger, void* p_object)
{
    mp_stream_logging_callback = p_stream_logger;
    mp_stream_logging_object = p_object;
}

void my_libav::RedirectLoggingOutputs(void *ptr, int level, const char *fmt, va_list vargs )
{
    std::string msg;
    ...
    if (g_mylibav->mp_stream_logging_callback)
        g_mylibav->mp_stream_logging_callback(msg, g_mylibav->mp_stream_logging_object);
}

顺便提一句,由于无论如何您都使用C ++ 11或更高版本,因此您可以考虑使用 std :: function 用于客户端回调,然后客户端可以使用任何 bind表达式或其他函数对象,以及指向成员函数的指针和指向数据成员的指针",而不必来回传递单独的 void * :

On a side note, since you are using C++11 or later anyway, you might consider using std::function for your client callback, then a client can use "any Callable target -- function, lambda expression, bind expression, or other function object, as well as a pointer to member function and pointer to data member", and not have to pass around a separate void* back and forth:

class my_libav
{ 
public:
    typedef std::function<void(std::string)> STREAM_LOGGING_CALLBACK_CB;

    ...

    void SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger);

private:
    STREAM_LOGGING_CALLBACK_CB  mp_stream_logging_callback;

    ...

    static void RedirectLoggingOutputs( void *ptr, int level, const char *fmt, va_list vargs );
};

void my_libav::SetStreamLoggingCallback(STREAM_LOGGING_CALLBACK_CB p_stream_logger)
{
    mp_stream_logging_callback = p_stream_logger;
}

void my_libav::RedirectLoggingOutputs(void *ptr, int level, const char *fmt, va_list vargs )
{
    std::string msg;
    ...
    if (g_mylibav->mp_stream_logging_callback)
        g_mylibav->mp_stream_logging_callback(msg);
}

这篇关于C ++如何使用lambdas将ffmpeg的av_log_set_callback()设置为成员函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆