diff options
author | Thomas Vander Stichele <thomas (at) apestaart (dot) org> | 2013-02-24 19:05:07 +0100 |
---|---|---|
committer | Thomas Vander Stichele <thomas (at) apestaart (dot) org> | 2013-02-25 00:11:55 +0100 |
commit | 0290f21f7fd9ec0e0b180ab57f7be9d937b067ee (patch) | |
tree | b81229aee945f3f561ee949e94f15fb0bb2b5b00 | |
parent | a158d6111f1d42024bc314d65633615869a5fdcd (diff) |
level: send last message on EOS
-rw-r--r-- | gst/level/gstlevel.c | 121 | ||||
-rw-r--r-- | tests/check/elements/level.c | 113 |
2 files changed, 188 insertions, 46 deletions
diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c index 112c0fe20..19e02bcee 100644 --- a/gst/level/gstlevel.c +++ b/gst/level/gstlevel.c @@ -166,6 +166,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 +215,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,61 +647,86 @@ 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); + gst_level_post_message (filter); + } + + gst_buffer_unmap (in, &map); + + 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); + 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: 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; + "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_element_post_message (GST_ELEMENT (filter), m); + 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; } - filter->num_frames = 0; + + gst_element_post_message (GST_ELEMENT (filter), m); } + filter->num_frames = 0; +} - gst_buffer_unmap (in, &map); - return GST_FLOW_OK; +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 diff --git a/tests/check/elements/level.c b/tests/check/elements/level.c index d29518800..fa406122e 100644 --- a/tests/check/elements/level.c +++ b/tests/check/elements/level.c @@ -311,6 +311,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 +432,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; } |