GStreamer —— 2.16、Windows下Qt加载GStreamer库后运行 - “播放教程 2:字幕管理“(附:完整源码)

ops/2025/3/15 17:28:00/
运行效果在这里插入图片描述

介绍

     本教程与上一个教程非常相似,但不是 在不同的音频流之间切换,我们将使用字幕流。 这将使我们能够学习:

          • 如何选择字幕流

          • 如何添加外部字幕

          • 如何自定义用于字幕的字体

     我们已经知道(从前面的教程中)容器文件可以 保存多个音频和视频流,并且我们可以很容易地 通过更改 or 属性在它们中进行选择。切换字幕很容易。值得注意的是,就像音频和视频一样,要注意为字幕选择合适的解码器, 并且 GStreamer 的插件结构允许添加对新 格式与复制文件一样简单。除了容器中嵌入的字幕外,还提供 可以从外部 URI 添加额外的字幕流。本教程将打开一个已包含 5 个字幕流的文件, 并从另一个文件(希腊语)添加另一个 1 个文件。

GStreamer_16">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/includeLIBS += 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 <stdio.h>
#include <gst/gst.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的flag */
typedef enum
{GST_PLAY_FLAG_VIDEO         = (1 << 0), /* 想要视频输出 */GST_PLAY_FLAG_AUDIO         = (1 << 1), /* 想要音频频输出 */GST_PLAY_FLAG_TEXT          = (1 << 2)  /* 想要字幕输出 */
} GstPlayFlags;/* 消息和键盘处理功能的转发定义 */
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_trailer-480p.ogv", NULL);/* 设置要播放的字幕URI和一些字体描述 */g_object_set (data.playbin, "suburi", "https://gstreamer.freedesktop.org/data/media/sintel_trailer_gr.srt", NULL);g_object_set (data.playbin, "subtitle-font-desc", "Sans, 18", NULL);/* 设置标志以显示音频、视频和字幕 */gint flags;g_object_get (data.playbin, "flags", &flags, NULL);flags |= GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_TEXT;g_object_set (data.playbin, "flags", flags, NULL);/* 添加一个bus监视,这样我们就可以在消息到达时收到通知 */GstBus *bus = gst_element_get_bus (data.playbin);gst_bus_add_watch (bus, (GstBusFunc)handle_message, &data);/* 添加键盘监视,以便我们收到按键通知 */
#ifdef G_OS_WIN32GIOChannel *io_stdin = g_io_channel_win32_new_fd (fileno (stdin));
#elseGIOChannel *io_stdin = g_io_channel_unix_new (fileno (stdin));
#endifg_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)
{GstTagList *tags;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");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_print ("subtitle stream %d:\n", i);g_signal_emit_by_name (data->playbin, "get-text-tags", i, &tags);if (tags){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);}else{g_print ("  no tags found\n");}}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 subtitle stream %d\n", data->current_video, data->current_audio, data->current_text);g_print ("Type any number and hit ENTER to select a different subtitle 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 = atoi (str);if (index < 0 || index >= data->n_text){g_printerr ("Index out of bounds\n");}else{/* 如果输入是有效的字幕流索引,请设置当前字幕流 */g_print ("Setting current subtitle stream to %d\n", index);g_object_set (data->playbin, "current-text", index, NULL);}}g_free (str);return TRUE;
}

关注

笔者 - jxd


http://www.ppmy.cn/ops/165994.html

相关文章

什么是SEO泛目(什么是SEO站群)

SEO泛目录与站群策略&#xff1a;提升网站优化的双剑合璧 在当今竞争激烈的互联网环境中&#xff0c;SEO优化已成为企业提升网站流量和品牌曝光的重要手段。而在众多SEO策略中&#xff0c;泛目录和站群因其独特的技术优势和效果&#xff0c;逐渐成为SEO从业者的热门选择。本文…

MIPI电平标准详解

一、MIPI电平的定义与核心特性 MIPI&#xff08;Mobile Industry Processor Interface&#xff09; 是由 MIPI联盟 制定的移动设备接口标准&#xff0c;涵盖摄像头&#xff08;CSI&#xff09;、显示屏&#xff08;DSI&#xff09;、射频&#xff08;RFFE&#xff09;等多个领…

Python----数据可视化(pyecharts二:绘图一:条形图,直方图,折线图,散点图,箱图,饼图,热力图)

1、条形图 from pyecharts.charts import Bar from pyecharts.faker import Faker from pyecharts import options as opts # 绘制柱状图 bar (Bar() # 创建柱状图.add_yaxis("商家A", Faker.values(),colorFaker.rand_color()) # 添加数据.add_yaxis("商家B&…

3.14学习总结

今天完成了几道关于二叉树的算法题 关于二叉树的最小最大深度和数据流中的第k大元素&#xff0c;用到优先队列&#xff0c;学习了有关java的基础知识&#xff0c;学习了双指针法。

蓝桥杯 3514子串简写

问题描述 程序猿圈子里正在流行一种很新的简写方法&#xff1a;对于一个字符串&#xff0c;只保留首尾字符&#xff0c;将首尾字符之间的所有字符用这部分的长度代替。例如 internation-alization 简写成 i18n&#xff0c;Kubernetes &#xff08;注意连字符不是字符串的一部分…

Unity开发的抖音小游戏接入抖音开放平台中的流量主(抖音小游戏接入广告)

前言:作者在进行小游戏审核版本的过程中,碰到了下列问题,所以对这个抖音小游戏接入广告研究了下。 还有就是作者的TTSDK版本号是6.2.6,使用的Unity版本是Unity2022.3.29f1,最好和作者的两个版本号保持一致,因为我发现TTSDK旧版的很多函数在新版中就已经无法正常使用了,必…

江科大51单片机笔记【17】红外遥控电机调速

写在前言 此为博主自学江科大51单片机&#xff08;B站&#xff09;的笔记&#xff0c;方便后续重温知识 在后面的章节中&#xff0c;为了防止篇幅过长和易于查找&#xff0c;我把一个小节分成两部分来发&#xff0c;上章节主要是关于本节课的硬件介绍、电路图、原理图等理论知识…

【病毒分析】熊猫烧香病毒分析及其查杀修复

目录 前言 一、样本概况 1.1 样本信息 1.2 测试环境及工具 1.3 分析目标 二、具体行为分析 2.1 主要行为 2.1.1 恶意程序对用户造成的危害 2.2 恶意代码分析 2.2.1 加固后的恶意代码树结构图(是否有加固) 2.2.2 恶意程序的代码分析片段 三、解决方案(或总结) 3.1 …