Merge branch 'master' into 0.11

Conflicts:
	configure.ac
	gst-libs/gst/audio/gstbaseaudiosink.c
	gst/audioconvert/channelmixtest.c
	gst/playback/gstplaybasebin.c
	gst/playback/gstsubtitleoverlay.c
	tests/examples/Makefile.am
	tests/examples/audio/Makefile.am
This commit is contained in:
Wim Taymans 2011-10-27 15:44:58 +02:00
commit 016d036137
20 changed files with 347 additions and 165 deletions

View file

@ -61,9 +61,12 @@ GST_PLUGINS_BASE_BUILT_SOURCES := \
gst/audiorate/Android.mk \
gst/volume/Android.mk \
tools/Android.mk \
ext/vorbis/Android.mk \
ext/ogg/Android.mk
ifneq ($(NDK_BUILD), true)
GST_PLUGINS_BASE_BUILT_SOURCES += ext/vorbis/Android.mk
endif
GST_PLUGINS_BASE_BUILT_SOURCES := $(patsubst %, $(abspath $(GST_PLUGINS_BASE_TOP))/%, $(GST_PLUGINS_BASE_BUILT_SOURCES))
@ -119,5 +122,7 @@ CONFIGURE_TARGETS += gst-plugins-base-configure
-include $(GST_PLUGINS_BASE_TOP)/gst/audiorate/Android.mk
-include $(GST_PLUGINS_BASE_TOP)/gst/volume/Android.mk
-include $(GST_PLUGINS_BASE_TOP)/ext/ogg/Android.mk
ifneq ($(NDK_BUILD), true)
-include $(GST_PLUGINS_BASE_TOP)/ext/vorbis/Android.mk
endif
-include $(GST_PLUGINS_BASE_TOP)/tools/Android.mk

View file

@ -77,6 +77,7 @@ CRUFT_FILES = \
$(top_builddir)/common/shave \
$(top_builddir)/common/shave-libtool \
$(top_builddir)/gst-libs/gst/audio/testchannels \
$(top_builddir)/tests/examples/volume/volume \
$(top_builddir)/tools/gst-discoverer
CRUFT_DIRS = \

View file

@ -1697,7 +1697,9 @@ gst_ogg_chain_new_stream (GstOggChain * chain, guint32 serialno)
GST_DEBUG_OBJECT (chain->ogg,
"creating new stream %08x in chain %p", serialno, chain);
ret = g_object_new (GST_TYPE_OGG_PAD, NULL);
name = g_strdup_printf ("serial_%08x", serialno);
ret = g_object_new (GST_TYPE_OGG_PAD, "name", name, NULL);
g_free (name);
/* we own this one */
gst_object_ref_sink (ret);
@ -1711,10 +1713,6 @@ gst_ogg_chain_new_stream (GstOggChain * chain, guint32 serialno)
if (ogg_stream_init (&ret->map.stream, serialno) != 0)
goto init_failed;
name = g_strdup_printf ("serial_%08x", serialno);
gst_object_set_name (GST_OBJECT (ret), name);
g_free (name);
/* FIXME: either do something with it or remove it */
list = gst_tag_list_new ();
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno,
@ -3077,6 +3075,7 @@ gst_ogg_demux_get_duration_push (GstOggDemux * ogg, int flags)
} else {
GST_INFO_OBJECT (ogg, "Seek failed, duration will stay unknown");
ogg->push_state = PUSH_PLAYING;
ogg->push_disable_seeking = TRUE;
return FALSE;
}
}

View file

@ -428,9 +428,6 @@ vorbis_handle_header_packet (GstVorbisDec * vd, ogg_packet * packet)
break;
}
/* consumer header packet/frame */
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (vd), NULL, 1);
return res;
/* ERRORS */
@ -482,7 +479,7 @@ vorbis_dec_handle_header_caps (GstVorbisDec * vd)
GstBuffer *buf = NULL;
gint i = 0;
while (result == GST_FLOW_OK) {
while (result == GST_FLOW_OK && i < gst_value_array_get_size (array)) {
value = gst_value_array_get_value (array, i);
buf = gst_value_get_buffer (value);
if (!buf)
@ -668,6 +665,8 @@ vorbis_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
goto done;
}
result = vorbis_handle_header_packet (vd, packet);
/* consumer header packet/frame */
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (vd), NULL, 1);
} else {
GstClockTime timestamp, duration;

View file

@ -1031,7 +1031,7 @@ gst_audio_decoder_drain (GstAudioDecoder * dec)
{
GstFlowReturn ret;
if (dec->priv->drained)
if (dec->priv->drained && !dec->priv->gather)
return GST_FLOW_OK;
else {
/* dispatch reverse pending buffers */

View file

@ -1335,8 +1335,11 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink,
"align with prev sample, ABS (%" G_GINT64_FORMAT ") < %"
G_GINT64_FORMAT, align, maxdrift);
} else {
gint64 diff_s G_GNUC_UNUSED;
/* calculate sample diff in seconds for error message */
gint64 diff_s = gst_util_uint64_scale_int (diff, GST_SECOND, rate);
diff_s = gst_util_uint64_scale_int (diff, GST_SECOND, rate);
/* timestamps drifted apart from previous samples too much, we need to
* resync. We log this as an element warning. */
GST_WARNING_OBJECT (sink,

View file

@ -26,15 +26,6 @@ noinst_HEADERS = \
gstfastrandom.h \
plugin.h
#TESTS = channelmixtest
#noinst_PROGRAMS = channelmixtest
#channelmixtest_CFLAGS = $(GST_CFLAGS)
#channelmixtest_LDADD = libgstaudioconvert.la \
# $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
# $(GST_LIBS)
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
-:PROJECT libgstaudioconvert -:SHARED libgstaudioconvert \

View file

@ -1,95 +0,0 @@
/* GStreamer
* Copyright (C) 2005 Benjamin Otte <otte@gnome.org>
*
* channelmixtest.c: simple test of channel mixing
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstchannelmix.h"
#include "plugin.h"
int
main (gint argc, gchar ** argv)
{
GstElement *bin, *src, *sink;
GstAudioConvert *c;
GstCaps *caps;
guint i, j, k;
struct
{
gchar *sinkcaps;
gchar *srccaps;
gfloat matrix[6][6]; /* use a predefined matrix here, makes stuff simpler */
} tests[] = {
/* stereo => mono */
{
"audio/x-raw, channels=2", "audio/x-raw, channels=1", { {
0.5,}, {
0.5,},}},
/* mono => stereo */
{
"audio/x-raw, channels=1", "audio/x-raw, channels=2", { {
1, 1,},}}
};
gst_init (&argc, &argv);
for (i = 0; i < G_N_ELEMENTS (tests); i++) {
g_print ("running test %u\n", i);
bin = gst_element_factory_make ("pipeline", NULL);
c = g_object_new (GST_TYPE_AUDIO_CONVERT, NULL);
/* avoid gst being braindead */
gst_object_set_name (GST_OBJECT (c), "shuddup");
src = gst_element_factory_make ("fakesrc", NULL);
sink = gst_element_factory_make ("fakesink", NULL);
gst_bin_add_many (GST_BIN (bin), src, c, sink, NULL);
caps = gst_caps_from_string (tests[i].sinkcaps);
g_assert (caps);
if (!gst_element_link_filtered (src, GST_ELEMENT (c), caps))
g_assert_not_reached ();
gst_caps_unref (caps);
caps = gst_caps_from_string (tests[i].srccaps);
g_assert (caps);
if (!gst_element_link_filtered (GST_ELEMENT (c), sink, caps))
g_assert_not_reached ();
gst_caps_unref (caps);
if (!gst_element_set_state (bin, GST_STATE_PLAYING))
g_assert_not_reached ();
g_assert (c->srccaps.channels <= 6);
g_assert (c->sinkcaps.channels <= 6);
for (j = 0; j < 6; j++) {
for (k = 0; k < 6; k++) {
if (j < c->sinkcaps.channels && k < c->srccaps.channels) {
if (tests[i].matrix[j][k] != c->matrix[j][k]) {
g_printerr ("matrix[j][k] should be %g but is %g\n",
tests[i].matrix[j][k], c->matrix[j][k]);
g_assert_not_reached ();
}
} else {
g_assert (tests[i].matrix[j][k] == 0);
}
}
}
gst_object_unref (bin);
}
return 0;
}

View file

@ -174,6 +174,8 @@ struct _GstDecodeBin
gboolean expose_allstreams; /* Whether to expose unknow type streams or not */
gboolean upstream_seekable; /* if upstream is seekable */
GList *filtered; /* elements for which error messages are filtered */
};
struct _GstDecodeBinClass
@ -289,6 +291,7 @@ static void caps_notify_cb (GstPad * pad, GParamSpec * unused,
static GstPad *find_sink_pad (GstElement * element);
static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
GstStateChange transition);
static void gst_decode_bin_handle_message (GstBin * bin, GstMessage * message);
#define EXPOSE_LOCK(dbin) G_STMT_START { \
GST_LOG_OBJECT (dbin, \
@ -584,9 +587,11 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
{
GObjectClass *gobject_klass;
GstElementClass *gstelement_klass;
GstBinClass *gstbin_klass;
gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass;
gstbin_klass = (GstBinClass *) klass;
parent_class = g_type_class_peek_parent (klass);
@ -898,6 +903,9 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
gstbin_klass->handle_message =
GST_DEBUG_FUNCPTR (gst_decode_bin_handle_message);
}
/* Must be called with factories lock! */
@ -1692,6 +1700,21 @@ setup_caps_delay:
}
}
static void
add_error_filter (GstDecodeBin * dbin, GstElement * element)
{
GST_OBJECT_LOCK (dbin);
dbin->filtered = g_list_prepend (dbin->filtered, element);
GST_OBJECT_UNLOCK (dbin);
}
static void
remove_error_filter (GstDecodeBin * dbin, GstElement * element)
{
GST_OBJECT_LOCK (dbin);
dbin->filtered = g_list_remove (dbin->filtered, element);
GST_OBJECT_UNLOCK (dbin);
}
/* connect_pad:
*
@ -1856,45 +1879,52 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
continue;
}
/* ... activate it ... We do this before adding it to the bin so that we
* don't accidentally make it post error messages that will stop
* everything. */
if ((gst_element_set_state (element,
GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
GST_ELEMENT_NAME (element));
gst_object_unref (element);
continue;
}
/* Filter errors, this will prevent the element from causing the pipeline
* to error while we test it using READY state. */
add_error_filter (dbin, element);
/* 2.3. Find its sink pad, this should work after activating it. */
if (!(sinkpad = find_sink_pad (element))) {
GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
GST_ELEMENT_NAME (element));
gst_element_set_state (element, GST_STATE_NULL);
gst_object_unref (element);
continue;
}
/* 2.4 add it ... */
/* ... add it ... */
if (!(gst_bin_add (GST_BIN_CAST (dbin), element))) {
GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
GST_ELEMENT_NAME (element));
gst_object_unref (sinkpad);
gst_element_set_state (element, GST_STATE_NULL);
remove_error_filter (dbin, element);
gst_object_unref (element);
continue;
}
/* 2.5 ...and try to link */
/* Find its sink pad. */
if (!(sinkpad = find_sink_pad (element))) {
GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
GST_ELEMENT_NAME (element));
remove_error_filter (dbin, element);
gst_bin_remove (GST_BIN (dbin), element);
continue;
}
/* ... and try to link */
if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s",
GST_DEBUG_PAD_NAME (sinkpad));
gst_element_set_state (element, GST_STATE_NULL);
remove_error_filter (dbin, element);
gst_object_unref (sinkpad);
gst_bin_remove (GST_BIN (dbin), element);
continue;
}
/* ... activate it ... */
if ((gst_element_set_state (element,
GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
GST_ELEMENT_NAME (element));
remove_error_filter (dbin, element);
gst_object_unref (sinkpad);
gst_bin_remove (GST_BIN (dbin), element);
continue;
}
/* Stop filtering errors. */
remove_error_filter (dbin, element);
gst_object_unref (sinkpad);
GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
@ -3162,6 +3192,9 @@ beach:
GST_DEBUG ("Chain %p (handled:%d, last_group:%d, drained:%d, switched:%d)",
chain, handled, *last_group, *drained, *switched);
if (*drained)
g_signal_emit (dbin, gst_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
return handled;
}
@ -4003,6 +4036,24 @@ activate_failed:
}
}
static void
gst_decode_bin_handle_message (GstBin * bin, GstMessage * msg)
{
GstDecodeBin *dbin = GST_DECODE_BIN (bin);
gboolean drop = FALSE;
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
GST_OBJECT_LOCK (dbin);
drop = (g_list_find (dbin->filtered, GST_MESSAGE_SRC (msg)) != NULL);
GST_OBJECT_UNLOCK (dbin);
}
if (drop)
gst_message_unref (msg);
else
GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
}
gboolean
gst_decode_bin_plugin_init (GstPlugin * plugin)
{

View file

@ -336,13 +336,18 @@ gst_play_sink_audio_convert_getcaps (GstPad * pad, GstCaps * filter)
GstPlaySinkAudioConvert *self =
GST_PLAY_SINK_AUDIO_CONVERT (gst_pad_get_parent (pad));
GstCaps *ret;
GstPad *otherpad, *peer;
GstPad *otherpad, *peer = NULL;
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
otherpad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad));
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
peer = gst_pad_get_peer (otherpad);
if (otherpad) {
peer = gst_pad_get_peer (otherpad);
gst_object_unref (otherpad);
otherpad = NULL;
}
if (peer) {
ret = gst_pad_get_caps (peer, filter);
gst_object_unref (peer);
@ -350,7 +355,6 @@ gst_play_sink_audio_convert_getcaps (GstPad * pad, GstCaps * filter)
ret = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
}
gst_object_unref (otherpad);
gst_object_unref (self);
return ret;

View file

@ -122,8 +122,7 @@ block_video (GstSubtitleOverlay * self)
if (self->video_block_pad) {
self->video_block_id =
gst_pad_add_probe (self->video_block_pad, GST_PROBE_TYPE_BLOCK,
_pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
_pad_blocked_cb, self, NULL);
}
}
@ -146,8 +145,7 @@ block_subtitle (GstSubtitleOverlay * self)
if (self->subtitle_block_pad) {
self->subtitle_block_id =
gst_pad_add_probe (self->subtitle_block_pad, GST_PROBE_TYPE_BLOCK,
_pad_blocked_cb, gst_object_ref (self),
(GDestroyNotify) gst_object_unref);
_pad_blocked_cb, self, NULL);
}
}
@ -805,7 +803,6 @@ _pad_blocked_cb (GstPad * pad, GstProbeType type, gpointer type_data,
/* Unblock pads */
unblock_video (self);
unblock_subtitle (self);
goto out;
} else if (target) {
gst_object_unref (target);
@ -2059,6 +2056,7 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self)
templ = gst_static_pad_template_get (&srctemplate);
self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ);
gst_object_unref (templ);
proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->srcpad)));
@ -2073,6 +2071,7 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self)
templ = gst_static_pad_template_get (&video_sinktemplate);
self->video_sinkpad =
gst_ghost_pad_new_no_target_from_template ("video_sink", templ);
gst_object_unref (templ);
gst_pad_set_event_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_event));
gst_pad_set_chain_function (self->video_sinkpad,
@ -2082,12 +2081,13 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self)
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(self->video_sinkpad)));
self->video_block_pad = proxypad;
gst_object_unref (proxypad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->video_sinkpad);
templ = gst_static_pad_template_get (&subtitle_sinktemplate);
self->subtitle_sinkpad =
gst_ghost_pad_new_no_target_from_template ("subtitle_sink", templ);
gst_object_unref (templ);
gst_pad_set_link_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_link));
gst_pad_set_unlink_function (self->subtitle_sinkpad,
@ -2105,6 +2105,7 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self)
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(self->subtitle_sinkpad)));
self->subtitle_block_pad = proxypad;
gst_object_unref (proxypad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->subtitle_sinkpad);

View file

@ -1920,8 +1920,9 @@ gst_ximagesink_class_init (GstXImageSinkClass * klass)
g_param_spec_string ("display", "Display", "X Display name",
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
g_param_spec_boolean ("synchronous", "Synchronous", "When enabled, runs "
"the X display in synchronous mode. (used only for debugging)", FALSE,
g_param_spec_boolean ("synchronous", "Synchronous",
"When enabled, runs the X display in synchronous mode. "
"(unrelated to A/V sync, used only for debugging)", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",

View file

@ -2826,8 +2826,8 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS,
g_param_spec_boolean ("synchronous", "Synchronous",
"When enabled, runs "
"the X display in synchronous mode. (used only for debugging)", FALSE,
"When enabled, runs the X display in synchronous mode. "
"(unrelated to A/V sync, used only for debugging)", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",

View file

@ -8,8 +8,9 @@ if USE_GIO
GIO_SUBDIRS = gio
endif
SUBDIRS = app audio dynamic $(FT2_SUBDIRS) $(GIO_SUBDIRS) overlay playrec volume encoding
SUBDIRS = app audio dynamic $(FT2_SUBDIRS) $(GIO_SUBDIRS) overlay playrec encoding
DIST_SUBDIRS = app audio dynamic gio overlay seek snapshot playrec volume encoding
DIST_SUBDIRS = app audio dynamic gio overlay seek snapshot playrec encoding
include $(top_srcdir)/common/parallel-subdirs.mak

View file

@ -1 +1,4 @@
audiomix
testchannels
volume

View file

@ -1,6 +1,21 @@
if HAVE_GTK
GTK_EXAMPLES = audiomix volume
else
GTK_EXAMPLES =
endif
noinst_PROGRAMS = testchannels $(GTK_EXAMPLES)
noinst_PROGRAMS = testchannels
testchannels_SOURCES = testchannels.c
testchannels_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
testchannels_LDADD = $(top_builddir)/gst-libs/gst/audio/libgstaudio-$(GST_MAJORMINOR).la \
$(GST_LIBS)
if HAVE_GTK
audiomix_SOURCES = audiomix.c
audiomix_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -D_GNU_SOURCE
audiomix_LDADD = $(GST_LIBS) $(GTK_LIBS) $(LIBM)
volume_SOURCES = volume.c
volume_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -D_GNU_SOURCE
volume_LDADD = $(GST_LIBS) $(GTK_LIBS) $(LIBM)
endif

View file

@ -0,0 +1,210 @@
/* GStreamer
*
* audiomix.c: sample audio mixing application
*
* Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gtk/gtk.h>
/* global items for the interaction */
static GtkWidget *scale;
static GObject *volumes[2];
static gint num_vol = 0;
static void
value_changed_callback (GtkWidget * widget, gpointer * user_data)
{
gdouble value = gtk_range_get_value (GTK_RANGE (widget));
g_object_set (volumes[0], "volume", 1.0 - value, NULL);
g_object_set (volumes[1], "volume", value, NULL);
}
static void
setup_gui (GstElement * volume, gchar * file_name1, gchar * file_name2)
{
GtkWidget *window, *layout, *label;
gchar *name, *ext;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "audiomix");
g_signal_connect (window, "destroy", gtk_main_quit, NULL);
layout = gtk_table_new (2, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (layout), 6);
gtk_container_add (GTK_CONTAINER (window), layout);
/* channel labels */
name = g_path_get_basename (file_name1);
if ((ext = strrchr (name, '.')))
*ext = '\0';
label = gtk_label_new (name);
g_free (name);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach_defaults (GTK_TABLE (layout), label, 0, 1, 0, 1);
gtk_table_attach_defaults (GTK_TABLE (layout), gtk_label_new ("|"), 1, 2, 0,
1);
name = g_path_get_basename (file_name2);
if ((ext = strrchr (name, '.')))
*ext = '\0';
label = gtk_label_new (name);
g_free (name);
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
gtk_table_attach_defaults (GTK_TABLE (layout), label, 2, 3, 0, 1);
/* mix slider */
scale = gtk_hscale_new_with_range (0.0, 1.0, 1.0 / 200.0);
gtk_range_set_value (GTK_RANGE (scale), 0.0);
gtk_widget_set_size_request (scale, 200, -1);
gtk_table_attach_defaults (GTK_TABLE (layout), scale, 0, 3, 1, 2);
g_signal_connect (scale, "value-changed",
G_CALLBACK (value_changed_callback), volume);
gtk_widget_show_all (GTK_WIDGET (window));
}
static void
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
const GstStructure *s;
s = gst_message_get_structure (message);
g_print ("message from \"%s\" (%s): ",
GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
if (s) {
gchar *sstr;
sstr = gst_structure_to_string (s);
g_print ("%s\n", sstr);
g_free (sstr);
} else {
g_print ("no message details\n");
}
}
static void
eos_message_received (GstBus * bus, GstMessage * message,
GstPipeline * pipeline)
{
message_received (bus, message, pipeline);
gtk_main_quit ();
}
static void
dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer user_data)
{
GstPad *target = GST_PAD (user_data);
gst_pad_link (newpad, target);
gst_object_unref (target);
}
static void
make_mixer_channel (GstElement * pipeline, GstElement * mix, gchar * file_name)
{
GstElement *filesrc, *decodebin, *volume, *convert, *format;
GstCaps *caps;
/* prepare mixer channel */
filesrc = gst_element_factory_make ("filesrc", NULL);
decodebin = gst_element_factory_make ("decodebin2", NULL);
volume = gst_element_factory_make ("volume", NULL);
convert = gst_element_factory_make ("audioconvert", NULL);
format = gst_element_factory_make ("capsfilter", NULL);
gst_bin_add_many (GST_BIN (pipeline), filesrc, decodebin, volume, convert,
format, NULL);
gst_element_link (filesrc, decodebin);
gst_element_link_many (volume, convert, format, mix, NULL);
/* configure elements */
g_object_set (filesrc, "location", file_name, NULL);
g_object_set (volume, "volume", (num_vol == 0) ? 1.0 : 0.0, NULL);
caps = gst_caps_from_string ("audio/x-raw-int, "
"channels = (int) 2, "
"endianness = (int) BYTE_ORDER, "
"width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true");
g_object_set (format, "caps", caps, NULL);
gst_caps_unref (caps);
/* remember volume element */
volumes[num_vol++] = (GObject *) volume;
/* handle dynamic pads */
g_signal_connect (G_OBJECT (decodebin), "pad-added",
G_CALLBACK (dynamic_link), gst_element_get_static_pad (volume, "sink"));
}
int
main (int argc, char *argv[])
{
GstElement *pipeline = NULL;
GstElement *mix, *convert, *sink;
GstBus *bus;
if (argc < 3) {
g_print ("Usage: audiomix <file1> <file2>\n");
return 1;
}
gst_init (&argc, &argv);
gtk_init (&argc, &argv);
/* prepare tail of pipeline */
pipeline = gst_pipeline_new ("audiomix");
mix = gst_element_factory_make ("adder", NULL);
convert = gst_element_factory_make ("audioconvert", NULL);
sink = gst_element_factory_make ("autoaudiosink", NULL);
gst_bin_add_many (GST_BIN (pipeline), mix, convert, sink, NULL);
gst_element_link_many (mix, convert, sink, NULL);
/* prepare mixer channel strips */
make_mixer_channel (pipeline, mix, argv[1]);
make_mixer_channel (pipeline, mix, argv[2]);
/* setup message handling */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
g_signal_connect (bus, "message::error", (GCallback) message_received,
pipeline);
g_signal_connect (bus, "message::warning", (GCallback) message_received,
pipeline);
g_signal_connect (bus, "message::eos", (GCallback) eos_message_received,
pipeline);
/* setup GUI */
setup_gui (pipeline, argv[1], argv[2]);
/* go to main loop */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gtk_main ();
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}

View file

@ -30,8 +30,8 @@
#include <gtk/gtk.h>
/* global pointer for the scale widget */
GtkWidget *elapsed;
GtkWidget *scale;
static GtkWidget *elapsed;
static GtkWidget *scale;
#ifndef M_LN10
#define M_LN10 (log(10.0))

View file

@ -1 +0,0 @@
volume

View file

@ -1,6 +0,0 @@
if HAVE_GTK
noinst_PROGRAMS = volume
volume_SOURCES = volume.c
volume_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) -D_GNU_SOURCE
volume_LDADD = $(GST_LIBS) $(GTK_LIBS) $(LIBM)
endif