summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Vander Stichele <thomas (at) apestaart (dot) org>2013-02-24 19:05:07 +0100
committerThomas Vander Stichele <thomas (at) apestaart (dot) org>2013-02-25 00:11:55 +0100
commit0290f21f7fd9ec0e0b180ab57f7be9d937b067ee (patch)
treeb81229aee945f3f561ee949e94f15fb0bb2b5b00
parenta158d6111f1d42024bc314d65633615869a5fdcd (diff)
level: send last message on EOS
-rw-r--r--gst/level/gstlevel.c121
-rw-r--r--tests/check/elements/level.c113
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;
}