rtspsrc: check port-range format
[platform/upstream/gst-plugins-good.git] / gst / rtsp / gstrtspsrc.c
index 4cdd335..9f806ec 100644 (file)
@@ -232,6 +232,7 @@ gst_rtsp_src_ntp_time_source_get_type (void)
 #define DEFAULT_DO_RETRANSMISSION        TRUE
 #define DEFAULT_NTP_TIME_SOURCE  NTP_TIME_SOURCE_NTP
 #define DEFAULT_USER_AGENT       "GStreamer/" PACKAGE_VERSION
+#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
 
 enum
 {
@@ -269,7 +270,8 @@ enum
   PROP_TLS_INTERACTION,
   PROP_DO_RETRANSMISSION,
   PROP_NTP_TIME_SOURCE,
-  PROP_USER_AGENT
+  PROP_USER_AGENT,
+  PROP_MAX_RTCP_RTP_TIME_DIFF
 };
 
 #define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type())
@@ -732,6 +734,13 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
           "The User-Agent string to send to the server",
           DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_MAX_RTCP_RTP_TIME_DIFF,
+      g_param_spec_int ("max-rtcp-rtp-time-diff", "Max RTCP RTP Time Diff",
+          "Maximum amount of time in ms that the RTP time in RTCP SRs "
+          "is allowed to be ahead (-1 disabled)", -1, G_MAXINT,
+          DEFAULT_MAX_RTCP_RTP_TIME_DIFF,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   /**
    * GstRTSPSrc::handle-request:
    * @rtspsrc: a #GstRTSPSrc
@@ -879,6 +888,7 @@ gst_rtspsrc_init (GstRTSPSrc * src)
   src->do_retransmission = DEFAULT_DO_RETRANSMISSION;
   src->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
   src->user_agent = g_strdup (DEFAULT_USER_AGENT);
+  src->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
 
   /* get a list of all extensions */
   src->extensions = gst_rtsp_ext_list_get ();
@@ -1072,26 +1082,22 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
       gst_rtspsrc_set_proxy (rtspsrc, g_value_get_string (value));
       break;
     case PROP_PROXY_ID:
-      if (rtspsrc->prop_proxy_id)
-        g_free (rtspsrc->prop_proxy_id);
+      g_free (rtspsrc->prop_proxy_id);
       rtspsrc->prop_proxy_id = g_value_dup_string (value);
       break;
     case PROP_PROXY_PW:
-      if (rtspsrc->prop_proxy_pw)
-        g_free (rtspsrc->prop_proxy_pw);
+      g_free (rtspsrc->prop_proxy_pw);
       rtspsrc->prop_proxy_pw = g_value_dup_string (value);
       break;
     case PROP_RTP_BLOCKSIZE:
       rtspsrc->rtp_blocksize = g_value_get_uint (value);
       break;
     case PROP_USER_ID:
-      if (rtspsrc->user_id)
-        g_free (rtspsrc->user_id);
+      g_free (rtspsrc->user_id);
       rtspsrc->user_id = g_value_dup_string (value);
       break;
     case PROP_USER_PW:
-      if (rtspsrc->user_pw)
-        g_free (rtspsrc->user_pw);
+      g_free (rtspsrc->user_pw);
       rtspsrc->user_pw = g_value_dup_string (value);
       break;
     case PROP_BUFFER_MODE:
@@ -1102,10 +1108,8 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
       const gchar *str;
 
       str = g_value_get_string (value);
-      if (str) {
-        sscanf (str, "%u-%u",
-            &rtspsrc->client_port_range.min, &rtspsrc->client_port_range.max);
-      } else {
+      if (sscanf (str, "%u-%u", &rtspsrc->client_port_range.min,
+              &rtspsrc->client_port_range.max) != 2) {
         rtspsrc->client_port_range.min = 0;
         rtspsrc->client_port_range.max = 0;
       }
@@ -1161,6 +1165,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
       g_free (rtspsrc->user_agent);
       rtspsrc->user_agent = g_value_dup_string (value);
       break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      rtspsrc->max_rtcp_rtp_time_diff = g_value_get_int (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1304,6 +1311,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_USER_AGENT:
       g_value_set_string (value, rtspsrc->user_agent);
       break;
+    case PROP_MAX_RTCP_RTP_TIME_DIFF:
+      g_value_set_int (value, rtspsrc->max_rtcp_rtp_time_diff);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1483,6 +1493,7 @@ gst_rtspsrc_collect_payloads (GstRTSPSrc * src, const GstSDPMessage * sdp,
 {
   guint i, len;
   const gchar *proto;
+  GstCaps *global_caps;
 
   /* get proto */
   proto = gst_sdp_media_get_proto (media);
@@ -1500,10 +1511,17 @@ gst_rtspsrc_collect_payloads (GstRTSPSrc * src, const GstSDPMessage * sdp,
   else
     goto unknown_proto;
 
+  /* Parse global SDP attributes once */
+  global_caps = gst_caps_new_empty_simple ("application/x-unknown");
+  GST_DEBUG ("mapping sdp session level attributes to caps");
+  gst_rtspsrc_sdp_attributes_to_caps (sdp->attributes, global_caps);
+  GST_DEBUG ("mapping sdp media level attributes to caps");
+  gst_rtspsrc_sdp_attributes_to_caps (media->attributes, global_caps);
+
   len = gst_sdp_media_formats_len (media);
   for (i = 0; i < len; i++) {
     gint pt;
-    GstCaps *caps;
+    GstCaps *caps, *outcaps;
     GstStructure *s;
     const gchar *enc;
     PtMapItem item;
@@ -1526,19 +1544,23 @@ gst_rtspsrc_collect_payloads (GstRTSPSrc * src, const GstSDPMessage * sdp,
       if (strcmp (enc, "X-ASF-PF") == 0)
         stream->container = TRUE;
     }
-    GST_DEBUG ("mapping sdp session level attributes to caps");
-    gst_rtspsrc_sdp_attributes_to_caps (sdp->attributes, caps);
-    GST_DEBUG ("mapping sdp media level attributes to caps");
-    gst_rtspsrc_sdp_attributes_to_caps (media->attributes, caps);
+
+    /* Merge in global caps */
+    /* Intersect will merge in missing fields to the current caps */
+    outcaps = gst_caps_intersect (caps, global_caps);
+    gst_caps_unref (caps);
 
     /* the first pt will be the default */
     if (stream->ptmap->len == 0)
       stream->default_pt = pt;
 
     item.pt = pt;
-    item.caps = caps;
+    item.caps = outcaps;
+
     g_array_append_val (stream->ptmap, item);
   }
+
+  gst_caps_unref (global_caps);
   return;
 
 no_proto:
@@ -1858,7 +1880,6 @@ static gboolean
 parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
 {
   gboolean res = FALSE;
-  gchar *p, *kmpid;
   gsize size;
   guchar *data;
   GstMIKEYMessage *msg;
@@ -1866,17 +1887,28 @@ parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
   const gchar *srtp_cipher;
   const gchar *srtp_auth;
 
-  p = (gchar *) keymgmt;
+  {
+    gchar *orig_value;
+    gchar *p, *kmpid;
 
-  SKIP_SPACES (p);
-  if (*p == '\0')
-    return FALSE;
+    p = orig_value = g_strdup (keymgmt);
 
-  PARSE_STRING (p, " ", kmpid);
-  if (!g_str_equal (kmpid, "mikey"))
-    return FALSE;
+    SKIP_SPACES (p);
+    if (*p == '\0') {
+      g_free (orig_value);
+      return FALSE;
+    }
+
+    PARSE_STRING (p, " ", kmpid);
+    if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) {
+      g_free (orig_value);
+      return FALSE;
+    }
+    data = g_base64_decode (p, &size);
+
+    g_free (orig_value);        /* Don't need this any more */
+  }
 
-  data = g_base64_decode (p, &size);
   if (data == NULL)
     return FALSE;
 
@@ -1984,6 +2016,7 @@ parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
         gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
         pkd->key_len);
     gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL);
+    gst_buffer_unref (buf);
   }
 
   gst_caps_set_simple (caps,
@@ -3470,6 +3503,11 @@ gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
             NULL);
       }
 
+      if (g_object_class_find_property (klass, "max-rtcp-rtp-time-diff")) {
+        g_object_set (src->manager, "max-rtcp-rtp-time-diff",
+            src->max_rtcp_rtp_time_diff, NULL);
+      }
+
       /* buffer mode pauses are handled by adding offsets to buffer times,
        * but some depayloaders may have a hard time syncing output times
        * with such input times, e.g. container ones, most notably ASF */
@@ -4466,8 +4504,7 @@ gst_rtsp_conninfo_connect (GstRTSPSrc * src, GstRTSPConnInfo * info,
     if ((res = gst_rtsp_connection_create (info->url, &info->connection)) < 0)
       goto could_not_create;
 
-    if (info->url_str)
-      g_free (info->url_str);
+    g_free (info->url_str);
     info->url_str = gst_rtsp_url_get_request_uri (info->url);
 
     GST_DEBUG_OBJECT (src, "sanitized uri %s", info->url_str);
@@ -5940,6 +5977,7 @@ gst_rtspsrc_send (GstRTSPSrc * src, GstRTSPConnection * conn,
 
     switch (int_code) {
       case GST_RTSP_STS_UNAUTHORIZED:
+      case GST_RTSP_STS_NOT_FOUND:
         if (gst_rtspsrc_setup_auth (src, response)) {
           /* Try the request/response again after configuring the auth info
            * and loop again */
@@ -6335,10 +6373,11 @@ default_srtcp_params (void)
   GstBuffer *buf;
   guint8 *key_data;
 #define KEY_SIZE 30
+  guint data_size = GST_ROUND_UP_4 (KEY_SIZE);
 
   /* create a random key */
-  key_data = g_malloc (KEY_SIZE);
-  for (i = 0; i < KEY_SIZE; i += 4)
+  key_data = g_malloc (data_size);
+  for (i = 0; i < data_size; i += 4)
     GST_WRITE_UINT32_BE (key_data + i, g_random_int ());
 
   buf = gst_buffer_new_wrapped (key_data, KEY_SIZE);
@@ -7214,7 +7253,7 @@ restart:
   }
 
   /* it could be that the DESCRIBE method was not implemented */
-  if (!src->methods & GST_RTSP_DESCRIBE)
+  if (!(src->methods & GST_RTSP_DESCRIBE))
     goto no_describe;
 
   /* check if reply is SDP */