rtph264pay/depay: Add optional framerate caps for use in SDP
authorSebastian Rasmussen <sebrn@axis.com>
Wed, 22 May 2013 01:18:07 +0000 (03:18 +0200)
committerSebastian Dröge <slomo@circular-chaos.org>
Thu, 23 May 2013 19:04:17 +0000 (21:04 +0200)
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
gst/rtp/gstrtph264depay.h
gst/rtp/gstrtph264pay.c

index 198d1de..8eb1ebb 100644 (file)
@@ -48,11 +48,13 @@ static GstStaticPadTemplate gst_rtp_h264_depay_src_template =
         /** optional parameters **/
     /* "width = (int) [ 1, MAX ], " */
     /* "height = (int) [ 1, MAX ], " */
+    /* "framerate = (fraction) [ 0/1, MAX/1 ], " */
         "video/x-h264, "
         "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
         /** optional parameters **/
     /* "width = (int) [ 1, MAX ], " */
     /* "height = (int) [ 1, MAX ], " */
+    /* "framerate = (fraction) [ 0/1, MAX/1 ], " */
     );
 
 static GstStaticPadTemplate gst_rtp_h264_depay_sink_template =
@@ -82,6 +84,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     /* "max-rcmd-nalu-size = (string) ANY, " */
     /* "width = (int) [ 1, MAX ], " */
     /* "height = (int) [ 1, MAX ], " */
+    /* "framerate = (fraction) [ 0/1, MAX/1 ] " */
     );
 
 #define gst_rtp_h264_depay_parent_class parent_class
@@ -158,6 +161,8 @@ gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay)
   rtph264depay->new_codec_data = FALSE;
   rtph264depay->width = 0;
   rtph264depay->height = 0;
+  rtph264depay->frate_num = 0;
+  rtph264depay->frate_denom = 1;
   g_ptr_array_set_size (rtph264depay->sps, 0);
   g_ptr_array_set_size (rtph264depay->pps, 0);
 }
@@ -321,6 +326,11 @@ gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay)
         "height", G_TYPE_INT, rtph264depay->height, NULL);
   }
 
+  if (rtph264depay->frate_num > 0) {
+    gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION,
+        rtph264depay->frate_num, rtph264depay->frate_denom, NULL);
+  }
+
   if (!rtph264depay->byte_stream) {
     GstBuffer *codec_data;
     GstMapInfo map;
@@ -536,6 +546,7 @@ gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
   GstMapInfo map;
   guint8 *ptr;
   gint width = 0, height = 0;
+  gint num = 0, denom = 1;
 
   rtph264depay = GST_RTP_H264_DEPAY (depayload);
 
@@ -642,8 +653,15 @@ gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
     goto invalid_dimension;
   }
 
+  if (gst_structure_get_fraction (structure, "framerate", &num, &denom) &&
+      (num < 0 || denom <= 0)) {
+    goto invalid_framerate;
+  }
+
   rtph264depay->width = width;
   rtph264depay->height = height;
+  rtph264depay->frate_num = num;
+  rtph264depay->frate_denom = denom;
 
   return gst_rtp_h264_set_src_caps (rtph264depay);
 
@@ -659,6 +677,11 @@ invalid_dimension:
     GST_ERROR_OBJECT (depayload, "invalid width/height from caps");
     return FALSE;
   }
+invalid_framerate:
+  {
+    GST_ERROR_OBJECT (depayload, "invalid framerate from caps");
+    return FALSE;
+  }
 }
 
 static GstBuffer *
index c62625b..ac805a4 100644 (file)
@@ -68,6 +68,8 @@ struct _GstRtpH264Depay
   gboolean new_codec_data;
   gint width;
   gint height;
+  gint frate_num;
+  gint frate_denom;
 };
 
 struct _GstRtpH264DepayClass
index 14d113f..96db611 100644 (file)
@@ -52,6 +52,8 @@ static GstStaticPadTemplate gst_rtp_h264_pay_sink_template =
         "video/x-h264, "
         "stream-format = (string) byte-stream, alignment = (string) { nal, au }, "
         "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]")
+        /** optional parameters **/
+    /* "framerate = (fraction) [ 0/1, MAX/1 ] " */
     );
 
 static GstStaticPadTemplate gst_rtp_h264_pay_src_template =
@@ -64,6 +66,8 @@ GST_STATIC_PAD_TEMPLATE ("src",
         "clock-rate = (int) 90000, "
         "encoding-name = (string) \"H264\", "
         "width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]")
+        /** optional parameters **/
+    /* "framerate = (fraction) [ 0/1, MAX/1 ] " */
     );
 
 #define DEFAULT_SPROP_PARAMETER_SETS    NULL
@@ -431,6 +435,7 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
   gchar *sprops;
   gboolean caps_set;
   gint width, height;
+  gint num = 0, denom = 1;
 
   rtph264pay = GST_RTP_H264_PAY (basepayload);
 
@@ -465,6 +470,11 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
     goto invalid_dimension;
   }
 
+  if (gst_structure_get_fraction (str, "framerate", &num, &denom) &&
+      (num < 0 || denom <= 0)) {
+    goto invalid_framerate;
+  }
+
   /* packetized AVC video has a codec_data */
   if ((value = gst_structure_get_value (str, "codec_data"))) {
     guint num_sps, num_pps;
@@ -569,10 +579,19 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
     sprops = NULL;
   }
 
-  if (sprops != NULL) {
+  if (num > 0 && sprops != NULL) {
+    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, "framerate",
+        GST_TYPE_FRACTION, num, denom, NULL);
+  } else if (num <= 0 && sprops != NULL) {
     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 if (num > 0 && sprops == NULL) {
+    caps_set = gst_rtp_base_payload_set_outcaps (basepayload, "width",
+        G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate",
+        GST_TYPE_FRACTION, num, denom, NULL);
   } else {
     caps_set = gst_rtp_base_payload_set_outcaps (basepayload, "width",
         G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
@@ -613,6 +632,11 @@ invalid_dimension:
     GST_ERROR_OBJECT (rtph264pay, "invalid width/height from caps");
     return FALSE;
   }
+invalid_framerate:
+  {
+    GST_ERROR_OBJECT (rtph264pay, "invalid framerate from caps");
+    return FALSE;
+  }
 error:
   {
     gst_buffer_unmap (buffer, &map);