[gstreamer-bugs] [Bug 357026] New: How can be a plugin based on pipeline made?

GStreamer (bugzilla.gnome.org) bugzilla-daemon at bugzilla.gnome.org
Thu Sep 21 00:19:25 PDT 2006


Do not reply to this via email (we are currently unable to handle email
responses and they get discarded).  You can add comments to this bug at
http://bugzilla.gnome.org/show_bug.cgi?id=357026

GStreamer | gst-plugins | Ver: 0.10.4

           Summary: How can be a plugin based on pipeline made?
           Product: GStreamer
           Version: 0.10.4
          Platform: Other
        OS/Version: All
            Status: UNCONFIRMED
          Severity: normal
          Priority: Normal
         Component: gst-plugins
        AssignedTo: gstreamer-bugs at lists.sourceforge.net
        ReportedBy: spk9012 at gmail.com
         QAContact: gstreamer-bugs at lists.sourceforge.net
     GNOME version: 2.5/2.6
   GNOME milestone: Unspecified


Please describe the problem:
I'm trying to make a plugin to record A/V that is similar to playbin based on
pipeline.

At first, I made a simple plugin but it's not working while the plugin has
registerd in the gstreamer registry. (It's can be checked by gst-inspect)

Please show my source code and reply why it's not working.

###################### Header File ##########################################
#ifndef __GST_CAMCORDER_BIN_H__
#define __GST_CAMCORDER_BIN_H__

#include <gst/gst.h>

G_BEGIN_DECLS

/* #defines don't like whitespacey bits */
#define GST_TYPE_CAMCORDER_BIN \
  (gst_camcorder_bin_get_type())
#define GST_CAMCORDER_BIN(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMCORDER_BIN,GstCamcorderBin))
#define GST_CAMCORDER_BIN_CLASS(klass) \
 
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMCORDER_BIN,GstCamcorderBinClass))
#define GST_IS_CAMCORDER_BIN(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMCORDER_BIN))
#define GST_IS_CAMCORDER_BIN_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMCORDER_BIN))

typedef struct _GstCamcorderBin      GstCamcorderBin;
typedef struct _GstCamcorderBinClass GstCamcorderBinClass;

struct _GstCamcorderBin
{
  GstPipeline    pipeline;

  GstElement *v_enc_bin;
  GstElement *video_src, *video_sink;

  /* default from make_element */
  GstPad *sinkpad, *srcpad;
};

struct _GstCamcorderBinClass 
{
  GstPipelineClass parent_class;
};

GType gst_camcorder_bin_get_type (void);

G_END_DECLS

#endif /* __GST_CAMCORDER_BIN_H__ */

#############################################################################
###################### Source File ##########################################


#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gst/gst.h>

#include "gstcamcorderbin.h"

GST_DEBUG_CATEGORY_STATIC (gst_camcorder_bin_debug);
#define GST_CAT_DEFAULT gst_camcorder_bin_debug

#define VOLUME_MAX_DOUBLE 4.0
#ifndef GST_HAVE_GLIB_2_8

#define _gst_gvalue_set_gstobject(gvalue,obj)  \
      if (obj != NULL) {                       \
        gst_object_ref (obj);                  \
        g_value_set_object (gvalue, obj);      \
        g_object_unref (obj);                  \
      } else {                                 \
        g_value_set_object (gvalue, NULL);     \
      }
#else
#define _gst_gvalue_set_gstobject(gvalue,obj)  \
      g_value_set_object (gvalue, obj);
#endif

/* Filter signals and args */
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

enum
{
  ARG_0,
  ARG_VIDEO_SRC,
};

static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("ANY")
    );

static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("ANY")
    );

GST_BOILERPLATE (GstCamcorderBin, gst_camcorder_bin, GstElement,
    GST_TYPE_PIPELINE);

static void gst_camcorder_bin_dispose (GObject * object);

static void gst_camcorder_bin_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_camcorder_bin_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);

static GstStateChangeReturn gst_camcorder_bin_change_state (GstElement *
element,
    GstStateChange transition);

static void
gst_camcorder_bin_base_init (gpointer gclass)
{
  static GstElementDetails element_details = {
    "camcorder Bin",
    "Generic/Bin/camcorder",
    "A/V Recording from devices and streams",
    "Junghak Kim <kjh5 at samsung.com>"
  };
  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);

  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&src_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&sink_factory));
  gst_element_class_set_details (element_class, &element_details);
}

/* initialize the plugin's class */
static void
gst_camcorder_bin_class_init(GstCamcorderBinClass* klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;

  gobject_class->set_property = gst_camcorder_bin_set_property;
  gobject_class->get_property = gst_camcorder_bin_get_property;

  g_object_class_install_property (gobject_class, ARG_VIDEO_SRC,
    g_param_spec_object ("video-src", "Video Source",
    "the video input element to use (NULL = default sink)",
    GST_TYPE_ELEMENT, G_PARAM_READWRITE));

  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_camcorder_bin_dispose);

  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_camcorder_bin_change_state);
}

static void
gst_camcorder_bin_init (GstCamcorderBin* camcorder_bin,
    GstCamcorderBinClass* gclass)
{
  camcorder_bin->v_enc_bin = NULL;

  camcorder_bin->video_src = NULL;
  camcorder_bin->video_sink = NULL;
}

static void
gst_camcorder_bin_clean_elements(GstCamcorderBin* camcorder_bin)
{
  if (camcorder_bin->v_enc_bin)
    gst_object_unref(camcorder_bin->v_enc_bin);
  if (camcorder_bin->video_src)
    gst_object_unref(camcorder_bin->video_src);
  if (camcorder_bin->video_sink)
    gst_object_unref(camcorder_bin->video_sink);
}

static void
gst_camcorder_bin_dispose (GObject * object)
{
  GstCamcorderBin *camcorder_bin;

  camcorder_bin = GST_CAMCORDER_BIN(object);
  gst_camcorder_bin_clean_elements(camcorder_bin);

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
gst_camcorder_bin_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstCamcorderBin *camcorder_bin = NULL;

  g_return_if_fail (GST_IS_CAMCORDER_BIN (object));

  camcorder_bin = GST_CAMCORDER_BIN (object);

  switch (prop_id) {
    case ARG_VIDEO_SRC:
      if (camcorder_bin->video_src != NULL)
      {
        gst_object_unref (camcorder_bin->video_src);
      }
      camcorder_bin->video_src = g_value_get_object (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_camcorder_bin_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstCamcorderBin *camcorder_bin = NULL;

  g_return_if_fail (GST_IS_CAMCORDER_BIN (object));

  camcorder_bin = GST_CAMCORDER_BIN (object);

  switch (prop_id) {
    case ARG_VIDEO_SRC:
      _gst_gvalue_set_gstobject (value, camcorder_bin->video_src);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static GstElement*
gen_video_elements(GstCamcorderBin* camcorder_bin)
{
  GstPad *pad;
  GstCaps* caps;

  if (camcorder_bin->v_enc_bin != NULL)
    return camcorder_bin->v_enc_bin;

  camcorder_bin->v_enc_bin = gst_bin_new ("v_enc_bin");

  if (camcorder_bin->video_src == NULL)
  {
    camcorder_bin->video_src = gst_element_factory_make ("videotestsrc",
"videosrc");
    if (camcorder_bin->video_src == NULL)
    {
      g_printf("%s(%d): Both v4lsrc and videotestsrc elements are missing.\n",
__FILE__, __LINE__);
      goto video_err_handler;
    }
    g_object_set(G_OBJECT(camcorder_bin->video_src), "num-buffers", 250, NULL);
  }
  gst_element_set_state (camcorder_bin->video_src, GST_STATE_READY);

  camcorder_bin->video_sink = gst_element_factory_make("sdlvideosink",
"video_sink");
  if (camcorder_bin->video_sink == NULL);
  {
    g_printf("%s(%d): Failed to make a sdlvideosink element.\n", __FILE__,
__LINE__);
    goto video_err_handler;
  }
  gst_element_set_state (camcorder_bin->video_sink, GST_STATE_READY);

  gst_bin_add_many(GST_BIN(camcorder_bin->v_enc_bin),
    camcorder_bin->video_src,
    camcorder_bin->video_sink,
    NULL);

  gst_element_link(camcorder_bin->video_src, camcorder_bin->video_sink);

  gst_element_set_state (camcorder_bin->v_enc_bin, GST_STATE_READY);

  return camcorder_bin->v_enc_bin;

video_err_handler:
  gst_camcorder_bin_clean_elements(camcorder_bin);
  return NULL;
}

/* chain function
 * this function does the actual processing
 */
static GstFlowReturn
gst_camcorder_bin_chain (GstPad * pad, GstBuffer * buf)
{
  GstCamcorderBin *camcorder_bin;

  camcorder_bin = GST_CAMCORDER_BIN (GST_OBJECT_PARENT (pad));

  /* just push out the incoming buffer without touching it */
  return gst_pad_push (camcorder_bin->srcpad, buf);
}

static gboolean
gst_camcorder_bin_link(GstCamcorderBin* camcorder_bin)
{
  if (gen_video_elements(camcorder_bin) == NULL)
  {
    g_printf("%s(%d): Failed to create a v_enc_bin.\n", __FILE__, __LINE__);
    return FALSE;
  }

  return TRUE;
}

static GstStateChangeReturn
gst_camcorder_bin_change_state (GstElement * element, GstStateChange
transition)
{
  GstStateChangeReturn ret;
  GstCamcorderBin *camcorder_bin;

  camcorder_bin = GST_CAMCORDER_BIN (element);

  switch (transition)
  {
  case GST_STATE_CHANGE_NULL_TO_READY:
        g_printf("@%s(%d): The state is in GST_STATE_CHANGE_NULL_TO_READY.\n",
__FILE__, __LINE__);
    if (!gst_camcorder_bin_link(camcorder_bin))
      return GST_STATE_CHANGE_FAILURE;
    break;

  case GST_STATE_CHANGE_READY_TO_NULL:
    g_printf("@%s(%d): The state is in GST_STATE_CHANGE_READY_TO_NULL.\n",
__FILE__, __LINE__);
    gst_camcorder_bin_clean_elements(camcorder_bin);
    break;

  case GST_STATE_CHANGE_READY_TO_PAUSED:
    g_printf("@%s(%d): The state is in GST_STATE_CHANGE_READY_TO_PAUSED.\n",
__FILE__, __LINE__);
    break;

  case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
    g_printf("@%s(%d): The state is in GST_STATE_CHANGE_PLAYING_TO_PAUSED.\n",
__FILE__, __LINE__);
    gst_element_set_state (camcorder_bin->v_enc_bin, GST_STATE_PAUSED);
    break;

  case GST_STATE_CHANGE_PAUSED_TO_READY:
    g_printf("@%s(%d): The state is in GST_STATE_CHANGE_PAUSED_TO_READY.\n",
__FILE__, __LINE__);
    if (camcorder_bin->v_enc_bin != NULL)
    {
      gst_camcorder_bin_clean_elements(camcorder_bin);
    }
    break;

  default:
    break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      break;

    case GST_STATE_CHANGE_PAUSED_TO_READY:
      break;

    default:
      break;
  }

  return ret;
}

static gboolean
plugin_init (GstPlugin * plugin)
{
  /* exchange the strings 'plugin' and 'Template plugin' with your
   * plugin name and description */
  GST_DEBUG_CATEGORY_INIT (gst_camcorder_bin_debug, "camcorderbin",
      0, "camcorder bin");

  return gst_element_register (plugin, "camcorderbin",
      GST_RANK_NONE, GST_TYPE_CAMCORDER_BIN);
}

GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "camcorderbin",
    "camcorder bin",
    plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")


Steps to reproduce:
1. make; make install
2. gst-launch camcorderbin
3. You can show the messages below.
Setting pipeline to PAUSED ...
@gstcamcorderbin.c(271): The state is in GST_STATE_CHANGE_NULL_TO_READY.
gstcamcorderbin.c(213): Failed to make a sdlvideosink element.

(gst-launch-0.10:14717): GStreamer-CRITICAL **:
Trying to dispose element videosrc, but it is not in the NULL state.
You need to explicitly set elements to the NULL state before
dropping the final reference, to allow them to clean up.

gstcamcorderbin.c(253): Failed to create a v_enc_bin.
ERROR: Pipeline doesn't want to pause.
Setting pipeline to NULL ...
FREEING pipeline ...


Actual results:


Expected results:


Does this happen every time?


Other information:


-- 
Configure bugmail: http://bugzilla.gnome.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.




More information about the Gstreamer-bugs mailing list