使用非静态消息处理程序获取gstreamer总线消息

时间:2019-02-25 10:16:50

标签: c++ static gstreamer pipeline static-members

我使用gstreamer创建了一个程序,该程序侦听rtp数据包的不同端口 (例如5)

现在,我已经创建了一个类 (例如GstClass) ,该类创建了管道,并具有了一个回调函数,可以监听总线消息(我需要这个消息系统以在特定超时后关闭管道)

主要功能如下所示-使用2个对象创建2个线程,并在两个线程中调用GstFunc。第一个功能监听端口5000 ,第二个功能监听端口5008

int main() {

    char filepath1[ ]= "/home/rohan/Tornado1.raw";
    char filepath2[ ]= "/home/rohan/Tornado2.raw";
    unsigned int port1 = 5000;
    unsigned int port2 = 5008;

    GstClass GstObj1;
    GstClass GstObj2;

    boost::thread thrd1 { &GstClass::GstFunc, &GstObj1, filepath1, &port1 };
    boost::thread thrd2 { &GstClass::GstFunc, &GstObj2, filepath2, &port2 };

    thrd1.join();
    thrd2.join();

    return 0;
}

GstClass看起来像这样-

class GstClass {
protected:
    //some other variables...
    GMainLoop *msLoop;

public:

    gboolean bus_call(GstBus *bus, GstMessage *message,
        gpointer data);

    void GstFunc(char *filepath, unsigned int *port);

};

有关详细功能视图,请查看this example。进行适当更改后,将功能int main (int argc, char *argv[])替换为void GstFunc(char *filepath, unsigned int *port)

GstFunc看起来像

void GstFunc(char *filepath, unsigned int *port)
    GMainLoop *loop;
    GstElement *pipeline, *source, *conv, *sink;
    GstBus *bus;
    guint bus_watch_id;

    gst_init (NULL, NULL);

    loop = g_main_loop_new (NULL, FALSE);

    /* Create gstreamer elements */
    pipeline = gst_pipeline_new ("audio-player");
    source   = gst_element_factory_make ("autoaudiosrc",       "audiosource");
    conv     = gst_element_factory_make ("audioconvert",  "converter");
    sink     = gst_element_factory_make ("autoaudiosink", "audio-output");

    if (!pipeline || !source || !conv || !sink) {
          g_printerr ("One element could not be created. Exiting.\n");
          return -1;
    }
    /* we add a message handler */
    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
    bus_watch_id = gst_bus_add_watch (bus, bus_call, NULL);
    gst_object_unref (bus);

    gst_bin_add_many (GST_BIN (pipeline), source, conv, sink, NULL);
    gst_element_link_many (GST_BIN (pipeline), source, conv, sink, NULL);

    g_main_loop_run (loop);

    gst_element_set_state (pipeline, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT (pipeline));
    g_source_remove (bus_watch_id);
    g_main_loop_unref (loop);

    return 0;
}

现在我面临的困境是静态函数(例如) bus_call(...)

由于我正在2个不同的线程中创建2个管道,它们正在侦听2个不同的端口,因此我不能将此功能设为静态(在对象之间共享)。如何使这2条管道互不相交?或者如何使此静态bus_call(...)变为非静态的?

仅删除静态关键字并没有帮助,并显示此错误

  

错误:无效使用了非静态成员函数‘gboolean GstClass :: bus_call(GstBus *,GstMessage *,gpointer)’

少量展示点

我已经提到this document,它表示要使用总线,请使用gst_bus_add_watch()

将消息处理程序附加到管道的总线上

gst_bus_add_watch() (用于回调bus_call)中的GstClass::GstFunc()映射到头文件 gstbus.h ,声明为简单地

GST_API
guint gst_bus_add_watch(GstBus * bus, GstBusFunc func, gpointer user_data);

我最初的猜测是gst_bus_add_watch期望第二个参数是静态函数。我不确定为什么。在这里可以做什么?

************************ 问题编辑2 ************ *********

是否可以像bus_call一样向gboolean bus_call(GstBus *bus, GstMessage *message,gpointer data,**SOME POINTER TO THE OBJECT**)添加参数?

这样,该函数将保持静态,同时具有指向调用它的对象的指针并作用于对象(例如该对象的封闭管道)

1 个答案:

答案 0 :(得分:2)

我认为您无法摆脱想要的东西。回调GstBusFunc()的签名是指向函数的指针,而不是指向成员函数的指针。他们是different things。 (我也用std :: bind,fwiw失败了)。

我所做的事情与您所描述的非常相似,尽管不尽相同,但是我采取了不同的方法可能会对您有所帮助。您可以使用静态方法,但是必须将指向管道类的指针传递给gst_bus_add_watch。在busCallback内部,您取消指针的引用,然后离开!您可能还需要实现某种锁定方案。

class MyPipeline {

   GstElement *m_pipeline;

   public:

   MyPipeline(...);
   static void gboolean busCallback(GstBus *bus, GstMessage *msg, gpointer p);

}

MyPipeline::MyPipeline(...)
{
    // create pipeline...

    m_pipeline = ...;

    // bus callback, pass 'this' as arg for callback

    GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
    gst_bus_add_watch(bus, &MyPipeline::busCallback, this);
    gst_object_unref(bus);

    // ...
}

gboolean MyPipeline::busCallback(GstBus *, GstMessage *msg, gpointer p)
{

    // get lock if needed...

    // recover your class instance
    MyPipeline *myPipeline = (MyPipeline *)p;

    // do what you need to, free lock

    return TRUE;
}