C ++如何使用lambdas将ffmpeg的av_log_set_callback()设置为成员函数? [英] c++ how to use lambdas to set ffmpeg's av_log_set_callback() to a member function?
问题描述
我一直在研究如何使用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
用于客户端回调,然后客户端可以使用任何 lambda表达式, 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屋!