1 /* GStreamer unit tests for flvmux
2 *
3 * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
4 * Copyright (C) 2016 Havard Graff <havard@pexip.com>
5 * Copyright (C) 2016 David Buchmann <david@pexip.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #ifdef HAVE_VALGRIND
28 # include <valgrind/valgrind.h>
29 #endif
30
31 #include <gst/check/gstcheck.h>
32 #include <gst/check/gstharness.h>
33
34 #include <gst/gst.h>
35
36 static GstBusSyncReply
error_cb(GstBus * bus,GstMessage * msg,gpointer user_data)37 error_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
38 {
39 if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
40 GError *err = NULL;
41 gchar *dbg = NULL;
42
43 gst_message_parse_error (msg, &err, &dbg);
44 g_error ("ERROR: %s\n%s\n", err->message, dbg);
45 }
46
47 return GST_BUS_PASS;
48 }
49
50 static void
handoff_cb(GstElement * element,GstBuffer * buf,GstPad * pad,gint * p_counter)51 handoff_cb (GstElement * element, GstBuffer * buf, GstPad * pad,
52 gint * p_counter)
53 {
54 *p_counter += 1;
55 GST_LOG ("counter = %d", *p_counter);
56 }
57
58 static void
mux_pcm_audio(guint num_buffers,guint repeat)59 mux_pcm_audio (guint num_buffers, guint repeat)
60 {
61 GstElement *src, *sink, *flvmux, *conv, *pipeline;
62 GstPad *sinkpad, *srcpad;
63 gint counter;
64
65 GST_LOG ("num_buffers = %u", num_buffers);
66
67 pipeline = gst_pipeline_new ("pipeline");
68 fail_unless (pipeline != NULL, "Failed to create pipeline!");
69
70 /* kids, don't use a sync handler for this at home, really; we do because
71 * we just want to abort and nothing else */
72 gst_bus_set_sync_handler (GST_ELEMENT_BUS (pipeline), error_cb, NULL, NULL);
73
74 src = gst_element_factory_make ("audiotestsrc", "audiotestsrc");
75 fail_unless (src != NULL, "Failed to create 'audiotestsrc' element!");
76
77 g_object_set (src, "num-buffers", num_buffers, NULL);
78
79 conv = gst_element_factory_make ("audioconvert", "audioconvert");
80 fail_unless (conv != NULL, "Failed to create 'audioconvert' element!");
81
82 flvmux = gst_element_factory_make ("flvmux", "flvmux");
83 fail_unless (flvmux != NULL, "Failed to create 'flvmux' element!");
84
85 sink = gst_element_factory_make ("fakesink", "fakesink");
86 fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
87
88 g_object_set (sink, "signal-handoffs", TRUE, NULL);
89 g_signal_connect (sink, "handoff", G_CALLBACK (handoff_cb), &counter);
90
91 gst_bin_add_many (GST_BIN (pipeline), src, conv, flvmux, sink, NULL);
92
93 fail_unless (gst_element_link (src, conv));
94 fail_unless (gst_element_link (flvmux, sink));
95
96 /* now link the elements */
97 sinkpad = gst_element_request_pad_simple (flvmux, "audio");
98 fail_unless (sinkpad != NULL, "Could not get audio request pad");
99
100 srcpad = gst_element_get_static_pad (conv, "src");
101 fail_unless (srcpad != NULL, "Could not get audioconvert's source pad");
102
103 fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
104
105 gst_object_unref (srcpad);
106 gst_object_unref (sinkpad);
107
108 do {
109 GstStateChangeReturn state_ret;
110 GstMessage *msg;
111
112 GST_LOG ("repeat=%d", repeat);
113
114 counter = 0;
115
116 state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
117 fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
118
119 if (state_ret == GST_STATE_CHANGE_ASYNC) {
120 GST_LOG ("waiting for pipeline to reach PAUSED state");
121 state_ret = gst_element_get_state (pipeline, NULL, NULL, -1);
122 fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS);
123 }
124
125 GST_LOG ("PAUSED, let's do the rest of it");
126
127 state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
128 fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
129
130 msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
131 fail_unless (msg != NULL, "Expected EOS message on bus!");
132
133 GST_LOG ("EOS");
134 gst_message_unref (msg);
135
136 /* should have some output */
137 fail_unless (counter > 2);
138
139 fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
140 GST_STATE_CHANGE_SUCCESS);
141
142 /* repeat = test re-usability */
143 --repeat;
144 } while (repeat > 0);
145
146 gst_object_unref (pipeline);
147 }
148
GST_START_TEST(test_index_writing)149 GST_START_TEST (test_index_writing)
150 {
151 /* note: there's a magic 128 value in flvmux when doing index writing */
152 mux_pcm_audio (__i__ * 33 + 1, 2);
153 }
154
155 GST_END_TEST;
156
157 static GstBuffer *
create_buffer(guint8 * data,gsize size,GstClockTime timestamp,GstClockTime duration)158 create_buffer (guint8 * data, gsize size,
159 GstClockTime timestamp, GstClockTime duration)
160 {
161 GstBuffer *buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
162 data, size, 0, size, NULL, NULL);
163 GST_BUFFER_PTS (buf) = timestamp;
164 GST_BUFFER_DTS (buf) = timestamp;
165 GST_BUFFER_DURATION (buf) = duration;
166 GST_BUFFER_OFFSET (buf) = 0;
167 GST_BUFFER_OFFSET_END (buf) = 0;
168 return buf;
169 }
170
171 guint8 speex_hdr0[] = {
172 0x53, 0x70, 0x65, 0x65, 0x78, 0x20, 0x20, 0x20,
173 0x31, 0x2e, 0x32, 0x72, 0x63, 0x31, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
176 0x50, 0x00, 0x00, 0x00, 0x80, 0x3e, 0x00, 0x00,
177 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
178 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
179 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
182 };
183
184 guint8 speex_hdr1[] = {
185 0x1f, 0x00, 0x00, 0x00, 0x45, 0x6e, 0x63, 0x6f,
186 0x64, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68,
187 0x20, 0x47, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
188 0x65, 0x72, 0x20, 0x53, 0x70, 0x65, 0x65, 0x78,
189 0x65, 0x6e, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01
190 };
191
192 guint8 speex_buf[] = {
193 0x36, 0x9d, 0x1b, 0x9a, 0x20, 0x00, 0x01, 0x68,
194 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0x84,
195 0x00, 0xb4, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
196 0x74, 0x42, 0x00, 0x5a, 0x3a, 0x3a, 0x3a, 0x3a,
197 0x3a, 0x3a, 0x3a, 0x21, 0x00, 0x2d, 0x1d, 0x1d,
198 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1b, 0x3b, 0x60,
199 0xab, 0xab, 0xab, 0xab, 0xab, 0x0a, 0xba, 0xba,
200 0xba, 0xba, 0xb0, 0xab, 0xab, 0xab, 0xab, 0xab,
201 0x0a, 0xba, 0xba, 0xba, 0xba, 0xb7
202 };
203
204 guint8 h264_buf[] = {
205 0x00, 0x00, 0x00, 0x0b, 0x67, 0x42, 0xc0, 0x0c,
206 0x95, 0xa7, 0x20, 0x1e, 0x11, 0x08, 0xd4, 0x00,
207 0x00, 0x00, 0x04, 0x68, 0xce, 0x3c, 0x80, 0x00,
208 0x00, 0x00, 0x55, 0x65, 0xb8, 0x04, 0x0e, 0x7e,
209 0x1f, 0x22, 0x60, 0x34, 0x01, 0xe2, 0x00, 0x3c,
210 0xe1, 0xfc, 0x91, 0x40, 0xa6, 0x9e, 0x07, 0x42,
211 0x56, 0x44, 0x73, 0x75, 0x40, 0x9f, 0x0c, 0x87,
212 0x83, 0xc9, 0x52, 0x60, 0x6d, 0xd8, 0x98, 0x01,
213 0x16, 0xbd, 0x0f, 0xa6, 0xaf, 0x75, 0x83, 0xdd,
214 0xfa, 0xe7, 0x8f, 0xe3, 0x58, 0x10, 0x0f, 0x5c,
215 0x18, 0x2f, 0x41, 0x40, 0x23, 0x0b, 0x03, 0x70,
216 0x00, 0xff, 0xe4, 0xa6, 0x7d, 0x7f, 0x3f, 0x76,
217 0x01, 0xd0, 0x98, 0x2a, 0x0c, 0xb8, 0x02, 0x32,
218 0xbc, 0x56, 0xfd, 0x34, 0x4f, 0xcf, 0xfe, 0xa0,
219 };
220
GST_START_TEST(test_speex_streamable)221 GST_START_TEST (test_speex_streamable)
222 {
223 GstBuffer *buf;
224 GstMapInfo map = GST_MAP_INFO_INIT;
225
226
227 GstCaps *caps = gst_caps_new_simple ("audio/x-speex",
228 "rate", G_TYPE_INT, 16000,
229 "channels", G_TYPE_INT, 1,
230 NULL);
231
232 const GstClockTime base_time = 123456789;
233 const GstClockTime duration_ms = 20;
234 const GstClockTime duration = duration_ms * GST_MSECOND;
235
236 GstHarness *h = gst_harness_new_with_padnames ("flvmux", "audio", "src");
237 gst_harness_set_src_caps (h, caps);
238 g_object_set (h->element, "streamable", 1, NULL);
239
240 /* push speex header0 */
241 gst_harness_push (h, create_buffer (speex_hdr0,
242 sizeof (speex_hdr0), base_time, 0));
243
244 /* push speex header1 */
245 gst_harness_push (h, create_buffer (speex_hdr1,
246 sizeof (speex_hdr1), base_time, 0));
247
248 /* push speex data */
249 gst_harness_push (h, create_buffer (speex_buf,
250 sizeof (speex_buf), base_time, duration));
251
252 /* push speex data 2 */
253 gst_harness_push (h, create_buffer (speex_buf,
254 sizeof (speex_buf), base_time + duration, duration));
255
256 /* pull out stream-start event */
257 gst_event_unref (gst_harness_pull_event (h));
258
259 /* pull out caps event */
260 gst_event_unref (gst_harness_pull_event (h));
261
262 /* pull out segment event and verify we are using GST_FORMAT_TIME */
263 {
264 GstEvent *event = gst_harness_pull_event (h);
265 const GstSegment *segment;
266 gst_event_parse_segment (event, &segment);
267 fail_unless_equals_int (GST_FORMAT_TIME, segment->format);
268 gst_event_unref (event);
269 }
270
271 /* pull FLV header buffer */
272 buf = gst_harness_pull (h);
273 gst_buffer_unref (buf);
274
275 /* pull Metadata buffer */
276 buf = gst_harness_pull (h);
277 gst_buffer_unref (buf);
278
279 /* pull header0 */
280 buf = gst_harness_pull (h);
281 fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf));
282 fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, GST_BUFFER_DTS (buf));
283 fail_unless_equals_uint64 (0, GST_BUFFER_DURATION (buf));
284 gst_buffer_map (buf, &map, GST_MAP_READ);
285 /* 0x08 means it is audio */
286 fail_unless_equals_int (0x08, map.data[0]);
287 /* timestamp should be starting from 0 */
288 fail_unless_equals_int (0x00, map.data[6]);
289 /* 0xb2 means Speex, 16000Hz, Mono */
290 fail_unless_equals_int (0xb2, map.data[11]);
291 /* verify content is intact */
292 fail_unless_equals_int (0, memcmp (&map.data[12], speex_hdr0,
293 sizeof (speex_hdr0)));
294 gst_buffer_unmap (buf, &map);
295 gst_buffer_unref (buf);
296
297 /* pull header1 */
298 buf = gst_harness_pull (h);
299 fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf));
300 fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, GST_BUFFER_DTS (buf));
301 fail_unless_equals_uint64 (0, GST_BUFFER_DURATION (buf));
302 gst_buffer_map (buf, &map, GST_MAP_READ);
303 /* 0x08 means it is audio */
304 fail_unless_equals_int (0x08, map.data[0]);
305 /* timestamp should be starting from 0 */
306 fail_unless_equals_int (0x00, map.data[6]);
307 /* 0xb2 means Speex, 16000Hz, Mono */
308 fail_unless_equals_int (0xb2, map.data[11]);
309 /* verify content is intact */
310 fail_unless_equals_int (0, memcmp (&map.data[12], speex_hdr1,
311 sizeof (speex_hdr1)));
312 gst_buffer_unmap (buf, &map);
313 gst_buffer_unref (buf);
314
315 /* pull data */
316 buf = gst_harness_pull (h);
317 fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf));
318 fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, GST_BUFFER_DTS (buf));
319 fail_unless_equals_uint64 (duration, GST_BUFFER_DURATION (buf));
320 fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE, GST_BUFFER_OFFSET (buf));
321 fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE,
322 GST_BUFFER_OFFSET_END (buf));
323 gst_buffer_map (buf, &map, GST_MAP_READ);
324 /* 0x08 means it is audio */
325 fail_unless_equals_int (0x08, map.data[0]);
326 /* timestamp should be starting from 0 */
327 fail_unless_equals_int (0x00, map.data[6]);
328 /* 0xb2 means Speex, 16000Hz, Mono */
329 fail_unless_equals_int (0xb2, map.data[11]);
330 /* verify content is intact */
331 fail_unless_equals_int (0, memcmp (&map.data[12], speex_buf,
332 sizeof (speex_buf)));
333 gst_buffer_unmap (buf, &map);
334 gst_buffer_unref (buf);
335
336 /* pull data */
337 buf = gst_harness_pull (h);
338 fail_unless_equals_uint64 (base_time + duration, GST_BUFFER_PTS (buf));
339 fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, GST_BUFFER_DTS (buf));
340 fail_unless_equals_uint64 (duration, GST_BUFFER_DURATION (buf));
341 fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE, GST_BUFFER_OFFSET (buf));
342 fail_unless_equals_uint64 (GST_BUFFER_OFFSET_NONE,
343 GST_BUFFER_OFFSET_END (buf));
344 gst_buffer_map (buf, &map, GST_MAP_READ);
345 /* 0x08 means it is audio */
346 fail_unless_equals_int (0x08, map.data[0]);
347 /* timestamp should reflect the duration_ms */
348 fail_unless_equals_int (duration_ms, map.data[6]);
349 /* 0xb2 means Speex, 16000Hz, Mono */
350 fail_unless_equals_int (0xb2, map.data[11]);
351 /* verify content is intact */
352 fail_unless_equals_int (0, memcmp (&map.data[12], speex_buf,
353 sizeof (speex_buf)));
354 gst_buffer_unmap (buf, &map);
355 gst_buffer_unref (buf);
356
357 gst_harness_teardown (h);
358 }
359
360 GST_END_TEST;
361
362 static void
check_buf_type_timestamp(GstBuffer * buf,gint packet_type,gint timestamp)363 check_buf_type_timestamp (GstBuffer * buf, gint packet_type, gint timestamp)
364 {
365 GstMapInfo map = GST_MAP_INFO_INIT;
366 gst_buffer_map (buf, &map, GST_MAP_READ);
367 fail_unless_equals_int (packet_type, map.data[0]);
368 fail_unless_equals_int (timestamp, map.data[6]);
369 gst_buffer_unmap (buf, &map);
370 gst_buffer_unref (buf);
371 }
372
373 static const gint AUDIO = 0x08;
374 static const gint VIDEO = 0x09;
375
GST_START_TEST(test_increasing_timestamp_when_pts_none)376 GST_START_TEST (test_increasing_timestamp_when_pts_none)
377 {
378 gint timestamp = 3;
379 GstClockTime base_time = 42 * GST_SECOND;
380 GstPad *audio_sink, *video_sink, *audio_src, *video_src;
381 GstHarness *h, *audio, *video, *audio_q, *video_q;
382 GstCaps *audio_caps, *video_caps;
383 GstBuffer *buf;
384
385 h = gst_harness_new_with_padnames ("flvmux", NULL, "src");
386 audio = gst_harness_new_with_element (h->element, "audio", NULL);
387 video = gst_harness_new_with_element (h->element, "video", NULL);
388 audio_q = gst_harness_new ("queue");
389 video_q = gst_harness_new ("queue");
390
391 audio_sink = GST_PAD_PEER (audio->srcpad);
392 video_sink = GST_PAD_PEER (video->srcpad);
393 audio_src = GST_PAD_PEER (audio_q->sinkpad);
394 video_src = GST_PAD_PEER (video_q->sinkpad);
395
396 gst_pad_unlink (audio->srcpad, audio_sink);
397 gst_pad_unlink (video->srcpad, video_sink);
398 gst_pad_unlink (audio_src, audio_q->sinkpad);
399 gst_pad_unlink (video_src, video_q->sinkpad);
400 gst_pad_link (audio_src, audio_sink);
401 gst_pad_link (video_src, video_sink);
402
403 audio_caps = gst_caps_new_simple ("audio/x-speex",
404 "rate", G_TYPE_INT, 16000, "channels", G_TYPE_INT, 1, NULL);
405 gst_harness_set_src_caps (audio_q, audio_caps);
406 video_caps = gst_caps_new_simple ("video/x-h264",
407 "stream-format", G_TYPE_STRING, "avc", NULL);
408 gst_harness_set_src_caps (video_q, video_caps);
409
410 /* Push audio + video + audio with increasing DTS, but PTS for video is
411 * GST_CLOCK_TIME_NONE
412 */
413 buf = gst_buffer_new ();
414 GST_BUFFER_DTS (buf) = timestamp * GST_MSECOND + base_time;
415 GST_BUFFER_PTS (buf) = timestamp * GST_MSECOND + base_time;
416 gst_harness_push (audio_q, buf);
417
418 buf = gst_buffer_new ();
419 GST_BUFFER_DTS (buf) = (timestamp + 1) * GST_MSECOND + base_time;
420 GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
421 gst_harness_push (video_q, buf);
422
423 buf = gst_buffer_new ();
424 GST_BUFFER_DTS (buf) = (timestamp + 2) * GST_MSECOND + base_time;
425 GST_BUFFER_PTS (buf) = (timestamp + 2) * GST_MSECOND + base_time;
426 gst_harness_push (audio_q, buf);
427
428 /* Pull two metadata packets out */
429 gst_buffer_unref (gst_harness_pull (h));
430 gst_buffer_unref (gst_harness_pull (h));
431
432 /* Check that we receive the packets in monotonically increasing order and
433 * that their timestamps are correct (should start at 0)
434 */
435 buf = gst_harness_pull (h);
436 check_buf_type_timestamp (buf, AUDIO, 0);
437 buf = gst_harness_pull (h);
438 check_buf_type_timestamp (buf, VIDEO, 1);
439
440 /* teardown */
441 gst_harness_teardown (h);
442 gst_harness_teardown (audio);
443 gst_harness_teardown (video);
444 gst_harness_teardown (audio_q);
445 gst_harness_teardown (video_q);
446 }
447
448 GST_END_TEST;
449
450 typedef struct
451 {
452 GstHarness *a_sink;
453 GstHarness *v_sink;
454 } DemuxHarnesses;
455
456 static void
flvdemux_pad_added(GstElement * flvdemux,GstPad * srcpad,DemuxHarnesses * h)457 flvdemux_pad_added (GstElement * flvdemux, GstPad * srcpad, DemuxHarnesses * h)
458 {
459 GstCaps *caps = gst_pad_get_current_caps (srcpad);
460 const gchar *name = gst_structure_get_name (gst_caps_get_structure (caps, 0));
461
462 if (h->a_sink && g_ascii_strncasecmp ("audio", name, 5) == 0)
463 gst_harness_add_element_src_pad (h->a_sink, srcpad);
464 else if (h->v_sink && g_ascii_strncasecmp ("video", name, 5) == 0)
465 gst_harness_add_element_src_pad (h->v_sink, srcpad);
466 else
467 ck_abort_msg ("Unexpected demux pad: %s", GST_STR_NULL (name));
468
469 gst_caps_unref (caps);
470 }
471
GST_START_TEST(test_video_caps_late)472 GST_START_TEST (test_video_caps_late)
473 {
474 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
475 GstHarness *a_src =
476 gst_harness_new_with_element (mux->element, "audio", NULL);
477 GstHarness *v_src =
478 gst_harness_new_with_element (mux->element, "video", NULL);
479 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
480 GstHarness *a_sink =
481 gst_harness_new_with_element (demux->element, NULL, NULL);
482 GstHarness *v_sink =
483 gst_harness_new_with_element (demux->element, NULL, NULL);
484 DemuxHarnesses harnesses = { a_sink, v_sink };
485 GstTestClock *tclock;
486
487 g_object_set (mux->element, "streamable", TRUE,
488 "latency", G_GUINT64_CONSTANT (1), NULL);
489 gst_harness_use_testclock (mux);
490
491 g_signal_connect (demux->element, "pad-added",
492 G_CALLBACK (flvdemux_pad_added), &harnesses);
493 gst_harness_add_sink_harness (mux, demux);
494
495 gst_harness_set_src_caps_str (a_src,
496 "audio/x-speex, rate=(int)16000, channels=(int)1");
497
498 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
499 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
500 speex_hdr0, sizeof (speex_hdr0), 0, sizeof (speex_hdr0), NULL,
501 NULL)));
502
503 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
504 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
505 speex_hdr1, sizeof (speex_hdr1), 0, sizeof (speex_hdr1), NULL,
506 NULL)));
507
508 /* Wait a little and make sure no clock was scheduled as this shouldn't happen
509 * before the caps are set */
510 g_usleep (40 * 1000);
511 tclock = gst_harness_get_testclock (mux);
512 fail_unless (gst_test_clock_get_next_entry_time (tclock) ==
513 GST_CLOCK_TIME_NONE);
514
515 gst_harness_set_src_caps_str (v_src,
516 "video/x-h264, stream-format=(string)avc, alignment=(string)au, "
517 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
518
519 gst_harness_crank_single_clock_wait (mux);
520
521 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
522 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
523 speex_buf, sizeof (speex_buf), 0, sizeof (speex_buf), NULL,
524 NULL)));
525
526 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
527 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
528 h264_buf, sizeof (h264_buf), 0, sizeof (h264_buf), NULL, NULL)));
529
530 gst_harness_crank_single_clock_wait (mux);
531 gst_harness_crank_single_clock_wait (mux);
532 gst_harness_crank_single_clock_wait (mux);
533
534
535 /* push from flvmux to demux */
536 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 6));
537
538 /* verify we got 2x audio and 1x video buffers out of flvdemux */
539 gst_buffer_unref (gst_harness_pull (a_sink));
540 gst_buffer_unref (gst_harness_pull (a_sink));
541 gst_buffer_unref (gst_harness_pull (v_sink));
542
543 fail_unless (gst_test_clock_get_next_entry_time (tclock) ==
544 GST_CLOCK_TIME_NONE);
545
546 g_clear_object (&tclock);
547 gst_harness_teardown (a_src);
548 gst_harness_teardown (v_src);
549 gst_harness_teardown (mux);
550 gst_harness_teardown (a_sink);
551 gst_harness_teardown (v_sink);
552 }
553
554 GST_END_TEST;
555
556 guint8 raw_frame_short[] = {
557 0x27, 0x00, 0x03, 0x20, 0x64, 0x1c
558 };
559
GST_START_TEST(test_video_caps_change_streamable)560 GST_START_TEST (test_video_caps_change_streamable)
561 {
562 GstEvent *event;
563 GstCaps *a_caps1, *v_caps1, *v_caps2, *ret_caps;
564 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
565 GstHarness *a_src =
566 gst_harness_new_with_element (mux->element, "audio", NULL);
567 GstHarness *v_src =
568 gst_harness_new_with_element (mux->element, "video", NULL);
569 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
570 GstHarness *a_sink =
571 gst_harness_new_with_element (demux->element, NULL, NULL);
572 GstHarness *v_sink =
573 gst_harness_new_with_element (demux->element, NULL, NULL);
574 DemuxHarnesses harnesses = { a_sink, v_sink };
575
576 const GstClockTime base_time = 123456789;
577 const GstClockTime duration_ms = 20;
578 const GstClockTime duration = duration_ms * GST_MSECOND;
579
580 g_object_set (mux->element, "streamable", TRUE, NULL);
581
582 g_signal_connect (demux->element, "pad-added",
583 G_CALLBACK (flvdemux_pad_added), &harnesses);
584 gst_harness_add_sink_harness (mux, demux);
585
586 a_caps1 =
587 gst_caps_from_string
588 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
589 "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
590
591 v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
592 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
593
594 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps1));
595 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps1));
596
597 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
598 create_buffer (raw_frame_short, sizeof (raw_frame_short), base_time,
599 duration)));
600
601 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
602 create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
603
604 gst_harness_crank_single_clock_wait (mux);
605
606 /* push from flvmux to demux */
607 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 6));
608
609 /* should accept without the constraint */
610 while ((event = gst_harness_try_pull_event (v_sink))) {
611 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
612 gst_event_parse_caps (event, &ret_caps);
613 GST_LOG ("v_caps1 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
614 v_caps1, ret_caps);
615 fail_unless (gst_caps_is_equal (v_caps1, ret_caps));
616 }
617 gst_event_unref (event);
618 }
619
620 /* caps change */
621 v_caps2 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
622 "codec_data=(buffer)0164001fffe1001c6764001facd9405005bb016a02020280000003008000001e478c18cb01000568ebecb22c");
623
624 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps2));
625
626 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
627 create_buffer (h264_buf, sizeof (h264_buf), base_time + duration,
628 duration)));
629
630 gst_harness_crank_single_clock_wait (mux);
631
632 /* push from flvmux to demux */
633 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 2));
634
635 /* should accept without the constraint */
636 while ((event = gst_harness_try_pull_event (v_sink))) {
637 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
638 gst_event_parse_caps (event, &ret_caps);
639 GST_LOG ("v_caps2 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
640 v_caps2, ret_caps);
641 fail_unless (gst_caps_is_equal (v_caps2, ret_caps));
642 }
643 gst_event_unref (event);
644 }
645
646 /* verify we got 1x audio and 2x video buffers out of flvdemux */
647 gst_buffer_unref (gst_harness_pull (a_sink));
648 gst_buffer_unref (gst_harness_pull (v_sink));
649 gst_buffer_unref (gst_harness_pull (v_sink));
650 gst_caps_unref (a_caps1);
651 gst_caps_unref (v_caps1);
652 gst_caps_unref (v_caps2);
653
654 gst_harness_teardown (a_src);
655 gst_harness_teardown (v_src);
656 gst_harness_teardown (mux);
657 gst_harness_teardown (a_sink);
658 gst_harness_teardown (v_sink);
659 }
660
661 GST_END_TEST;
662
GST_START_TEST(test_audio_caps_change_streamable)663 GST_START_TEST (test_audio_caps_change_streamable)
664 {
665 GstEvent *event;
666 GstCaps *a_caps1, *a_caps2, *v_caps1, *ret_caps;
667 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
668 GstHarness *a_src =
669 gst_harness_new_with_element (mux->element, "audio", NULL);
670 GstHarness *v_src =
671 gst_harness_new_with_element (mux->element, "video", NULL);
672 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
673 GstHarness *a_sink =
674 gst_harness_new_with_element (demux->element, NULL, NULL);
675 GstHarness *v_sink =
676 gst_harness_new_with_element (demux->element, NULL, NULL);
677 DemuxHarnesses harnesses = { a_sink, v_sink };
678
679 const GstClockTime base_time = 123456789;
680 const GstClockTime duration_ms = 20;
681 const GstClockTime duration = duration_ms * GST_MSECOND;
682
683 g_object_set (mux->element, "streamable", TRUE, NULL);
684
685 g_signal_connect (demux->element, "pad-added",
686 G_CALLBACK (flvdemux_pad_added), &harnesses);
687 gst_harness_add_sink_harness (mux, demux);
688
689 a_caps1 =
690 gst_caps_from_string
691 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
692 "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
693
694 v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
695 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
696
697 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps1));
698 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps1));
699
700 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
701 create_buffer (raw_frame_short, sizeof (raw_frame_short), base_time,
702 duration)));
703
704 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
705 create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
706
707 gst_harness_crank_single_clock_wait (mux);
708
709 /* push from flvmux to demux */
710 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 6));
711
712 /* should accept without the constraint */
713 while ((event = gst_harness_try_pull_event (a_sink))) {
714 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
715 gst_event_parse_caps (event, &ret_caps);
716 GST_LOG ("a_caps1 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
717 a_caps1, ret_caps);
718 fail_unless (gst_caps_is_equal (a_caps1, ret_caps));
719 }
720 gst_event_unref (event);
721 }
722
723 /* caps change */
724 a_caps2 =
725 gst_caps_from_string
726 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
727 "rate=(int)22050, channels=(int)1, codec_data=(buffer)1388");
728
729 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps2));
730
731 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
732 create_buffer (raw_frame_short, sizeof (raw_frame_short),
733 base_time + duration, duration)));
734
735 gst_harness_crank_single_clock_wait (mux);
736
737 /* push from flvmux to demux */
738 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 2));
739
740 /* should accept without the constraint */
741 while ((event = gst_harness_try_pull_event (a_sink))) {
742 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
743 gst_event_parse_caps (event, &ret_caps);
744 GST_LOG ("a_caps2 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
745 a_caps2, ret_caps);
746 fail_unless (gst_caps_is_equal (a_caps2, ret_caps));
747 }
748 gst_event_unref (event);
749 }
750
751 /* verify we got 2x audio and 1x video buffers out of flvdemux */
752 gst_buffer_unref (gst_harness_pull (a_sink));
753 gst_buffer_unref (gst_harness_pull (a_sink));
754 gst_buffer_unref (gst_harness_pull (v_sink));
755 gst_caps_unref (a_caps1);
756 gst_caps_unref (a_caps2);
757 gst_caps_unref (v_caps1);
758
759 gst_harness_teardown (a_src);
760 gst_harness_teardown (v_src);
761 gst_harness_teardown (mux);
762 gst_harness_teardown (a_sink);
763 gst_harness_teardown (v_sink);
764 }
765
766 GST_END_TEST;
767
GST_START_TEST(test_video_caps_change_streamable_single)768 GST_START_TEST (test_video_caps_change_streamable_single)
769 {
770 GstEvent *event;
771 GstCaps *v_caps1, *v_caps2, *ret_caps;
772 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
773 GstHarness *v_src =
774 gst_harness_new_with_element (mux->element, "video", NULL);
775 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
776 GstHarness *v_sink =
777 gst_harness_new_with_element (demux->element, NULL, NULL);
778 DemuxHarnesses harnesses = { NULL, v_sink };
779
780 const GstClockTime base_time = 123456789;
781 const GstClockTime duration_ms = 20;
782 const GstClockTime duration = duration_ms * GST_MSECOND;
783
784 g_object_set (mux->element, "streamable", TRUE, NULL);
785
786 g_signal_connect (demux->element, "pad-added",
787 G_CALLBACK (flvdemux_pad_added), &harnesses);
788 gst_harness_add_sink_harness (mux, demux);
789
790 v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
791 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
792
793 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps1));
794
795 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
796 create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
797
798 /* push from flvmux to demux */
799 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 4));
800
801 /* should accept without the constraint */
802 while ((event = gst_harness_try_pull_event (v_sink))) {
803 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
804 gst_event_parse_caps (event, &ret_caps);
805 GST_LOG ("v_caps1 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
806 v_caps1, ret_caps);
807 fail_unless (gst_caps_is_equal (v_caps1, ret_caps));
808 }
809 gst_event_unref (event);
810 }
811
812 /* caps change */
813 v_caps2 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
814 "codec_data=(buffer)0164001fffe1001c6764001facd9405005bb016a02020280000003008000001e478c18cb01000568ebecb22c");
815
816 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps2));
817
818 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
819 create_buffer (h264_buf, sizeof (h264_buf), base_time + duration,
820 duration)));
821
822 /* push from flvmux to demux */
823 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 2));
824
825 /* should accept without the constraint */
826 while ((event = gst_harness_try_pull_event (v_sink))) {
827 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
828 gst_event_parse_caps (event, &ret_caps);
829 GST_LOG ("v_caps2 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
830 v_caps2, ret_caps);
831 fail_unless (gst_caps_is_equal (v_caps2, ret_caps));
832 }
833 gst_event_unref (event);
834 }
835
836 /* verify we got 2x video buffers out of flvdemux */
837 gst_buffer_unref (gst_harness_pull (v_sink));
838 gst_buffer_unref (gst_harness_pull (v_sink));
839 gst_caps_unref (v_caps1);
840 gst_caps_unref (v_caps2);
841
842 gst_harness_teardown (v_src);
843 gst_harness_teardown (mux);
844 gst_harness_teardown (v_sink);
845 }
846
847 GST_END_TEST;
848
GST_START_TEST(test_audio_caps_change_streamable_single)849 GST_START_TEST (test_audio_caps_change_streamable_single)
850 {
851 GstEvent *event;
852 GstCaps *a_caps1, *a_caps2, *ret_caps;
853 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
854 GstHarness *a_src =
855 gst_harness_new_with_element (mux->element, "audio", NULL);
856 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
857 GstHarness *a_sink =
858 gst_harness_new_with_element (demux->element, NULL, NULL);
859 DemuxHarnesses harnesses = { a_sink, NULL };
860
861 const GstClockTime base_time = 123456789;
862 const GstClockTime duration_ms = 20;
863 const GstClockTime duration = duration_ms * GST_MSECOND;
864
865 g_object_set (mux->element, "streamable", TRUE, NULL);
866
867 g_signal_connect (demux->element, "pad-added",
868 G_CALLBACK (flvdemux_pad_added), &harnesses);
869 gst_harness_add_sink_harness (mux, demux);
870
871 a_caps1 =
872 gst_caps_from_string
873 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
874 "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
875
876 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps1));
877
878 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
879 create_buffer (raw_frame_short, sizeof (raw_frame_short), base_time,
880 duration)));
881
882 /* push from flvmux to demux */
883 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 4));
884
885 /* should accept without the constraint */
886 while ((event = gst_harness_try_pull_event (a_sink))) {
887 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
888 gst_event_parse_caps (event, &ret_caps);
889 GST_LOG ("a_caps1 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
890 a_caps1, ret_caps);
891 fail_unless (gst_caps_is_equal (a_caps1, ret_caps));
892 }
893 gst_event_unref (event);
894 }
895
896 /* caps change */
897 a_caps2 =
898 gst_caps_from_string
899 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
900 "rate=(int)22050, channels=(int)1, codec_data=(buffer)1388");
901
902 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps2));
903
904 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
905 create_buffer (raw_frame_short, sizeof (raw_frame_short),
906 base_time + duration, duration)));
907
908 /* push from flvmux to demux */
909 fail_unless_equals_int (GST_FLOW_OK, gst_harness_sink_push_many (mux, 2));
910
911 /* should accept without the constraint */
912 while ((event = gst_harness_try_pull_event (a_sink))) {
913 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
914 gst_event_parse_caps (event, &ret_caps);
915 GST_LOG ("a_caps2 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
916 a_caps2, ret_caps);
917 fail_unless (gst_caps_is_equal (a_caps2, ret_caps));
918 }
919 gst_event_unref (event);
920 }
921
922 /* verify we got 2x audio out of flvdemux */
923 gst_buffer_unref (gst_harness_pull (a_sink));
924 gst_buffer_unref (gst_harness_pull (a_sink));
925 gst_caps_unref (a_caps1);
926 gst_caps_unref (a_caps2);
927
928 gst_harness_teardown (a_src);
929 gst_harness_teardown (mux);
930 gst_harness_teardown (a_sink);
931 }
932
933 GST_END_TEST;
934
935 typedef struct
936 {
937 guint media_type;
938 guint64 ts; /* timestamp in ms */
939 } InputData;
940
GST_START_TEST(test_incrementing_timestamps)941 GST_START_TEST (test_incrementing_timestamps)
942 {
943 GstPad *audio_sink, *video_sink, *audio_src, *video_src;
944 GstHarness *h, *audio, *video, *audio_q, *video_q;
945 guint i;
946 GstEvent *event;
947 guint32 prev_pts;
948 InputData input[] = {
949 {AUDIO, 155},
950 {VIDEO, 156},
951 {VIDEO, 190},
952 {AUDIO, 176},
953 {AUDIO, 197},
954 };
955
956 /* setup flvmuxer with queues in front */
957 h = gst_harness_new_with_padnames ("flvmux", NULL, "src");
958 audio = gst_harness_new_with_element (h->element, "audio", NULL);
959 video = gst_harness_new_with_element (h->element, "video", NULL);
960 audio_q = gst_harness_new ("queue");
961 video_q = gst_harness_new ("queue");
962 audio_sink = GST_PAD_PEER (audio->srcpad);
963 video_sink = GST_PAD_PEER (video->srcpad);
964 audio_src = GST_PAD_PEER (audio_q->sinkpad);
965 video_src = GST_PAD_PEER (video_q->sinkpad);
966 gst_pad_unlink (audio->srcpad, audio_sink);
967 gst_pad_unlink (video->srcpad, video_sink);
968 gst_pad_unlink (audio_src, audio_q->sinkpad);
969 gst_pad_unlink (video_src, video_q->sinkpad);
970 gst_pad_link (audio_src, audio_sink);
971 gst_pad_link (video_src, video_sink);
972 g_object_set (h->element, "streamable", TRUE, NULL);
973
974 gst_harness_set_src_caps_str (audio_q,
975 "audio/mpeg, mpegversion=(int)4, "
976 "rate=(int)44100, channels=(int)1, "
977 "stream-format=(string)raw, codec_data=(buffer)1208");
978
979 gst_harness_set_src_caps_str (video_q,
980 "video/x-h264, stream-format=(string)avc, alignment=(string)au, "
981 "codec_data=(buffer)0142c00dffe1000d6742c00d95a0507c807844235001000468ce3c80");
982
983 for (i = 0; i < G_N_ELEMENTS (input); i++) {
984 InputData *d = &input[i];
985 GstBuffer *buf = gst_buffer_new ();
986
987 GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = d->ts * GST_MSECOND;
988
989 if (d->media_type == AUDIO)
990 gst_harness_push (audio_q, buf);
991 else
992 gst_harness_push (video_q, buf);
993 }
994
995 gst_harness_push_event (audio_q, gst_event_new_eos ());
996 gst_harness_push_event (video_q, gst_event_new_eos ());
997
998 while ((event = gst_harness_pull_event (h)) != NULL) {
999 GstEventType event_type = GST_EVENT_TYPE (event);
1000 gst_event_unref (event);
1001
1002 if (event_type == GST_EVENT_EOS)
1003 break;
1004 }
1005
1006 /* pull the flv metadata */
1007 gst_buffer_unref (gst_harness_pull (h));
1008 gst_buffer_unref (gst_harness_pull (h));
1009 gst_buffer_unref (gst_harness_pull (h));
1010
1011 /* verify pts in the flvheader is increasing */
1012 prev_pts = 0;
1013 for (i = 0; i < G_N_ELEMENTS (input); i++) {
1014 GstBuffer *buf = gst_harness_pull (h);
1015 GstMapInfo map;
1016 guint32 pts;
1017
1018 fail_unless (buf != NULL);
1019
1020 gst_buffer_map (buf, &map, GST_MAP_READ);
1021 pts = GST_READ_UINT24_BE (map.data + 4);
1022 GST_DEBUG ("media=%u, pts = %u\n", map.data[0], pts);
1023 fail_unless (pts >= prev_pts);
1024 prev_pts = pts;
1025 gst_buffer_unmap (buf, &map);
1026 gst_buffer_unref (buf);
1027 }
1028
1029 /* teardown */
1030 gst_harness_teardown (h);
1031 gst_harness_teardown (audio);
1032 gst_harness_teardown (video);
1033 gst_harness_teardown (audio_q);
1034 gst_harness_teardown (video_q);
1035 }
1036
1037 GST_END_TEST;
1038
GST_START_TEST(test_rollover_timestamps)1039 GST_START_TEST (test_rollover_timestamps)
1040 {
1041 GstPad *audio_sink, *video_sink, *audio_src, *video_src;
1042 GstHarness *h, *audio, *video, *audio_q, *video_q;
1043 GstEvent *event;
1044 guint i;
1045 guint64 rollover_pts = (guint64) G_MAXUINT32 + 100;
1046 InputData input[] = {
1047 {AUDIO, 0}
1048 ,
1049 {VIDEO, 0}
1050 ,
1051 {VIDEO, (guint64) G_MAXUINT32 - 100}
1052 ,
1053 {AUDIO, (guint64) G_MAXUINT32 - 95}
1054 ,
1055 {AUDIO, rollover_pts}
1056 ,
1057 };
1058
1059 /* setup flvmuxer with queues in front */
1060 h = gst_harness_new_with_padnames ("flvmux", NULL, "src");
1061 audio = gst_harness_new_with_element (h->element, "audio", NULL);
1062 video = gst_harness_new_with_element (h->element, "video", NULL);
1063 audio_q = gst_harness_new ("queue");
1064 video_q = gst_harness_new ("queue");
1065 audio_sink = GST_PAD_PEER (audio->srcpad);
1066 video_sink = GST_PAD_PEER (video->srcpad);
1067 audio_src = GST_PAD_PEER (audio_q->sinkpad);
1068 video_src = GST_PAD_PEER (video_q->sinkpad);
1069 gst_pad_unlink (audio->srcpad, audio_sink);
1070 gst_pad_unlink (video->srcpad, video_sink);
1071 gst_pad_unlink (audio_src, audio_q->sinkpad);
1072 gst_pad_unlink (video_src, video_q->sinkpad);
1073 gst_pad_link (audio_src, audio_sink);
1074 gst_pad_link (video_src, video_sink);
1075 g_object_set (h->element, "streamable", TRUE, NULL);
1076
1077 gst_harness_set_src_caps_str (audio_q,
1078 "audio/mpeg, mpegversion=(int)4, "
1079 "rate=(int)44100, channels=(int)1, "
1080 "stream-format=(string)raw, codec_data=(buffer)1208");
1081
1082 gst_harness_set_src_caps_str (video_q,
1083 "video/x-h264, stream-format=(string)avc, alignment=(string)au, "
1084 "codec_data=(buffer)0142c00dffe1000d6742c00d95a0507c807844235001000468ce3c80");
1085
1086 for (i = 0; i < G_N_ELEMENTS (input); i++) {
1087 InputData *d = &input[i];
1088 GstBuffer *buf = gst_buffer_new ();
1089
1090 GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = d->ts * GST_MSECOND;
1091 GST_DEBUG ("Push media=%u, pts=%" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT
1092 ")", d->media_type, d->ts, GST_TIME_ARGS (GST_BUFFER_PTS (buf)));
1093
1094 if (d->media_type == AUDIO)
1095 gst_harness_push (audio_q, buf);
1096 else
1097 gst_harness_push (video_q, buf);
1098
1099 }
1100 gst_harness_push_event (audio_q, gst_event_new_eos ());
1101 gst_harness_push_event (video_q, gst_event_new_eos ());
1102
1103 while ((event = gst_harness_pull_event (h)) != NULL) {
1104 GstEventType event_type = GST_EVENT_TYPE (event);
1105 gst_event_unref (event);
1106
1107 if (event_type == GST_EVENT_EOS)
1108 break;
1109 }
1110
1111 /* pull the flv metadata */
1112 gst_buffer_unref (gst_harness_pull (h));
1113 gst_buffer_unref (gst_harness_pull (h));
1114 gst_buffer_unref (gst_harness_pull (h));
1115 gst_buffer_unref (gst_harness_pull (h));
1116
1117 /* verify rollover pts in the flvheader is handled */
1118 for (i = 0; i < G_N_ELEMENTS (input); i++) {
1119 GstBuffer *buf = gst_harness_pull (h);
1120 GstMapInfo map;
1121 guint32 pts, pts_ext;
1122
1123 fail_unless (buf != NULL);
1124
1125 gst_buffer_map (buf, &map, GST_MAP_READ);
1126 pts = GST_READ_UINT24_BE (map.data + 4);
1127 pts_ext = GST_READ_UINT8 (map.data + 7);
1128 pts |= pts_ext << 24;
1129 GST_DEBUG ("media=%u, pts=%u (%" GST_TIME_FORMAT ")",
1130 map.data[0], pts, GST_TIME_ARGS (pts * GST_MSECOND));
1131 fail_unless (pts == (guint32) input[i].ts);
1132 gst_buffer_unmap (buf, &map);
1133 gst_buffer_unref (buf);
1134 }
1135
1136 /* teardown */
1137 gst_harness_teardown (h);
1138 gst_harness_teardown (audio);
1139 gst_harness_teardown (video);
1140 gst_harness_teardown (audio_q);
1141 gst_harness_teardown (video_q);
1142 }
1143
1144 GST_END_TEST;
1145
1146 static Suite *
flvmux_suite(void)1147 flvmux_suite (void)
1148 {
1149 Suite *s = suite_create ("flvmux");
1150 TCase *tc_chain = tcase_create ("general");
1151 gint loop = 16;
1152
1153 suite_add_tcase (s, tc_chain);
1154
1155 #ifdef HAVE_VALGRIND
1156 if (RUNNING_ON_VALGRIND) {
1157 loop = 1;
1158 }
1159 #endif
1160
1161 tcase_add_loop_test (tc_chain, test_index_writing, 0, loop);
1162
1163 tcase_add_test (tc_chain, test_speex_streamable);
1164 tcase_add_test (tc_chain, test_increasing_timestamp_when_pts_none);
1165 tcase_add_test (tc_chain, test_video_caps_late);
1166 tcase_add_test (tc_chain, test_audio_caps_change_streamable);
1167 tcase_add_test (tc_chain, test_video_caps_change_streamable);
1168 tcase_add_test (tc_chain, test_audio_caps_change_streamable_single);
1169 tcase_add_test (tc_chain, test_video_caps_change_streamable_single);
1170 tcase_add_test (tc_chain, test_incrementing_timestamps);
1171 tcase_add_test (tc_chain, test_rollover_timestamps);
1172
1173 return s;
1174 }
1175
1176 GST_CHECK_MAIN (flvmux)
1177