*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
/**
* asks for the discovery to begin (through gst_discoverer_start()).
*
* All the information is returned in a #GstDiscovererInfo structure.
- *
- * Since: 0.10.31
*/
#ifdef HAVE_CONFIG_H
#endif
#include <gst/video/video.h>
+#include <gst/audio/audio.h>
#include "pbutils.h"
-#include "pbutils-marshal.h"
#include "pbutils-private.h"
-#include "gst/glib-compat-private.h"
-
GST_DEBUG_CATEGORY_STATIC (discoverer_debug);
#define GST_CAT_DEFAULT discoverer_debug
/* list of pending URI to process (current excluded) */
GList *pending_uris;
- GMutex *lock;
+ GMutex lock;
/* TRUE if processing a URI */
gboolean processing;
/* Handler ids for various callbacks */
gulong pad_added_id;
gulong pad_remove_id;
+ gulong source_chg_id;
gulong element_added_id;
gulong bus_cb_id;
};
-#define DISCO_LOCK(dc) g_mutex_lock (dc->priv->lock);
-#define DISCO_UNLOCK(dc) g_mutex_unlock (dc->priv->lock);
+#define DISCO_LOCK(dc) g_mutex_lock (&dc->priv->lock);
+#define DISCO_UNLOCK(dc) g_mutex_unlock (&dc->priv->lock);
static void
_do_init (void)
SIGNAL_FINISHED,
SIGNAL_STARTING,
SIGNAL_DISCOVERED,
+ SIGNAL_SOURCE_SETUP,
LAST_SIGNAL
};
GstDiscoverer * dc);
static void uridecodebin_pad_removed_cb (GstElement * uridecodebin,
GstPad * pad, GstDiscoverer * dc);
+static void uridecodebin_source_changed_cb (GstElement * uridecodebin,
+ GParamSpec * pspec, GstDiscoverer * dc);
static void gst_discoverer_dispose (GObject * dc);
+static void gst_discoverer_finalize (GObject * dc);
static void gst_discoverer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_discoverer_get_property (GObject * object, guint prop_id,
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->dispose = gst_discoverer_dispose;
+ gobject_class->finalize = gst_discoverer_finalize;
gobject_class->set_property = gst_discoverer_set_property;
gobject_class->get_property = gst_discoverer_get_property;
/* properties */
/**
- * GstDiscoverer:timeout
+ * GstDiscoverer:timeout:
*
* The duration (in nanoseconds) after which the discovery of an individual
* URI will timeout.
* @discoverer: the #GstDiscoverer
* @info: the results #GstDiscovererInfo
* @error: (type GLib.Error): #GError, which will be non-NULL if an error
- * occurred during discovery
+ * occurred during discovery. You must not
+ * free this #GError, it will be freed by
+ * the discoverer.
+ *
+ * Will be emitted when all information on a URI could be discovered, or
+ * an error ocurred.
*
- * Will be emitted when all information on a URI could be discovered.
+ * When an error occurs, @info might still contain some partial information,
+ * depending on the circumstances of the error.
*/
gst_discoverer_signals[SIGNAL_DISCOVERED] =
g_signal_new ("discovered", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstDiscovererClass, discovered),
- NULL, NULL, pbutils_marshal_VOID__POINTER_BOXED,
+ NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 2, GST_TYPE_DISCOVERER_INFO,
G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ /**
+ * GstDiscoverer::source-setup:
+ * @discoverer: the #GstDiscoverer
+ * @source: source element
+ *
+ * This signal is emitted after the source element has been created for, so
+ * the URI being discovered, so it can be configured by setting additional
+ * properties (e.g. set a proxy server for an http source, or set the device
+ * and read speed for an audio cd source).
+ *
+ * This signal is usually emitted from the context of a GStreamer streaming
+ * thread.
+ */
+ gst_discoverer_signals[SIGNAL_SOURCE_SETUP] =
+ g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDiscovererClass, source_setup),
+ NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
}
static void
dc->priv->async = FALSE;
dc->priv->async_done = FALSE;
- dc->priv->lock = g_mutex_new ();
+ g_mutex_init (&dc->priv->lock);
dc->priv->pending_subtitle_pads = 0;
dc->priv->pad_remove_id =
g_signal_connect_object (dc->priv->uridecodebin, "pad-removed",
G_CALLBACK (uridecodebin_pad_removed_cb), dc, 0);
+ dc->priv->source_chg_id =
+ g_signal_connect_object (dc->priv->uridecodebin, "notify::source",
+ G_CALLBACK (uridecodebin_source_changed_cb), dc, 0);
GST_LOG_OBJECT (dc, "Getting pipeline bus");
dc->priv->bus = gst_pipeline_get_bus ((GstPipeline *) dc->priv->pipeline);
/* Workaround for bug #118536 */
DISCONNECT_SIGNAL (dc->priv->uridecodebin, dc->priv->pad_added_id);
DISCONNECT_SIGNAL (dc->priv->uridecodebin, dc->priv->pad_remove_id);
+ DISCONNECT_SIGNAL (dc->priv->uridecodebin, dc->priv->source_chg_id);
DISCONNECT_SIGNAL (dc->priv->uridecodebin, dc->priv->element_added_id);
DISCONNECT_SIGNAL (dc->priv->bus, dc->priv->bus_cb_id);
gst_discoverer_stop (dc);
- if (dc->priv->lock) {
- g_mutex_free (dc->priv->lock);
- dc->priv->lock = NULL;
- }
-
if (dc->priv->seeking_query) {
gst_query_unref (dc->priv->seeking_query);
dc->priv->seeking_query = NULL;
}
static void
+gst_discoverer_finalize (GObject * obj)
+{
+ GstDiscoverer *dc = (GstDiscoverer *) obj;
+
+ g_mutex_clear (&dc->priv->lock);
+
+ G_OBJECT_CLASS (gst_discoverer_parent_class)->finalize (obj);
+}
+
+static void
gst_discoverer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
ps->tags);
tmp = gst_tag_list_merge (ps->tags, tl, GST_TAG_MERGE_APPEND);
if (ps->tags)
- gst_tag_list_free (ps->tags);
+ gst_tag_list_unref (ps->tags);
ps->tags = tmp;
GST_DEBUG_OBJECT (pad, "private stream %p new tags %" GST_PTR_FORMAT, ps,
tmp);
return GST_PAD_PROBE_OK;
}
-static GstStaticCaps subtitle_caps = GST_STATIC_CAPS ("text/plain; "
- "text/x-pango-markup; subpicture/x-pgs; subpicture/x-dvb; "
+static GstStaticCaps subtitle_caps = GST_STATIC_CAPS ("text/x-raw; "
+ "subpicture/x-pgs; subpicture/x-dvb; subpicture/x-dvd; "
"application/x-subtitle-unknown; application/x-ssa; application/x-ass; "
- "subtitle/x-kate; application/x-kate; video/x-dvd-subpicture");
+ "subtitle/x-kate; application/x-kate");
static gboolean
is_subtitle_caps (const GstCaps * caps)
}
static void
+uridecodebin_source_changed_cb (GstElement * uridecodebin,
+ GParamSpec * pspec, GstDiscoverer * dc)
+{
+ GstElement *src;
+ /* get a handle to the source */
+ g_object_get (uridecodebin, pspec->name, &src, NULL);
+
+ GST_DEBUG_OBJECT (dc, "got a new source %p", src);
+
+ g_signal_emit (dc, gst_discoverer_signals[SIGNAL_SOURCE_SETUP], 0, src);
+ gst_object_unref (src);
+}
+
+static void
uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
GstDiscoverer * dc)
{
gst_bin_remove_many (dc->priv->pipeline, ps->sink, ps->queue, NULL);
if (ps->tags) {
- gst_tag_list_free (ps->tags);
+ gst_tag_list_unref (ps->tags);
}
if (ps->toc) {
gst_toc_unref (ps->toc);
}
gst_tag_list_insert (*taglist, new_tags, GST_TAG_MERGE_REPLACE);
- gst_tag_list_free (new_tags);
+ gst_tag_list_unref (new_tags);
}
/* Parses a set of caps and tags in st and populates a GstDiscovererStreamInfo
if (g_str_has_prefix (name, "audio/")) {
GstDiscovererAudioInfo *info;
+ const gchar *format_str;
if (parent)
info = (GstDiscovererAudioInfo *) gst_discoverer_stream_info_ref (parent);
if (gst_structure_get_int (caps_st, "channels", &tmp))
info->channels = (guint) tmp;
- if (gst_structure_get_int (caps_st, "depth", &tmp))
- info->depth = (guint) tmp;
+ /* FIXME: we only want to extract depth if raw audio is what's in the
+ * container (i.e. not if there is a decoder involved) */
+ format_str = gst_structure_get_string (caps_st, "format");
+ if (format_str != NULL) {
+ const GstAudioFormatInfo *finfo;
+ GstAudioFormat format;
+
+ format = gst_audio_format_from_string (format_str);
+ finfo = gst_audio_format_get_info (format);
+ info->depth = GST_AUDIO_FORMAT_INFO_DEPTH (finfo);
+ }
if (gst_structure_id_has_field (st, _TAGS_QUARK)) {
gst_structure_id_get (st, _TAGS_QUARK, GST_TYPE_TAG_LIST, &tags_st, NULL);
info->parent.caps = gst_caps_ref (caps);
}
- /* FIXME : gst_video_info_from_caps only works with raw caps,
- * wouldn't we want to get all the info below for non-raw caps ?
- */
- if (g_str_has_prefix (name, "video/x-raw") &&
- gst_video_info_from_caps (&vinfo, caps)) {
+ if (gst_video_info_from_caps (&vinfo, caps)) {
info->width = (guint) vinfo.width;
info->height = (guint) vinfo.height;
GList *tmp;
if (!gst_structure_id_has_field (topology, _TOPOLOGY_PAD_QUARK)) {
- GST_DEBUG ("Could not find pad for node %" GST_PTR_FORMAT "\n", topology);
+ GST_DEBUG ("Could not find pad for node %" GST_PTR_FORMAT, topology);
return NULL;
}
tmp =
gst_tag_list_merge (cont->parent.tags, (GstTagList *) tags,
GST_TAG_MERGE_APPEND);
- gst_tag_list_free (tags);
+ gst_tag_list_unref (tags);
if (cont->parent.tags)
- gst_tag_list_free (cont->parent.tags);
+ gst_tag_list_unref (cont->parent.tags);
cont->parent.tags = tmp;
GST_DEBUG ("Container info tags %" GST_PTR_FORMAT, tmp);
}
if (dc->priv->current_info->duration == 0 &&
dc->priv->current_info->stream_info != NULL &&
dc->priv->current_info->stream_info->next == NULL) {
- GstStructure *st =
- gst_caps_get_structure (dc->priv->current_info->stream_info->caps, 0);
+ GstDiscovererStreamInfo *stream_info;
+ GstStructure *st;
+
+ stream_info = dc->priv->current_info->stream_info;
+ st = gst_caps_get_structure (stream_info->caps, 0);
if (g_str_has_prefix (gst_structure_get_name (st), "image/"))
- ((GstDiscovererVideoInfo *) dc->priv->current_info->stream_info)->
- is_image = TRUE;
+ ((GstDiscovererVideoInfo *) stream_info)->is_image = TRUE;
}
}
dc->priv->current_info, dc->priv->current_error);
/* Clients get a copy of current_info since it is a boxed type */
gst_discoverer_info_unref (dc->priv->current_info);
+ dc->priv->current_info = NULL;
}
}
tmp =
gst_tag_list_merge (dc->priv->current_info->tags, tl,
GST_TAG_MERGE_APPEND);
- gst_tag_list_free (tl);
+ gst_tag_list_unref (tl);
if (dc->priv->current_info->tags)
- gst_tag_list_free (dc->priv->current_info->tags);
+ gst_tag_list_unref (dc->priv->current_info->tags);
dc->priv->current_info->tags = tmp;
GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "Current info %p, tags %"
GST_PTR_FORMAT, dc->priv->current_info, tmp);
* Allow asynchronous discovering of URIs to take place.
* A #GMainLoop must be available for #GstDiscoverer to properly work in
* asynchronous mode.
- *
- * Since: 0.10.31
*/
void
gst_discoverer_start (GstDiscoverer * discoverer)
*
* Stop the discovery of any pending URIs and clears the list of
* pending URIS (if any).
- *
- * Since: 0.10.31
*/
void
gst_discoverer_stop (GstDiscoverer * discoverer)
*
* Returns: %TRUE if the @uri was successfully appended to the list of pending
* uris, else %FALSE
- *
- * Since: 0.10.31
*/
gboolean
gst_discoverer_discover_uri_async (GstDiscoverer * discoverer,
*
* Returns: (transfer full): the result of the scanning. Can be %NULL if an
* error occurred.
- *
- * Since: 0.10.31
*/
GstDiscovererInfo *
gst_discoverer_discover_uri (GstDiscoverer * discoverer, const gchar * uri,
* If an error occurred when creating the discoverer, @err will be set
* accordingly and %NULL will be returned. If @err is set, the caller must
* free it when no longer needed using g_error_free().
- *
- * Since: 0.10.31
*/
GstDiscoverer *
gst_discoverer_new (GstClockTime timeout, GError ** err)