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