From 52b7aab711367d16010453b8be05dbc57b0bc4f4 Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Sun, 24 Feb 2013 17:00:14 +0100 Subject: [PATCH] level: send last message on EOS --- gst/level/gstlevel.c | 133 +++++++++++++++++++++-------------- tests/check/elements/level.c | 119 +++++++++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 60 deletions(-) diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c index a5a4c98084..e58f5fc8a9 100644 --- a/gst/level/gstlevel.c +++ b/gst/level/gstlevel.c @@ -105,10 +105,6 @@ #include "config.h" #endif -/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - #include #include #include @@ -166,6 +162,9 @@ static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, static gboolean gst_level_start (GstBaseTransform * trans); static GstFlowReturn gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in); +static void gst_level_post_message (GstLevel * filter); +static gboolean gst_level_sink_event (GstBaseTransform * trans, + GstEvent * event); static void @@ -212,6 +211,7 @@ gst_level_class_init (GstLevelClass * klass) trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_level_set_caps); trans_class->start = GST_DEBUG_FUNCPTR (gst_level_start); trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_level_transform_ip); + trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_level_sink_event); trans_class->passthrough_on_same_caps = TRUE; } @@ -643,56 +643,7 @@ gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in) /* do we need to message ? */ if (filter->num_frames >= filter->interval_frames) { - if (filter->message) { - GstMessage *m; - GstClockTime duration = - GST_FRAMES_TO_CLOCK_TIME (filter->num_frames, rate); - - m = gst_level_message_new (filter, filter->message_ts, duration); - - GST_LOG_OBJECT (filter, - "message: ts %" GST_TIME_FORMAT ", num_frames %d", - GST_TIME_ARGS (filter->message_ts), filter->num_frames); - - for (i = 0; i < channels; ++i) { - gdouble RMS; - gdouble RMSdB, lastdB, decaydB; - - RMS = sqrt (filter->CS[i] / filter->num_frames); - GST_LOG_OBJECT (filter, - "message: channel %d, CS %f, num_frames %d, RMS %f", - i, filter->CS[i], filter->num_frames, RMS); - GST_LOG_OBJECT (filter, - "message: last_peak: %f, decay_peak: %f", - filter->last_peak[i], filter->decay_peak[i]); - /* RMS values are calculated in amplitude, so 20 * log 10 */ - RMSdB = 20 * log10 (RMS + EPSILON); - /* peak values are square sums, ie. power, so 10 * log 10 */ - lastdB = 10 * log10 (filter->last_peak[i] + EPSILON); - decaydB = 10 * log10 (filter->decay_peak[i] + EPSILON); - - if (filter->decay_peak[i] < filter->last_peak[i]) { - /* this can happen in certain cases, for example when - * the last peak is between decay_peak and decay_peak_base */ - GST_DEBUG_OBJECT (filter, - "message: decay peak dB %f smaller than last peak dB %f, copying", - decaydB, lastdB); - filter->decay_peak[i] = filter->last_peak[i]; - } - GST_LOG_OBJECT (filter, - "message: RMS %f dB, peak %f dB, decay %f dB", - RMSdB, lastdB, decaydB); - - gst_level_message_append_channel (m, RMSdB, lastdB, decaydB); - - /* reset cumulative and normal peak */ - filter->CS[i] = 0.0; - filter->last_peak[i] = 0.0; - } - - gst_element_post_message (GST_ELEMENT (filter), m); - } - filter->num_frames = 0; + gst_level_post_message (filter); } gst_buffer_unmap (in, &map); @@ -700,6 +651,80 @@ gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in) return GST_FLOW_OK; } +static void +gst_level_post_message (GstLevel * filter) +{ + guint i; + gint channels, rate; + + channels = GST_AUDIO_INFO_CHANNELS (&filter->info); + rate = GST_AUDIO_INFO_RATE (&filter->info); + + + if (filter->message) { + GstMessage *m; + GstClockTime duration = GST_FRAMES_TO_CLOCK_TIME (filter->num_frames, rate); + + m = gst_level_message_new (filter, filter->message_ts, duration); + + GST_LOG_OBJECT (filter, + "message: ts %" GST_TIME_FORMAT ", num_frames %d", + GST_TIME_ARGS (filter->message_ts), filter->num_frames); + + for (i = 0; i < channels; ++i) { + gdouble RMS; + gdouble RMSdB, lastdB, decaydB; + + RMS = sqrt (filter->CS[i] / filter->num_frames); + GST_LOG_OBJECT (filter, + "message: channel %d, CS %f, num_frames %d, RMS %f", + i, filter->CS[i], filter->num_frames, RMS); + GST_LOG_OBJECT (filter, + "message: last_peak: %f, decay_peak: %f", + filter->last_peak[i], filter->decay_peak[i]); + /* RMS values are calculated in amplitude, so 20 * log 10 */ + RMSdB = 20 * log10 (RMS + EPSILON); + /* peak values are square sums, ie. power, so 10 * log 10 */ + lastdB = 10 * log10 (filter->last_peak[i] + EPSILON); + decaydB = 10 * log10 (filter->decay_peak[i] + EPSILON); + + if (filter->decay_peak[i] < filter->last_peak[i]) { + /* this can happen in certain cases, for example when + * the last peak is between decay_peak and decay_peak_base */ + GST_DEBUG_OBJECT (filter, + "message: decay peak dB %f smaller than last peak dB %f, copying", + decaydB, lastdB); + filter->decay_peak[i] = filter->last_peak[i]; + } + GST_LOG_OBJECT (filter, + "message: RMS %f dB, peak %f dB, decay %f dB", + RMSdB, lastdB, decaydB); + + gst_level_message_append_channel (m, RMSdB, lastdB, decaydB); + + /* reset cumulative and normal peak */ + filter->CS[i] = 0.0; + filter->last_peak[i] = 0.0; + } + + gst_element_post_message (GST_ELEMENT (filter), m); + } + filter->num_frames = 0; +} + + +static gboolean +gst_level_sink_event (GstBaseTransform * trans, GstEvent * event) +{ + if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) { + GstLevel *filter = GST_LEVEL (trans); + + gst_level_post_message (filter); + } + + return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event); +} + static gboolean plugin_init (GstPlugin * plugin) { diff --git a/tests/check/elements/level.c b/tests/check/elements/level.c index f180fbb2d0..3ce7ad2833 100644 --- a/tests/check/elements/level.c +++ b/tests/check/elements/level.c @@ -20,18 +20,12 @@ * Boston, MA 02110-1301, USA. */ -/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - #include #include #include #include -gboolean have_eos = FALSE; - /* For ease of programming we use globals to keep refs for our floating * src and sink pads we create; otherwise we always have to do get_pad, * get_peer, and then remove references in every test function */ @@ -311,6 +305,118 @@ GST_START_TEST (test_int16_panned) GST_END_TEST; +GST_START_TEST (test_message_on_eos) +{ + GstElement *level; + GstBuffer *inbuffer, *outbuffer; + GstEvent *event; + GstBus *bus; + GstCaps *caps; + GstMessage *message; + const GstStructure *structure; + int i, j; + GstMapInfo map; + gint16 *data; + const GValue *list, *value; + GstClockTime endtime; + gdouble dB; + + level = setup_level (); + g_object_set (level, "message", TRUE, "interval", GST_SECOND / 5, NULL); + + fail_unless (gst_element_set_state (level, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* create a fake 0.1 sec buffer with a half-amplitude block signal */ + inbuffer = gst_buffer_new_and_alloc (400); + gst_buffer_map (inbuffer, &map, GST_MAP_WRITE); + data = (gint16 *) map.data; + for (j = 0; j < 200; ++j) { + *data = 16536; + ++data; + } + gst_buffer_unmap (inbuffer, &map); + caps = gst_caps_from_string (LEVEL_CAPS_STRING); + gst_pad_set_caps (mysrcpad, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* create a bus to get the level message on */ + bus = gst_bus_new (); + ASSERT_OBJECT_REFCOUNT (bus, "bus", 1); + gst_element_set_bus (level, bus); + ASSERT_OBJECT_REFCOUNT (bus, "bus", 2); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + + message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, 0); + fail_unless (message == NULL); + + event = gst_event_new_eos (); + fail_unless (gst_pad_push_event (mysrcpad, event) == TRUE); + + message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, 0); + fail_if (message == NULL); + + ASSERT_OBJECT_REFCOUNT (message, "message", 1); + + fail_unless (message != NULL); + fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (level)); + fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT); + structure = gst_message_get_structure (message); + fail_if (structure == NULL); + fail_unless_equals_string ((char *) gst_structure_get_name (structure), + "level"); + fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime)); + + /* block wave of half amplitude has -5.94 dB for rms, peak and decay */ + for (i = 0; i < 2; ++i) { + const gchar *fields[3] = { "rms", "peak", "decay" }; + for (j = 0; j < 3; ++j) { + GValueArray *arr; + + list = gst_structure_get_value (structure, fields[j]); + arr = g_value_get_boxed (list); + value = g_value_array_get_nth (arr, i); + dB = g_value_get_double (value); + GST_DEBUG ("%s is %lf", fields[j], dB); + fail_if (dB < -6.0); + fail_if (dB > -5.9); + } + } + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + + /* clean up */ + /* flush current messages,and future state change messages */ + gst_bus_set_flushing (bus, TRUE); + + /* message has a ref to the element */ + ASSERT_OBJECT_REFCOUNT (level, "level", 2); + gst_message_unref (message); + ASSERT_OBJECT_REFCOUNT (level, "level", 1); + + gst_element_set_bus (level, NULL); + ASSERT_OBJECT_REFCOUNT (bus, "bus", 1); + gst_object_unref (bus); + gst_buffer_unref (outbuffer); + fail_unless (gst_element_set_state (level, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); + ASSERT_OBJECT_REFCOUNT (level, "level", 1); + cleanup_level (level); +} + +GST_END_TEST; + + static Suite * level_suite (void) { @@ -320,6 +426,7 @@ level_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_int16); tcase_add_test (tc_chain, test_int16_panned); + tcase_add_test (tc_chain, test_message_on_eos); return s; }