From 3dca756a5dba55266256f239e3e12a3d058e185a Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Wed, 22 May 2013 03:09:44 +0200 Subject: [PATCH] rtph264pay/depay: Add frame dimensions a payloaded caps This allows for applications to format SDP attributes and still do SDP offer/answer based on caps negotiation. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=700749 --- gst/rtp/gstrtph264depay.c | 36 +++++++++++++++++++++++++-- gst/rtp/gstrtph264depay.h | 2 ++ gst/rtp/gstrtph264pay.c | 29 +++++++++++++++++---- tests/check/elements/rtp-payloading.c | 27 +++++++++++--------- 4 files changed, 75 insertions(+), 19 deletions(-) diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c index 64f8c8e66c..198d1de6ba 100644 --- a/gst/rtp/gstrtph264depay.c +++ b/gst/rtp/gstrtph264depay.c @@ -45,8 +45,14 @@ static GstStaticPadTemplate gst_rtp_h264_depay_src_template = GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-h264, " "stream-format = (string) avc, alignment = (string) au; " + /** optional parameters **/ + /* "width = (int) [ 1, MAX ], " */ + /* "height = (int) [ 1, MAX ], " */ "video/x-h264, " "stream-format = (string) byte-stream, alignment = (string) { nal, au }") + /** optional parameters **/ + /* "width = (int) [ 1, MAX ], " */ + /* "height = (int) [ 1, MAX ], " */ ); static GstStaticPadTemplate gst_rtp_h264_depay_sink_template = @@ -55,7 +61,8 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("application/x-rtp, " "media = (string) \"video\", " - "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"") + "clock-rate = (int) 90000, " + "encoding-name = (string) \"H264\"") /** optional parameters **/ /* "profile-level-id = (string) ANY, " */ /* "max-mbps = (string) ANY, " */ @@ -72,7 +79,9 @@ GST_STATIC_PAD_TEMPLATE ("sink", /* "deint-buf-cap = (string) ANY, " */ /* "sprop-init-buf-time = (string) ANY, " */ /* "sprop-max-don-diff = (string) ANY, " */ - /* "max-rcmd-nalu-size = (string) ANY " */ + /* "max-rcmd-nalu-size = (string) ANY, " */ + /* "width = (int) [ 1, MAX ], " */ + /* "height = (int) [ 1, MAX ], " */ ); #define gst_rtp_h264_depay_parent_class parent_class @@ -147,6 +156,8 @@ gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay) rtph264depay->last_ts = 0; rtph264depay->current_fu_type = 0; rtph264depay->new_codec_data = FALSE; + rtph264depay->width = 0; + rtph264depay->height = 0; g_ptr_array_set_size (rtph264depay->sps, 0); g_ptr_array_set_size (rtph264depay->pps, 0); } @@ -305,6 +316,11 @@ gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay) rtph264depay->byte_stream ? "byte-stream" : "avc", "alignment", G_TYPE_STRING, rtph264depay->merge ? "au" : "nal", NULL); + if (rtph264depay->width > 0 && rtph264depay->height > 0) { + gst_caps_set_simple (srccaps, "width", G_TYPE_INT, rtph264depay->width, + "height", G_TYPE_INT, rtph264depay->height, NULL); + } + if (!rtph264depay->byte_stream) { GstBuffer *codec_data; GstMapInfo map; @@ -519,6 +535,7 @@ gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) GstBuffer *codec_data; GstMapInfo map; guint8 *ptr; + gint width = 0, height = 0; rtph264depay = GST_RTP_H264_DEPAY (depayload); @@ -618,6 +635,16 @@ gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) goto incomplete_caps; } + if (gst_structure_get_int (structure, "width", &width) && width <= 0) { + goto invalid_dimension; + } + if (gst_structure_get_int (structure, "height", &height) && height <= 0) { + goto invalid_dimension; + } + + rtph264depay->width = width; + rtph264depay->height = height; + return gst_rtp_h264_set_src_caps (rtph264depay); /* ERRORS */ @@ -627,6 +654,11 @@ incomplete_caps: " doing setcaps later"); return TRUE; } +invalid_dimension: + { + GST_ERROR_OBJECT (depayload, "invalid width/height from caps"); + return FALSE; + } } static GstBuffer * diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h index e178dcf6d9..c62625bd68 100644 --- a/gst/rtp/gstrtph264depay.h +++ b/gst/rtp/gstrtph264depay.h @@ -66,6 +66,8 @@ struct _GstRtpH264Depay GPtrArray *sps; GPtrArray *pps; gboolean new_codec_data; + gint width; + gint height; }; struct _GstRtpH264DepayClass diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c index 4e4621ce15..14d113fe0c 100644 --- a/gst/rtp/gstrtph264pay.c +++ b/gst/rtp/gstrtph264pay.c @@ -47,9 +47,11 @@ static GstStaticPadTemplate gst_rtp_h264_pay_sink_template = GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-h264, " - "stream-format = (string) avc, alignment = (string) au;" + "stream-format = (string) avc, alignment = (string) au, " + "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]; " "video/x-h264, " - "stream-format = (string) byte-stream, alignment = (string) { nal, au }") + "stream-format = (string) byte-stream, alignment = (string) { nal, au }, " + "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]") ); static GstStaticPadTemplate gst_rtp_h264_pay_src_template = @@ -59,7 +61,9 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_CAPS ("application/x-rtp, " "media = (string) \"video\", " "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " - "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"") + "clock-rate = (int) 90000, " + "encoding-name = (string) \"H264\", " + "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]") ); #define DEFAULT_SPROP_PARAMETER_SETS NULL @@ -426,6 +430,7 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps) const gchar *alignment, *stream_format; gchar *sprops; gboolean caps_set; + gint width, height; rtph264pay = GST_RTP_H264_PAY (basepayload); @@ -453,6 +458,13 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps) rtph264pay->stream_format = GST_H264_STREAM_FORMAT_BYTESTREAM; } + if (!gst_structure_get_int (str, "height", &height) || height <= 0) { + goto invalid_dimension; + } + if (!gst_structure_get_int (str, "width", &width) || width <= 0) { + goto invalid_dimension; + } + /* packetized AVC video has a codec_data */ if ((value = gst_structure_get_value (str, "codec_data"))) { guint num_sps, num_pps; @@ -558,10 +570,12 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps) } if (sprops != NULL) { - caps_set = gst_rtp_base_payload_set_outcaps (basepayload, + caps_set = gst_rtp_base_payload_set_outcaps (basepayload, "width", + G_TYPE_INT, width, "height", G_TYPE_INT, height, "sprop-parameter-sets", G_TYPE_STRING, sprops, NULL); } else { - caps_set = gst_rtp_base_payload_set_outcaps (basepayload, NULL); + caps_set = gst_rtp_base_payload_set_outcaps (basepayload, "width", + G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); } if (sprops != NULL) { @@ -594,6 +608,11 @@ set_caps_failed: GST_ERROR_OBJECT (rtph264pay, "failed to set caps"); return FALSE; } +invalid_dimension: + { + GST_ERROR_OBJECT (rtph264pay, "invalid width/height from caps"); + return FALSE; + } error: { gst_buffer_unmap (buffer, &map); diff --git a/tests/check/elements/rtp-payloading.c b/tests/check/elements/rtp-payloading.c index 63db391ba4..3de1f91362 100644 --- a/tests/check/elements/rtp-payloading.c +++ b/tests/check/elements/rtp-payloading.c @@ -519,8 +519,9 @@ GST_START_TEST (rtp_h264) /* FIXME 0.11: fully specify h264 caps (and make payloader check) */ rtp_pipeline_test (rtp_h264_frame_data, rtp_h264_frame_data_size, rtp_h264_frame_count, - "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal", - "rtph264pay", "rtph264depay", 0, 0, FALSE); + "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal," + "width=(int)320,height=(int)240", "rtph264pay", "rtph264depay", 0, 0, + FALSE); } GST_END_TEST; @@ -546,8 +547,8 @@ GST_START_TEST (rtp_h264_list_lt_mtu) /* FIXME 0.11: fully specify h264 caps (and make payloader check) */ rtp_pipeline_test (rtp_h264_list_lt_mtu_frame_data, rtp_h264_list_lt_mtu_frame_data_size, rtp_h264_list_lt_mtu_frame_count, - "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal", - "rtph264pay", "rtph264depay", + "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal," + "width=(int)320,height=(int)240", "rtph264pay", "rtph264depay", rtp_h264_list_lt_mtu_bytes_sent, rtp_h264_list_lt_mtu_mtu_size, TRUE); } @@ -570,9 +571,10 @@ GST_START_TEST (rtp_h264_list_lt_mtu_avc) rtp_pipeline_test (rtp_h264_list_lt_mtu_frame_data_avc, rtp_h264_list_lt_mtu_frame_data_size, rtp_h264_list_lt_mtu_frame_count, "video/x-h264,stream-format=(string)avc,alignment=(string)au," - "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c", - "rtph264pay", "rtph264depay", - rtp_h264_list_lt_mtu_bytes_sent_avc, rtp_h264_list_lt_mtu_mtu_size, TRUE); + "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c," + "width=(int)320,height=(int)240,framerate=(fraction)30/1", "rtph264pay", + "rtph264depay", rtp_h264_list_lt_mtu_bytes_sent_avc, + rtp_h264_list_lt_mtu_mtu_size, TRUE); } GST_END_TEST; @@ -600,8 +602,8 @@ GST_START_TEST (rtp_h264_list_gt_mtu) /* FIXME 0.11: fully specify h264 caps (and make payloader check) */ rtp_pipeline_test (rtp_h264_list_gt_mtu_frame_data, rtp_h264_list_gt_mtu_frame_data_size, rtp_h264_list_gt_mtu_frame_count, - "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal", - "rtph264pay", "rtph264depay", + "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal," + "width=(int)320,height=(int)240", "rtph264pay", "rtph264depay", rtp_h264_list_gt_mtu_bytes_sent, rtp_h264_list_gt_mtu_mty_size, TRUE); } @@ -625,9 +627,10 @@ GST_START_TEST (rtp_h264_list_gt_mtu_avc) rtp_pipeline_test (rtp_h264_list_gt_mtu_frame_data_avc, rtp_h264_list_gt_mtu_frame_data_size, rtp_h264_list_gt_mtu_frame_count, "video/x-h264,stream-format=(string)avc,alignment=(string)au," - "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c", - "rtph264pay", "rtph264depay", - rtp_h264_list_gt_mtu_bytes_sent_avc, rtp_h264_list_gt_mtu_mty_size, TRUE); + "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c," + "width=(int)320,height=(int)240,framerate=(fraction)30/1" , "rtph264pay", + "rtph264depay", rtp_h264_list_gt_mtu_bytes_sent_avc, + rtp_h264_list_gt_mtu_mty_size, TRUE); } GST_END_TEST;