gmyth-stream/gmencoder/src/gmencoder.c
author renatofilho
Thu Jan 31 13:19:29 2008 +0000 (2008-01-31)
branchtrunk
changeset 901 d6ec9a68363e
parent 897 715f854a93cd
child 905 d2d226b5a4bd
permissions -rw-r--r--
[svn r907] created readme file
     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, NULL);
   507 
   508         if (gst_element_link_filtered(vrate, vencode, vcaps) == FALSE) {
   509             g_warning("Fail to link vrate with vencode.");
   510             goto error;
   511         }
   512         gst_caps_unref(vcaps);
   513     } else {
   514         if (gst_element_link(vcolorspace, vencode) == FALSE) {
   515             g_warning("Fail to link colorspace and video encode element.");
   516             goto error;
   517         }
   518     }
   519 
   520     gst_element_link(vencode, vqueue_src);
   521 
   522     // ghost pad the video bin
   523     vpad = gst_element_get_pad(vqueue, "sink");
   524     gst_element_add_pad(vbin, gst_ghost_pad_new("sink", vpad));
   525     gst_object_unref(vpad);
   526 
   527     vpad = gst_element_get_pad(vqueue_src, "src");
   528     gst_element_add_pad(vbin, gst_ghost_pad_new("src", vpad));
   529     gst_object_unref(vpad);
   530 
   531     return vbin;
   532 
   533   error:
   534     if (vpad != NULL)
   535         gst_object_unref(vpad);
   536 
   537     if (vbin != NULL)
   538         gst_object_unref(vbin);
   539 
   540     if (vqueue != NULL)
   541         gst_object_unref(vqueue);
   542 
   543     if (vencode != NULL)
   544         gst_object_unref(vencode);
   545 
   546     if (vqueue_src != NULL)
   547         gst_object_unref(vqueue_src);
   548 
   549     if (vcolorspace != NULL)
   550         gst_object_unref(vcolorspace);
   551 
   552     return NULL;
   553 }
   554 
   555 
   556 
   557 gboolean 
   558 g_mencoder_setup_stream(GMencoder * self,
   559 			gboolean chunked,
   560 			gboolean deinterlace,
   561                         const gchar * mux_name,
   562                         const gchar * video_encode,
   563                         gchar ** video_encode_prop,
   564                         gdouble video_fps,
   565                         gdouble video_rate,
   566                         guint video_width,
   567                         guint video_height,
   568                         const gchar * audio_encode,
   569                         gchar ** audio_encode_prop,
   570                         guint audio_rate, const gchar * out_uri)
   571 {
   572     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   573     if (priv->ready == TRUE) {
   574         g_warning
   575             ("Stream already configured. You need close stream first.");
   576         return FALSE;
   577     }
   578 
   579     _close_output(self);
   580     if (_open_output(self, out_uri) == FALSE) {	
   581         return FALSE;
   582     }
   583 
   584     priv->sources = 0;
   585     priv->send_chunked = chunked;
   586     priv->pipe = _create_pipeline(self,
   587                                   video_encode,
   588                                   mux_name,
   589                                   video_encode_prop,
   590                                   video_fps,
   591                                   video_rate,
   592                                   video_width,
   593                                   video_height,
   594                                   audio_encode, audio_encode_prop,
   595                                   audio_rate,
   596                                   deinterlace);
   597 
   598     return (priv->pipe != NULL);
   599 }
   600 
   601 
   602 gboolean
   603 g_mencoder_append_uri(GMencoder * self, const gchar * uri)
   604 {
   605     GstPad         *pad_src;
   606     GstPad         *pad_sink;
   607     GstElement     *src;
   608     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   609     gboolean        ret = FALSE;
   610     GstElement     *ap = NULL;
   611     GstElement     *vp = NULL;
   612 
   613 
   614     g_return_val_if_fail(priv->pipe != NULL, FALSE);
   615     g_return_val_if_fail(priv->ready == FALSE, FALSE);
   616 
   617     src = _create_source(self, uri);
   618     if (src == NULL)
   619         return FALSE;
   620 
   621     priv->src = gst_bin_get_by_name(GST_BIN(src), "src");
   622 
   623     gst_bin_add(GST_BIN(priv->pipe), src);
   624 
   625     ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "abin");
   626     vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vbin");
   627 
   628     if ((vp == NULL) || (ap == NULL)) {
   629         g_warning("Fail to get output bin");
   630         goto error;
   631     }
   632 
   633     pad_src = gst_element_get_pad(src, "src_audio");
   634     pad_sink = gst_element_get_compatible_pad(ap,
   635                                               pad_src,
   636                                               gst_pad_get_caps(pad_src));
   637 
   638     if ((pad_sink == NULL) || (pad_src == NULL))
   639         goto error;
   640 
   641     GstPadLinkReturn lret = gst_pad_link(pad_src, pad_sink);
   642     if (lret != GST_PAD_LINK_OK)
   643         goto error;
   644 
   645     gst_object_unref(pad_src);
   646     gst_object_unref(pad_sink);
   647 
   648     pad_src = gst_element_get_pad(src, "src_video");
   649     pad_sink = gst_element_get_compatible_pad(vp,
   650                                               pad_src,
   651                                               gst_pad_get_caps(pad_src));
   652 
   653     if ((pad_src == NULL) || (pad_sink == NULL))
   654         goto error;
   655 
   656     if (gst_pad_link(pad_src, pad_sink) != GST_PAD_LINK_OK) {
   657         g_warning("invalid source. video");
   658         goto error;
   659     }
   660 
   661     priv->sources++;
   662     ret = TRUE;
   663   error:
   664 
   665     if ((src != NULL) && (ret == FALSE)) {
   666         gst_bin_remove(GST_BIN(priv->pipe), src);
   667         gst_object_unref(src);
   668     }
   669 
   670     if (ap != NULL)
   671         gst_object_unref(ap);
   672 
   673     if (vp != NULL)
   674         gst_object_unref(vp);
   675 
   676     if (pad_src != NULL)
   677         gst_object_unref(pad_src);
   678 
   679     if (pad_sink != NULL)
   680         gst_object_unref(pad_sink);
   681 
   682     return ret;
   683 }
   684 
   685 
   686 
   687 void
   688 g_mencoder_remove_uri(GMencoder * self, const gchar * uri)
   689 {
   690     // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   691     // TODO: remove src
   692 }
   693 
   694 void
   695 g_mencoder_play_stream(GMencoder * self)
   696 {
   697     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   698     g_return_if_fail(priv->ready == FALSE);
   699     priv->ready = TRUE;
   700     gst_element_set_state(priv->pipe, GST_STATE_PLAYING);
   701     if (priv->tick_id != 0) {
   702         g_source_remove (priv->tick_id);
   703     }
   704     priv->tick_id = g_timeout_add(500, _tick_cb, self);
   705 
   706     if (priv->timeout_id != 0) {
   707         g_source_remove (priv->timeout_id);
   708     }
   709     //priv->timeout_id = g_timeout_add(GMENCODER_TIMEOUT, _process_timeout_cb, self);
   710 }
   711 
   712 void
   713 g_mencoder_pause_stream(GMencoder * self)
   714 {
   715     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   716     g_return_if_fail(priv->ready == TRUE);
   717     gst_element_set_state(priv->pipe, GST_STATE_PAUSED);
   718 }
   719 
   720 void
   721 g_mencoder_close_stream(GMencoder * self)
   722 {
   723 
   724     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   725     if (priv->tick_id != 0) {
   726         g_source_remove(priv->tick_id);
   727         priv->tick_id = 0;
   728     }
   729 
   730     if (priv->timeout_id != 0) {
   731         g_source_remove (priv->timeout_id);
   732 	priv->timeout_id = 0;
   733     }
   734 
   735     if (priv->pipe != NULL) {
   736         // TODO: fixe pipeline dispose
   737         //gst_element_set_state (priv->pipe, GST_STATE_NULL);
   738         // g_debug ("SETING STATE TO NULL: OK");
   739         // gst_element_set_state (priv->pipe, GST_STATE_NULL);
   740         //gst_object_unref (priv->pipe);
   741         //gst_object_unref(priv->src);
   742         priv->src = NULL;
   743         priv->pipe = NULL;
   744         priv->abin = NULL;
   745         priv->vbin = NULL;
   746         priv->sink = NULL;
   747     }
   748     priv->ready = FALSE;
   749 }
   750 
   751 static GstElement *
   752 _create_pipeline(GMencoder * self,
   753                  const gchar * video_encode,
   754                  const gchar * mux_name,
   755                  gchar ** video_encode_prop,
   756                  gdouble video_fps,
   757                  gdouble video_rate,
   758                  guint video_width,
   759                  guint video_height,
   760                  const gchar * audio_encode,
   761                  gchar ** audio_encode_prop, guint audio_rate,
   762 		         gboolean deinterlace)
   763 {
   764     GstBus         *bus = NULL;
   765     GstElement     *pipe = NULL;
   766     GstElement     *sink = NULL;
   767     GstElement     *mux = NULL;
   768     GstElement     *abin = NULL;
   769     GstElement     *vbin = NULL;
   770     GstElement     *queue = NULL;
   771     GstPad         *aux_pad = NULL;
   772     GstPad         *mux_pad = NULL;
   773 
   774     pipe = gst_pipeline_new("pipe");
   775 
   776     mux =
   777         gst_element_factory_make((mux_name ? mux_name : "ffmux_mpeg"),
   778                                  "mux");
   779     if (mux == NULL)
   780         goto error;
   781 
   782     queue = gst_element_factory_make("queue", "queueu_sink");
   783 
   784 
   785     sink = gst_element_factory_make("fakesink", "sink");
   786     g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
   787     g_signal_connect (G_OBJECT (sink),
   788                       "handoff",
   789                       G_CALLBACK (_buffer_arrive_cb),
   790                       self);
   791 
   792     abin = _create_audio_bin(audio_encode, audio_encode_prop, audio_rate);
   793     if (abin == NULL)
   794         goto error;
   795 
   796     vbin =
   797         _create_video_bin(video_encode, video_encode_prop, video_fps,
   798                           video_rate, video_width, video_height, deinterlace);
   799     if (vbin == NULL)
   800         goto error;
   801 
   802     // Finish Pipe
   803     gst_bin_add_many(GST_BIN(pipe), abin, vbin, mux, queue, sink, NULL);
   804 
   805 
   806     // Link bins with mux
   807     aux_pad = gst_element_get_pad(abin, "src");
   808     mux_pad =
   809         gst_element_get_compatible_pad(mux, aux_pad,
   810                                        GST_PAD_CAPS(aux_pad));
   811     if (mux_pad == NULL) {
   812         g_warning("Mux element no have audio PAD");
   813         goto error;
   814     }
   815     GstPadLinkReturn ret = gst_pad_link(aux_pad, mux_pad);
   816     if (ret != GST_PAD_LINK_OK) {
   817         g_warning("Fail link audio and mux: %d", ret);
   818         goto error;
   819 
   820     }
   821     gst_object_unref(aux_pad);
   822     gst_object_unref(mux_pad);
   823 
   824     aux_pad = gst_element_get_pad(vbin, "src");
   825     mux_pad =
   826         gst_element_get_compatible_pad(mux, aux_pad,
   827                                        GST_PAD_CAPS(aux_pad));
   828     if (mux_pad == NULL) {
   829         g_warning("Mux element no have video PAD");
   830         goto error;
   831     }
   832     ret = gst_pad_link(aux_pad, mux_pad);
   833     if (ret != GST_PAD_LINK_OK) {
   834         g_warning("Fail link video and mux: %d", ret);
   835         goto error;
   836     }
   837     gst_object_unref(aux_pad);
   838     gst_object_unref(mux_pad);
   839     aux_pad = NULL;
   840     mux_pad = NULL;
   841 
   842     // Link mux with sink
   843     gst_element_link_many(mux, queue, sink, NULL);
   844 
   845     bus = gst_pipeline_get_bus(GST_PIPELINE(pipe));
   846     gst_bus_add_watch(bus, _pipeline_bus_cb, self);
   847     gst_object_unref(bus);
   848     return pipe;
   849 
   850   error:
   851     g_warning("Invalid uri");
   852 
   853     if (pipe != NULL) {
   854         gst_object_unref(pipe);
   855     }
   856 
   857 
   858     if (mux != NULL) {
   859         gst_object_unref(mux);
   860     }
   861 
   862     if (mux_pad != NULL) {
   863         gst_object_unref(mux_pad);
   864     }
   865 
   866     if (aux_pad != NULL) {
   867         gst_object_unref(mux_pad);
   868     }
   869 
   870     if (sink != NULL) {
   871         gst_object_unref(sink);
   872     }
   873 
   874     if (abin != NULL) {
   875         gst_object_unref(abin);
   876     }
   877 
   878     if (vbin != NULL) {
   879         gst_object_unref(vbin);
   880     }
   881 
   882     return FALSE;
   883 }
   884 
   885 
   886 static void
   887 _close_output(GMencoder * self)
   888 {
   889 }
   890 
   891 static GstElement *
   892 _create_v4l_source (GMencoder *self, const gchar * uri)
   893 {
   894     gchar **info;
   895     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   896 
   897 
   898     info = g_strsplit (uri+6, ":", 3);
   899     if (g_strv_length (info) != 3) {
   900         return NULL;
   901     }
   902 
   903     priv->v4lsrc = gst_element_factory_make ("v4l2src", "src");
   904     g_debug ("channel %s, norm %s, frequ %s", info[0], info[1], info[2]);
   905     g_object_set (G_OBJECT (priv->v4lsrc),
   906                   "channel", info[0],
   907                   "norm", info[1],
   908                   "frequency", atoi (info[2]),
   909                   NULL);
   910 
   911     return priv->v4lsrc;
   912 }
   913 
   914 static GstElement *
   915 _create_source(GMencoder *self, const gchar * uri)
   916 {
   917 
   918     GstElement     *bsrc = NULL;
   919     GstElement     *src = NULL;
   920     GstElement     *aqueue = NULL;
   921     GstElement     *vqueue = NULL;
   922     GstElement     *decode = NULL;
   923     GstPad         *src_pad = NULL;
   924 
   925 
   926     bsrc = gst_bin_new(NULL);
   927 
   928     // src = gst_element_factory_make ("gnomevfssrc", "src");
   929     // g_object_set (G_OBJECT (src), "location", uri, NULL);
   930     if (strncmp (uri, "v4l://", 6) == 0) {
   931         g_debug ("V4L");
   932         src = _create_v4l_source (self, uri);
   933     }
   934     else {
   935         src = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
   936     }
   937 
   938     if (src == NULL)
   939         goto error;
   940 
   941 
   942     if (g_getenv ("USE_DECODEBIN1"))
   943       decode = gst_element_factory_make("decodebin", "decode");
   944     else
   945       decode = gst_element_factory_make("decodebin2", "decode");
   946     if (decode == NULL)
   947         goto error;
   948 
   949     aqueue = gst_element_factory_make("queue", "aqueue");
   950     if (aqueue == NULL)
   951         goto error;
   952 
   953     vqueue = gst_element_factory_make("queue", "vqueue");
   954     if (vqueue == NULL)
   955         goto error;
   956 
   957     gst_bin_add_many(GST_BIN(bsrc), src, decode, aqueue, vqueue,
   958                      NULL);
   959     gst_element_link (src, decode);
   960 
   961     g_signal_connect(G_OBJECT(decode),
   962                      "new-decoded-pad",
   963                      G_CALLBACK(_decodebin_new_pad_cb), bsrc);
   964 
   965     g_signal_connect(G_OBJECT(decode),
   966                      "unknown-type",
   967                      G_CALLBACK(_decodebin_unknown_type_cb), pipe);
   968 
   969     src_pad = gst_element_get_pad(aqueue, "src");
   970     gst_element_add_pad(bsrc, gst_ghost_pad_new("src_audio", src_pad));
   971     gst_object_unref(src_pad);
   972 
   973     src_pad = gst_element_get_pad(vqueue, "src");
   974     gst_element_add_pad(bsrc, gst_ghost_pad_new("src_video", src_pad));
   975     gst_object_unref(src_pad);
   976 
   977     return bsrc;
   978 
   979   error:
   980     g_debug ("Fail to create source element");
   981     if (src != NULL) {
   982         gst_object_unref(src);
   983     }
   984 
   985     if (decode != NULL) {
   986         gst_object_unref(decode);
   987     }
   988 
   989     if (aqueue != NULL) {
   990         gst_object_unref(aqueue);
   991     }
   992 
   993     if (vqueue != NULL) {
   994         gst_object_unref(vqueue);
   995     }
   996 
   997     return NULL;
   998 }
   999 
  1000 static gboolean
  1001 _open_output(GMencoder * self, const gchar * uri)
  1002 {
  1003     gchar         **i;
  1004     GnomeVFSResult result;
  1005     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
  1006 
  1007     i = g_strsplit(uri, "://", 0);
  1008     if (strcmp(i[0], "fd") == 0) {
  1009         result = gnome_vfs_open_fd (&priv->handle, atoi(i[1]));
  1010     } else {
  1011         if (g_file_test (i[1], G_FILE_TEST_EXISTS) == FALSE) {
  1012             result = gnome_vfs_create (&priv->handle, uri, GNOME_VFS_OPEN_WRITE, FALSE,
  1013                               GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_GROUP_READ);
  1014         } else {
  1015             result = gnome_vfs_open (&priv->handle, uri,
  1016                                      GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_TRUNCATE);
  1017         }
  1018     }
  1019 
  1020     g_strfreev(i);
  1021     return (result == GNOME_VFS_OK);
  1022 }
  1023 
  1024 static          gboolean
  1025 _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data)
  1026 {
  1027     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1028 
  1029     switch (GST_MESSAGE_TYPE(msg)) {
  1030 
  1031     case GST_MESSAGE_STATE_CHANGED:
  1032         {
  1033             GstState        oldstate;
  1034             GstState        newstate;
  1035             GstState        pendingstate;
  1036 
  1037 
  1038             gst_message_parse_state_changed(msg, &oldstate,
  1039                                             &newstate, &pendingstate);
  1040 
  1041             if (pendingstate != GST_STATE_VOID_PENDING)
  1042                 break;
  1043 
  1044             if ((oldstate == GST_STATE_READY)
  1045                 && (newstate == GST_STATE_PAUSED)) {
  1046                 if (priv->ready)
  1047                     g_signal_emit(user_data, g_mencoder_signals[PAUSED],
  1048                                   0);
  1049             } else if ((oldstate == GST_STATE_PAUSED)
  1050                        && (newstate == GST_STATE_PLAYING)) {
  1051                 g_signal_emit(user_data, g_mencoder_signals[PLAYING], 0);
  1052             } else if ((oldstate == GST_STATE_READY) &&
  1053                        (newstate == GST_STATE_NULL)) {
  1054                 g_signal_emit(user_data, g_mencoder_signals[STOPED], 0);
  1055             }
  1056             break;
  1057         }
  1058 
  1059     case GST_MESSAGE_ERROR:
  1060         {
  1061             GError         *error;
  1062             gchar          *debug;
  1063             gchar          *err_str;
  1064 
  1065             if (priv->tick_id != 0) {
  1066                 g_source_remove(priv->tick_id);
  1067                 priv->tick_id = 0;
  1068             }
  1069 
  1070             gst_message_parse_error(msg, &error, &debug);
  1071             err_str = g_strdup_printf("Error [%d] %s (%s)", error->code,
  1072                                       error->message, debug);
  1073             priv->ready = FALSE;
  1074             /*
  1075             g_signal_emit(user_data, g_mencoder_signals[ERROR], 0,
  1076                           err_str);
  1077                           */
  1078             g_free(err_str);
  1079             g_clear_error(&error);
  1080             g_free(debug);
  1081             break;
  1082         }
  1083 
  1084     case GST_MESSAGE_EOS:
  1085         priv->ready = FALSE;
  1086 #ifdef USE_MANUAL_SINK
  1087         _flush_queue (G_MENCODER (user_data));
  1088 #endif
  1089         g_signal_emit(user_data, g_mencoder_signals[EOS], 0);
  1090         break;
  1091 
  1092     case GST_MESSAGE_DURATION:
  1093         {
  1094             GstFormat       format;
  1095             gint64          duration;
  1096             gst_message_parse_duration(msg, &format, &duration);
  1097             if (format == GST_FORMAT_BYTES)
  1098                 priv->duration = duration;
  1099             break;
  1100         }
  1101     default:
  1102         {
  1103             break;
  1104         }
  1105     }
  1106     return TRUE;
  1107 }
  1108 
  1109 
  1110 
  1111 static void
  1112 _decodebin_new_pad_cb(GstElement * object,
  1113                       GstPad * pad, gboolean flag, gpointer user_data)
  1114 {
  1115     GstCaps        *caps;
  1116     gchar          *str_caps = NULL;
  1117     GstElement     *sink_element;
  1118     GstPad         *sink_pad;
  1119 
  1120     caps = gst_pad_get_caps(pad);
  1121     str_caps = gst_caps_to_string(caps);
  1122     if (strstr(str_caps, "audio") != NULL) {
  1123         sink_element = gst_bin_get_by_name(GST_BIN(user_data), "aqueue");
  1124     } else if (strstr(str_caps, "video") != NULL) {
  1125         sink_element = gst_bin_get_by_name(GST_BIN(user_data), "vqueue");
  1126     } else {
  1127         g_warning("invalid caps %s", str_caps);
  1128     }
  1129 
  1130     sink_pad = gst_element_get_pad(sink_element, "sink");
  1131     if (!gst_pad_is_linked (sink_pad))
  1132         gst_pad_link(pad, sink_pad);
  1133 
  1134     gst_object_unref(sink_element);
  1135     gst_object_unref(sink_pad);
  1136     g_free(str_caps);
  1137     gst_caps_unref(caps);
  1138 }
  1139 
  1140 static void
  1141 _decodebin_unknown_type_cb(GstElement * object,
  1142                            GstPad * pad, GstCaps * caps,
  1143                            gpointer user_data)
  1144 {
  1145     g_warning("Unknown Type");
  1146     // priv->ready = FALSE;
  1147 }
  1148 
  1149 static          gboolean
  1150 _tick_cb(gpointer user_data)
  1151 {
  1152     GstFormat       format = GST_FORMAT_BYTES;
  1153     gint64          cur = 0;
  1154 
  1155     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1156 
  1157     if (priv->duration == 0) {
  1158         gint64          d = 0;
  1159         if (gst_element_query_duration(priv->src, &format, &d))
  1160             priv->duration = d;
  1161     }
  1162 
  1163     if (priv->duration != 0) {
  1164         gst_element_query_position(priv->src, &format, &cur);
  1165         g_print("PROGRESS:%lli\n", (99 * cur) / priv->duration);
  1166     }
  1167 
  1168     return TRUE;
  1169 }
  1170 
  1171 static gboolean 
  1172 _process_timeout_cb (gpointer user_data)
  1173 {
  1174     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1175 
  1176     g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "timeout");
  1177     priv->timeout_id = 0;
  1178     return FALSE;
  1179 }
  1180 
  1181 
  1182 #ifdef USE_MANUAL_SINK
  1183 static gboolean
  1184 _send_buffer (GnomeVFSHandle *handle, gpointer buff, gint size)
  1185 {
  1186     gchar *msg;
  1187     GByteArray *b_send;
  1188     GnomeVFSResult result;
  1189     GnomeVFSFileSize bytes_written;
  1190 
  1191     b_send = g_byte_array_new ();
  1192     msg = g_strdup_printf ("%x\r\n", size);
  1193     b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar));
  1194     g_free (msg);
  1195 
  1196     b_send = g_byte_array_append (b_send, buff, size);
  1197 
  1198     msg = g_strdup ("\r\n");
  1199     b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar));
  1200     g_free (msg);
  1201 
  1202     result = gnome_vfs_write (handle, b_send->data, b_send->len, &bytes_written);
  1203     g_byte_array_free (b_send, TRUE);
  1204 
  1205     return (result == GNOME_VFS_OK);
  1206 }
  1207 
  1208 static void
  1209 _flush_queue (GMencoder *self)
  1210 {
  1211     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
  1212 
  1213     if (priv->send_chunked) {
  1214         GnomeVFSFileSize bytes_written;
  1215         gchar *end_msg;
  1216         end_msg = g_strdup ("0\r\n\r\n");
  1217         gnome_vfs_write (priv->handle,
  1218                          (const guint8*) end_msg,
  1219                          strlen(end_msg) * sizeof(gchar),
  1220                          &bytes_written);
  1221         g_free (end_msg);
  1222     }
  1223 }
  1224 
  1225 static void
  1226 _buffer_arrive_cb (GstElement* object,
  1227                    GstBuffer* buff,
  1228                    GstPad* pad,
  1229                    gpointer user_data)
  1230 {
  1231     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1232 
  1233     if (priv->timeout_id != 0) {
  1234 	g_source_remove (priv->timeout_id);
  1235 	priv->timeout_id = 0;
  1236     }
  1237 
  1238     if (priv->send_chunked) {
  1239         if (_send_buffer (priv->handle, GST_BUFFER_DATA (buff), GST_BUFFER_SIZE (buff)) == FALSE)
  1240             goto error;
  1241     } else {
  1242         GnomeVFSResult result;
  1243         GnomeVFSFileSize bytes_written;
  1244 
  1245         result = gnome_vfs_write (priv->handle,
  1246                                   GST_BUFFER_DATA (buff),
  1247                                   GST_BUFFER_SIZE (buff),
  1248                                   &bytes_written);
  1249 
  1250         if (result != GNOME_VFS_OK)
  1251             goto error;
  1252     }
  1253 
  1254     return;
  1255 
  1256 error:
  1257     if (priv->tick_id != 0) {
  1258         g_source_remove(priv->tick_id);
  1259         priv->tick_id = 0;
  1260     }
  1261     g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "Fail to write on socket");
  1262     gst_element_set_state (priv->pipe, GST_STATE_PAUSED);
  1263 }
  1264 
  1265 #endif