Gstreamer播放教程2: Subtitle management (字幕管理)
文章目录
- 1.目标
- 2.介绍
- 3.实现
- 1.compile
- 2.code
- 4.解析
- 1.属性设置
- 5.讨论
1.目标
本教程与前一个非常类似,但我们将使用字幕流之间的不同音频流之间切换。 这将允许我们学习:
- 如何选择字幕流
- 如何增加外部的字幕
- 如何自定义字幕的字体
2.介绍
我们已经知道(从之前的教程中)容器文件可以容纳多个音频和视频流,我们可以很容易地通过改变playbin的current-audio或current-video属性来选择它们。切换字幕也很简单。
值得注意的是,就像音频和视频一样,playbin负责为字幕选择正确的解码器,GStreamer的插件结构允许添加对新格式的支持,就像复制文件一样容易。所有东西对应用程序开发人员都是不可见的。
除了容器中嵌入的字幕外,playbin还提供了从外部URI添加额外字幕流的可能性。
本教程打开一个已经包含5个字幕流的文件,并从另一个文件中添加另一个字幕流(用于希腊语)。
3.实现
1.compile
gcc playback-tutorial-2.c -o playback-tutorial-2 `pkg-config --cflags --libs gstreamer-1.0`
2.code
#include <stdio.h>
#include <gst/gst.h>/* Structure to contain all our information, so we can pass it around */
typedef struct _CustomData {GstElement *playbin; /* Our one and only element */gint n_video; /* Number of embedded video streams */gint n_audio; /* Number of embedded audio streams */gint n_text; /* Number of embedded subtitle streams */gint current_video; /* Currently playing video stream */gint current_audio; /* Currently playing audio stream */gint current_text; /* Currently playing subtitle stream */GMainLoop *main_loop; /* GLib's Main Loop */
} 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[]) {CustomData data;GstBus *bus;GstStateChangeReturn ret;gint flags;GIOChannel *io_stdin;/* Initialize GStreamer */gst_init (&argc, &argv);/* Create the elements */data.playbin = gst_element_factory_make ("playbin", "playbin");if (!data.playbin) {g_printerr ("Not all elements could be created.\n");return -1;}/* Set the URI to play */g_object_set (data.playbin, "uri", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv", NULL);/* Set the subtitle URI to play and some font description */g_object_set (data.playbin, "suburi", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer_gr.srt", NULL);g_object_set (data.playbin, "subtitle-font-desc", "Sans, 18", NULL);/* Set flags to show Audio, Video and Subtitles */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);/* Add a bus watch, so we get notified when a message arrives */bus = gst_element_get_bus (data.playbin);gst_bus_add_watch (bus, (GstBusFunc)handle_message, &data);/* Add a keyboard watch so we get notified of keystrokes */
#ifdef G_OS_WIN32io_stdin = g_io_channel_win32_new_fd (fileno (stdin));
#elseio_stdin = g_io_channel_unix_new (fileno (stdin));
#endifg_io_add_watch (io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data);/* Start playing */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;}/* Create a GLib Main Loop and set it to run */data.main_loop = g_main_loop_new (NULL, FALSE);g_main_loop_run (data.main_loop);/* Free resources */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;
}/* Extract some metadata from the streams and print it on the screen */
static void analyze_streams (CustomData *data) {gint i;GstTagList *tags;gchar *str;guint rate;/* Read some properties */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 (i = 0; i < data->n_video; i++) {tags = NULL;/* Retrieve the stream's video tags */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 (i = 0; i < data->n_audio; i++) {tags = NULL;/* Retrieve the stream's audio tags */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 (i = 0; i < data->n_text; i++) {tags = NULL;/* Retrieve the stream's subtitle tags */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");
}/* Process messages from 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) {/* Once we are in the playing state, analyze the streams */analyze_streams (data);}}} break;}/* We want to keep receiving messages */return TRUE;
}/* Process keyboard input */
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 {/* If the input was a valid subtitle stream index, set the current subtitle stream */g_print ("Setting current subtitle stream to %d\n", index);g_object_set (data->playbin, "current-text", index, NULL);}}g_free (str);return TRUE;
}
4.解析
1.属性设置
/* Set the subtitle URI to play and some font description */
g_object_set (data.playbin, "suburi", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer_gr.srt", NULL);
g_object_set (data.playbin, "subtitle-font-desc", "Sans, 18", NULL);
设置媒体URI之后,我们设置suburi属性,它将playbin指向包含字幕流的文件。在本例中,媒体文件已经包含多个字幕流,因此suburi中提供的字幕流将被添加到列表中,并且将是当前选中的字幕流。
注意,关于字幕流(像它的语言一样)的元数据驻留在容器文件中,因此,没有嵌入到容器中的字幕将没有元数据。运行本教程时,您会发现第一个字幕流没有语言标记。
subtitle-font-desc属性允许指定显示字幕的字体。由于Pango是用来呈现字体的库,您可以查看它的文档,以了解应该如何指定这种字体,特别是pango-font-description-from-string函数。
简而言之,字符串表示的格式是[FAMILY-LIST] [STYLE-OPTIONS] [SIZE],其中FAMILY-LIST是用逗号分隔的列表,可以用逗号结束,STYLE_OPTIONS是用空格分隔的单词列表,其中每个单词描述样式、变体、weights或延伸,SIZE是一个小数(以点数表示)。例如,下面的都是有效的字符串表示
- sans bold 12
- serif,monospace bold italic condensed 16
- normal 10
常用的字体有:普通字体(Normal)、无字体(Sans)、衬线字体(Serif)和单色字体(Monospace)。
可用的样式有:Normal(字体是垂直的),Oblique(字体是倾斜的,但是罗马风格),Italic(字体是倾斜的,以斜体风格)。
可用的weights是:Ultra-Light(超轻),Light(轻),Normal(正常),Bold(粗体),Ultra-Bold,Heavy。
可用的变体有:Normal(普通)、Small_Caps小写(一种用小写字符替换为更小的大写字符变体的字体)
可拉伸的款式有:Ultra-Condensed超浓缩,Extra-Condensed超浓缩,Condensed浓缩,Semi-Condensed半浓缩,Normal普通,Semi-Expanded半膨胀,Expanded膨胀,Extra-Expanded超膨胀,Ultra-Expanded超膨胀
/* Set flags to show Audio, Video and Subtitles */
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);
我们设置了flags属性来允许音频、视频和文本(字幕)。
本教程的其余部分与播放教程1:Playbin使用相同,只是键盘输入改变了当前文本属性而不是当前音频属性。与前面一样,请记住流的更改不是立即的,因为在新流出现之前,有大量的信息流经管道,需要到达管道的末端。
5.讨论
本教程展示了如何处理来自playbin的字幕,无论它们是嵌入在容器中还是不同的文件中
- 使用playbin的当前文本和n-text属性选择字幕
- 可以使用suburi属性选择外部字幕文件
- 字幕外观可以使用subtitle-font-desc属性进行自定义
Gstreamer播放教程2: Subtitle management (字幕管理)相关推荐
- GStreamer播放教程05——色彩平衡
目标 亮度,对比度,色度和饱和度都是常见的视频调节参数,也是GStreamer里面设置色彩平衡的参数.本教程将展示: 如何发现可用的色彩平衡通道 如何改变它们 介绍 <GStreamer基础教程 ...
- GStreamer官方教程系列——Basic tutorial 5: GUI toolkit integration
GStreamer官方教程系列 Basic tutorial 5: GUI toolkit integration 原文:https://gstreamer.freedesktop.org/docum ...
- [转]详细的GStreamer开发教程
详细的GStreamer开发教程 文章目录 详细的GStreamer开发教程 1. 什么是GStreamer? 2. GStreamer架构 2.1 Media Applications 2.2 Co ...
- 详细的GStreamer开发教程
详细的GStreamer开发教程 文章目录 详细的GStreamer开发教程 1. 什么是GStreamer? 2. GStreamer架构 2.1 Media Applications 2.2 Co ...
- 转贴:网友【原创·教程】 SRT外挂字幕时间轴调整及合并中英文同步字幕制作方法
[原创·教程] SRT外挂字幕时间轴调整及合并中英文同步字幕制作方法 现时比较流行的一种外挂字幕之一就是SRT字幕了,视频电影在压制过程中如果加入字幕就会有损画质,所以就使用起外挂字幕,可隐藏可换多种 ...
- 下载b站外挂字幕,用 potplayer 播放视频也能看字幕了
苏生不惑第175 篇原创文章,将本公众号设为星标,第一时间看最新文章. 关于b站之前已经写过很多文章了,有兴趣可以点击阅读: bilibili(b站)升级到BV号了,还想用av号怎么办? 那些你可能不 ...
- GStreamer基础教程10——GStreamer工具
目标 GStreamer提供了一系列方便使用的工具.这篇教程里不牵涉任何代码,但还是会讲一些有用的内容: 如何在命令行下建立一个pipeline--完全不使用C 如何找出一个element的Capab ...
- 为potplayer播放器添加实时中文字幕
为potplayer播放器添加实时中文字幕 大家好,现在的国外视频引进至国内后,也不再去进行中文配音了,而是直接出中文字幕.而那些不是通过正规途径进入中国的电影.视频,只有英文或者韩文或者其他国家的字 ...
- Win7迅雷影音播放器右键菜单的字幕选项是灰色的解决方法
迅雷影音播放器能够支持各种不同的视频解码,而且还有在线匹配字幕的功能,用户可以在线播放各种热门大片,也可以本地播放收藏的经典大片,很多用户都喜欢使用.但是最近有Win7系统用户在使用迅雷影音播放视频的 ...
最新文章
- python真的这么厉害吗-嗯?python居然可以这么嚣张?这么厉害!到底是为什么?...
- 【Machine Learning】OpenCV中的K-means聚类
- 使用Java 8处理并行数据库流
- 鸿蒙系统r如何升级,高歌猛进,鸿蒙系统升级机型再次确认,花粉:终等到!...
- stm32中stm32f10x_type.h(固件3.0以前)、stm32f10x.h(固件3.0以后)、stdint.h文件的关系
- PyTorch实现自由的数据读取
- 583. 两个字符串的删除操作(JavaScript)
- python正则表达式之match,search,findall区别
- 山东财经大学燕山学院计算机王栋,选修课Photoshop王栋的群谁有
- 计算机基础表格函数基础知识大全,计算机基础-EXCEL公式和函数
- 一键批量下载皮皮虾视频
- CCF公布国家集训队50进15名单!5月确定IOI2019选手!
- DELL笔记本电脑电池不充电以及键盘失灵问题
- 费马小定理在ACM中的应用
- Python Web项目
- 无人机三维建模(5) Photoscan建模
- WPF datagrid数据导出到Excel表格
- Windows安全中心输入用户名密码
- 全文同音文言文——智侄治蛭
- 【开源软件开发导论作业-1】
热门文章
- 摘录与评论·《致我们终将逝去的青春》
- c++fstream 中 ios::in ios::out ios::ate ios::app ios::trunc ios::binary
- IT业史上最棒的图片之一
- 【约稿】给自己交一份年度总结——我的2014年
- c语言u8u16u的区别,u8,u16,u32和uint8_t,uint16_t,uint32_t的含义
- 【深蓝学院:语音信号处理笔记】前端语音处理技术综述
- 激光点云处理的学习之路(深蓝学院)
- 【模拟电子技术Analog Electronics Technology 4】——晶体三极管工作原理及放大作用详解
- 阿里云服务器(Windows32操作系统)及配置方法
- 基于电位器式传感器位移测量仪的设计