mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-01 22:21:13 +00:00
174 lines
5.8 KiB
C
174 lines
5.8 KiB
C
#include <gst/gst.h>
|
|
#include <gst/base/gstaggregator.h>
|
|
|
|
#define MAKE_AND_ADD(var, pipe, name, label) \
|
|
G_STMT_START \
|
|
{ \
|
|
GError* make_and_add_err = NULL; \
|
|
if (G_UNLIKELY(!(var = (gst_parse_bin_from_description_full( \
|
|
name, \
|
|
TRUE, \
|
|
NULL, \
|
|
GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS, \
|
|
&make_and_add_err))))) { \
|
|
GST_ERROR( \
|
|
"Could not create element %s (%s)", name, make_and_add_err->message); \
|
|
g_clear_error(&make_and_add_err); \
|
|
goto label; \
|
|
} \
|
|
if (G_UNLIKELY(!gst_bin_add(GST_BIN_CAST(pipe), var))) { \
|
|
GST_ERROR("Could not add element %s", name); \
|
|
goto label; \
|
|
} \
|
|
} \
|
|
G_STMT_END
|
|
|
|
static gboolean
|
|
check_aggregated_buffer (GstElement * agg, GstPad * pad,
|
|
GHashTable * consumed_buffers)
|
|
{
|
|
GstSample *sample;
|
|
GList *pad_consumed_buffers;
|
|
GList *tmp;
|
|
|
|
sample =
|
|
gst_aggregator_peek_next_sample (GST_AGGREGATOR (agg),
|
|
GST_AGGREGATOR_PAD (pad));
|
|
|
|
pad_consumed_buffers = g_hash_table_lookup (consumed_buffers, pad);
|
|
|
|
for (tmp = pad_consumed_buffers; tmp; tmp = tmp->next) {
|
|
GstBuffer *consumed_buffer = (GstBuffer *) tmp->data;
|
|
gboolean aggregated = FALSE;
|
|
|
|
if (sample) {
|
|
aggregated =
|
|
consumed_buffer == gst_sample_get_buffer (sample) ? TRUE : FALSE;
|
|
}
|
|
|
|
gst_printerr ("One consumed buffer: %" GST_PTR_FORMAT
|
|
", it was%s aggregated\n", consumed_buffer, aggregated ? "" : " not");
|
|
}
|
|
|
|
if (sample) {
|
|
gst_sample_unref (sample);
|
|
}
|
|
|
|
g_list_free_full (pad_consumed_buffers, (GDestroyNotify) gst_buffer_unref);
|
|
g_hash_table_steal (consumed_buffers, pad);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
samples_selected_cb (GstElement * agg, GstSegment * segment, GstClockTime pts,
|
|
GstClockTime dts, GstClockTime duration, GstStructure * info,
|
|
GHashTable * consumed_buffers)
|
|
{
|
|
gst_printerr
|
|
("Compositor has selected the samples it will aggregate for output buffer with PTS %"
|
|
GST_TIME_FORMAT " and duration %" GST_TIME_FORMAT "\n",
|
|
GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
|
|
gst_element_foreach_sink_pad (agg,
|
|
(GstElementForeachPadFunc) check_aggregated_buffer, consumed_buffers);
|
|
}
|
|
|
|
static void
|
|
pad_buffer_consumed_cb (GstAggregatorPad * pad, GstBuffer * buffer,
|
|
GHashTable * consumed_buffers)
|
|
{
|
|
GList *pad_consumed_buffers;
|
|
gboolean was_empty;
|
|
|
|
pad_consumed_buffers = g_hash_table_lookup (consumed_buffers, pad);
|
|
|
|
was_empty = (pad_consumed_buffers == NULL);
|
|
|
|
pad_consumed_buffers =
|
|
g_list_append (pad_consumed_buffers, gst_buffer_ref (buffer));
|
|
|
|
/* we know the list's head pointer doesn't change when items get appended */
|
|
if (was_empty)
|
|
g_hash_table_insert (consumed_buffers, pad, pad_consumed_buffers);
|
|
}
|
|
|
|
static gboolean
|
|
unref_consumed_buffers (gpointer key, GList * pad_consumed_buffers)
|
|
{
|
|
g_list_free_full (pad_consumed_buffers, (GDestroyNotify) gst_buffer_unref);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int
|
|
main (int ac, char **av)
|
|
{
|
|
int ret = 0;
|
|
GstElement *pipe;
|
|
GstBus *bus;
|
|
GstElement *vsrc, *vcfltr1, *compositor, *vcfltr2, *vsink;
|
|
GstCaps *caps;
|
|
GstPad *pad;
|
|
GHashTable *consumed_buffers =
|
|
g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
|
|
gst_init (NULL, NULL);
|
|
|
|
pipe = gst_pipeline_new (NULL);
|
|
|
|
MAKE_AND_ADD (vsrc, pipe, "videotestsrc", err);
|
|
MAKE_AND_ADD (vcfltr1, pipe, "capsfilter", err);
|
|
MAKE_AND_ADD (compositor, pipe, "compositor", err);
|
|
MAKE_AND_ADD (vcfltr2, pipe, "capsfilter", err);
|
|
MAKE_AND_ADD (vsink, pipe, "autovideosink", err);
|
|
|
|
if (!gst_element_link_many (vsrc, vcfltr1, compositor, vcfltr2, vsink, NULL)) {
|
|
GST_ERROR ("Failed to link pipeline");
|
|
goto err;
|
|
}
|
|
|
|
caps =
|
|
gst_caps_new_simple ("video/x-raw", "framerate", GST_TYPE_FRACTION, 30, 1,
|
|
NULL);
|
|
g_object_set (vcfltr1, "caps", caps, NULL);
|
|
gst_caps_unref (caps);
|
|
|
|
caps =
|
|
gst_caps_new_simple ("video/x-raw", "framerate", GST_TYPE_FRACTION, 6, 1,
|
|
NULL);
|
|
g_object_set (vcfltr2, "caps", caps, NULL);
|
|
gst_caps_unref (caps);
|
|
|
|
g_object_set (vsrc, "num-buffers", 300, NULL);
|
|
|
|
g_object_set (compositor, "emit-signals", TRUE, NULL);
|
|
g_signal_connect (compositor, "samples-selected",
|
|
G_CALLBACK (samples_selected_cb), consumed_buffers);
|
|
|
|
pad = gst_element_get_static_pad (compositor, "sink_0");
|
|
g_object_set (pad, "emit-signals", TRUE, NULL);
|
|
g_signal_connect (pad, "buffer-consumed", G_CALLBACK (pad_buffer_consumed_cb),
|
|
consumed_buffers);
|
|
gst_object_unref (pad);
|
|
|
|
gst_element_set_state (pipe, GST_STATE_PLAYING);
|
|
|
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
|
|
|
|
gst_message_unref (gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
|
|
GST_MESSAGE_EOS));
|
|
|
|
gst_object_unref (bus);
|
|
|
|
done:
|
|
g_hash_table_foreach_remove (consumed_buffers,
|
|
(GHRFunc) unref_consumed_buffers, NULL);
|
|
g_hash_table_unref (consumed_buffers);
|
|
gst_element_set_state (pipe, GST_STATE_NULL);
|
|
gst_object_unref (pipe);
|
|
return ret;
|
|
|
|
err:
|
|
ret = 1;
|
|
goto done;
|
|
}
|