gmyth-stream/gmencoder/src/gmencoder.c
author renatofilho
Sat Feb 02 23:22:44 2008 +0000 (2008-02-02)
branchtrunk
changeset 910 d20c167cc988
parent 898 4fbbacbbca34
child 916 39d46bc373eb
permissions -rw-r--r--
[svn r916] fixed gmyth.h corruption
     1 /* 
     2  *  arch-tag: Implementation gmencoder engine
     3  *
     4  *  Copyright (C) 2007 INdT - Renato Filho <renato.filho@indt.org>
     5  *
     6  *  This program is free software; you can redistribute it and/or modify
     7  *  it under the terms of the GNU General Public License as published by
     8  *  the Free Software Foundation; either version 2 of the License, or
     9  *  (at your option) any later version.
    10  *
    11  *  This program is distributed in the hope that it will be useful,
    12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  *  GNU General Public License for more details.
    15  *
    16  *  You should have received a copy of the GNU General Public License
    17  *  along with this program; if not, write to the Free Software
    18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
    19  *
    20  */
    21 
    22 #ifdef HAVE_CONFIG_H
    23 #include "config.h"
    24 #endif
    25 
    26 #include <sys/stat.h>
    27 #include <fcntl.h>
    28 #include <unistd.h>
    29 #include <glib.h>
    30 #include <gst/gst.h>
    31 #include <string.h>
    32 #include <sys/types.h>
    33 #include <sys/socket.h>
    34 #include <libgnomevfs/gnome-vfs.h>
    35 #include <gst/interfaces/tuner.h>
    36 
    37 #include "gmencoder.h"
    38 
    39 #define G_MENCODER_GET_PRIVATE(obj) \
    40     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_TYPE_MENCODER, GMencoderPrivate))
    41 
    42 #define USE_MANUAL_SINK
    43 #define GMENCODER_TIMEOUT	5000
    44 
    45 typedef struct _GMencoderPrivate GMencoderPrivate;
    46 typedef struct _SetupInfo SetupInfo;
    47 
    48 struct _SetupInfo {
    49     gchar          *video_encode;
    50     gchar          *mux_name;
    51     gchar         **video_encode_prop;
    52     gdouble         video_fps;
    53     gdouble         video_rate;
    54     guint           video_width;
    55     guint           video_height;
    56     gchar          *audio_encode;
    57     gchar         **audio_encode_prop;
    58     guint           audio_rate;
    59 };
    60 
    61 
    62 struct _GMencoderPrivate {
    63     GstElement     *pipe;
    64     GstElement     *abin;
    65     GstElement     *vbin;
    66     GstElement     *sink;
    67     GstElement     *src;
    68 
    69     GnomeVFSHandle  *handle;
    70 
    71     gboolean        ready;
    72     SetupInfo      *info;
    73     GstClockTime    videot;
    74     GstClockTime    audiot;
    75     gint            sources;
    76     gint            tick_id;
    77     gint64          duration;
    78     gboolean        send_chunked;
    79     gint 	    timeout_id;
    80 
    81     //V4l info
    82     GstElement *v4lsrc;
    83     gchar *channel;
    84     gchar *norm;
    85     glong frequency;
    86 };
    87 
    88 enum {
    89     PAUSED,
    90     PLAYING,
    91     STOPED,
    92     EOS,
    93     ERROR,
    94     LAST_SIGNAL
    95 };
    96 
    97 static void     g_mencoder_class_init(GMencoderClass * klass);
    98 static void     g_mencoder_init(GMencoder * object);
    99 static void     g_mencoder_dispose(GObject * object);
   100 static void     g_mencoder_finalize(GObject * object);
   101 static GstElement *_create_audio_bin(const gchar * encode,
   102                                      gchar ** encode_prop, gint rate);
   103 static GstElement *_create_video_bin(const gchar * encode,
   104                                      gchar ** encode_prop,
   105                                      gdouble fps,
   106                                      gint rate, guint width, guint height,
   107                                      gboolean use_deinterlace);
   108 
   109 static          gboolean
   110 _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data);
   111 
   112 static void     _decodebin_new_pad_cb(GstElement * object,
   113                                       GstPad * pad,
   114                                       gboolean flag, gpointer user_data);
   115 
   116 static void     _decodebin_unknown_type_cb(GstElement * object,
   117                                            GstPad * pad,
   118                                            GstCaps * caps,
   119                                            gpointer user_data);
   120 
   121 static void     _close_output(GMencoder * self);
   122 static gboolean _open_output(GMencoder * self, const gchar * uri);
   123 
   124 static GstElement *_create_source(GMencoder *self, const gchar * uri);
   125 static GstElement *_create_pipeline(GMencoder * self,
   126                                     const gchar * video_encode,
   127                                     const gchar * mux_name,
   128                                     gchar ** video_encode_prop,
   129                                     gdouble video_fps,
   130                                     gdouble video_rate,
   131                                     guint video_width,
   132                                     guint video_height,
   133                                     const gchar * audio_encode,
   134                                     gchar ** audio_encode_prop,
   135                                     guint audio_rate,
   136 				    gboolean deinterlace);
   137 static gboolean	_process_timeout_cb (gpointer user_data);
   138 #ifdef USE_MANUAL_SINK
   139 static void _flush_queue	        (GMencoder *self);
   140 static void _buffer_arrive_cb       (GstElement* object,
   141                                      GstBuffer* buff,
   142                                      GstPad* pad,
   143                                      gpointer user_data);
   144 #endif
   145 
   146 
   147 static gboolean _tick_cb(gpointer data);
   148 
   149 static guint    g_mencoder_signals[LAST_SIGNAL] = { 0 };
   150 
   151 G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT)
   152 
   153 static void     g_mencoder_class_init(GMencoderClass * klass)
   154 {
   155     GObjectClass   *object_class;
   156     object_class = (GObjectClass *) klass;
   157     g_type_class_add_private(klass, sizeof(GMencoderPrivate));
   158 
   159     object_class->dispose = g_mencoder_dispose;
   160     object_class->finalize = g_mencoder_finalize;
   161 
   162     g_mencoder_signals[PAUSED] =
   163         g_signal_new("paused",
   164                      G_OBJECT_CLASS_TYPE(object_class),
   165                      G_SIGNAL_RUN_FIRST,
   166                      0, NULL, NULL,
   167                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
   168 
   169     g_mencoder_signals[PLAYING] =
   170         g_signal_new("playing",
   171                      G_OBJECT_CLASS_TYPE(object_class),
   172                      G_SIGNAL_RUN_FIRST,
   173                      0, NULL, NULL,
   174                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
   175 
   176     g_mencoder_signals[STOPED] =
   177         g_signal_new("stoped",
   178                      G_OBJECT_CLASS_TYPE(object_class),
   179                      G_SIGNAL_RUN_FIRST,
   180                      0, NULL, NULL,
   181                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
   182 
   183     g_mencoder_signals[EOS] =
   184         g_signal_new("eos",
   185                      G_OBJECT_CLASS_TYPE(object_class),
   186                      G_SIGNAL_RUN_FIRST,
   187                      0, NULL, NULL,
   188                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
   189 
   190     g_mencoder_signals[ERROR] =
   191         g_signal_new("error",
   192                      G_OBJECT_CLASS_TYPE(object_class),
   193                      G_SIGNAL_RUN_LAST,
   194                      0, NULL, NULL,
   195                      g_cclosure_marshal_VOID__STRING,
   196                      G_TYPE_NONE, 1, G_TYPE_STRING);
   197 }
   198 
   199 static void
   200 g_mencoder_init(GMencoder * self)
   201 {
   202     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   203     priv->info = g_new0(SetupInfo, 1);
   204 }
   205 
   206 static void
   207 g_mencoder_dispose(GObject * object)
   208 {
   209 }
   210 
   211 static void
   212 g_mencoder_finalize(GObject * object)
   213 {
   214     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(object);
   215 
   216     // TODO: clear vars
   217     g_mencoder_close_stream(G_MENCODER(object));
   218     g_free (priv->info);
   219 }
   220 
   221 GMencoder      *
   222 g_mencoder_new(void)
   223 {
   224     return g_object_new(G_TYPE_MENCODER, NULL);
   225 }
   226 
   227 
   228 static void
   229 _obj_set_prop(GObject * obj, const gchar * prop_name,
   230               const gchar * prop_val)
   231 {
   232     GValue          p = { 0 };
   233     GValue          v = { 0 };
   234     GParamSpec     *s = NULL;
   235     GObjectClass   *k = G_OBJECT_GET_CLASS(obj);
   236 
   237 
   238     g_value_init(&v, G_TYPE_STRING);
   239     g_value_set_string(&v, prop_val);
   240 
   241     s = g_object_class_find_property(k, prop_name);
   242     if (s == NULL) {
   243         g_print("Invalid property name: %s\n", prop_name);
   244         return;
   245     }
   246 
   247     g_value_init(&p, s->value_type);
   248     switch (s->value_type) {
   249     case G_TYPE_INT:
   250         g_value_set_int(&p, atoi(prop_val));
   251         break;
   252     case G_TYPE_UINT:
   253         g_value_set_uint (&p, (guint) atoi(prop_val));
   254         break;
   255     case G_TYPE_ULONG:
   256         g_value_set_ulong (&p, atol(prop_val));
   257         break;
   258     case G_TYPE_STRING:
   259         g_value_set_string(&p, prop_val);
   260         break;
   261     case G_TYPE_BOOLEAN:
   262         g_value_set_boolean(&p, (gboolean) atoi (prop_val));
   263         break;
   264     case G_TYPE_DOUBLE:
   265         g_value_set_double(&p, atof (prop_val));
   266         break;
   267     case G_TYPE_FLOAT:
   268         g_value_set_float(&p, (float) atof (prop_val));
   269         break;
   270     default:
   271         g_value_set_enum(&p, atoi(prop_val));
   272         g_warning ("Property %s of type %s. Not supported using default enum", 
   273                    prop_name, g_type_name (s->value_type));
   274         return;
   275     }
   276 
   277     g_object_set_property(obj, prop_name, &p);
   278     g_value_unset(&v);
   279     g_value_unset(&p);
   280 }
   281 
   282 static GstElement *
   283 _create_element_with_prop(const gchar * factory_name,
   284                           const gchar * element_name, gchar ** prop)
   285 {
   286     GstElement     *ret;
   287     int             i;
   288 
   289     ret = gst_element_factory_make(factory_name, element_name);
   290     if (ret == NULL)
   291         return NULL;
   292 
   293     if (prop != NULL) {
   294         for (i = 0; i < g_strv_length(prop); i++) {
   295             if (prop[i] != NULL) {
   296                 char **v = g_strsplit(prop[i], "=", 2);
   297                 if (g_strv_length(v) == 2) {
   298                     _obj_set_prop(G_OBJECT(ret), v[0], v[1]);
   299                 }
   300                 g_strfreev(v);
   301             }
   302         }
   303     }
   304 
   305     return ret;
   306 
   307 }
   308 
   309 static GstElement *
   310 _create_audio_bin(const gchar * encode, gchar ** encode_prop, gint rate)
   311 {
   312     GstElement     *abin = NULL;
   313     GstElement     *aqueue = NULL;
   314     GstElement     *aconvert = NULL;
   315     GstElement     *aencode = NULL;
   316     GstElement     *aqueue_src = NULL;
   317     GstPad         *apad = NULL;
   318 
   319     // audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay !
   320     // udpsink name=upd_audio host=224.0.0.1 port=5002
   321     abin = gst_bin_new("abin");
   322     aqueue = gst_element_factory_make("queue", "aqueue");
   323     aconvert = gst_element_factory_make("audioconvert", "aconvert");
   324     aencode =
   325         _create_element_with_prop((encode ? encode : "lame"), "aencode",
   326                                   encode_prop);
   327     aqueue_src = gst_element_factory_make("queue", "aqueue_src");
   328 
   329     if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL)
   330         || (aencode == NULL) || (aqueue_src == NULL)) {
   331         g_warning("Audio elements not found");
   332         goto error;
   333     }
   334 
   335 
   336 
   337     gst_bin_add_many(GST_BIN(abin), aqueue, aconvert, aencode, aqueue_src,
   338                      NULL);
   339 
   340     if (!gst_element_link (aqueue, aconvert))
   341     {
   342         g_warning("Not Link audio elements");
   343         goto error;
   344     }
   345 
   346     if (rate > 0) {
   347         GstCaps *caps;
   348 
   349         caps = gst_caps_new_simple ("audio/x-raw-int",
   350                                     "rate", G_TYPE_INT, rate, NULL);
   351         if (!gst_element_link_filtered (aconvert, aencode, caps))
   352         {
   353             gst_caps_unref (caps);
   354             g_warning("Not link rate filter");
   355             goto error;
   356         }
   357 
   358         gst_caps_unref (caps);
   359     }
   360     else
   361     {
   362         if (!gst_element_link (aconvert, aencode))
   363         {
   364             g_warning ("Fail to link audio elements");
   365             goto error;
   366         }
   367     }
   368 
   369 
   370     if (!gst_element_link (aencode, aqueue_src))
   371     {
   372         g_warning("Not Link audio elements");
   373         goto error;
   374     }
   375     // TODO: apply audio rate
   376 
   377     // ghost pad the audio bin
   378     apad = gst_element_get_pad(aqueue, "sink");
   379     gst_element_add_pad(abin, gst_ghost_pad_new("sink", apad));
   380     gst_object_unref(apad);
   381 
   382     apad = gst_element_get_pad(aqueue_src, "src");
   383     gst_element_add_pad(abin, gst_ghost_pad_new("src", apad));
   384     gst_object_unref(apad);
   385 
   386     return abin;
   387   error:
   388     if (abin != NULL)
   389         gst_object_unref(abin);
   390 
   391     if (aqueue != NULL)
   392         gst_object_unref(aqueue);
   393 
   394     if (aconvert != NULL)
   395         gst_object_unref(aconvert);
   396 
   397     if (aencode != NULL)
   398         gst_object_unref(aencode);
   399 
   400     if (aqueue_src != NULL)
   401         gst_object_unref(aqueue_src);
   402 
   403     if (apad != NULL)
   404         gst_object_unref(apad);
   405 
   406     return NULL;
   407 }
   408 
   409 
   410 
   411 
   412 // queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace
   413 // ! rate ! encode ! queue
   414 static GstElement *
   415 _create_video_bin(const gchar * encode,
   416                   gchar ** encode_prop,
   417                   gdouble fps, gint rate, guint width, guint height,
   418                   gboolean use_deinterlace)
   419 {
   420     GstElement     *vbin = NULL;
   421     GstElement     *vqueue = NULL;
   422     GstElement     *vqueue_src = NULL;
   423     GstElement     *vcolorspace = NULL;
   424     GstElement     *vencode = NULL;
   425     GstElement     *vrate = NULL;
   426     GstElement     *deinterlace = NULL;
   427     GstElement     *walk = NULL;
   428     GstPad         *vpad = NULL;
   429 
   430     vbin = gst_bin_new("vbin");
   431     vqueue = gst_element_factory_make("queue", "vqueue");
   432     vcolorspace =
   433         gst_element_factory_make("ffmpegcolorspace", "colorspace");
   434 
   435     if (use_deinterlace) {
   436         deinterlace = gst_element_factory_make ("ffdeinterlace", "deinterlace");
   437         if (deinterlace == NULL) {
   438            g_warning ("Fail to create deinterlace element: Continue without deinterlace.");
   439         }
   440     }
   441 
   442 
   443     vencode = _create_element_with_prop((encode !=
   444                                          NULL ? encode :
   445                                          "ffenc_mpeg1video"), "vencode",
   446                                         encode_prop);
   447     vqueue_src = gst_element_factory_make("queue", "queue_src");
   448 
   449     if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL)
   450         || (vencode == NULL) || (vqueue_src == NULL)) {
   451         g_warning("Video elements not found");
   452         goto error;
   453     }
   454 
   455     gst_bin_add_many(GST_BIN(vbin), vqueue, vcolorspace, vencode,
   456                      vqueue_src, NULL);
   457 
   458     if (deinterlace != NULL) {
   459         gst_bin_add(GST_BIN(vbin), deinterlace);
   460         gst_element_link (vqueue, deinterlace);
   461         walk = deinterlace;
   462     } else {
   463         walk = vqueue;
   464     }
   465 
   466     if ((width > 0) && (height > 0)) {
   467         // Scalling video
   468         GstCaps        *vcaps;
   469         GstElement     *vscale;
   470 
   471         vscale = gst_element_factory_make("videoscale", "vscale");
   472         //g_object_set (G_OBJECT (vscale), "method", 1, NULL);
   473         gst_bin_add(GST_BIN(vbin), vscale);
   474 
   475         vcaps = gst_caps_new_simple("video/x-raw-yuv",
   476                                     "width", G_TYPE_INT, width,
   477                                     "height", G_TYPE_INT, height, NULL);
   478 
   479         gst_element_link(walk, vscale);
   480 
   481         if (gst_element_link_filtered(vscale, vcolorspace, vcaps) == FALSE) {
   482             g_warning("Fail to resize video");
   483             gst_object_unref(vcaps);
   484             gst_object_unref(vscale);
   485             goto error;
   486         }
   487         gst_caps_unref(vcaps);
   488     } else {
   489         gst_element_link(walk, vcolorspace);
   490     }
   491 
   492     if (fps > 0) {
   493         // Changing the video fps
   494         GstCaps        *vcaps;
   495         vrate = gst_element_factory_make("videorate", "vrate");
   496 
   497         gst_bin_add(GST_BIN(vbin), vrate);
   498 
   499         if (gst_element_link(vcolorspace, vrate) == FALSE) {
   500             g_warning("Fail to link video elements");
   501             goto error;
   502         }
   503 
   504         vcaps = gst_caps_new_simple("video/x-raw-yuv",
   505                                     "framerate", GST_TYPE_FRACTION,
   506                                     (int) (fps * 1000), 1000,
   507                                     NULL);
   508 
   509         if (gst_element_link_filtered(vrate, vencode, vcaps) == FALSE) {
   510             g_warning("Fail to link vrate with vencode.");
   511             goto error;
   512         }
   513         gst_caps_unref(vcaps);
   514     } else {
   515         if (gst_element_link(vcolorspace, vencode) == FALSE) {
   516             g_warning("Fail to link colorspace and video encode element.");
   517             goto error;
   518         }
   519     }
   520 
   521     gst_element_link(vencode, vqueue_src);
   522 
   523     // ghost pad the video bin
   524     vpad = gst_element_get_pad(vqueue, "sink");
   525     gst_element_add_pad(vbin, gst_ghost_pad_new("sink", vpad));
   526     gst_object_unref(vpad);
   527 
   528     vpad = gst_element_get_pad(vqueue_src, "src");
   529     gst_element_add_pad(vbin, gst_ghost_pad_new("src", vpad));
   530     gst_object_unref(vpad);
   531 
   532     return vbin;
   533 
   534   error:
   535     if (vpad != NULL)
   536         gst_object_unref(vpad);
   537 
   538     if (vbin != NULL)
   539         gst_object_unref(vbin);
   540 
   541     if (vqueue != NULL)
   542         gst_object_unref(vqueue);
   543 
   544     if (vencode != NULL)
   545         gst_object_unref(vencode);
   546 
   547     if (vqueue_src != NULL)
   548         gst_object_unref(vqueue_src);
   549 
   550     if (vcolorspace != NULL)
   551         gst_object_unref(vcolorspace);
   552 
   553     return NULL;
   554 }
   555 
   556 
   557 
   558 gboolean 
   559 g_mencoder_setup_stream(GMencoder * self,
   560 			gboolean chunked,
   561 			gboolean deinterlace,
   562                         const gchar * mux_name,
   563                         const gchar * video_encode,
   564                         gchar ** video_encode_prop,
   565                         gdouble video_fps,
   566                         gdouble video_rate,
   567                         guint video_width,
   568                         guint video_height,
   569                         const gchar * audio_encode,
   570                         gchar ** audio_encode_prop,
   571                         guint audio_rate, const gchar * out_uri)
   572 {
   573     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   574     if (priv->ready == TRUE) {
   575         g_warning
   576             ("Stream already configured. You need close stream first.");
   577         return FALSE;
   578     }
   579 
   580     _close_output(self);
   581     if (_open_output(self, out_uri) == FALSE) {	
   582         return FALSE;
   583     }
   584 
   585     priv->sources = 0;
   586     priv->send_chunked = chunked;
   587     priv->pipe = _create_pipeline(self,
   588                                   video_encode,
   589                                   mux_name,
   590                                   video_encode_prop,
   591                                   video_fps,
   592                                   video_rate,
   593                                   video_width,
   594                                   video_height,
   595                                   audio_encode, audio_encode_prop,
   596                                   audio_rate,
   597                                   deinterlace);
   598 
   599     return (priv->pipe != NULL);
   600 }
   601 
   602 
   603 gboolean
   604 g_mencoder_append_uri(GMencoder * self, const gchar * uri)
   605 {
   606     GstPad         *pad_src;
   607     GstPad         *pad_sink;
   608     GstElement     *src;
   609     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   610     gboolean        ret = FALSE;
   611     GstElement     *ap = NULL;
   612     GstElement     *vp = NULL;
   613 
   614 
   615     g_return_val_if_fail(priv->pipe != NULL, FALSE);
   616     g_return_val_if_fail(priv->ready == FALSE, FALSE);
   617 
   618     src = _create_source(self, uri);
   619     if (src == NULL)
   620         return FALSE;
   621 
   622     priv->src = gst_bin_get_by_name(GST_BIN(src), "src");
   623 
   624     gst_bin_add(GST_BIN(priv->pipe), src);
   625 
   626     ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "abin");
   627     vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vbin");
   628 
   629     if ((vp == NULL) || (ap == NULL)) {
   630         g_warning("Fail to get output bin");
   631         goto error;
   632     }
   633 
   634     pad_src = gst_element_get_pad(src, "src_audio");
   635     pad_sink = gst_element_get_compatible_pad(ap,
   636                                               pad_src,
   637                                               gst_pad_get_caps(pad_src));
   638 
   639     if ((pad_sink == NULL) || (pad_src == NULL))
   640         goto error;
   641 
   642     GstPadLinkReturn lret = gst_pad_link(pad_src, pad_sink);
   643     if (lret != GST_PAD_LINK_OK)
   644         goto error;
   645 
   646     gst_object_unref(pad_src);
   647     gst_object_unref(pad_sink);
   648 
   649     pad_src = gst_element_get_pad(src, "src_video");
   650     pad_sink = gst_element_get_compatible_pad(vp,
   651                                               pad_src,
   652                                               gst_pad_get_caps(pad_src));
   653 
   654     if ((pad_src == NULL) || (pad_sink == NULL))
   655         goto error;
   656 
   657     if (gst_pad_link(pad_src, pad_sink) != GST_PAD_LINK_OK) {
   658         g_warning("invalid source. video");
   659         goto error;
   660     }
   661 
   662     priv->sources++;
   663     ret = TRUE;
   664   error:
   665 
   666     if ((src != NULL) && (ret == FALSE)) {
   667         gst_bin_remove(GST_BIN(priv->pipe), src);
   668         gst_object_unref(src);
   669     }
   670 
   671     if (ap != NULL)
   672         gst_object_unref(ap);
   673 
   674     if (vp != NULL)
   675         gst_object_unref(vp);
   676 
   677     if (pad_src != NULL)
   678         gst_object_unref(pad_src);
   679 
   680     if (pad_sink != NULL)
   681         gst_object_unref(pad_sink);
   682 
   683     return ret;
   684 }
   685 
   686 
   687 
   688 void
   689 g_mencoder_remove_uri(GMencoder * self, const gchar * uri)
   690 {
   691     // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   692     // TODO: remove src
   693 }
   694 
   695 void
   696 g_mencoder_play_stream(GMencoder * self)
   697 {
   698     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   699     g_return_if_fail(priv->ready == FALSE);
   700     priv->ready = TRUE;
   701     gst_element_set_state(priv->pipe, GST_STATE_PLAYING);
   702     if (priv->tick_id != 0) {
   703         g_source_remove (priv->tick_id);
   704     }
   705     priv->tick_id = g_timeout_add(500, _tick_cb, self);
   706 
   707     if (priv->timeout_id != 0) {
   708         g_source_remove (priv->timeout_id);
   709     }
   710     //priv->timeout_id = g_timeout_add(GMENCODER_TIMEOUT, _process_timeout_cb, self);
   711 }
   712 
   713 void
   714 g_mencoder_pause_stream(GMencoder * self)
   715 {
   716     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   717     g_return_if_fail(priv->ready == TRUE);
   718     gst_element_set_state(priv->pipe, GST_STATE_PAUSED);
   719 }
   720 
   721 void
   722 g_mencoder_close_stream(GMencoder * self)
   723 {
   724 
   725     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   726     if (priv->tick_id != 0) {
   727         g_source_remove(priv->tick_id);
   728         priv->tick_id = 0;
   729     }
   730 
   731     if (priv->timeout_id != 0) {
   732         g_source_remove (priv->timeout_id);
   733 	priv->timeout_id = 0;
   734     }
   735 
   736     if (priv->pipe != NULL) {
   737         // TODO: fixe pipeline dispose
   738         //gst_element_set_state (priv->pipe, GST_STATE_NULL);
   739         // g_debug ("SETING STATE TO NULL: OK");
   740         // gst_element_set_state (priv->pipe, GST_STATE_NULL);
   741         //gst_object_unref (priv->pipe);
   742         //gst_object_unref(priv->src);
   743         priv->src = NULL;
   744         priv->pipe = NULL;
   745         priv->abin = NULL;
   746         priv->vbin = NULL;
   747         priv->sink = NULL;
   748     }
   749     priv->ready = FALSE;
   750 }
   751 
   752 static GstElement *
   753 _create_pipeline(GMencoder * self,
   754                  const gchar * video_encode,
   755                  const gchar * mux_name,
   756                  gchar ** video_encode_prop,
   757                  gdouble video_fps,
   758                  gdouble video_rate,
   759                  guint video_width,
   760                  guint video_height,
   761                  const gchar * audio_encode,
   762                  gchar ** audio_encode_prop, guint audio_rate,
   763 		         gboolean deinterlace)
   764 {
   765     GstBus         *bus = NULL;
   766     GstElement     *pipe = NULL;
   767     GstElement     *sink = NULL;
   768     GstElement     *mux = NULL;
   769     GstElement     *abin = NULL;
   770     GstElement     *vbin = NULL;
   771     GstElement     *queue = NULL;
   772     GstPad         *aux_pad = NULL;
   773     GstPad         *mux_pad = NULL;
   774 
   775     pipe = gst_pipeline_new("pipe");
   776 
   777     mux =
   778         gst_element_factory_make((mux_name ? mux_name : "ffmux_mpeg"),
   779                                  "mux");
   780     if (mux == NULL)
   781         goto error;
   782 
   783     queue = gst_element_factory_make("queue", "queueu_sink");
   784 
   785 
   786     sink = gst_element_factory_make("fakesink", "sink");
   787     g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
   788     g_signal_connect (G_OBJECT (sink),
   789                       "handoff",
   790                       G_CALLBACK (_buffer_arrive_cb),
   791                       self);
   792 
   793     abin = _create_audio_bin(audio_encode, audio_encode_prop, audio_rate);
   794     if (abin == NULL)
   795         goto error;
   796 
   797     vbin =
   798         _create_video_bin(video_encode, video_encode_prop, video_fps,
   799                           video_rate, video_width, video_height, deinterlace);
   800     if (vbin == NULL)
   801         goto error;
   802 
   803     // Finish Pipe
   804     gst_bin_add_many(GST_BIN(pipe), abin, vbin, mux, queue, sink, NULL);
   805 
   806 
   807     // Link bins with mux
   808     aux_pad = gst_element_get_pad(abin, "src");
   809     mux_pad =
   810         gst_element_get_compatible_pad(mux, aux_pad,
   811                                        GST_PAD_CAPS(aux_pad));
   812     if (mux_pad == NULL) {
   813         g_warning("Mux element no have audio PAD");
   814         goto error;
   815     }
   816     GstPadLinkReturn ret = gst_pad_link(aux_pad, mux_pad);
   817     if (ret != GST_PAD_LINK_OK) {
   818         g_warning("Fail link audio and mux: %d", ret);
   819         goto error;
   820 
   821     }
   822     gst_object_unref(aux_pad);
   823     gst_object_unref(mux_pad);
   824 
   825     aux_pad = gst_element_get_pad(vbin, "src");
   826     mux_pad =
   827         gst_element_get_compatible_pad(mux, aux_pad,
   828                                        GST_PAD_CAPS(aux_pad));
   829     if (mux_pad == NULL) {
   830         g_warning("Mux element no have video PAD");
   831         goto error;
   832     }
   833     ret = gst_pad_link(aux_pad, mux_pad);
   834     if (ret != GST_PAD_LINK_OK) {
   835         g_warning("Fail link video and mux: %d", ret);
   836         goto error;
   837     }
   838     gst_object_unref(aux_pad);
   839     gst_object_unref(mux_pad);
   840     aux_pad = NULL;
   841     mux_pad = NULL;
   842 
   843     // Link mux with sink
   844     gst_element_link_many(mux, queue, sink, NULL);
   845 
   846     bus = gst_pipeline_get_bus(GST_PIPELINE(pipe));
   847     gst_bus_add_watch(bus, _pipeline_bus_cb, self);
   848     gst_object_unref(bus);
   849     return pipe;
   850 
   851   error:
   852     g_warning("Invalid uri");
   853 
   854     if (pipe != NULL) {
   855         gst_object_unref(pipe);
   856     }
   857 
   858 
   859     if (mux != NULL) {
   860         gst_object_unref(mux);
   861     }
   862 
   863     if (mux_pad != NULL) {
   864         gst_object_unref(mux_pad);
   865     }
   866 
   867     if (aux_pad != NULL) {
   868         gst_object_unref(mux_pad);
   869     }
   870 
   871     if (sink != NULL) {
   872         gst_object_unref(sink);
   873     }
   874 
   875     if (abin != NULL) {
   876         gst_object_unref(abin);
   877     }
   878 
   879     if (vbin != NULL) {
   880         gst_object_unref(vbin);
   881     }
   882 
   883     return FALSE;
   884 }
   885 
   886 
   887 static void
   888 _close_output(GMencoder * self)
   889 {
   890 }
   891 
   892 static GstElement *
   893 _create_v4l_source (GMencoder *self, const gchar * uri)
   894 {
   895     gchar **info;
   896     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   897 
   898 
   899     info = g_strsplit (uri+6, ":", 3);
   900     if (g_strv_length (info) != 3) {
   901         return NULL;
   902     }
   903 
   904     priv->v4lsrc = gst_element_factory_make ("v4l2src", "src");
   905     g_debug ("channel %s, norm %s, frequ %s", info[0], info[1], info[2]);
   906     g_object_set (G_OBJECT (priv->v4lsrc),
   907                   "channel", info[0],
   908                   "norm", info[1],
   909                   "frequency", atoi (info[2]),
   910                   NULL);
   911 
   912     return priv->v4lsrc;
   913 }
   914 
   915 static GstElement *
   916 _create_source(GMencoder *self, const gchar * uri)
   917 {
   918 
   919     GstElement     *bsrc = NULL;
   920     GstElement     *src = NULL;
   921     GstElement     *aqueue = NULL;
   922     GstElement     *vqueue = NULL;
   923     GstElement     *decode = NULL;
   924     GstPad         *src_pad = NULL;
   925 
   926 
   927     bsrc = gst_bin_new(NULL);
   928 
   929     // src = gst_element_factory_make ("gnomevfssrc", "src");
   930     // g_object_set (G_OBJECT (src), "location", uri, NULL);
   931     if (strncmp (uri, "v4l://", 6) == 0) {
   932         g_debug ("V4L");
   933         src = _create_v4l_source (self, uri);
   934     }
   935     else {
   936         src = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
   937     }
   938 
   939     if (src == NULL)
   940         goto error;
   941 
   942 
   943     if (g_getenv ("USE_DECODEBIN1"))
   944       decode = gst_element_factory_make("decodebin", "decode");
   945     else
   946       decode = gst_element_factory_make("decodebin2", "decode");
   947     if (decode == NULL)
   948         goto error;
   949 
   950     aqueue = gst_element_factory_make("queue", "aqueue");
   951     if (aqueue == NULL)
   952         goto error;
   953 
   954     vqueue = gst_element_factory_make("queue", "vqueue");
   955     if (vqueue == NULL)
   956         goto error;
   957 
   958     gst_bin_add_many(GST_BIN(bsrc), src, decode, aqueue, vqueue,
   959                      NULL);
   960     gst_element_link (src, decode);
   961 
   962     g_signal_connect(G_OBJECT(decode),
   963                      "new-decoded-pad",
   964                      G_CALLBACK(_decodebin_new_pad_cb), bsrc);
   965 
   966     g_signal_connect(G_OBJECT(decode),
   967                      "unknown-type",
   968                      G_CALLBACK(_decodebin_unknown_type_cb), pipe);
   969 
   970     src_pad = gst_element_get_pad(aqueue, "src");
   971     gst_element_add_pad(bsrc, gst_ghost_pad_new("src_audio", src_pad));
   972     gst_object_unref(src_pad);
   973 
   974     src_pad = gst_element_get_pad(vqueue, "src");
   975     gst_element_add_pad(bsrc, gst_ghost_pad_new("src_video", src_pad));
   976     gst_object_unref(src_pad);
   977 
   978     return bsrc;
   979 
   980   error:
   981     g_debug ("Fail to create source element");
   982     if (src != NULL) {
   983         gst_object_unref(src);
   984     }
   985 
   986     if (decode != NULL) {
   987         gst_object_unref(decode);
   988     }
   989 
   990     if (aqueue != NULL) {
   991         gst_object_unref(aqueue);
   992     }
   993 
   994     if (vqueue != NULL) {
   995         gst_object_unref(vqueue);
   996     }
   997 
   998     return NULL;
   999 }
  1000 
  1001 static gboolean
  1002 _open_output(GMencoder * self, const gchar * uri)
  1003 {
  1004     gchar         **i;
  1005     GnomeVFSResult result;
  1006     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
  1007 
  1008     i = g_strsplit(uri, "://", 0);
  1009     if (strcmp(i[0], "fd") == 0) {
  1010         result = gnome_vfs_open_fd (&priv->handle, atoi(i[1]));
  1011     } else {
  1012         if (g_file_test (i[1], G_FILE_TEST_EXISTS) == FALSE) {
  1013             result = gnome_vfs_create (&priv->handle, uri, GNOME_VFS_OPEN_WRITE, FALSE,
  1014                               GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_GROUP_READ);
  1015         } else {
  1016             result = gnome_vfs_open (&priv->handle, uri,
  1017                                      GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_TRUNCATE);
  1018         }
  1019     }
  1020 
  1021     g_strfreev(i);
  1022     return (result == GNOME_VFS_OK);
  1023 }
  1024 
  1025 static          gboolean
  1026 _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data)
  1027 {
  1028     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1029 
  1030     switch (GST_MESSAGE_TYPE(msg)) {
  1031 
  1032     case GST_MESSAGE_STATE_CHANGED:
  1033         {
  1034             GstState        oldstate;
  1035             GstState        newstate;
  1036             GstState        pendingstate;
  1037 
  1038 
  1039             gst_message_parse_state_changed(msg, &oldstate,
  1040                                             &newstate, &pendingstate);
  1041 
  1042             if (pendingstate != GST_STATE_VOID_PENDING)
  1043                 break;
  1044 
  1045             if ((oldstate == GST_STATE_READY)
  1046                 && (newstate == GST_STATE_PAUSED)) {
  1047                 if (priv->ready)
  1048                     g_signal_emit(user_data, g_mencoder_signals[PAUSED],
  1049                                   0);
  1050             } else if ((oldstate == GST_STATE_PAUSED)
  1051                        && (newstate == GST_STATE_PLAYING)) {
  1052                 g_signal_emit(user_data, g_mencoder_signals[PLAYING], 0);
  1053             } else if ((oldstate == GST_STATE_READY) &&
  1054                        (newstate == GST_STATE_NULL)) {
  1055                 g_signal_emit(user_data, g_mencoder_signals[STOPED], 0);
  1056             }
  1057             break;
  1058         }
  1059 
  1060     case GST_MESSAGE_ERROR:
  1061         {
  1062             GError         *error;
  1063             gchar          *debug;
  1064             gchar          *err_str;
  1065 
  1066             if (priv->tick_id != 0) {
  1067                 g_source_remove(priv->tick_id);
  1068                 priv->tick_id = 0;
  1069             }
  1070 
  1071             gst_message_parse_error(msg, &error, &debug);
  1072             err_str = g_strdup_printf("Error [%d] %s (%s)", error->code,
  1073                                       error->message, debug);
  1074             priv->ready = FALSE;
  1075             /*
  1076             g_signal_emit(user_data, g_mencoder_signals[ERROR], 0,
  1077                           err_str);
  1078                           */
  1079             g_free(err_str);
  1080             g_clear_error(&error);
  1081             g_free(debug);
  1082             break;
  1083         }
  1084 
  1085     case GST_MESSAGE_EOS:
  1086         priv->ready = FALSE;
  1087 #ifdef USE_MANUAL_SINK
  1088         _flush_queue (G_MENCODER (user_data));
  1089 #endif
  1090         g_signal_emit(user_data, g_mencoder_signals[EOS], 0);
  1091         break;
  1092 
  1093     case GST_MESSAGE_DURATION:
  1094         {
  1095             GstFormat       format;
  1096             gint64          duration;
  1097             gst_message_parse_duration(msg, &format, &duration);
  1098             if (format == GST_FORMAT_BYTES)
  1099                 priv->duration = duration;
  1100             break;
  1101         }
  1102     default:
  1103         {
  1104             break;
  1105         }
  1106     }
  1107     return TRUE;
  1108 }
  1109 
  1110 
  1111 
  1112 static void
  1113 _decodebin_new_pad_cb(GstElement * object,
  1114                       GstPad * pad, gboolean flag, gpointer user_data)
  1115 {
  1116     GstCaps        *caps;
  1117     gchar          *str_caps = NULL;
  1118     GstElement     *sink_element;
  1119     GstPad         *sink_pad;
  1120 
  1121     caps = gst_pad_get_caps(pad);
  1122     str_caps = gst_caps_to_string(caps);
  1123     if (strstr(str_caps, "audio") != NULL) {
  1124         sink_element = gst_bin_get_by_name(GST_BIN(user_data), "aqueue");
  1125     } else if (strstr(str_caps, "video") != NULL) {
  1126         sink_element = gst_bin_get_by_name(GST_BIN(user_data), "vqueue");
  1127     } else {
  1128         g_warning("invalid caps %s", str_caps);
  1129     }
  1130 
  1131     sink_pad = gst_element_get_pad(sink_element, "sink");
  1132     if (!gst_pad_is_linked (sink_pad))
  1133         gst_pad_link(pad, sink_pad);
  1134 
  1135     gst_object_unref(sink_element);
  1136     gst_object_unref(sink_pad);
  1137     g_free(str_caps);
  1138     gst_caps_unref(caps);
  1139 }
  1140 
  1141 static void
  1142 _decodebin_unknown_type_cb(GstElement * object,
  1143                            GstPad * pad, GstCaps * caps,
  1144                            gpointer user_data)
  1145 {
  1146     g_warning("Unknown Type");
  1147     // priv->ready = FALSE;
  1148 }
  1149 
  1150 static          gboolean
  1151 _tick_cb(gpointer user_data)
  1152 {
  1153     GstFormat       format = GST_FORMAT_BYTES;
  1154     gint64          cur = 0;
  1155 
  1156     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1157 
  1158     if (priv->duration == 0) {
  1159         gint64          d = 0;
  1160         if (gst_element_query_duration(priv->src, &format, &d))
  1161             priv->duration = d;
  1162     }
  1163 
  1164     if (priv->duration != 0) {
  1165         gst_element_query_position(priv->src, &format, &cur);
  1166         g_print("PROGRESS:%lli\n", (99 * cur) / priv->duration);
  1167     }
  1168 
  1169     return TRUE;
  1170 }
  1171 
  1172 static gboolean 
  1173 _process_timeout_cb (gpointer user_data)
  1174 {
  1175     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1176 
  1177     g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "timeout");
  1178     priv->timeout_id = 0;
  1179     return FALSE;
  1180 }
  1181 
  1182 
  1183 #ifdef USE_MANUAL_SINK
  1184 static gboolean
  1185 _send_buffer (GnomeVFSHandle *handle, gpointer buff, gint size)
  1186 {
  1187     gchar *msg;
  1188     GByteArray *b_send;
  1189     GnomeVFSResult result;
  1190     GnomeVFSFileSize bytes_written;
  1191 
  1192     b_send = g_byte_array_new ();
  1193     msg = g_strdup_printf ("%x\r\n", size);
  1194     b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar));
  1195     g_free (msg);
  1196 
  1197     b_send = g_byte_array_append (b_send, buff, size);
  1198 
  1199     msg = g_strdup ("\r\n");
  1200     b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar));
  1201     g_free (msg);
  1202 
  1203     result = gnome_vfs_write (handle, b_send->data, b_send->len, &bytes_written);
  1204     g_byte_array_free (b_send, TRUE);
  1205 
  1206     return (result == GNOME_VFS_OK);
  1207 }
  1208 
  1209 static void
  1210 _flush_queue (GMencoder *self)
  1211 {
  1212     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
  1213 
  1214     if (priv->send_chunked) {
  1215         GnomeVFSFileSize bytes_written;
  1216         gchar *end_msg;
  1217         end_msg = g_strdup ("0\r\n\r\n");
  1218         gnome_vfs_write (priv->handle,
  1219                          (const guint8*) end_msg,
  1220                          strlen(end_msg) * sizeof(gchar),
  1221                          &bytes_written);
  1222         g_free (end_msg);
  1223     }
  1224 }
  1225 
  1226 static void
  1227 _buffer_arrive_cb (GstElement* object,
  1228                    GstBuffer* buff,
  1229                    GstPad* pad,
  1230                    gpointer user_data)
  1231 {
  1232     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1233 
  1234     if (priv->timeout_id != 0) {
  1235         g_source_remove (priv->timeout_id);
  1236         priv->timeout_id = 0;
  1237     }
  1238 
  1239     if (priv->send_chunked) {
  1240         if (_send_buffer (priv->handle, GST_BUFFER_DATA (buff), GST_BUFFER_SIZE (buff)) == FALSE)
  1241             goto error;
  1242     } else {
  1243         GnomeVFSResult result;
  1244         GnomeVFSFileSize bytes_written;
  1245 
  1246         result = gnome_vfs_write (priv->handle,
  1247                                   GST_BUFFER_DATA (buff),
  1248                                   GST_BUFFER_SIZE (buff),
  1249                                   &bytes_written);
  1250 
  1251         if (result != GNOME_VFS_OK)
  1252             goto error;
  1253     }
  1254 
  1255     return;
  1256 
  1257 error:
  1258     if (priv->tick_id != 0) {
  1259         g_source_remove(priv->tick_id);
  1260         priv->tick_id = 0;
  1261     }
  1262     g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "Fail to write on socket");
  1263     gst_element_set_state (priv->pipe, GST_STATE_PAUSED);
  1264 }
  1265 
  1266 #endif