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