diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index e1029fac91..1ab02d1683 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -1125,6 +1125,10 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, data[11] |= (cpad->width << 1) & 0x02; data[11] |= (cpad->channels << 0) & 0x01; + GST_DEBUG_OBJECT (mux, "Creating byte %02x with " + "audio_codec:%d, rate:%d, width:%d, channels:%d", + data[11], cpad->audio_codec, cpad->rate, cpad->width, cpad->channels); + if (cpad->audio_codec == 10) { data[12] = is_codec_data ? 0 : 1; @@ -1144,8 +1148,14 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, GST_BUFFER_DURATION (tag) = GST_CLOCK_TIME_NONE; if (buffer) { - GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET (buffer); - GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_END (buffer); + /* if we are streamable we copy over timestamps and offsets, + if not just copy the offsets */ + if (mux->streamable) { + gst_buffer_copy_into (tag, buffer, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); + } else { + GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET (buffer); + GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_END (buffer); + } /* mark the buffer if it's an audio buffer and there's also video being muxed * or it's a video interframe */ @@ -1298,7 +1308,8 @@ gst_flv_mux_write_header (GstFlvMux * mux) gst_caps_unref (caps); /* segment */ - gst_segment_init (&segment, GST_FORMAT_BYTES); + gst_segment_init (&segment, + mux->streamable ? GST_FORMAT_TIME : GST_FORMAT_BYTES); gst_pad_push_event (mux->srcpad, gst_event_new_segment (&segment)); /* push the header buffer, the metadata and the codec info, if any */ diff --git a/tests/check/elements/flvmux.c b/tests/check/elements/flvmux.c index 1df2efe423..96354d591f 100644 --- a/tests/check/elements/flvmux.c +++ b/tests/check/elements/flvmux.c @@ -27,6 +27,7 @@ #endif #include +#include #include @@ -152,6 +153,178 @@ GST_START_TEST (test_index_writing) GST_END_TEST; +static GstBuffer * +create_buffer (guint8 * data, gsize size, + GstClockTime timestamp, GstClockTime duration) +{ + GstBuffer * buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + data, size, 0, size, NULL, NULL); + GST_BUFFER_PTS (buf) = timestamp; + GST_BUFFER_DTS (buf) = timestamp; + GST_BUFFER_DURATION (buf) = duration; + return buf; +} + +GST_START_TEST (test_speex_streamable) +{ + GstBuffer * buf; + GstMapInfo map = GST_MAP_INFO_INIT; + + guint8 header0[] = { + 0x53, 0x70, 0x65, 0x65, 0x78, 0x20, 0x20, 0x20, + 0x31, 0x2e, 0x32, 0x72, 0x63, 0x31, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x80, 0x3e, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + guint8 header1[] = { + 0x1f, 0x00, 0x00, 0x00, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x47, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x65, 0x72, 0x20, 0x53, 0x70, 0x65, 0x65, 0x78, + 0x65, 0x6e, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + + guint8 buffer[] = { + 0x36, 0x9d, 0x1b, 0x9a, 0x20, 0x00, 0x01, 0x68, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0x84, + 0x00, 0xb4, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x42, 0x00, 0x5a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x21, 0x00, 0x2d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1b, 0x3b, 0x60, + 0xab, 0xab, 0xab, 0xab, 0xab, 0x0a, 0xba, 0xba, + 0xba, 0xba, 0xb0, 0xab, 0xab, 0xab, 0xab, 0xab, + 0x0a, 0xba, 0xba, 0xba, 0xba, 0xb7 + }; + + GstCaps * caps = gst_caps_new_simple ("audio/x-speex", + "rate", G_TYPE_INT, 16000, + "channels", G_TYPE_INT, 1, + NULL); + + const GstClockTime base_time = 123456789; + const GstClockTime duration_ms = 20; + const GstClockTime duration = duration_ms * GST_MSECOND; + + GstHarness * h = gst_harness_new_with_padnames ("flvmux", "audio", "src"); + gst_harness_set_src_caps (h, caps); + g_object_set (h->element, "streamable", 1, NULL); + + /* push speex header0 */ + gst_harness_push (h, create_buffer (header0, sizeof (header0), base_time, 0)); + + /* push speex header1 */ + gst_harness_push (h, create_buffer (header1, sizeof (header1), base_time, 0)); + + /* push speex data */ + gst_harness_push (h, create_buffer (buffer, sizeof (buffer), + base_time, duration)); + + /* push speex data 2*/ + gst_harness_push (h, create_buffer (buffer, sizeof (buffer), + base_time + duration, duration)); + + /* pull out stream-start event */ + gst_event_unref (gst_harness_pull_event (h)); + + /* pull out caps event */ + gst_event_unref (gst_harness_pull_event (h)); + + /* pull out segment event and verify we are using GST_FORMAT_TIME */ + { + GstEvent * event = gst_harness_pull_event (h); + const GstSegment * segment; + gst_event_parse_segment (event, &segment); + fail_unless_equals_int (GST_FORMAT_TIME, segment->format); + gst_event_unref (event); + } + + /* pull FLV header buffer */ + buf = gst_harness_pull (h); + gst_buffer_unref (buf); + + /* pull Metadata buffer */ + buf = gst_harness_pull (h); + gst_buffer_unref (buf); + + /* pull header0 */ + buf = gst_harness_pull (h); + fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf)); + fail_unless_equals_uint64 (base_time, GST_BUFFER_DTS (buf)); + fail_unless_equals_uint64 (0, GST_BUFFER_DURATION (buf)); + gst_buffer_map (buf, &map, GST_MAP_READ); + /* 0x08 means it is audio */ + fail_unless_equals_int (0x08, map.data[0]); + /* timestamp should be starting from 0 */ + fail_unless_equals_int (0x00, map.data[6]); + /* 0xb2 means Speex, 16000Hz, Mono */ + fail_unless_equals_int (0xb2, map.data[11]); + /* verify content is intact */ + fail_unless_equals_int (0, memcmp (&map.data[12], header0, sizeof (header0))); + gst_buffer_unmap (buf, &map); + gst_buffer_unref (buf); + + /* pull header1 */ + buf = gst_harness_pull (h); + fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf)); + fail_unless_equals_uint64 (base_time, GST_BUFFER_DTS (buf)); + fail_unless_equals_uint64 (0, GST_BUFFER_DURATION (buf)); + gst_buffer_map (buf, &map, GST_MAP_READ); + /* 0x08 means it is audio */ + fail_unless_equals_int (0x08, map.data[0]); + /* timestamp should be starting from 0 */ + fail_unless_equals_int (0x00, map.data[6]); + /* 0xb2 means Speex, 16000Hz, Mono */ + fail_unless_equals_int (0xb2, map.data[11]); + /* verify content is intact */ + fail_unless_equals_int (0, memcmp (&map.data[12], header1, sizeof (header1))); + gst_buffer_unmap (buf, &map); + gst_buffer_unref (buf); + + /* pull data */ + buf = gst_harness_pull (h); + fail_unless_equals_uint64 (base_time, GST_BUFFER_PTS (buf)); + fail_unless_equals_uint64 (base_time, GST_BUFFER_DTS (buf)); + fail_unless_equals_uint64 (duration, GST_BUFFER_DURATION (buf)); + gst_buffer_map (buf, &map, GST_MAP_READ); + /* 0x08 means it is audio */ + fail_unless_equals_int (0x08, map.data[0]); + /* timestamp should be starting from 0 */ + fail_unless_equals_int (0x00, map.data[6]); + /* 0xb2 means Speex, 16000Hz, Mono */ + fail_unless_equals_int (0xb2, map.data[11]); + /* verify content is intact */ + fail_unless_equals_int (0, memcmp (&map.data[12], buffer, sizeof (buffer))); + gst_buffer_unmap (buf, &map); + gst_buffer_unref (buf); + + /* pull data */ + buf = gst_harness_pull (h); + fail_unless_equals_uint64 (base_time + duration, GST_BUFFER_PTS (buf)); + fail_unless_equals_uint64 (base_time + duration, GST_BUFFER_DTS (buf)); + fail_unless_equals_uint64 (duration, GST_BUFFER_DURATION (buf)); + gst_buffer_map (buf, &map, GST_MAP_READ); + /* 0x08 means it is audio */ + fail_unless_equals_int (0x08, map.data[0]); + /* timestamp should reflect the duration_ms */ + fail_unless_equals_int (duration_ms, map.data[6]); + /* 0xb2 means Speex, 16000Hz, Mono */ + fail_unless_equals_int (0xb2, map.data[11]); + /* verify content is intact */ + fail_unless_equals_int (0, memcmp (&map.data[12], buffer, sizeof (buffer))); + gst_buffer_unmap (buf, &map); + gst_buffer_unref (buf); + + gst_harness_teardown (h); +} +GST_END_TEST; + static Suite * flvmux_suite (void) { @@ -169,6 +342,8 @@ flvmux_suite (void) tcase_add_loop_test (tc_chain, test_index_writing, 1, loop); + tcase_add_test (tc_chain, test_speex_streamable); + return s; }