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

news2025/3/17 9:06:07
运行效果

在这里插入图片描述

介绍

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

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

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

     通常情况下,多个音频、视频和字幕流可以是嵌入在单个文件中。最常见的情况是常规电影,其中包含一个视频和音频流(立体声或 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.coloradmin.cn/o/2316530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MYsql—1

1.mysql的安装 在windows下安装mysql&#xff0c;直接官网搜索即可&#xff1a;http://www.mysql.com/&#xff0c;自己找想要的版本进行download&#xff0c;官网长这样 安装路径需要是英文路径&#xff0c;设置默认即可&#xff0c;若安装执行内容时报错&#xff0c;则AltCt…

位运算(基础算法)

按位与AND&#xff08; & &#xff09; 只有当两个位都为1时&#xff0c;结果才为1,否则为0。结果不会变大 按位或 OR&#xff08; | &#xff09; 只有当两个位中有一个为1时&#xff0c;结果才为1,否则为0。结果不会变小 按位异或 XOR &#xff08; ^ &#xff09; 只…

硬件地址反序?用位操作为LED灯序“纠偏”。反转二进制数即可解决

特别有意思&#xff0c;LED的灯序与其硬件地址刚好相反&#xff0c;没办法直接通过加1实现二进制进位的亮灯操作&#xff0c;查了一些资料说用数组和switch实现&#xff0c;觉得太麻烦了&#xff0c;思索良久&#xff0c;就想到了反转二进制数解决这个问题。 reverse_bits( )是…

图解AUTOSAR_CP_BSWMulticoreLibrary

AUTOSAR BSW 多核库详解 AUTOSAR基础软件多核操作库详细解析 目录 架构概述 1.1. 组件架构 1.2. API结构 1.3. 错误处理流程详细设计 2.1. 基础数据类型 2.2. 接口说明 2.3. 错误处理机制使用指南 3.1. 配置说明 3.2. 典型应用场景 3.3. 注意事项 1. 架构概述 1.1. 组件架构 …

热key探测技术架构设计与实践

参考&#xff1a; 得物热点探测技术架构设计与实践 Redis数据倾斜与JD开源hotkey源码分析揭秘 京东热点检测 HotKey 学习笔记 hotkey: 京东App后台中间件&#xff0c;毫秒级探测热点数据&#xff0c;毫秒级推送至服务器集群内存&#xff0c;大幅降低热key对数据层查询压力 …

【微服务】java中http调用组件深入实战详解

目录 一、前言 二、http调用概述 2.1 什么是http调用 2.1.1 http调用步骤 2.2 HTTP调用特点 2.3 HTTP调用应用场景 三、微服务场景下http调用概述 3.1 微服务开发中http调用场景 3.2 微服务组件中http的应用 四、常用的http调用组件 4.1 java中常用的http组件介绍 4…

app.config.globalProperties

目录 一:基础使用 1、简介 2、使用 3、打印结果: 二:封装 1、创建一个.ts文件(utils/msg.ts) 2、在main.ts中全局注册 3、在页面中使用 4、打印结果 一:基础使用 1、简介 app.config.globalProperties 是 Vue 3 应用实例&#xff08;app&#xff09;的一个配置属性&…

Leetcode做题记录----3

1474、删除链表M个节点之后的N个节点 思路&#xff1a; 1、两个循环解决问题 第一个循环移动M个位置&#xff0c;第二个循环确定移动N个位置后的&#xff0c;然后将M位置的节点的next指向&#xff0c;N位置后的节点即可 2、注意边界条件和判空处理 代码实现&#xff1a; pub…

React(二):JSX语法解析+综合案例

事件绑定 this绑定方式 问题&#xff1a;在事件执行后&#xff0c;需获取当前类的对象中相关属性&#xff0c;此时需要this——当打印时&#xff0c;发现this为undefined,这又是为啥&#xff1f; 假设有一个btnClick函数&#xff0c;但它并不是我们主动调用的&#xff0c;而是…

Gitee重新远程连接仓库(Linux)

Gitee重新远程连接仓库&#xff08;Linux&#xff09; 因为虚拟机重新安装了一回&#xff0c;所以需要重新和远程仓库连接&#xff0c;在网上找了很久没有找到相关操作&#xff0c;自己实操成功&#xff0c;记录下本博客&#xff0c;帮助有需要的人 确保新虚拟机安装Git 在新虚…

Vitis HLS中的Array Partition与Array Reshape详解

Vitis HLS中的Array Partition与Array Reshape详解 引言 在高层次综合(HLS)设计中&#xff0c;数组是最常用的数据结构之一&#xff0c;但默认情况下&#xff0c;HLS会将数组映射到单个BRAM块&#xff0c;这会限制并行访问能力&#xff0c;成为性能瓶颈。为了克服这一限制&am…

Centos离线安装openssl

文章目录 Centos离线安装openssl1. openssl是什么&#xff1f;2. openssl下载地址3. openssl-devel安装4. 安装结果验证5. 版本查看 Centos离线安装openssl 1. openssl是什么&#xff1f; OpenSSL 是一个开源的、跨平台的 加密工具库 和 命令行工具集&#xff0c;广泛用于实现…

protobuf安装

安装 github官方链接 https://github.com/protocolbuffers/protobuf/ 以protobuf21为例 https://github.com/protocolbuffers/protobuf/releases/download/v21.11/protobuf-all-21.11.zip windows 解压好文件夹后,使用cmake,vs,qt creator等工具打开该项目,进行编译,编译需…

《基于超高频RFID的图书馆管理系统的设计与实现》开题报告

一、研究背景与意义 1.研究背景 随着信息化时代的到来&#xff0c;运用计算机科学技术实现图书馆的管理工作已成为优势。更加科学地管理图书馆会大大提高工作效率。我国的图书管理体系发展经历了三个阶段&#xff1a;传统图书管理模式、现代图书管理模式以及基于无线射频识别&…

小程序渲染之谜:如何解决“加载中...”不消失的 Bug(glass-easel)

&#x1f389; 小程序渲染之谜&#xff1a;如何解决“加载中…”不消失的 Bug &#x1f389; 引言 在小程序开发中&#xff0c;渲染问题总能让人抓狂。&#x1f62b; 这次&#xff0c;我遇到了一个奇怪的 bug&#xff1a;产品详情页的内容已经正常显示&#xff0c;但页面却一…

网络原理之HTTPS(如果想知道网络原理中有关HTTPS的知识,那么只看这一篇就足够了!)

前言&#xff1a;随着互联网安全问题日益严重&#xff0c;HTTPS已成为保障数据传输安全的标准协议&#xff0c;通过加密技术和身份验证&#xff0c;HTTPS有效防止数据窃取、篡改和中间人攻击&#xff0c;确保通信双方的安全和信任。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要…

五子棋小游戏-简单开发版

一、需求分析 开发一个基于 Pygame 库的五子棋小游戏&#xff0c;允许两名玩家在棋盘上轮流落子&#xff0c;当有一方达成五子连珠时游戏结束&#xff0c;显示获胜信息&#xff0c;并提供退出游戏和重新开始游戏的操作选项。 1.棋盘显示 &#xff1a; 显示一个 15x15 的五子棋…

2025中国科技大学少年班/创新试点班·初试备考测试卷(数学)

本卷考查内容&#xff1a;高中课程内容及拓展。 本卷考查形式&#xff1a;书面作答&#xff08;客观题18小题解答题4题&#xff09;。 卷首语&#xff1a;中科大少年班、创新班每年大规模招录在数理成绩优异的中学学生。其中初试数学题在高考基础上略有拓展&#xff0c;难度又低…

即时通讯平台测试报告

1.项目概述 项目名称&#xff1a;即时通讯平台 版本号&#xff1a;V1.0.0 测试周期&#xff1a;2025年2月25日--2025年3月15日 测试目标&#xff1a;验证核心功能&#xff08;登录、注册、消息收发、用户管理、群组功能等&#xff09;的稳定性和性能指标。 2. 测试范围 功…

如何记录Matlab程序运行过程中所占用的最大内存

有些时候&#xff0c;我们需要分析Matlab程序运行过程中所占用的最大内存。如果只是得到程序运行到当前位置所占用的内存&#xff0c;可以简单在程序当前位置插入memory命令即可&#xff1a; user memory; MemUsed_now user.MemUsedMATLAB; 但如果我们想要的是整个程序在运行…