...
 
Commits (73)
......@@ -832,6 +832,10 @@ if test "x$HAVE_CXX" = "xyes"; then
fi
AC_SUBST(VISIBILITY_CXXFLAGS)
dnl disable strict aliasing
AS_COMPILER_FLAG([-fno-strict-aliasing], [EXTRA_CFLAGS="-fno-strict-aliasing"])
AC_SUBST(EXTRA_CFLAGS)
dnl every flag in GST_OPTION_CFLAGS and GST_OPTION_CXXFLAGS can be overridden
dnl at make time with e.g. make ERROR_CFLAGS=""
GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)"
......@@ -851,8 +855,8 @@ AC_SUBST(GST_PLUGINS_BASE_CFLAGS)
dnl FIXME: do we want to rename to GST_ALL_* ?
dnl add GST_OPTION_CFLAGS, but overridable
GST_CFLAGS="$GST_CFLAGS $GST_STATIC_CFLAGS"
GST_CXXFLAGS="$GLIB_CFLAGS $GST_CFLAGS \$(GLIB_EXTRA_CFLAGS) \$(GST_OPTION_CXXFLAGS) \$(VISIBILITY_CXXFLAGS)"
GST_CFLAGS="$GLIB_CFLAGS $GST_CFLAGS \$(GLIB_EXTRA_CFLAGS) \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)"
GST_CXXFLAGS="$GLIB_CFLAGS $GST_CFLAGS $EXTRA_CFLAGS \$(GLIB_EXTRA_CFLAGS) \$(GST_OPTION_CXXFLAGS) \$(VISIBILITY_CXXFLAGS)"
GST_CFLAGS="$GLIB_CFLAGS $GST_CFLAGS $EXTRA_CFLAGS \$(GLIB_EXTRA_CFLAGS) \$(GST_OPTION_CFLAGS) \$(VISIBILITY_CFLAGS)"
AC_SUBST(GST_CFLAGS)
AC_SUBST(GST_CXXFLAGS)
dnl add GCOV libs because libtool strips -fprofile-arcs -ftest-coverage
......
......@@ -159,6 +159,18 @@ _set_caps_features (const GstCaps * caps, const gchar * feature_name)
return tmp;
}
static void
_remove_field (GstCaps * caps, const gchar * field)
{
guint n = gst_caps_get_size (caps);
guint i = 0;
for (i = 0; i < n; i++) {
GstStructure *s = gst_caps_get_structure (caps, i);
gst_structure_remove_field (s, field);
}
}
static GstCaps *
gst_gl_download_element_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
......@@ -174,10 +186,12 @@ gst_gl_download_element_transform_caps (GstBaseTransform * bt,
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_DMABUF);
_remove_field (newcaps, "texture-target");
tmp = gst_caps_merge (tmp, newcaps);
#endif
newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
_remove_field (newcaps, "texture-target");
tmp = gst_caps_merge (tmp, newcaps);
}
......
......@@ -48,6 +48,7 @@ G_DEFINE_TYPE_WITH_CODE (GstGLFilterBin, gst_gl_filter_bin,
GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT (gst_gl_filter_bin_debug,
"glfilterbin", 0, "glfilterbin element"););
static void gst_gl_filter_bin_finalize (GObject * object);
static void gst_gl_filter_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_filter_bin_set_property (GObject * object, guint prop_id,
......@@ -72,6 +73,7 @@ gst_gl_filter_bin_class_init (GstGLFilterBinClass * klass)
gobject_class->set_property = gst_gl_filter_bin_set_property;
gobject_class->get_property = gst_gl_filter_bin_get_property;
gobject_class->finalize = gst_gl_filter_bin_finalize;
gst_element_class_add_static_pad_template (element_class, &_src_pad_template);
......@@ -142,6 +144,17 @@ gst_gl_filter_bin_init (GstGLFilterBin * self)
}
}
static void
gst_gl_filter_bin_finalize (GObject * object)
{
GstGLFilterBin *self = GST_GL_FILTER_BIN (object);
if (self->filter)
gst_object_unref (self->filter);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
_connect_filter_element (GstGLFilterBin * self)
{
......@@ -159,18 +172,40 @@ _connect_filter_element (GstGLFilterBin * self)
return res;
}
void
gst_gl_filter_bin_finish_init_with_element (GstGLFilterBin * self,
GstElement * element)
/*
* @filter: (transfer full):
*/
static gboolean
gst_gl_filter_bin_set_filter (GstGLFilterBin * self, GstElement * filter)
{
g_return_if_fail (GST_IS_ELEMENT (element));
self->filter = element;
g_return_val_if_fail (GST_IS_ELEMENT (filter), FALSE);
if (!_connect_filter_element (self)) {
if (self->filter) {
gst_element_set_locked_state (self->filter, TRUE);
gst_bin_remove (GST_BIN (self), self->filter);
gst_element_set_state (self->filter, GST_STATE_NULL);
gst_object_unref (self->filter);
self->filter = NULL;
}
self->filter = filter;
if (filter && g_object_is_floating (filter))
gst_object_ref_sink (filter);
if (filter && !_connect_filter_element (self)) {
self->filter = NULL;
return FALSE;
}
return TRUE;
}
void
gst_gl_filter_bin_finish_init_with_element (GstGLFilterBin * self,
GstElement * element)
{
if (!gst_gl_filter_bin_set_filter (self, element))
gst_object_unref (element);
}
void
......@@ -210,17 +245,8 @@ gst_gl_filter_bin_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_FILTER:
{
GstElement *filter = g_value_get_object (value);
if (self->filter)
gst_bin_remove (GST_BIN (self), self->filter);
self->filter = filter;
if (filter) {
gst_object_ref_sink (filter);
_connect_filter_element (self);
}
gst_gl_filter_bin_set_filter (self, g_value_get_object (value));
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -240,10 +266,13 @@ gst_gl_filter_bin_change_state (GstElement * element, GstStateChange transition)
if (klass->create_element)
self->filter = klass->create_element ();
if (!self->filter)
if (!self->filter) {
g_signal_emit (element,
gst_gl_filter_bin_signals[SIGNAL_CREATE_ELEMENT], 0,
&self->filter);
if (self->filter && g_object_is_floating (self->filter))
gst_object_ref_sink (self->filter);
}
if (!self->filter) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
......
......@@ -122,7 +122,8 @@ enum
PROP_BIN_SHOW_PREROLL_FRAME,
PROP_BIN_OUTPUT_MULTIVIEW_LAYOUT,
PROP_BIN_OUTPUT_MULTIVIEW_FLAGS,
PROP_BIN_OUTPUT_MULTIVIEW_DOWNMIX_MODE
PROP_BIN_OUTPUT_MULTIVIEW_DOWNMIX_MODE,
PROP_BIN_LAST
};
enum
......@@ -284,6 +285,9 @@ gst_gl_image_sink_bin_class_init (GstGLImageSinkBinClass * klass)
"Output anaglyph type to generate when downmixing to mono",
GST_TYPE_GL_STEREO_DOWNMIX_MODE_TYPE, DEFAULT_MULTIVIEW_DOWNMIX,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_video_overlay_install_properties (gobject_class, PROP_BIN_LAST);
gst_gl_image_sink_bin_signals[SIGNAL_BIN_CLIENT_DRAW] =
g_signal_new ("client-draw", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2,
......@@ -389,7 +393,8 @@ enum
PROP_IGNORE_ALPHA,
PROP_OUTPUT_MULTIVIEW_LAYOUT,
PROP_OUTPUT_MULTIVIEW_FLAGS,
PROP_OUTPUT_MULTIVIEW_DOWNMIX_MODE
PROP_OUTPUT_MULTIVIEW_DOWNMIX_MODE,
PROP_LAST
};
enum
......@@ -692,6 +697,8 @@ gst_glimage_sink_class_init (GstGLImageSinkClass * klass)
GST_TYPE_GL_STEREO_DOWNMIX_MODE_TYPE, DEFAULT_MULTIVIEW_DOWNMIX,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_video_overlay_install_properties (gobject_class, PROP_LAST);
gst_element_class_set_metadata (element_class, "OpenGL video sink",
"Sink/Video", "A videosink based on OpenGL",
"Julien Isorce <julien.isorce@gmail.com>");
......@@ -827,7 +834,8 @@ gst_glimage_sink_set_property (GObject * object, guint prop_id,
GST_GLIMAGE_SINK_UNLOCK (glimage_sink);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
if (!gst_video_overlay_set_property (object, PROP_LAST, prop_id, value))
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
......@@ -885,7 +893,8 @@ gst_glimage_sink_get_property (GObject * object, guint prop_id,
g_value_set_enum (value, glimage_sink->mview_downmix_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
if (!gst_video_overlay_set_property (object, PROP_LAST, prop_id, value))
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
......@@ -984,11 +993,8 @@ _ensure_gl_setup (GstGLImageSink * gl_sink)
g_signal_connect (window, "mouse-event",
G_CALLBACK (gst_glimage_sink_mouse_event_cb), gl_sink);
if (gl_sink->x >= 0 && gl_sink->y >= 0 && gl_sink->width > 0 &&
gl_sink->height > 0) {
gst_gl_window_set_render_rectangle (window, gl_sink->x, gl_sink->y,
gl_sink->width, gl_sink->height);
}
gst_gl_window_set_render_rectangle (window, gl_sink->x, gl_sink->y,
gl_sink->width, gl_sink->height);
if (other_context)
gst_object_unref (other_context);
......@@ -1378,7 +1384,6 @@ static gboolean
update_output_format (GstGLImageSink * glimage_sink)
{
GstVideoInfo *out_info = &glimage_sink->out_info;
gboolean input_is_mono = FALSE;
GstVideoMultiviewMode mv_mode;
GstGLWindow *window = NULL;
GstGLTextureTarget previous_target;
......@@ -1392,14 +1397,7 @@ update_output_format (GstGLImageSink * glimage_sink)
mv_mode = GST_VIDEO_INFO_MULTIVIEW_MODE (&glimage_sink->in_info);
if (mv_mode == GST_VIDEO_MULTIVIEW_MODE_NONE ||
mv_mode == GST_VIDEO_MULTIVIEW_MODE_MONO ||
mv_mode == GST_VIDEO_MULTIVIEW_MODE_LEFT ||
mv_mode == GST_VIDEO_MULTIVIEW_MODE_RIGHT)
input_is_mono = TRUE;
if (input_is_mono == FALSE &&
glimage_sink->mview_output_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
if (glimage_sink->mview_output_mode != mv_mode) {
/* Input is multiview, and output wants a conversion - configure 3d converter now,
* otherwise defer it until either the caps or the 3D output mode changes */
gst_video_multiview_video_info_change_mode (out_info,
......
......@@ -145,6 +145,7 @@ static void gst_gl_mixer_bin_set_property (GObject * object, guint prop_id,
static void gst_gl_mixer_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_mixer_bin_dispose (GObject * object);
static void gst_gl_mixer_bin_finalize (GObject * object);
static GstPad *gst_gl_mixer_bin_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps);
......@@ -171,6 +172,7 @@ gst_gl_mixer_bin_class_init (GstGLMixerBinClass * klass)
gobject_class->get_property = gst_gl_mixer_bin_get_property;
gobject_class->set_property = gst_gl_mixer_bin_set_property;
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_gl_mixer_bin_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_bin_finalize);
g_object_class_install_property (gobject_class, PROP_MIXER,
g_param_spec_object ("mixer",
......@@ -257,6 +259,17 @@ gst_gl_mixer_bin_init (GstGLMixerBin * self)
GST_ERROR_OBJECT (self, "failed to create output chain");
}
static void
gst_gl_mixer_bin_finalize (GObject * object)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
if (self->mixer)
gst_object_unref (self->mixer);
G_OBJECT_CLASS (gst_gl_mixer_bin_parent_class)->finalize (object);
}
static void
gst_gl_mixer_bin_dispose (GObject * object)
{
......@@ -385,18 +398,40 @@ _connect_mixer_element (GstGLMixerBin * self)
return res;
}
void
gst_gl_mixer_bin_finish_init_with_element (GstGLMixerBin * self,
GstElement * element)
/*
* @mixer: (transfer full):
*/
static gboolean
gst_gl_mixer_bin_set_mixer (GstGLMixerBin * self, GstElement * mixer)
{
g_return_if_fail (GST_IS_ELEMENT (element));
g_return_val_if_fail (GST_IS_ELEMENT (mixer), FALSE);
self->mixer = element;
if (!_connect_mixer_element (self)) {
if (self->mixer) {
gst_element_set_locked_state (self->mixer, TRUE);
gst_bin_remove (GST_BIN (self), self->mixer);
gst_element_set_state (self->mixer, GST_STATE_NULL);
gst_object_unref (self->mixer);
self->mixer = NULL;
}
self->mixer = mixer;
if (mixer && g_object_is_floating (mixer))
gst_object_ref_sink (mixer);
if (mixer && !_connect_mixer_element (self)) {
self->mixer = NULL;
return FALSE;
}
return TRUE;
}
void
gst_gl_mixer_bin_finish_init_with_element (GstGLMixerBin * self,
GstElement * element)
{
if (!gst_gl_mixer_bin_set_mixer (self, element))
gst_object_unref (element);
}
void
......@@ -441,11 +476,7 @@ gst_gl_mixer_bin_set_property (GObject * object,
GstElement *mixer = g_value_get_object (value);
/* FIXME: deal with replacing a mixer */
g_return_if_fail (!self->mixer || (self->mixer == mixer));
self->mixer = mixer;
if (mixer) {
gst_object_ref_sink (mixer);
_connect_mixer_element (self);
}
gst_gl_mixer_bin_set_mixer (self, mixer);
break;
}
default:
......@@ -530,9 +561,12 @@ gst_gl_mixer_bin_change_state (GstElement * element, GstStateChange transition)
if (klass->create_element)
self->mixer = klass->create_element ();
if (!self->mixer)
if (!self->mixer) {
g_signal_emit (element,
gst_gl_mixer_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->mixer);
if (self->mixer && g_object_is_floating (self->mixer))
gst_object_ref_sink (self->mixer);
}
if (!self->mixer) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
......
......@@ -31,6 +31,7 @@
GST_DEBUG_CATEGORY (gst_debug_gl_sink_bin);
#define GST_CAT_DEFAULT gst_debug_gl_sink_bin
static void gst_gl_sink_bin_finalize (GObject * object);
static void gst_gl_sink_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec);
static void gst_gl_sink_bin_get_property (GObject * object, guint prop_id,
......@@ -119,6 +120,7 @@ gst_gl_sink_bin_class_init (GstGLSinkBinClass * klass)
gobject_class->set_property = gst_gl_sink_bin_set_property;
gobject_class->get_property = gst_gl_sink_bin_get_property;
gobject_class->finalize = gst_gl_sink_bin_finalize;
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio",
......@@ -264,6 +266,17 @@ gst_gl_sink_bin_init (GstGLSinkBin * self)
}
}
static void
gst_gl_sink_bin_finalize (GObject * object)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (object);
if (self->sink)
gst_object_unref (self->sink);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
_connect_sink_element (GstGLSinkBin * self)
{
......@@ -277,28 +290,40 @@ _connect_sink_element (GstGLSinkBin * self)
return FALSE;
}
static void
/*
* @sink: (transfer full):
*/
static gboolean
gst_gl_sink_bin_set_sink (GstGLSinkBin * self, GstElement * sink)
{
g_return_if_fail (GST_IS_ELEMENT (sink));
g_return_val_if_fail (GST_IS_ELEMENT (sink), FALSE);
if (self->sink) {
gst_element_set_locked_state (self->sink, TRUE);
gst_bin_remove (GST_BIN (self), self->sink);
gst_element_set_state (self->sink, GST_STATE_NULL);
gst_object_unref (self->sink);
self->sink = NULL;
}
/* We keep an indirect reference when the element is added */
self->sink = sink;
if (sink && !_connect_sink_element (self))
if (sink && g_object_is_floating (sink))
gst_object_ref_sink (sink);
if (sink && !_connect_sink_element (self)) {
self->sink = NULL;
return FALSE;
}
return TRUE;
}
void
gst_gl_sink_bin_finish_init_with_element (GstGLSinkBin * self,
GstElement * element)
{
gst_gl_sink_bin_set_sink (self, element);
if (!gst_gl_sink_bin_set_sink (self, element))
gst_object_unref (element);
}
void
......@@ -311,7 +336,7 @@ gst_gl_sink_bin_finish_init (GstGLSinkBin * self)
element = klass->create_element ();
if (element)
gst_gl_sink_bin_set_sink (self, element);
gst_gl_sink_bin_finish_init_with_element (self, element);
}
static void
......@@ -379,9 +404,12 @@ gst_gl_sink_bin_change_state (GstElement * element, GstStateChange transition)
if (klass->create_element)
self->sink = klass->create_element ();
if (!self->sink)
if (!self->sink) {
g_signal_emit (element,
gst_gl_sink_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->sink);
if (self->sink && g_object_is_floating (self->sink))
gst_object_ref_sink (self->sink);
}
if (!self->sink) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
......
......@@ -27,6 +27,7 @@
GST_DEBUG_CATEGORY (gst_debug_gl_src_bin);
#define GST_CAT_DEFAULT gst_debug_gl_src_bin
static void gst_gl_src_bin_finalize (GObject * object);
static void gst_gl_src_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec);
static void gst_gl_src_bin_get_property (GObject * object, guint prop_id,
......@@ -75,6 +76,7 @@ gst_gl_src_bin_class_init (GstGLSrcBinClass * klass)
gobject_class->set_property = gst_gl_src_bin_set_property;
gobject_class->get_property = gst_gl_src_bin_get_property;
gobject_class->finalize = gst_gl_src_bin_finalize;
g_object_class_install_property (gobject_class, PROP_SRC,
g_param_spec_object ("src",
......@@ -135,6 +137,17 @@ gst_gl_src_bin_init (GstGLSrcBin * self)
}
}
static void
gst_gl_src_bin_finalize (GObject * object)
{
GstGLSrcBin *self = GST_GL_SRC_BIN (object);
if (self->src)
gst_object_unref (self->src);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
_connect_src_element (GstGLSrcBin * self)
{
......@@ -151,18 +164,40 @@ _connect_src_element (GstGLSrcBin * self)
return res;
}
void
gst_gl_src_bin_finish_init_with_element (GstGLSrcBin * self,
GstElement * element)
/*
* @src: (transfer full):
*/
static gboolean
gst_gl_src_bin_set_src (GstGLSrcBin * self, GstElement * src)
{
g_return_if_fail (GST_IS_ELEMENT (element));
g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
self->src = element;
if (!_connect_src_element (self)) {
if (self->src) {
gst_element_set_locked_state (self->src, TRUE);
gst_bin_remove (GST_BIN (self), self->src);
gst_element_set_state (self->src, GST_STATE_NULL);
gst_object_unref (self->src);
self->src = NULL;
}
self->src = src;
if (src && g_object_is_floating (src))
gst_object_ref_sink (src);
if (src && !_connect_src_element (self)) {
self->src = NULL;
return FALSE;
}
return TRUE;
}
void
gst_gl_src_bin_finish_init_with_element (GstGLSrcBin * self,
GstElement * element)
{
if (!gst_gl_src_bin_set_src (self, element))
gst_object_unref (self->src);
}
void
......@@ -186,17 +221,8 @@ gst_gl_src_bin_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_SRC:
{
GstElement *src = g_value_get_object (value);
if (self->src)
gst_bin_remove (GST_BIN (self), self->src);
self->src = src;
if (src) {
gst_object_ref_sink (src);
_connect_src_element (self);
}
gst_gl_src_bin_set_src (self, g_value_get_object (value));
break;
}
default:
if (self->src)
g_object_set_property (G_OBJECT (self->src), pspec->name, value);
......@@ -238,9 +264,12 @@ gst_gl_src_bin_change_state (GstElement * element, GstStateChange transition)
if (klass->create_element)
self->src = klass->create_element ();
if (!self->src)
if (!self->src) {
g_signal_emit (element,
gst_gl_src_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->src);
if (self->src && g_object_is_floating (self->src))
gst_object_ref_sink (self->src);
}
if (!self->src) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
......
......@@ -778,7 +778,9 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
pad->prev_granule = pad->current_granule;
}
if (pad->map.is_ogm_text) {
if (G_UNLIKELY (offset + trim > packet->bytes))
goto invalid_packet;
else if (pad->map.is_ogm_text) {
/* check for invalid buffer sizes */
if (G_UNLIKELY (offset + trim >= packet->bytes))
goto empty_packet;
......@@ -901,6 +903,12 @@ empty_packet:
goto done;
}
invalid_packet:
{
GST_DEBUG_OBJECT (ogg, "Skipping invalid packet");
goto done;
}
no_timestamp:
{
GST_DEBUG_OBJECT (ogg, "skipping packet: no valid granule found yet");
......
This diff is collapsed.
......@@ -131,6 +131,11 @@ struct _GstAudioConverter
/* quant */
GstAudioQuantize *quant;
/* change layout */
GstAudioFormat chlayout_format;
GstAudioLayout chlayout_target;
gint chlayout_channels;
/* pack */
gboolean out_default;
AudioChain *chain_end; /* NULL for empty chain or points to the last element in the chain */
......@@ -567,6 +572,108 @@ do_quantize (AudioChain * chain, gpointer user_data)
return TRUE;
}
#define MAKE_INTERLEAVE_FUNC(type) \
static inline void \
interleave_##type (const type * in[], type * out[], \
gint num_samples, gint channels) \
{ \
gint s, c; \
for (s = 0; s < num_samples; s++) { \
for (c = 0; c < channels; c++) { \
out[0][s * channels + c] = in[c][s]; \
} \
} \
}
#define MAKE_DEINTERLEAVE_FUNC(type) \
static inline void \
deinterleave_##type (const type * in[], type * out[], \
gint num_samples, gint channels) \
{ \
gint s, c; \
for (s = 0; s < num_samples; s++) { \
for (c = 0; c < channels; c++) { \
out[c][s] = in[0][s * channels + c]; \
} \
} \
}
MAKE_INTERLEAVE_FUNC (gint16);
MAKE_INTERLEAVE_FUNC (gint32);
MAKE_INTERLEAVE_FUNC (gfloat);
MAKE_INTERLEAVE_FUNC (gdouble);
MAKE_DEINTERLEAVE_FUNC (gint16);
MAKE_DEINTERLEAVE_FUNC (gint32);
MAKE_DEINTERLEAVE_FUNC (gfloat);
MAKE_DEINTERLEAVE_FUNC (gdouble);
static gboolean
do_change_layout (AudioChain * chain, gpointer user_data)
{
GstAudioConverter *convert = user_data;
GstAudioFormat format = convert->chlayout_format;
GstAudioLayout out_layout = convert->chlayout_target;
gint channels = convert->chlayout_channels;
gsize num_samples;
gpointer *in, *out;
in = audio_chain_get_samples (chain->prev, &num_samples);
out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
if (out_layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
/* interleave */
GST_LOG ("interleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
switch (format) {
case GST_AUDIO_FORMAT_S16:
interleave_gint16 ((const gint16 **) in, (gint16 **) out,
num_samples, channels);
break;
case GST_AUDIO_FORMAT_S32:
interleave_gint32 ((const gint32 **) in, (gint32 **) out,
num_samples, channels);
break;
case GST_AUDIO_FORMAT_F32:
interleave_gfloat ((const gfloat **) in, (gfloat **) out,
num_samples, channels);
break;
case GST_AUDIO_FORMAT_F64:
interleave_gdouble ((const gdouble **) in, (gdouble **) out,
num_samples, channels);
break;
default:
g_assert_not_reached ();
break;
}
} else {
/* deinterleave */
GST_LOG ("deinterleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
switch (format) {
case GST_AUDIO_FORMAT_S16:
deinterleave_gint16 ((const gint16 **) in, (gint16 **) out,
num_samples, channels);
break;
case GST_AUDIO_FORMAT_S32:
deinterleave_gint32 ((const gint32 **) in, (gint32 **) out,
num_samples, channels);
break;
case GST_AUDIO_FORMAT_F32:
deinterleave_gfloat ((const gfloat **) in, (gfloat **) out,
num_samples, channels);
break;
case GST_AUDIO_FORMAT_F64:
deinterleave_gdouble ((const gdouble **) in, (gdouble **) out,
num_samples, channels);
break;
default:
g_assert_not_reached ();
break;
}
}
audio_chain_set_samples (chain, out, num_samples);
return TRUE;
}
static gboolean
is_intermediate_format (GstAudioFormat format)
{
......@@ -704,9 +811,16 @@ chain_mix (GstAudioConverter * convert, AudioChain * prev)
GstAudioInfo *out = &convert->out;
GstAudioFormat format = convert->current_format;
const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
GstAudioChannelMixerFlags flags = 0;
convert->current_channels = out->channels;
/* keep the input layout */
if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN;
flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT;
}
if (opt_matrix) {
gfloat **matrix = NULL;
......@@ -715,12 +829,10 @@ chain_mix (GstAudioConverter * convert, AudioChain * prev)
mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
convert->mix =
gst_audio_channel_mixer_new_with_matrix (0, format, in->channels,
gst_audio_channel_mixer_new_with_matrix (flags, format, in->channels,
out->channels, matrix);
} else {
GstAudioChannelMixerFlags flags;
flags =
flags |=
GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
flags |=
......@@ -766,8 +878,13 @@ chain_resample (GstAudioConverter * convert, AudioChain * prev)
flags = 0;
if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN;
}
/* if the resampler is activated, it is optimal to change layout here */
if (out->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT;
}
convert->current_layout = out->layout;
if (variable_rate)
flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
......@@ -860,6 +977,29 @@ chain_quantize (GstAudioConverter * convert, AudioChain * prev)
return prev;
}
static AudioChain *
chain_change_layout (GstAudioConverter * convert, AudioChain * prev)
{
GstAudioInfo *out = &convert->out;
if (convert->current_layout != out->layout) {
convert->current_layout = out->layout;
/* if there is only 1 channel, layouts are identical */
if (convert->current_channels > 1) {
convert->chlayout_target = convert->current_layout;
convert->chlayout_format = convert->current_format;
convert->chlayout_channels = convert->current_channels;
prev = audio_chain_new (prev, convert);
prev->allow_ip = FALSE;
prev->pass_alloc = FALSE;
audio_chain_set_make_func (prev, do_change_layout, convert, NULL);
}
}
return prev;
}
static AudioChain *
chain_pack (GstAudioConverter * convert, AudioChain * prev)
{
......@@ -1169,8 +1309,6 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
g_return_val_if_fail (in_info != NULL, FALSE);
g_return_val_if_fail (out_info != NULL, FALSE);
g_return_val_if_fail (in_info->layout == GST_AUDIO_LAYOUT_INTERLEAVED, FALSE);
g_return_val_if_fail (in_info->layout == out_info->layout, FALSE);
if (config)
opt_matrix =
......@@ -1211,7 +1349,9 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
prev = chain_convert_out (convert, prev);
/* step 6, optional quantize */
prev = chain_quantize (convert, prev);
/* step 7, pack */
/* step 7, change layout */
prev = chain_change_layout (convert, prev);
/* step 8, pack */
convert->chain_end = chain_pack (convert, prev);
convert->convert = converter_generic;
......@@ -1221,10 +1361,12 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
if (convert->mix_passthrough) {
if (out_info->finfo->format == in_info->finfo->format) {
if (convert->resampler == NULL) {
GST_INFO
("same formats, no resampler and passthrough mixing -> passthrough");
convert->convert = converter_passthrough;
convert->in_place = TRUE;
if (out_info->layout == in_info->layout) {
GST_INFO ("same formats, same layout, no resampler and "
"passthrough mixing -> passthrough");
convert->convert = converter_passthrough;
convert->in_place = TRUE;
}
} else {
if (is_intermediate_format (in_info->finfo->format)) {
GST_INFO ("same formats, and passthrough mixing -> only resampling");
......@@ -1233,7 +1375,7 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
}
} else if (GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION (out_info->finfo,
in_info->finfo)) {
if (convert->resampler == NULL) {
if (convert->resampler == NULL && out_info->layout == in_info->layout) {
GST_INFO ("no resampler, passthrough mixing -> only endian conversion");
convert->convert = converter_endian;
convert->in_place = TRUE;
......
......@@ -911,6 +911,23 @@ static DeinterleaveFunc deinterleave_funcs[] = {
deinterleave_gdouble
};
static void
copy_func (GstAudioResampler * resampler, gpointer sbuf[],
gpointer in[], gsize in_frames)
{
gint i, c, channels = resampler->channels;
gsize samples_avail = resampler->samples_avail;
for (c = 0; c < channels; c++) {
gpointer *s = sbuf[c] + (samples_avail * resampler->bps);
if (G_UNLIKELY (in == NULL)) {
for (i = 0; i < in_frames; i++)
s[i] = 0;
} else {
memcpy (s, in[c], in_frames * resampler->bps);
}
}
}
static void
calculate_kaiser_params (GstAudioResampler * resampler)
{
......@@ -1332,7 +1349,7 @@ gst_audio_resampler_new (GstAudioResamplerMethod method,
GstAudioFormat format, gint channels,
gint in_rate, gint out_rate, GstStructure * options)
{
gboolean non_interleaved;
gboolean non_interleaved_in, non_interleaved_out;
GstAudioResampler *resampler;
const GstAudioFormatInfo *info;
GstStructure *def_options = NULL;
......@@ -1376,14 +1393,17 @@ gst_audio_resampler_new (GstAudioResamplerMethod method,
resampler->bps = GST_AUDIO_FORMAT_INFO_WIDTH (info) / 8;
resampler->sbuf = g_malloc0 (sizeof (gpointer) * channels);
non_interleaved =
non_interleaved_in =
(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN);
non_interleaved_out =
(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT);
/* we resample each channel separately */
resampler->blocks = resampler->channels;
resampler->inc = 1;
resampler->ostride = non_interleaved ? 1 : resampler->channels;
resampler->deinterleave = deinterleave_funcs[resampler->format_index];
resampler->ostride = non_interleaved_out ? 1 : resampler->channels;
resampler->deinterleave = non_interleaved_in ?
copy_func : deinterleave_funcs[resampler->format_index];
resampler->convert_taps = convert_taps_funcs[resampler->format_index];
GST_DEBUG ("method %d, bps %d, channels %d", method, resampler->bps,
......
......@@ -80,9 +80,10 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
gint rate, gint bpf)
{
GstBuffer *ret;
GstAudioMeta *meta;
GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
gsize trim, size, osize;
gint trim, size, osize;
gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
TRUE;
......@@ -98,8 +99,11 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
* Calculate the missing values for the calculations,
* they won't be changed later though. */
meta = gst_buffer_get_audio_meta (buffer);
/* these variables measure samples */
trim = 0;
osize = size = gst_buffer_get_size (buffer);
osize = size = meta ? meta->samples : (gst_buffer_get_size (buffer) / bpf);
/* no data, nothing to clip */
if (!size)
......@@ -111,7 +115,7 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
duration = GST_BUFFER_DURATION (buffer);
} else {
change_duration = FALSE;
duration = gst_util_uint64_scale (size / bpf, GST_SECOND, rate);
duration = gst_util_uint64_scale (size, GST_SECOND, rate);
}
if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
......@@ -125,7 +129,7 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
offset_end = GST_BUFFER_OFFSET_END (buffer);
} else {
change_offset_end = FALSE;
offset_end = offset + size / bpf;
offset_end = offset + size;
}
if (segment->format == GST_FORMAT_TIME) {
......@@ -149,8 +153,8 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
if (change_offset)
offset += diff;
trim += diff * bpf;
size -= diff * bpf;
trim += diff;
size -= diff;
}
diff = stop - cstop;
......@@ -161,7 +165,7 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
if (change_offset_end)
offset_end -= diff;
size -= diff * bpf;
size -= diff;
}
} else {
gst_buffer_unref (buffer);
......@@ -188,8 +192,8 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
if (change_duration)
duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
trim += diff * bpf;
size -= diff * bpf;
trim += diff;
size -= diff;
}
diff = stop - cstop;
......@@ -199,7 +203,7 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
if (change_duration)
duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
size -= diff * bpf;
size -= diff;
}
} else {
gst_buffer_unref (buffer);
......@@ -219,10 +223,9 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
GST_BUFFER_DURATION (ret) = duration;
}
} else {
/* Get a writable buffer and apply all changes */
GST_DEBUG ("trim %" G_GSIZE_FORMAT " size %" G_GSIZE_FORMAT, trim, size);
ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, trim, size);
gst_buffer_unref (buffer);
/* cut out all the samples that are no longer relevant */
GST_DEBUG ("trim %d, size %d", trim, size);
ret = gst_audio_buffer_truncate (buffer, bpf, trim, size);
GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
if (ret) {
......@@ -235,8 +238,75 @@ gst_audio_buffer_clip (GstBuffer * buffer, const GstSegment * segment,
if (change_offset_end)
GST_BUFFER_OFFSET_END (ret) = offset_end;
} else {
GST_ERROR ("copy_region failed");
GST_ERROR ("gst_audio_buffer_truncate failed");
}
}
return ret;
}
/**
* gst_audio_buffer_truncate:
* @buffer: (transfer full): The buffer to truncate.
* @bpf: size of one audio frame in bytes. This is the size of one sample *
* number of channels.
* @trim: the number of samples to remove from the beginning of the buffer
* @samples: the final number of samples that should exist in this buffer or -1
* to use all the remaining samples if you are only removing samples from the
* beginning.
*
* Truncate the buffer to finally have @samples number of samples, removing
* the necessary amount of samples from the end and @trim number of samples
* from the beginning.
*
* After calling this function the caller does not own a reference to
* @buffer anymore.
*
* Returns: (transfer full): the truncated buffer or %NULL if the arguments
* were invalid
*
* Since: UNRELEASED
*/
GstBuffer *
gst_audio_buffer_truncate (GstBuffer * buffer, gint bpf, gint trim,
gint samples)
{
GstAudioMeta *meta = NULL;
GstBuffer *ret = NULL;
gint orig_samples, i;
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
g_return_val_if_fail (trim >= 0, NULL);
meta = gst_buffer_get_audio_meta (buffer);
orig_samples = meta ? meta->samples : gst_buffer_get_size (buffer) / bpf;
g_return_val_if_fail (trim < orig_samples, NULL);
g_return_val_if_fail (samples == -1 || trim + samples <= orig_samples, NULL);
if (samples == -1)
samples = orig_samples - trim;
/* nothing to truncate */
if (samples == orig_samples)
return buffer;
if (!meta || meta->layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
/* interleaved */
ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, trim * bpf,
samples * bpf);
gst_buffer_unref (buffer);
if ((meta = gst_buffer_get_audio_meta (ret)))
meta->samples = samples;
} else {
/* non-interleaved */
ret = gst_buffer_make_writable (buffer);
meta = gst_buffer_get_audio_meta (buffer);
meta->samples = samples;
for (i = 0; i < meta->channels; i++) {
meta->offsets[i] += trim * bpf / meta->channels;
}
}
return ret;
}
......@@ -94,6 +94,9 @@ GstBuffer * gst_audio_buffer_clip (GstBuffer *buffer,
const GstSegment *segment,
gint rate, gint bpf);
GST_EXPORT
GstBuffer * gst_audio_buffer_truncate (GstBuffer *buffer,
gint bpf, gint trim, gint samples);
G_END_DECLS
......
......@@ -304,3 +304,165 @@ gst_audio_clipping_meta_get_info (void)
}
return audio_clipping_meta_info;
}
static gboolean
gst_audio_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
{
GstAudioMeta *ameta = (GstAudioMeta *) meta;
ameta->format = GST_AUDIO_FORMAT_UNKNOWN;
ameta->layout = GST_AUDIO_LAYOUT_INTERLEAVED;
ameta->channels = ameta->samples = 0;
ameta->offsets = NULL;
return TRUE;
}
static void
gst_audio_meta_free (GstMeta * meta, GstBuffer * buffer)
{
GstAudioMeta *ameta = (GstAudioMeta *) meta;
if (ameta->offsets)
g_slice_free1 (ameta->channels * sizeof (gsize), ameta->offsets);
}
static gboolean
gst_audio_meta_transform (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, GQuark type, gpointer data)
{
GstAudioMeta *smeta, *dmeta;
smeta = (GstAudioMeta *) meta;
if (GST_META_TRANSFORM_IS_COPY (type)) {
dmeta = gst_buffer_add_audio_meta (dest, smeta->format, smeta->layout,
smeta->channels, smeta->samples, smeta->offsets);
if (!dmeta)
return FALSE;
} else {
/* return FALSE, if transform type is not supported */
return FALSE;
}
return TRUE;
}
GstAudioMeta *
gst_buffer_add_audio_meta (GstBuffer * buffer, GstAudioFormat format,
GstAudioLayout layout, gint channels, gint samples, gsize offsets[])
{
GstAudioMeta *meta;
gint i;
g_return_val_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN, NULL);
meta =
(GstAudioMeta *) gst_buffer_add_meta (buffer, GST_AUDIO_META_INFO, NULL);
meta->format = format;
meta->layout = layout;
meta->channels = channels;
meta->samples = samples;
if (layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
meta->offsets = g_slice_alloc (channels * sizeof (gsize));
if (offsets) {
for (i = 0; i < channels; i++)
meta->offsets[i] = offsets[i];
} else {
/* default offsets assume channels are laid out sequentially in memory */
const GstAudioFormatInfo *finfo =
gst_audio_format_get_info (meta->format);
for (i = 0; i < channels; i++)
meta->offsets[i] = i * samples * finfo->width / 8;
}
}
return meta;
}
gboolean
gst_audio_buffer_map (GstBuffer * buffer, GstAudioMapInfo * info,
GstMapFlags flags)
{
GstAudioMeta *meta = NULL;
gboolean ret = TRUE;
gint i;
meta = gst_buffer_get_audio_meta (buffer);
if (!meta || meta->layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
/* interleaved */
if (!gst_buffer_map (buffer, &info->map_info, flags))
return FALSE;
info->n_planes = 1;
info->plane_size = info->map_info.size;
info->planes = g_slice_alloc (info->n_planes * sizeof (gpointer));
info->planes[0] = info->map_info.data;
} else {
/* non-interleaved */
const GstAudioFormatInfo *finfo = gst_audio_format_get_info (meta->format);
if (!gst_buffer_map (buffer, &info->map_info, flags))
return FALSE;
info->n_planes = meta->channels;
info->plane_size = meta->samples * finfo->width / 8;
if (info->n_planes * info->plane_size > info->map_info.size) {
GST_ERROR ("Invalid buffer size according to its attached GstAudioMeta");
gst_buffer_unmap (buffer, &info->map_info);
return FALSE;
}
info->planes = g_slice_alloc (info->n_planes * sizeof (gpointer));
for (i = 0; i < meta->channels; i++)
info->planes[i] = info->map_info.data + meta->offsets[i];
}
return ret;
}
void
gst_audio_buffer_unmap (GstBuffer * buffer, GstAudioMapInfo * info)
{
gst_buffer_unmap (buffer, &info->map_info);
g_slice_free1 (info->n_planes * sizeof (gpointer), info->planes);
memset (info, 0, sizeof (GstAudioMapInfo));
}
GType
gst_audio_meta_api_get_type (void)
{
static volatile GType type;
static const gchar *tags[] = {
GST_META_TAG_AUDIO_STR, GST_META_TAG_AUDIO_CHANNELS_STR,
GST_META_TAG_AUDIO_RATE_STR, NULL
};
if (g_once_init_enter (&type)) {
GType _type = gst_meta_api_type_register ("GstAudioMetaAPI", tags);
g_once_init_leave (&type, _type);
}
return type;
}
const GstMetaInfo *
gst_audio_meta_get_info (void)
{
static const GstMetaInfo *audio_meta_info = NULL;
if (g_once_init_enter ((GstMetaInfo **) & audio_meta_info)) {
const GstMetaInfo *meta = gst_meta_register (GST_AUDIO_META_API_TYPE,
"GstAudioMeta", sizeof (GstAudioMeta),
gst_audio_meta_init,
gst_audio_meta_free,
gst_audio_meta_transform);
g_once_init_leave ((GstMetaInfo **) & audio_meta_info,
(GstMetaInfo *) meta);
}
return audio_meta_info;
}
......@@ -125,6 +125,60 @@ GstAudioClippingMeta * gst_buffer_add_audio_clipping_meta (GstBuffer *buffer,
guint64 start,
guint64 end);
#define GST_AUDIO_META_API_TYPE (gst_audio_meta_api_get_type())
#define GST_AUDIO_META_INFO (gst_audio_meta_get_info())
typedef struct _GstAudioMeta GstAudioMeta;
typedef struct {
gint n_planes;
gsize plane_size;
gpointer *planes;
GstMapInfo map_info;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
} GstAudioMapInfo;