当前位置: 首页 > article >正文

GStreamer —— 2.15、Windows下Qt加载GStreamer库后运行 - “播放教程 1:Playbin 使用“(附:完整源码)

运行效果

在这里插入图片描述

介绍

     我们已经使用了这个元素,它能够构建一个完整的播放管道,而无需做太多工作。 本教程介绍如何进一步自定义,以防其默认值不适合我们的特定需求。将学习:

          • 如何确定文件包含多少个流,以及如何切换 其中。

          • 如何收集有关每个流的信息。

     通常情况下,多个音频、视频和字幕流可以是嵌入在单个文件中。最常见的情况是常规电影,其中包含一个视频和音频流(立体声或 5.1 音轨被视为单个流)。它也越来越 常见查找具有一个视频和多个音频流的电影,以考虑不同的语言。在这种情况下,用户选择一个 audio 流,并且应用程序将仅播放该流。为了能够选择合适的流,用户需要知道有关他们的某些信息,例如他们的语言。这 信息以 “元数据” 的形式嵌入到流中 (附加的数据),本教程将介绍如何检索它。

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>

#include <iostream>
#include <stdio.h>

typedef struct _CustomData
{
    GstElement *playbin;    /* 播放元素 */

    gint n_video;          /* 视频流数量 */
    gint n_audio;          /* 音频流数量 */
    gint n_text;           /* 字幕流数量 */

    gint current_video;    /* 当前正在播放视频流 */
    gint current_audio;    /* 当前正在播放音频流 */
    gint current_text;     /* 当前正在播放字母流*/

    GMainLoop *main_loop;  /* glib主循环 */
} CustomData;

/* playbin flags */
typedef enum 
{
    GST_PLAY_FLAG_VIDEO         = (1 << 0), /* We want video output */
    GST_PLAY_FLAG_AUDIO         = (1 << 1), /* We want audio output */
    GST_PLAY_FLAG_TEXT          = (1 << 2)  /* We want subtitle output */
} GstPlayFlags;

/* Forward definition for the message and keyboard processing functions */
static gboolean handle_message (GstBus *bus, GstMessage *msg, CustomData *data);
static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data);

int main(int argc, char *argv[])
{
    /* 初始化GStreamer */
    gst_init (&argc, &argv);

    /* 创建元素 */
    CustomData data;
    data.playbin = gst_element_factory_make ("playbin", "playbin");
    if (!data.playbin) { g_printerr ("Not all elements could be created.\n"); return -1;}

    /* 设置播放的uri */
    g_object_set (data.playbin, "uri", "https://gstreamer.freedesktop.org/data/media/sintel_cropped_multilingual.webm", NULL);

    /* 设置标志以显示音频和视频,但忽略字幕 */
    gint flags;
    g_object_get (data.playbin, "flags", &flags, NULL);
    flags |= GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO;
    flags &= ~GST_PLAY_FLAG_TEXT;
    g_object_set (data.playbin, "flags", flags, NULL);

    /* 设置连接速度。这将影响playbin的一些内部决策 */
    g_object_set (data.playbin, "connection-speed", 56, NULL);

    /* 添加bus监视,这样就可以在消息到达时收到通知 */
    GstBus *bus = gst_element_get_bus (data.playbin);
    gst_bus_add_watch (bus, (GstBusFunc)handle_message, &data);

    /* 添加键盘监视,以便我们收到按键通知 */
#ifdef G_OS_WIN32
    GIOChannel *io_stdin = g_io_channel_win32_new_fd (fileno (stdin));
#else
    GIOChannel *io_stdin = g_io_channel_unix_new (fileno (stdin));
#endif
    g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data);

    /* 开始播放 */
    GstStateChangeReturn ret = gst_element_set_state (data.playbin, 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.playbin); return -1;
    }

    /* 创建GLib主循环并将其设置为运行 */
    data.main_loop = g_main_loop_new (NULL, FALSE);
    g_main_loop_run (data.main_loop);

    /* 释放资源 */
    g_main_loop_unref (data.main_loop);
    g_io_channel_unref (io_stdin);
    gst_object_unref (bus);
    gst_element_set_state (data.playbin, GST_STATE_NULL);
    gst_object_unref (data.playbin);

    return 0;
}

/* 从流中提取一些元数据并将其打印在屏幕上 */
static void analyze_streams (CustomData *data)
{
    gchar *str;
    guint rate;

    /* 读取一些属性 */
    g_object_get (data->playbin, "n-video", &data->n_video, NULL);
    g_object_get (data->playbin, "n-audio", &data->n_audio, NULL);
    g_object_get (data->playbin, "n-text", &data->n_text, NULL);

    g_print ("%d video stream(s), %d audio stream(s), %d text stream(s)\n", data->n_video, data->n_audio, data->n_text);
    g_print ("\n");

    GstTagList *tags;
    for (gint i = 0; i < data->n_video; i++)
    {
        tags = NULL;
        /* 检索流的视频标签 */
        g_signal_emit_by_name (data->playbin, "get-video-tags", i, &tags);
        if (tags)
        {
            g_print ("video stream %d:\n", i);
            gst_tag_list_get_string (tags, GST_TAG_VIDEO_CODEC, &str);
            g_print ("  codec: %s\n", str ? str : "unknown");
            g_free (str);
            gst_tag_list_free (tags);
        }
    }

    g_print ("\n");
    for (gint i = 0; i < data->n_audio; i++)
    {
        tags = NULL;
        /* 检索流的音频标签 */
        g_signal_emit_by_name (data->playbin, "get-audio-tags", i, &tags);
        if (tags)
        {
            g_print ("audio stream %d:\n", i);
            if (gst_tag_list_get_string (tags, GST_TAG_AUDIO_CODEC, &str))
            {
                g_print ("  codec: %s\n", str);
                g_free (str);
            }
            if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str))
            {
                g_print ("  language: %s\n", str);
                g_free (str);
            }
            if (gst_tag_list_get_uint (tags, GST_TAG_BITRATE, &rate))
            {
                g_print ("  bitrate: %d\n", rate);
            }
            gst_tag_list_free (tags);
        }
    }

    g_print ("\n");
    for (gint i = 0; i < data->n_text; i++)
    {
        tags = NULL;
        /* 检索流的字幕标签 */
        g_signal_emit_by_name (data->playbin, "get-text-tags", i, &tags);
        if (tags)
        {
            g_print ("subtitle stream %d:\n", i);
            if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str))
            {
                g_print ("  language: %s\n", str);
                g_free (str);
            }
            gst_tag_list_free (tags);
        }
    }

    g_object_get (data->playbin, "current-video", &data->current_video, NULL);
    g_object_get (data->playbin, "current-audio", &data->current_audio, NULL);
    g_object_get (data->playbin, "current-text", &data->current_text, NULL);

    g_print ("\n");
    g_print ("Currently playing video stream %d, audio stream %d and text stream %d\n", data->current_video, data->current_audio, data->current_text);
    g_print ("Type any number and hit ENTER to select a different audio stream\n");
}

/* 处理GStreamer的消息 */
static gboolean handle_message (GstBus *bus, GstMessage *msg, CustomData *data)
{
    GError *err;
    gchar *debug_info;

    switch (GST_MESSAGE_TYPE (msg))
    {
    case GST_MESSAGE_ERROR:
        gst_message_parse_error (msg, &err, &debug_info);
        g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
        g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");
        g_clear_error (&err); g_free (debug_info); g_main_loop_quit (data->main_loop);
        break;
    case GST_MESSAGE_EOS:
        g_print ("End-Of-Stream reached.\n");
        g_main_loop_quit (data->main_loop);
        break;
    case GST_MESSAGE_STATE_CHANGED:
    {
        GstState old_state, new_state, pending_state;
        gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
        if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->playbin))
        {
            if (new_state == GST_STATE_PLAYING)
            {
                /* 一旦我们进入播放状态,分析流 */
                analyze_streams (data);
            }
        }
    } break;
    }

    /* 继续收到消息 */
    return TRUE;
}

/* 处理键盘输入 */
static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data)
{
    gchar *str = NULL;
    if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) == G_IO_STATUS_NORMAL)
    {
        int index = g_ascii_strtoull (str, NULL, 0);
        if (index < 0 || index >= data->n_audio)
        {
            g_printerr ("Index out of bounds\n");
        }
        else
        {
            /* 如果输入是有效的音频流索引,请设置当前音频流 */
            g_print ("Setting current audio stream to %d\n", index);
            g_object_set (data->playbin, "current-audio", index, NULL);
        }
    }
    g_free (str);
    return TRUE;
}

关注

笔者 - jxd


http://www.kler.cn/a/581765.html

相关文章:

  • AI重构私域增长:从流量收割到终身价值运营的三阶跃迁
  • AutoMQ x OSS 的 Iceberg 数据入湖的最佳实践
  • 深度评测DeepSeek、ChatGPT O1和谷歌Gemini AI应用开发场景 - DeepSeek性能完胜!
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-7.3.1直接调用ES API的风险与替代方案
  • 如何使用 CSS 实现黑色遮罩效果
  • 深度学习基础:线性代数本质2——线性组合、张成的空间与基
  • Torch 模型 model => .onnx => .trt 及利用 TensorTR 在 C++ 下的模型部署教程
  • 技术速递|Visual Studio Code 2025年2月更新(v1.98)
  • IHAOAVOA:一种改进的混合aquila优化器和非洲秃鹫优化算法的全局优化问题,附完整MATLAB代码
  • 【prompt实战】知乎问题解答专家
  • 为什么使用 XML Schema?
  • 初识大模型——大语言模型 LLMBook 学习(一)
  • 【数据挖掘】异构图与同构图
  • C++设计模式-抽象工厂模式:从原理、适用场景、使用方法,常见问题和解决方案深度解析
  • Android Compose: `remember` 与 `ViewModel` 保存数据的优缺点对比
  • Docker构建启动jar包
  • MySQL 的索引机制
  • java中过滤器
  • 指针的工作原理,函数的传值和传址
  • 使用curl库编写爬虫程序的指令抓取优质视频