Skip to content
Snippets Groups Projects
xineinput.c 10.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* GStreamer
     * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Library General Public
     * License as published by the Free Software Foundation; either
     * version 2 of the License, or (at your option) any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Library General Public License for more details.
     *
     * 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.
     */
    
    #include <gst/gst.h>
    #include "gstxine.h"
    #include <xine/input_plugin.h>
    #include <xine/xine_internal.h>
    #include <xine/plugin_catalog.h>
    
    #define GST_TYPE_XINE_INPUT \
      (gst_xine_input_get_type())
    #define GST_XINE_INPUT(obj) \
      (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XINE_INPUT,GstXineInput))
    #define GST_XINE_INPUT_GET_CLASS(obj) \
      (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XINE_INPUT, GstXineInputClass))
    #define GST_XINE_INPUT_CLASS(klass) \
      (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XINE_INPUT,GstXineInputClass))
    #define GST_IS_XINE_INPUT(obj) \
      (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XINE_INPUT))
    
    Stefan Kost's avatar
    Stefan Kost committed
    #define GST_IS_XINE_INPUT_CLASS(klass) \
    
      (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XINE_INPUT))
    
    GType gst_xine_input_get_type (void);
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    typedef struct _GstXineInput GstXineInput;
    
    typedef struct _GstXineInputClass GstXineInputClass;
    
    struct _GstXineInput
    {
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      GstXine parent;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      GstPad *srcpad;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      input_plugin_t *input;
      gchar *location;
      guint blocksize;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    struct _GstXineInputClass
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      GstXineClass parent_class;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      plugin_node_t *plugin_node;
    
    };
    
    /** GstXineInput ***********************************************************/
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    enum
    {
    
    GST_BOILERPLATE (GstXineInput, gst_xine_input, GstXine, GST_TYPE_XINE);
    
    static void gst_xine_input_dispose (GObject * object);
    static void gst_xine_input_set_property (GObject * object, guint prop_id,
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        const GValue * value, GParamSpec * pspec);
    
    static void gst_xine_input_get_property (GObject * object, guint prop_id,
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        GValue * value, GParamSpec * pspec);
    
    static GstStateChangeReturn
    gst_xine_input_change_state (GstElement * element, GstStateChange transition);
    
    static void
    gst_xine_input_base_init (gpointer g_class)
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_class_init (GstXineInputClass * klass)
    
    {
      GstElementClass *element = GST_ELEMENT_CLASS (klass);
      GObjectClass *object = G_OBJECT_CLASS (klass);
    
      element->change_state = gst_xine_input_change_state;
    
      object->set_property = gst_xine_input_set_property;
      object->get_property = gst_xine_input_get_property;
      object->dispose = gst_xine_input_dispose;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
      g_object_class_install_property (object, ARG_LOCATION,
          g_param_spec_string ("location", "location", "location",
    
              NULL, G_PARAM_READWRITE));
    
    gst_xine_input_init (GstXineInput * xine, GstXineInputClass * g_class)
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_dispose (GObject * object)
    
    {
      GstXineInput *xine = GST_XINE_INPUT (object);
    
      g_free (xine->location);
      xine->location = NULL;
    
    
      GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_set_property (GObject * object, guint prop_id,
        const GValue * value, GParamSpec * pspec)
    
    {
      GstXineInput *xine = GST_XINE_INPUT (object);
    
      switch (prop_id) {
        case ARG_LOCATION:
          if (gst_element_get_state (GST_ELEMENT (xine)) != GST_STATE_NULL)
    
            g_free (xine->location);
    
          xine->location = g_strdup (g_value_get_string (value));
          break;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        default:
          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
          return;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_get_property (GObject * object, guint prop_id, GValue * value,
        GParamSpec * pspec)
    
    {
      GstXineInput *xine = GST_XINE_INPUT (object);
    
      switch (prop_id) {
        case ARG_LOCATION:
          g_value_set_string (value, xine->location);
          break;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        default:
          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
          return;
    
    #define BUFFER_SIZE 4096        /* FIXME: what size? */
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_get (GstPad * pad)
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      GstXineInput *xine =
          GST_XINE_INPUT (gst_object_get_parent (GST_OBJECT (pad)));
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
      /* FIXME: how does xine figure out EOS? */
      position = xine->input->get_current_pos (xine->input);
      if (position > 0 && position == xine->input->get_length (xine->input)) {
        gst_element_set_eos (GST_ELEMENT (xine));
        return GST_DATA (gst_event_new (GST_EVENT_EOS));
      }
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
      buf =
    
          gst_pad_alloc_buffer_and_set_caps (xine->srcpad, GST_BUFFER_OFFSET_NONE,
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
          xine->blocksize);
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      real_size =
          xine->input->read (xine->input, GST_BUFFER_DATA (buf),
          GST_BUFFER_MAXSIZE (buf));
    
      GST_BUFFER_SIZE (buf) = real_size;
      if (real_size < 0) {
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        GST_ELEMENT_ERROR (xine, RESOURCE, READ, (NULL), ("error %d reading data",
    
                real_size));
    
        gst_data_unref (GST_DATA (buf));
        return NULL;
      } else if (real_size == 0) {
        buf_element_t *element;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
        if (xine->input->get_capabilities (xine->input) & INPUT_CAP_BLOCK)
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
          element =
    
              xine->input->read_block (xine->input,
              gst_xine_get_stream (GST_XINE (xine))->audio_fifo, xine->blocksize);
    
        if (element == NULL) {
          /* FIXME: is this EOS? */
          gst_element_set_eos (GST_ELEMENT (xine));
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
          return GST_DATA (gst_event_new (GST_EVENT_EOS));
    
        } else {
          GST_BUFFER_SIZE (buf) = element->size;
          /* FIXME: put buf_element_t data in buffer */
          memcpy (GST_BUFFER_DATA (buf), element->mem, element->size);
          element->free_buffer (element);
        }
      }
      GST_BUFFER_OFFSET_END (buf) = xine->input->get_current_pos (xine->input);
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
    static GstStateChangeReturn
    gst_xine_input_change_state (GstElement * element, GstStateChange transition)
    
    {
      GstXineInput *xine = GST_XINE_INPUT (element);
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      input_class_t *input =
          (input_class_t *) GST_XINE_INPUT_GET_CLASS (xine)->plugin_node->
          plugin_class;
    
    
      switch (transition) {
        case GST_STATE_CHANGE_NULL_TO_READY:
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
          xine->input =
    
              input->get_instance (input, gst_xine_get_stream (GST_XINE (xine)),
              xine->location);
    
            return GST_STATE_CHANGE_FAILURE;
    
            return GST_STATE_CHANGE_FAILURE;
    
          xine->blocksize = xine->input->get_blocksize (xine->input);
          if (xine->blocksize == 0)
    
            xine->blocksize = BUFFER_SIZE;
    
        case GST_STATE_CHANGE_READY_TO_PAUSED:
    
        case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
    
        case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
    
        case GST_STATE_CHANGE_PAUSED_TO_READY:
    
        case GST_STATE_CHANGE_READY_TO_NULL:
    
          xine->input->dispose (xine->input);
          xine->input = NULL;
          break;
        default:
          GST_ERROR_OBJECT (element, "invalid state change");
          break;
      }
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
      return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
    
          (element), GST_STATE_CHANGE_SUCCESS);
    
    }
    
    /** GstXineInput subclasses ************************************************/
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    static GstStaticPadTemplate any_template = GST_STATIC_PAD_TEMPLATE ("src",
        GST_PAD_SRC,
        GST_PAD_ALWAYS,
        GST_STATIC_CAPS_ANY);
    
    static GstStaticPadTemplate cdda_template = GST_STATIC_PAD_TEMPLATE ("src",
        GST_PAD_SRC,
        GST_PAD_ALWAYS,
        GST_STATIC_CAPS ("audio/x-raw-int, "
    
            "endianness = (int) LITTLE_ENDIAN, "
            "signed = (boolean) true, "
            "width = (int) 16, "
            "depth = (int) 16, " "rate = (int) 44100, " "channels = (int) 2")
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        );
    
    
    static void
    gst_xine_input_subclass_init (gpointer g_class, gpointer class_data)
    {
      GstXineInputClass *xine_class = GST_XINE_INPUT_CLASS (g_class);
      GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      GstElementDetails details = GST_ELEMENT_DETAILS (NULL,
          "Source",
          NULL,
          "Benjamin Otte <otte@gnome.org>");
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
      xine_class->plugin_node = class_data;
      input = (input_class_t *) xine_class->plugin_node->plugin_class;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      details.longname =
          g_strdup_printf ("%s xine input", input->get_identifier (input));
    
      details.description = g_strdup_printf ("%s", input->get_description (input));
      gst_element_class_set_details (element_class, &details);
      g_free (details.longname);
      g_free (details.description);
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
      /* FIXME: this is pretty hackish, anyone knows a better idea (xine doesn't) */
    
      if (strcmp (input->get_identifier (input), "cdda") == 0) {
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        gst_element_class_add_pad_template (element_class,
    
            gst_static_pad_template_get (&cdda_template));
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        gst_element_class_add_pad_template (element_class,
    
            gst_static_pad_template_get (&any_template));
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_sub_init (GTypeInstance * instance, gpointer g_class)
    
    {
      GstElementClass *klass = GST_ELEMENT_GET_CLASS (instance);
      GstXineInput *xine = GST_XINE_INPUT (instance);
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      xine->srcpad =
          gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
    
              "src"), "src");
    
      gst_pad_set_get_function (xine->srcpad, gst_xine_input_get);
      gst_element_add_pad (GST_ELEMENT (xine), xine->srcpad);
    }
    
    gboolean
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    gst_xine_input_init_plugin (GstPlugin * plugin)
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      GTypeInfo plugin_info = {
    
        sizeof (GstXineInputClass),
        NULL,
        NULL,
        gst_xine_input_subclass_init,
        NULL,
        NULL,
        sizeof (GstXineInput),
        0,
        gst_xine_input_sub_init,
      };
      plugin_node_t *node;
      GstXineClass *klass;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
      node = xine_list_first_content (klass->xine->plugin_catalog->input);
      while (node) {
        gchar *plugin_name = g_strdup_printf ("xinesrc_%s", node->info->id);
        gchar *type_name = g_strdup_printf ("GstXineInput%s", node->info->id);
        GType type;
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        type =
    
            g_type_register_static (GST_TYPE_XINE_INPUT, type_name, &plugin_info,
            0);
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
        if (!gst_element_register (plugin, plugin_name, GST_RANK_MARGINAL, type)) {
    
          g_free (plugin_name);
          return FALSE;
        }
        g_free (plugin_name);
    
        node = xine_list_next_content (klass->xine->plugin_catalog->input);
      }
    
    
    Thomas Vander Stichele's avatar
    Thomas Vander Stichele committed
      g_type_class_unref (klass);