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