天天看點

gstreamer實作sink插件的代碼,及無法結束的問題

同僚寫了一個 gstreamer插件,去掉顯示之後,整個流不運作。吾視之,看不出問題。猜測是插件類型不對,于是改寫了一個sink插件,試之,流運作了。然後,有一個問題沒有解決:

如果是播放檔案,檔案結束後,無法結束(即使得GstBus收到GST_MESSAGE_EOS消息)。

雖然有此嚴重問題,整個系統運作起來了。這個問題以後看看怎麼解決。這裡把代碼共享出來,希望能給朋友們們帶來檔案。

  • 頭檔案
#ifndef __GH_GSTSINK_H__
#define __GH_GSTSINK_H__
 
#include <gst/base/gstbasesink.h>
#include <gst/video/video.h>
 
 
#define GH_GSTSINK_NAME "gh_gstsink"
 
/* Package and library details required for plugin_init */
#define PACKAGE         GH_GSTSINK_NAME
#define VERSION         "1.0"
#define LICENSE         "Proprietary"
#define DESCRIPTION     "wuxi sink"
#define BINARY_PACKAGE  "wuxi sink"
#define URL             "http://wuxi.com/"
 
 
G_BEGIN_DECLS
 
/* Standard boilerplate stuff */
typedef struct _GhGstSink GhGstSink;
typedef struct _GhGstSinkClass GhGstSinkClass;
 
/* Standard boilerplate stuff */
#define GST_TYPE_GHGSTSINK            (gh_gstsink_get_type())
#define GST_GHGSTSINK(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GHGSTSINK,GhGstSink))
#define GST_GHGSTSINK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GHGSTSINK,GhGstSinkClass))
#define GST_GHGSTSINK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_GHGSTSINK, GhGstSinkClass))
#define GST_IS_GHGSTSINK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GHGSTSINK))
#define GST_IS_GHGSTSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GHGSTSINK))
#define GST_GHGSTSINK_CAST(obj)       ((GhGstSink *)(obj))
 
struct _GhGstSink
{
  GstBaseSink base_trans;
 
  //when i received a eos, how to end ? 
  int isEOS;
 
};
 
// Boiler plate stuff
struct _GhGstSinkClass
{
  GstBaseSinkClass parent_class;
 
  //gint (*eos)(GhGstSink *sink);
  //gint (*signal_action)(GhGstSink *sink);
};
 
GType gh_gst_sink_get_type (void);
 
G_END_DECLS
 
#endif /* __GH_GSTSINK_H__ */      
  • 代碼
#include <string.h>
#include <string>
#include <fstream>
 
#include "gh_kit.h"
#include "gh_gstsink.h"
 
GST_DEBUG_CATEGORY_STATIC (gh_gstsink_debug);
#define GST_CAT_DEFAULT gh_gstsink_debug
 
/* Enum to identify properties */
enum
{
  PROP_0,
  PROP_UNIQUE_ID
};
 
/* Default values for properties */
#define DEFAULT_UNIQUE_ID       15
#define DEFAULT_PROCESSING_WIDTH    640
#define DEFAULT_PROCESSING_HEIGHT   480
#define DEFAULT_PROCESS_FULL_FRAME  TRUE
#define DEFAULT_GPU_ID          0
 
static GstStaticPadTemplate gh_gstsink_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("WUXI"));
 
static GstStaticPadTemplate gh_gstsink_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("WUXI"));
 
/* Define our element type. Standard GObject/GStreamer boilerplate stuff */
#define gh_gstsink_parent_class parent_class
G_DEFINE_TYPE (GhGstSink, gh_gstsink, GST_TYPE_BASE_SINK);
 
static void gh_gstsink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);
static void gh_gstsink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);
 
static gboolean gh_gstsink_start (   GstBaseSink * basesink);
static gboolean gh_gstsink_stop (    GstBaseSink * basesink);
 
/**
GstEvent *gst_event_new_eos (void);
Create a new EOS event. The eos event can only travel downstream synchronized with the buffer flow. Elements that receive the EOS event on a pad can return GST_FLOW_EOS as a GstFlowReturn when data after the EOS event arrives.
The EOS event will travel down to the sink elements in the pipeline which will then post the GST_MESSAGE_EOS on the bus after they have finished playing any buffered data.
When all sinks have posted an EOS message, an EOS message is forwarded to the application.
The EOS event itself will not cause any state transitions of the pipeline.
Events are usually created with gst_event_new_*() which takes event-type specific parameters as arguments. To send an event application will usually use gst_element_send_event() and elements will use gst_pad_send_event() or gst_pad_push_event(). The event should be unreffed with gst_event_unref() if it has not been sent.
gst_event_type_get_flags(), GST_EVENT_IS_UPSTREAM, GST_EVENT_IS_DOWNSTREAM, and GST_EVENT_IS_SERIALIZED. 
gst_collect_pads_event
*/
 
//所有sinks發出了EOS消息,EOS就會轉發給應用。我這裡發出了,為什麼還沒結束?
//GST_MESSAGE_EOS
static gboolean gh_gstsink_event(GstBaseSink *sink, GstEvent *event)
{
    GstElement* element = (GstElement*)sink;
    GhGstSink*  ghsink  = (GhGstSink*) sink;
 
    switch(event-> type)
    {
        case GST_EVENT_EOS:
            //GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
            //parent_class->change_state(element, transition);
            GH_LOG_TEXT("GST_EVENT_EOS");
            gst_element_set_state(element, GST_STATE_NULL);
            //gst_event_new_eos();
            //gst_send_event(
            ghsink->isEOS = 1;
            gst_element_send_event(element, event);
            gst_pad_send_event ((GstPad*)element, event);
            return TRUE;
 
        case GST_EVENT_FLUSH_START:
        case GST_EVENT_FLUSH_STOP:
        default:
            break;
    }
    return TRUE;
}
 
static GstFlowReturn gh_gstsink_render(GstBaseSink *sink, GstBuffer *buffer)
{
    GhGstSink*  ghsink  = (GhGstSink*) sink;
    return ghsink->isEOS ? GST_FLOW_EOS : GST_FLOW_OK;
}
 
 
static GstStateChangeReturn gh_gstsink_change_state(GstElement* element, GstStateChange transition)
{
  GstElementClass *oclass;
  GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
  GhGstSink*  ghsink  = (GhGstSink*) element;
 
 
  g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);
 
  oclass = GST_ELEMENT_GET_CLASS (element);
 
  if (oclass->set_state && ghsink->isEOS)
  {
     (oclass->set_state) (element, GST_STATE_NULL);
  }
  
  return result;
}
 
 
/* Install properties, set sink and src pad capabilities, override the required
 * functions of the base class, These are common to all instances of the
 * element.
 */
static void gh_gstsink_class_init (GhGstSinkClass * klass)
{
  GObjectClass     *gobject_class;
  GstElementClass  *gstelement_class;
  GstBaseSinkClass *gstbasesink_class;
 
  gobject_class     = (GObjectClass *) klass;
  gstelement_class  = (GstElementClass *) klass;
  gstbasesink_class = (GstBaseSinkClass *) klass;
 
  /* Overide base class functions */
  gobject_class->set_property     = GST_DEBUG_FUNCPTR (gh_gstsink_set_property);
  gobject_class->get_property     = GST_DEBUG_FUNCPTR (gh_gstsink_get_property);
 
  gstbasesink_class->render       = GST_DEBUG_FUNCPTR (gh_gstsink_render);
  gstbasesink_class->start        = GST_DEBUG_FUNCPTR (gh_gstsink_start);
  gstbasesink_class->stop         = GST_DEBUG_FUNCPTR (gh_gstsink_stop);
  gstbasesink_class->event        = GST_DEBUG_FUNCPTR (gh_gstsink_event);
 
  //gstelement_class->change_state  = GST_DEBUG_FUNCPTR (gh_gstsink_change_state);
 
  //klass->eos                      = gh_gstsink_eos_cb;
  //guint eossignal_id = 0;
  //eossignal_id = g_signal_new ("eos", G_TYPE_FROM_CLASS(klass),
  //        G_SIGNAL_RUN_LAST,
  //        G_STRUCT_OFFSET (GhGstSinkClass, eos), NULL, NULL, NULL, G_TYPE_INT, 0, G_TYPE_NONE);
 
  //klass->signal_action  = gh_gstsink_callback;
  //eossignal_id = g_signal_new ("act", G_TYPE_FROM_CLASS (klass),
  //        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
  //        G_STRUCT_OFFSET (GhGstSinkClass, act), NULL, NULL, NULL, G_TYPE_INT, 0, G_TYPE_NONE);
 
  /* Install properties */
  g_object_class_install_property (gobject_class, PROP_UNIQUE_ID,
      g_param_spec_uint ("unique-id",
          "Unique ID",
          "Unique ID for the element. Can be used to identify output of the element", 0, G_MAXUINT, DEFAULT_UNIQUE_ID, (GParamFlags)
          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
 
 
  /* Set sink and src pad capabilities */
  //gst_element_class_add_pad_template (gstelement_class,
  //    gst_static_pad_template_get (&gh_gstsink_src_template));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gh_gstsink_sink_template));
 
  /* Set metadata describing the element */
  gst_element_class_set_details_simple (gstelement_class,
      "GhGstSink plugin",
      "GhGstSink Plugin",
      "wuxi data sink",
      URL
      URL);
}
 
static void gh_gstsink_init (GhGstSink * ghsink)
{
   ghsink->isEOS = 0;
}
 
/* Function called when a property of the element is set. Standard boilerplate.
 */
static void gh_gstsink_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GhGstSink *ghsink = GST_GHGSTSINK (object);
  switch (prop_id)
  {
    case PROP_UNIQUE_ID:
      ghsink->unique_id = g_value_get_uint (value);
      break;
 
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
 
/* Function called when a property of the element is requested. Standard
 * boilerplate.
 */
static void gh_gstsink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GhGstSink *ghsink = GST_GHGSTSINK (object);
 
  switch (prop_id)
  {
    case PROP_UNIQUE_ID:
      g_value_set_uint (value, ghsink->unique_id);
      break;
 
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
 
/**
 * Initialize all resources and start the output thread
 */
static gboolean gh_gstsink_start (GstBaseSink * basesink)
{
  GH_LOG_HERE();
  return TRUE;
}
 
/**
 * Stop the output thread and free up all the resources
 */
static gboolean gh_gstsink_stop (GstBaseSink * basesink)
{
  GH_LOG_HERE();
  return TRUE;
}
 
/**
 * Boiler plate for registering a plugin and an element.
 */
static gboolean ghsink_plugin_init (GstPlugin * plugin)
{
  GST_DEBUG_CATEGORY_INIT (gh_gstsink_debug, GH_GSTSINK_NAME, 0,
      "ghgstsink plugin");
 
  return gst_element_register (plugin, GH_GSTSINK_NAME, GST_RANK_PRIMARY,
      GST_TYPE_GHGSTSINK);
}
 
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    ghsink,
    DESCRIPTION, ghsink_plugin_init, VERSION, LICENSE, BINARY_PACKAGE, URL)
  GST_TYPE_GHGSTSINK);
}
 
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    ghsink,
    DESCRIPTION, ghsink_plugin_init, VERSION, LICENSE, BINARY_PACKAGE, URL)
      

繼續閱讀