gstreamer移植qnx:编写gstreamer插件audio sink和video sink
Posted 玄道公子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gstreamer移植qnx:编写gstreamer插件audio sink和video sink相关的知识,希望对你有一定的参考价值。
一、概述
因为gstreamer没有提供qnx系统的支持, 因此这里要实现音频和视频的播放,就必须自己实现最终的音视频输出的元件,即sink元件,一开始,我的想法是,可否移植开源的音视频输出库,比如sdl,alsa等等, 但是发现有些麻烦, 反而把事情弄的更复杂了。 最终还是踏踏实实的两个gstreamer的sink元件,用来输出音频和视频。
要编写gstreamer的插件有很多方式, 比如直接“继承”实现GstElementClass和GstElement,使用gst-template工具创建一个插件模板,然后去实现。 我这里使用的另一种方式, 既然是实现sink类型的元件。 那么就直接找gstreamer已有的sink元件作为模板,将他们复制过来,删除原有的接口实现代码,换上自己的实现。
注意, 输出的plugin动态库名称以 libpluginname.so 的形式, 而这个pluginname就是 编写插件时,定义插件的宏GST_PLUGIN_DEFINE 的参数中的name, 如果不匹配,就会出现插件无法是使用,被gstreamer将插件加入黑名单
二、实现QNX audio sink插件
其实gstreamer有sink插件的“基类”:GstAudiosinkClass, 我们要做的就是继承和override一些接口。GstAudioSinkClass的全部接口如下:
struct _GstAudioSinkClass
/**基类,其完成的继承路径是 GSTAudioSinkClass ——> GstAudioBaseSinkClass ——>
GstBaseSinkClass ——> GstElementClass ,再向上就是和gobject相关的东西了,这里不涉及 */
GstAudioBaseSinkClass parent_class;
/* vtable, 接口定义 */
/* open the device with given specs, 打开设备*/
gboolean (*open) (GstAudioSink *sink);
/* prepare resources and state to operate with the given specs, 进行prepare操作 */
gboolean (*prepare) (GstAudioSink *sink, GstAudioRingBufferSpec *spec);
/* undo anything that was done in prepare(), 回退到prepare之前 */
gboolean (*unprepare) (GstAudioSink *sink);
/* close the device, 关闭设备 */
gboolean (*close) (GstAudioSink *sink);
/* write samples to the device, 向音频设备写数据 */
gint (*write) (GstAudioSink *sink, gpointer data, guint length);
/* get number of frames queued in the device,获取设备队列里面有多少帧没有输出(即缓存) */
guint (*delay) (GstAudioSink *sink);
/* reset the audio device, unblock from a write,重置设备 */
void (*reset) (GstAudioSink *sink);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
;
我这里就是以oss音频 sink插件作为模板,将其源码复制出来,删除基于oss接口实现的 gstreamer audio sink接口的代码,然后再填充自己的代码, 其中 头文件 gstQnxAudioSink.h, 其内容如下:
/* GStreamer
* Copyright (C) gu.wen <454727014@qq.com>
*
* gstqnxaudiosink.h:
*
*/
#ifndef __GST_QNXAUDIO_H__
#define __GST_QNXAUDIO_H__
#include <gst/gst.h>
#include <gst/audio/gstaudiosink.h>
#include <glib/gtypes.h>
#include <sys/asoundlib.h> /** 包含qnx audio接口的头文件 */
G_BEGIN_DECLS
/** 定义方面操作的工具宏 */
#define GST_TYPE_QNXAUDIOSINK (gst_qnxaudio_sink_get_type())
#define GST_QNXAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \\
GST_TYPE_QNXAUDIOSINK, \\
GstQnxAudioSink))
#define GST_QNXAUDIOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \\
GST_TYPE_QNXAUDIOSINK, \\
GstQnxAudioSinkClass))
#define GST_IS_QNXAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \\
GST_TYPE_QNXAUDIOSINK))
#define GST_IS_QNXAUDIOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \\
GST_TYPE_QNXAUDIOSINK))
typedef struct _GstQnxAudioSink GstQnxAudioSink;
typedef struct _GstQnxAudioSinkClass GstQnxAudioSinkClass;
struct _GstQnxAudioSink
GstAudioSink sink; /** 继承audio sink, 这个成员变量必须放在首位 */
gchar *device; /** qnx audio 设备节点的路径 */
gint audioCard; /** 声卡id */
gint bytes_per_sample;
GstCaps *probed_caps; /** 存放检索到的caps信息 */
/** qnx audio 相关的 数据结构 */
snd_pcm_info_t info;
snd_pcm_t *pcm_handle;
snd_pcm_channel_info_t channelInfo;
snd_mixer_t *mixer_handle;
snd_mixer_group_t mixerGroup;
snd_pcm_channel_params_t channelParam;
snd_pcm_channel_setup_t channelSetup;
;
struct _GstQnxAudioSinkClass
/**类,用于定义接口,其完成的继承路径是
* _GstQnxAudioSinkClass ——> GSTAudioSinkClass ——> GstAudioBaseSinkClass
* ——> GstBaseSinkClass ——> GstElementClass
* 再向上就是和gobject相关的东西了,这里不涉及
*/
GstAudioSinkClass parent_class;
;
/** 获取GType,具体的参考 gobject/glib相关的信息 */
GType gst_qnxaudio_sink_get_type(void);
G_END_DECLS
#endif /* __GST_QNXAUDIO_H__ */
接下来再试重点, qnx audio sink 的实现源文件, 如下所示:
/* GStreamer
* Copyright (C) gu.wen <454727014@qq.com>
*
* gstqnxaudiosink.c:
*
*/
/**
* SECTION:element-qnxaudio
*
* This element lets you output sound using the qnx audio system (QNXAUDIO).
*
* Note that you should almost always use generic audio conversion elements
* like audioconvert and audioresample in front of an audiosink to make sure
* your pipeline works under all circumstances (those conversion elements will
* act in passthrough-mode if no conversion is necessary).
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! qnxaudio
* ]| will output a sine wave (continuous beep sound) to your sound card (with
* a very low volume as precaution).
* |[
* gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert !
* audioresample ! qnxaudio ]|
* will play an Ogg/Vorbis audio file and output it using the Open Sound System.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "gstQnxAudioSink.h"
#define PLUGIN_VERSION "00.01.00"
#define PACKAGE "gst-plugins-qnx"
#define GST_LICENSE "LGPL"
#define GST_PACKAGE_NAME "GStreamer qnx Plug-ins source release"
#define GST_PACKAGE_ORIGIN "Unknown package origin"
GST_DEBUG_CATEGORY_EXTERN(qnxaudio_debug);
#define GST_CAT_DEFAULT qnxaudio_debug
static void gst_qnxaudio_sink_dispose(GObject *object);
static void gst_qnxaudio_sink_finalise(GObject *object);
static void gst_qnxaudio_sink_get_property(GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static void gst_qnxaudio_sink_set_property(GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static GstCaps *gst_qnxaudio_sink_getcaps(GstBaseSink *bsink, GstCaps *filter);
static gboolean gst_qnxaudio_sink_open(GstAudioSink *asink);
static gboolean gst_qnxaudio_sink_close(GstAudioSink *asink);
static gboolean gst_qnxaudio_sink_prepare(GstAudioSink *asink,
GstAudioRingBufferSpec *spec);
static gboolean gst_qnxaudio_sink_unprepare(GstAudioSink *asink);
static gint gst_qnxaudio_sink_write(GstAudioSink *asink, gpointer data,
guint length);
static guint gst_qnxaudio_sink_delay(GstAudioSink *asink);
static void gst_qnxaudio_sink_reset(GstAudioSink *asink);
/* QnxAudioSink signals and args */
enum
LAST_SIGNAL
;
#define DEFAULT_DEVICE "/dev/snd/pcmPreferredp"
enum
PROP_0,
PROP_DEVICE,
;
#define FORMATS "" GST_AUDIO_NE(S16) "," GST_AUDIO_NE(U16) ", S8, U8 "
/** 定义 固定pad的工厂 */
static GstStaticPadTemplate qnxaudio_sink_factory =
GST_STATIC_PAD_TEMPLATE("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS("audio/x-raw, "
"format = (string) " FORMATS ", "
"layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], "
"channels = (int) 1; "
"audio/x-raw, "
"format = (string) " FORMATS ", "
"layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], "
"channels = (int) 2, "
"channel-mask = (bitmask) 0x3"));
/* static guint gst_qnxaudio_sink_signals[LAST_SIGNAL] = 0 ; */
#define gst_qnxaudio_sink_parent_class parent_class
G_DEFINE_TYPE(GstQnxAudioSink, gst_qnxaudio_sink, GST_TYPE_AUDIO_SINK);
static void gst_qnxaudio_sink_dispose(GObject *object)
/** override GObjectClass 的dispose接口 */
GstQnxAudioSink *qnxaudio = GST_QNXAUDIOSINK(object);
if (qnxaudio->probed_caps)
/**如果已经索引过qnx audio sink 的能力, 就是放已有的caps信息 */
gst_caps_unref(qnxaudio->probed_caps);
qnxaudio->probed_caps = NULL;
/** 再调用父类的dispose接口 */
G_OBJECT_CLASS(parent_class)->dispose(object);
static GstStructure *
gst_qnxaudio_helper_get_format_structure(unsigned int format_bit)
/** 根据qnx audio的类型生成caps信息的结构体 */
GstStructure *structure;
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
const gchar *format;
switch (format_bit)
case SND_PCM_SFMT_U8:
format = "U8";
break;
case SND_PCM_SFMT_S16_LE:
format = "S16LE";
break;
case SND_PCM_SFMT_S16_BE:
format = "S16BE";
break;
case SND_PCM_SFMT_S8:
format = "S8";
break;
case SND_PCM_SFMT_U16_LE:
format = "U16LE";
break;
case SND_PCM_SFMT_U16_BE:
format = "U16BE";
break;
default:
g_assert_not_reached();
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
return NULL;
printf("[%s.%d]===>:format: %s\\n", __FUNCTION__, __LINE__, format);
structure = gst_structure_new("audio/x-raw",
"format", G_TYPE_STRING, format,
"layout", G_TYPE_STRING, "interleaved", NULL);
return structure;
static GstCaps *
gst_qnxaudio_helper_probe_caps(snd_pcm_channel_info_t *channelInfo)
/** 索引qnx audio的能力信息 */
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
const guint probe_formats[] =
SND_PCM_SFMT_S16_LE, SND_PCM_SFMT_U16_LE, SND_PCM_SFMT_U8, SND_PCM_SFMT_S8;
#else
const guint probe_formats[] =
SND_PCM_SFMT_S16_BE, SND_PCM_SFMT_U16_BE, SND_PCM_SFMT_U8, SND_PCM_SFMT_S8;
#endif
GstStructure *structure;
GstCaps *caps;
int f;
/* FIXME test make sure we're not currently playing */
/* FIXME test both mono and stereo */
caps = gst_caps_new_empty();
/* assume that the most significant bit of format_mask is 0 */
for (f = 0; f < G_N_ELEMENTS(probe_formats); ++f)
printf("[%s.%d]===>:idx:%d, rate range(%d - %d)\\n",
__FUNCTION__, __LINE__, f,
channelInfo->min_rate, channelInfo->max_rate);
GValue rate_value = 0;
/* one big range */
g_value_init(&rate_value, GST_TYPE_INT_RANGE);
gst_value_set_int_range(&rate_value, channelInfo->min_rate,
(channelInfo->max_rate == -1) ?
channelInfo->min_rate :
channelInfo->max_rate);
structure = gst_qnxaudio_helper_get_format_structure(probe_formats[f]);
gst_structure_set(structure, "channels",
GST_TYPE_INT_RANGE, 1, 2, NULL);
gst_structure_set_value(structure, "rate", &rate_value);
g_value_unset(&rate_value);
gst_caps_append_structure(caps, structure);
if (gst_caps_is_empty(caps))
/* fixme: make user-visible */
GST_WARNING("Your qnx audio device could not be probed correctly");
else
caps = gst_caps_simplify(caps);
printf("[%s.%d]===>:probed caps: %p\\n",
__FUNCTION__, __LINE__, caps);
GST_DEBUG("probed caps: %" GST_PTR_FORMAT, caps);
return caps;
static void gst_qnxaudio_sink_class_init(GstQnxAudioSinkClass *klass)
/** 类初始化接口 */
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
GstAudioSinkClass *gstaudiosink_class;
gobject_class = (GObjectClass *)klass;
gstelement_class = (GstElementClass *)klass;
gstbasesink_class = (GstBaseSinkClass *)klass;
gstaudiosink_class = (GstAudioSinkClass *)klass;
parent_class = g_type_class_peek_parent(klass);
/** override 父类接口 */
gobject_class->dispose = gst_qnxaudio_sink_dispose;
gobject_class->finalize = gst_qnxaudio_sink_finalise;
gobject_class->get_property = gst_qnxaudio_sink_get_property;
gobject_class->set_property = gst_qnxaudio_sink_set_property;
/** 安装属性接口 */
g_object_class_install_property(gobject_class, PROP_DEVICE,
g_param_spec_string("device", "Device",
"QNXAUDIO device (usually /dev/dspN)",
DEFAULT_DEVICE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** override 父类接口 */
gstbasesink_class->get_caps =
GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_getcaps);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_open);
gstaudiosink_class->close = GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_close);
gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_prepare);
gstaudiosink_class->unprepare =
GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_unprepare);
gstaudiosink_class->write = GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_write);
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_delay);
gstaudiosink_class->reset = GST_DEBUG_FUNCPTR(gst_qnxaudio_sink_reset);
/** 设置qnx audio sink 元件的meta信息 */
gst_element_class_set_static_metadata(gstelement_class,
"Audio Sink (QNXAUDIO)",
"Sink/Audio",
"Output to a sound card via QNXAUDIO",
"guwen <454727014@qq.com>");
/** 添加固定pad工厂 */
gst_element_class_add_static_pad_template(gstelement_class,
&qnxaudio_sink_factory);
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
static void gst_qnxaudio_sink_init(GstQnxAudioSink *qnxaudio)
/** qnx audio sink数据结构初始化 */
GST_DEBUG_OBJECT(qnxaudio, "initializing qnxaudio");
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
qnxaudio->pcm_handle = NULL;
qnxaudio->mixer_handle = NULL;
qnxaudio->audioCard = -1;
qnxaudio->probed_caps = NULL;
qnxaudio->device = strdup(DEFAULT_DEVICE);
memset(&qnxaudio->channelInfo, 0, sizeof(qnxaudio->channelInfo));
memset(&qnxaudio->channelParam, 0, sizeof(qnxaudio->channelParam));
memset(&qnxaudio->channelSetup, 0, sizeof(qnxaudio->channelSetup));
memset(&qnxaudio->mixerGroup, 0, sizeof(qnxaudio->mixerGroup));
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
static void gst_qnxaudio_sink_finalise(GObject *object)
/** override finalise接口 */
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
GstQnxAudioSink *qnxaudio = GST_QNXAUDIOSINK(object);
g_free(qnxaudio->device);
G_OBJECT_CLASS(parent_class)->finalize((GObject *)(object));
static void
gst_qnxaudio_sink_set_property(GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
/** 设置属性 */
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
GstQnxAudioSink *sink;
sink = GST_QNXAUDIOSINK(object);
switch (prop_id)
case PROP_DEVICE:
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
g_free(sink->device);
sink->device = g_value_dup_string(value);
if (sink->probed_caps)
gst_caps_unref(sink->probed_caps);
sink->probed_caps = NULL;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
static void gst_qnxaudio_sink_get_property(GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
GstQnxAudioSink *sink;
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
sink = GST_QNXAUDIOSINK(object);
switch (prop_id)
case PROP_DEVICE:
g_value_set_string(value, sink->device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
static GstCaps *gst_qnxaudio_sink_getcaps(GstBaseSink *bsink,
GstCaps *filter)
GstQnxAudioSink *qnxaudio;
GstCaps *caps;
qnxaudio = GST_QNXAUDIOSINK(bsink);
// printf("[%s.%d]===>:pcm_handle: %p\\n",
// __FUNCTION__, __LINE__, qnxaudio->pcm_handle);
if (qnxaudio->pcm_handle == NULL)
printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
caps = gst_pad_get_pad_template_caps(GST_BASE_SINK_PAD(bsink));
else if (qnxaudio->probed_caps)
printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
caps = gst_caps_ref(qnxaudio->probed_caps);
else
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
caps = gst_qnxaudio_helper_probe_caps(&qnxaudio->channelInfo);
if (caps && !gst_caps_is_empty(caps))
qnxaudio->probed_caps = gst_caps_ref(caps);
if (filter && caps)
//printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
GstCaps *intersection;
intersection =
gst_caps_intersect_full(filter, caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref(caps);
return intersection;
else
printf("[%s.%d]===>:\\n", __FUNCTION__, __LINE__);
return caps;
static gint ilog2(gint x)
/* well... hacker's delight explains... */
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (以上是关于gstreamer移植qnx:编写gstreamer插件audio sink和video sink的主要内容,如果未能解决你的问题,请参考以下文章