GStreamer —— 2.7、Windows下Qt加载GStreamer库后运行 - “教程7:多线程和 Pad 可用性“(附:完整源码)
运行效果(音频)
简介
上一个教程演示了媒体格式和Pad功能。本教程介绍多线程和 Pad 可用性。GStreamer 会自动处理多线程,但是,在某些 情况下,您可能需要手动解耦线程。这 教程 演示如何执行此作,此外,还完成了 Exposition 关于 Pad 可用性。更准确地说,本文档解释了:
• 如何为 管道
• 什么是 Pad 可用性
• 如何复制流
GStreamer 是一个多线程框架。这意味着在内部它根据需要创建和销毁线程,例如,解耦 从应用程序线程流式传输。此外,插件也是免费的 创建用于自身处理的线程,例如,视频解码器 可以创建 4 个线程以充分利用具有 4 个内核的 CPU。最重要的是,在构建管道时,应用程序可以指定 明确地,分支(管道的一部分)在不同的 thread 中执行 同时)。这是使用 element 完成的,其工作方式如下。 sink pad 只是将数据排入队列并返回控制权。在不同的 thread,数据将出列并推送到下游。此元素也是 用于缓冲,如后面的流式处理教程所示。
源是合成音频信号(连续音调),即 使用 Element 进行 split(它通过其源 pad 发送所有内容 它通过其 Sink Pad 接收)。然后,一个分支将信号发送到 Audio Card 和 Present 的 Alpha S 的 S 的 S Alpha S 的 它到屏幕上。如图所示,队列会创建一个新线程,因此此管道 在 3 个线程中运行。具有多个 sink 的管道通常需要 multithreaded,因为要同步,sink 通常会阻塞 执行,直到所有其他 sink 都准备就绪,如果 只有一个线程被第一个 sink 阻塞。
GStreamer相关运行库
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/gstreamer-1.0/gst
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/gstreamer-1.0
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/glib-2.0
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/lib/glib-2.0/include
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gstreamer-1.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/glib-2.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gobject-2.0.lib
完整源码
#include <gst/gst.h>
int main(int argc, char *argv[])
{
/* 初始化GStreamer */
gst_init (&argc, &argv);
/* 创建元素 */
GstElement *audio_source = gst_element_factory_make ("audiotestsrc", "audio_source");
GstElement *tee = gst_element_factory_make ("tee", "tee");
GstElement *audio_queue = gst_element_factory_make ("queue", "audio_queue");
GstElement *audio_convert = gst_element_factory_make ("audioconvert", "audio_convert");
GstElement *audio_resample = gst_element_factory_make ("audioresample", "audio_resample");
GstElement *audio_sink = gst_element_factory_make ("autoaudiosink", "audio_sink");
GstElement *video_queue = gst_element_factory_make ("queue", "video_queue");
GstElement *visual = gst_element_factory_make ("wavescope", "visual");
GstElement *video_convert = gst_element_factory_make ("videoconvert", "csp");
GstElement *video_sink = gst_element_factory_make ("autovideosink", "video_sink");
/* 创建空管道 */
GstElement *pipeline = gst_pipeline_new ("test-pipeline");
if (!pipeline || !audio_source || !tee || !audio_queue || !audio_convert || !audio_resample || !audio_sink || !video_queue || !visual || !video_convert || !video_sink)
{ g_printerr ("Not all elements could be created.\n"); return -1; }
/* 配置元素 */
g_object_set (audio_source, "freq", 215.0f, NULL);
g_object_set (visual, "shader", 0, "style", 1, NULL);
/* 链接所有可以自动链接的元素,因为它们有"Always"的pod */
gst_bin_add_many (GST_BIN (pipeline), audio_source, tee, audio_queue, audio_convert, audio_resample, audio_sink, video_queue, visual, video_convert, video_sink, NULL);
if (gst_element_link_many (audio_source, tee, NULL) != TRUE ||
gst_element_link_many (audio_queue, audio_convert, audio_resample, audio_sink, NULL) != TRUE ||
gst_element_link_many (video_queue, visual, video_convert, video_sink, NULL) != TRUE)
{
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline); return -1;
}
/* 手动连接带有"Request"的pads */
GstPad *tee_audio_pad = gst_element_request_pad_simple (tee, "src_%u");
g_print ("Obtained request pad %s for audio branch.\n", gst_pad_get_name (tee_audio_pad));
GstPad *queue_audio_pad = gst_element_get_static_pad (audio_queue, "sink");
GstPad *tee_video_pad = gst_element_request_pad_simple (tee, "src_%u");
g_print ("Obtained request pad %s for video branch.\n", gst_pad_get_name (tee_video_pad));
GstPad *queue_video_pad = gst_element_get_static_pad (video_queue, "sink");
if (gst_pad_link (tee_audio_pad, queue_audio_pad) != GST_PAD_LINK_OK || gst_pad_link (tee_video_pad, queue_video_pad) != GST_PAD_LINK_OK)
{
g_printerr ("Tee could not be linked.\n");
gst_object_unref (pipeline); return -1;
}
gst_object_unref (queue_audio_pad);
gst_object_unref (queue_video_pad);
/* 开始播放管道 */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* 等待错误或EOS */
GstBus *bus = gst_element_get_bus (pipeline);
GstMessage *msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
/* 释放请求的pad从tee中,然后释放 */
gst_element_release_request_pad (tee, tee_audio_pad);
gst_element_release_request_pad (tee, tee_video_pad);
gst_object_unref (tee_audio_pad);
gst_object_unref (tee_video_pad);
/* 释放资源 */
if (msg != NULL)
gst_message_unref (msg);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
关注
笔者 - jxd