文章目录

  • 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 (字幕管理)相关推荐

  1. GStreamer播放教程05——色彩平衡

    目标 亮度,对比度,色度和饱和度都是常见的视频调节参数,也是GStreamer里面设置色彩平衡的参数.本教程将展示: 如何发现可用的色彩平衡通道 如何改变它们 介绍 <GStreamer基础教程 ...

  2. GStreamer官方教程系列——Basic tutorial 5: GUI toolkit integration

    GStreamer官方教程系列 Basic tutorial 5: GUI toolkit integration 原文:https://gstreamer.freedesktop.org/docum ...

  3. [转]详细的GStreamer开发教程

    详细的GStreamer开发教程 文章目录 详细的GStreamer开发教程 1. 什么是GStreamer? 2. GStreamer架构 2.1 Media Applications 2.2 Co ...

  4. 详细的GStreamer开发教程

    详细的GStreamer开发教程 文章目录 详细的GStreamer开发教程 1. 什么是GStreamer? 2. GStreamer架构 2.1 Media Applications 2.2 Co ...

  5. 转贴:网友【原创·教程】 SRT外挂字幕时间轴调整及合并中英文同步字幕制作方法

    [原创·教程] SRT外挂字幕时间轴调整及合并中英文同步字幕制作方法 现时比较流行的一种外挂字幕之一就是SRT字幕了,视频电影在压制过程中如果加入字幕就会有损画质,所以就使用起外挂字幕,可隐藏可换多种 ...

  6. 下载b站外挂字幕,用 potplayer 播放视频也能看字幕了

    苏生不惑第175 篇原创文章,将本公众号设为星标,第一时间看最新文章. 关于b站之前已经写过很多文章了,有兴趣可以点击阅读: bilibili(b站)升级到BV号了,还想用av号怎么办? 那些你可能不 ...

  7. GStreamer基础教程10——GStreamer工具

    目标 GStreamer提供了一系列方便使用的工具.这篇教程里不牵涉任何代码,但还是会讲一些有用的内容: 如何在命令行下建立一个pipeline--完全不使用C 如何找出一个element的Capab ...

  8. 为potplayer播放器添加实时中文字幕

    为potplayer播放器添加实时中文字幕 大家好,现在的国外视频引进至国内后,也不再去进行中文配音了,而是直接出中文字幕.而那些不是通过正规途径进入中国的电影.视频,只有英文或者韩文或者其他国家的字 ...

  9. Win7迅雷影音播放器右键菜单的字幕选项是灰色的解决方法

    迅雷影音播放器能够支持各种不同的视频解码,而且还有在线匹配字幕的功能,用户可以在线播放各种热门大片,也可以本地播放收藏的经典大片,很多用户都喜欢使用.但是最近有Win7系统用户在使用迅雷影音播放视频的 ...

最新文章

  1. python真的这么厉害吗-嗯?python居然可以这么嚣张?这么厉害!到底是为什么?...
  2. 【Machine Learning】OpenCV中的K-means聚类
  3. 使用Java 8处理并行数据库流
  4. 鸿蒙系统r如何升级,高歌猛进,鸿蒙系统升级机型再次确认,花粉:终等到!...
  5. stm32中stm32f10x_type.h(固件3.0以前)、stm32f10x.h(固件3.0以后)、stdint.h文件的关系
  6. PyTorch实现自由的数据读取
  7. 583. 两个字符串的删除操作(JavaScript)
  8. python正则表达式之match,search,findall区别
  9. 山东财经大学燕山学院计算机王栋,选修课Photoshop王栋的群谁有
  10. 计算机基础表格函数基础知识大全,计算机基础-EXCEL公式和函数
  11. 一键批量下载皮皮虾视频
  12. CCF公布国家集训队50进15名单!5月确定IOI2019选手!
  13. DELL笔记本电脑电池不充电以及键盘失灵问题
  14. 费马小定理在ACM中的应用
  15. Python Web项目
  16. 无人机三维建模(5) Photoscan建模
  17. WPF datagrid数据导出到Excel表格
  18. Windows安全中心输入用户名密码
  19. 全文同音文言文——智侄治蛭
  20. 【开源软件开发导论作业-1】

热门文章

  1. 摘录与评论·《致我们终将逝去的青春》
  2. c++fstream 中 ios::in ios::out ios::ate ios::app ios::trunc ios::binary
  3. IT业史上最棒的图片之一
  4. 【约稿】给自己交一份年度总结——我的2014年
  5. c语言u8u16u的区别,u8,u16,u32和uint8_t,uint16_t,uint32_t的含义
  6. 【深蓝学院:语音信号处理笔记】前端语音处理技术综述
  7. 激光点云处理的学习之路(深蓝学院)
  8. 【模拟电子技术Analog Electronics Technology 4】——晶体三极管工作原理及放大作用详解
  9. 阿里云服务器(Windows32操作系统)及配置方法
  10. 基于电位器式传感器位移测量仪的设计