• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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