使用QT来简单实现播放gstreamer的命令(一)

一、几条常用的gstreamer指令

        gstreamer是插件式的,我们一般测试的时候,都是使用命令行工具来测试功能,比如:

  • 播放一段测试视频流:gst-launch-1.0.exe videotestsrc ! autovideosink
  • 播放摄像头视频:

        window:

gst-launch-1.0.exe ksvideosrc ! image/jpeg,width=1280,height=720,framerate=30/1 ! jpegdec ! videoconvert ! autovideosink

        Linux:

gst-launch-1.0 v4l2 ! image/jpeg,width=1280,height=720,framerate=30/1 ! jpegdec ! videoconvert ! autovideosink

  • 实时将摄像头录制到视频文件:gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! x264enc ! mp4mux ! filesink location=output.mp4

        

但是!!!

如果我们想使用C++代码来测试的时候,比如使用QT来测试的时候,就没有那么容易了,需要写一大堆的代码来实现命令行非常简单的功能,那么是否有快速的方式呢?

最近还真的被我发现一种方式,实现起来会比较简单。

二、简单测试

原理非常简单,就是使用 pipeline 在创建的时候,使用 gst_parse_launch 即可。

比如我们实现播放播放测试视频流:

window的命令:

  • gst-launch-1.0.exe videotestsrc ! autovideosink

Linux的命令:

  • gst-launch-1.0 videotestsrc ! autovideosink

那么我们只需要在创建 pipeline 的时候,将gst-launch-1.0后面的内容,写在 gst_parse_launch 里面即可。例如刚刚的代码,就是 

GstElement *pipeline = gst_parse_launch("videotestsrc ! autovideosink", NULL);

实现效果:

使用QT来简单实现播放gstreamer的命令(一)_第1张图片

只能说,跟命令行的效果一样,但是我们可以在上面使用一些QT的元素。

下面是使用更加复杂的实现将摄像头数据进行播放的案例,大家基本上只需要更改gst_parse_launch的内容即可:

#include 
#include 
#include 
#include 
#include 

// Callback function to retrieve the actual video sink
static void on_child_added(GstChildProxy *proxy, GObject *object, gchar *name, gpointer user_data) {
    WId *window_handle = (WId *)user_data;
    if (GST_IS_VIDEO_OVERLAY(object)) {
        gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(object), (guintptr)(*window_handle));
    }
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget window;
    WId window_handle;

    gst_init(&argc, &argv);

    // Create GStreamer pipeline
    // 源代码是 gst-launch-1.0 ksvideosrc ! image/jpeg,width=1920,height=1080,framerate=30/1 ! jpegdec ! videoconvert ! autovideosink
    GstElement *pipeline = gst_parse_launch("ksvideosrc ! image/jpeg,width=1920,height=1080,framerate=30/1 ! jpegdec ! videoconvert ! autovideosink", NULL);

    // Get the sink element from the pipeline
    GstElement *sink = gst_bin_get_by_name(GST_BIN(pipeline), "autovideosink0");

    window.show();
    window_handle = window.winId();

    // Connect to child-added signal to retrieve the actual video sink
    g_signal_connect(sink, "child-added", G_CALLBACK(on_child_added), &window_handle);

    // Start playing
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    // Run the QT application loop
    int ret = app.exec();

    // Clean up
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(GST_OBJECT(pipeline));

    return ret;
}

三、中级用法:较复杂指令,更简洁代码

 1. 简单demo:显示在QT界面

#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    gst_init(&argc, &argv);

    // 准备pipeline
    GstElement *pipeline = gst_parse_launch ("playbin uri=file:home/enpht/Videos/1081.mp4", NULL);

    // 准备ui,Qwidget就行。是否显示无所谓。
    QWidget *window = new QWidget();
    window->resize(900, 600);
    window->show();

    // 将刚刚界面的WID传给gstreamer的sink
    GstElement *vsink = gst_element_factory_make ("ximagesink", "vsink");
    WId xwinid = window->winId();
    gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (vsink), xwinid);
    g_object_set(GST_OBJECT(pipeline), "video-sink", vsink, NULL);

    // 开始播放
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    int ret = app.exec();

    // 清除缓存
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(GST_OBJECT(pipeline));

    return ret;
}

2. 较复杂指令:

        这种方法,通过 gst_bin_get_by_name 获取到管道内的元素,然后设置属性。

#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget window;
    WId window_handle;

    gst_init(&argc, &argv);

    // 创建管道 pipeline
    GstElement *pipeline = gst_parse_launch("filesrc name=mysrc ! qtdemux name=demux demux.video_0 ! h264parse ! avdec_h264 ! videoconvert ! videoscale ! video/x-raw, width=640,height=480 ! ximagesink name=vsink", NULL);
    //GstElement *pipeline = gst_parse_launch("videotestsrc ! ximagesink name=vsink",NULL);

    // 设置管道中的属性
    GstElement *mysrc = gst_bin_get_by_name (GST_BIN (pipeline), "mysrc");
    g_object_set (mysrc, "location", "/home/enpht/Videos/1081.mp4", NULL);
    g_object_unref (mysrc);

    // 创建界面
    window.show();
    window_handle = window.winId();

    // 链接到QT:
    GstElement *vsink = gst_bin_get_by_name (GST_BIN (pipeline), "vsink");
    gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (vsink), window_handle);

    // Start playing
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    // Run the QT application loop
    int ret = app.exec();

    // Clean up
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(GST_OBJECT(pipeline));

    return ret;
}

四、后期优化计划

        但是后期测试发现,无法在widget上面添加控件,添加了无法正常显示,后续会想办法嵌入其他控件,或者将这个封装一层嵌入其他界面中。

你可能感兴趣的:(qt,开发语言)