运行效果(音频)
简介
上一个教程演示了GStreamer工具。本教程介绍视频播放控制。快进、反向播放和慢动作都是技术 统称为 Trick Modes,它们都有一个共同点 修改 Normal playback rate。本教程介绍如何实现 这些效果并在交易中添加了帧步进。特别是,它 显示:
• 如何更改播放速率,比正常更快和更慢, 前进和向后。
• 如何逐帧推进视频
快进是一种以高于 它的正常(预期)速度;而慢动作使用低于 预期的那个。反向播放执行相同的作,但向后播放, 从流的结尾到开头。所有这些技术所做的只是更改播放速率,这是一个变量 等于 1.0 表示正常播放,大于 1.0(绝对值) 对于快速模式,对于慢速模式,低于 1.0(绝对值), positive 表示正向播放,negative 表示反向播放。GStreamer 提供了两种机制来更改播放速率:步进 事件 (Events) 和查找事件 (Seek Events)。Step Events 允许跳过给定数量的 媒体,除了更改后续播放速率(仅为正数 值)。此外,Seek Events 还允许跳转到 流式传输并设置正播放速率和负播放速率。
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 <string.h>
#include <stdio.h>
#include <gst/gst.h>#ifdef __APPLE__
#include <TargetConditionals.h>
#endiftypedef struct _CustomData
{GstElement *pipeline;GstElement *video_sink;GMainLoop *loop;gboolean playing; /* 播放或暂停 */gdouble rate; /* 当前播放速率(可以为负) */
} CustomData;/* Send seek event to change rate */
static void
send_seek_event (CustomData * data)
{gint64 position;GstEvent *seek_event;/* Obtain the current position, needed for the seek event */if (!gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &position)) {g_printerr ("Unable to retrieve current position.\n");return;}/* Create the seek event */if (data->rate > 0) {seek_event =gst_event_new_seek (data->rate, GST_FORMAT_TIME,(GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), GST_SEEK_TYPE_SET,position, GST_SEEK_TYPE_END, 0);} else {seek_event =gst_event_new_seek (data->rate, GST_FORMAT_TIME,GstSeekFlags(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), GST_SEEK_TYPE_SET, 0,GST_SEEK_TYPE_SET, position);}if (data->video_sink == NULL) {/* If we have not done so, obtain the sink through which we will send the seek events */g_object_get (data->pipeline, "video-sink", &data->video_sink, NULL);}/* Send the event */gst_element_send_event (data->video_sink, seek_event);g_print ("Current rate: %g\n", data->rate);
}/* 处理键盘输入 */
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) { return TRUE; }switch (g_ascii_tolower (str[0])){case 'p':data->playing = !data->playing;gst_element_set_state (data->pipeline, data->playing ? GST_STATE_PLAYING : GST_STATE_PAUSED);g_print ("Setting state to %s\n", data->playing ? "PLAYING" : "PAUSE"); break;case 's':if (g_ascii_isupper (str[0])){data->rate *= 2.0;}else{data->rate /= 2.0;}send_seek_event (data); break;case 'd':data->rate *= -1.0; send_seek_event (data); break;case 'n':if (data->video_sink == NULL){/* If we have not done so, obtain the sink through which we will send the step events */g_object_get (data->pipeline, "video-sink", &data->video_sink, NULL);}gst_element_send_event (data->video_sink,gst_event_new_step (GST_FORMAT_BUFFERS, 1, ABS (data->rate), TRUE,FALSE));g_print ("Stepping one frame\n");break;case 'q':g_main_loop_quit (data->loop);break;default:break;}g_free (str);return TRUE;
}int tutorial_main (int argc, char *argv[])
{/* 初始化GStreamer */gst_init (&argc, &argv);/* 初始化自定义数据 */CustomData data;memset (&data, 0, sizeof (data));/* 输出使用方式 */g_print ("USAGE: Choose one of the following options, then press enter:\n"" 'P' to toggle between PAUSE and PLAY\n"" 'S' to increase playback speed, 's' to decrease playback speed\n"" 'D' to toggle playback direction\n"" 'N' to move to next frame (in the current direction, better in PAUSE)\n"" 'Q' to quit\n");/* 构建管道 */data.pipeline =gst_parse_launch("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);/* 增加键盘输入以进行控制 */
#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.pipeline, 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.pipeline); return -1;}data.playing = TRUE;data.rate = 1.0;/* 创建GLib主循环并将其设置为运行 */data.loop = g_main_loop_new (NULL, FALSE);g_main_loop_run (data.loop);/* 释放资源 */g_main_loop_unref (data.loop);g_io_channel_unref (io_stdin);gst_element_set_state (data.pipeline, GST_STATE_NULL);if (data.video_sink != NULL)gst_object_unref (data.video_sink);gst_object_unref (data.pipeline);return 0;
}int main (int argc, char *argv[])
{
#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONEreturn gst_macos_main ((GstMainFunc) tutorial_main, argc, argv, NULL);
#elsereturn tutorial_main (argc, argv);
#endif
}
关注
笔者 - jxd