官网地址
Playback tutorial 7: Custom playbin sinks
一、目标
通过手动选择其音频和视频接收器,可以进一步定制playbin。这允许应用程序依赖playbin检索和解码媒体,然后自行管理最终的渲染/显示。本教程展示了:
- 如何替换playbin选择的接收器。
- 如何使用复杂的管道作为接收器。
二、介绍
playbin有两个属性允许选择所需的音频和视频接收器:分别是audio-sink和video-sink。应用程序只需要实例化适当的GstElement并通过这些属性传递给playbin即可。
然而,这种方法只允许使用单个元素作为接收器。如果需要更复杂的管道,例如,一个均衡器加上一个音频接收器,则需要将其封装在一个Bin中,这样对于playbin来说,它看起来就像是一个单一的元素。
Bin(GstBin)是一种容器,用于封装部分管道以便将其作为一个单一元素进行管理。例如,我们在所有教程中使用的GstPipeline就是一种不与外部元素交互的GstBin。Bin内的元素通过Ghost Pads(GstGhostPad)连接到外部元素,也就是说,位于Bin表面的Pads简单地将数据从外部Pad转发到内部元素的特定Pad上。
图1:包含两个元素和一个Ghost Pad的Bin。
GstBin也是一种GstElement,因此可以在任何需要元素的地方使用它们,特别是作为playbin的接收器(这时它们被称为sink-bins)。
三、一个带有均衡器的播放器
将这些代码复制到一个名为playback-tutorial-7.c的文本文件中。
playback-tutorial7.c
#include <gst/gst.h>
int main(int argc, char *argv[]) {
GstElement *pipeline, *bin, *equalizer, *convert, *sink;
GstPad *pad, *ghost_pad;
GstBus *bus;
GstMessage *msg;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Build the pipeline */
pipeline = gst_parse_launch ("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);
/* Create the elements inside the sink bin */
equalizer = gst_element_factory_make ("equalizer-3bands", "equalizer");
convert = gst_element_factory_make ("audioconvert", "convert");
sink = gst_element_factory_make ("autoaudiosink", "audio_sink");
if (!equalizer || !convert || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* Create the sink bin, add the elements and link them */
bin = gst_bin_new ("audio_sink_bin");
gst_bin_add_many (GST_BIN (bin), equalizer, convert, sink, NULL);
gst_element_link_many (equalizer, convert, sink, NULL);
pad = gst_element_get_static_pad (equalizer, "sink");
ghost_pad = gst_ghost_pad_new ("sink", pad);
gst_pad_set_active (ghost_pad, TRUE);
gst_element_add_pad (bin, ghost_pad);
gst_object_unref (pad);
/* Configure the equalizer */
g_object_set (G_OBJECT (equalizer), "band1", (gdouble)-24.0, NULL);
g_object_set (G_OBJECT (equalizer), "band2", (gdouble)-24.0, NULL);
/* Set playbin's audio sink to be our sink bin */
g_object_set (GST_OBJECT (pipeline), "audio-sink", bin, NULL);
/* Start playing */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* Wait until error or EOS */
bus = gst_element_get_bus (pipeline);
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Free resources */
if (msg != NULL)
gst_message_unref (msg);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
Linux 安装库(Install GStreamer on Ubuntu or Debian)
apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio
其他的系统看官网教程。
执行编译
gcc playback-tutorial-7.c -o playback-tutorial-7 `pkg-config --cflags --libs gstreamer-1.0`
必需的库:gstreamer-1.0
四、代码解析
/* Create the elements inside the sink bin */
equalizer = gst_element_factory_make ("equalizer-3bands", "equalizer");
convert = gst_element_factory_make ("audioconvert", "convert");
sink = gst_element_factory_make ("autoaudiosink", "audio_sink");
if (!equalizer || !convert || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
我们实例化了组成sink-bin的所有元素。这里使用了一个equalizer-3bands
和一个autoaudiosink
,并在它们之间加入了一个audioconvert
,因为我们不确定音频接收器的能力(因为这些能力依赖于硬件)。
/* Create the sink bin, add the elements and link them */
bin = gst_bin_new ("audio_sink_bin");
gst_bin_add_many (GST_BIN (bin), equalizer, convert, sink, NULL);
gst_element_link_many (equalizer, convert, sink, NULL);
这将新元素添加到Bin中,并像处理管道一样链接它们。
pad = gst_element_get_static_pad (equalizer, "sink");
ghost_pad = gst_ghost_pad_new ("sink", pad);
gst_pad_set_active (ghost_pad, TRUE);
gst_element_add_pad (bin, ghost_pad);
gst_object_unref (pad);
现在我们需要创建一个Ghost Pad,以便Bin内部的部分管道可以连接到外部。这个Ghost Pad将连接到内部元素中的一个Pad(这里是均衡器的sink pad),所以我们使用gst_element_get_static_pad()获取这个Pad。记住,如果这是一个请求Pad而不是始终存在的Pad,我们将需要使用gst_element_request_pad()。
Ghost Pad通过gst_ghost_pad_new()创建(指向我们刚刚获得的内部Pad),并通过gst_pad_set_active()激活。然后它通过gst_element_add_pad()添加到Bin中,转移Ghost Pad的所有权给Bin,因此我们不需要担心释放它。
最后,从均衡器获得的sink Pad需要用gst_object_unref()释放。
此时,我们有了一个功能性的sink-bin,可以用作playbin中的音频接收器。只需要指示playbin使用它:
/* Set playbin's audio sink to be our sink bin */
g_object_set (GST_OBJECT (pipeline), "audio-sink", bin, NULL);
只需简单地将playbin的audio-sink属性设置为新创建的sink即可。
/* Configure the equalizer */
g_object_set (G_OBJECT (equalizer), "band1", (gdouble)-24.0, NULL);
g_object_set (G_OBJECT (equalizer), "band2", (gdouble)-24.0, NULL);
剩下的唯一工作是配置均衡器。在这个例子中,两个较高频率段被设置为最大衰减,以增强低音效果。尝试调整这些值以感受不同(查看equalizer-3bands元素的文档以了解允许的值范围)。
五、练习
构建一个视频bin而不是音频bin,使用GStreamer提供的许多有趣视频滤镜之一,如solarize、vertigotv或effectv插件中的任何元素。如果由于不兼容的caps导致管道无法链接,请记得使用颜色空间转换元素videoconvert。
六、结论
本教程展示了:
- 如何使用audio-sink和video-sink属性为playbin设置自己的接收器。
- 如何将一段管道封装进GstBin中,以便作为playbin的sink-bin使用。