1 #include "common.h"
2 
3 void
poll_the_bus(GstBus * bus)4 poll_the_bus (GstBus * bus)
5 {
6   GstMessage *message;
7   gboolean carry_on = TRUE;
8 
9   while (carry_on) {
10     message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 10);
11     if (message) {
12       switch (GST_MESSAGE_TYPE (message)) {
13         case GST_MESSAGE_EOS:
14           /* we should check if we really finished here */
15           GST_DEBUG ("Got an EOS");
16           carry_on = FALSE;
17           break;
18         case GST_MESSAGE_SEGMENT_START:
19         case GST_MESSAGE_SEGMENT_DONE:
20           /* We shouldn't see any segement messages, since we didn't do a segment seek */
21           GST_WARNING ("Saw a Segment start/stop");
22           fail_if (TRUE);
23           break;
24         case GST_MESSAGE_ERROR:
25           fail_error_message (message);
26         default:
27           break;
28       }
29       gst_mini_object_unref (GST_MINI_OBJECT (message));
30     }
31   }
32 }
33 
34 static gboolean
nle_object_commit(GstElement * nlesource,gboolean recurse)35 nle_object_commit (GstElement * nlesource, gboolean recurse)
36 {
37   gboolean ret;
38 
39   g_signal_emit_by_name (nlesource, "commit", recurse, &ret);
40 
41   return ret;
42 }
43 
44 GstElement *
gst_element_factory_make_or_warn(const gchar * factoryname,const gchar * name)45 gst_element_factory_make_or_warn (const gchar * factoryname, const gchar * name)
46 {
47   GstElement *element;
48 
49   element = gst_element_factory_make (factoryname, name);
50   fail_unless (element != NULL, "Failed to make element %s", factoryname);
51   return element;
52 }
53 
54 void
composition_pad_added_cb(GstElement * composition,GstPad * pad,CollectStructure * collect)55 composition_pad_added_cb (GstElement * composition, GstPad * pad,
56     CollectStructure * collect)
57 {
58   fail_if (!(gst_element_link_pads_full (composition, GST_OBJECT_NAME (pad),
59               collect->sink, "sink", GST_PAD_LINK_CHECK_NOTHING)));
60 }
61 
62 /* return TRUE to discard the Segment */
63 static gboolean
compare_segments(CollectStructure * collect,Segment * segment,GstEvent * event)64 compare_segments (CollectStructure * collect, Segment * segment,
65     GstEvent * event)
66 {
67   const GstSegment *received_segment;
68   guint64 running_stop, running_start, running_duration;
69 
70   gst_event_parse_segment (event, &received_segment);
71 
72   GST_DEBUG ("Got Segment rate:%f, format:%s, start:%" GST_TIME_FORMAT
73       ", stop:%" GST_TIME_FORMAT ", time:%" GST_TIME_FORMAT
74       ", base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT,
75       received_segment->rate, gst_format_get_name (received_segment->format),
76       GST_TIME_ARGS (received_segment->start),
77       GST_TIME_ARGS (received_segment->stop),
78       GST_TIME_ARGS (received_segment->time),
79       GST_TIME_ARGS (received_segment->base),
80       GST_TIME_ARGS (received_segment->offset));
81   GST_DEBUG ("[RUNNING] start:%" GST_TIME_FORMAT " [STREAM] start:%"
82       GST_TIME_FORMAT,
83       GST_TIME_ARGS (gst_segment_to_running_time (received_segment,
84               GST_FORMAT_TIME, received_segment->start)),
85       GST_TIME_ARGS (gst_segment_to_stream_time (received_segment,
86               GST_FORMAT_TIME, received_segment->start)));
87 
88   GST_DEBUG ("Expecting rate:%f, format:%s, start:%" GST_TIME_FORMAT
89       ", stop:%" GST_TIME_FORMAT ", position:%" GST_TIME_FORMAT ", base:%"
90       GST_TIME_FORMAT, segment->rate, gst_format_get_name (segment->format),
91       GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop),
92       GST_TIME_ARGS (segment->position),
93       GST_TIME_ARGS (collect->expected_base));
94 
95   running_start =
96       gst_segment_to_running_time (received_segment, GST_FORMAT_TIME,
97       received_segment->start);
98   running_stop =
99       gst_segment_to_running_time (received_segment, GST_FORMAT_TIME,
100       received_segment->stop);
101   running_duration = running_stop - running_start;
102   fail_if (received_segment->rate != segment->rate);
103   fail_if (received_segment->format != segment->format);
104   fail_unless_equals_int64 (received_segment->time, segment->position);
105   fail_unless_equals_int64 (received_segment->base, collect->expected_base);
106   fail_unless_equals_uint64 (received_segment->stop - received_segment->start,
107       segment->stop - segment->start);
108 
109   collect->expected_base += running_duration;
110 
111   GST_DEBUG ("Segment was valid, discarding expected Segment");
112 
113   return TRUE;
114 }
115 
116 static GstPadProbeReturn
sinkpad_event_probe(GstPad * sinkpad,GstEvent * event,CollectStructure * collect)117 sinkpad_event_probe (GstPad * sinkpad, GstEvent * event,
118     CollectStructure * collect)
119 {
120   Segment *segment;
121 
122   GST_DEBUG_OBJECT (sinkpad, "event:%p (%s seqnum:%d) , collect:%p", event,
123       GST_EVENT_TYPE_NAME (event), GST_EVENT_SEQNUM (event), collect);
124 
125   if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
126     fail_if (collect->expected_segments == NULL,
127         "Received unexpected segment on pad: %s:%s",
128         GST_DEBUG_PAD_NAME (sinkpad));
129 
130     if (!collect->gotsegment)
131       collect->seen_segments =
132           g_list_append (NULL, GINT_TO_POINTER (GST_EVENT_SEQNUM (event)));
133     else {
134       fail_if (g_list_find (collect->seen_segments,
135               GINT_TO_POINTER (GST_EVENT_SEQNUM (event))),
136           "Got a segment event we already saw before !");
137       collect->seen_segments =
138           g_list_append (collect->seen_segments,
139           GINT_TO_POINTER (GST_EVENT_SEQNUM (event)));
140     }
141 
142     segment = (Segment *) collect->expected_segments->data;
143 
144     if (compare_segments (collect, segment, event) &&
145         collect->keep_expected_segments == FALSE) {
146       collect->expected_segments =
147           g_list_remove (collect->expected_segments, segment);
148       g_free (segment);
149     }
150 
151     collect->gotsegment = TRUE;
152   }
153 
154   return GST_PAD_PROBE_OK;
155 }
156 
157 static GstPadProbeReturn
sinkpad_buffer_probe(GstPad * sinkpad,GstBuffer * buffer,CollectStructure * collect)158 sinkpad_buffer_probe (GstPad * sinkpad, GstBuffer * buffer,
159     CollectStructure * collect)
160 {
161   GST_LOG_OBJECT (sinkpad, "buffer:%p (%" GST_TIME_FORMAT ") , collect:%p",
162       buffer, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), collect);
163   fail_if (!collect->gotsegment,
164       "Received a buffer without a preceding segment");
165   return GST_PAD_PROBE_OK;
166 }
167 
168 GstPadProbeReturn
sinkpad_probe(GstPad * sinkpad,GstPadProbeInfo * info,CollectStructure * collect)169 sinkpad_probe (GstPad * sinkpad, GstPadProbeInfo * info,
170     CollectStructure * collect)
171 {
172   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
173     return sinkpad_buffer_probe (sinkpad, (GstBuffer *) info->data, collect);
174   if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
175     return sinkpad_event_probe (sinkpad, (GstEvent *) info->data, collect);
176   return GST_PAD_PROBE_OK;
177 }
178 
179 static GstElement *
new_nle_src(const gchar * name,guint64 start,gint64 duration,gint priority)180 new_nle_src (const gchar * name, guint64 start, gint64 duration, gint priority)
181 {
182   GstElement *nlesource = NULL;
183 
184   nlesource = gst_element_factory_make_or_warn ("nlesource", name);
185   fail_if (nlesource == NULL);
186 
187   g_object_set (G_OBJECT (nlesource),
188       "start", start,
189       "duration", duration, "inpoint", start, "priority", priority, NULL);
190   nle_object_commit (nlesource, FALSE);
191 
192   return nlesource;
193 }
194 
195 GstElement *
videotest_nle_src(const gchar * name,guint64 start,gint64 duration,gint pattern,guint priority)196 videotest_nle_src (const gchar * name, guint64 start, gint64 duration,
197     gint pattern, guint priority)
198 {
199   GstElement *nlesource = NULL;
200   GstElement *videotestsrc = NULL;
201   GstCaps *caps =
202       gst_caps_from_string
203       ("video/x-raw,format=(string)I420,framerate=(fraction)3/2");
204 
205   fail_if (caps == NULL);
206 
207   videotestsrc = gst_element_factory_make_or_warn ("videotestsrc", NULL);
208   g_object_set (G_OBJECT (videotestsrc), "pattern", pattern, NULL);
209 
210   nlesource = new_nle_src (name, start, duration, priority);
211   g_object_set (G_OBJECT (nlesource), "caps", caps, NULL);
212   gst_caps_unref (caps);
213 
214   gst_bin_add (GST_BIN (nlesource), videotestsrc);
215 
216   return nlesource;
217 }
218 
219 GstElement *
videotest_nle_src_full(const gchar * name,guint64 start,gint64 duration,guint64 inpoint,gint pattern,guint priority)220 videotest_nle_src_full (const gchar * name, guint64 start, gint64 duration,
221     guint64 inpoint, gint pattern, guint priority)
222 {
223   GstElement *nles;
224 
225   nles = videotest_nle_src (name, start, duration, pattern, priority);
226   if (nles) {
227     g_object_set (G_OBJECT (nles), "inpoint", inpoint, NULL);
228   }
229 
230 
231   return nles;
232 }
233 
234 GstElement *
videotest_in_bin_nle_src(const gchar * name,guint64 start,gint64 duration,gint pattern,guint priority)235 videotest_in_bin_nle_src (const gchar * name, guint64 start, gint64 duration,
236     gint pattern, guint priority)
237 {
238   GstElement *nlesource = NULL;
239   GstElement *videotestsrc = NULL;
240   GstElement *bin = NULL;
241   GstElement *alpha = NULL;
242   GstPad *srcpad = NULL;
243 
244   alpha = gst_element_factory_make ("alpha", NULL);
245   if (alpha == NULL)
246     return NULL;
247 
248   videotestsrc = gst_element_factory_make_or_warn ("videotestsrc", NULL);
249   g_object_set (G_OBJECT (videotestsrc), "pattern", pattern, NULL);
250   bin = gst_bin_new (NULL);
251 
252   nlesource = new_nle_src (name, start, duration, priority);
253 
254   gst_bin_add (GST_BIN (bin), videotestsrc);
255   gst_bin_add (GST_BIN (bin), alpha);
256 
257   gst_element_link_pads_full (videotestsrc, "src", alpha, "sink",
258       GST_PAD_LINK_CHECK_NOTHING);
259 
260   gst_bin_add (GST_BIN (nlesource), bin);
261 
262   srcpad = gst_element_get_static_pad (alpha, "src");
263 
264   gst_element_add_pad (bin, gst_ghost_pad_new ("src", srcpad));
265 
266   gst_object_unref (srcpad);
267 
268   return nlesource;
269 }
270 
271 GstElement *
audiotest_bin_src(const gchar * name,guint64 start,gint64 duration,guint priority,gboolean intaudio)272 audiotest_bin_src (const gchar * name, guint64 start,
273     gint64 duration, guint priority, gboolean intaudio)
274 {
275   GstElement *source = NULL;
276   GstElement *identity = NULL;
277   GstElement *audiotestsrc = NULL;
278   GstElement *audioconvert = NULL;
279   GstElement *bin = NULL;
280   GstCaps *caps;
281   GstPad *srcpad = NULL;
282 
283   audiotestsrc = gst_element_factory_make_or_warn ("audiotestsrc", NULL);
284   identity = gst_element_factory_make_or_warn ("identity", NULL);
285   bin = gst_bin_new (NULL);
286   source = new_nle_src (name, start, duration, priority);
287   audioconvert = gst_element_factory_make_or_warn ("audioconvert", NULL);
288 
289   if (intaudio)
290     caps = gst_caps_from_string ("audio/x-raw,format=(string)S16LE");
291   else
292     caps = gst_caps_from_string ("audio/x-raw,format=(string)F32LE");
293 
294   gst_bin_add_many (GST_BIN (bin), audiotestsrc, audioconvert, identity, NULL);
295   gst_element_link_pads_full (audiotestsrc, "src", audioconvert, "sink",
296       GST_PAD_LINK_CHECK_NOTHING);
297   fail_if ((gst_element_link_filtered (audioconvert, identity, caps)) != TRUE);
298 
299   gst_caps_unref (caps);
300 
301   gst_bin_add (GST_BIN (source), bin);
302 
303   srcpad = gst_element_get_static_pad (identity, "src");
304 
305   gst_element_add_pad (bin, gst_ghost_pad_new ("src", srcpad));
306 
307   gst_object_unref (srcpad);
308 
309   return source;
310 }
311 
312 GstElement *
new_operation(const gchar * name,const gchar * factory,guint64 start,gint64 duration,guint priority)313 new_operation (const gchar * name, const gchar * factory, guint64 start,
314     gint64 duration, guint priority)
315 {
316   GstElement *nleoperation = NULL;
317   GstElement *operation = NULL;
318 
319   operation = gst_element_factory_make_or_warn (factory, NULL);
320   nleoperation = gst_element_factory_make_or_warn ("nleoperation", name);
321 
322   g_object_set (G_OBJECT (nleoperation),
323       "start", start, "duration", duration, "priority", priority, NULL);
324 
325   gst_bin_add (GST_BIN (nleoperation), operation);
326 
327   return nleoperation;
328 }
329 
330 
331 Segment *
segment_new(gdouble rate,GstFormat format,gint64 start,gint64 stop,gint64 position)332 segment_new (gdouble rate, GstFormat format, gint64 start, gint64 stop,
333     gint64 position)
334 {
335   Segment *segment;
336 
337   segment = g_new0 (Segment, 1);
338 
339   segment->rate = rate;
340   segment->format = format;
341   segment->start = start;
342   segment->stop = stop;
343   segment->position = position;
344 
345   return segment;
346 }
347 
348 GList *
copy_segment_list(GList * list)349 copy_segment_list (GList * list)
350 {
351   GList *res = NULL;
352 
353   while (list) {
354     Segment *pdata = (Segment *) list->data;
355 
356     res =
357         g_list_append (res, segment_new (pdata->rate, pdata->format,
358             pdata->start, pdata->stop, pdata->position));
359 
360     list = list->next;
361   }
362 
363   return res;
364 }
365 
366 static GMutex lock;
367 static GCond cond;
368 static void
commited_cb(GstElement * comp,gboolean changed)369 commited_cb (GstElement * comp, gboolean changed)
370 {
371   g_mutex_lock (&lock);
372   g_cond_signal (&cond);
373   g_mutex_unlock (&lock);
374 }
375 
376 void
commit_and_wait(GstElement * comp,gboolean * ret)377 commit_and_wait (GstElement * comp, gboolean * ret)
378 {
379   gulong handler_id =
380       g_signal_connect (comp, "commited", (GCallback) commited_cb, NULL);
381   g_mutex_lock (&lock);
382   *ret = nle_object_commit (comp, TRUE);
383   g_cond_wait (&cond, &lock);
384   g_mutex_unlock (&lock);
385   g_signal_handler_disconnect (comp, handler_id);
386 }
387 
388 gboolean
nle_composition_remove(GstBin * comp,GstElement * object)389 nle_composition_remove (GstBin * comp, GstElement * object)
390 {
391   gboolean ret;
392 
393   ret = gst_bin_remove (comp, object);
394   if (!ret)
395     return ret;
396 
397   commit_and_wait ((GstElement *) comp, &ret);
398 
399   return ret;
400 }
401 
402 gboolean
nle_composition_add(GstBin * comp,GstElement * object)403 nle_composition_add (GstBin * comp, GstElement * object)
404 {
405   return gst_bin_add (comp, object);
406 }
407 
408 void
collect_free(CollectStructure * collect)409 collect_free (CollectStructure * collect)
410 {
411   if (collect->seen_segments)
412     g_list_free (collect->seen_segments);
413   if (collect->expected_segments)
414     g_list_free_full (collect->expected_segments, (GDestroyNotify) g_free);
415 
416   g_free (collect);
417 }
418