• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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