audiomixer: Port to GstAggregator

https://bugzilla.gnome.org/show_bug.cgi?id=737183

Co-Authored by: Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
This commit is contained in:
Thibault Saunier 2014-05-28 16:29:37 +02:00
parent 2ddbaaf866
commit 183f4b3227
4 changed files with 406 additions and 673 deletions

View file

@ -6,11 +6,15 @@ include $(top_srcdir)/common/orc.mak
libgstaudiomixer_la_SOURCES = gstaudiomixer.c libgstaudiomixer_la_SOURCES = gstaudiomixer.c
nodist_libgstaudiomixer_la_SOURCES = $(ORC_NODIST_SOURCES) nodist_libgstaudiomixer_la_SOURCES = $(ORC_NODIST_SOURCES)
libgstaudiomixer_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(ORC_CFLAGS) libgstaudiomixer_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_CFLAGS) $(ORC_CFLAGS) \
-I$(top_srcdir)/gst-libs \
-I$(top_builddir)/gst-libs
libgstaudiomixer_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstaudiomixer_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstaudiomixer_la_LIBADD = \ libgstaudiomixer_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-@GST_API_VERSION@ \ -lgstaudio-@GST_API_VERSION@ \
$(top_builddir)/gst-libs/gst/base/libgstbadbase-$(GST_API_VERSION).la \
$(GST_BASE_LIBS) $(GST_LIBS) $(ORC_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(ORC_LIBS)
libgstaudiomixer_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) libgstaudiomixer_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
#define __GST_AUDIO_MIXER_H__ #define __GST_AUDIO_MIXER_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstcollectpads.h> #include <gst/base/gstaggregator.h>
#include <gst/audio/audio.h> #include <gst/audio/audio.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -49,12 +49,7 @@ typedef struct _GstAudioMixerPadClass GstAudioMixerPadClass;
* The audiomixer object structure. * The audiomixer object structure.
*/ */
struct _GstAudioMixer { struct _GstAudioMixer {
GstElement element; GstAggregator element;
GstPad *srcpad;
GstCollectPads *collect;
/* pad counter, used for creating unique request pads */
gint padcount;
/* the next are valid for both int and float */ /* the next are valid for both int and float */
GstAudioInfo info; GstAudioInfo info;
@ -64,13 +59,9 @@ struct _GstAudioMixer {
/* Buffer starting at offset containing block_size samples */ /* Buffer starting at offset containing block_size samples */
GstBuffer *current_buffer; GstBuffer *current_buffer;
/* sink event handling */
GstSegment segment;
volatile gboolean segment_pending;
volatile gboolean flush_stop_pending;
/* current caps */ /* current caps */
GstCaps *current_caps; GstCaps *current_caps;
gboolean send_caps;
/* target caps (set via property) */ /* target caps (set via property) */
GstCaps *filter_caps; GstCaps *filter_caps;
@ -83,16 +74,10 @@ struct _GstAudioMixer {
/* Size in samples that is output per buffer */ /* Size in samples that is output per buffer */
guint blocksize; guint blocksize;
/* Pending inline events */
GList *pending_events;
gboolean send_stream_start;
gboolean send_caps;
}; };
struct _GstAudioMixerClass { struct _GstAudioMixerClass {
GstElementClass parent_class; GstAggregatorClass parent_class;
}; };
GType gst_audiomixer_get_type (void); GType gst_audiomixer_get_type (void);
@ -105,17 +90,30 @@ GType gst_audiomixer_get_type (void);
#define GST_AUDIO_MIXER_PAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_MIXER_PAD,GstAudioMixerPadClass)) #define GST_AUDIO_MIXER_PAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_MIXER_PAD,GstAudioMixerPadClass))
struct _GstAudioMixerPad { struct _GstAudioMixerPad {
GstPad parent; GstAggregatorPad parent;
gdouble volume; gdouble volume;
gint volume_i32; gint volume_i32;
gint volume_i16; gint volume_i16;
gint volume_i8; gint volume_i8;
gboolean mute; gboolean mute;
/* < private > */
GstBuffer *buffer; /* current buffer we're mixing,
for comparison with collect.buffer
to see if we need to update our
cached values. */
guint position, size;
guint64 output_offset; /* Offset in output segment that
collect.pos refers to in the
current buffer. */
guint64 next_offset; /* Next expected offset in the input segment */
}; };
struct _GstAudioMixerPadClass { struct _GstAudioMixerPadClass {
GstPadClass parent_class; GstAggregatorPadClass parent_class;
}; };
GType gst_audiomixer_pad_get_type (void); GType gst_audiomixer_pad_get_type (void);

View file

@ -870,12 +870,35 @@ GST_END_TEST;
static GstBuffer *handoff_buffer = NULL; static GstBuffer *handoff_buffer = NULL;
static gboolean
_quit (GMainLoop * ml)
{
g_main_loop_quit (ml);
return G_SOURCE_REMOVE;
}
static void static void
handoff_buffer_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad, handoff_buffer_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
gpointer user_data) GstClockTime * wanted_end)
{ {
GST_DEBUG ("got buffer %p", buffer); GST_DEBUG ("got buffer -- SIZE: %ld -- %p DURATION is %" GST_TIME_FORMAT
" -- WANTED END %" GST_TIME_FORMAT, gst_buffer_get_size (buffer), buffer,
GST_TIME_ARGS (GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer)),
GST_TIME_ARGS (*wanted_end));
gst_buffer_replace (&handoff_buffer, buffer); gst_buffer_replace (&handoff_buffer, buffer);
/* Buffers we push in will be 'cut' into different smaller buffers,
* we make sure that the last chunck was pushes before we concider the buffer
* we pushed as being done */
if (main_loop && *wanted_end
&& *wanted_end <=
GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer)) {
*wanted_end = 0;
g_idle_add ((GSourceFunc) _quit, main_loop);
}
} }
/* check if clipping works as expected */ /* check if clipping works as expected */
@ -891,9 +914,14 @@ GST_START_TEST (test_clip)
GstEvent *event; GstEvent *event;
GstBuffer *buffer; GstBuffer *buffer;
GstCaps *caps; GstCaps *caps;
GMainLoop *local_mainloop;
GstClockTime wanted_end = 0;
GST_INFO ("preparing test"); GST_INFO ("preparing test");
local_mainloop = g_main_loop_new (NULL, FALSE);
main_loop = NULL;
/* build pipeline */ /* build pipeline */
bin = gst_pipeline_new ("pipeline"); bin = gst_pipeline_new ("pipeline");
bus = gst_element_get_bus (bin); bus = gst_element_get_bus (bin);
@ -907,7 +935,8 @@ GST_START_TEST (test_clip)
audiomixer = gst_element_factory_make ("audiomixer", "audiomixer"); audiomixer = gst_element_factory_make ("audiomixer", "audiomixer");
sink = gst_element_factory_make ("fakesink", "sink"); sink = gst_element_factory_make ("fakesink", "sink");
g_object_set (sink, "signal-handoffs", TRUE, NULL); g_object_set (sink, "signal-handoffs", TRUE, NULL);
g_signal_connect (sink, "handoff", (GCallback) handoff_buffer_cb, NULL); g_signal_connect (sink, "handoff", (GCallback) handoff_buffer_cb,
&wanted_end);
gst_bin_add_many (GST_BIN (bin), audiomixer, sink, NULL); gst_bin_add_many (GST_BIN (bin), audiomixer, sink, NULL);
res = gst_element_link (audiomixer, sink); res = gst_element_link (audiomixer, sink);
@ -948,8 +977,19 @@ GST_START_TEST (test_clip)
buffer = gst_buffer_new_and_alloc (44100); buffer = gst_buffer_new_and_alloc (44100);
GST_BUFFER_TIMESTAMP (buffer) = 0; GST_BUFFER_TIMESTAMP (buffer) = 0;
GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
GST_DEBUG ("pushing buffer %p", buffer); GST_DEBUG ("pushing buffer %p END is %" GST_TIME_FORMAT,
buffer,
GST_TIME_ARGS (GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer)));
ret = gst_pad_chain (sinkpad, buffer); ret = gst_pad_chain (sinkpad, buffer);
main_loop = local_mainloop;
/* The aggregation is done in a dedicated thread, so we can't
* not know when it is actually going to happen, so we just add\
* a 100 ms timeout to be able to then check that the aggregation
* did happen as we do not have much other choice.
*/
g_timeout_add (100, (GSourceFunc) _quit, main_loop);
g_main_loop_run (main_loop);
ck_assert_int_eq (ret, GST_FLOW_OK); ck_assert_int_eq (ret, GST_FLOW_OK);
fail_unless (handoff_buffer == NULL); fail_unless (handoff_buffer == NULL);
@ -957,9 +997,16 @@ GST_START_TEST (test_clip)
buffer = gst_buffer_new_and_alloc (44100); buffer = gst_buffer_new_and_alloc (44100);
GST_BUFFER_TIMESTAMP (buffer) = 900 * GST_MSECOND; GST_BUFFER_TIMESTAMP (buffer) = 900 * GST_MSECOND;
GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
GST_DEBUG ("pushing buffer %p", buffer);
wanted_end = 135 * GST_MSECOND;
GST_DEBUG ("pushing buffer %p START %" GST_TIME_FORMAT " -- DURATION is %"
GST_TIME_FORMAT, buffer, GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
main_loop = local_mainloop;
ret = gst_pad_chain (sinkpad, buffer); ret = gst_pad_chain (sinkpad, buffer);
ck_assert_int_eq (ret, GST_FLOW_OK); ck_assert_int_eq (ret, GST_FLOW_OK);
g_main_loop_run (main_loop);
fail_unless (handoff_buffer != NULL); fail_unless (handoff_buffer != NULL);
gst_buffer_replace (&handoff_buffer, NULL); gst_buffer_replace (&handoff_buffer, NULL);
@ -967,18 +1014,28 @@ GST_START_TEST (test_clip)
buffer = gst_buffer_new_and_alloc (44100); buffer = gst_buffer_new_and_alloc (44100);
GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND; GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
GST_DEBUG ("pushing buffer %p", buffer);
wanted_end = 390 * GST_MSECOND;
GST_DEBUG ("pushing buffer %p END is %" GST_TIME_FORMAT,
buffer,
GST_TIME_ARGS (GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer)));
ret = gst_pad_chain (sinkpad, buffer); ret = gst_pad_chain (sinkpad, buffer);
ck_assert_int_eq (ret, GST_FLOW_OK); ck_assert_int_eq (ret, GST_FLOW_OK);
g_main_loop_run (main_loop);
fail_unless (handoff_buffer != NULL); fail_unless (handoff_buffer != NULL);
gst_buffer_replace (&handoff_buffer, NULL); gst_buffer_replace (&handoff_buffer, NULL);
fail_unless (handoff_buffer == NULL);
/* should be clipped and ok */ /* should be clipped and ok */
buffer = gst_buffer_new_and_alloc (44100); buffer = gst_buffer_new_and_alloc (44100);
GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND; GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND;
GST_DEBUG ("pushing buffer %p", buffer); GST_DEBUG ("pushing buffer %p END is %" GST_TIME_FORMAT,
buffer,
GST_TIME_ARGS (GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer)));
ret = gst_pad_chain (sinkpad, buffer); ret = gst_pad_chain (sinkpad, buffer);
g_timeout_add (100, (GSourceFunc) _quit, main_loop);
g_main_loop_run (main_loop);
ck_assert_int_eq (ret, GST_FLOW_OK); ck_assert_int_eq (ret, GST_FLOW_OK);
fail_unless (handoff_buffer == NULL); fail_unless (handoff_buffer == NULL);
@ -1245,9 +1302,11 @@ GST_START_TEST (test_flush_start_flush_stop)
audiomixer_src = gst_element_get_static_pad (audiomixer, "src"); audiomixer_src = gst_element_get_static_pad (audiomixer, "src");
fail_if (GST_PAD_IS_FLUSHING (audiomixer_src)); fail_if (GST_PAD_IS_FLUSHING (audiomixer_src));
gst_pad_send_event (sinkpad1, gst_event_new_flush_start ()); gst_pad_send_event (sinkpad1, gst_event_new_flush_start ());
fail_unless (GST_PAD_IS_FLUSHING (audiomixer_src)); fail_if (GST_PAD_IS_FLUSHING (audiomixer_src));
fail_unless (GST_PAD_IS_FLUSHING (sinkpad1));
gst_pad_send_event (sinkpad1, gst_event_new_flush_stop (TRUE)); gst_pad_send_event (sinkpad1, gst_event_new_flush_stop (TRUE));
fail_if (GST_PAD_IS_FLUSHING (audiomixer_src)); fail_if (GST_PAD_IS_FLUSHING (audiomixer_src));
fail_if (GST_PAD_IS_FLUSHING (sinkpad1));
gst_object_unref (audiomixer_src); gst_object_unref (audiomixer_src);
gst_element_release_request_pad (audiomixer, sinkpad1); gst_element_release_request_pad (audiomixer, sinkpad1);