Exemple #1
0
static void
gst_mms_finalize (GObject * gobject)
{
  GstMMS *mmssrc = GST_MMS (gobject);

  /* We may still have a connection open, as we preserve unused / pristine
     open connections in stop to reuse them in start. */
  if (mmssrc->connection) {
    mmsx_close (mmssrc->connection);
    mmssrc->connection = NULL;
  }

  if (mmssrc->current_connection_uri_name) {
    g_free (mmssrc->current_connection_uri_name);
    mmssrc->current_connection_uri_name = NULL;
  }

  if (mmssrc->uri_name) {
    g_free (mmssrc->uri_name);
    mmssrc->uri_name = NULL;
  }

  if (G_OBJECT_CLASS (parent_class)->finalize)
    G_OBJECT_CLASS (parent_class)->finalize (gobject);

}
Exemple #2
0
static gboolean
gst_mms_is_seekable (GstBaseSrc * src)
{
  GstMMS *mmssrc = GST_MMS (src);

  return mmsx_get_seekable (mmssrc->connection);
}
Exemple #3
0
static void
gst_mms_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstMMS *mmssrc;

  mmssrc = GST_MMS (object);

  GST_OBJECT_LOCK (mmssrc);
  switch (prop_id) {
    case ARG_LOCATION:
      if (mmssrc->uri_name) {
        g_free (mmssrc->uri_name);
        mmssrc->uri_name = NULL;
      }
      mmssrc->uri_name = g_value_dup_string (value);
      break;
    case ARG_CONNECTION_SPEED:
      mmssrc->connection_speed = g_value_get_uint (value) * 1000;
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
  GST_OBJECT_UNLOCK (mmssrc);
}
Exemple #4
0
static const gchar *
gst_mms_uri_get_uri (GstURIHandler * handler)
{
  GstMMS *src = GST_MMS (handler);

  return src->uri_name;
}
Exemple #5
0
static gchar *
gst_mms_uri_get_uri (GstURIHandler * handler)
{
  GstMMS *src = GST_MMS (handler);

  /* FIXME: make thread-safe */
  return g_strdup (src->uri_name);
}
Exemple #6
0
static GstFlowReturn
gst_mms_create (GstPushSrc * psrc, GstBuffer ** buf)
{
  GstMMS *mmssrc;
  guint8 *data;
  guint blocksize;
  gint result;
  mms_off_t offset;

  *buf = NULL;

  mmssrc = GST_MMS (psrc);

  offset = mmsx_get_current_pos (mmssrc->connection);

  /* Check if a seek perhaps has wrecked our connection */
  if (offset == -1) {
    GST_DEBUG_OBJECT (mmssrc,
        "connection broken (probably an error during mmsx_seek_time during a convert query) returning FLOW_ERROR");
    return GST_FLOW_ERROR;
  }

  /* Choose blocksize best for optimum performance */
  if (offset == 0)
    blocksize = mmsx_get_asf_header_len (mmssrc->connection);
  else
    blocksize = mmsx_get_asf_packet_len (mmssrc->connection);

  *buf = gst_buffer_new_and_alloc (blocksize);

  data = GST_BUFFER_DATA (*buf);
  GST_BUFFER_SIZE (*buf) = 0;
  GST_LOG_OBJECT (mmssrc, "reading %d bytes", blocksize);
  result = mmsx_read (NULL, mmssrc->connection, (char *) data, blocksize);

  /* EOS? */
  if (result == 0)
    goto eos;

  GST_BUFFER_OFFSET (*buf) = offset;
  GST_BUFFER_SIZE (*buf) = result;

  GST_LOG_OBJECT (mmssrc, "Returning buffer with offset %" G_GINT64_FORMAT
      " and size %u", GST_BUFFER_OFFSET (*buf), GST_BUFFER_SIZE (*buf));

  gst_buffer_set_caps (*buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (mmssrc)));

  return GST_FLOW_OK;

eos:
  {
    GST_DEBUG_OBJECT (mmssrc, "EOS");
    gst_buffer_unref (*buf);
    *buf = NULL;
    return GST_FLOW_UNEXPECTED;
  }
}
Exemple #7
0
static GstFlowReturn
gst_mms_create (GstPushSrc * psrc, GstBuffer ** buf)
{
  GstMMS *mmssrc = GST_MMS (psrc);
  guint8 *data;
  guint blocksize;
  gint result;
  mms_off_t offset;

  *buf = NULL;

  offset = mmsx_get_current_pos (mmssrc->connection);

  /* Check if a seek perhaps has wrecked our connection */
  if (offset == -1) {
    GST_ERROR_OBJECT (mmssrc,
        "connection broken (probably an error during mmsx_seek_time during a convert query) returning FLOW_ERROR");
    return GST_FLOW_ERROR;
  }

  /* Choose blocksize best for optimum performance */
  if (offset == 0)
    blocksize = mmsx_get_asf_header_len (mmssrc->connection);
  else
    blocksize = mmsx_get_asf_packet_len (mmssrc->connection);

  data = g_try_malloc (blocksize);
  if (!data) {
    GST_ERROR_OBJECT (mmssrc, "Failed to allocate %u bytes", blocksize);
    return GST_FLOW_ERROR;
  }

  GST_LOG_OBJECT (mmssrc, "reading %d bytes", blocksize);
  result = mmsx_read (NULL, mmssrc->connection, (char *) data, blocksize);
  /* EOS? */
  if (result == 0)
    goto eos;

  *buf = gst_buffer_new_wrapped (data, result);
  GST_BUFFER_OFFSET (*buf) = offset;

  GST_LOG_OBJECT (mmssrc, "Returning buffer with offset %" G_GINT64_FORMAT
      " and size %u", offset, result);

  return GST_FLOW_OK;

eos:
  {
    GST_DEBUG_OBJECT (mmssrc, "EOS");
    g_free (data);
    *buf = NULL;
    return GST_FLOW_EOS;
  }
}
Exemple #8
0
static gboolean
gst_mms_start (GstBaseSrc * bsrc)
{
  GstMMS *mms;
  guint bandwidth_avail;

  mms = GST_MMS (bsrc);

  if (!mms->uri_name || *mms->uri_name == '\0')
    goto no_uri;

  if (mms->connection_speed)
    bandwidth_avail = mms->connection_speed;
  else
    bandwidth_avail = G_MAXINT;

  /* FIXME: pass some sane arguments here */
  GST_DEBUG_OBJECT (mms,
      "Trying mms_connect (%s) with bandwidth constraint of %d bps",
      mms->uri_name, bandwidth_avail);
  mms->connection = mms_connect (NULL, NULL, mms->uri_name, bandwidth_avail);
  if (mms->connection)
    goto success;

  GST_DEBUG_OBJECT (mms,
      "Trying mmsh_connect (%s) with bandwidth constraint of %d bps",
      mms->uri_name, bandwidth_avail);
  mms->connection_h = mmsh_connect (NULL, NULL, mms->uri_name, bandwidth_avail);
  if (!mms->connection_h)
    goto no_connect;

  /* fall through */

success:
  {
    GST_DEBUG_OBJECT (mms, "Connect successful");
    return TRUE;
  }

no_uri:
  {
    GST_ELEMENT_ERROR (mms, RESOURCE, OPEN_READ,
        ("No URI to open specified"), (NULL));
    return FALSE;
  }

no_connect:
  {
    GST_ELEMENT_ERROR (mms, RESOURCE, OPEN_READ,
        ("Could not connect to this stream"), (NULL));
    return FALSE;
  }
}
Exemple #9
0
static GstFlowReturn
gst_mms_create (GstPushSrc * psrc, GstBuffer ** buf)
{
  GstMMS *mmssrc;
  guint8 *data;
  guint blocksize;
  gint result;

  mmssrc = GST_MMS (psrc);

  GST_OBJECT_LOCK (mmssrc);
  blocksize = GST_BASE_SRC (mmssrc)->blocksize;
  GST_OBJECT_UNLOCK (mmssrc);

  *buf = gst_buffer_new_and_alloc (blocksize);

  data = GST_BUFFER_DATA (*buf);
  GST_BUFFER_SIZE (*buf) = 0;
  GST_LOG_OBJECT (mmssrc, "reading %d bytes", blocksize);
  if (mmssrc->connection) {
    result = mms_read (NULL, mmssrc->connection, (char *) data, blocksize);
  } else {
    result = mmsh_read (NULL, mmssrc->connection_h, (char *) data, blocksize);
  }

  /* EOS? */
  if (result == 0)
    goto eos;

  if (mmssrc->connection) {
    GST_BUFFER_OFFSET (*buf) =
        mms_get_current_pos (mmssrc->connection) - result;
  } else {
    GST_BUFFER_OFFSET (*buf) =
        mmsh_get_current_pos (mmssrc->connection_h) - result;
  }
  GST_BUFFER_SIZE (*buf) = result;

  GST_LOG_OBJECT (mmssrc, "Returning buffer with offset %" G_GINT64_FORMAT
      " and size %u", GST_BUFFER_OFFSET (*buf), GST_BUFFER_SIZE (*buf));

  gst_buffer_set_caps (*buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (mmssrc)));

  return GST_FLOW_OK;

eos:
  {
    GST_DEBUG_OBJECT (mmssrc, "EOS");
    gst_buffer_unref (*buf);
    *buf = NULL;
    return GST_FLOW_UNEXPECTED;
  }
}
Exemple #10
0
static gboolean
gst_mms_get_size (GstBaseSrc * src, guint64 * size)
{
  GstMMS *mmssrc = GST_MMS (src);

  /* non seekable usually means live streams, and get_length() returns,
     erm, interesting values for live streams */
  if (!mmsx_get_seekable (mmssrc->connection))
    return FALSE;

  *size = mmsx_get_length (mmssrc->connection);
  return TRUE;
}
Exemple #11
0
static void
gst_mms_finalize (GObject * gobject)
{
  GstMMS *mmssrc = GST_MMS (gobject);

  if (mmssrc->uri_name) {
    g_free (mmssrc->uri_name);
    mmssrc->uri_name = NULL;
  }

  if (G_OBJECT_CLASS (parent_class)->finalize)
    G_OBJECT_CLASS (parent_class)->finalize (gobject);

}
Exemple #12
0
static gboolean
gst_mms_stop (GstBaseSrc * bsrc)
{
  GstMMS *mms;

  mms = GST_MMS (bsrc);
  if (mms->connection != NULL) {
    mms_close (mms->connection);
    mms->connection = NULL;
  }
  if (mms->connection_h != NULL) {
    mmsh_close (mms->connection_h);
    mms->connection_h = NULL;
  }
  return TRUE;
}
Exemple #13
0
static gboolean
gst_mms_uri_set_uri (GstURIHandler * handler, const gchar * uri)
{
  gchar *protocol;
  GstMMS *src = GST_MMS (handler);

  protocol = gst_uri_get_protocol (uri);
  if ((strcmp (protocol, "mms") != 0) && (strcmp (protocol, "mmsh") != 0)) {
    g_free (protocol);
    return FALSE;
  }
  g_free (protocol);
  g_object_set (src, "location", uri, NULL);

  return TRUE;
}
Exemple #14
0
/* FIXME operating in TIME rather than BYTES could remove this altogether
 * and be more convenient elsewhere */
static gboolean
gst_mms_query (GstBaseSrc * src, GstQuery * query)
{
  GstMMS *mmssrc = GST_MMS (src);
  gboolean res = TRUE;
  GstFormat format;
  gint64 value;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
      gst_query_parse_position (query, &format, &value);
      if (format != GST_FORMAT_BYTES) {
        res = FALSE;
        break;
      }
      value = (gint64) mmsx_get_current_pos (mmssrc->connection);
      gst_query_set_position (query, format, value);
      break;
    case GST_QUERY_DURATION:
      if (!mmsx_get_seekable (mmssrc->connection)) {
        res = FALSE;
        break;
      }
      gst_query_parse_duration (query, &format, &value);
      switch (format) {
        case GST_FORMAT_BYTES:
          value = (gint64) mmsx_get_length (mmssrc->connection);
          gst_query_set_duration (query, format, value);
          break;
        case GST_FORMAT_TIME:
          value = mmsx_get_time_length (mmssrc->connection) * GST_SECOND;
          gst_query_set_duration (query, format, value);
          break;
        default:
          res = FALSE;
      }
      break;
    default:
      /* chain to parent */
      res =
          GST_BASE_SRC_CLASS (parent_class)->query (GST_BASE_SRC (src), query);
      break;
  }

  return res;
}
Exemple #15
0
static gboolean
gst_mms_src_query (GstPad * pad, GstQuery * query)
{

  GstMMS *mmssrc = GST_MMS (gst_pad_get_parent (pad));
  gboolean res = TRUE;
  GstFormat format;
  gint64 value;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
      gst_query_parse_position (query, &format, &value);
      if (format != GST_FORMAT_BYTES) {
        res = FALSE;
        break;
      }
      if (mmssrc->connection) {
        value = (gint64) mms_get_current_pos (mmssrc->connection);
      } else {
        value = (gint64) mmsh_get_current_pos (mmssrc->connection_h);
      }
      gst_query_set_position (query, format, value);
      break;
    case GST_QUERY_DURATION:
      gst_query_parse_duration (query, &format, &value);
      if (format != GST_FORMAT_BYTES) {
        res = FALSE;
        break;
      }
      if (mmssrc->connection) {
        value = (gint64) mms_get_length (mmssrc->connection);
      } else {
        value = (gint64) mmsh_get_length (mmssrc->connection_h);
      }
      gst_query_set_duration (query, format, value);
      break;
    default:
      res = FALSE;
      break;
  }

  gst_object_unref (mmssrc);
  return res;

}
Exemple #16
0
static gboolean
gst_mms_stop (GstBaseSrc * bsrc)
{
  GstMMS *mms = GST_MMS (bsrc);

  if (mms->connection != NULL) {
    /* Check if the connection is still pristine, that is if no more then
       just the mmslib cached asf header has been read. If it is still pristine
       preserve it as we often are re-started with the same URL and connecting
       is expensive */
    if (mmsx_get_current_pos (mms->connection) >
        mmsx_get_asf_header_len (mms->connection)) {
      mmsx_close (mms->connection);
      mms->connection = NULL;
      g_free (mms->current_connection_uri_name);
      mms->current_connection_uri_name = NULL;
    }
  }
  return TRUE;
}
Exemple #17
0
static gboolean
gst_mms_uri_set_uri (GstURIHandler * handler, const gchar * uri,
    GError ** error)
{
  GstMMS *src = GST_MMS (handler);
  gchar *fixed_uri;

  fixed_uri = gst_mms_src_make_valid_uri (uri);
  if (!fixed_uri && uri) {
    g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
        "Invalid MMS URI");
    return FALSE;
  }

  GST_OBJECT_LOCK (src);
  g_free (src->uri_name);
  src->uri_name = fixed_uri;
  GST_OBJECT_UNLOCK (src);

  return TRUE;
}
Exemple #18
0
static void
gst_mms_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstMMS *mmssrc = GST_MMS (object);

  switch (prop_id) {
    case PROP_LOCATION:
      gst_mms_uri_set_uri (GST_URI_HANDLER (mmssrc),
          g_value_get_string (value), NULL);
      break;
    case PROP_CONNECTION_SPEED:
      GST_OBJECT_LOCK (mmssrc);
      mmssrc->connection_speed = g_value_get_uint64 (value) * 1000;
      GST_OBJECT_UNLOCK (mmssrc);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
Exemple #19
0
static void
gst_mms_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstMMS *mmssrc = GST_MMS (object);

  GST_OBJECT_LOCK (mmssrc);
  switch (prop_id) {
    case PROP_LOCATION:
      if (mmssrc->uri_name)
        g_value_set_string (value, mmssrc->uri_name);
      break;
    case PROP_CONNECTION_SPEED:
      g_value_set_uint64 (value, mmssrc->connection_speed / 1000);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
  GST_OBJECT_UNLOCK (mmssrc);
}
Exemple #20
0
static gboolean
gst_mms_do_seek (GstBaseSrc * src, GstSegment * segment)
{
  mms_off_t start;
  GstMMS *mmssrc = GST_MMS (src);

  if (segment->format == GST_FORMAT_TIME) {
    if (!mmsx_time_seek (NULL, mmssrc->connection,
            (double) segment->start / GST_SECOND)) {
      GST_LOG_OBJECT (mmssrc, "mmsx_time_seek() failed");
      return FALSE;
    }
    start = mmsx_get_current_pos (mmssrc->connection);
    GST_INFO_OBJECT (mmssrc, "sought to %" GST_TIME_FORMAT ", offset after "
        "seek: %" G_GINT64_FORMAT, GST_TIME_ARGS (segment->start), start);
  } else if (segment->format == GST_FORMAT_BYTES) {
    start = mmsx_seek (NULL, mmssrc->connection, segment->start, SEEK_SET);
    /* mmsx_seek will close and reopen the connection when seeking with the
       mmsh protocol, if the reopening fails this is indicated with -1 */
    if (start == -1) {
      GST_DEBUG_OBJECT (mmssrc, "connection broken during seek");
      return FALSE;
    }
    GST_INFO_OBJECT (mmssrc, "sought to: %" G_GINT64_FORMAT " bytes, "
        "result: %" G_GINT64_FORMAT, segment->start, start);
  } else {
    GST_DEBUG_OBJECT (mmssrc, "unsupported seek segment format: %s",
        GST_STR_NULL (gst_format_get_name (segment->format)));
    return FALSE;
  }
  gst_segment_init (segment, GST_FORMAT_BYTES);
  gst_segment_set_seek (segment, segment->rate, GST_FORMAT_BYTES,
      segment->flags, GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_NONE,
      segment->stop, NULL);
  return TRUE;
}
Exemple #21
0
static gboolean
gst_mms_start (GstBaseSrc * bsrc)
{
  GstMMS *mms;
  guint bandwidth_avail;

  mms = GST_MMS (bsrc);

  if (!mms->uri_name || *mms->uri_name == '\0')
    goto no_uri;

  if (mms->connection_speed)
    bandwidth_avail = mms->connection_speed;
  else
    bandwidth_avail = G_MAXINT;

  /* If we already have a connection, and the uri isn't changed, reuse it,
     as connecting is expensive. */
  if (mms->connection) {
    if (!strcmp (mms->uri_name, mms->current_connection_uri_name)) {
      GST_DEBUG_OBJECT (mms, "Reusing existing connection for %s",
          mms->uri_name);
      return TRUE;
    } else {
      mmsx_close (mms->connection);
      g_free (mms->current_connection_uri_name);
      mms->current_connection_uri_name = NULL;
    }
  }

  /* FIXME: pass some sane arguments here */
  GST_DEBUG_OBJECT (mms,
      "Trying mms_connect (%s) with bandwidth constraint of %d bps",
      mms->uri_name, bandwidth_avail);
  mms->connection = mmsx_connect (NULL, NULL, mms->uri_name, bandwidth_avail);
  if (mms->connection) {
    /* Save the uri name so that it can be checked for connection reusing,
       see above. */
    mms->current_connection_uri_name = g_strdup (mms->uri_name);
    GST_DEBUG_OBJECT (mms, "Connect successful");
    return TRUE;
  } else {
    gchar *url, *location;

    GST_ERROR_OBJECT (mms,
        "Could not connect to this stream, redirecting to rtsp");
    location = gst_uri_get_location (mms->uri_name);
    url = g_strdup_printf ("rtsp://%s", location);
    g_free (location);

    gst_element_post_message (GST_ELEMENT_CAST (mms),
        gst_message_new_element (GST_OBJECT_CAST (mms),
            gst_structure_new ("redirect", "new-location", G_TYPE_STRING, url,
                NULL)));
    return FALSE;
  }

no_uri:
  {
    GST_ELEMENT_ERROR (mms, RESOURCE, OPEN_READ,
        ("No URI to open specified"), (NULL));
    return FALSE;
  }
}