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