tests: rtp-payloading: add test for rtph264depay avc/byte-stream output
authorTim-Philipp Müller <tim@centricular.com>
Mon, 24 Apr 2017 16:31:04 +0000 (17:31 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Mon, 24 Apr 2017 16:31:04 +0000 (17:31 +0100)
Make sure avc output doesn't contain SPS/PPS inline, but
byte-stream output does.

tests/check/Makefile.am
tests/check/elements/rtp-payloading.c

index 6e8ede7..899b182 100644 (file)
@@ -483,8 +483,8 @@ elements_rglimiter_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION
 elements_rgvolume_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
 elements_rgvolume_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD) $(LIBM)
 
-elements_rtp_payloading_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
-elements_rtp_payloading_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
+elements_rtp_payloading_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+elements_rtp_payloading_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
 
 elements_spectrum_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
 elements_spectrum_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(LDADD)
index d09f303..c68b2ba 100644 (file)
@@ -20,6 +20,7 @@
 #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>
 
@@ -650,6 +651,174 @@ GST_START_TEST (rtp_h264)
 }
 
 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,
@@ -1446,6 +1615,8 @@ rtp_payloading_suite (void)
   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);