rtpbasepayload: Implement video SDP attributes
authorSebastian Rasmussen <sebras@hotmail.com>
Sat, 15 Mar 2014 16:35:56 +0000 (17:35 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 2 Oct 2015 14:44:14 +0000 (17:44 +0300)
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=726472

gst-libs/gst/rtp/gstrtpbasepayload.c
tests/check/libs/rtpbasepayload.c

index 393d8c6..7efbf11 100644 (file)
@@ -60,6 +60,7 @@ struct _GstRTPBasePayloadPrivate
   GstEvent *pending_segment;
 
   GstCaps *subclass_srccaps;
+  GstCaps *sinkcaps;
 };
 
 /* RTPBasePayload signals and args */
@@ -403,6 +404,7 @@ gst_rtp_base_payload_finalize (GObject * object)
   rtpbasepayload->encoding_name = NULL;
 
   gst_caps_replace (&rtpbasepayload->priv->subclass_srccaps, NULL);
+  gst_caps_replace (&rtpbasepayload->priv->sinkcaps, NULL);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -450,6 +452,8 @@ gst_rtp_base_payload_sink_event_default (GstRTPBasePayload * rtpbasepayload,
       gst_event_parse_caps (event, &caps);
       GST_DEBUG_OBJECT (rtpbasepayload, "setting caps %" GST_PTR_FORMAT, caps);
 
+      gst_caps_replace (&rtpbasepayload->priv->sinkcaps, caps);
+
       rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload);
       if (rtpbasepayload_class->set_caps)
         res = rtpbasepayload_class->set_caps (rtpbasepayload, caps);
@@ -775,6 +779,7 @@ static gboolean
 gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload)
 {
   GstCaps *templ, *peercaps, *srccaps;
+  GstStructure *s, *d;
   gboolean res;
 
   payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
@@ -806,7 +811,6 @@ gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload)
     GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps);
   } else {
     GstCaps *temp;
-    GstStructure *s, *d;
     const GValue *value;
     gboolean have_pt = FALSE;
     gboolean have_ts_offset = FALSE;
@@ -1029,6 +1033,35 @@ gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload)
     GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps);
   }
 
+  if (payload->priv->sinkcaps != NULL) {
+    s = gst_caps_get_structure (payload->priv->sinkcaps, 0);
+    if (g_str_has_prefix (gst_structure_get_name (s), "video")) {
+      gboolean has_framerate;
+      gint num, denom;
+
+      GST_DEBUG_OBJECT (payload, "video caps: %" GST_PTR_FORMAT,
+          payload->priv->sinkcaps);
+
+      has_framerate = gst_structure_get_fraction (s, "framerate", &num, &denom);
+      if (has_framerate && num == 0 && denom == 1) {
+        has_framerate =
+            gst_structure_get_fraction (s, "max-framerate", &num, &denom);
+      }
+
+      if (has_framerate) {
+        gchar str[G_ASCII_DTOSTR_BUF_SIZE];
+        gdouble framerate;
+
+        gst_util_fraction_to_double (num, denom, &framerate);
+        g_ascii_dtostr (str, G_ASCII_DTOSTR_BUF_SIZE, framerate);
+        d = gst_caps_get_structure (srccaps, 0);
+        gst_structure_set (d, "a-framerate", G_TYPE_STRING, str, NULL);
+      }
+
+      GST_DEBUG_OBJECT (payload, "with video caps: %" GST_PTR_FORMAT, srccaps);
+    }
+  }
+
   update_max_ptime (payload);
 
   res = gst_pad_set_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), srccaps);
@@ -1493,6 +1526,7 @@ gst_rtp_base_payload_change_state (GstElement * element,
       priv->base_offset = GST_BUFFER_OFFSET_NONE;
       priv->negotiated = FALSE;
       gst_caps_replace (&rtpbasepayload->priv->subclass_srccaps, NULL);
+      gst_caps_replace (&rtpbasepayload->priv->sinkcaps, NULL);
       break;
     default:
       break;
index 900b0b9..cb38be3 100644 (file)
@@ -287,6 +287,14 @@ validate_event (guint index, const gchar * name, const gchar * field, ...)
       fail_unless (gst_structure_get_uint (gst_caps_get_structure (caps, 0),
               "ssrc", &ssrc));
       fail_unless_equals_int (ssrc, expected);
+    } else if (!g_strcmp0 (field, "a-framerate")) {
+      const gchar *expected = va_arg (var_args, const gchar *);
+      GstCaps *caps;
+      const gchar *framerate;
+      gst_event_parse_caps (event, &caps);
+      framerate = gst_structure_get_string (gst_caps_get_structure (caps, 0),
+          "a-framerate");
+      fail_unless_equals_string (framerate, expected);
     } else {
       fail ("test cannot validate unknown event field '%s'", field);
     }
@@ -1764,6 +1772,90 @@ GST_START_TEST (rtp_base_payload_property_stats_test)
 
 GST_END_TEST;
 
+/* push a single buffer to the payloader which should successfully payload it
+ * into an RTP packet. besides the payloaded RTP packet there should be the
+ * three events initial events: stream-start, caps and segment. because of that
+ * the input caps has framerate this will be propagated to an a-framerate field
+ * on the output caps.
+ */
+GST_START_TEST (rtp_base_payload_framerate_attribute)
+{
+  State *state;
+
+  state = create_payloader ("video/x-raw,framerate=(fraction)1/4", &sinktmpl,
+      "perfect-rtptime", FALSE,
+      NULL);
+
+  set_state (state, GST_STATE_PLAYING);
+
+  push_buffer (state,
+      "pts", 0 * GST_SECOND,
+      NULL);
+
+  set_state (state, GST_STATE_NULL);
+
+  validate_buffers_received (1);
+
+  validate_buffer (0,
+      "pts", 0 * GST_SECOND,
+      NULL);
+
+  validate_events_received (3);
+
+  validate_normal_start_events (0);
+
+  validate_event (1, "caps",
+      "a-framerate", "0.25",
+      NULL);
+
+  destroy_payloader (state);
+}
+
+GST_END_TEST;
+
+/* push a single buffer to the payloader which should successfully payload it
+ * into an RTP packet. besides the payloaded RTP packet there should be the
+ * three events initial events: stream-start, caps and segment. because of that
+ * the input caps has both framerate and max-framerate set the a-framerate field
+ * on the output caps will correspond to the value of the max-framerate field.
+ */
+GST_START_TEST (rtp_base_payload_max_framerate_attribute)
+{
+  State *state;
+
+  state = create_payloader (
+      "video/x-raw,framerate=(fraction)0/1,max-framerate=(fraction)1/8",
+      &sinktmpl,
+      "perfect-rtptime", FALSE,
+      NULL);
+
+  set_state (state, GST_STATE_PLAYING);
+
+  push_buffer (state,
+      "pts", 0 * GST_SECOND,
+      NULL);
+
+  set_state (state, GST_STATE_NULL);
+
+  validate_buffers_received (1);
+
+  validate_buffer (0,
+      "pts", 0 * GST_SECOND,
+      NULL);
+
+  validate_events_received (3);
+
+  validate_normal_start_events (0);
+
+  validate_event (1, "caps",
+      "a-framerate", "0.125",
+      NULL);
+
+  destroy_payloader (state);
+}
+
+GST_END_TEST;
+
 static Suite *
 rtp_basepayloading_suite (void)
 {
@@ -1798,6 +1890,9 @@ rtp_basepayloading_suite (void)
   tcase_add_test (tc_chain, rtp_base_payload_property_ptime_multiple_test);
   tcase_add_test (tc_chain, rtp_base_payload_property_stats_test);
 
+  tcase_add_test (tc_chain, rtp_base_payload_framerate_attribute);
+  tcase_add_test (tc_chain, rtp_base_payload_max_framerate_attribute);
+
   return s;
 }