gst/playback/: Post missing-plugin messages on the bus for missing sources and missin...
authorTim-Philipp Müller <tim@centricular.net>
Tue, 9 Jan 2007 14:33:24 +0000 (14:33 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Tue, 9 Jan 2007 14:33:24 +0000 (14:33 +0000)
Original commit message from CVS:
* gst/playback/Makefile.am:
* gst/playback/gstplaybasebin.c: (string_arr_has_str),
(unknown_type), (setup_subtitle), (gen_source_element):
* gst/playback/gstplaybin.c: (plugin_init):
Post missing-plugin messages on the bus for missing sources and
missing decoders/demuxers/depayloaders; fix error code used when
we're missing an URI handler source; for media types that we are not
handling on purpose at the moment, don't print "don't know how to
handle xyz" messages to the terminal or post missing-plugin
messages on the bus.
* tests/check/elements/playbin.c: (create_playbin),
(GST_START_TEST), (gst_codec_src_uri_get_type),
(gst_codec_src_uri_get_protocols), (gst_codec_src_uri_get_uri),
(gst_codec_src_uri_set_uri), (gst_codec_src_uri_handler_init),
(gst_codec_src_init_type), (gst_codec_src_base_init),
(gst_codec_src_create), (gst_codec_src_class_init),
(gst_codec_src_init), (plugin_init), (playbin_suite):
Add some tests for the missing-plugin stuff.

ChangeLog
gst/playback/Makefile.am
gst/playback/gstplaybasebin.c
gst/playback/gstplaybin.c
tests/check/elements/playbin.c

index 409c77d..e4ed9c5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
 2007-01-09  Tim-Philipp Müller  <tim at centricular dot net>
 
+       * gst/playback/Makefile.am:
+       * gst/playback/gstplaybasebin.c: (string_arr_has_str),
+       (unknown_type), (setup_subtitle), (gen_source_element):
+       * gst/playback/gstplaybin.c: (plugin_init):
+         Post missing-plugin messages on the bus for missing sources and
+         missing decoders/demuxers/depayloaders; fix error code used when
+         we're missing an URI handler source; for media types that we are not
+         handling on purpose at the moment, don't print "don't know how to
+         handle xyz" messages to the terminal or post missing-plugin
+         messages on the bus.
+
+       * tests/check/elements/playbin.c: (create_playbin),
+       (GST_START_TEST), (gst_codec_src_uri_get_type),
+       (gst_codec_src_uri_get_protocols), (gst_codec_src_uri_get_uri),
+       (gst_codec_src_uri_set_uri), (gst_codec_src_uri_handler_init),
+       (gst_codec_src_init_type), (gst_codec_src_base_init),
+       (gst_codec_src_create), (gst_codec_src_class_init),
+       (gst_codec_src_init), (plugin_init), (playbin_suite):
+         Add some tests for the missing-plugin stuff.
+
+2007-01-09  Tim-Philipp Müller  <tim at centricular dot net>
+
        * configure.ac:
        * gst-libs/gst/Makefile.am:
        * gst-libs/gst/utils/Makefile.am:
index e154b94..c395504 100644 (file)
@@ -18,7 +18,9 @@ libgstplaybin_la_SOURCES = \
 nodist_libgstplaybin_la_SOURCES = $(built_sources)
 libgstplaybin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
 libgstplaybin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstplaybin_la_LIBADD = $(GST_LIBS)
+libgstplaybin_la_LIBADD = \
+       $(top_builddir)/gst-libs/gst/utils/libgstbaseutils-@GST_MAJORMINOR@.la \
+       $(GST_LIBS)
 
 libgstdecodebin_la_SOURCES = gstdecodebin.c
 nodist_libgstdecodebin_la_SOURCES = $(built_sources)
index 7e2ef7d..52a34a1 100644 (file)
@@ -27,6 +27,8 @@
 #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
 
@@ -911,6 +913,27 @@ add_stream (GstPlayBaseGroup * group, GstStreamInfo * info)
   }
 }
 
+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.
@@ -919,14 +942,28 @@ static void
 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);
 
@@ -939,8 +976,6 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
   add_stream (group, info);
 
   GROUP_UNLOCK (play_base_bin);
-
-  g_free (capsstr);
 }
 
 /* add a streaminfo that indicates that the stream is handled by the
@@ -1386,7 +1421,7 @@ unknown_uri:
     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
@@ -1503,7 +1538,13 @@ no_source:
     /* 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
index 67e3ef4..5f8edaa 100644 (file)
 #include <gst/gst.h>
 
 #include <gst/gst-i18n-plugin.h>
+#include <gst/utils/base-utils.h>
 
 #include "gstplaybasebin.h"
 
@@ -1879,6 +1880,8 @@ plugin_init (GstPlugin * plugin)
 {
   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin", 0, "play bin");
 
+  gst_base_utils_init ();
+
 #ifdef ENABLE_NLS
   GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
       LOCALEDIR);
index 4cebbe2..29de2a1 100644 (file)
@@ -161,6 +161,134 @@ GST_START_TEST (test_suburi_error_wrongproto)
 
 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)
 {
@@ -268,6 +396,109 @@ gst_red_video_src_init (GstRedVideoSrc * src, GstRedVideoSrcClass * klass)
 {
 }
 
+/*** 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)
 {
@@ -275,6 +506,10 @@ 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;
 }
 
@@ -300,6 +535,14 @@ playbin_suite (void)
   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;