1 /* GStreamer unit tests for flvmux
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>
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.
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.
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.
28 # include <valgrind/valgrind.h>
31 #include <gst/check/gstcheck.h>
32 #include <gst/check/gstharness.h>
36 static GstBusSyncReply
37 error_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
39 if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
43 gst_message_parse_error (msg, &err, &dbg);
44 g_error ("ERROR: %s\n%s\n", err->message, dbg);
51 handoff_cb (GstElement * element, GstBuffer * buf, GstPad * pad,
55 GST_LOG ("counter = %d", *p_counter);
59 mux_pcm_audio (guint num_buffers, guint repeat)
61 GstElement *src, *sink, *flvmux, *conv, *pipeline;
62 GstPad *sinkpad, *srcpad;
65 GST_LOG ("num_buffers = %u", num_buffers);
67 pipeline = gst_pipeline_new ("pipeline");
68 fail_unless (pipeline != NULL, "Failed to create pipeline!");
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);
74 src = gst_element_factory_make ("audiotestsrc", "audiotestsrc");
75 fail_unless (src != NULL, "Failed to create 'audiotestsrc' element!");
77 g_object_set (src, "num-buffers", num_buffers, NULL);
79 conv = gst_element_factory_make ("audioconvert", "audioconvert");
80 fail_unless (conv != NULL, "Failed to create 'audioconvert' element!");
82 flvmux = gst_element_factory_make ("flvmux", "flvmux");
83 fail_unless (flvmux != NULL, "Failed to create 'flvmux' element!");
85 sink = gst_element_factory_make ("fakesink", "fakesink");
86 fail_unless (sink != NULL, "Failed to create 'fakesink' element!");
88 g_object_set (sink, "signal-handoffs", TRUE, NULL);
89 g_signal_connect (sink, "handoff", G_CALLBACK (handoff_cb), &counter);
91 gst_bin_add_many (GST_BIN (pipeline), src, conv, flvmux, sink, NULL);
93 fail_unless (gst_element_link (src, conv));
94 fail_unless (gst_element_link (flvmux, sink));
96 /* now link the elements */
97 sinkpad = gst_element_get_request_pad (flvmux, "audio");
98 fail_unless (sinkpad != NULL, "Could not get audio request pad");
100 srcpad = gst_element_get_static_pad (conv, "src");
101 fail_unless (srcpad != NULL, "Could not get audioconvert's source pad");
103 fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
105 gst_object_unref (srcpad);
106 gst_object_unref (sinkpad);
109 GstStateChangeReturn state_ret;
112 GST_LOG ("repeat=%d", repeat);
116 state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
117 fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
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);
125 GST_LOG ("PAUSED, let's do the rest of it");
127 state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
128 fail_unless (state_ret != GST_STATE_CHANGE_FAILURE);
130 msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
131 fail_unless (msg != NULL, "Expected EOS message on bus!");
134 gst_message_unref (msg);
136 /* should have some output */
137 fail_unless (counter > 2);
139 fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
140 GST_STATE_CHANGE_SUCCESS);
142 /* repeat = test re-usability */
144 } while (repeat > 0);
146 gst_object_unref (pipeline);
149 GST_START_TEST (test_index_writing)
151 /* note: there's a magic 128 value in flvmux when doing index writing */
152 mux_pcm_audio (__i__ * 33 + 1, 2);
158 create_buffer (guint8 * data, gsize size,
159 GstClockTime timestamp, GstClockTime duration)
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;
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
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
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
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,
221 GST_START_TEST (test_speex_streamable)
224 GstMapInfo map = GST_MAP_INFO_INIT;
227 GstCaps *caps = gst_caps_new_simple ("audio/x-speex",
228 "rate", G_TYPE_INT, 16000,
229 "channels", G_TYPE_INT, 1,
232 const GstClockTime base_time = 123456789;
233 const GstClockTime duration_ms = 20;
234 const GstClockTime duration = duration_ms * GST_MSECOND;
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);
240 /* push speex header0 */
241 gst_harness_push (h, create_buffer (speex_hdr0,
242 sizeof (speex_hdr0), base_time, 0));
244 /* push speex header1 */
245 gst_harness_push (h, create_buffer (speex_hdr1,
246 sizeof (speex_hdr1), base_time, 0));
248 /* push speex data */
249 gst_harness_push (h, create_buffer (speex_buf,
250 sizeof (speex_buf), base_time, duration));
252 /* push speex data 2 */
253 gst_harness_push (h, create_buffer (speex_buf,
254 sizeof (speex_buf), base_time + duration, duration));
256 /* pull out stream-start event */
257 gst_event_unref (gst_harness_pull_event (h));
259 /* pull out caps event */
260 gst_event_unref (gst_harness_pull_event (h));
262 /* pull out segment event and verify we are using GST_FORMAT_TIME */
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);
271 /* pull FLV header buffer */
272 buf = gst_harness_pull (h);
273 gst_buffer_unref (buf);
275 /* pull Metadata buffer */
276 buf = gst_harness_pull (h);
277 gst_buffer_unref (buf);
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);
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);
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);
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);
357 gst_harness_teardown (h);
363 check_buf_type_timestamp (GstBuffer * buf, gint packet_type, gint timestamp)
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);
373 static const gint AUDIO = 0x08;
374 static const gint VIDEO = 0x09;
376 GST_START_TEST (test_increasing_timestamp_when_pts_none)
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;
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");
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);
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);
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);
410 /* Push audio + video + audio with increasing DTS, but PTS for video is
411 * GST_CLOCK_TIME_NONE
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);
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);
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);
428 /* Pull two metadata packets out */
429 gst_buffer_unref (gst_harness_pull (h));
430 gst_buffer_unref (gst_harness_pull (h));
432 /* Check that we receive the packets in monotonically increasing order and
433 * that their timestamps are correct (should start at 0)
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);
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);
457 flvdemux_pad_added (GstElement * flvdemux, GstPad * srcpad, DemuxHarnesses * h)
459 GstCaps *caps = gst_pad_get_current_caps (srcpad);
460 const gchar *name = gst_structure_get_name (gst_caps_get_structure (caps, 0));
462 if (g_ascii_strncasecmp ("audio", name, 5) == 0)
463 gst_harness_add_element_src_pad (h->a_sink, srcpad);
465 gst_harness_add_element_src_pad (h->v_sink, srcpad);
467 gst_caps_unref (caps);
470 GST_START_TEST (test_video_caps_late)
472 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
474 gst_harness_new_with_element (mux->element, "audio", NULL);
476 gst_harness_new_with_element (mux->element, "video", NULL);
477 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
479 gst_harness_new_with_element (demux->element, NULL, NULL);
481 gst_harness_new_with_element (demux->element, NULL, NULL);
482 DemuxHarnesses harnesses = { a_sink, v_sink };
484 GstTestClock *tclock;
486 g_object_set (mux->element, "streamable", TRUE,
487 "latency", G_GUINT64_CONSTANT (1), NULL);
488 gst_harness_use_testclock (mux);
490 g_signal_connect (demux->element, "pad-added",
491 G_CALLBACK (flvdemux_pad_added), &harnesses);
492 gst_harness_add_sink_harness (mux, demux);
494 gst_harness_set_src_caps_str (a_src,
495 "audio/x-speex, rate=(int)16000, channels=(int)1");
497 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
498 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
499 speex_hdr0, sizeof (speex_hdr0), 0, sizeof (speex_hdr0), NULL,
502 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
503 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
504 speex_hdr1, sizeof (speex_hdr1), 0, sizeof (speex_hdr1), NULL,
507 /* Wait a little and make sure no clock was scheduled as this shouldn't happen
508 * before the caps are set */
509 g_usleep (40 * 1000);
510 tclock = gst_harness_get_testclock (mux);
511 fail_unless (gst_test_clock_get_next_entry_time (tclock) ==
512 GST_CLOCK_TIME_NONE);
514 gst_harness_set_src_caps_str (v_src,
515 "video/x-h264, stream-format=(string)avc, alignment=(string)au, "
516 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
518 gst_harness_crank_single_clock_wait (mux);
520 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
521 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
522 speex_buf, sizeof (speex_buf), 0, sizeof (speex_buf), NULL,
525 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
526 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
527 h264_buf, sizeof (h264_buf), 0, sizeof (h264_buf), NULL, NULL)));
529 gst_harness_crank_single_clock_wait (mux);
530 gst_harness_crank_single_clock_wait (mux);
531 gst_harness_crank_single_clock_wait (mux);
534 /* push from flvmux to demux */
535 for (i = 0; i < 6; i++)
536 gst_harness_push_to_sink (mux);
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));
543 fail_unless (gst_test_clock_get_next_entry_time (tclock) ==
544 GST_CLOCK_TIME_NONE);
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);
556 guint8 raw_frame_short[] = {
557 0x27, 0x00, 0x03, 0x20, 0x64, 0x1c
560 GST_START_TEST (test_video_caps_change_streamable)
563 GstCaps *a_caps1, *v_caps1, *v_caps2, *ret_caps;
564 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
566 gst_harness_new_with_element (mux->element, "audio", NULL);
568 gst_harness_new_with_element (mux->element, "video", NULL);
569 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
571 gst_harness_new_with_element (demux->element, NULL, NULL);
573 gst_harness_new_with_element (demux->element, NULL, NULL);
574 DemuxHarnesses harnesses = { a_sink, v_sink };
577 const GstClockTime base_time = 123456789;
578 const GstClockTime duration_ms = 20;
579 const GstClockTime duration = duration_ms * GST_MSECOND;
581 g_object_set (mux->element, "streamable", TRUE, NULL);
583 g_signal_connect (demux->element, "pad-added",
584 G_CALLBACK (flvdemux_pad_added), &harnesses);
585 gst_harness_add_sink_harness (mux, demux);
589 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
590 "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
592 v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
593 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
595 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps1));
596 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps1));
598 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
599 create_buffer (raw_frame_short, sizeof (raw_frame_short), base_time,
602 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
603 create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
605 gst_harness_crank_single_clock_wait (mux);
607 /* push from flvmux to demux */
608 for (i = 0; i < 6; i++) {
609 gst_harness_push_to_sink (mux);
612 /* should accept without the constraint */
613 while ((event = gst_harness_try_pull_event (v_sink))) {
614 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
615 gst_event_parse_caps (event, &ret_caps);
616 GST_LOG ("v_caps1 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
618 fail_unless (gst_caps_is_equal (v_caps1, ret_caps));
620 gst_event_unref (event);
624 v_caps2 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
625 "codec_data=(buffer)0164001fffe1001c6764001facd9405005bb016a02020280000003008000001e478c18cb01000568ebecb22c");
627 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps2));
629 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
630 create_buffer (h264_buf, sizeof (h264_buf), base_time + duration,
633 gst_harness_crank_single_clock_wait (mux);
635 /* push from flvmux to demux */
636 for (i = 0; i < 2; i++) {
637 gst_harness_push_to_sink (mux);
640 /* should accept without the constraint */
641 while ((event = gst_harness_try_pull_event (v_sink))) {
642 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
643 gst_event_parse_caps (event, &ret_caps);
644 GST_LOG ("v_caps2 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
646 fail_unless (gst_caps_is_equal (v_caps2, ret_caps));
648 gst_event_unref (event);
651 /* verify we got 1x audio and 2x video buffers out of flvdemux */
652 gst_buffer_unref (gst_harness_pull (a_sink));
653 gst_buffer_unref (gst_harness_pull (v_sink));
654 gst_buffer_unref (gst_harness_pull (v_sink));
655 gst_caps_unref (a_caps1);
656 gst_caps_unref (v_caps1);
657 gst_caps_unref (v_caps2);
659 gst_harness_teardown (a_src);
660 gst_harness_teardown (v_src);
661 gst_harness_teardown (mux);
662 gst_harness_teardown (a_sink);
663 gst_harness_teardown (v_sink);
668 GST_START_TEST (test_audio_caps_change_streamable)
671 GstCaps *a_caps1, *a_caps2, *v_caps1, *ret_caps;
672 GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
674 gst_harness_new_with_element (mux->element, "audio", NULL);
676 gst_harness_new_with_element (mux->element, "video", NULL);
677 GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
679 gst_harness_new_with_element (demux->element, NULL, NULL);
681 gst_harness_new_with_element (demux->element, NULL, NULL);
682 DemuxHarnesses harnesses = { a_sink, v_sink };
685 const GstClockTime base_time = 123456789;
686 const GstClockTime duration_ms = 20;
687 const GstClockTime duration = duration_ms * GST_MSECOND;
689 g_object_set (mux->element, "streamable", TRUE, NULL);
691 g_signal_connect (demux->element, "pad-added",
692 G_CALLBACK (flvdemux_pad_added), &harnesses);
693 gst_harness_add_sink_harness (mux, demux);
697 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
698 "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
700 v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
701 "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
703 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps1));
704 gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps1));
706 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
707 create_buffer (raw_frame_short, sizeof (raw_frame_short), base_time,
710 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
711 create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
713 gst_harness_crank_single_clock_wait (mux);
715 /* push from flvmux to demux */
716 for (i = 0; i < 6; i++) {
717 gst_harness_push_to_sink (mux);
720 /* should accept without the constraint */
721 while ((event = gst_harness_try_pull_event (a_sink))) {
722 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
723 gst_event_parse_caps (event, &ret_caps);
724 GST_LOG ("a_caps1 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
726 fail_unless (gst_caps_is_equal (a_caps1, ret_caps));
728 gst_event_unref (event);
734 ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
735 "rate=(int)22050, channels=(int)1, codec_data=(buffer)1388");
737 gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps2));
739 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (a_src,
740 create_buffer (raw_frame_short, sizeof (raw_frame_short),
741 base_time + duration, duration)));
743 gst_harness_crank_single_clock_wait (mux);
745 /* push from flvmux to demux */
746 for (i = 0; i < 2; i++) {
747 gst_harness_push_to_sink (mux);
750 /* should accept without the constraint */
751 while ((event = gst_harness_try_pull_event (a_sink))) {
752 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
753 gst_event_parse_caps (event, &ret_caps);
754 GST_LOG ("a_caps2 %" GST_PTR_FORMAT ", ret caps %" GST_PTR_FORMAT,
756 fail_unless (gst_caps_is_equal (a_caps2, ret_caps));
758 gst_event_unref (event);
761 /* verify we got 2x audio and 1x video buffers out of flvdemux */
762 gst_buffer_unref (gst_harness_pull (a_sink));
763 gst_buffer_unref (gst_harness_pull (a_sink));
764 gst_buffer_unref (gst_harness_pull (v_sink));
765 gst_caps_unref (a_caps1);
766 gst_caps_unref (a_caps2);
767 gst_caps_unref (v_caps1);
769 gst_harness_teardown (a_src);
770 gst_harness_teardown (v_src);
771 gst_harness_teardown (mux);
772 gst_harness_teardown (a_sink);
773 gst_harness_teardown (v_sink);
781 gint ts; /* timestamp in ms */
782 gint rt; /* running_time in ms */
785 GST_START_TEST (test_incrementing_timestamps)
787 GstPad *audio_sink, *video_sink, *audio_src, *video_src;
788 GstHarness *h, *audio, *video, *audio_q, *video_q;
789 GstTestClock *tclock;
792 InputData input[] = {
800 /* setup flvmuxer with queues in front */
801 h = gst_harness_new_with_padnames ("flvmux", NULL, "src");
802 audio = gst_harness_new_with_element (h->element, "audio", NULL);
803 video = gst_harness_new_with_element (h->element, "video", NULL);
804 audio_q = gst_harness_new ("queue");
805 video_q = gst_harness_new ("queue");
806 audio_sink = GST_PAD_PEER (audio->srcpad);
807 video_sink = GST_PAD_PEER (video->srcpad);
808 audio_src = GST_PAD_PEER (audio_q->sinkpad);
809 video_src = GST_PAD_PEER (video_q->sinkpad);
810 gst_pad_unlink (audio->srcpad, audio_sink);
811 gst_pad_unlink (video->srcpad, video_sink);
812 gst_pad_unlink (audio_src, audio_q->sinkpad);
813 gst_pad_unlink (video_src, video_q->sinkpad);
814 gst_pad_link (audio_src, audio_sink);
815 gst_pad_link (video_src, video_sink);
816 g_object_set (h->element, "streamable", TRUE, NULL);
818 gst_harness_set_src_caps_str (audio_q,
819 "audio/mpeg, mpegversion=(int)4, "
820 "rate=(int)44100, channels=(int)1, "
821 "stream-format=(string)raw, codec_data=(buffer)1208");
823 gst_harness_set_src_caps_str (video_q,
824 "video/x-h264, stream-format=(string)avc, alignment=(string)au, "
825 "codec_data=(buffer)0142c00dffe1000d6742c00d95a0507c807844235001000468ce3c80");
827 tclock = gst_harness_get_testclock (h);
829 for (i = 0; i < G_N_ELEMENTS (input); i++) {
830 InputData *d = &input[i];
831 GstBuffer *buf = gst_buffer_new ();
832 GstClockTime now = d->rt * GST_MSECOND;
833 GstClockID pending, res;
835 GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = d->ts * GST_MSECOND;
836 gst_test_clock_set_time (tclock, now);
838 if (d->media_type == AUDIO)
839 gst_harness_push (audio_q, buf);
841 gst_harness_push (video_q, buf);
843 gst_test_clock_wait_for_next_pending_id (tclock, &pending);
844 res = gst_test_clock_process_next_clock_id (tclock);
845 gst_clock_id_unref (pending);
846 gst_clock_id_unref (res);
849 /* pull the flv metadata */
850 gst_buffer_unref (gst_harness_pull (h));
851 gst_buffer_unref (gst_harness_pull (h));
852 gst_buffer_unref (gst_harness_pull (h));
854 /* verify pts in the flvheader is increasing */
856 for (i = 0; i < G_N_ELEMENTS (input); i++) {
857 GstBuffer *buf = gst_harness_pull (h);
860 gst_buffer_map (buf, &map, GST_MAP_READ);
861 pts = GST_READ_UINT24_BE (map.data + 4);
862 GST_DEBUG ("media=%u, pts = %u\n", map.data[0], pts);
863 fail_unless (pts >= prev_pts);
865 gst_buffer_unmap (buf, &map);
866 gst_buffer_unref (buf);
870 gst_object_unref (tclock);
871 gst_harness_teardown (h);
872 gst_harness_teardown (audio);
873 gst_harness_teardown (video);
874 gst_harness_teardown (audio_q);
875 gst_harness_teardown (video_q);
883 Suite *s = suite_create ("flvmux");
884 TCase *tc_chain = tcase_create ("general");
887 suite_add_tcase (s, tc_chain);
890 if (RUNNING_ON_VALGRIND) {
895 tcase_add_loop_test (tc_chain, test_index_writing, 0, loop);
897 tcase_add_test (tc_chain, test_speex_streamable);
898 tcase_add_test (tc_chain, test_increasing_timestamp_when_pts_none);
899 tcase_add_test (tc_chain, test_video_caps_late);
900 tcase_add_test (tc_chain, test_audio_caps_change_streamable);
901 tcase_add_test (tc_chain, test_video_caps_change_streamable);
902 tcase_add_test (tc_chain, test_incrementing_timestamps);
907 GST_CHECK_MAIN (flvmux)