#include "gststreamselector.h"
#include "gstplay-marshal.h"
+#include <gst/utils/base-utils.h>
+
GST_DEBUG_CATEGORY_STATIC (gst_play_base_bin_debug);
#define GST_CAT_DEFAULT gst_play_base_bin_debug
}
}
+static gboolean
+string_arr_has_str (const gchar * values[], const gchar * value)
+{
+ if (values && value) {
+ while (*values != NULL) {
+ if (strcmp (value, *values) == 0)
+ return TRUE;
+ ++values;
+ }
+ }
+ return FALSE;
+}
+
+/* mime types we are not handling on purpose right now, don't post a
+ * missing-plugin message for these */
+static const gchar *blacklisted_mimes[] = {
+ "video/x-dvd-subpicture", NULL
+};
+
+#define IS_BLACKLISTED_MIME(type) (string_arr_has_str(blacklisted_mimes,type))
+
/*
* signal fired when an unknown stream is found. We create a new
* UNKNOWN streaminfo object.
unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
GstPlayBaseBin * play_base_bin)
{
- gchar *capsstr;
+ const gchar *type_name;
GstStreamInfo *info;
GstPlayBaseGroup *group;
- capsstr = gst_caps_to_string (caps);
- GST_DEBUG_OBJECT (play_base_bin, "don't know how to handle %s", capsstr);
- /* FIXME, g_message() ? */
- g_message ("don't know how to handle %s", capsstr);
+ type_name = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+ if (type_name && !IS_BLACKLISTED_MIME (type_name)) {
+ GstMessage *msg;
+ gchar *capsstr;
+
+ capsstr = gst_caps_to_string (caps);
+ GST_DEBUG_OBJECT (play_base_bin, "don't know how to handle %s", capsstr);
+ /* FIXME, g_message() ? */
+ g_message ("don't know how to handle %s", capsstr);
+ g_free (capsstr);
+
+ msg = gst_missing_decoder_message_new (GST_ELEMENT (play_base_bin), caps);
+ gst_element_post_message (GST_ELEMENT_CAST (play_base_bin), msg);
+ } else {
+ /* don't spew stuff to the terminal or send message if it's blacklisted */
+ GST_DEBUG_OBJECT (play_base_bin, "media type %s not handled on purpose, "
+ "not posting a missing-plugin message on the bus", type_name);
+ }
GROUP_LOCK (play_base_bin);
add_stream (group, info);
GROUP_UNLOCK (play_base_bin);
-
- g_free (capsstr);
}
/* add a streaminfo that indicates that the stream is handled by the
gchar *prot = gst_uri_get_protocol (sub_uri);
if (prot) {
- GST_ELEMENT_ERROR (play_base_bin, RESOURCE, FAILED,
+ GST_ELEMENT_ERROR (play_base_bin, CORE, MISSING_PLUGIN,
(_("No URI handler implemented for \"%s\"."), prot), (NULL));
g_free (prot);
} else
/* whoops, could not create the source element, dig a little deeper to
* figure out what might be wrong. */
if (prot) {
- GST_ELEMENT_ERROR (play_base_bin, RESOURCE, FAILED,
+ GstElement *this = GST_ELEMENT_CAST (play_base_bin);
+ GstMessage *msg;
+
+ msg = gst_missing_uri_source_message_new (this, prot);
+ gst_element_post_message (this, msg);
+
+ GST_ELEMENT_ERROR (play_base_bin, CORE, MISSING_PLUGIN,
(_("No URI handler implemented for \"%s\"."), prot), (NULL));
g_free (prot);
} else
GST_END_TEST;
+static GstElement *
+create_playbin (const gchar * uri)
+{
+ GstElement *playbin, *fakesink1, *fakesink2;
+
+ playbin = gst_element_factory_make ("playbin", "playbin");
+ fail_unless (playbin != NULL, "Failed to create playbin element");
+
+ fakesink1 = gst_element_factory_make ("fakesink", NULL);
+ fail_unless (fakesink1 != NULL, "Failed to create fakesink element #1");
+
+ fakesink2 = gst_element_factory_make ("fakesink", NULL);
+ fail_unless (fakesink2 != NULL, "Failed to create fakesink element #2");
+
+ /* make them behave like normal sinks, even if not needed for the test */
+ g_object_set (fakesink1, "sync", TRUE, NULL);
+ g_object_set (fakesink2, "sync", TRUE, NULL);
+
+ g_object_set (playbin, "video-sink", fakesink1, NULL);
+ g_object_set (playbin, "audio-sink", fakesink2, NULL);
+
+ g_object_set (playbin, "uri", uri, NULL);
+
+ return playbin;
+}
+
+GST_START_TEST (test_missing_urisource_handler)
+{
+ GstStructure *s;
+ GstMessage *msg;
+ GstElement *playbin;
+ GError *err = NULL;
+ GstBus *bus;
+
+ playbin = create_playbin ("chocchipcookie://withahint.of/cinnamon");
+
+ fail_unless_equals_int (gst_element_set_state (playbin, GST_STATE_READY),
+ GST_STATE_CHANGE_SUCCESS);
+ fail_unless_equals_int (gst_element_set_state (playbin, GST_STATE_PAUSED),
+ GST_STATE_CHANGE_FAILURE);
+
+ /* there should be at least a missing-plugin message on the bus now and an
+ * error message; the missing-plugin message should be first */
+ bus = gst_element_get_bus (playbin);
+
+ msg = gst_bus_poll (bus, GST_MESSAGE_ELEMENT | GST_MESSAGE_ERROR, -1);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "detail", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "detail"),
+ "chocchipcookie");
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "urisource");
+ gst_message_unref (msg);
+
+ msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, -1);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ERROR);
+
+ /* make sure the error is a CORE MISSING_PLUGIN one */
+ gst_message_parse_error (msg, &err, NULL);
+ fail_unless (err != NULL);
+ fail_unless (err->domain == GST_CORE_ERROR, "error has wrong error domain "
+ "%s instead of core-error-quark", g_quark_to_string (err->domain));
+ fail_unless (err->code == GST_CORE_ERROR_MISSING_PLUGIN, "error has wrong "
+ "code %u instead of GST_CORE_ERROR_MISSING_PLUGIN", err->code);
+ g_error_free (err);
+ gst_message_unref (msg);
+ gst_object_unref (bus);
+
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ gst_object_unref (playbin);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_missing_primary_decoder)
+{
+ GstStructure *s;
+ GstMessage *msg;
+ GstElement *playbin;
+ GError *err = NULL;
+ GstBus *bus;
+
+ playbin = create_playbin ("codec://");
+
+ fail_unless_equals_int (gst_element_set_state (playbin, GST_STATE_READY),
+ GST_STATE_CHANGE_SUCCESS);
+ fail_unless_equals_int (gst_element_set_state (playbin, GST_STATE_PAUSED),
+ GST_STATE_CHANGE_ASYNC);
+
+ /* there should soon be at least a missing-plugin message on the bus and an
+ * error message; the missing-plugin message should be first */
+ bus = gst_element_get_bus (playbin);
+
+ msg = gst_bus_poll (bus, GST_MESSAGE_ELEMENT | GST_MESSAGE_ERROR, -1);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ELEMENT);
+ fail_unless (msg->structure != NULL);
+ s = msg->structure;
+ fail_unless (gst_structure_has_name (s, "missing-plugin"));
+ fail_unless (gst_structure_has_field_typed (s, "type", G_TYPE_STRING));
+ fail_unless_equals_string (gst_structure_get_string (s, "type"), "decoder");
+ fail_unless (gst_structure_has_field_typed (s, "detail", GST_TYPE_CAPS));
+ gst_message_unref (msg);
+
+ msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, -1);
+ fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_ERROR);
+
+ /* make sure the error is a STREAM CODEC_NOT_FOUND one */
+ gst_message_parse_error (msg, &err, NULL);
+ fail_unless (err != NULL);
+ fail_unless (err->domain == GST_STREAM_ERROR, "error has wrong error domain "
+ "%s instead of stream-error-quark", g_quark_to_string (err->domain));
+ fail_unless (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND, "error has wrong "
+ "code %u instead of GST_STREAM_ERROR_CODEC_NOT_FOUND", err->code);
+ g_error_free (err);
+ gst_message_unref (msg);
+ gst_object_unref (bus);
+
+ gst_element_set_state (playbin, GST_STATE_NULL);
+ gst_object_unref (playbin);
+}
+
+GST_END_TEST;
+
+/*** redvideo:// source ***/
+
static guint
gst_red_video_src_uri_get_type (void)
{
{
}
+/*** codec:// source ***/
+
+static guint
+gst_codec_src_uri_get_type (void)
+{
+ return GST_URI_SRC;
+}
+static gchar **
+gst_codec_src_uri_get_protocols (void)
+{
+ static gchar *protocols[] = { "codec", NULL };
+
+ return protocols;
+}
+
+static const gchar *
+gst_codec_src_uri_get_uri (GstURIHandler * handler)
+{
+ return "codec://";
+}
+
+static gboolean
+gst_codec_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+ return (uri != NULL && g_str_has_prefix (uri, "codec:"));
+}
+
+static void
+gst_codec_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_codec_src_uri_get_type;
+ iface->get_protocols = gst_codec_src_uri_get_protocols;
+ iface->get_uri = gst_codec_src_uri_get_uri;
+ iface->set_uri = gst_codec_src_uri_set_uri;
+}
+
+static void
+gst_codec_src_init_type (GType type)
+{
+ static const GInterfaceInfo uri_hdlr_info = {
+ gst_codec_src_uri_handler_init, NULL, NULL
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &uri_hdlr_info);
+}
+
+#undef parent_class
+#define parent_class codec_src_parent_class
+
+typedef GstPushSrc GstCodecSrc;
+typedef GstPushSrcClass GstCodecSrcClass;
+
+GST_BOILERPLATE_FULL (GstCodecSrc, gst_codec_src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, gst_codec_src_init_type);
+
+static void
+gst_codec_src_base_init (gpointer klass)
+{
+ static const GstElementDetails details =
+ GST_ELEMENT_DETAILS ("Codec Src", "Source/Video", "yep", "me");
+ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-codec")
+ );
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_set_details (element_class, &details);
+}
+
+static GstFlowReturn
+gst_codec_src_create (GstPushSrc * src, GstBuffer ** p_buf)
+{
+ GstBuffer *buf;
+ GstCaps *caps;
+
+ buf = gst_buffer_new_and_alloc (20);
+ memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
+
+ caps = gst_caps_new_simple ("application/x-codec", NULL);
+ gst_buffer_set_caps (buf, caps);
+ gst_caps_unref (caps);
+
+ *p_buf = buf;
+ return GST_FLOW_OK;
+}
+
+static void
+gst_codec_src_class_init (GstCodecSrcClass * klass)
+{
+ GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+ pushsrc_class->create = gst_codec_src_create;
+}
+
+static void
+gst_codec_src_init (GstCodecSrc * src, GstCodecSrcClass * klass)
+{
+}
+
static gboolean
plugin_init (GstPlugin * plugin)
{
gst_red_video_src_get_type ())) {
return FALSE;
}
+ if (!gst_element_register (plugin, "codecsrc", GST_RANK_PRIMARY,
+ gst_codec_src_get_type ())) {
+ return FALSE;
+ }
return TRUE;
}
tcase_add_test (tc_chain, test_suburi_error_wrongproto);
tcase_add_test (tc_chain, test_suburi_error_invalidfile);
tcase_add_test (tc_chain, test_suburi_error_unknowntype);
+ tcase_add_test (tc_chain, test_missing_urisource_handler);
+ tcase_add_test (tc_chain, test_missing_primary_decoder);
+
+ /* one day we might also want to have the following checks:
+ * tcase_add_test (tc_chain, test_missing_secondary_decoder_one_fatal);
+ * tcase_add_test (tc_chain, test_missing_secondary_decoder_two_fatal);
+ * tcase_add_test (tc_chain, test_missing_secondary_decoder_two_with_preroll);
+ */
#endif
return s;