1 #include <gst/gst.h>
2 #include <gst/base/gstaggregator.h>
3
4 #define MAKE_AND_ADD(var, pipe, name, label) \
5 G_STMT_START \
6 { \
7 GError* make_and_add_err = NULL; \
8 if (G_UNLIKELY(!(var = (gst_parse_bin_from_description_full( \
9 name, \
10 TRUE, \
11 NULL, \
12 GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS, \
13 &make_and_add_err))))) { \
14 GST_ERROR( \
15 "Could not create element %s (%s)", name, make_and_add_err->message); \
16 g_clear_error(&make_and_add_err); \
17 goto label; \
18 } \
19 if (G_UNLIKELY(!gst_bin_add(GST_BIN_CAST(pipe), var))) { \
20 GST_ERROR("Could not add element %s", name); \
21 goto label; \
22 } \
23 } \
24 G_STMT_END
25
26 static gboolean
check_aggregated_buffer(GstElement * agg,GstPad * pad,GHashTable * consumed_buffers)27 check_aggregated_buffer (GstElement * agg, GstPad * pad,
28 GHashTable * consumed_buffers)
29 {
30 GstSample *sample;
31 GList *pad_consumed_buffers;
32 GList *tmp;
33
34 sample =
35 gst_aggregator_peek_next_sample (GST_AGGREGATOR (agg),
36 GST_AGGREGATOR_PAD (pad));
37
38 pad_consumed_buffers = g_hash_table_lookup (consumed_buffers, pad);
39
40 for (tmp = pad_consumed_buffers; tmp; tmp = tmp->next) {
41 GstBuffer *consumed_buffer = (GstBuffer *) tmp->data;
42 gboolean aggregated = FALSE;
43
44 if (sample) {
45 aggregated =
46 consumed_buffer == gst_sample_get_buffer (sample) ? TRUE : FALSE;
47 }
48
49 gst_printerr ("One consumed buffer: %" GST_PTR_FORMAT
50 ", it was%s aggregated\n", consumed_buffer, aggregated ? "" : " not");
51 }
52
53 if (sample) {
54 gst_sample_unref (sample);
55 }
56
57 g_list_free_full (pad_consumed_buffers, (GDestroyNotify) gst_buffer_unref);
58 g_hash_table_steal (consumed_buffers, pad);
59
60 return TRUE;
61 }
62
63 static void
samples_selected_cb(GstElement * agg,GstSegment * segment,GstClockTime pts,GstClockTime dts,GstClockTime duration,GstStructure * info,GHashTable * consumed_buffers)64 samples_selected_cb (GstElement * agg, GstSegment * segment, GstClockTime pts,
65 GstClockTime dts, GstClockTime duration, GstStructure * info,
66 GHashTable * consumed_buffers)
67 {
68 gst_printerr
69 ("Compositor has selected the samples it will aggregate for output buffer with PTS %"
70 GST_TIME_FORMAT " and duration %" GST_TIME_FORMAT "\n",
71 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
72 gst_element_foreach_sink_pad (agg,
73 (GstElementForeachPadFunc) check_aggregated_buffer, consumed_buffers);
74 }
75
76 static void
pad_buffer_consumed_cb(GstAggregatorPad * pad,GstBuffer * buffer,GHashTable * consumed_buffers)77 pad_buffer_consumed_cb (GstAggregatorPad * pad, GstBuffer * buffer,
78 GHashTable * consumed_buffers)
79 {
80 GList *pad_consumed_buffers;
81 gboolean was_empty;
82
83 pad_consumed_buffers = g_hash_table_lookup (consumed_buffers, pad);
84
85 was_empty = (pad_consumed_buffers == NULL);
86
87 pad_consumed_buffers =
88 g_list_append (pad_consumed_buffers, gst_buffer_ref (buffer));
89
90 /* we know the list's head pointer doesn't change when items get appended */
91 if (was_empty)
92 g_hash_table_insert (consumed_buffers, pad, pad_consumed_buffers);
93 }
94
95 static gboolean
unref_consumed_buffers(gpointer key,GList * pad_consumed_buffers)96 unref_consumed_buffers (gpointer key, GList * pad_consumed_buffers)
97 {
98 g_list_free_full (pad_consumed_buffers, (GDestroyNotify) gst_buffer_unref);
99
100 return TRUE;
101 }
102
103 int
main(int ac,char ** av)104 main (int ac, char **av)
105 {
106 int ret = 0;
107 GstElement *pipe;
108 GstBus *bus;
109 GstElement *vsrc, *vcfltr1, *compositor, *vcfltr2, *vsink;
110 GstCaps *caps;
111 GstPad *pad;
112 GHashTable *consumed_buffers =
113 g_hash_table_new (g_direct_hash, g_direct_equal);
114
115 gst_init (NULL, NULL);
116
117 pipe = gst_pipeline_new (NULL);
118
119 MAKE_AND_ADD (vsrc, pipe, "videotestsrc", err);
120 MAKE_AND_ADD (vcfltr1, pipe, "capsfilter", err);
121 MAKE_AND_ADD (compositor, pipe, "compositor", err);
122 MAKE_AND_ADD (vcfltr2, pipe, "capsfilter", err);
123 MAKE_AND_ADD (vsink, pipe, "autovideosink", err);
124
125 if (!gst_element_link_many (vsrc, vcfltr1, compositor, vcfltr2, vsink, NULL)) {
126 GST_ERROR ("Failed to link pipeline");
127 goto err;
128 }
129
130 caps =
131 gst_caps_new_simple ("video/x-raw", "framerate", GST_TYPE_FRACTION, 30, 1,
132 NULL);
133 g_object_set (vcfltr1, "caps", caps, NULL);
134 gst_caps_unref (caps);
135
136 caps =
137 gst_caps_new_simple ("video/x-raw", "framerate", GST_TYPE_FRACTION, 6, 1,
138 NULL);
139 g_object_set (vcfltr2, "caps", caps, NULL);
140 gst_caps_unref (caps);
141
142 g_object_set (vsrc, "num-buffers", 300, NULL);
143
144 g_object_set (compositor, "emit-signals", TRUE, NULL);
145 g_signal_connect (compositor, "samples-selected",
146 G_CALLBACK (samples_selected_cb), consumed_buffers);
147
148 pad = gst_element_get_static_pad (compositor, "sink_0");
149 g_object_set (pad, "emit-signals", TRUE, NULL);
150 g_signal_connect (pad, "buffer-consumed", G_CALLBACK (pad_buffer_consumed_cb),
151 consumed_buffers);
152 gst_object_unref (pad);
153
154 gst_element_set_state (pipe, GST_STATE_PLAYING);
155
156 bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
157
158 gst_message_unref (gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
159 GST_MESSAGE_EOS));
160
161 gst_object_unref (bus);
162
163 done:
164 g_hash_table_foreach_remove (consumed_buffers,
165 (GHRFunc) unref_consumed_buffers, NULL);
166 g_hash_table_unref (consumed_buffers);
167 gst_element_set_state (pipe, GST_STATE_NULL);
168 gst_object_unref (pipe);
169 return ret;
170
171 err:
172 ret = 1;
173 goto done;
174 }
175