flvmux: Test that timestamps are always increasing
[platform/upstream/gst-plugins-good.git] / tests / check / elements / flvmux.c
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
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
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
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_get_request_pad (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
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 *
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
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
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
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
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 (g_ascii_strncasecmp ("audio", name, 5) == 0)
463     gst_harness_add_element_src_pad (h->a_sink, srcpad);
464   else
465     gst_harness_add_element_src_pad (h->v_sink, srcpad);
466
467   gst_caps_unref (caps);
468 }
469
470 GST_START_TEST (test_video_caps_late)
471 {
472   GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
473   GstHarness *a_src =
474       gst_harness_new_with_element (mux->element, "audio", NULL);
475   GstHarness *v_src =
476       gst_harness_new_with_element (mux->element, "video", NULL);
477   GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
478   GstHarness *a_sink =
479       gst_harness_new_with_element (demux->element, NULL, NULL);
480   GstHarness *v_sink =
481       gst_harness_new_with_element (demux->element, NULL, NULL);
482   DemuxHarnesses harnesses = { a_sink, v_sink };
483   guint i;
484   GstTestClock *tclock;
485
486   g_object_set (mux->element, "streamable", TRUE,
487       "latency", G_GUINT64_CONSTANT (1), NULL);
488   gst_harness_use_testclock (mux);
489
490   g_signal_connect (demux->element, "pad-added",
491       G_CALLBACK (flvdemux_pad_added), &harnesses);
492   gst_harness_add_sink_harness (mux, demux);
493
494   gst_harness_set_src_caps_str (a_src,
495       "audio/x-speex, rate=(int)16000, channels=(int)1");
496
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,
500               NULL)));
501
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,
505               NULL)));
506
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);
513
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");
517
518   gst_harness_crank_single_clock_wait (mux);
519
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,
523               NULL)));
524
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)));
528
529   gst_harness_crank_single_clock_wait (mux);
530   gst_harness_crank_single_clock_wait (mux);
531   gst_harness_crank_single_clock_wait (mux);
532
533
534   /* push from flvmux to demux */
535   for (i = 0; i < 6; i++)
536     gst_harness_push_to_sink (mux);
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
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   guint i;
576
577   const GstClockTime base_time = 123456789;
578   const GstClockTime duration_ms = 20;
579   const GstClockTime duration = duration_ms * GST_MSECOND;
580
581   g_object_set (mux->element, "streamable", TRUE, NULL);
582
583   g_signal_connect (demux->element, "pad-added",
584       G_CALLBACK (flvdemux_pad_added), &harnesses);
585   gst_harness_add_sink_harness (mux, demux);
586
587   a_caps1 =
588       gst_caps_from_string
589       ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
590       "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
591
592   v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
593       "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
594
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));
597
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,
600               duration)));
601
602   fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
603           create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
604
605   gst_harness_crank_single_clock_wait (mux);
606
607   /* push from flvmux to demux */
608   for (i = 0; i < 6; i++) {
609     gst_harness_push_to_sink (mux);
610   }
611
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,
617           v_caps1, ret_caps);
618       fail_unless (gst_caps_is_equal (v_caps1, ret_caps));
619     }
620     gst_event_unref (event);
621   }
622
623   /* caps change */
624   v_caps2 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
625       "codec_data=(buffer)0164001fffe1001c6764001facd9405005bb016a02020280000003008000001e478c18cb01000568ebecb22c");
626
627   gst_harness_set_src_caps (v_src, gst_caps_ref (v_caps2));
628
629   fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
630           create_buffer (h264_buf, sizeof (h264_buf), base_time + duration,
631               duration)));
632
633   gst_harness_crank_single_clock_wait (mux);
634
635   /* push from flvmux to demux */
636   for (i = 0; i < 2; i++) {
637     gst_harness_push_to_sink (mux);
638   }
639
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,
645           v_caps2, ret_caps);
646       fail_unless (gst_caps_is_equal (v_caps2, ret_caps));
647     }
648     gst_event_unref (event);
649   }
650
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);
658
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);
664 }
665
666 GST_END_TEST;
667
668 GST_START_TEST (test_audio_caps_change_streamable)
669 {
670   GstEvent *event;
671   GstCaps *a_caps1, *a_caps2, *v_caps1, *ret_caps;
672   GstHarness *mux = gst_harness_new_with_padnames ("flvmux", NULL, "src");
673   GstHarness *a_src =
674       gst_harness_new_with_element (mux->element, "audio", NULL);
675   GstHarness *v_src =
676       gst_harness_new_with_element (mux->element, "video", NULL);
677   GstHarness *demux = gst_harness_new_with_padnames ("flvdemux", "sink", NULL);
678   GstHarness *a_sink =
679       gst_harness_new_with_element (demux->element, NULL, NULL);
680   GstHarness *v_sink =
681       gst_harness_new_with_element (demux->element, NULL, NULL);
682   DemuxHarnesses harnesses = { a_sink, v_sink };
683   guint i;
684
685   const GstClockTime base_time = 123456789;
686   const GstClockTime duration_ms = 20;
687   const GstClockTime duration = duration_ms * GST_MSECOND;
688
689   g_object_set (mux->element, "streamable", TRUE, NULL);
690
691   g_signal_connect (demux->element, "pad-added",
692       G_CALLBACK (flvdemux_pad_added), &harnesses);
693   gst_harness_add_sink_harness (mux, demux);
694
695   a_caps1 =
696       gst_caps_from_string
697       ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
698       "rate=(int)44100, channels=(int)1, codec_data=(buffer)1208");
699
700   v_caps1 = gst_caps_from_string ("video/x-h264, stream-format=(string)avc, "
701       "codec_data=(buffer)0142c00cffe1000b6742c00c95a7201e1108d401000468ce3c80");
702
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));
705
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,
708               duration)));
709
710   fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (v_src,
711           create_buffer (h264_buf, sizeof (h264_buf), base_time, duration)));
712
713   gst_harness_crank_single_clock_wait (mux);
714
715   /* push from flvmux to demux */
716   for (i = 0; i < 6; i++) {
717     gst_harness_push_to_sink (mux);
718   }
719
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,
725           a_caps1, ret_caps);
726       fail_unless (gst_caps_is_equal (a_caps1, ret_caps));
727     }
728     gst_event_unref (event);
729   }
730
731   /* caps change */
732   a_caps2 =
733       gst_caps_from_string
734       ("audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, "
735       "rate=(int)22050, channels=(int)1, codec_data=(buffer)1388");
736
737   gst_harness_set_src_caps (a_src, gst_caps_ref (a_caps2));
738
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)));
742
743   gst_harness_crank_single_clock_wait (mux);
744
745   /* push from flvmux to demux */
746   for (i = 0; i < 2; i++) {
747     gst_harness_push_to_sink (mux);
748   }
749
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,
755           a_caps2, ret_caps);
756       fail_unless (gst_caps_is_equal (a_caps2, ret_caps));
757     }
758     gst_event_unref (event);
759   }
760
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);
768
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);
774 }
775
776 GST_END_TEST;
777
778 typedef struct
779 {
780   guint media_type;
781   gint ts;                      /* timestamp in ms */
782   gint rt;                      /* running_time in ms */
783 } InputData;
784
785 GST_START_TEST (test_incrementing_timestamps)
786 {
787   GstPad *audio_sink, *video_sink, *audio_src, *video_src;
788   GstHarness *h, *audio, *video, *audio_q, *video_q;
789   GstTestClock *tclock;
790   guint i;
791   guint32 prev_pts;
792   InputData input[] = {
793     {AUDIO, 155, 175},
794     {VIDEO, 156, 191},
795     {VIDEO, 190, 191},
796     {AUDIO, 176, 195},
797     {AUDIO, 197, 215},
798   };
799
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);
817
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");
822
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");
826
827   tclock = gst_harness_get_testclock (h);
828
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;
834
835     GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = d->ts * GST_MSECOND;
836     gst_test_clock_set_time (tclock, now);
837
838     if (d->media_type == AUDIO)
839       gst_harness_push (audio_q, buf);
840     else
841       gst_harness_push (video_q, buf);
842
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);
847   }
848
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));
853
854   /* verify pts in the flvheader is increasing */
855   prev_pts = 0;
856   for (i = 0; i < G_N_ELEMENTS (input); i++) {
857     GstBuffer *buf = gst_harness_pull (h);
858     GstMapInfo map;
859     guint32 pts;
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);
864     prev_pts = pts;
865     gst_buffer_unmap (buf, &map);
866     gst_buffer_unref (buf);
867   }
868
869   /* teardown */
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);
876 }
877
878 GST_END_TEST;
879
880 static Suite *
881 flvmux_suite (void)
882 {
883   Suite *s = suite_create ("flvmux");
884   TCase *tc_chain = tcase_create ("general");
885   gint loop = 16;
886
887   suite_add_tcase (s, tc_chain);
888
889 #ifdef HAVE_VALGRIND
890   if (RUNNING_ON_VALGRIND) {
891     loop = 1;
892   }
893 #endif
894
895   tcase_add_loop_test (tc_chain, test_index_writing, 0, loop);
896
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);
903
904   return s;
905 }
906
907 GST_CHECK_MAIN (flvmux)