diff --git a/subprojects/gst-integration-testsuites/testsuites/validate.testslist b/subprojects/gst-integration-testsuites/testsuites/validate.testslist index a78f21da90..bf5d235c83 100644 --- a/subprojects/gst-integration-testsuites/testsuites/validate.testslist +++ b/subprojects/gst-integration-testsuites/testsuites/validate.testslist @@ -944,6 +944,8 @@ validate.test.mp4.redirect.play_15s validate.test.nle.urisource.play validate.test.playbin.check_active_stream validate.test.playbin3.sourcebin_check_mixed_static_and_dyanmic_pads +validate.test.rtp.h264.payloader_fail_nego_force_profile +validate.test.rtp.h264.payloader_nego_profile validate.test.rtp.rtpsession_recv_simple validate.test.rtp.rtpsession_send_simple validate.test.scaletempo.playbin_audio_filter.fast_forward diff --git a/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_fail_nego_force_profile.validatetest b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_fail_nego_force_profile.validatetest new file mode 100644 index 0000000000..a951c5c417 --- /dev/null +++ b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_fail_nego_force_profile.validatetest @@ -0,0 +1,16 @@ +meta, + args = { + "videotestsrc num-buffers=1 ! x264enc ! h264parse ! \ + video/x-h264,level=(string)4,profile=baseline ! rtph264pay name=pay ! \ + application/x-rtp,profile=constrained-baseline ! fakesink", + }, + expected-issues = { + [ + expected-issue, + level=critical, + issue-id=runtime::not-negotiated, + details=".*Field 'profile'.*can't intersect with filter value.*baseline.*", + ], + } + + diff --git a/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile.validatetest b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile.validatetest new file mode 100644 index 0000000000..195a343cc5 --- /dev/null +++ b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile.validatetest @@ -0,0 +1,13 @@ +meta, + args = { + "videotestsrc num-buffers=1 ! x264enc ! h264parse ! \ + video/x-h264,level=(string)4 ! rtph264pay name=pay ! \ + application/x-rtp,profile=constrained-baseline ! fakesink", + }, + configs = { + "$(validateflow), pad=pay:sink, ignored-event-types={tag, segment}, \ + logged-fields=\"caps={framerate, height, level, profile, stream-format, width}\"", + "$(validateflow), pad=pay:src, ignored-event-types={tag, segment}, \ + logged-fields=\"caps={a-framerate, clock-rate, encoding-name, media, packetization-mode, payload, profile, profile-level-id}\"", + } + diff --git a/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile/flow-expectations/log-pay-sink-expected b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile/flow-expectations/log-pay-sink-expected new file mode 100644 index 0000000000..5367ae3bf0 --- /dev/null +++ b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile/flow-expectations/log-pay-sink-expected @@ -0,0 +1,3 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event caps: video/x-h264, framerate=(fraction)30/1, height=(int)240, level=(string)4, profile=(string)constrained-baseline, stream-format=(string)avc, width=(int)320; +event eos: (no structure) diff --git a/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile/flow-expectations/log-pay-src-expected b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile/flow-expectations/log-pay-src-expected new file mode 100644 index 0000000000..4c18169f6c --- /dev/null +++ b/subprojects/gst-integration-testsuites/testsuites/validate/rtp/h264/payloader_nego_profile/flow-expectations/log-pay-src-expected @@ -0,0 +1,3 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event caps: application/x-rtp, a-framerate=(string)30, clock-rate=(int)90000, encoding-name=(string)H264, media=(string)video, packetization-mode=(string)1, payload=(int)96, profile=(string)constrained-baseline, profile-level-id=(string)42c028; +event eos: (no structure) diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.c index 49471d8678..5df5b8badc 100644 --- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.c +++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.c @@ -223,7 +223,7 @@ static void gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay) { rtph264pay->queue = g_array_new (FALSE, FALSE, sizeof (guint)); - rtph264pay->profile = 0; + rtph264pay->profile_level = 0; rtph264pay->sps = g_ptr_array_new_with_free_func ( (GDestroyNotify) gst_buffer_unref); rtph264pay->pps = g_ptr_array_new_with_free_func ( @@ -321,7 +321,7 @@ gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, 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-h264"); - const gchar *profile_level_id; + const gchar *profile_level_id, *profile; profile_level_id = gst_structure_get_string (s, "profile-level-id"); @@ -343,9 +343,9 @@ gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s", profile, level); - if (!strcmp (profile, "constrained-baseline")) + if (!strcmp (profile, "constrained-baseline")) { gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL); - else { + } else { GValue val = { 0, }; GValue profiles = { 0, }; @@ -385,6 +385,8 @@ gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad, gst_structure_set (new_s, "profile", G_TYPE_STRING, "constrained-baseline", NULL); } + } else if ((profile = gst_structure_get_string (s, "profile"))) { + gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL); } else { /* No profile-level-id means baseline or unrestricted */ @@ -457,14 +459,13 @@ gst_rtp_h264_pay_src_query (GstPad * pad, GstObject * parent, GstQuery * query) return gst_pad_query_default (pad, parent, query); } - /* take the currently configured SPS and PPS lists and set them on the caps as * sprop-parameter-sets */ static gboolean gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload) { + GstStructure *s = gst_structure_new_empty ("unused"); GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload); - gchar *profile; gchar *set; GString *sprops; guint count; @@ -502,24 +503,34 @@ gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload) } if (G_LIKELY (count)) { - if (payloader->profile != 0) { - /* 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, - "packetization-mode", G_TYPE_STRING, "1", - "profile-level-id", G_TYPE_STRING, profile, - "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL); - g_free (profile); - } else { - res = gst_rtp_base_payload_set_outcaps (basepayload, - "packetization-mode", G_TYPE_STRING, "1", - "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL); + gchar *profile_level; + + gst_structure_set (s, + "packetization-mode", G_TYPE_STRING, "1", + "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL); + + if (payloader->profile_level != 0) { + guint8 sps[2] = { + payloader->profile_level >> 16, + payloader->profile_level >> 8, + }; + + profile_level = + g_strdup_printf ("%06x", payloader->profile_level & 0xffffff); + gst_structure_set (s, + "profile-level-id", G_TYPE_STRING, profile_level, + "profile", G_TYPE_STRING, gst_codec_utils_h264_get_profile (sps, 2), + NULL); + + g_free (profile_level); } + /* combine into output caps */ + res = gst_rtp_base_payload_set_outcaps_structure (basepayload, s); } else { res = gst_rtp_base_payload_set_outcaps (basepayload, NULL); } + gst_structure_free (s); g_string_free (sprops, TRUE); return res; @@ -591,8 +602,8 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps) /* AVCProfileIndication */ /* profile_compat */ /* AVCLevelIndication */ - rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3]; - GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile); + rtph264pay->profile_level = (data[1] << 16) | (data[2] << 8) | data[3]; + GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile_level); /* 6 bits reserved | 2 bits lengthSizeMinusOne */ /* this is the number of bytes in front of the NAL units to mark their diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.h b/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.h index 47cc896e1d..c983a9251a 100644 --- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.h +++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264pay.h @@ -65,7 +65,7 @@ struct _GstRtpH264Pay { GstRTPBasePayload payload; - guint profile; + guint profile_level; GPtrArray *sps, *pps; GstH264StreamFormat stream_format;