From a06152c40ac79f77ac9d275f00b40e4e9e3a3f81 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Mon, 4 Jul 2016 09:50:11 +0200 Subject: [PATCH] rtph265pay/depay: Sync against RFC 7798 Handle sprop-vps, sprop-sps and sprop-pps in caps instead of sprop-parameter-sets. rtph265pay works with byte-stream and hvc1 formats but not hev1 yet. It handles profile-id, tier-flag and level-id in caps query. https://bugzilla.gnome.org/show_bug.cgi?id=753760 --- gst/rtp/gstrtph265depay.c | 25 +++- gst/rtp/gstrtph265pay.c | 174 +++++++++++++------------- gst/rtp/gstrtph265pay.h | 1 - tests/check/elements/rtp-payloading.c | 159 +++++++++++++++++++++++ 4 files changed, 268 insertions(+), 91 deletions(-) diff --git a/gst/rtp/gstrtph265depay.c b/gst/rtp/gstrtph265depay.c index 9705c4d3c5..97353afcbf 100644 --- a/gst/rtp/gstrtph265depay.c +++ b/gst/rtp/gstrtph265depay.c @@ -131,7 +131,7 @@ gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass) gst_element_class_set_static_metadata (gstelement_class, "RTP H265 depayloader", "Codec/Depayloader/Network/RTP", - "Extracts H265 video from RTP packets (draft-ietf-payload-rtp-h265-03.txt)", + "Extracts H265 video from RTP packets (RFC 7798)", "Jurgen Slowack "); gstelement_class->change_state = gst_rtp_h265_depay_change_state; @@ -754,8 +754,10 @@ gst_rtp_h265_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) gint clock_rate; GstStructure *structure = gst_caps_get_structure (caps, 0); GstRtpH265Depay *rtph265depay; - const gchar *ps; - GstBuffer *codec_data; + const gchar *vps; + const gchar *sps; + const gchar *pps; + gchar *ps; GstMapInfo map; guint8 *ptr; @@ -766,7 +768,14 @@ gst_rtp_h265_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) depayload->clock_rate = clock_rate; /* Base64 encoded, comma separated config NALs */ - ps = gst_structure_get_string (structure, "sprop-parameter-sets"); + vps = gst_structure_get_string (structure, "sprop-vps"); + sps = gst_structure_get_string (structure, "sprop-sps"); + pps = gst_structure_get_string (structure, "sprop-pps"); + if (vps == NULL || sps == NULL || pps == NULL) { + ps = NULL; + } else { + ps = g_strdup_printf ("%s,%s,%s", vps, sps, pps); + } /* negotiate with downstream w.r.t. output format and alignment */ gst_rtp_h265_depay_negotiate (rtph265depay); @@ -775,6 +784,7 @@ gst_rtp_h265_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) /* for bytestream we only need the parameter sets but we don't error out * when they are not there, we assume they are in the stream. */ gchar **params; + GstBuffer *codec_data; guint len, total; gint i; @@ -855,10 +865,14 @@ gst_rtp_h265_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) } g_strfreev (params); - if (rtph265depay->sps->len == 0 || rtph265depay->pps->len == 0) + if (rtph265depay->vps->len == 0 || rtph265depay->sps->len == 0 || + rtph265depay->pps->len == 0) { goto incomplete_caps; + } } + g_free (ps); + return gst_rtp_h265_set_src_caps (rtph265depay); /* ERRORS */ @@ -866,6 +880,7 @@ incomplete_caps: { GST_DEBUG_OBJECT (depayload, "we have incomplete caps," " doing setcaps later"); + g_free (ps); return TRUE; } } diff --git a/gst/rtp/gstrtph265pay.c b/gst/rtp/gstrtph265pay.c index 067e5228b3..ed1d8b9b09 100644 --- a/gst/rtp/gstrtph265pay.c +++ b/gst/rtp/gstrtph265pay.c @@ -53,13 +53,12 @@ static GstStaticPadTemplate gst_rtp_h265_pay_sink_template = GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ( - /* Only bytestream format supported for now */ + /* only hvc1 and byte-stream formats supported for now */ + "video/x-h265, stream-format = (string) hvc1, alignment = (string) au; " /* "video/x-h265, " - "stream-format = (string) hvc1, alignment = (string) au; " - "video/x-h265, " "stream-format = (string) hev1, alignment = (string) au; " */ - "video/x-h265, " - "stream-format = (string) byte-stream, alignment = (string) { nal, au }") + "video/x-h265, stream-format = (string) byte-stream, " + "alignment = (string) { nal, au }") ); static GstStaticPadTemplate gst_rtp_h265_pay_src_template = @@ -167,7 +166,7 @@ gst_rtp_h265_pay_class_init (GstRtpH265PayClass * klass) gst_element_class_set_static_metadata (gstelement_class, "RTP H265 payloader", "Codec/Payloader/Network/RTP", - "Payload-encode H265 video into RTP packets (based on draft-ietf-payload-rtp-h265-03.txt)", + "Payload-encode H265 video into RTP packets (RFC 7798)", "Jurgen Slowack "); gstelement_class->change_state = @@ -186,7 +185,6 @@ static void gst_rtp_h265_pay_init (GstRtpH265Pay * rtph265pay) { rtph265pay->queue = g_array_new (FALSE, FALSE, sizeof (guint)); - rtph265pay->profile = 0; rtph265pay->sps = g_ptr_array_new_with_free_func ( (GDestroyNotify) gst_buffer_unref); rtph265pay->pps = g_ptr_array_new_with_free_func ( @@ -241,6 +239,32 @@ static const gchar all_levels[][4] = { "6.2" }; +static gboolean +parse_field (GstStructure * s, const gchar * field, gulong min, gulong max, + guint8 * result) +{ + const gchar *str; + + g_assert (result != NULL); + + str = gst_structure_get_string (s, field); + if (str != NULL && *str != '\0') { + gulong value; + gchar *end; + + value = strtoul (str, &end, 10); + if (*end == '\0' && value >= min && value <= max) { + *result = (guint8) value; + } else { + return FALSE; + } + } else { + return FALSE; + } + + return TRUE; +} + static GstCaps * gst_rtp_h265_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, GstCaps * filter) @@ -249,7 +273,6 @@ gst_rtp_h265_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, GstCaps *allowed_caps; GstCaps *caps; GstCaps *icaps; - gboolean append_unrestricted; guint i; allowed_caps = @@ -272,54 +295,48 @@ gst_rtp_h265_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, } caps = gst_caps_new_empty (); - - append_unrestricted = FALSE; for (i = 0; i < gst_caps_get_size (allowed_caps); i++) { GstStructure *s = gst_caps_get_structure (allowed_caps, i); GstStructure *new_s = gst_structure_new_empty ("video/x-h265"); - const gchar *profile_level_id; + guint8 ptl[12] = { 0, }; + guint8 value; - profile_level_id = gst_structure_get_string (s, "profile-level-id"); - - if (profile_level_id && strlen (profile_level_id) == 6) { /* Code taken from gstrtph264pay.c, needs to be revised for H.265 */ + if (parse_field (s, "profile-id", 0, 31, &value)) { const gchar *profile; + + ptl[0] = value; + profile = gst_codec_utils_h265_get_profile (ptl, sizeof (ptl)); + if (profile != NULL) { + GST_DEBUG_OBJECT (payload, "profile %s", profile); + gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL); + } else { + GST_WARNING_OBJECT (payload, "invalid profile-id %d in caps", value); + } + } else { + GST_DEBUG_OBJECT (payload, "no valid profile-id in caps"); + } + + if (parse_field (s, "tier-flag", 0, 1, &value)) { + const gchar *tier; + + ptl[0] |= value << 5; + tier = gst_codec_utils_h265_get_tier (ptl, sizeof (ptl)); + GST_DEBUG_OBJECT (payload, "tier %s", tier); + gst_structure_set (new_s, "tier", G_TYPE_STRING, tier, NULL); + } else { + GST_DEBUG_OBJECT (payload, "no valid tier-flag in caps"); + } + + if (parse_field (s, "level-id", 0, 255, &value)) { const gchar *level; - long int spsint; - guint8 sps[3]; - spsint = strtol (profile_level_id, NULL, 16); - sps[0] = spsint >> 16; - sps[1] = spsint >> 8; - sps[2] = spsint; - - profile = gst_codec_utils_h265_get_profile (sps, 3); - level = gst_codec_utils_h265_get_level (sps, 3); - - if (profile && level) { - GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s", - profile, level); - - if (!strcmp (profile, "main")) - gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL); - else { - GValue val = { 0, }; - GValue profiles = { 0, }; - - g_value_init (&profiles, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_STRING); - - g_value_set_static_string (&val, profile); - gst_value_list_append_value (&profiles, &val); - - g_value_set_static_string (&val, "main"); - gst_value_list_append_value (&profiles, &val); - - gst_structure_take_value (new_s, "profile", &profiles); - } - - if (!strcmp (level, "1")) + ptl[11] = value; + level = gst_codec_utils_h265_get_level (ptl, sizeof (ptl)); + if (level != NULL) { + GST_DEBUG_OBJECT (payload, "level %s", level); + if (strcmp (level, "1") == 0) { gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL); - else { + } else { GValue levels = { 0, }; GValue val = { 0, }; int j; @@ -336,26 +353,15 @@ gst_rtp_h265_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, gst_structure_take_value (new_s, "level", &levels); } } else { - /* Invalid profile-level-id means main */ - - gst_structure_set (new_s, "profile", G_TYPE_STRING, "main", NULL); + GST_WARNING_OBJECT (payload, "invalid level-id %d in caps", value); } } else { - /* No profile-level-id means main or unrestricted */ - - gst_structure_set (new_s, "profile", G_TYPE_STRING, "main", NULL); - append_unrestricted = TRUE; + GST_DEBUG_OBJECT (payload, "no valid level-id in caps"); } caps = gst_caps_merge_structure (caps, new_s); } - if (append_unrestricted) { - caps = - gst_caps_merge_structure (caps, gst_structure_new ("video/x-h265", NULL, - NULL)); - } - icaps = gst_caps_intersect (caps, template_caps); gst_caps_unref (caps); caps = icaps; @@ -369,27 +375,26 @@ done: return caps; } -/* take the currently configured VPS, SPS and PPS lists and set them on the caps as - * sprop-parameter-sets */ +/* take the currently configured VPS, SPS and PPS lists and set them on the + * caps */ static gboolean gst_rtp_h265_pay_set_vps_sps_pps (GstRTPBasePayload * basepayload) { GstRtpH265Pay *payloader = GST_RTP_H265_PAY (basepayload); - gchar *profile; gchar *set; - GString *sprops; + GString *vps; + GString *sps; + GString *pps; guint count; gboolean res; GstMapInfo map; guint i; - sprops = g_string_new (""); + vps = g_string_new (""); + sps = g_string_new (""); + pps = g_string_new (""); count = 0; - GST_DEBUG_OBJECT (payloader, - "Entering function gst_rtp_h265_pay_set_vps_sps_pps"); - - /* build the sprop-parameter-sets */ for (i = 0; i < payloader->vps->len; i++) { GstBuffer *vps_buf = GST_BUFFER_CAST (g_ptr_array_index (payloader->vps, i)); @@ -398,7 +403,7 @@ gst_rtp_h265_pay_set_vps_sps_pps (GstRTPBasePayload * basepayload) set = g_base64_encode (map.data, map.size); gst_buffer_unmap (vps_buf, &map); - g_string_append_printf (sprops, "%s%s", count ? "," : "", set); + g_string_append_printf (vps, "%s%s", i ? "," : "", set); g_free (set); count++; } @@ -410,7 +415,7 @@ gst_rtp_h265_pay_set_vps_sps_pps (GstRTPBasePayload * basepayload) set = g_base64_encode (map.data, map.size); gst_buffer_unmap (sps_buf, &map); - g_string_append_printf (sprops, "%s%s", count ? "," : "", set); + g_string_append_printf (sps, "%s%s", i ? "," : "", set); g_free (set); count++; } @@ -422,22 +427,23 @@ gst_rtp_h265_pay_set_vps_sps_pps (GstRTPBasePayload * basepayload) set = g_base64_encode (map.data, map.size); gst_buffer_unmap (pps_buf, &map); - g_string_append_printf (sprops, "%s%s", count ? "," : "", set); + g_string_append_printf (pps, "%s%s", i ? "," : "", set); g_free (set); count++; } if (G_LIKELY (count)) { - /* profile is 24 bit. Force it to respect the limit */ - profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff); /* combine into output caps */ res = gst_rtp_base_payload_set_outcaps (basepayload, - "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL); - g_free (profile); + "sprop-vps", G_TYPE_STRING, vps->str, + "sprop-sps", G_TYPE_STRING, sps->str, + "sprop-pps", G_TYPE_STRING, pps->str, NULL); } else { res = gst_rtp_base_payload_set_outcaps (basepayload, NULL); } - g_string_free (sprops, TRUE); + g_string_free (vps, TRUE); + g_string_free (sps, TRUE); + g_string_free (pps, TRUE); return res; } @@ -505,8 +511,7 @@ gst_rtp_h265_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps) goto wrong_version; /* profile_space | tier_flag | profile_idc */ - rtph265pay->profile = data[1]; - GST_DEBUG_OBJECT (rtph265pay, "profile %06x", rtph265pay->profile); + GST_DEBUG_OBJECT (rtph265pay, "profile %06x", data[1]); /* profile_compatibility_flags */ for (i = 2; i < 6; i++) { @@ -773,7 +778,7 @@ gst_rtp_h265_pay_decode_nal (GstRtpH265Pay * payloader, /* encode the entire NAL in base64 */ GST_DEBUG_OBJECT (payloader, "found %s (type 0x%x), size %u", type == GST_H265_NAL_VPS ? "VPS" : type == GST_H265_NAL_SPS ? - "SPS" : "PPS", type, size); + "SPS" : "PPS", type, size); nal = gst_buffer_new_allocate (NULL, size, NULL); gst_buffer_fill (nal, 0, data, size); @@ -1189,7 +1194,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, GST_DEBUG_OBJECT (basepayload, "found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size); - /* first pass to locate NALs and parse SPS/PPS */ + /* first pass to locate NALs and parse VPS/SPS/PPS */ while (size > 4) { /* skip start code */ data += 3; @@ -1217,10 +1222,9 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, nal_len); /* We know our stream is a valid H265 NAL packet, - * go parse it for SPS/PPS to enrich the caps */ + * go parse it for VPS/SPS/PPS to enrich the caps */ /* order: make sure to check nal */ - update = - gst_rtp_h265_pay_decode_nal (rtph265pay, data, nal_len, dts, pts) + update = gst_rtp_h265_pay_decode_nal (rtph265pay, data, nal_len, dts, pts) || update; /* move to next NAL packet */ diff --git a/gst/rtp/gstrtph265pay.h b/gst/rtp/gstrtph265pay.h index 9e6bb29f54..cd42fbad3e 100644 --- a/gst/rtp/gstrtph265pay.h +++ b/gst/rtp/gstrtph265pay.h @@ -51,7 +51,6 @@ struct _GstRtpH265Pay { GstRTPBasePayload payload; - guint profile; GPtrArray *sps, *pps, *vps; GstH265StreamFormat stream_format; diff --git a/tests/check/elements/rtp-payloading.c b/tests/check/elements/rtp-payloading.c index 2eea4a9333..1f864a6f24 100644 --- a/tests/check/elements/rtp-payloading.c +++ b/tests/check/elements/rtp-payloading.c @@ -60,6 +60,7 @@ rtp_pipeline_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list) * Count the size of the payload in the buffer list. */ len = gst_buffer_list_length (list); + GST_LOG ("list length %u", len); /* Loop through all groups */ for (i = 0; i < len; i++) { @@ -69,12 +70,14 @@ rtp_pipeline_chain_list (GstPad * pad, GstObject * parent, GstBufferList * list) paybuf = gst_buffer_list_get (list, i); /* only count real data which is expected in last memory block */ + GST_LOG ("n_memory %d", gst_buffer_n_memory (paybuf)); fail_unless (gst_buffer_n_memory (paybuf) > 1); mem = gst_buffer_get_memory_range (paybuf, gst_buffer_n_memory (paybuf) - 1, 1); size = gst_memory_get_sizes (mem, NULL, NULL); gst_memory_unref (mem); chain_list_bytes_received += size; + GST_LOG ("size %d, total %u", size, chain_list_bytes_received); } gst_buffer_list_unref (list); @@ -752,6 +755,157 @@ GST_START_TEST (rtp_h264_list_gt_mtu_avc) GST_END_TEST; +static const guint8 rtp_h265_frame_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static int rtp_h265_frame_data_size = 20; + +static int rtp_h265_frame_count = 1; + +GST_START_TEST (rtp_h265) +{ + rtp_pipeline_test (rtp_h265_frame_data, rtp_h265_frame_data_size, + rtp_h265_frame_count, + "video/x-h265,stream-format=(string)byte-stream,alignment=(string)nal", + "rtph265pay", "rtph265depay", 0, 0, FALSE); + + /* config-interval property used to be of uint type, was changed to int, + * make sure old GValue stuff still works */ + { + GValue val = G_VALUE_INIT; + GstElement *rtph265pay; + GParamSpec *pspec; + + + rtph265pay = gst_element_factory_make ("rtph265pay", NULL); + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (rtph265pay), + "config-interval"); + fail_unless (pspec->value_type == G_TYPE_INT); + g_value_init (&val, G_TYPE_UINT); + g_value_set_uint (&val, 10); + g_object_set_property (G_OBJECT (rtph265pay), "config-interval", &val); + g_value_set_uint (&val, 0); + g_object_get_property (G_OBJECT (rtph265pay), "config-interval", &val); + fail_unless_equals_int (10, g_value_get_uint (&val)); + g_object_set (G_OBJECT (rtph265pay), "config-interval", -1, NULL); + g_object_get_property (G_OBJECT (rtph265pay), "config-interval", &val); + fail_unless (g_value_get_uint (&val) == G_MAXUINT); + g_value_unset (&val); + gst_object_unref (rtph265pay); + } +} + +GST_END_TEST; +static const guint8 rtp_h265_list_lt_mtu_frame_data[] = { + /* not packetized, next NALU starts with 0x00000001 */ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 +}; + +static int rtp_h265_list_lt_mtu_frame_data_size = 16; + +static int rtp_h265_list_lt_mtu_frame_count = 2; + +/* 3 bytes start code prefixed with one zero byte, NALU header is in payload */ +static int rtp_h265_list_lt_mtu_bytes_sent = 2 * (16 - 3 - 1); + +static int rtp_h265_list_lt_mtu_mtu_size = 1024; + +GST_START_TEST (rtp_h265_list_lt_mtu) +{ + rtp_pipeline_test (rtp_h265_list_lt_mtu_frame_data, + rtp_h265_list_lt_mtu_frame_data_size, rtp_h265_list_lt_mtu_frame_count, + "video/x-h265,stream-format=(string)byte-stream,alignment=(string)nal", + "rtph265pay", "rtph265depay", rtp_h265_list_lt_mtu_bytes_sent, + rtp_h265_list_lt_mtu_mtu_size, TRUE); +} + +GST_END_TEST; +static const guint8 rtp_h265_list_lt_mtu_frame_data_hvc1[] = { + /* packetized data */ + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, +}; + +/* length size is 3 bytes */ +static int rtp_h265_list_lt_mtu_bytes_sent_hvc1 = 2 * (16 - 2 * 3); + + +GST_START_TEST (rtp_h265_list_lt_mtu_hvc1) +{ + rtp_pipeline_test (rtp_h265_list_lt_mtu_frame_data_hvc1, + rtp_h265_list_lt_mtu_frame_data_size, rtp_h265_list_lt_mtu_frame_count, + "video/x-h265,stream-format=(string)hvc1,alignment=(string)au," + "codec_data=(buffer)01640032ffe1002a67640032ac1b1a80a03dff016e02020280000" + "003008000000a74300018fff5de5c68600031ffebbcb85001000468ee3830", + "rtph265pay", "rtph265depay", rtp_h265_list_lt_mtu_bytes_sent_hvc1, + rtp_h265_list_lt_mtu_mtu_size, TRUE); +} + +GST_END_TEST; +static const guint8 rtp_h265_list_gt_mtu_frame_data[] = { + /* not packetized, next NAL starts with 0x000001 */ + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10 +}; + +static const int const rtp_h265_list_gt_mtu_frame_data_size = 62; + +static const int rtp_h265_list_gt_mtu_frame_count = 1; + +/* start code is 3 bytes, NALU header is 2 bytes */ +static int rtp_h265_list_gt_mtu_bytes_sent = 1 * (62 - 3 - 2); + +static int rtp_h265_list_gt_mtu_mtu_size = 28; + +GST_START_TEST (rtp_h265_list_gt_mtu) +{ + rtp_pipeline_test (rtp_h265_list_gt_mtu_frame_data, + rtp_h265_list_gt_mtu_frame_data_size, rtp_h265_list_gt_mtu_frame_count, + "video/x-h265,stream-format=(string)byte-stream,alignment=(string)nal", + "rtph265pay", "rtph265depay", rtp_h265_list_gt_mtu_bytes_sent, + rtp_h265_list_gt_mtu_mtu_size, TRUE); +} + +GST_END_TEST; +static const guint8 rtp_h265_list_gt_mtu_frame_data_hvc1[] = { + /* packetized data */ + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* length size is 3 bytes, NALU header is 2 bytes */ +static int rtp_h265_list_gt_mtu_bytes_sent_hvc1 = 1 * (62 - 2 * 3 - 2 * 2); + +GST_START_TEST (rtp_h265_list_gt_mtu_hvc1) +{ + rtp_pipeline_test (rtp_h265_list_gt_mtu_frame_data_hvc1, + rtp_h265_list_gt_mtu_frame_data_size, rtp_h265_list_gt_mtu_frame_count, + "video/x-h265,stream-format=(string)hvc1,alignment=(string)au," + "codec_data=(buffer)01640032ffe1002a67640032ac1b1a80a03dff016e02020280000" + "003008000000a74300018fff5de5c68600031ffebbcb85001000468ee3830", + "rtph265pay", "rtph265depay", rtp_h265_list_gt_mtu_bytes_sent_hvc1, + rtp_h265_list_gt_mtu_mtu_size, TRUE); +} + +GST_END_TEST; + /* KLV data from Day_Flight.mpg */ static const guint8 rtp_KLV_frame_data[] = { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x0b, 0x01, 0x01, @@ -1200,6 +1354,11 @@ rtp_payloading_suite (void) tcase_add_test (tc_chain, rtp_h264_list_lt_mtu_avc); tcase_add_test (tc_chain, rtp_h264_list_gt_mtu); tcase_add_test (tc_chain, rtp_h264_list_gt_mtu_avc); + tcase_add_test (tc_chain, rtp_h265); + tcase_add_test (tc_chain, rtp_h265_list_lt_mtu); + tcase_add_test (tc_chain, rtp_h265_list_lt_mtu_hvc1); + tcase_add_test (tc_chain, rtp_h265_list_gt_mtu); + tcase_add_test (tc_chain, rtp_h265_list_gt_mtu_hvc1); tcase_add_test (tc_chain, rtp_klv); tcase_add_test (tc_chain, rtp_klv_fragmented); tcase_add_test (tc_chain, rtp_L16);