renatofilho@898: /* renatofilho@898: * arch-tag: Implementation gmencoder engine renatofilho@898: * melunko@931: * Copyright (C) 2007 INdT - Renato Filho renatofilho@898: * renatofilho@898: * This program is free software; you can redistribute it and/or modify renatofilho@898: * it under the terms of the GNU General Public License as published by renatofilho@898: * the Free Software Foundation; either version 2 of the License, or renatofilho@898: * (at your option) any later version. renatofilho@898: * renatofilho@898: * This program is distributed in the hope that it will be useful, renatofilho@898: * but WITHOUT ANY WARRANTY; without even the implied warranty of renatofilho@898: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the renatofilho@898: * GNU General Public License for more details. renatofilho@898: * renatofilho@898: * You should have received a copy of the GNU General Public License renatofilho@898: * along with this program; if not, write to the Free Software renatofilho@898: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. renatofilho@898: * renatofilho@898: */ renatofilho@898: renatofilho@588: #ifdef HAVE_CONFIG_H renatofilho@588: #include "config.h" renatofilho@588: #endif renatofilho@588: renatofilho@600: #include renatofilho@600: #include renatofilho@600: #include renatofilho@588: #include renatofilho@588: #include renatofilho@588: #include renatofilho@762: #include renatofilho@762: #include renatofilho@786: #include renatofilho@789: #include renatofilho@588: renatofilho@588: #include "gmencoder.h" renatofilho@588: renatofilho@588: #define G_MENCODER_GET_PRIVATE(obj) \ renatofilho@588: (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_TYPE_MENCODER, GMencoderPrivate)) renatofilho@588: renatofilho@807: #define USE_MANUAL_SINK renatofilho@807: #define GMENCODER_TIMEOUT 5000 renatofilho@807: renatofilho@588: typedef struct _GMencoderPrivate GMencoderPrivate; renatofilho@600: typedef struct _SetupInfo SetupInfo; renatofilho@600: renatofilho@754: struct _SetupInfo { renatofilho@754: gchar *video_encode; renatofilho@754: gchar *mux_name; renatofilho@754: gchar **video_encode_prop; renatofilho@754: gdouble video_fps; renatofilho@754: gdouble video_rate; renatofilho@754: guint video_width; renatofilho@754: guint video_height; renatofilho@754: gchar *audio_encode; renatofilho@754: gchar **audio_encode_prop; renatofilho@754: guint audio_rate; renatofilho@600: }; renatofilho@600: renatofilho@588: renatofilho@754: struct _GMencoderPrivate { renatofilho@754: GstElement *pipe; renatofilho@754: GstElement *abin; renatofilho@754: GstElement *vbin; renatofilho@754: GstElement *sink; renatofilho@754: GstElement *src; renatofilho@786: renatofilho@807: GnomeVFSHandle *handle; renatofilho@786: renatofilho@754: gboolean ready; renatofilho@754: SetupInfo *info; renatofilho@754: GstClockTime videot; renatofilho@754: GstClockTime audiot; renatofilho@754: gint sources; renatofilho@754: gint tick_id; renatofilho@754: gint64 duration; renatofilho@768: gboolean send_chunked; renatofilho@807: gint timeout_id; renatofilho@789: renatofilho@789: //V4l info renatofilho@789: GstElement *v4lsrc; renatofilho@789: gchar *channel; renatofilho@789: gchar *norm; renatofilho@789: glong frequency; renatofilho@588: }; renatofilho@588: renatofilho@754: enum { renatofilho@754: PAUSED, renatofilho@754: PLAYING, renatofilho@754: STOPED, renatofilho@754: EOS, renatofilho@754: ERROR, renatofilho@754: LAST_SIGNAL renatofilho@588: }; renatofilho@588: renatofilho@754: static void g_mencoder_class_init(GMencoderClass * klass); renatofilho@754: static void g_mencoder_init(GMencoder * object); renatofilho@754: static void g_mencoder_dispose(GObject * object); renatofilho@754: static void g_mencoder_finalize(GObject * object); renatofilho@752: static GstElement *_create_audio_bin(const gchar * encode, renatofilho@754: gchar ** encode_prop, gint rate); renatofilho@752: static GstElement *_create_video_bin(const gchar * encode, renatofilho@754: gchar ** encode_prop, renatofilho@754: gdouble fps, renatofilho@777: gint rate, guint width, guint height, renatofilho@777: gboolean use_deinterlace); renatofilho@588: renatofilho@754: static gboolean renatofilho@752: _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data); morphbr@748: renatofilho@754: static void _decodebin_new_pad_cb(GstElement * object, renatofilho@754: GstPad * pad, renatofilho@754: gboolean flag, gpointer user_data); morphbr@748: renatofilho@754: static void _decodebin_unknown_type_cb(GstElement * object, renatofilho@754: GstPad * pad, renatofilho@754: GstCaps * caps, renatofilho@754: gpointer user_data); morphbr@748: renatofilho@754: static void _close_output(GMencoder * self); renatofilho@757: static gboolean _open_output(GMencoder * self, const gchar * uri); morphbr@748: renatofilho@789: static GstElement *_create_source(GMencoder *self, const gchar * uri); renatofilho@752: static GstElement *_create_pipeline(GMencoder * self, renatofilho@754: const gchar * video_encode, renatofilho@754: const gchar * mux_name, renatofilho@754: gchar ** video_encode_prop, renatofilho@754: gdouble video_fps, renatofilho@754: gdouble video_rate, renatofilho@754: guint video_width, renatofilho@754: guint video_height, renatofilho@754: const gchar * audio_encode, renatofilho@754: gchar ** audio_encode_prop, renatofilho@777: guint audio_rate, renatofilho@777: gboolean deinterlace); renatofilho@807: static gboolean _process_timeout_cb (gpointer user_data); renatofilho@807: #ifdef USE_MANUAL_SINK renatofilho@789: static void _flush_queue (GMencoder *self); renatofilho@761: static void _buffer_arrive_cb (GstElement* object, renatofilho@761: GstBuffer* buff, renatofilho@807: GstPad* pad, renatofilho@761: gpointer user_data); renatofilho@807: #endif renatofilho@807: renatofilho@807: renatofilho@752: static gboolean _tick_cb(gpointer data); renatofilho@588: renatofilho@754: static guint g_mencoder_signals[LAST_SIGNAL] = { 0 }; renatofilho@588: renatofilho@588: G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT) renatofilho@761: renatofilho@761: static void g_mencoder_class_init(GMencoderClass * klass) renatofilho@752: { renatofilho@754: GObjectClass *object_class; renatofilho@754: object_class = (GObjectClass *) klass; renatofilho@754: g_type_class_add_private(klass, sizeof(GMencoderPrivate)); renatofilho@588: renatofilho@754: object_class->dispose = g_mencoder_dispose; renatofilho@754: object_class->finalize = g_mencoder_finalize; renatofilho@588: renatofilho@754: g_mencoder_signals[PAUSED] = renatofilho@754: g_signal_new("paused", renatofilho@754: G_OBJECT_CLASS_TYPE(object_class), renatofilho@754: G_SIGNAL_RUN_FIRST, renatofilho@754: 0, NULL, NULL, renatofilho@754: g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); renatofilho@588: renatofilho@754: g_mencoder_signals[PLAYING] = renatofilho@754: g_signal_new("playing", renatofilho@754: G_OBJECT_CLASS_TYPE(object_class), renatofilho@754: G_SIGNAL_RUN_FIRST, renatofilho@754: 0, NULL, NULL, renatofilho@754: g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); morphbr@748: renatofilho@754: g_mencoder_signals[STOPED] = renatofilho@754: g_signal_new("stoped", renatofilho@754: G_OBJECT_CLASS_TYPE(object_class), renatofilho@754: G_SIGNAL_RUN_FIRST, renatofilho@754: 0, NULL, NULL, renatofilho@754: g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); renatofilho@588: renatofilho@754: g_mencoder_signals[EOS] = renatofilho@754: g_signal_new("eos", renatofilho@754: G_OBJECT_CLASS_TYPE(object_class), renatofilho@754: G_SIGNAL_RUN_FIRST, renatofilho@754: 0, NULL, NULL, renatofilho@754: g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); renatofilho@588: renatofilho@754: g_mencoder_signals[ERROR] = renatofilho@754: g_signal_new("error", renatofilho@754: G_OBJECT_CLASS_TYPE(object_class), renatofilho@754: G_SIGNAL_RUN_LAST, renatofilho@754: 0, NULL, NULL, renatofilho@754: g_cclosure_marshal_VOID__STRING, renatofilho@754: G_TYPE_NONE, 1, G_TYPE_STRING); renatofilho@588: } renatofilho@588: renatofilho@588: static void renatofilho@752: g_mencoder_init(GMencoder * self) renatofilho@588: { renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@754: priv->info = g_new0(SetupInfo, 1); renatofilho@588: } renatofilho@588: morphbr@748: static void renatofilho@752: g_mencoder_dispose(GObject * object) renatofilho@588: { renatofilho@588: } renatofilho@588: morphbr@748: static void renatofilho@752: g_mencoder_finalize(GObject * object) renatofilho@588: { renatofilho@762: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(object); renatofilho@762: renatofilho@754: // TODO: clear vars renatofilho@754: g_mencoder_close_stream(G_MENCODER(object)); renatofilho@762: g_free (priv->info); renatofilho@588: } renatofilho@588: renatofilho@754: GMencoder * renatofilho@752: g_mencoder_new(void) renatofilho@588: { renatofilho@754: return g_object_new(G_TYPE_MENCODER, NULL); renatofilho@588: } renatofilho@588: renatofilho@600: renatofilho@588: static void renatofilho@754: _obj_set_prop(GObject * obj, const gchar * prop_name, renatofilho@754: const gchar * prop_val) renatofilho@588: { renatofilho@754: GValue p = { 0 }; renatofilho@754: GValue v = { 0 }; renatofilho@754: GParamSpec *s = NULL; renatofilho@754: GObjectClass *k = G_OBJECT_GET_CLASS(obj); renatofilho@588: renatofilho@588: renatofilho@754: g_value_init(&v, G_TYPE_STRING); renatofilho@754: g_value_set_string(&v, prop_val); renatofilho@588: renatofilho@754: s = g_object_class_find_property(k, prop_name); renatofilho@754: if (s == NULL) { renatofilho@754: g_print("Invalid property name: %s\n", prop_name); renatofilho@754: return; renatofilho@754: } renatofilho@588: renatofilho@754: g_value_init(&p, s->value_type); renatofilho@754: switch (s->value_type) { renatofilho@754: case G_TYPE_INT: renatofilho@754: g_value_set_int(&p, atoi(prop_val)); renatofilho@754: break; renatofilho@889: case G_TYPE_UINT: renatofilho@889: g_value_set_uint (&p, (guint) atoi(prop_val)); renatofilho@889: break; renatofilho@772: case G_TYPE_ULONG: renatofilho@772: g_value_set_ulong (&p, atol(prop_val)); renatofilho@772: break; renatofilho@754: case G_TYPE_STRING: renatofilho@754: g_value_set_string(&p, prop_val); renatofilho@754: break; renatofilho@772: case G_TYPE_BOOLEAN: renatofilho@772: g_value_set_boolean(&p, (gboolean) atoi (prop_val)); renatofilho@772: break; renatofilho@772: case G_TYPE_DOUBLE: renatofilho@772: g_value_set_double(&p, atof (prop_val)); renatofilho@772: break; renatofilho@772: case G_TYPE_FLOAT: renatofilho@772: g_value_set_float(&p, (float) atof (prop_val)); renatofilho@772: break; renatofilho@754: default: renatofilho@777: g_value_set_enum(&p, atoi(prop_val)); renatofilho@777: g_warning ("Property %s of type %s. Not supported using default enum", renatofilho@772: prop_name, g_type_name (s->value_type)); renatofilho@754: return; renatofilho@754: } morphbr@748: renatofilho@754: g_object_set_property(obj, prop_name, &p); renatofilho@754: g_value_unset(&v); renatofilho@754: g_value_unset(&p); renatofilho@588: } renatofilho@588: renatofilho@752: static GstElement * renatofilho@752: _create_element_with_prop(const gchar * factory_name, renatofilho@754: const gchar * element_name, gchar ** prop) renatofilho@588: { renatofilho@754: GstElement *ret; renatofilho@754: int i; renatofilho@588: renatofilho@754: ret = gst_element_factory_make(factory_name, element_name); renatofilho@754: if (ret == NULL) renatofilho@754: return NULL; renatofilho@588: renatofilho@754: if (prop != NULL) { renatofilho@754: for (i = 0; i < g_strv_length(prop); i++) { renatofilho@754: if (prop[i] != NULL) { renatofilho@781: char **v = g_strsplit(prop[i], "=", 2); renatofilho@754: if (g_strv_length(v) == 2) { renatofilho@754: _obj_set_prop(G_OBJECT(ret), v[0], v[1]); renatofilho@754: } renatofilho@754: g_strfreev(v); renatofilho@754: } renatofilho@754: } renatofilho@754: } renatofilho@588: renatofilho@754: return ret; renatofilho@588: renatofilho@588: } renatofilho@588: renatofilho@752: static GstElement * renatofilho@752: _create_audio_bin(const gchar * encode, gchar ** encode_prop, gint rate) renatofilho@588: { renatofilho@754: GstElement *abin = NULL; renatofilho@754: GstElement *aqueue = NULL; renatofilho@754: GstElement *aconvert = NULL; renatofilho@754: GstElement *aencode = NULL; renatofilho@754: GstElement *aqueue_src = NULL; renatofilho@754: GstPad *apad = NULL; renatofilho@588: renatofilho@754: // audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay ! renatofilho@754: // udpsink name=upd_audio host=224.0.0.1 port=5002 renatofilho@754: abin = gst_bin_new("abin"); renatofilho@754: aqueue = gst_element_factory_make("queue", "aqueue"); renatofilho@754: aconvert = gst_element_factory_make("audioconvert", "aconvert"); renatofilho@754: aencode = renatofilho@754: _create_element_with_prop((encode ? encode : "lame"), "aencode", renatofilho@754: encode_prop); renatofilho@754: aqueue_src = gst_element_factory_make("queue", "aqueue_src"); renatofilho@588: renatofilho@754: if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL) renatofilho@754: || (aencode == NULL) || (aqueue_src == NULL)) { renatofilho@754: g_warning("Audio elements not found"); renatofilho@754: goto error; renatofilho@754: } renatofilho@752: renatofilho@897: renatofilho@754: renatofilho@754: gst_bin_add_many(GST_BIN(abin), aqueue, aconvert, aencode, aqueue_src, renatofilho@754: NULL); renatofilho@897: renatofilho@897: if (!gst_element_link (aqueue, aconvert)) renatofilho@897: { renatofilho@754: g_warning("Not Link audio elements"); renatofilho@897: goto error; renatofilho@897: } renatofilho@897: renatofilho@897: if (rate > 0) { renatofilho@897: GstCaps *caps; renatofilho@897: renatofilho@897: caps = gst_caps_new_simple ("audio/x-raw-int", renatofilho@897: "rate", G_TYPE_INT, rate, NULL); renatofilho@897: if (!gst_element_link_filtered (aconvert, aencode, caps)) renatofilho@897: { renatofilho@897: gst_caps_unref (caps); renatofilho@897: g_warning("Not link rate filter"); renatofilho@897: goto error; renatofilho@897: } renatofilho@897: renatofilho@897: gst_caps_unref (caps); renatofilho@897: } renatofilho@897: else renatofilho@897: { renatofilho@897: if (!gst_element_link (aconvert, aencode)) renatofilho@897: { renatofilho@897: g_warning ("Fail to link audio elements"); renatofilho@897: goto error; renatofilho@897: } renatofilho@897: } renatofilho@897: renatofilho@897: renatofilho@897: if (!gst_element_link (aencode, aqueue_src)) renatofilho@897: { renatofilho@897: g_warning("Not Link audio elements"); renatofilho@897: goto error; morphbr@748: } renatofilho@754: // TODO: apply audio rate renatofilho@588: renatofilho@754: // ghost pad the audio bin renatofilho@754: apad = gst_element_get_pad(aqueue, "sink"); renatofilho@754: gst_element_add_pad(abin, gst_ghost_pad_new("sink", apad)); renatofilho@754: gst_object_unref(apad); renatofilho@600: renatofilho@754: apad = gst_element_get_pad(aqueue_src, "src"); renatofilho@754: gst_element_add_pad(abin, gst_ghost_pad_new("src", apad)); renatofilho@754: gst_object_unref(apad); renatofilho@588: renatofilho@754: return abin; renatofilho@754: error: renatofilho@754: if (abin != NULL) renatofilho@754: gst_object_unref(abin); renatofilho@588: renatofilho@754: if (aqueue != NULL) renatofilho@754: gst_object_unref(aqueue); morphbr@748: renatofilho@754: if (aconvert != NULL) renatofilho@754: gst_object_unref(aconvert); renatofilho@588: renatofilho@754: if (aencode != NULL) renatofilho@754: gst_object_unref(aencode); renatofilho@588: renatofilho@754: if (aqueue_src != NULL) renatofilho@754: gst_object_unref(aqueue_src); renatofilho@588: renatofilho@754: if (apad != NULL) renatofilho@754: gst_object_unref(apad); renatofilho@588: renatofilho@754: return NULL; renatofilho@588: } renatofilho@588: renatofilho@588: renatofilho@588: renatofilho@588: renatofilho@754: // queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace renatofilho@754: // ! rate ! encode ! queue renatofilho@752: static GstElement * renatofilho@752: _create_video_bin(const gchar * encode, renatofilho@754: gchar ** encode_prop, renatofilho@777: gdouble fps, gint rate, guint width, guint height, renatofilho@777: gboolean use_deinterlace) renatofilho@588: { renatofilho@754: GstElement *vbin = NULL; renatofilho@754: GstElement *vqueue = NULL; renatofilho@754: GstElement *vqueue_src = NULL; renatofilho@754: GstElement *vcolorspace = NULL; renatofilho@754: GstElement *vencode = NULL; renatofilho@754: GstElement *vrate = NULL; renatofilho@888: GstElement *deinterlace = NULL; renatofilho@777: GstElement *walk = NULL; renatofilho@754: GstPad *vpad = NULL; renatofilho@588: renatofilho@754: vbin = gst_bin_new("vbin"); renatofilho@754: vqueue = gst_element_factory_make("queue", "vqueue"); renatofilho@754: vcolorspace = renatofilho@754: gst_element_factory_make("ffmpegcolorspace", "colorspace"); renatofilho@616: renatofilho@777: if (use_deinterlace) { renatofilho@789: deinterlace = gst_element_factory_make ("ffdeinterlace", "deinterlace"); renatofilho@888: if (deinterlace == NULL) { renatofilho@888: g_warning ("Fail to create deinterlace element: Continue without deinterlace."); renatofilho@789: } renatofilho@777: } renatofilho@777: renatofilho@777: renatofilho@754: vencode = _create_element_with_prop((encode != renatofilho@754: NULL ? encode : renatofilho@754: "ffenc_mpeg1video"), "vencode", renatofilho@754: encode_prop); renatofilho@754: vqueue_src = gst_element_factory_make("queue", "queue_src"); renatofilho@588: renatofilho@754: if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL) renatofilho@754: || (vencode == NULL) || (vqueue_src == NULL)) { renatofilho@754: g_warning("Video elements not found"); renatofilho@754: goto error; renatofilho@754: } renatofilho@588: renatofilho@754: gst_bin_add_many(GST_BIN(vbin), vqueue, vcolorspace, vencode, renatofilho@754: vqueue_src, NULL); morphbr@748: renatofilho@777: if (deinterlace != NULL) { renatofilho@777: gst_bin_add(GST_BIN(vbin), deinterlace); renatofilho@777: gst_element_link (vqueue, deinterlace); renatofilho@777: walk = deinterlace; renatofilho@777: } else { renatofilho@777: walk = vqueue; renatofilho@777: } renatofilho@777: renatofilho@754: if ((width > 0) && (height > 0)) { renatofilho@754: // Scalling video renatofilho@754: GstCaps *vcaps; renatofilho@888: GstElement *vscale; renatofilho@588: renatofilho@888: vscale = gst_element_factory_make("videoscale", "vscale"); renatofilho@916: g_object_set (G_OBJECT (vscale), "method", 1, NULL); renatofilho@754: gst_bin_add(GST_BIN(vbin), vscale); renatofilho@588: renatofilho@754: vcaps = gst_caps_new_simple("video/x-raw-yuv", renatofilho@754: "width", G_TYPE_INT, width, renatofilho@754: "height", G_TYPE_INT, height, NULL); renatofilho@588: renatofilho@777: gst_element_link(walk, vscale); morphbr@748: renatofilho@754: if (gst_element_link_filtered(vscale, vcolorspace, vcaps) == FALSE) { renatofilho@754: g_warning("Fail to resize video"); renatofilho@754: gst_object_unref(vcaps); renatofilho@754: gst_object_unref(vscale); renatofilho@754: goto error; renatofilho@754: } renatofilho@754: gst_caps_unref(vcaps); renatofilho@754: } else { renatofilho@777: gst_element_link(walk, vcolorspace); renatofilho@754: } renatofilho@588: renatofilho@754: if (fps > 0) { renatofilho@754: // Changing the video fps renatofilho@916: g_debug ("Changing FPS TO : %5.2f", fps); renatofilho@754: GstCaps *vcaps; renatofilho@754: vrate = gst_element_factory_make("videorate", "vrate"); renatofilho@588: renatofilho@754: gst_bin_add(GST_BIN(vbin), vrate); renatofilho@588: renatofilho@754: if (gst_element_link(vcolorspace, vrate) == FALSE) { renatofilho@754: g_warning("Fail to link video elements"); renatofilho@754: goto error; renatofilho@754: } renatofilho@588: renatofilho@754: vcaps = gst_caps_new_simple("video/x-raw-yuv", renatofilho@754: "framerate", GST_TYPE_FRACTION, renatofilho@916: (int) fps, 1, renatofilho@905: NULL); renatofilho@588: renatofilho@754: if (gst_element_link_filtered(vrate, vencode, vcaps) == FALSE) { renatofilho@754: g_warning("Fail to link vrate with vencode."); renatofilho@754: goto error; renatofilho@754: } renatofilho@754: gst_caps_unref(vcaps); renatofilho@754: } else { renatofilho@754: if (gst_element_link(vcolorspace, vencode) == FALSE) { renatofilho@754: g_warning("Fail to link colorspace and video encode element."); renatofilho@754: goto error; renatofilho@754: } renatofilho@754: } morphbr@748: renatofilho@754: gst_element_link(vencode, vqueue_src); renatofilho@588: renatofilho@754: // ghost pad the video bin renatofilho@754: vpad = gst_element_get_pad(vqueue, "sink"); renatofilho@754: gst_element_add_pad(vbin, gst_ghost_pad_new("sink", vpad)); renatofilho@754: gst_object_unref(vpad); morphbr@748: renatofilho@754: vpad = gst_element_get_pad(vqueue_src, "src"); renatofilho@754: gst_element_add_pad(vbin, gst_ghost_pad_new("src", vpad)); renatofilho@754: gst_object_unref(vpad); renatofilho@588: renatofilho@754: return vbin; renatofilho@588: renatofilho@754: error: renatofilho@754: if (vpad != NULL) renatofilho@754: gst_object_unref(vpad); renatofilho@588: renatofilho@754: if (vbin != NULL) renatofilho@754: gst_object_unref(vbin); renatofilho@588: renatofilho@754: if (vqueue != NULL) renatofilho@754: gst_object_unref(vqueue); renatofilho@588: renatofilho@754: if (vencode != NULL) renatofilho@754: gst_object_unref(vencode); renatofilho@588: renatofilho@754: if (vqueue_src != NULL) renatofilho@754: gst_object_unref(vqueue_src); renatofilho@588: renatofilho@754: if (vcolorspace != NULL) renatofilho@754: gst_object_unref(vcolorspace); renatofilho@588: renatofilho@754: return NULL; renatofilho@588: } renatofilho@588: renatofilho@588: renatofilho@600: renatofilho@757: gboolean renatofilho@752: g_mencoder_setup_stream(GMencoder * self, renatofilho@768: gboolean chunked, renatofilho@777: gboolean deinterlace, renatofilho@754: const gchar * mux_name, renatofilho@754: const gchar * video_encode, renatofilho@754: gchar ** video_encode_prop, renatofilho@754: gdouble video_fps, renatofilho@754: gdouble video_rate, renatofilho@754: guint video_width, renatofilho@754: guint video_height, renatofilho@754: const gchar * audio_encode, renatofilho@754: gchar ** audio_encode_prop, renatofilho@754: guint audio_rate, const gchar * out_uri) renatofilho@600: { renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@754: if (priv->ready == TRUE) { renatofilho@754: g_warning renatofilho@754: ("Stream already configured. You need close stream first."); renatofilho@757: return FALSE; renatofilho@754: } renatofilho@600: renatofilho@754: _close_output(self); melunko@826: if (_open_output(self, out_uri) == FALSE) { renatofilho@757: return FALSE; renatofilho@789: } renatofilho@634: renatofilho@754: priv->sources = 0; renatofilho@768: priv->send_chunked = chunked; renatofilho@754: priv->pipe = _create_pipeline(self, renatofilho@754: video_encode, renatofilho@754: mux_name, renatofilho@754: video_encode_prop, renatofilho@754: video_fps, renatofilho@754: video_rate, renatofilho@754: video_width, renatofilho@754: video_height, renatofilho@754: audio_encode, audio_encode_prop, renatofilho@777: audio_rate, renatofilho@777: deinterlace); renatofilho@600: renatofilho@757: return (priv->pipe != NULL); renatofilho@600: } renatofilho@600: renatofilho@600: renatofilho@600: gboolean renatofilho@752: g_mencoder_append_uri(GMencoder * self, const gchar * uri) renatofilho@600: { renatofilho@754: GstPad *pad_src; renatofilho@754: GstPad *pad_sink; renatofilho@754: GstElement *src; renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@754: gboolean ret = FALSE; renatofilho@754: GstElement *ap = NULL; renatofilho@754: GstElement *vp = NULL; renatofilho@634: renatofilho@600: renatofilho@754: g_return_val_if_fail(priv->pipe != NULL, FALSE); renatofilho@754: g_return_val_if_fail(priv->ready == FALSE, FALSE); renatofilho@600: renatofilho@789: src = _create_source(self, uri); renatofilho@754: if (src == NULL) renatofilho@754: return FALSE; renatofilho@600: renatofilho@754: priv->src = gst_bin_get_by_name(GST_BIN(src), "src"); renatofilho@671: renatofilho@754: gst_bin_add(GST_BIN(priv->pipe), src); renatofilho@600: renatofilho@754: ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "abin"); renatofilho@754: vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vbin"); renatofilho@634: renatofilho@754: if ((vp == NULL) || (ap == NULL)) { renatofilho@754: g_warning("Fail to get output bin"); renatofilho@754: goto error; renatofilho@754: } renatofilho@600: renatofilho@754: pad_src = gst_element_get_pad(src, "src_audio"); renatofilho@754: pad_sink = gst_element_get_compatible_pad(ap, renatofilho@754: pad_src, renatofilho@754: gst_pad_get_caps(pad_src)); renatofilho@600: renatofilho@754: if ((pad_sink == NULL) || (pad_src == NULL)) renatofilho@754: goto error; renatofilho@600: renatofilho@754: GstPadLinkReturn lret = gst_pad_link(pad_src, pad_sink); renatofilho@754: if (lret != GST_PAD_LINK_OK) renatofilho@754: goto error; renatofilho@600: renatofilho@754: gst_object_unref(pad_src); renatofilho@754: gst_object_unref(pad_sink); renatofilho@600: renatofilho@754: pad_src = gst_element_get_pad(src, "src_video"); renatofilho@754: pad_sink = gst_element_get_compatible_pad(vp, renatofilho@754: pad_src, renatofilho@754: gst_pad_get_caps(pad_src)); renatofilho@600: renatofilho@754: if ((pad_src == NULL) || (pad_sink == NULL)) renatofilho@754: goto error; renatofilho@600: renatofilho@754: if (gst_pad_link(pad_src, pad_sink) != GST_PAD_LINK_OK) { renatofilho@754: g_warning("invalid source. video"); renatofilho@754: goto error; renatofilho@754: } renatofilho@600: renatofilho@754: priv->sources++; renatofilho@754: ret = TRUE; renatofilho@754: error: renatofilho@600: renatofilho@754: if ((src != NULL) && (ret == FALSE)) { renatofilho@754: gst_bin_remove(GST_BIN(priv->pipe), src); renatofilho@754: gst_object_unref(src); renatofilho@754: } renatofilho@600: renatofilho@754: if (ap != NULL) renatofilho@754: gst_object_unref(ap); renatofilho@600: renatofilho@754: if (vp != NULL) renatofilho@754: gst_object_unref(vp); renatofilho@600: renatofilho@754: if (pad_src != NULL) renatofilho@754: gst_object_unref(pad_src); renatofilho@600: renatofilho@754: if (pad_sink != NULL) renatofilho@754: gst_object_unref(pad_sink); renatofilho@600: renatofilho@754: return ret; renatofilho@600: } renatofilho@600: renatofilho@600: renatofilho@600: morphbr@748: void renatofilho@752: g_mencoder_remove_uri(GMencoder * self, const gchar * uri) renatofilho@600: { renatofilho@754: // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self); renatofilho@754: // TODO: remove src renatofilho@600: } renatofilho@600: renatofilho@600: void renatofilho@752: g_mencoder_play_stream(GMencoder * self) renatofilho@600: { renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@754: g_return_if_fail(priv->ready == FALSE); renatofilho@754: priv->ready = TRUE; renatofilho@754: gst_element_set_state(priv->pipe, GST_STATE_PLAYING); renatofilho@807: if (priv->tick_id != 0) { renatofilho@807: g_source_remove (priv->tick_id); renatofilho@807: } renatofilho@754: priv->tick_id = g_timeout_add(500, _tick_cb, self); renatofilho@807: renatofilho@807: if (priv->timeout_id != 0) { renatofilho@807: g_source_remove (priv->timeout_id); renatofilho@807: } renatofilho@933: priv->timeout_id = g_timeout_add(GMENCODER_TIMEOUT, _process_timeout_cb, self); renatofilho@600: } renatofilho@600: renatofilho@600: void renatofilho@752: g_mencoder_pause_stream(GMencoder * self) renatofilho@600: { renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@754: g_return_if_fail(priv->ready == TRUE); renatofilho@754: gst_element_set_state(priv->pipe, GST_STATE_PAUSED); renatofilho@600: } renatofilho@600: renatofilho@600: void renatofilho@752: g_mencoder_close_stream(GMencoder * self) renatofilho@600: { renatofilho@600: renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@754: if (priv->tick_id != 0) { renatofilho@754: g_source_remove(priv->tick_id); renatofilho@754: priv->tick_id = 0; renatofilho@754: } renatofilho@600: renatofilho@807: if (priv->timeout_id != 0) { renatofilho@807: g_source_remove (priv->timeout_id); renatofilho@807: priv->timeout_id = 0; renatofilho@807: } renatofilho@807: renatofilho@754: if (priv->pipe != NULL) { renatofilho@754: // TODO: fixe pipeline dispose renatofilho@786: //gst_element_set_state (priv->pipe, GST_STATE_NULL); renatofilho@754: // g_debug ("SETING STATE TO NULL: OK"); renatofilho@754: // gst_element_set_state (priv->pipe, GST_STATE_NULL); renatofilho@786: //gst_object_unref (priv->pipe); renatofilho@780: //gst_object_unref(priv->src); renatofilho@754: priv->src = NULL; renatofilho@754: priv->pipe = NULL; renatofilho@754: priv->abin = NULL; renatofilho@754: priv->vbin = NULL; renatofilho@807: priv->sink = NULL; renatofilho@754: } renatofilho@754: priv->ready = FALSE; renatofilho@600: } renatofilho@600: renatofilho@752: static GstElement * renatofilho@752: _create_pipeline(GMencoder * self, renatofilho@754: const gchar * video_encode, renatofilho@754: const gchar * mux_name, renatofilho@754: gchar ** video_encode_prop, renatofilho@754: gdouble video_fps, renatofilho@754: gdouble video_rate, renatofilho@754: guint video_width, renatofilho@754: guint video_height, renatofilho@754: const gchar * audio_encode, renatofilho@777: gchar ** audio_encode_prop, guint audio_rate, renatofilho@789: gboolean deinterlace) renatofilho@588: { renatofilho@754: GstBus *bus = NULL; renatofilho@754: GstElement *pipe = NULL; renatofilho@754: GstElement *sink = NULL; renatofilho@754: GstElement *mux = NULL; renatofilho@754: GstElement *abin = NULL; renatofilho@754: GstElement *vbin = NULL; renatofilho@754: GstElement *queue = NULL; renatofilho@754: GstPad *aux_pad = NULL; renatofilho@754: GstPad *mux_pad = NULL; renatofilho@588: renatofilho@754: pipe = gst_pipeline_new("pipe"); renatofilho@588: renatofilho@754: mux = renatofilho@754: gst_element_factory_make((mux_name ? mux_name : "ffmux_mpeg"), renatofilho@754: "mux"); renatofilho@754: if (mux == NULL) renatofilho@754: goto error; renatofilho@588: renatofilho@754: queue = gst_element_factory_make("queue", "queueu_sink"); renatofilho@807: renatofilho@807: renatofilho@807: sink = gst_element_factory_make("fakesink", "sink"); renatofilho@807: g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL); renatofilho@807: g_signal_connect (G_OBJECT (sink), renatofilho@761: "handoff", renatofilho@761: G_CALLBACK (_buffer_arrive_cb), renatofilho@762: self); renatofilho@600: renatofilho@754: abin = _create_audio_bin(audio_encode, audio_encode_prop, audio_rate); renatofilho@754: if (abin == NULL) renatofilho@754: goto error; renatofilho@588: renatofilho@754: vbin = renatofilho@754: _create_video_bin(video_encode, video_encode_prop, video_fps, renatofilho@777: video_rate, video_width, video_height, deinterlace); renatofilho@754: if (vbin == NULL) renatofilho@754: goto error; renatofilho@588: renatofilho@754: // Finish Pipe renatofilho@807: gst_bin_add_many(GST_BIN(pipe), abin, vbin, mux, queue, sink, NULL); renatofilho@600: renatofilho@600: renatofilho@754: // Link bins with mux renatofilho@754: aux_pad = gst_element_get_pad(abin, "src"); renatofilho@754: mux_pad = renatofilho@754: gst_element_get_compatible_pad(mux, aux_pad, renatofilho@754: GST_PAD_CAPS(aux_pad)); renatofilho@754: if (mux_pad == NULL) { renatofilho@754: g_warning("Mux element no have audio PAD"); renatofilho@754: goto error; renatofilho@754: } renatofilho@754: GstPadLinkReturn ret = gst_pad_link(aux_pad, mux_pad); renatofilho@754: if (ret != GST_PAD_LINK_OK) { renatofilho@754: g_warning("Fail link audio and mux: %d", ret); renatofilho@754: goto error; morphbr@748: renatofilho@754: } renatofilho@754: gst_object_unref(aux_pad); renatofilho@754: gst_object_unref(mux_pad); renatofilho@588: renatofilho@754: aux_pad = gst_element_get_pad(vbin, "src"); renatofilho@754: mux_pad = renatofilho@754: gst_element_get_compatible_pad(mux, aux_pad, renatofilho@754: GST_PAD_CAPS(aux_pad)); renatofilho@754: if (mux_pad == NULL) { renatofilho@754: g_warning("Mux element no have video PAD"); renatofilho@754: goto error; renatofilho@754: } renatofilho@754: ret = gst_pad_link(aux_pad, mux_pad); renatofilho@754: if (ret != GST_PAD_LINK_OK) { renatofilho@754: g_warning("Fail link video and mux: %d", ret); renatofilho@754: goto error; renatofilho@754: } renatofilho@754: gst_object_unref(aux_pad); renatofilho@754: gst_object_unref(mux_pad); renatofilho@754: aux_pad = NULL; renatofilho@754: mux_pad = NULL; renatofilho@588: renatofilho@754: // Link mux with sink renatofilho@807: gst_element_link_many(mux, queue, sink, NULL); renatofilho@588: renatofilho@754: bus = gst_pipeline_get_bus(GST_PIPELINE(pipe)); renatofilho@754: gst_bus_add_watch(bus, _pipeline_bus_cb, self); renatofilho@754: gst_object_unref(bus); renatofilho@754: return pipe; renatofilho@588: renatofilho@754: error: renatofilho@754: g_warning("Invalid uri"); morphbr@748: renatofilho@754: if (pipe != NULL) { renatofilho@754: gst_object_unref(pipe); renatofilho@754: } renatofilho@588: renatofilho@588: renatofilho@754: if (mux != NULL) { renatofilho@754: gst_object_unref(mux); renatofilho@754: } renatofilho@588: renatofilho@754: if (mux_pad != NULL) { renatofilho@754: gst_object_unref(mux_pad); renatofilho@754: } renatofilho@588: renatofilho@754: if (aux_pad != NULL) { renatofilho@754: gst_object_unref(mux_pad); renatofilho@754: } renatofilho@588: renatofilho@754: if (sink != NULL) { renatofilho@754: gst_object_unref(sink); renatofilho@754: } renatofilho@588: renatofilho@754: if (abin != NULL) { renatofilho@754: gst_object_unref(abin); renatofilho@754: } renatofilho@588: renatofilho@754: if (vbin != NULL) { renatofilho@754: gst_object_unref(vbin); renatofilho@754: } renatofilho@588: renatofilho@754: return FALSE; renatofilho@588: } renatofilho@588: renatofilho@600: renatofilho@600: static void renatofilho@752: _close_output(GMencoder * self) renatofilho@588: { renatofilho@600: } renatofilho@600: renatofilho@752: static GstElement * renatofilho@789: _create_v4l_source (GMencoder *self, const gchar * uri) renatofilho@789: { renatofilho@789: gchar **info; renatofilho@789: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@789: renatofilho@789: renatofilho@789: info = g_strsplit (uri+6, ":", 3); renatofilho@789: if (g_strv_length (info) != 3) { renatofilho@789: return NULL; renatofilho@789: } renatofilho@789: renatofilho@789: priv->v4lsrc = gst_element_factory_make ("v4l2src", "src"); renatofilho@789: g_debug ("channel %s, norm %s, frequ %s", info[0], info[1], info[2]); renatofilho@789: g_object_set (G_OBJECT (priv->v4lsrc), renatofilho@789: "channel", info[0], renatofilho@789: "norm", info[1], renatofilho@789: "frequency", atoi (info[2]), renatofilho@789: NULL); renatofilho@789: renatofilho@789: return priv->v4lsrc; renatofilho@789: } renatofilho@789: renatofilho@789: static GstElement * renatofilho@789: _create_source(GMencoder *self, const gchar * uri) renatofilho@600: { renatofilho@600: renatofilho@754: GstElement *bsrc = NULL; renatofilho@754: GstElement *src = NULL; renatofilho@754: GstElement *aqueue = NULL; renatofilho@754: GstElement *vqueue = NULL; renatofilho@754: GstElement *decode = NULL; renatofilho@754: GstPad *src_pad = NULL; renatofilho@600: renatofilho@600: renatofilho@754: bsrc = gst_bin_new(NULL); renatofilho@600: renatofilho@754: // src = gst_element_factory_make ("gnomevfssrc", "src"); renatofilho@754: // g_object_set (G_OBJECT (src), "location", uri, NULL); renatofilho@789: if (strncmp (uri, "v4l://", 6) == 0) { renatofilho@789: g_debug ("V4L"); renatofilho@789: src = _create_v4l_source (self, uri); renatofilho@789: } renatofilho@789: else { renatofilho@789: src = gst_element_make_from_uri(GST_URI_SRC, uri, "src"); renatofilho@789: } renatofilho@789: renatofilho@754: if (src == NULL) renatofilho@754: goto error; renatofilho@600: renatofilho@857: renatofilho@857: if (g_getenv ("USE_DECODEBIN1")) renatofilho@857: decode = gst_element_factory_make("decodebin", "decode"); renatofilho@857: else renatofilho@857: decode = gst_element_factory_make("decodebin2", "decode"); renatofilho@754: if (decode == NULL) renatofilho@754: goto error; renatofilho@600: renatofilho@754: aqueue = gst_element_factory_make("queue", "aqueue"); renatofilho@754: if (aqueue == NULL) renatofilho@754: goto error; renatofilho@600: renatofilho@754: vqueue = gst_element_factory_make("queue", "vqueue"); renatofilho@754: if (vqueue == NULL) renatofilho@754: goto error; renatofilho@600: morphbr@831: gst_bin_add_many(GST_BIN(bsrc), src, decode, aqueue, vqueue, renatofilho@754: NULL); morphbr@831: gst_element_link (src, decode); renatofilho@600: renatofilho@754: g_signal_connect(G_OBJECT(decode), renatofilho@754: "new-decoded-pad", renatofilho@754: G_CALLBACK(_decodebin_new_pad_cb), bsrc); renatofilho@600: renatofilho@754: g_signal_connect(G_OBJECT(decode), renatofilho@754: "unknown-type", renatofilho@754: G_CALLBACK(_decodebin_unknown_type_cb), pipe); renatofilho@600: renatofilho@754: src_pad = gst_element_get_pad(aqueue, "src"); renatofilho@754: gst_element_add_pad(bsrc, gst_ghost_pad_new("src_audio", src_pad)); renatofilho@754: gst_object_unref(src_pad); renatofilho@600: renatofilho@754: src_pad = gst_element_get_pad(vqueue, "src"); renatofilho@754: gst_element_add_pad(bsrc, gst_ghost_pad_new("src_video", src_pad)); renatofilho@754: gst_object_unref(src_pad); renatofilho@600: renatofilho@754: return bsrc; renatofilho@600: renatofilho@754: error: renatofilho@789: g_debug ("Fail to create source element"); renatofilho@754: if (src != NULL) { renatofilho@754: gst_object_unref(src); renatofilho@754: } renatofilho@600: renatofilho@754: if (decode != NULL) { renatofilho@754: gst_object_unref(decode); renatofilho@754: } renatofilho@600: renatofilho@754: if (aqueue != NULL) { renatofilho@754: gst_object_unref(aqueue); renatofilho@754: } renatofilho@600: renatofilho@754: if (vqueue != NULL) { renatofilho@754: gst_object_unref(vqueue); renatofilho@754: } renatofilho@600: renatofilho@754: return NULL; renatofilho@600: } renatofilho@600: renatofilho@757: static gboolean renatofilho@752: _open_output(GMencoder * self, const gchar * uri) renatofilho@600: { renatofilho@754: gchar **i; renatofilho@807: GnomeVFSResult result; renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@588: renatofilho@754: i = g_strsplit(uri, "://", 0); renatofilho@754: if (strcmp(i[0], "fd") == 0) { renatofilho@807: result = gnome_vfs_open_fd (&priv->handle, atoi(i[1])); renatofilho@789: } else { renatofilho@807: if (g_file_test (i[1], G_FILE_TEST_EXISTS) == FALSE) { melunko@826: result = gnome_vfs_create (&priv->handle, uri, GNOME_VFS_OPEN_WRITE, FALSE, renatofilho@807: GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_GROUP_READ); renatofilho@807: } else { renatofilho@807: result = gnome_vfs_open (&priv->handle, uri, renatofilho@807: GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_TRUNCATE); renatofilho@807: } renatofilho@754: } renatofilho@588: renatofilho@754: g_strfreev(i); renatofilho@807: return (result == GNOME_VFS_OK); renatofilho@588: } renatofilho@588: renatofilho@754: static gboolean renatofilho@752: _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data) renatofilho@588: { renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data); renatofilho@600: renatofilho@754: switch (GST_MESSAGE_TYPE(msg)) { renatofilho@588: renatofilho@754: case GST_MESSAGE_STATE_CHANGED: renatofilho@754: { renatofilho@754: GstState oldstate; renatofilho@754: GstState newstate; renatofilho@754: GstState pendingstate; renatofilho@588: morphbr@748: renatofilho@754: gst_message_parse_state_changed(msg, &oldstate, renatofilho@754: &newstate, &pendingstate); renatofilho@588: renatofilho@754: if (pendingstate != GST_STATE_VOID_PENDING) renatofilho@754: break; renatofilho@588: renatofilho@754: if ((oldstate == GST_STATE_READY) renatofilho@754: && (newstate == GST_STATE_PAUSED)) { renatofilho@754: if (priv->ready) renatofilho@754: g_signal_emit(user_data, g_mencoder_signals[PAUSED], renatofilho@754: 0); renatofilho@754: } else if ((oldstate == GST_STATE_PAUSED) renatofilho@754: && (newstate == GST_STATE_PLAYING)) { renatofilho@754: g_signal_emit(user_data, g_mencoder_signals[PLAYING], 0); renatofilho@754: } else if ((oldstate == GST_STATE_READY) && renatofilho@754: (newstate == GST_STATE_NULL)) { renatofilho@754: g_signal_emit(user_data, g_mencoder_signals[STOPED], 0); renatofilho@754: } renatofilho@754: break; renatofilho@754: } renatofilho@678: renatofilho@754: case GST_MESSAGE_ERROR: renatofilho@754: { renatofilho@754: GError *error; renatofilho@754: gchar *debug; renatofilho@754: gchar *err_str; morphbr@748: renatofilho@754: if (priv->tick_id != 0) { renatofilho@754: g_source_remove(priv->tick_id); renatofilho@754: priv->tick_id = 0; renatofilho@754: } morphbr@748: renatofilho@754: gst_message_parse_error(msg, &error, &debug); renatofilho@754: err_str = g_strdup_printf("Error [%d] %s (%s)", error->code, renatofilho@754: error->message, debug); renatofilho@754: priv->ready = FALSE; renatofilho@897: /* renatofilho@754: g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, renatofilho@754: err_str); renatofilho@897: */ renatofilho@754: g_free(err_str); renatofilho@754: g_clear_error(&error); renatofilho@754: g_free(debug); renatofilho@754: break; renatofilho@754: } morphbr@748: renatofilho@754: case GST_MESSAGE_EOS: renatofilho@754: priv->ready = FALSE; renatofilho@807: #ifdef USE_MANUAL_SINK renatofilho@781: _flush_queue (G_MENCODER (user_data)); renatofilho@807: #endif renatofilho@754: g_signal_emit(user_data, g_mencoder_signals[EOS], 0); renatofilho@754: break; morphbr@748: renatofilho@754: case GST_MESSAGE_DURATION: renatofilho@754: { renatofilho@754: GstFormat format; renatofilho@754: gint64 duration; renatofilho@754: gst_message_parse_duration(msg, &format, &duration); renatofilho@754: if (format == GST_FORMAT_BYTES) renatofilho@754: priv->duration = duration; renatofilho@754: break; renatofilho@754: } renatofilho@754: default: renatofilho@754: { renatofilho@754: break; renatofilho@754: } renatofilho@754: } renatofilho@754: return TRUE; renatofilho@588: } renatofilho@588: renatofilho@600: renatofilho@600: morphbr@748: static void renatofilho@752: _decodebin_new_pad_cb(GstElement * object, renatofilho@754: GstPad * pad, gboolean flag, gpointer user_data) renatofilho@588: { renatofilho@754: GstCaps *caps; renatofilho@754: gchar *str_caps = NULL; renatofilho@754: GstElement *sink_element; renatofilho@754: GstPad *sink_pad; renatofilho@588: renatofilho@754: caps = gst_pad_get_caps(pad); renatofilho@754: str_caps = gst_caps_to_string(caps); renatofilho@754: if (strstr(str_caps, "audio") != NULL) { renatofilho@754: sink_element = gst_bin_get_by_name(GST_BIN(user_data), "aqueue"); renatofilho@754: } else if (strstr(str_caps, "video") != NULL) { renatofilho@754: sink_element = gst_bin_get_by_name(GST_BIN(user_data), "vqueue"); renatofilho@754: } else { renatofilho@754: g_warning("invalid caps %s", str_caps); renatofilho@754: } renatofilho@588: renatofilho@754: sink_pad = gst_element_get_pad(sink_element, "sink"); renatofilho@897: if (!gst_pad_is_linked (sink_pad)) renatofilho@897: gst_pad_link(pad, sink_pad); renatofilho@600: renatofilho@754: gst_object_unref(sink_element); renatofilho@754: gst_object_unref(sink_pad); renatofilho@754: g_free(str_caps); renatofilho@754: gst_caps_unref(caps); renatofilho@588: } renatofilho@588: morphbr@748: static void renatofilho@752: _decodebin_unknown_type_cb(GstElement * object, renatofilho@754: GstPad * pad, GstCaps * caps, renatofilho@754: gpointer user_data) renatofilho@588: { renatofilho@754: g_warning("Unknown Type"); renatofilho@754: // priv->ready = FALSE; renatofilho@588: } renatofilho@654: renatofilho@754: static gboolean renatofilho@752: _tick_cb(gpointer user_data) renatofilho@654: { renatofilho@754: GstFormat format = GST_FORMAT_BYTES; renatofilho@754: gint64 cur = 0; renatofilho@654: renatofilho@754: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data); renatofilho@654: renatofilho@754: if (priv->duration == 0) { renatofilho@754: gint64 d = 0; renatofilho@754: if (gst_element_query_duration(priv->src, &format, &d)) renatofilho@754: priv->duration = d; renatofilho@754: } renatofilho@671: renatofilho@754: if (priv->duration != 0) { renatofilho@754: gst_element_query_position(priv->src, &format, &cur); renatofilho@754: g_print("PROGRESS:%lli\n", (99 * cur) / priv->duration); renatofilho@754: } renatofilho@654: renatofilho@754: return TRUE; renatofilho@654: } renatofilho@761: renatofilho@807: static gboolean renatofilho@807: _process_timeout_cb (gpointer user_data) renatofilho@807: { renatofilho@807: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data); renatofilho@761: renatofilho@807: g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "timeout"); renatofilho@807: priv->timeout_id = 0; renatofilho@807: return FALSE; renatofilho@807: } renatofilho@807: renatofilho@807: renatofilho@807: #ifdef USE_MANUAL_SINK renatofilho@807: static gboolean renatofilho@807: _send_buffer (GnomeVFSHandle *handle, gpointer buff, gint size) renatofilho@762: { renatofilho@762: gchar *msg; renatofilho@762: GByteArray *b_send; renatofilho@807: GnomeVFSResult result; renatofilho@807: GnomeVFSFileSize bytes_written; renatofilho@762: renatofilho@762: b_send = g_byte_array_new (); renatofilho@807: msg = g_strdup_printf ("%x\r\n", size); renatofilho@762: b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar)); renatofilho@762: g_free (msg); renatofilho@762: renatofilho@807: b_send = g_byte_array_append (b_send, buff, size); renatofilho@762: renatofilho@762: msg = g_strdup ("\r\n"); renatofilho@762: b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar)); renatofilho@762: g_free (msg); renatofilho@762: renatofilho@807: result = gnome_vfs_write (handle, b_send->data, b_send->len, &bytes_written); renatofilho@807: g_byte_array_free (b_send, TRUE); renatofilho@762: renatofilho@807: return (result == GNOME_VFS_OK); renatofilho@762: } renatofilho@762: renatofilho@762: static void renatofilho@762: _flush_queue (GMencoder *self) renatofilho@762: { renatofilho@762: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self); renatofilho@762: renatofilho@781: if (priv->send_chunked) { renatofilho@807: GnomeVFSFileSize bytes_written; renatofilho@781: gchar *end_msg; renatofilho@781: end_msg = g_strdup ("0\r\n\r\n"); renatofilho@789: gnome_vfs_write (priv->handle, renatofilho@789: (const guint8*) end_msg, renatofilho@786: strlen(end_msg) * sizeof(gchar), renatofilho@786: &bytes_written); renatofilho@781: g_free (end_msg); renatofilho@762: } renatofilho@762: } renatofilho@786: renatofilho@789: static void renatofilho@761: _buffer_arrive_cb (GstElement* object, renatofilho@807: GstBuffer* buff, renatofilho@807: GstPad* pad, renatofilho@761: gpointer user_data) renatofilho@761: { renatofilho@762: GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data); renatofilho@761: renatofilho@807: if (priv->timeout_id != 0) { renatofilho@905: g_source_remove (priv->timeout_id); renatofilho@905: priv->timeout_id = 0; renatofilho@807: } renatofilho@807: renatofilho@933: priv->timeout_id = g_timeout_add(GMENCODER_TIMEOUT, _process_timeout_cb, user_data); renatofilho@933: renatofilho@781: if (priv->send_chunked) { renatofilho@807: if (_send_buffer (priv->handle, GST_BUFFER_DATA (buff), GST_BUFFER_SIZE (buff)) == FALSE) renatofilho@807: goto error; renatofilho@807: } else { renatofilho@807: GnomeVFSResult result; renatofilho@807: GnomeVFSFileSize bytes_written; renatofilho@807: renatofilho@807: result = gnome_vfs_write (priv->handle, renatofilho@807: GST_BUFFER_DATA (buff), renatofilho@807: GST_BUFFER_SIZE (buff), renatofilho@807: &bytes_written); renatofilho@807: renatofilho@807: if (result != GNOME_VFS_OK) renatofilho@807: goto error; renatofilho@762: } renatofilho@807: renatofilho@807: return; renatofilho@807: renatofilho@807: error: renatofilho@807: if (priv->tick_id != 0) { renatofilho@807: g_source_remove(priv->tick_id); renatofilho@807: priv->tick_id = 0; renatofilho@807: } renatofilho@807: g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "Fail to write on socket"); renatofilho@807: gst_element_set_state (priv->pipe, GST_STATE_PAUSED); renatofilho@761: } renatofilho@807: renatofilho@807: #endif