mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-03 14:08:56 +00:00
rtph264pay: Handle 'profile' field
In order to allow "level-asymmetry-allowed" we now handle a new "profile" field, which as the same semantics as the "profile" field in H.264 stream so that we can force payloaded stream to have the right format when using the `gst_sdp_media_get_caps_from_media` to set caps filter after the payloader. This allows a simple negotiation in standard RTP negotiation based on SDPs (like webrtc) for that particular case, closely respecting the specs. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1410>
This commit is contained in:
parent
9ac502c21d
commit
49055f1cd5
7 changed files with 70 additions and 22 deletions
|
@ -944,6 +944,8 @@ validate.test.mp4.redirect.play_15s
|
||||||
validate.test.nle.urisource.play
|
validate.test.nle.urisource.play
|
||||||
validate.test.playbin.check_active_stream
|
validate.test.playbin.check_active_stream
|
||||||
validate.test.playbin3.sourcebin_check_mixed_static_and_dyanmic_pads
|
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_recv_simple
|
||||||
validate.test.rtp.rtpsession_send_simple
|
validate.test.rtp.rtpsession_send_simple
|
||||||
validate.test.scaletempo.playbin_audio_filter.fast_forward
|
validate.test.scaletempo.playbin_audio_filter.fast_forward
|
||||||
|
|
|
@ -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.*",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}\"",
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -223,7 +223,7 @@ static void
|
||||||
gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
|
gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
|
||||||
{
|
{
|
||||||
rtph264pay->queue = g_array_new (FALSE, FALSE, sizeof (guint));
|
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 (
|
rtph264pay->sps = g_ptr_array_new_with_free_func (
|
||||||
(GDestroyNotify) gst_buffer_unref);
|
(GDestroyNotify) gst_buffer_unref);
|
||||||
rtph264pay->pps = g_ptr_array_new_with_free_func (
|
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++) {
|
for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
|
||||||
GstStructure *s = gst_caps_get_structure (allowed_caps, i);
|
GstStructure *s = gst_caps_get_structure (allowed_caps, i);
|
||||||
GstStructure *new_s = gst_structure_new_empty ("video/x-h264");
|
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");
|
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",
|
GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
|
||||||
profile, level);
|
profile, level);
|
||||||
|
|
||||||
if (!strcmp (profile, "constrained-baseline"))
|
if (!strcmp (profile, "constrained-baseline")) {
|
||||||
gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
|
gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
|
||||||
else {
|
} else {
|
||||||
GValue val = { 0, };
|
GValue val = { 0, };
|
||||||
GValue profiles = { 0, };
|
GValue profiles = { 0, };
|
||||||
|
|
||||||
|
@ -385,6 +385,8 @@ gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
|
||||||
gst_structure_set (new_s,
|
gst_structure_set (new_s,
|
||||||
"profile", G_TYPE_STRING, "constrained-baseline", NULL);
|
"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 {
|
} else {
|
||||||
/* No profile-level-id means baseline or unrestricted */
|
/* 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);
|
return gst_pad_query_default (pad, parent, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* take the currently configured SPS and PPS lists and set them on the caps as
|
/* take the currently configured SPS and PPS lists and set them on the caps as
|
||||||
* sprop-parameter-sets */
|
* sprop-parameter-sets */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
|
gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
|
||||||
{
|
{
|
||||||
|
GstStructure *s = gst_structure_new_empty ("unused");
|
||||||
GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
|
GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
|
||||||
gchar *profile;
|
|
||||||
gchar *set;
|
gchar *set;
|
||||||
GString *sprops;
|
GString *sprops;
|
||||||
guint count;
|
guint count;
|
||||||
|
@ -502,24 +503,34 @@ gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (G_LIKELY (count)) {
|
if (G_LIKELY (count)) {
|
||||||
if (payloader->profile != 0) {
|
gchar *profile_level;
|
||||||
/* profile is 24 bit. Force it to respect the limit */
|
|
||||||
profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
|
gst_structure_set (s,
|
||||||
/* combine into output caps */
|
"packetization-mode", G_TYPE_STRING, "1",
|
||||||
res = gst_rtp_base_payload_set_outcaps (basepayload,
|
"sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
|
||||||
"packetization-mode", G_TYPE_STRING, "1",
|
|
||||||
"profile-level-id", G_TYPE_STRING, profile,
|
if (payloader->profile_level != 0) {
|
||||||
"sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
|
guint8 sps[2] = {
|
||||||
g_free (profile);
|
payloader->profile_level >> 16,
|
||||||
} else {
|
payloader->profile_level >> 8,
|
||||||
res = gst_rtp_base_payload_set_outcaps (basepayload,
|
};
|
||||||
"packetization-mode", G_TYPE_STRING, "1",
|
|
||||||
"sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
|
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 {
|
} else {
|
||||||
res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
|
res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
|
||||||
}
|
}
|
||||||
|
gst_structure_free (s);
|
||||||
g_string_free (sprops, TRUE);
|
g_string_free (sprops, TRUE);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -591,8 +602,8 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
|
||||||
/* AVCProfileIndication */
|
/* AVCProfileIndication */
|
||||||
/* profile_compat */
|
/* profile_compat */
|
||||||
/* AVCLevelIndication */
|
/* AVCLevelIndication */
|
||||||
rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3];
|
rtph264pay->profile_level = (data[1] << 16) | (data[2] << 8) | data[3];
|
||||||
GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile);
|
GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile_level);
|
||||||
|
|
||||||
/* 6 bits reserved | 2 bits lengthSizeMinusOne */
|
/* 6 bits reserved | 2 bits lengthSizeMinusOne */
|
||||||
/* this is the number of bytes in front of the NAL units to mark their
|
/* this is the number of bytes in front of the NAL units to mark their
|
||||||
|
|
|
@ -65,7 +65,7 @@ struct _GstRtpH264Pay
|
||||||
{
|
{
|
||||||
GstRTPBasePayload payload;
|
GstRTPBasePayload payload;
|
||||||
|
|
||||||
guint profile;
|
guint profile_level;
|
||||||
GPtrArray *sps, *pps;
|
GPtrArray *sps, *pps;
|
||||||
|
|
||||||
GstH264StreamFormat stream_format;
|
GstH264StreamFormat stream_format;
|
||||||
|
|
Loading…
Reference in a new issue