diff -r 3219eb5401c0 -r aa1f309ec686 gmyth-stream/gmemcoder/src/gmencoder.c --- a/gmyth-stream/gmemcoder/src/gmencoder.c Mon Apr 23 21:05:21 2007 +0100 +++ b/gmyth-stream/gmemcoder/src/gmencoder.c Tue May 01 17:03:38 2007 +0100 @@ -2,6 +2,9 @@ #include "config.h" #endif +#include +#include +#include #include #include #include @@ -13,6 +16,22 @@ typedef struct _GMencoderPrivate GMencoderPrivate; +typedef struct _SetupInfo SetupInfo; + +struct _SetupInfo +{ + gchar* video_encode; + gchar* mux_name; + gchar** video_encode_prop; + gdouble video_fps; + gdouble video_rate; + guint video_width; + guint video_height; + gchar* audio_encode; + gchar** audio_encode_prop; + guint audio_rate; +}; + struct _GMencoderPrivate { @@ -21,10 +40,13 @@ GstElement *vbin; GstElement *sink; gboolean ready; + SetupInfo *info; + GstClockTime videot; + GstClockTime audiot; + gint fd; }; enum { - READY, PAUSED, PLAYING, STOPED, @@ -38,13 +60,11 @@ static void g_mencoder_dispose (GObject *object); static void g_mencoder_finalize (GObject *object); static GstElement* - _create_audio_bin (GMencoder *self, - const gchar* encode, - gchar** encode_prop, - gint rate); + _create_audio_bin (const gchar* encode, + gchar** encode_prop, + gint rate); static GstElement* - _create_video_bin (GMencoder* self, - const gchar* encode, + _create_video_bin (const gchar* encode, gchar** encode_prop, gdouble fps, gint rate, @@ -63,6 +83,24 @@ GstPad* pad, GstCaps* caps, gpointer user_data); +static void _close_output (GMencoder *self); +static void _open_output (GMencoder *self, + const gchar* uri); +static GstElement* _create_source (const gchar* uri); +static GstElement*_create_pipeline (GMencoder *self, + const gchar* video_encode, + const gchar* mux_name, + gchar** video_encode_prop, + gdouble video_fps, + gdouble video_rate, + guint video_width, + guint video_height, + const gchar* audio_encode, + gchar** audio_encode_prop, + guint audio_rate); + + + static guint g_mencoder_signals[LAST_SIGNAL] = { 0 }; @@ -81,14 +119,6 @@ object_class->dispose = g_mencoder_dispose; object_class->finalize = g_mencoder_finalize; - g_mencoder_signals[READY] = - g_signal_new ("ready", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - g_mencoder_signals[PAUSED] = g_signal_new ("paused", G_OBJECT_CLASS_TYPE (object_class), @@ -134,6 +164,8 @@ static void g_mencoder_init (GMencoder *self) { + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + priv->info = g_new0 (SetupInfo, 1); } static void @@ -144,6 +176,7 @@ static void g_mencoder_finalize (GObject *object) { + //TODO: clear vars g_mencoder_close_stream (G_MENCODER (object)); } @@ -153,6 +186,7 @@ return g_object_new (G_TYPE_MENCODER, NULL); } + static void _obj_set_prop (GObject *obj, const gchar *prop_name, @@ -167,8 +201,6 @@ g_value_init (&v, G_TYPE_STRING); g_value_set_string (&v, prop_val); - g_debug ("PROP [%s] VAL [%s]", prop_name, prop_val); - s = g_object_class_find_property (k, prop_name); if (s == NULL) { g_print ("Invalid property name: %s\n", prop_name); @@ -201,8 +233,6 @@ GstElement *ret; int i; - - g_debug ("SET OBJ [%s]", factory_name); ret = gst_element_factory_make (factory_name, element_name); if (ret == NULL) return NULL; @@ -222,10 +252,9 @@ } static GstElement* -_create_audio_bin (GMencoder* self, - const gchar* encode, - gchar** encode_prop, - gint rate) +_create_audio_bin (const gchar* encode, + gchar** encode_prop, + gint rate) { GstElement *abin = NULL; GstElement *aqueue = NULL; @@ -247,8 +276,17 @@ goto error; } + g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL); + /* + if (rate > 0) { + g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL); + } + */ + gst_bin_add_many (GST_BIN (abin), aqueue, aconvert, aencode, aqueue_src, NULL); - gst_element_link_many (aqueue, aconvert, aencode, aqueue_src, NULL); + if (gst_element_link_many (aqueue, aconvert, aencode, aqueue_src, NULL) == FALSE) { + g_warning ("Not Link audio elements"); + } //TODO: apply audio rate @@ -289,8 +327,7 @@ //queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace ! rate ! encode ! queue static GstElement* -_create_video_bin (GMencoder* self, - const gchar* encode, +_create_video_bin (const gchar* encode, gchar** encode_prop, gdouble fps, gint rate, @@ -320,6 +357,7 @@ gst_bin_add_many (GST_BIN (vbin), vqueue, vcolorspace, vencode, vqueue_src, NULL); + if ((width > 0) && (height > 0)) { //Scalling video @@ -345,6 +383,7 @@ } else { gst_element_link (vqueue, vcolorspace); } + if (fps > 0) { //Changing the video fps @@ -371,7 +410,6 @@ goto error; } } - gst_element_link (vencode, vqueue_src); @@ -409,66 +447,251 @@ } -gboolean + +void g_mencoder_setup_stream (GMencoder *self, - const gchar* uri, const gchar* video_encode, + const gchar* mux_name, gchar** video_encode_prop, gdouble video_fps, gdouble video_rate, guint video_width, - guint video_height, + guint video_height, const gchar* audio_encode, gchar** audio_encode_prop, guint audio_rate, - const gchar* sink_name, - gchar** sink_prop) + const gchar* out_uri) +{ + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + if (priv->ready == TRUE) { + g_warning ("Stream already configured. You need close stream first."); + return; + } + + priv->pipe = _create_pipeline (self, + video_encode, + mux_name, + video_encode_prop, + video_fps, + video_rate, + video_width, + video_height, + audio_encode, + audio_encode_prop, + audio_rate); + + _close_output (self); + _open_output (self, out_uri); +} + + +gboolean +g_mencoder_append_uri (GMencoder *self, + const gchar* uri) +{ + GstElement *ap; + GstElement *vp; + GstPad *pad_src; + GstPad *pad_sink; + GstElement *src; + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + gboolean ret = FALSE; + + g_return_val_if_fail (priv->pipe != NULL, FALSE); + g_return_val_if_fail (priv->ready == FALSE, FALSE); + + src = _create_source (uri); + if (src == NULL) + return FALSE; + + gst_bin_add (GST_BIN (priv->pipe), src); + + ap = gst_bin_get_by_name (GST_BIN (priv->pipe), "ap"); + vp = gst_bin_get_by_name (GST_BIN (priv->pipe), "vp"); + if ((vp == NULL) || (ap == NULL)) + goto error; + + pad_src = gst_element_get_pad (src, "src_audio"); + pad_sink = gst_element_get_compatible_pad (ap, + pad_src, + gst_pad_get_caps (pad_src)); + + if ((pad_sink == NULL) || (pad_src == NULL)) + goto error; + + GstPadLinkReturn lret = gst_pad_link (pad_src, pad_sink); + if (lret != GST_PAD_LINK_OK) + goto error; + + gst_object_unref (pad_src); + gst_object_unref (pad_sink); + + pad_src = gst_element_get_pad (src, "src_video"); + pad_sink = gst_element_get_compatible_pad (vp, + pad_src, + gst_pad_get_caps (pad_src)); + + if ((pad_src == NULL) || (pad_sink == NULL)) + goto error; + + if (gst_pad_link (pad_src, pad_sink) != GST_PAD_LINK_OK) { + g_warning ("invalid source. video"); + goto error; + } + + ret = TRUE; +error: + + if ((src != NULL) && (ret == FALSE)) { + gst_bin_remove (GST_BIN (priv->pipe), src); + gst_object_unref (src); + } + + if (ap != NULL) + gst_object_unref (ap); + + if (vp != NULL) + gst_object_unref (vp); + + if (pad_src != NULL) + gst_object_unref (pad_src); + + if (pad_sink != NULL) + gst_object_unref (pad_sink); + + return ret; +} + + + +void +g_mencoder_remove_uri (GMencoder *self, + const gchar* uri) +{ + // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + //TODO: remove src +} + +void +g_mencoder_play_stream (GMencoder *self) +{ + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + + g_return_if_fail (priv->ready == FALSE); + priv->ready = TRUE; + gst_element_set_state (priv->pipe, GST_STATE_PLAYING); +} + +void +g_mencoder_pause_stream (GMencoder *self) +{ + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + + g_return_if_fail (priv->ready == TRUE); + gst_element_set_state (priv->pipe, GST_STATE_PAUSED); +} + +void +g_mencoder_close_stream (GMencoder *self) +{ + + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + + if (priv->pipe != NULL) { + gst_element_set_state (priv->pipe, GST_STATE_NULL); + gst_object_unref (priv->pipe); + priv->pipe = NULL; + priv->abin = NULL; + priv->vbin = NULL; + priv->sink = NULL; + } + priv->ready = FALSE; +} + +static void +_sink_handoff_cb (GstElement* object, + GstBuffer* buf, + GstPad* pad, + gpointer user_data) +{ + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data); + gint size = 0; + + size = write (priv->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + if (size == -1) { + g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, "Fail to write output"); + } +} + + +static GstElement* +_create_pipeline (GMencoder *self, + const gchar* video_encode, + const gchar* mux_name, + gchar** video_encode_prop, + gdouble video_fps, + gdouble video_rate, + guint video_width, + guint video_height, + const gchar* audio_encode, + gchar** audio_encode_prop, + guint audio_rate) { GstBus *bus = NULL; GstElement *pipe = NULL; - GstElement *fdsink = NULL; + GstElement *sink = NULL; GstElement *mux = NULL; - GstElement *decode = NULL; - GstElement *src = NULL; GstElement *abin = NULL; - GstElement *vbin = NULL; + GstElement *vbin = NULL; + GstElement *ap = NULL; + GstElement *vp = NULL; GstPad *aux_pad = NULL; GstPad *mux_pad = NULL; - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); + pipe = gst_pipeline_new ("pipe"); - pipe = gst_pipeline_new ("pipe"); - src = gst_element_make_from_uri (GST_URI_SRC, uri, "src"); - if (src == NULL) - goto error; + ap = gst_element_factory_make ("multipartmux", "ap"); + vp = gst_element_factory_make ("multipartmux", "vp"); - decode = gst_element_factory_make ("decodebin2", "decode"); - if (decode == NULL) - goto error; - - mux = gst_element_factory_make ("ffmux_mpeg", "mux"); + mux = gst_element_factory_make ((mux_name ? mux_name : "ffmux_mpeg"), "mux"); if (mux == NULL) goto error; - fdsink = _create_element_with_prop (sink_name, "sink", sink_prop); - if (fdsink == NULL) + sink = gst_element_factory_make ("fakesink", "sink"); + if (sink == NULL) goto error; - abin = _create_audio_bin (self, audio_encode, audio_encode_prop, audio_rate); + g_object_set (G_OBJECT(sink), + "sync", FALSE, + "signal-handoffs", TRUE, NULL); + + abin = _create_audio_bin (audio_encode, audio_encode_prop, audio_rate); if (abin == NULL) goto error; - vbin = _create_video_bin (self, video_encode, video_encode_prop, video_fps, video_rate, video_width, video_height); + vbin = _create_video_bin (video_encode, video_encode_prop, video_fps, video_rate, video_width, video_height); if (vbin == NULL) goto error; // Finish Pipe - gst_bin_add_many (GST_BIN (pipe), src, decode, abin, vbin, mux, fdsink, NULL); - gst_element_link (src, decode); + gst_bin_add_many (GST_BIN (pipe), ap, abin, vp, vbin, mux, sink, NULL); + + if (gst_element_link (ap, abin) == FALSE) { + g_warning ("Fail to link multipart and abin"); + goto error; + } + + if (gst_element_link (vp, vbin) == FALSE) { + g_warning ("Fail to link multipart and vbin"); + } //Link bins with mux aux_pad = gst_element_get_pad (abin, "src"); mux_pad = gst_element_get_pad (mux, "audio_0"); + if (mux_pad == NULL) { + g_warning ("Mux element no have audio_0 PAD"); + goto error; + } GstPadLinkReturn ret = gst_pad_link (aux_pad, mux_pad); if (ret != GST_PAD_LINK_OK) { g_warning ("Fail link audio and mux: %d", ret); @@ -480,6 +703,10 @@ aux_pad = gst_element_get_pad (vbin, "src"); mux_pad = gst_element_get_pad (mux, "video_0"); + if (mux_pad == NULL) { + g_warning ("Mux element no have video_0 PAD"); + goto error; + } ret = gst_pad_link (aux_pad, mux_pad); if (ret != GST_PAD_LINK_OK) { g_warning ("Fail link video and mux: %d", ret); @@ -491,32 +718,17 @@ mux_pad = NULL; //Link mux with sink - gst_element_link (mux, fdsink); + gst_element_link (mux, sink); - g_signal_connect (G_OBJECT (decode), - "new-decoded-pad", - G_CALLBACK (_decodebin_new_pad_cb), + g_signal_connect (G_OBJECT (sink), + "handoff", + G_CALLBACK (_sink_handoff_cb), self); - - g_signal_connect (G_OBJECT (decode), - "unknown-type", - G_CALLBACK (_decodebin_unknown_type_cb), - self); - bus = gst_pipeline_get_bus (GST_PIPELINE (pipe)); gst_bus_add_watch (bus, _pipeline_bus_cb, self); gst_object_unref (bus); - - - priv->pipe = pipe; - priv->abin = abin; - priv->vbin = vbin; - priv->sink = fdsink; - priv->ready = FALSE; - - gst_element_set_state (pipe, GST_STATE_PAUSED); - return TRUE; + return pipe; error: g_warning ("Invalid uri"); @@ -525,9 +737,6 @@ gst_object_unref (pipe); } - if (src != NULL) { - gst_object_unref (src); - } if (mux != NULL) { gst_object_unref (mux); @@ -541,8 +750,8 @@ gst_object_unref (mux_pad); } - if (fdsink != NULL) { - gst_object_unref (fdsink); + if (sink != NULL) { + gst_object_unref (sink); } if (abin != NULL) { @@ -556,49 +765,104 @@ return FALSE; } -gboolean -g_mencoder_play_stream (GMencoder *self) + +static void +_close_output (GMencoder *self) { + +} + +static GstElement* +_create_source (const gchar* uri) +{ + + GstElement *bsrc; + GstElement *src; + GstElement *aqueue; + GstElement *vqueue; + GstElement *decode; + GstPad *src_pad; + + + bsrc = gst_bin_new (NULL); + + src = gst_element_factory_make ("gnomevfssrc", "src"); + g_object_set (G_OBJECT (src), "location", uri, NULL); + if (src == NULL) + goto error; + + decode = gst_element_factory_make ("decodebin2", "decode"); + if (decode == NULL) + goto error; + + aqueue = gst_element_factory_make ("queue", "aqueue"); + if (aqueue == NULL) + goto error; + + vqueue = gst_element_factory_make ("queue", "vqueue"); + if (vqueue == NULL) + goto error; + + gst_bin_add_many (GST_BIN (bsrc), src, decode, aqueue, vqueue, NULL); + gst_element_link (src, decode); + + g_signal_connect (G_OBJECT (decode), + "new-decoded-pad", + G_CALLBACK (_decodebin_new_pad_cb), + bsrc); + + g_signal_connect (G_OBJECT (decode), + "unknown-type", + G_CALLBACK (_decodebin_unknown_type_cb), + pipe); + + src_pad = gst_element_get_pad (aqueue, "src"); + gst_element_add_pad (bsrc, gst_ghost_pad_new("src_audio", src_pad)); + gst_object_unref (src_pad); + + src_pad = gst_element_get_pad (vqueue, "src"); + gst_element_add_pad (bsrc, gst_ghost_pad_new("src_video", src_pad)); + gst_object_unref (src_pad); + + return bsrc; + +error: + if (src != NULL) { + gst_object_unref (src); + } + + if (decode != NULL) { + gst_object_unref (decode); + } + + if (aqueue != NULL) { + gst_object_unref (aqueue); + } + + if (vqueue != NULL) { + gst_object_unref (vqueue); + } + + return NULL; +} + +static void +_open_output (GMencoder *self, + const gchar* uri) +{ + gchar** i; GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); - g_return_val_if_fail (priv->ready == TRUE, FALSE); - - if (gst_element_set_state (priv->pipe, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) { - g_debug ("PLAYING"); - return TRUE; - } - return FALSE; -} + i = g_strsplit (uri, "://", 0); + if (strcmp (i[0], "fd") == 0) { + priv->fd = atoi (i[1]); + } else if (strcmp (i[0], "file") == 0) { + priv->fd = open (i[1], O_WRONLY | O_CREAT | O_TRUNC); + } else { + g_warning ("Output uri not supported"); + } -gboolean -g_mencoder_pause_stream (GMencoder *self) -{ - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); - - g_return_val_if_fail (priv->ready == TRUE, FALSE); - - if (gst_element_set_state (priv->pipe, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE) { - g_debug ("PAUSED"); - return TRUE; - } - return FALSE; -} - -void -g_mencoder_close_stream (GMencoder *self) -{ - - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); - - g_return_if_fail (priv->ready == TRUE); - - gst_element_set_state (priv->pipe, GST_STATE_NULL); - gst_object_unref (priv->pipe); - priv->pipe = NULL; - priv->abin = NULL; - priv->vbin = NULL; - priv->sink = NULL; - priv->ready = FALSE; + g_strfreev (i); } static gboolean @@ -606,6 +870,8 @@ GstMessage *msg, gpointer user_data) { + GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data); + switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_STATE_CHANGED: @@ -614,7 +880,6 @@ GstState newstate; GstState pendingstate; - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data); gst_message_parse_state_changed (msg, &oldstate, &newstate, &pendingstate); @@ -626,10 +891,6 @@ (newstate == GST_STATE_PAUSED)) { if (priv->ready) g_signal_emit (user_data, g_mencoder_signals[PAUSED], 0); - else { - priv->ready = TRUE; - g_signal_emit (user_data, g_mencoder_signals[READY], 0); - } } else if ((oldstate == GST_STATE_PAUSED) && (newstate == GST_STATE_PLAYING)) { g_signal_emit (user_data, g_mencoder_signals[PLAYING], 0); @@ -650,6 +911,7 @@ error->message, debug); g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, err_str); + priv->ready = FALSE; g_free (err_str); g_clear_error (&error); g_free (debug); @@ -657,6 +919,7 @@ } case GST_MESSAGE_EOS: + priv->ready = FALSE; g_signal_emit (user_data, g_mencoder_signals[EOS], 0); break; default: @@ -665,6 +928,8 @@ return TRUE; } + + static void _decodebin_new_pad_cb (GstElement* object, GstPad* pad, @@ -673,24 +938,24 @@ { GstCaps *caps; gchar *str_caps = NULL; - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data); + GstElement *sink_element; + GstPad *sink_pad; caps = gst_pad_get_caps (pad); str_caps = gst_caps_to_string (caps); - g_debug ("CAPS : %s", str_caps); - if (strstr (str_caps, "audio") != NULL) { - GstPad *apad = gst_element_get_pad (priv->abin, "sink"); - gst_pad_link (pad, apad); - gst_object_unref (apad); + sink_element = gst_bin_get_by_name (GST_BIN (user_data), "aqueue"); } else if (strstr (str_caps, "video") != NULL) { - GstPad *vpad = gst_element_get_pad (priv->vbin, "sink"); - gst_pad_link (pad, vpad); - gst_object_unref (vpad); + sink_element = gst_bin_get_by_name (GST_BIN (user_data), "vqueue"); } else { g_warning ("invalid caps %s", str_caps); } + sink_pad = gst_element_get_pad (sink_element, "sink"); + gst_pad_link (pad, sink_pad); + + gst_object_unref (sink_element); + gst_object_unref (sink_pad); g_free (str_caps); gst_caps_unref (caps); } @@ -702,4 +967,5 @@ gpointer user_data) { g_warning ("Unknown Type"); + //priv->ready = FALSE; }