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