【glib】g_timeout_add ()

在Gstreamer中,如果您要定时让程序去作某件事,则可以使用g_timeout_add()g_timeout_add_full().

1 函数原型

g_timeout_add 设置要定期调用的函数,默认优先级为G_PRIORITY_DEFAULT。 重复调用该函数,直到返回FALSE,这时超时将自动销毁,并且不会再次调用该函数。 该函数的第一个调用将在第一个间隔的结尾。

请注意,由于其他事件源的处理,超时功能可能会延迟。 因此,不应依赖它们来获得精确的时间。 每次调用超时功能后,都会根据当前时间和给定的间隔重新计算下一次超时的时间(它不会尝试“追赶”因延迟而损失的时间)。

guint g_timeout_add(guint interval,
					GSourceFunc function,
					gpointer data);
参数说明
intervalthe time between calls to the function, in milliseconds (1/1000ths of a second)
functionfunction to call
datadata to pass to function
Returnsthe ID (greater than 0) of the event source.

第一个参数是间隔的毫秒数,第二个参数是定时后的callback,第三个是传递给callback的数据。callback的形式如下:

gint timeout_callback(gpointer data);

g_timeout_add的返回值可以用来结束这个timeout,如下(假如返回放到tag中)

void g_source_remove(gint tag);

也可以让callback返回0或FALSE来结束timeout。

更多的参考可见 glib tutorial 相关章节:
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add

2 示例

2.1 示例1

// test-gmainloop.c
#include <stdio.h>
#include <glib.h>

static gboolean test_timeout (gpointer arg)
{
    printf("Hello World!\n");
    return TRUE;
}

int main()
{
    static GMainLoop *main_loop = NULL;
    main_loop = g_main_loop_new (NULL, FALSE);
    g_timeout_add (1000, test_timeout, NULL); // 1s
    g_main_loop_run (main_loop);
    return 0;
}

2.1.1 编译

gcc test-gmainloop.c -o test-gmainloop `pkg-config --cflags --libs glib-2.0`

2.1.2 结果

每隔1s中输出一次“Hello World!
在这里插入图片描述
注意:

  • g_timeout_add 必须在 g_main_loop_run 函数前使用,否则无效。
  • 如果1s上一个回调未完成,

2.2 示例2

本示例改编自:Gstreamer Basic tutorial 3: Dynamic pipelines

// basic-tutorial-3.c

#include <gst/gst.h>

/* Structure to contain all our information, so we can pass it to callbacks */
typedef struct _CustomData {
    GstElement *pipeline;
    GstElement *source;
    GstElement *convert;
    GstElement *sink;
    GMainLoop  *main_loop;  /* GLib's Main Loop */
} CustomData;

/* Handler for the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *pad, CustomData *data);
static gboolean gtimeout_callback (gpointer data);

static gboolean
bus_callback (GstBus * bus, GstMessage * message, gpointer data)
{
    CustomData *appCtx = (CustomData *) data;

    /* Parse message */
    if (message != NULL) {
        GError *err;
        gchar *debug_info;

        switch (GST_MESSAGE_TYPE (message))
        {
        case GST_MESSAGE_ERROR:
            gst_message_parse_error (message, &err, &debug_info);
            g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (message->src), err->message);
//            g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
            g_clear_error (&err);
            g_free (debug_info);
            break;
        case GST_MESSAGE_EOS:
            g_print ("End-Of-Stream reached.\n");
            //            GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(data.pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
            g_main_loop_quit(appCtx->main_loop);
            break;
        case GST_MESSAGE_STATE_CHANGED:
            /* We are only interested in state-changed messages from the pipeline */
            if (GST_MESSAGE_SRC (message) == GST_OBJECT (appCtx->pipeline)) {
                GstState old_state, new_state, pending_state;
                gst_message_parse_state_changed (message, &old_state, &new_state, &pending_state);
                g_print ("Pipeline state changed from %s to %s:\n",
                         gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
            }
            break;
        default:
            /* We should not reach here */
//            g_printerr ("Unexpected message received.\n");
            break;
        }
    }

    return TRUE;
}

int main(int argc, char *argv[]) {
    CustomData data;
    GstBus *bus;
    GstStateChangeReturn ret;

    //g_setenv("GST_DEBUG_DUMP_DOT_DIR", "/home/xxx", TRUE);

    /* Initialize GStreamer */
    gst_init (&argc, &argv);

    /* Create the elements */
    data.source = gst_element_factory_make ("uridecodebin", "source");
    // data.convert = gst_element_factory_make ("audioconvert", "convert");
    //data.sink = gst_element_factory_make ("autoaudiosink", "sink");
    data.convert = gst_element_factory_make ("videoconvert", "convert");
    data.sink = gst_element_factory_make ("autovideosink", "sink");

    /* Create the empty pipeline */
    data.pipeline = gst_pipeline_new ("test-pipeline");

    if (!data.pipeline || !data.source || !data.convert || !data.sink) {
        g_printerr ("Not all elements could be created.\n");
        return -1;
    }

    /* Build the pipeline. Note that we are NOT linking the source at this
   * point. We will do it later. */
    gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert , data.sink, NULL);
    if (!gst_element_link (data.convert, data.sink)) {
        g_printerr ("Elements could not be linked.\n");
        gst_object_unref (data.pipeline);
        return -1;
    }

    /* Set the URI to play */
    g_object_set (data.source, "uri", "file:///home/xxx/sample.mp4", NULL);

    /* Connect to the pad-added signal */
    g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data);

    /* Start playing */
    ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr ("Unable to set the pipeline to the playing state.\n");
        gst_object_unref (data.pipeline);
        return -1;
    }

    /* Create a GLib Main Loop and set it to run */
    data.main_loop = g_main_loop_new (NULL, FALSE);

    /* Listen to the bus */
    bus = gst_element_get_bus (data.pipeline);
    gst_bus_add_watch (bus, (GstBusFunc)bus_callback, &data);

    g_timeout_add(2000, gtimeout_callback, NULL);

    g_main_loop_run (data.main_loop);

    /* Free resources */
    g_main_loop_unref (data.main_loop);
    gst_object_unref (bus);
    gst_element_set_state (data.pipeline, GST_STATE_NULL);
    gst_object_unref (data.pipeline);
    return 0;
}

gboolean
gtimeout_callback (gpointer data)
{
    g_print ("#### Reset source pipeline %s \n", __func__);

    return FALSE;
//    return TRUE;
}


/* This function will be called by the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data)
{
    GstPad *sink_pad = gst_element_get_static_pad (data->convert, "sink");
    GstPadLinkReturn ret;
    GstCaps *new_pad_caps = NULL;
    GstStructure *new_pad_struct = NULL;
    const gchar *new_pad_type = NULL;

    g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));

    /* If our converter is already linked, we have nothing to do here */
    if (gst_pad_is_linked (sink_pad))
    {
        g_print ("We are already linked. Ignoring.\n");
        goto exit;
    }

    /* Check the new pad's type */
    new_pad_caps = gst_pad_get_current_caps (new_pad);
    new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
    new_pad_type = gst_structure_get_name (new_pad_struct);
    if (!g_str_has_prefix (new_pad_type, "video/x-raw"))
    {
        g_print ("It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
        goto exit;
    }

    /* Attempt the link */
    ret = gst_pad_link (new_pad, sink_pad);
    if (GST_PAD_LINK_FAILED (ret)) {
        g_print ("Type is '%s' but link failed.\n", new_pad_type);
    } else {
        g_print ("Link succeeded (type '%s').\n", new_pad_type);
    }

exit:
    /* Unreference the new pad's caps, if we got them */
    if (new_pad_caps != NULL)
        gst_caps_unref (new_pad_caps);

    /* Unreference the sink pad */
    gst_object_unref (sink_pad);
}

2.2.1 编译

gcc basic-tutorial-3.c -o basic-tutorial-3 `pkg-config --cflags --libs gstreamer-1.0`

2.2.2 结果

在这里插入图片描述

3 说明

g_timeout_add ()的回调函数必须有返回值为TURE。否则结果时钟只执行了一次就退出了。如上所示。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页