1.1 --- a/gmyth-stream/gmemcoder/src/gmencoder.c Tue Sep 18 13:45:04 2007 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1207 +0,0 @@
1.4 -#ifdef HAVE_CONFIG_H
1.5 -#include "config.h"
1.6 -#endif
1.7 -
1.8 -#include <sys/stat.h>
1.9 -#include <fcntl.h>
1.10 -#include <unistd.h>
1.11 -#include <glib.h>
1.12 -#include <gst/gst.h>
1.13 -#include <string.h>
1.14 -#include <sys/types.h>
1.15 -#include <sys/socket.h>
1.16 -#include <libgnomevfs/gnome-vfs.h>
1.17 -#include <gst/interfaces/tuner.h>
1.18 -
1.19 -#include "gmencoder.h"
1.20 -
1.21 -#define G_MENCODER_GET_PRIVATE(obj) \
1.22 - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_TYPE_MENCODER, GMencoderPrivate))
1.23 -
1.24 -#define USE_MANUAL_SINK
1.25 -#define GMENCODER_TIMEOUT 5000
1.26 -
1.27 -typedef struct _GMencoderPrivate GMencoderPrivate;
1.28 -typedef struct _SetupInfo SetupInfo;
1.29 -
1.30 -struct _SetupInfo {
1.31 - gchar *video_encode;
1.32 - gchar *mux_name;
1.33 - gchar **video_encode_prop;
1.34 - gdouble video_fps;
1.35 - gdouble video_rate;
1.36 - guint video_width;
1.37 - guint video_height;
1.38 - gchar *audio_encode;
1.39 - gchar **audio_encode_prop;
1.40 - guint audio_rate;
1.41 -};
1.42 -
1.43 -
1.44 -struct _GMencoderPrivate {
1.45 - GstElement *pipe;
1.46 - GstElement *abin;
1.47 - GstElement *vbin;
1.48 - GstElement *sink;
1.49 - GstElement *src;
1.50 -
1.51 - GnomeVFSHandle *handle;
1.52 -
1.53 - gboolean ready;
1.54 - SetupInfo *info;
1.55 - GstClockTime videot;
1.56 - GstClockTime audiot;
1.57 - gint sources;
1.58 - gint tick_id;
1.59 - gint64 duration;
1.60 - gboolean send_chunked;
1.61 - gint timeout_id;
1.62 -
1.63 - //V4l info
1.64 - GstElement *v4lsrc;
1.65 - gchar *channel;
1.66 - gchar *norm;
1.67 - glong frequency;
1.68 -};
1.69 -
1.70 -enum {
1.71 - PAUSED,
1.72 - PLAYING,
1.73 - STOPED,
1.74 - EOS,
1.75 - ERROR,
1.76 - LAST_SIGNAL
1.77 -};
1.78 -
1.79 -static void g_mencoder_class_init(GMencoderClass * klass);
1.80 -static void g_mencoder_init(GMencoder * object);
1.81 -static void g_mencoder_dispose(GObject * object);
1.82 -static void g_mencoder_finalize(GObject * object);
1.83 -static GstElement *_create_audio_bin(const gchar * encode,
1.84 - gchar ** encode_prop, gint rate);
1.85 -static GstElement *_create_video_bin(const gchar * encode,
1.86 - gchar ** encode_prop,
1.87 - gdouble fps,
1.88 - gint rate, guint width, guint height,
1.89 - gboolean use_deinterlace);
1.90 -
1.91 -static gboolean
1.92 -_pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data);
1.93 -
1.94 -static void _decodebin_new_pad_cb(GstElement * object,
1.95 - GstPad * pad,
1.96 - gboolean flag, gpointer user_data);
1.97 -
1.98 -static void _decodebin_unknown_type_cb(GstElement * object,
1.99 - GstPad * pad,
1.100 - GstCaps * caps,
1.101 - gpointer user_data);
1.102 -
1.103 -static void _close_output(GMencoder * self);
1.104 -static gboolean _open_output(GMencoder * self, const gchar * uri);
1.105 -
1.106 -static GstElement *_create_source(GMencoder *self, const gchar * uri);
1.107 -static GstElement *_create_pipeline(GMencoder * self,
1.108 - const gchar * video_encode,
1.109 - const gchar * mux_name,
1.110 - gchar ** video_encode_prop,
1.111 - gdouble video_fps,
1.112 - gdouble video_rate,
1.113 - guint video_width,
1.114 - guint video_height,
1.115 - const gchar * audio_encode,
1.116 - gchar ** audio_encode_prop,
1.117 - guint audio_rate,
1.118 - gboolean deinterlace);
1.119 -static gboolean _process_timeout_cb (gpointer user_data);
1.120 -#ifdef USE_MANUAL_SINK
1.121 -static void _flush_queue (GMencoder *self);
1.122 -static void _buffer_arrive_cb (GstElement* object,
1.123 - GstBuffer* buff,
1.124 - GstPad* pad,
1.125 - gpointer user_data);
1.126 -#endif
1.127 -
1.128 -
1.129 -static gboolean _tick_cb(gpointer data);
1.130 -
1.131 -static guint g_mencoder_signals[LAST_SIGNAL] = { 0 };
1.132 -
1.133 -G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT)
1.134 -
1.135 -static void g_mencoder_class_init(GMencoderClass * klass)
1.136 -{
1.137 - GObjectClass *object_class;
1.138 - object_class = (GObjectClass *) klass;
1.139 - g_type_class_add_private(klass, sizeof(GMencoderPrivate));
1.140 -
1.141 - object_class->dispose = g_mencoder_dispose;
1.142 - object_class->finalize = g_mencoder_finalize;
1.143 -
1.144 - g_mencoder_signals[PAUSED] =
1.145 - g_signal_new("paused",
1.146 - G_OBJECT_CLASS_TYPE(object_class),
1.147 - G_SIGNAL_RUN_FIRST,
1.148 - 0, NULL, NULL,
1.149 - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1.150 -
1.151 - g_mencoder_signals[PLAYING] =
1.152 - g_signal_new("playing",
1.153 - G_OBJECT_CLASS_TYPE(object_class),
1.154 - G_SIGNAL_RUN_FIRST,
1.155 - 0, NULL, NULL,
1.156 - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1.157 -
1.158 - g_mencoder_signals[STOPED] =
1.159 - g_signal_new("stoped",
1.160 - G_OBJECT_CLASS_TYPE(object_class),
1.161 - G_SIGNAL_RUN_FIRST,
1.162 - 0, NULL, NULL,
1.163 - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1.164 -
1.165 - g_mencoder_signals[EOS] =
1.166 - g_signal_new("eos",
1.167 - G_OBJECT_CLASS_TYPE(object_class),
1.168 - G_SIGNAL_RUN_FIRST,
1.169 - 0, NULL, NULL,
1.170 - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1.171 -
1.172 - g_mencoder_signals[ERROR] =
1.173 - g_signal_new("error",
1.174 - G_OBJECT_CLASS_TYPE(object_class),
1.175 - G_SIGNAL_RUN_LAST,
1.176 - 0, NULL, NULL,
1.177 - g_cclosure_marshal_VOID__STRING,
1.178 - G_TYPE_NONE, 1, G_TYPE_STRING);
1.179 -}
1.180 -
1.181 -static void
1.182 -g_mencoder_init(GMencoder * self)
1.183 -{
1.184 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.185 - priv->info = g_new0(SetupInfo, 1);
1.186 -}
1.187 -
1.188 -static void
1.189 -g_mencoder_dispose(GObject * object)
1.190 -{
1.191 -}
1.192 -
1.193 -static void
1.194 -g_mencoder_finalize(GObject * object)
1.195 -{
1.196 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(object);
1.197 -
1.198 - // TODO: clear vars
1.199 - g_mencoder_close_stream(G_MENCODER(object));
1.200 - g_free (priv->info);
1.201 -}
1.202 -
1.203 -GMencoder *
1.204 -g_mencoder_new(void)
1.205 -{
1.206 - return g_object_new(G_TYPE_MENCODER, NULL);
1.207 -}
1.208 -
1.209 -
1.210 -static void
1.211 -_obj_set_prop(GObject * obj, const gchar * prop_name,
1.212 - const gchar * prop_val)
1.213 -{
1.214 - GValue p = { 0 };
1.215 - GValue v = { 0 };
1.216 - GParamSpec *s = NULL;
1.217 - GObjectClass *k = G_OBJECT_GET_CLASS(obj);
1.218 -
1.219 -
1.220 - g_value_init(&v, G_TYPE_STRING);
1.221 - g_value_set_string(&v, prop_val);
1.222 -
1.223 - s = g_object_class_find_property(k, prop_name);
1.224 - if (s == NULL) {
1.225 - g_print("Invalid property name: %s\n", prop_name);
1.226 - return;
1.227 - }
1.228 -
1.229 - g_value_init(&p, s->value_type);
1.230 - switch (s->value_type) {
1.231 - case G_TYPE_INT:
1.232 - g_value_set_int(&p, atoi(prop_val));
1.233 - break;
1.234 - case G_TYPE_ULONG:
1.235 - g_value_set_ulong (&p, atol(prop_val));
1.236 - break;
1.237 - case G_TYPE_STRING:
1.238 - g_value_set_string(&p, prop_val);
1.239 - break;
1.240 - case G_TYPE_BOOLEAN:
1.241 - g_value_set_boolean(&p, (gboolean) atoi (prop_val));
1.242 - break;
1.243 - case G_TYPE_DOUBLE:
1.244 - g_value_set_double(&p, atof (prop_val));
1.245 - break;
1.246 - case G_TYPE_FLOAT:
1.247 - g_value_set_float(&p, (float) atof (prop_val));
1.248 - break;
1.249 - default:
1.250 - g_value_set_enum(&p, atoi(prop_val));
1.251 - g_warning ("Property %s of type %s. Not supported using default enum",
1.252 - prop_name, g_type_name (s->value_type));
1.253 - return;
1.254 - }
1.255 -
1.256 - g_object_set_property(obj, prop_name, &p);
1.257 - g_value_unset(&v);
1.258 - g_value_unset(&p);
1.259 -}
1.260 -
1.261 -static GstElement *
1.262 -_create_element_with_prop(const gchar * factory_name,
1.263 - const gchar * element_name, gchar ** prop)
1.264 -{
1.265 - GstElement *ret;
1.266 - int i;
1.267 -
1.268 - ret = gst_element_factory_make(factory_name, element_name);
1.269 - if (ret == NULL)
1.270 - return NULL;
1.271 -
1.272 - if (prop != NULL) {
1.273 - for (i = 0; i < g_strv_length(prop); i++) {
1.274 - if (prop[i] != NULL) {
1.275 - char **v = g_strsplit(prop[i], "=", 2);
1.276 - if (g_strv_length(v) == 2) {
1.277 - _obj_set_prop(G_OBJECT(ret), v[0], v[1]);
1.278 - }
1.279 - g_strfreev(v);
1.280 - }
1.281 - }
1.282 - }
1.283 -
1.284 - return ret;
1.285 -
1.286 -}
1.287 -
1.288 -static GstElement *
1.289 -_create_audio_bin(const gchar * encode, gchar ** encode_prop, gint rate)
1.290 -{
1.291 - GstElement *abin = NULL;
1.292 - GstElement *aqueue = NULL;
1.293 - GstElement *aconvert = NULL;
1.294 - GstElement *aencode = NULL;
1.295 - GstElement *aqueue_src = NULL;
1.296 - GstPad *apad = NULL;
1.297 -
1.298 - // audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay !
1.299 - // udpsink name=upd_audio host=224.0.0.1 port=5002
1.300 - abin = gst_bin_new("abin");
1.301 - aqueue = gst_element_factory_make("queue", "aqueue");
1.302 - aconvert = gst_element_factory_make("audioconvert", "aconvert");
1.303 - aencode =
1.304 - _create_element_with_prop((encode ? encode : "lame"), "aencode",
1.305 - encode_prop);
1.306 - aqueue_src = gst_element_factory_make("queue", "aqueue_src");
1.307 -
1.308 - if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL)
1.309 - || (aencode == NULL) || (aqueue_src == NULL)) {
1.310 - g_warning("Audio elements not found");
1.311 - goto error;
1.312 - }
1.313 -
1.314 - g_object_set(G_OBJECT(aencode), "bitrate", 32, NULL);
1.315 - /*
1.316 - * if (rate > 0) { g_object_set (G_OBJECT (aencode), "bitrate", 32,
1.317 - * NULL); }
1.318 - */
1.319 -
1.320 - gst_bin_add_many(GST_BIN(abin), aqueue, aconvert, aencode, aqueue_src,
1.321 - NULL);
1.322 - if (gst_element_link_many(aqueue, aconvert, aencode, aqueue_src, NULL)
1.323 - == FALSE) {
1.324 - g_warning("Not Link audio elements");
1.325 - }
1.326 - // TODO: apply audio rate
1.327 -
1.328 - // ghost pad the audio bin
1.329 - apad = gst_element_get_pad(aqueue, "sink");
1.330 - gst_element_add_pad(abin, gst_ghost_pad_new("sink", apad));
1.331 - gst_object_unref(apad);
1.332 -
1.333 - apad = gst_element_get_pad(aqueue_src, "src");
1.334 - gst_element_add_pad(abin, gst_ghost_pad_new("src", apad));
1.335 - gst_object_unref(apad);
1.336 -
1.337 - return abin;
1.338 - error:
1.339 - if (abin != NULL)
1.340 - gst_object_unref(abin);
1.341 -
1.342 - if (aqueue != NULL)
1.343 - gst_object_unref(aqueue);
1.344 -
1.345 - if (aconvert != NULL)
1.346 - gst_object_unref(aconvert);
1.347 -
1.348 - if (aencode != NULL)
1.349 - gst_object_unref(aencode);
1.350 -
1.351 - if (aqueue_src != NULL)
1.352 - gst_object_unref(aqueue_src);
1.353 -
1.354 - if (apad != NULL)
1.355 - gst_object_unref(apad);
1.356 -
1.357 - return NULL;
1.358 -}
1.359 -
1.360 -
1.361 -
1.362 -
1.363 -// queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace
1.364 -// ! rate ! encode ! queue
1.365 -static GstElement *
1.366 -_create_video_bin(const gchar * encode,
1.367 - gchar ** encode_prop,
1.368 - gdouble fps, gint rate, guint width, guint height,
1.369 - gboolean use_deinterlace)
1.370 -{
1.371 - GstElement *vbin = NULL;
1.372 - GstElement *vqueue = NULL;
1.373 - GstElement *vqueue_src = NULL;
1.374 - GstElement *vcolorspace = NULL;
1.375 - GstElement *vencode = NULL;
1.376 - GstElement *vrate = NULL;
1.377 - GstElement *deinterlace = NULL;
1.378 - GstElement *walk = NULL;
1.379 - GstPad *vpad = NULL;
1.380 -
1.381 - vbin = gst_bin_new("vbin");
1.382 - vqueue = gst_element_factory_make("queue", "vqueue");
1.383 - vcolorspace =
1.384 - gst_element_factory_make("ffmpegcolorspace", "colorspace");
1.385 -
1.386 - if (use_deinterlace) {
1.387 - deinterlace = gst_element_factory_make ("ffdeinterlace", "deinterlace");
1.388 - if (deinterlace == NULL) {
1.389 - g_warning ("Fail to create deinterlace element: Continue without deinterlace.");
1.390 - }
1.391 - }
1.392 -
1.393 -
1.394 - vencode = _create_element_with_prop((encode !=
1.395 - NULL ? encode :
1.396 - "ffenc_mpeg1video"), "vencode",
1.397 - encode_prop);
1.398 - vqueue_src = gst_element_factory_make("queue", "queue_src");
1.399 -
1.400 - if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL)
1.401 - || (vencode == NULL) || (vqueue_src == NULL)) {
1.402 - g_warning("Video elements not found");
1.403 - goto error;
1.404 - }
1.405 -
1.406 - gst_bin_add_many(GST_BIN(vbin), vqueue, vcolorspace, vencode,
1.407 - vqueue_src, NULL);
1.408 -
1.409 - if (deinterlace != NULL) {
1.410 - gst_bin_add(GST_BIN(vbin), deinterlace);
1.411 - gst_element_link (vqueue, deinterlace);
1.412 - walk = deinterlace;
1.413 - } else {
1.414 - walk = vqueue;
1.415 - }
1.416 -
1.417 - if ((width > 0) && (height > 0)) {
1.418 - // Scalling video
1.419 - GstCaps *vcaps;
1.420 - GstElement *vscale =
1.421 - gst_element_factory_make("videoscale", "vscale");
1.422 -
1.423 - g_object_set (G_OBJECT (vscale), "method", 1, NULL);
1.424 -
1.425 - gst_bin_add(GST_BIN(vbin), vscale);
1.426 -
1.427 - vcaps = gst_caps_new_simple("video/x-raw-yuv",
1.428 - "width", G_TYPE_INT, width,
1.429 - "height", G_TYPE_INT, height, NULL);
1.430 -
1.431 - gst_element_link(walk, vscale);
1.432 -
1.433 - if (gst_element_link_filtered(vscale, vcolorspace, vcaps) == FALSE) {
1.434 - g_warning("Fail to resize video");
1.435 - gst_object_unref(vcaps);
1.436 - gst_object_unref(vscale);
1.437 - goto error;
1.438 - }
1.439 - gst_caps_unref(vcaps);
1.440 - } else {
1.441 - gst_element_link(walk, vcolorspace);
1.442 - }
1.443 -
1.444 - if (fps > 0) {
1.445 - // Changing the video fps
1.446 - GstCaps *vcaps;
1.447 - vrate = gst_element_factory_make("videorate", "vrate");
1.448 -
1.449 - gst_bin_add(GST_BIN(vbin), vrate);
1.450 -
1.451 - if (gst_element_link(vcolorspace, vrate) == FALSE) {
1.452 - g_warning("Fail to link video elements");
1.453 - goto error;
1.454 - }
1.455 -
1.456 - vcaps = gst_caps_new_simple("video/x-raw-yuv",
1.457 - "framerate", GST_TYPE_FRACTION,
1.458 - (int) (fps * 1000), 1000, NULL);
1.459 -
1.460 - if (gst_element_link_filtered(vrate, vencode, vcaps) == FALSE) {
1.461 - g_warning("Fail to link vrate with vencode.");
1.462 - goto error;
1.463 - }
1.464 - gst_caps_unref(vcaps);
1.465 - } else {
1.466 - if (gst_element_link(vcolorspace, vencode) == FALSE) {
1.467 - g_warning("Fail to link colorspace and video encode element.");
1.468 - goto error;
1.469 - }
1.470 - }
1.471 -
1.472 - gst_element_link(vencode, vqueue_src);
1.473 -
1.474 - // ghost pad the video bin
1.475 - vpad = gst_element_get_pad(vqueue, "sink");
1.476 - gst_element_add_pad(vbin, gst_ghost_pad_new("sink", vpad));
1.477 - gst_object_unref(vpad);
1.478 -
1.479 - vpad = gst_element_get_pad(vqueue_src, "src");
1.480 - gst_element_add_pad(vbin, gst_ghost_pad_new("src", vpad));
1.481 - gst_object_unref(vpad);
1.482 -
1.483 - return vbin;
1.484 -
1.485 - error:
1.486 - if (vpad != NULL)
1.487 - gst_object_unref(vpad);
1.488 -
1.489 - if (vbin != NULL)
1.490 - gst_object_unref(vbin);
1.491 -
1.492 - if (vqueue != NULL)
1.493 - gst_object_unref(vqueue);
1.494 -
1.495 - if (vencode != NULL)
1.496 - gst_object_unref(vencode);
1.497 -
1.498 - if (vqueue_src != NULL)
1.499 - gst_object_unref(vqueue_src);
1.500 -
1.501 - if (vcolorspace != NULL)
1.502 - gst_object_unref(vcolorspace);
1.503 -
1.504 - return NULL;
1.505 -}
1.506 -
1.507 -
1.508 -
1.509 -gboolean
1.510 -g_mencoder_setup_stream(GMencoder * self,
1.511 - gboolean chunked,
1.512 - gboolean deinterlace,
1.513 - const gchar * mux_name,
1.514 - const gchar * video_encode,
1.515 - gchar ** video_encode_prop,
1.516 - gdouble video_fps,
1.517 - gdouble video_rate,
1.518 - guint video_width,
1.519 - guint video_height,
1.520 - const gchar * audio_encode,
1.521 - gchar ** audio_encode_prop,
1.522 - guint audio_rate, const gchar * out_uri)
1.523 -{
1.524 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.525 - if (priv->ready == TRUE) {
1.526 - g_warning
1.527 - ("Stream already configured. You need close stream first.");
1.528 - return FALSE;
1.529 - }
1.530 -
1.531 - _close_output(self);
1.532 - if (_open_output(self, out_uri) == FALSE) {
1.533 - return FALSE;
1.534 - }
1.535 -
1.536 - priv->sources = 0;
1.537 - priv->send_chunked = chunked;
1.538 - priv->pipe = _create_pipeline(self,
1.539 - video_encode,
1.540 - mux_name,
1.541 - video_encode_prop,
1.542 - video_fps,
1.543 - video_rate,
1.544 - video_width,
1.545 - video_height,
1.546 - audio_encode, audio_encode_prop,
1.547 - audio_rate,
1.548 - deinterlace);
1.549 -
1.550 - return (priv->pipe != NULL);
1.551 -}
1.552 -
1.553 -
1.554 -gboolean
1.555 -g_mencoder_append_uri(GMencoder * self, const gchar * uri)
1.556 -{
1.557 - GstPad *pad_src;
1.558 - GstPad *pad_sink;
1.559 - GstElement *src;
1.560 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.561 - gboolean ret = FALSE;
1.562 - GstElement *ap = NULL;
1.563 - GstElement *vp = NULL;
1.564 -
1.565 -
1.566 - g_return_val_if_fail(priv->pipe != NULL, FALSE);
1.567 - g_return_val_if_fail(priv->ready == FALSE, FALSE);
1.568 -
1.569 - src = _create_source(self, uri);
1.570 - if (src == NULL)
1.571 - return FALSE;
1.572 -
1.573 - priv->src = gst_bin_get_by_name(GST_BIN(src), "src");
1.574 -
1.575 - gst_bin_add(GST_BIN(priv->pipe), src);
1.576 -
1.577 - ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "abin");
1.578 - vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vbin");
1.579 -
1.580 - if ((vp == NULL) || (ap == NULL)) {
1.581 - g_warning("Fail to get output bin");
1.582 - goto error;
1.583 - }
1.584 -
1.585 - pad_src = gst_element_get_pad(src, "src_audio");
1.586 - pad_sink = gst_element_get_compatible_pad(ap,
1.587 - pad_src,
1.588 - gst_pad_get_caps(pad_src));
1.589 -
1.590 - if ((pad_sink == NULL) || (pad_src == NULL))
1.591 - goto error;
1.592 -
1.593 - GstPadLinkReturn lret = gst_pad_link(pad_src, pad_sink);
1.594 - if (lret != GST_PAD_LINK_OK)
1.595 - goto error;
1.596 -
1.597 - gst_object_unref(pad_src);
1.598 - gst_object_unref(pad_sink);
1.599 -
1.600 - pad_src = gst_element_get_pad(src, "src_video");
1.601 - pad_sink = gst_element_get_compatible_pad(vp,
1.602 - pad_src,
1.603 - gst_pad_get_caps(pad_src));
1.604 -
1.605 - if ((pad_src == NULL) || (pad_sink == NULL))
1.606 - goto error;
1.607 -
1.608 - if (gst_pad_link(pad_src, pad_sink) != GST_PAD_LINK_OK) {
1.609 - g_warning("invalid source. video");
1.610 - goto error;
1.611 - }
1.612 -
1.613 - priv->sources++;
1.614 - ret = TRUE;
1.615 - error:
1.616 -
1.617 - if ((src != NULL) && (ret == FALSE)) {
1.618 - gst_bin_remove(GST_BIN(priv->pipe), src);
1.619 - gst_object_unref(src);
1.620 - }
1.621 -
1.622 - if (ap != NULL)
1.623 - gst_object_unref(ap);
1.624 -
1.625 - if (vp != NULL)
1.626 - gst_object_unref(vp);
1.627 -
1.628 - if (pad_src != NULL)
1.629 - gst_object_unref(pad_src);
1.630 -
1.631 - if (pad_sink != NULL)
1.632 - gst_object_unref(pad_sink);
1.633 -
1.634 - return ret;
1.635 -}
1.636 -
1.637 -
1.638 -
1.639 -void
1.640 -g_mencoder_remove_uri(GMencoder * self, const gchar * uri)
1.641 -{
1.642 - // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
1.643 - // TODO: remove src
1.644 -}
1.645 -
1.646 -void
1.647 -g_mencoder_play_stream(GMencoder * self)
1.648 -{
1.649 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.650 - g_return_if_fail(priv->ready == FALSE);
1.651 - priv->ready = TRUE;
1.652 - gst_element_set_state(priv->pipe, GST_STATE_PLAYING);
1.653 - if (priv->tick_id != 0) {
1.654 - g_source_remove (priv->tick_id);
1.655 - }
1.656 - priv->tick_id = g_timeout_add(500, _tick_cb, self);
1.657 -
1.658 - if (priv->timeout_id != 0) {
1.659 - g_source_remove (priv->timeout_id);
1.660 - }
1.661 - //priv->timeout_id = g_timeout_add(GMENCODER_TIMEOUT, _process_timeout_cb, self);
1.662 -}
1.663 -
1.664 -void
1.665 -g_mencoder_pause_stream(GMencoder * self)
1.666 -{
1.667 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.668 - g_return_if_fail(priv->ready == TRUE);
1.669 - gst_element_set_state(priv->pipe, GST_STATE_PAUSED);
1.670 -}
1.671 -
1.672 -void
1.673 -g_mencoder_close_stream(GMencoder * self)
1.674 -{
1.675 -
1.676 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.677 - if (priv->tick_id != 0) {
1.678 - g_source_remove(priv->tick_id);
1.679 - priv->tick_id = 0;
1.680 - }
1.681 -
1.682 - if (priv->timeout_id != 0) {
1.683 - g_source_remove (priv->timeout_id);
1.684 - priv->timeout_id = 0;
1.685 - }
1.686 -
1.687 - if (priv->pipe != NULL) {
1.688 - // TODO: fixe pipeline dispose
1.689 - //gst_element_set_state (priv->pipe, GST_STATE_NULL);
1.690 - // g_debug ("SETING STATE TO NULL: OK");
1.691 - // gst_element_set_state (priv->pipe, GST_STATE_NULL);
1.692 - //gst_object_unref (priv->pipe);
1.693 - //gst_object_unref(priv->src);
1.694 - priv->src = NULL;
1.695 - priv->pipe = NULL;
1.696 - priv->abin = NULL;
1.697 - priv->vbin = NULL;
1.698 - priv->sink = NULL;
1.699 - }
1.700 - priv->ready = FALSE;
1.701 -}
1.702 -
1.703 -static GstElement *
1.704 -_create_pipeline(GMencoder * self,
1.705 - const gchar * video_encode,
1.706 - const gchar * mux_name,
1.707 - gchar ** video_encode_prop,
1.708 - gdouble video_fps,
1.709 - gdouble video_rate,
1.710 - guint video_width,
1.711 - guint video_height,
1.712 - const gchar * audio_encode,
1.713 - gchar ** audio_encode_prop, guint audio_rate,
1.714 - gboolean deinterlace)
1.715 -{
1.716 - GstBus *bus = NULL;
1.717 - GstElement *pipe = NULL;
1.718 - GstElement *sink = NULL;
1.719 - GstElement *mux = NULL;
1.720 - GstElement *abin = NULL;
1.721 - GstElement *vbin = NULL;
1.722 - GstElement *queue = NULL;
1.723 - GstPad *aux_pad = NULL;
1.724 - GstPad *mux_pad = NULL;
1.725 -
1.726 - pipe = gst_pipeline_new("pipe");
1.727 -
1.728 - mux =
1.729 - gst_element_factory_make((mux_name ? mux_name : "ffmux_mpeg"),
1.730 - "mux");
1.731 - if (mux == NULL)
1.732 - goto error;
1.733 -
1.734 - queue = gst_element_factory_make("queue", "queueu_sink");
1.735 -
1.736 -
1.737 - sink = gst_element_factory_make("fakesink", "sink");
1.738 - g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
1.739 - g_signal_connect (G_OBJECT (sink),
1.740 - "handoff",
1.741 - G_CALLBACK (_buffer_arrive_cb),
1.742 - self);
1.743 -
1.744 - abin = _create_audio_bin(audio_encode, audio_encode_prop, audio_rate);
1.745 - if (abin == NULL)
1.746 - goto error;
1.747 -
1.748 - vbin =
1.749 - _create_video_bin(video_encode, video_encode_prop, video_fps,
1.750 - video_rate, video_width, video_height, deinterlace);
1.751 - if (vbin == NULL)
1.752 - goto error;
1.753 -
1.754 - // Finish Pipe
1.755 - gst_bin_add_many(GST_BIN(pipe), abin, vbin, mux, queue, sink, NULL);
1.756 -
1.757 -
1.758 - // Link bins with mux
1.759 - aux_pad = gst_element_get_pad(abin, "src");
1.760 - mux_pad =
1.761 - gst_element_get_compatible_pad(mux, aux_pad,
1.762 - GST_PAD_CAPS(aux_pad));
1.763 - if (mux_pad == NULL) {
1.764 - g_warning("Mux element no have audio PAD");
1.765 - goto error;
1.766 - }
1.767 - GstPadLinkReturn ret = gst_pad_link(aux_pad, mux_pad);
1.768 - if (ret != GST_PAD_LINK_OK) {
1.769 - g_warning("Fail link audio and mux: %d", ret);
1.770 - goto error;
1.771 -
1.772 - }
1.773 - gst_object_unref(aux_pad);
1.774 - gst_object_unref(mux_pad);
1.775 -
1.776 - aux_pad = gst_element_get_pad(vbin, "src");
1.777 - mux_pad =
1.778 - gst_element_get_compatible_pad(mux, aux_pad,
1.779 - GST_PAD_CAPS(aux_pad));
1.780 - if (mux_pad == NULL) {
1.781 - g_warning("Mux element no have video PAD");
1.782 - goto error;
1.783 - }
1.784 - ret = gst_pad_link(aux_pad, mux_pad);
1.785 - if (ret != GST_PAD_LINK_OK) {
1.786 - g_warning("Fail link video and mux: %d", ret);
1.787 - goto error;
1.788 - }
1.789 - gst_object_unref(aux_pad);
1.790 - gst_object_unref(mux_pad);
1.791 - aux_pad = NULL;
1.792 - mux_pad = NULL;
1.793 -
1.794 - // Link mux with sink
1.795 - gst_element_link_many(mux, queue, sink, NULL);
1.796 -
1.797 - bus = gst_pipeline_get_bus(GST_PIPELINE(pipe));
1.798 - gst_bus_add_watch(bus, _pipeline_bus_cb, self);
1.799 - gst_object_unref(bus);
1.800 - return pipe;
1.801 -
1.802 - error:
1.803 - g_warning("Invalid uri");
1.804 -
1.805 - if (pipe != NULL) {
1.806 - gst_object_unref(pipe);
1.807 - }
1.808 -
1.809 -
1.810 - if (mux != NULL) {
1.811 - gst_object_unref(mux);
1.812 - }
1.813 -
1.814 - if (mux_pad != NULL) {
1.815 - gst_object_unref(mux_pad);
1.816 - }
1.817 -
1.818 - if (aux_pad != NULL) {
1.819 - gst_object_unref(mux_pad);
1.820 - }
1.821 -
1.822 - if (sink != NULL) {
1.823 - gst_object_unref(sink);
1.824 - }
1.825 -
1.826 - if (abin != NULL) {
1.827 - gst_object_unref(abin);
1.828 - }
1.829 -
1.830 - if (vbin != NULL) {
1.831 - gst_object_unref(vbin);
1.832 - }
1.833 -
1.834 - return FALSE;
1.835 -}
1.836 -
1.837 -
1.838 -static void
1.839 -_close_output(GMencoder * self)
1.840 -{
1.841 -}
1.842 -
1.843 -static GstElement *
1.844 -_create_v4l_source (GMencoder *self, const gchar * uri)
1.845 -{
1.846 - gchar **info;
1.847 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.848 -
1.849 -
1.850 - info = g_strsplit (uri+6, ":", 3);
1.851 - if (g_strv_length (info) != 3) {
1.852 - return NULL;
1.853 - }
1.854 -
1.855 - priv->v4lsrc = gst_element_factory_make ("v4l2src", "src");
1.856 - g_debug ("channel %s, norm %s, frequ %s", info[0], info[1], info[2]);
1.857 - g_object_set (G_OBJECT (priv->v4lsrc),
1.858 - "channel", info[0],
1.859 - "norm", info[1],
1.860 - "frequency", atoi (info[2]),
1.861 - NULL);
1.862 -
1.863 - return priv->v4lsrc;
1.864 -}
1.865 -
1.866 -static GstElement *
1.867 -_create_source(GMencoder *self, const gchar * uri)
1.868 -{
1.869 -
1.870 - GstElement *bsrc = NULL;
1.871 - GstElement *src = NULL;
1.872 - GstElement *aqueue = NULL;
1.873 - GstElement *vqueue = NULL;
1.874 - GstElement *decode = NULL;
1.875 - GstPad *src_pad = NULL;
1.876 -
1.877 -
1.878 - bsrc = gst_bin_new(NULL);
1.879 -
1.880 - // src = gst_element_factory_make ("gnomevfssrc", "src");
1.881 - // g_object_set (G_OBJECT (src), "location", uri, NULL);
1.882 - if (strncmp (uri, "v4l://", 6) == 0) {
1.883 - g_debug ("V4L");
1.884 - src = _create_v4l_source (self, uri);
1.885 - }
1.886 - else {
1.887 - src = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
1.888 - }
1.889 -
1.890 - if (src == NULL)
1.891 - goto error;
1.892 -
1.893 - decode = gst_element_factory_make("decodebin2", "decode");
1.894 - if (decode == NULL)
1.895 - goto error;
1.896 -
1.897 - aqueue = gst_element_factory_make("queue", "aqueue");
1.898 - if (aqueue == NULL)
1.899 - goto error;
1.900 -
1.901 - vqueue = gst_element_factory_make("queue", "vqueue");
1.902 - if (vqueue == NULL)
1.903 - goto error;
1.904 -
1.905 - gst_bin_add_many(GST_BIN(bsrc), src, decode, aqueue, vqueue,
1.906 - NULL);
1.907 - gst_element_link (src, decode);
1.908 -
1.909 - g_signal_connect(G_OBJECT(decode),
1.910 - "new-decoded-pad",
1.911 - G_CALLBACK(_decodebin_new_pad_cb), bsrc);
1.912 -
1.913 - g_signal_connect(G_OBJECT(decode),
1.914 - "unknown-type",
1.915 - G_CALLBACK(_decodebin_unknown_type_cb), pipe);
1.916 -
1.917 - src_pad = gst_element_get_pad(aqueue, "src");
1.918 - gst_element_add_pad(bsrc, gst_ghost_pad_new("src_audio", src_pad));
1.919 - gst_object_unref(src_pad);
1.920 -
1.921 - src_pad = gst_element_get_pad(vqueue, "src");
1.922 - gst_element_add_pad(bsrc, gst_ghost_pad_new("src_video", src_pad));
1.923 - gst_object_unref(src_pad);
1.924 -
1.925 - return bsrc;
1.926 -
1.927 - error:
1.928 - g_debug ("Fail to create source element");
1.929 - if (src != NULL) {
1.930 - gst_object_unref(src);
1.931 - }
1.932 -
1.933 - if (decode != NULL) {
1.934 - gst_object_unref(decode);
1.935 - }
1.936 -
1.937 - if (aqueue != NULL) {
1.938 - gst_object_unref(aqueue);
1.939 - }
1.940 -
1.941 - if (vqueue != NULL) {
1.942 - gst_object_unref(vqueue);
1.943 - }
1.944 -
1.945 - return NULL;
1.946 -}
1.947 -
1.948 -static gboolean
1.949 -_open_output(GMencoder * self, const gchar * uri)
1.950 -{
1.951 - gchar **i;
1.952 - GnomeVFSResult result;
1.953 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.954 -
1.955 - i = g_strsplit(uri, "://", 0);
1.956 - if (strcmp(i[0], "fd") == 0) {
1.957 - result = gnome_vfs_open_fd (&priv->handle, atoi(i[1]));
1.958 - } else {
1.959 - if (g_file_test (i[1], G_FILE_TEST_EXISTS) == FALSE) {
1.960 - result = gnome_vfs_create (&priv->handle, uri, GNOME_VFS_OPEN_WRITE, FALSE,
1.961 - GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_GROUP_READ);
1.962 - } else {
1.963 - result = gnome_vfs_open (&priv->handle, uri,
1.964 - GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_TRUNCATE);
1.965 - }
1.966 - }
1.967 -
1.968 - g_strfreev(i);
1.969 - return (result == GNOME_VFS_OK);
1.970 -}
1.971 -
1.972 -static gboolean
1.973 -_pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data)
1.974 -{
1.975 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
1.976 -
1.977 - switch (GST_MESSAGE_TYPE(msg)) {
1.978 -
1.979 - case GST_MESSAGE_STATE_CHANGED:
1.980 - {
1.981 - GstState oldstate;
1.982 - GstState newstate;
1.983 - GstState pendingstate;
1.984 -
1.985 -
1.986 - gst_message_parse_state_changed(msg, &oldstate,
1.987 - &newstate, &pendingstate);
1.988 -
1.989 - if (pendingstate != GST_STATE_VOID_PENDING)
1.990 - break;
1.991 -
1.992 - if ((oldstate == GST_STATE_READY)
1.993 - && (newstate == GST_STATE_PAUSED)) {
1.994 - if (priv->ready)
1.995 - g_signal_emit(user_data, g_mencoder_signals[PAUSED],
1.996 - 0);
1.997 - } else if ((oldstate == GST_STATE_PAUSED)
1.998 - && (newstate == GST_STATE_PLAYING)) {
1.999 - g_signal_emit(user_data, g_mencoder_signals[PLAYING], 0);
1.1000 - } else if ((oldstate == GST_STATE_READY) &&
1.1001 - (newstate == GST_STATE_NULL)) {
1.1002 - g_signal_emit(user_data, g_mencoder_signals[STOPED], 0);
1.1003 - }
1.1004 - break;
1.1005 - }
1.1006 -
1.1007 - case GST_MESSAGE_ERROR:
1.1008 - {
1.1009 - GError *error;
1.1010 - gchar *debug;
1.1011 - gchar *err_str;
1.1012 -
1.1013 - if (priv->tick_id != 0) {
1.1014 - g_source_remove(priv->tick_id);
1.1015 - priv->tick_id = 0;
1.1016 - }
1.1017 -
1.1018 - gst_message_parse_error(msg, &error, &debug);
1.1019 - err_str = g_strdup_printf("Error [%d] %s (%s)", error->code,
1.1020 - error->message, debug);
1.1021 - priv->ready = FALSE;
1.1022 - g_signal_emit(user_data, g_mencoder_signals[ERROR], 0,
1.1023 - err_str);
1.1024 - g_free(err_str);
1.1025 - g_clear_error(&error);
1.1026 - g_free(debug);
1.1027 - break;
1.1028 - }
1.1029 -
1.1030 - case GST_MESSAGE_EOS:
1.1031 - priv->ready = FALSE;
1.1032 -#ifdef USE_MANUAL_SINK
1.1033 - _flush_queue (G_MENCODER (user_data));
1.1034 -#endif
1.1035 - g_signal_emit(user_data, g_mencoder_signals[EOS], 0);
1.1036 - break;
1.1037 -
1.1038 - case GST_MESSAGE_DURATION:
1.1039 - {
1.1040 - GstFormat format;
1.1041 - gint64 duration;
1.1042 - gst_message_parse_duration(msg, &format, &duration);
1.1043 - if (format == GST_FORMAT_BYTES)
1.1044 - priv->duration = duration;
1.1045 - break;
1.1046 - }
1.1047 - default:
1.1048 - {
1.1049 - break;
1.1050 - }
1.1051 - }
1.1052 - return TRUE;
1.1053 -}
1.1054 -
1.1055 -
1.1056 -
1.1057 -static void
1.1058 -_decodebin_new_pad_cb(GstElement * object,
1.1059 - GstPad * pad, gboolean flag, gpointer user_data)
1.1060 -{
1.1061 - GstCaps *caps;
1.1062 - gchar *str_caps = NULL;
1.1063 - GstElement *sink_element;
1.1064 - GstPad *sink_pad;
1.1065 -
1.1066 - caps = gst_pad_get_caps(pad);
1.1067 - str_caps = gst_caps_to_string(caps);
1.1068 - if (strstr(str_caps, "audio") != NULL) {
1.1069 - sink_element = gst_bin_get_by_name(GST_BIN(user_data), "aqueue");
1.1070 - } else if (strstr(str_caps, "video") != NULL) {
1.1071 - sink_element = gst_bin_get_by_name(GST_BIN(user_data), "vqueue");
1.1072 - } else {
1.1073 - g_warning("invalid caps %s", str_caps);
1.1074 - }
1.1075 -
1.1076 - sink_pad = gst_element_get_pad(sink_element, "sink");
1.1077 - gst_pad_link(pad, sink_pad);
1.1078 -
1.1079 - gst_object_unref(sink_element);
1.1080 - gst_object_unref(sink_pad);
1.1081 - g_free(str_caps);
1.1082 - gst_caps_unref(caps);
1.1083 -}
1.1084 -
1.1085 -static void
1.1086 -_decodebin_unknown_type_cb(GstElement * object,
1.1087 - GstPad * pad, GstCaps * caps,
1.1088 - gpointer user_data)
1.1089 -{
1.1090 - g_warning("Unknown Type");
1.1091 - // priv->ready = FALSE;
1.1092 -}
1.1093 -
1.1094 -static gboolean
1.1095 -_tick_cb(gpointer user_data)
1.1096 -{
1.1097 - GstFormat format = GST_FORMAT_BYTES;
1.1098 - gint64 cur = 0;
1.1099 -
1.1100 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
1.1101 -
1.1102 - if (priv->duration == 0) {
1.1103 - gint64 d = 0;
1.1104 - if (gst_element_query_duration(priv->src, &format, &d))
1.1105 - priv->duration = d;
1.1106 - }
1.1107 -
1.1108 - if (priv->duration != 0) {
1.1109 - gst_element_query_position(priv->src, &format, &cur);
1.1110 - g_print("PROGRESS:%lli\n", (99 * cur) / priv->duration);
1.1111 - }
1.1112 -
1.1113 - return TRUE;
1.1114 -}
1.1115 -
1.1116 -static gboolean
1.1117 -_process_timeout_cb (gpointer user_data)
1.1118 -{
1.1119 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
1.1120 -
1.1121 - g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "timeout");
1.1122 - priv->timeout_id = 0;
1.1123 - return FALSE;
1.1124 -}
1.1125 -
1.1126 -
1.1127 -#ifdef USE_MANUAL_SINK
1.1128 -static gboolean
1.1129 -_send_buffer (GnomeVFSHandle *handle, gpointer buff, gint size)
1.1130 -{
1.1131 - gchar *msg;
1.1132 - GByteArray *b_send;
1.1133 - GnomeVFSResult result;
1.1134 - GnomeVFSFileSize bytes_written;
1.1135 -
1.1136 - b_send = g_byte_array_new ();
1.1137 - msg = g_strdup_printf ("%x\r\n", size);
1.1138 - b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar));
1.1139 - g_free (msg);
1.1140 -
1.1141 - b_send = g_byte_array_append (b_send, buff, size);
1.1142 -
1.1143 - msg = g_strdup ("\r\n");
1.1144 - b_send = g_byte_array_append (b_send, (const guint8*) msg, strlen (msg) * sizeof (gchar));
1.1145 - g_free (msg);
1.1146 -
1.1147 - result = gnome_vfs_write (handle, b_send->data, b_send->len, &bytes_written);
1.1148 - g_byte_array_free (b_send, TRUE);
1.1149 -
1.1150 - return (result == GNOME_VFS_OK);
1.1151 -}
1.1152 -
1.1153 -static void
1.1154 -_flush_queue (GMencoder *self)
1.1155 -{
1.1156 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
1.1157 -
1.1158 - if (priv->send_chunked) {
1.1159 - GnomeVFSFileSize bytes_written;
1.1160 - gchar *end_msg;
1.1161 - end_msg = g_strdup ("0\r\n\r\n");
1.1162 - gnome_vfs_write (priv->handle,
1.1163 - (const guint8*) end_msg,
1.1164 - strlen(end_msg) * sizeof(gchar),
1.1165 - &bytes_written);
1.1166 - g_free (end_msg);
1.1167 - }
1.1168 -}
1.1169 -
1.1170 -static void
1.1171 -_buffer_arrive_cb (GstElement* object,
1.1172 - GstBuffer* buff,
1.1173 - GstPad* pad,
1.1174 - gpointer user_data)
1.1175 -{
1.1176 - GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
1.1177 -
1.1178 - if (priv->timeout_id != 0) {
1.1179 - g_source_remove (priv->timeout_id);
1.1180 - priv->timeout_id = 0;
1.1181 - }
1.1182 -
1.1183 - if (priv->send_chunked) {
1.1184 - if (_send_buffer (priv->handle, GST_BUFFER_DATA (buff), GST_BUFFER_SIZE (buff)) == FALSE)
1.1185 - goto error;
1.1186 - } else {
1.1187 - GnomeVFSResult result;
1.1188 - GnomeVFSFileSize bytes_written;
1.1189 -
1.1190 - result = gnome_vfs_write (priv->handle,
1.1191 - GST_BUFFER_DATA (buff),
1.1192 - GST_BUFFER_SIZE (buff),
1.1193 - &bytes_written);
1.1194 -
1.1195 - if (result != GNOME_VFS_OK)
1.1196 - goto error;
1.1197 - }
1.1198 -
1.1199 - return;
1.1200 -
1.1201 -error:
1.1202 - if (priv->tick_id != 0) {
1.1203 - g_source_remove(priv->tick_id);
1.1204 - priv->tick_id = 0;
1.1205 - }
1.1206 - g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, "Fail to write on socket");
1.1207 - gst_element_set_state (priv->pipe, GST_STATE_PAUSED);
1.1208 -}
1.1209 -
1.1210 -#endif