#include <gst/check/gstcheck.h>
#include <gst/check/gstharness.h>
#include <gst/audio/audio.h>
+#include <gst/base/base.h>
#include <stdlib.h>
#include <unistd.h>
}
GST_END_TEST;
+
+/* H264 data generated with:
+ * videotestsrc pattern=black ! video/x-raw,width=16,height=16 ! openh264enc */
+static const guint8 h264_16x16_black_bs[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xd0, 0x0b,
+ 0x8c, 0x8d, 0x4e, 0x40, 0x3c, 0x22, 0x11, 0xa8,
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x3c, 0x80,
+ 0x00, 0x00, 0x00, 0x01, 0x65, 0xb8, 0x00, 0x04,
+ 0x00, 0x00, 0x09, 0xe4, 0xc5, 0x00, 0x01, 0x19,
+ 0xfc
+};
+
+static GstSample *
+rtp_h264depay_run (const gchar * stream_format)
+{
+ GstHarness *h;
+ GstSample *sample;
+ GstBuffer *buf;
+ GstEvent *e;
+ GstCaps *out_caps;
+ GstCaps *in_caps;
+ gboolean seen_caps = FALSE;
+ gsize size;
+
+ h = gst_harness_new_parse ("rtph264pay ! rtph264depay");
+
+ /* Our input data is in byte-stream format (not that it matters) */
+ in_caps = gst_caps_new_simple ("video/x-h264",
+ "stream-format", G_TYPE_STRING, "byte-stream",
+ "alignment", G_TYPE_STRING, "au",
+ "profile", G_TYPE_STRING, "baseline",
+ "width", G_TYPE_INT, 16,
+ "height", G_TYPE_INT, 16, "framerate", GST_TYPE_FRACTION, 30, 1, NULL);
+
+ /* Force rtph264depay to output format as requested */
+ out_caps = gst_caps_new_simple ("video/x-h264",
+ "stream-format", G_TYPE_STRING, stream_format,
+ "alignment", G_TYPE_STRING, "au", NULL);
+
+ gst_harness_set_caps (h, in_caps, out_caps);
+ in_caps = NULL;
+ out_caps = NULL;
+
+ gst_harness_play (h);
+
+ size = sizeof (h264_16x16_black_bs);
+ buf = gst_buffer_new_wrapped (g_memdup (h264_16x16_black_bs, size), size);
+ fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
+ fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
+
+ while ((e = gst_harness_try_pull_event (h))) {
+ if (GST_EVENT_TYPE (e) == GST_EVENT_CAPS) {
+ GstCaps *caps = NULL;
+
+ gst_event_parse_caps (e, &caps);
+ gst_caps_replace (&out_caps, caps);
+ seen_caps = TRUE;
+ }
+ gst_event_unref (e);
+ }
+ fail_unless (seen_caps);
+
+ buf = gst_harness_pull (h);
+ sample = gst_sample_new (buf, out_caps, NULL, NULL);
+ gst_buffer_unref (buf);
+ gst_caps_replace (&out_caps, NULL);
+
+ gst_harness_teardown (h);
+ return sample;
+}
+
+GST_START_TEST (rtp_h264depay_avc)
+{
+ const GValue *val;
+ GstStructure *st;
+ GstMapInfo map = GST_MAP_INFO_INIT;
+ GstBuffer *buf;
+ GstSample *s;
+ GstCaps *caps;
+
+ s = rtp_h264depay_run ("avc");
+
+ /* must have codec_data in output caps */
+ caps = gst_sample_get_caps (s);
+ st = gst_caps_get_structure (caps, 0);
+ GST_LOG ("caps: %" GST_PTR_FORMAT, caps);
+ fail_unless (gst_structure_has_field (st, "stream-format"));
+ fail_unless (gst_structure_has_field (st, "alignment"));
+ fail_unless (gst_structure_has_field (st, "level"));
+ fail_unless (gst_structure_has_field (st, "profile"));
+ val = gst_structure_get_value (st, "codec_data");
+ fail_unless (val != NULL);
+
+ buf = gst_sample_get_buffer (s);
+ fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+ GST_MEMDUMP ("H.264 AVC frame", map.data, map.size);
+ fail_unless (map.size >= 4 + 13);
+ /* Want IDR slice as very first thing.
+ * We assume nal size markers are 4 bytes here. */
+ fail_unless_equals_int (map.data[4] & 0x1f, 5);
+ gst_buffer_unmap (buf, &map);
+
+ gst_sample_unref (s);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (rtp_h264depay_bytestream)
+{
+ GstByteReader br;
+ GstStructure *st;
+ GstMapInfo map = GST_MAP_INFO_INIT;
+ GstBuffer *buf;
+ GstSample *s;
+ GstCaps *caps;
+ guint32 dw;
+ guint8 b;
+ guint off, left;
+
+ s = rtp_h264depay_run ("byte-stream");
+
+ /* must not have codec_data in output caps */
+ caps = gst_sample_get_caps (s);
+ st = gst_caps_get_structure (caps, 0);
+ GST_LOG ("caps: %" GST_PTR_FORMAT, caps);
+ fail_if (gst_structure_has_field (st, "codec_data"));
+
+ buf = gst_sample_get_buffer (s);
+ fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ));
+ GST_MEMDUMP ("H.264 byte-stream frame", map.data, map.size);
+ fail_unless (map.size > 40);
+ gst_byte_reader_init (&br, map.data, map.size);
+ /* We assume nal sync markers are 4 bytes... */
+ fail_unless (gst_byte_reader_get_uint32_be (&br, &dw));
+ fail_unless_equals_int (dw, 0x00000001);
+ /* Want SPS as very first thing */
+ fail_unless (gst_byte_reader_get_uint8 (&br, &b));
+ fail_unless_equals_int (b & 0x1f, 7);
+ /* Then, we want the PPS */
+ left = gst_byte_reader_get_remaining (&br);
+ off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+ fail_if (off == (guint) - 1);
+ gst_byte_reader_skip (&br, off + 4);
+ fail_unless (gst_byte_reader_get_uint8 (&br, &b));
+ fail_unless_equals_int (b & 0x1f, 8);
+ /* FIXME: looks like we get two sets of SPS/PPS ?! */
+ left = gst_byte_reader_get_remaining (&br);
+ off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+ fail_if (off == (guint) - 1);
+ gst_byte_reader_skip (&br, off + 4);
+ left = gst_byte_reader_get_remaining (&br);
+ off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+ fail_if (off == (guint) - 1);
+ gst_byte_reader_skip (&br, off + 4);
+ /* Finally, we want an IDR slice */
+ left = gst_byte_reader_get_remaining (&br);
+ off = gst_byte_reader_masked_scan_uint32 (&br, 0xffffffff, 1, 0, left);
+ fail_if (off == (guint) - 1);
+ gst_byte_reader_skip (&br, off + 4);
+ fail_unless (gst_byte_reader_get_uint8 (&br, &b));
+ fail_unless_equals_int (b & 0x1f, 5);
+ gst_buffer_unmap (buf, &map);
+
+ gst_sample_unref (s);
+}
+
+GST_END_TEST;
+
static const guint8 rtp_h264_list_lt_mtu_frame_data[] =
/* not packetized, next NAL starts with 0001 */
{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
tcase_add_test (tc_chain, rtp_h263);
tcase_add_test (tc_chain, rtp_h263p);
tcase_add_test (tc_chain, rtp_h264);
+ tcase_add_test (tc_chain, rtp_h264depay_avc);
+ tcase_add_test (tc_chain, rtp_h264depay_bytestream);
tcase_add_test (tc_chain, rtp_h264_list_lt_mtu);
tcase_add_test (tc_chain, rtp_h264_list_lt_mtu_avc);
tcase_add_test (tc_chain, rtp_h264_list_gt_mtu);