gmyth-stream/gmemcoder/src/gmencoder.c
author morphbr
Tue Jun 26 14:32:33 2007 +0100 (2007-06-26)
branchtrunk
changeset 759 6620b7037407
parent 756 59623bb25c17
child 761 949291aaba65
permissions -rw-r--r--
[svn r765] * Removed Multicast feature
     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 gboolean _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 gboolean 
   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 FALSE;
   458     }
   459 
   460     _close_output(self);
   461     if (_open_output(self, out_uri) == FALSE)
   462         return FALSE;
   463 
   464     priv->sources = 0;
   465     priv->pipe = _create_pipeline(self,
   466                                   video_encode,
   467                                   mux_name,
   468                                   video_encode_prop,
   469                                   video_fps,
   470                                   video_rate,
   471                                   video_width,
   472                                   video_height,
   473                                   audio_encode, audio_encode_prop,
   474                                   audio_rate);
   475 
   476     return (priv->pipe != NULL);
   477 }
   478 
   479 
   480 gboolean
   481 g_mencoder_append_uri(GMencoder * self, const gchar * uri)
   482 {
   483     GstPad         *pad_src;
   484     GstPad         *pad_sink;
   485     GstElement     *src;
   486     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   487     gboolean        ret = FALSE;
   488     GstElement     *ap = NULL;
   489     GstElement     *vp = NULL;
   490 
   491 
   492     g_return_val_if_fail(priv->pipe != NULL, FALSE);
   493     g_return_val_if_fail(priv->ready == FALSE, FALSE);
   494 
   495 #ifndef SUPPORT_MULT_INPUT
   496     g_return_val_if_fail(priv->sources < 1, FALSE);
   497 #endif
   498 
   499     src = _create_source(uri);
   500     if (src == NULL)
   501         return FALSE;
   502 
   503     priv->src = gst_bin_get_by_name(GST_BIN(src), "src");
   504 
   505     gst_bin_add(GST_BIN(priv->pipe), src);
   506 
   507 #ifdef SUPPORT_MULT_INPUT
   508     ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "ap");
   509     vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vp");
   510 #else
   511     ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "abin");
   512     vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vbin");
   513 #endif
   514 
   515     if ((vp == NULL) || (ap == NULL)) {
   516         g_warning("Fail to get output bin");
   517         goto error;
   518     }
   519 
   520     pad_src = gst_element_get_pad(src, "src_audio");
   521     pad_sink = gst_element_get_compatible_pad(ap,
   522                                               pad_src,
   523                                               gst_pad_get_caps(pad_src));
   524 
   525     if ((pad_sink == NULL) || (pad_src == NULL))
   526         goto error;
   527 
   528     GstPadLinkReturn lret = gst_pad_link(pad_src, pad_sink);
   529     if (lret != GST_PAD_LINK_OK)
   530         goto error;
   531 
   532     gst_object_unref(pad_src);
   533     gst_object_unref(pad_sink);
   534 
   535     pad_src = gst_element_get_pad(src, "src_video");
   536     pad_sink = gst_element_get_compatible_pad(vp,
   537                                               pad_src,
   538                                               gst_pad_get_caps(pad_src));
   539 
   540     if ((pad_src == NULL) || (pad_sink == NULL))
   541         goto error;
   542 
   543     if (gst_pad_link(pad_src, pad_sink) != GST_PAD_LINK_OK) {
   544         g_warning("invalid source. video");
   545         goto error;
   546     }
   547 
   548     priv->sources++;
   549     ret = TRUE;
   550   error:
   551 
   552     if ((src != NULL) && (ret == FALSE)) {
   553         gst_bin_remove(GST_BIN(priv->pipe), src);
   554         gst_object_unref(src);
   555     }
   556 
   557     if (ap != NULL)
   558         gst_object_unref(ap);
   559 
   560     if (vp != NULL)
   561         gst_object_unref(vp);
   562 
   563     if (pad_src != NULL)
   564         gst_object_unref(pad_src);
   565 
   566     if (pad_sink != NULL)
   567         gst_object_unref(pad_sink);
   568 
   569     return ret;
   570 }
   571 
   572 
   573 
   574 void
   575 g_mencoder_remove_uri(GMencoder * self, const gchar * uri)
   576 {
   577     // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   578     // TODO: remove src
   579 }
   580 
   581 void
   582 g_mencoder_play_stream(GMencoder * self)
   583 {
   584     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   585     g_return_if_fail(priv->ready == FALSE);
   586     priv->ready = TRUE;
   587     gst_element_set_state(priv->pipe, GST_STATE_PLAYING);
   588     priv->tick_id = g_timeout_add(500, _tick_cb, self);
   589 }
   590 
   591 void
   592 g_mencoder_pause_stream(GMencoder * self)
   593 {
   594     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   595     g_return_if_fail(priv->ready == TRUE);
   596     gst_element_set_state(priv->pipe, GST_STATE_PAUSED);
   597 }
   598 
   599 void
   600 g_mencoder_close_stream(GMencoder * self)
   601 {
   602 
   603     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   604     if (priv->tick_id != 0) {
   605         g_source_remove(priv->tick_id);
   606         priv->tick_id = 0;
   607     }
   608 
   609     if (priv->pipe != NULL) {
   610         // TODO: fixe pipeline dispose
   611         // gst_element_set_state (priv->pipe, GST_STATE_NULL);
   612         // g_debug ("SETING STATE TO NULL: OK");
   613         // gst_element_set_state (priv->pipe, GST_STATE_NULL);
   614         // gst_object_unref (priv->pipe);
   615         gst_object_unref(priv->src);
   616         priv->src = NULL;
   617         priv->pipe = NULL;
   618         priv->abin = NULL;
   619         priv->vbin = NULL;
   620         priv->sink = NULL;
   621     }
   622     priv->ready = FALSE;
   623 }
   624 
   625 static GstElement *
   626 _create_pipeline(GMencoder * self,
   627                  const gchar * video_encode,
   628                  const gchar * mux_name,
   629                  gchar ** video_encode_prop,
   630                  gdouble video_fps,
   631                  gdouble video_rate,
   632                  guint video_width,
   633                  guint video_height,
   634                  const gchar * audio_encode,
   635                  gchar ** audio_encode_prop, guint audio_rate)
   636 {
   637     GstBus         *bus = NULL;
   638     GstElement     *pipe = NULL;
   639     GstElement     *sink = NULL;
   640     GstElement     *mux = NULL;
   641     GstElement     *abin = NULL;
   642     GstElement     *vbin = NULL;
   643     GstElement     *queue = NULL;
   644     GstPad         *aux_pad = NULL;
   645     GstPad         *mux_pad = NULL;
   646 #ifdef SUPPORT_MULT_INPUT
   647     GstElement     *ap = NULL;
   648     GstElement     *vp = NULL;
   649 #endif
   650     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   651 
   652     pipe = gst_pipeline_new("pipe");
   653 
   654 #ifdef SUPPORT_MULT_INPUT
   655     ap = gst_element_factory_make("concatmux", "ap");
   656     vp = gst_element_factory_make("concatmux", "vp");
   657     gst_bin_add_many(GST_BIN(pipe), ap, vp, NULL);
   658 #endif
   659 
   660     mux =
   661         gst_element_factory_make((mux_name ? mux_name : "ffmux_mpeg"),
   662                                  "mux");
   663     if (mux == NULL)
   664         goto error;
   665 
   666     queue = gst_element_factory_make("queue", "queueu_sink");
   667 
   668 
   669     sink = gst_element_factory_make("fdsink", "sink");
   670     if (sink == NULL)
   671         goto error;
   672 
   673     g_object_set(G_OBJECT(sink), "fd", priv->fd, "sync", FALSE, NULL);
   674 
   675     abin = _create_audio_bin(audio_encode, audio_encode_prop, audio_rate);
   676     if (abin == NULL)
   677         goto error;
   678 
   679     vbin =
   680         _create_video_bin(video_encode, video_encode_prop, video_fps,
   681                           video_rate, video_width, video_height);
   682     if (vbin == NULL)
   683         goto error;
   684 
   685     // Finish Pipe
   686     gst_bin_add_many(GST_BIN(pipe), abin, vbin, mux, queue, sink, NULL);
   687 
   688 
   689 #ifdef SUPPORT_MULT_INPUT
   690     if (gst_element_link(ap, abin) == FALSE) {
   691         g_warning("Fail to link concat and abin");
   692         goto error;
   693     }
   694 
   695     if (gst_element_link(vp, vbin) == FALSE) {
   696         g_warning("Fail to link concat and vbin");
   697     }
   698 #endif
   699 
   700     // Link bins with mux
   701     aux_pad = gst_element_get_pad(abin, "src");
   702     mux_pad =
   703         gst_element_get_compatible_pad(mux, aux_pad,
   704                                        GST_PAD_CAPS(aux_pad));
   705     if (mux_pad == NULL) {
   706         g_warning("Mux element no have audio PAD");
   707         goto error;
   708     }
   709     GstPadLinkReturn ret = gst_pad_link(aux_pad, mux_pad);
   710     if (ret != GST_PAD_LINK_OK) {
   711         g_warning("Fail link audio and mux: %d", ret);
   712         goto error;
   713 
   714     }
   715     gst_object_unref(aux_pad);
   716     gst_object_unref(mux_pad);
   717 
   718     aux_pad = gst_element_get_pad(vbin, "src");
   719     mux_pad =
   720         gst_element_get_compatible_pad(mux, aux_pad,
   721                                        GST_PAD_CAPS(aux_pad));
   722     if (mux_pad == NULL) {
   723         g_warning("Mux element no have video PAD");
   724         goto error;
   725     }
   726     ret = gst_pad_link(aux_pad, mux_pad);
   727     if (ret != GST_PAD_LINK_OK) {
   728         g_warning("Fail link video and mux: %d", ret);
   729         goto error;
   730     }
   731     gst_object_unref(aux_pad);
   732     gst_object_unref(mux_pad);
   733     aux_pad = NULL;
   734     mux_pad = NULL;
   735 
   736     // Link mux with sink
   737     gst_element_link_many(mux, queue, sink, NULL);
   738 
   739     bus = gst_pipeline_get_bus(GST_PIPELINE(pipe));
   740     gst_bus_add_watch(bus, _pipeline_bus_cb, self);
   741     gst_object_unref(bus);
   742     return pipe;
   743 
   744   error:
   745     g_warning("Invalid uri");
   746 
   747     if (pipe != NULL) {
   748         gst_object_unref(pipe);
   749     }
   750 
   751 
   752     if (mux != NULL) {
   753         gst_object_unref(mux);
   754     }
   755 
   756     if (mux_pad != NULL) {
   757         gst_object_unref(mux_pad);
   758     }
   759 
   760     if (aux_pad != NULL) {
   761         gst_object_unref(mux_pad);
   762     }
   763 
   764     if (sink != NULL) {
   765         gst_object_unref(sink);
   766     }
   767 
   768     if (abin != NULL) {
   769         gst_object_unref(abin);
   770     }
   771 
   772     if (vbin != NULL) {
   773         gst_object_unref(vbin);
   774     }
   775 
   776     return FALSE;
   777 }
   778 
   779 
   780 static void
   781 _close_output(GMencoder * self)
   782 {
   783 }
   784 
   785 static GstElement *
   786 _create_source(const gchar * uri)
   787 {
   788 
   789     GstElement     *bsrc = NULL;
   790     GstElement     *src = NULL;
   791     GstElement     *queue = NULL;
   792     GstElement     *aqueue = NULL;
   793     GstElement     *vqueue = NULL;
   794     GstElement     *decode = NULL;
   795     GstPad         *src_pad = NULL;
   796 
   797 
   798     bsrc = gst_bin_new(NULL);
   799 
   800     // src = gst_element_factory_make ("gnomevfssrc", "src");
   801     // g_object_set (G_OBJECT (src), "location", uri, NULL);
   802     src = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
   803     if (src == NULL)
   804         goto error;
   805 
   806     decode = gst_element_factory_make("decodebin", "decode");
   807     if (decode == NULL)
   808         goto error;
   809 
   810     queue = gst_element_factory_make("queue", "queue_src");
   811     aqueue = gst_element_factory_make("queue", "aqueue");
   812     if (aqueue == NULL)
   813         goto error;
   814 
   815     vqueue = gst_element_factory_make("queue", "vqueue");
   816     if (vqueue == NULL)
   817         goto error;
   818 
   819     gst_bin_add_many(GST_BIN(bsrc), src, queue, decode, aqueue, vqueue,
   820                      NULL);
   821     gst_element_link_many(src, queue, decode, NULL);
   822 
   823     g_signal_connect(G_OBJECT(decode),
   824                      "new-decoded-pad",
   825                      G_CALLBACK(_decodebin_new_pad_cb), bsrc);
   826 
   827     g_signal_connect(G_OBJECT(decode),
   828                      "unknown-type",
   829                      G_CALLBACK(_decodebin_unknown_type_cb), pipe);
   830 
   831     src_pad = gst_element_get_pad(aqueue, "src");
   832     gst_element_add_pad(bsrc, gst_ghost_pad_new("src_audio", src_pad));
   833     gst_object_unref(src_pad);
   834 
   835     src_pad = gst_element_get_pad(vqueue, "src");
   836     gst_element_add_pad(bsrc, gst_ghost_pad_new("src_video", src_pad));
   837     gst_object_unref(src_pad);
   838 
   839     return bsrc;
   840 
   841   error:
   842     if (src != NULL) {
   843         gst_object_unref(src);
   844     }
   845 
   846     if (decode != NULL) {
   847         gst_object_unref(decode);
   848     }
   849 
   850     if (aqueue != NULL) {
   851         gst_object_unref(aqueue);
   852     }
   853 
   854     if (vqueue != NULL) {
   855         gst_object_unref(vqueue);
   856     }
   857 
   858     return NULL;
   859 }
   860 
   861 static gboolean
   862 _open_output(GMencoder * self, const gchar * uri)
   863 {
   864     gboolean ret = TRUE;
   865     gchar         **i;
   866     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
   867 
   868     i = g_strsplit(uri, "://", 0);
   869     if (strcmp(i[0], "fd") == 0) {
   870         priv->fd = atoi(i[1]);
   871     } else if (strcmp(i[0], "file") == 0) {
   872         if (g_file_test (i[1], G_FILE_TEST_EXISTS)) {
   873             if (unlink (i[1]) != 0) {
   874                 g_warning ("Fail to write in : %s", uri);
   875                 ret = FALSE;
   876                 goto done;
   877             }
   878         }
   879         priv->fd = open(i[1], O_WRONLY | O_CREAT | O_TRUNC,
   880                         S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
   881 
   882         if (priv->fd == -1) {
   883             g_warning ("Fail to open : %s", uri);
   884             ret = FALSE;
   885         }
   886     } else {
   887         g_warning("Output uri not supported");
   888         ret = FALSE;
   889     }
   890 
   891 done:
   892     g_strfreev(i);
   893     return ret;
   894 }
   895 
   896 static          gboolean
   897 _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data)
   898 {
   899     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
   900 
   901     switch (GST_MESSAGE_TYPE(msg)) {
   902 
   903     case GST_MESSAGE_STATE_CHANGED:
   904         {
   905             GstState        oldstate;
   906             GstState        newstate;
   907             GstState        pendingstate;
   908 
   909 
   910             gst_message_parse_state_changed(msg, &oldstate,
   911                                             &newstate, &pendingstate);
   912 
   913             if (pendingstate != GST_STATE_VOID_PENDING)
   914                 break;
   915 
   916             if ((oldstate == GST_STATE_READY)
   917                 && (newstate == GST_STATE_PAUSED)) {
   918                 if (priv->ready)
   919                     g_signal_emit(user_data, g_mencoder_signals[PAUSED],
   920                                   0);
   921             } else if ((oldstate == GST_STATE_PAUSED)
   922                        && (newstate == GST_STATE_PLAYING)) {
   923                 g_signal_emit(user_data, g_mencoder_signals[PLAYING], 0);
   924             } else if ((oldstate == GST_STATE_READY) &&
   925                        (newstate == GST_STATE_NULL)) {
   926                 g_signal_emit(user_data, g_mencoder_signals[STOPED], 0);
   927             }
   928             break;
   929         }
   930 
   931     case GST_MESSAGE_ERROR:
   932         {
   933             GError         *error;
   934             gchar          *debug;
   935             gchar          *err_str;
   936 
   937             if (priv->tick_id != 0) {
   938                 g_source_remove(priv->tick_id);
   939                 priv->tick_id = 0;
   940             }
   941 
   942             gst_message_parse_error(msg, &error, &debug);
   943             err_str = g_strdup_printf("Error [%d] %s (%s)", error->code,
   944                                       error->message, debug);
   945             priv->ready = FALSE;
   946             g_signal_emit(user_data, g_mencoder_signals[ERROR], 0,
   947                           err_str);
   948             g_free(err_str);
   949             g_clear_error(&error);
   950             g_free(debug);
   951             break;
   952         }
   953 
   954     case GST_MESSAGE_EOS:
   955         priv->ready = FALSE;
   956         g_signal_emit(user_data, g_mencoder_signals[EOS], 0);
   957         break;
   958 
   959     case GST_MESSAGE_DURATION:
   960         {
   961             GstFormat       format;
   962             gint64          duration;
   963             gst_message_parse_duration(msg, &format, &duration);
   964             if (format == GST_FORMAT_BYTES)
   965                 priv->duration = duration;
   966             break;
   967         }
   968     default:
   969         {
   970             break;
   971         }
   972     }
   973     return TRUE;
   974 }
   975 
   976 
   977 
   978 static void
   979 _decodebin_new_pad_cb(GstElement * object,
   980                       GstPad * pad, gboolean flag, gpointer user_data)
   981 {
   982     GstCaps        *caps;
   983     gchar          *str_caps = NULL;
   984     GstElement     *sink_element;
   985     GstPad         *sink_pad;
   986 
   987     caps = gst_pad_get_caps(pad);
   988     str_caps = gst_caps_to_string(caps);
   989     if (strstr(str_caps, "audio") != NULL) {
   990         sink_element = gst_bin_get_by_name(GST_BIN(user_data), "aqueue");
   991     } else if (strstr(str_caps, "video") != NULL) {
   992         sink_element = gst_bin_get_by_name(GST_BIN(user_data), "vqueue");
   993     } else {
   994         g_warning("invalid caps %s", str_caps);
   995     }
   996 
   997     sink_pad = gst_element_get_pad(sink_element, "sink");
   998     gst_pad_link(pad, sink_pad);
   999 
  1000     gst_object_unref(sink_element);
  1001     gst_object_unref(sink_pad);
  1002     g_free(str_caps);
  1003     gst_caps_unref(caps);
  1004 }
  1005 
  1006 static void
  1007 _decodebin_unknown_type_cb(GstElement * object,
  1008                            GstPad * pad, GstCaps * caps,
  1009                            gpointer user_data)
  1010 {
  1011     g_warning("Unknown Type");
  1012     // priv->ready = FALSE;
  1013 }
  1014 
  1015 static          gboolean
  1016 _tick_cb(gpointer user_data)
  1017 {
  1018     GstFormat       format = GST_FORMAT_BYTES;
  1019     gint64          cur = 0;
  1020 
  1021     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
  1022 
  1023     if (priv->duration == 0) {
  1024         gint64          d = 0;
  1025         if (gst_element_query_duration(priv->src, &format, &d))
  1026             priv->duration = d;
  1027     }
  1028 
  1029     if (priv->duration != 0) {
  1030         gst_element_query_position(priv->src, &format, &cur);
  1031         g_print("PROGRESS:%lli\n", (99 * cur) / priv->duration);
  1032     }
  1033 
  1034     return TRUE;
  1035 }