12 #include "gmencoder.h"
14 #define G_MENCODER_GET_PRIVATE(obj) \
15 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_TYPE_MENCODER, GMencoderPrivate))
17 //#define SUPPORT_MULT_INPUT 0
19 typedef struct _GMencoderPrivate GMencoderPrivate;
20 typedef struct _SetupInfo SetupInfo;
26 gchar **video_encode_prop;
32 gchar **audio_encode_prop;
37 struct _GMencoderPrivate
64 static void g_mencoder_class_init(GMencoderClass * klass);
65 static void g_mencoder_init(GMencoder * object);
66 static void g_mencoder_dispose(GObject * object);
67 static void g_mencoder_finalize(GObject * object);
68 static GstElement *_create_audio_bin(const gchar * encode,
69 gchar ** encode_prop, gint rate);
70 static GstElement *_create_video_bin(const gchar * encode,
73 gint rate, guint width, guint height);
76 _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data);
78 static void _decodebin_new_pad_cb(GstElement * object,
80 gboolean flag, gpointer user_data);
82 static void _decodebin_unknown_type_cb(GstElement * object,
84 GstCaps * caps, gpointer user_data);
86 static void _close_output(GMencoder * self);
87 static void _open_output(GMencoder * self, const gchar * uri);
89 static GstElement *_create_source(const gchar * uri);
90 static GstElement *_create_pipeline(GMencoder * self,
91 const gchar * video_encode,
92 const gchar * mux_name,
93 gchar ** video_encode_prop,
98 const gchar * audio_encode,
99 gchar ** audio_encode_prop,
102 static gboolean _tick_cb(gpointer data);
104 static guint g_mencoder_signals[LAST_SIGNAL] = { 0 };
106 G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT)
107 static void g_mencoder_class_init(GMencoderClass * klass)
109 GObjectClass *object_class;
110 object_class = (GObjectClass *) klass;
111 g_type_class_add_private(klass, sizeof(GMencoderPrivate));
113 object_class->dispose = g_mencoder_dispose;
114 object_class->finalize = g_mencoder_finalize;
116 g_mencoder_signals[PAUSED] =
117 g_signal_new("paused",
118 G_OBJECT_CLASS_TYPE(object_class),
121 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
123 g_mencoder_signals[PLAYING] =
124 g_signal_new("playing",
125 G_OBJECT_CLASS_TYPE(object_class),
128 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
130 g_mencoder_signals[STOPED] =
131 g_signal_new("stoped",
132 G_OBJECT_CLASS_TYPE(object_class),
135 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
137 g_mencoder_signals[EOS] =
139 G_OBJECT_CLASS_TYPE(object_class),
142 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
144 g_mencoder_signals[ERROR] =
145 g_signal_new("error",
146 G_OBJECT_CLASS_TYPE(object_class),
149 g_cclosure_marshal_VOID__STRING,
150 G_TYPE_NONE, 1, G_TYPE_STRING);
154 g_mencoder_init(GMencoder * self)
156 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
157 priv->info = g_new0(SetupInfo, 1);
161 g_mencoder_dispose(GObject * object)
166 g_mencoder_finalize(GObject * object)
169 g_mencoder_close_stream(G_MENCODER(object));
175 return g_object_new(G_TYPE_MENCODER, NULL);
180 _obj_set_prop(GObject * obj, const gchar * prop_name, const gchar * prop_val)
184 GParamSpec *s = NULL;
185 GObjectClass *k = G_OBJECT_GET_CLASS(obj);
188 g_value_init(&v, G_TYPE_STRING);
189 g_value_set_string(&v, prop_val);
191 s = g_object_class_find_property(k, prop_name);
194 g_print("Invalid property name: %s\n", prop_name);
198 g_value_init(&p, s->value_type);
199 switch (s->value_type)
202 g_value_set_int(&p, atoi(prop_val));
205 g_value_set_string(&p, prop_val);
211 g_object_set_property(obj, prop_name, &p);
217 _create_element_with_prop(const gchar * factory_name,
218 const gchar * element_name, gchar ** prop)
223 ret = gst_element_factory_make(factory_name, element_name);
229 for (i = 0; i < g_strv_length(prop); i++)
233 char **v = g_strsplit(prop[i], "=", 2);
234 if (g_strv_length(v) == 2)
236 _obj_set_prop(G_OBJECT(ret), v[0], v[1]);
248 _create_audio_bin(const gchar * encode, gchar ** encode_prop, gint rate)
250 GstElement *abin = NULL;
251 GstElement *aqueue = NULL;
252 GstElement *aconvert = NULL;
253 GstElement *aencode = NULL;
254 GstElement *aqueue_src = NULL;
257 //audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay ! udpsink name=upd_audio host=224.0.0.1 port=5002
258 abin = gst_bin_new("abin");
259 aqueue = gst_element_factory_make("queue", "aqueue");
260 aconvert = gst_element_factory_make("audioconvert", "aconvert");
262 _create_element_with_prop((encode ? encode : "lame"), "aencode",
264 aqueue_src = gst_element_factory_make("queue", "aqueue_src");
266 if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL)
267 || (aencode == NULL) || (aqueue_src == NULL))
269 g_warning("Audio elements not found");
273 g_object_set(G_OBJECT(aencode), "bitrate", 32, NULL);
276 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
280 gst_bin_add_many(GST_BIN(abin), aqueue, aconvert, aencode, aqueue_src,
282 if (gst_element_link_many(aqueue, aconvert, aencode, aqueue_src, NULL) ==
285 g_warning("Not Link audio elements");
288 //TODO: apply audio rate
290 // ghost pad the audio bin
291 apad = gst_element_get_pad(aqueue, "sink");
292 gst_element_add_pad(abin, gst_ghost_pad_new("sink", apad));
293 gst_object_unref(apad);
295 apad = gst_element_get_pad(aqueue_src, "src");
296 gst_element_add_pad(abin, gst_ghost_pad_new("src", apad));
297 gst_object_unref(apad);
302 gst_object_unref(abin);
305 gst_object_unref(aqueue);
307 if (aconvert != NULL)
308 gst_object_unref(aconvert);
311 gst_object_unref(aencode);
313 if (aqueue_src != NULL)
314 gst_object_unref(aqueue_src);
317 gst_object_unref(apad);
325 //queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace ! rate ! encode ! queue
327 _create_video_bin(const gchar * encode,
328 gchar ** encode_prop,
329 gdouble fps, gint rate, guint width, guint height)
331 GstElement *vbin = NULL;
332 GstElement *vqueue = NULL;
333 GstElement *vqueue_src = NULL;
334 GstElement *vcolorspace = NULL;
335 GstElement *vencode = NULL;
336 GstElement *vrate = NULL;
339 vbin = gst_bin_new("vbin");
340 vqueue = gst_element_factory_make("queue", "vqueue");
341 vcolorspace = gst_element_factory_make("ffmpegcolorspace", "colorspace");
343 vencode = _create_element_with_prop((encode !=
344 NULL ? encode : "ffenc_mpeg1video"),
345 "vencode", encode_prop);
346 vqueue_src = gst_element_factory_make("queue", "queue_src");
348 if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL)
349 || (vencode == NULL) || (vqueue_src == NULL))
351 g_warning("Video elements not found");
355 gst_bin_add_many(GST_BIN(vbin), vqueue, vcolorspace, vencode, vqueue_src,
358 if ((width > 0) && (height > 0))
362 GstElement *vscale = gst_element_factory_make("videoscale", "vscale");
364 gst_bin_add(GST_BIN(vbin), vscale);
366 vcaps = gst_caps_new_simple("video/x-raw-yuv",
367 "width", G_TYPE_INT, width,
368 "height", G_TYPE_INT, height, NULL);
370 gst_element_link(vqueue, vscale);
372 if (gst_element_link_filtered(vscale, vcolorspace, vcaps) == FALSE)
374 g_warning("Fail to resize video");
375 gst_object_unref(vcaps);
376 gst_object_unref(vscale);
379 gst_caps_unref(vcaps);
383 gst_element_link(vqueue, vcolorspace);
388 //Changing the video fps
390 vrate = gst_element_factory_make("videorate", "vrate");
392 gst_bin_add(GST_BIN(vbin), vrate);
394 if (gst_element_link(vcolorspace, vrate) == FALSE)
396 g_warning("Fail to link video elements");
400 vcaps = gst_caps_new_simple("video/x-raw-yuv",
401 "framerate", GST_TYPE_FRACTION,
402 (int) (fps * 1000), 1000, NULL);
404 if (gst_element_link_filtered(vrate, vencode, vcaps) == FALSE)
406 g_warning("Fail to link vrate with vencode.");
409 gst_caps_unref(vcaps);
413 if (gst_element_link(vcolorspace, vencode) == FALSE)
415 g_warning("Fail to link colorspace and video encode element.");
420 gst_element_link(vencode, vqueue_src);
422 // ghost pad the video bin
423 vpad = gst_element_get_pad(vqueue, "sink");
424 gst_element_add_pad(vbin, gst_ghost_pad_new("sink", vpad));
425 gst_object_unref(vpad);
427 vpad = gst_element_get_pad(vqueue_src, "src");
428 gst_element_add_pad(vbin, gst_ghost_pad_new("src", vpad));
429 gst_object_unref(vpad);
435 gst_object_unref(vpad);
438 gst_object_unref(vbin);
441 gst_object_unref(vqueue);
444 gst_object_unref(vencode);
446 if (vqueue_src != NULL)
447 gst_object_unref(vqueue_src);
449 if (vcolorspace != NULL)
450 gst_object_unref(vcolorspace);
458 g_mencoder_setup_stream(GMencoder * self,
459 const gchar * mux_name,
460 const gchar * video_encode,
461 gchar ** video_encode_prop,
466 const gchar * audio_encode,
467 gchar ** audio_encode_prop,
468 guint audio_rate, const gchar * out_uri)
470 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
471 if (priv->ready == TRUE)
473 g_warning("Stream already configured. You need close stream first.");
478 _open_output(self, out_uri);
481 priv->pipe = _create_pipeline(self,
489 audio_encode, audio_encode_prop, audio_rate);
495 g_mencoder_append_uri(GMencoder * self, const gchar * uri)
500 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
501 gboolean ret = FALSE;
502 GstElement *ap = NULL;
503 GstElement *vp = NULL;
506 g_return_val_if_fail(priv->pipe != NULL, FALSE);
507 g_return_val_if_fail(priv->ready == FALSE, FALSE);
509 #ifndef SUPPORT_MULT_INPUT
510 g_return_val_if_fail(priv->sources < 1, FALSE);
513 src = _create_source(uri);
517 priv->src = gst_bin_get_by_name(GST_BIN(src), "src");
519 gst_bin_add(GST_BIN(priv->pipe), src);
521 #ifdef SUPPORT_MULT_INPUT
522 ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "ap");
523 vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vp");
525 ap = gst_bin_get_by_name(GST_BIN(priv->pipe), "abin");
526 vp = gst_bin_get_by_name(GST_BIN(priv->pipe), "vbin");
529 if ((vp == NULL) || (ap == NULL))
531 g_warning("Fail to get output bin");
535 pad_src = gst_element_get_pad(src, "src_audio");
536 pad_sink = gst_element_get_compatible_pad(ap,
538 gst_pad_get_caps(pad_src));
540 if ((pad_sink == NULL) || (pad_src == NULL))
543 GstPadLinkReturn lret = gst_pad_link(pad_src, pad_sink);
544 if (lret != GST_PAD_LINK_OK)
547 gst_object_unref(pad_src);
548 gst_object_unref(pad_sink);
550 pad_src = gst_element_get_pad(src, "src_video");
551 pad_sink = gst_element_get_compatible_pad(vp,
553 gst_pad_get_caps(pad_src));
555 if ((pad_src == NULL) || (pad_sink == NULL))
558 if (gst_pad_link(pad_src, pad_sink) != GST_PAD_LINK_OK)
560 g_warning("invalid source. video");
568 if ((src != NULL) && (ret == FALSE))
570 gst_bin_remove(GST_BIN(priv->pipe), src);
571 gst_object_unref(src);
575 gst_object_unref(ap);
578 gst_object_unref(vp);
581 gst_object_unref(pad_src);
583 if (pad_sink != NULL)
584 gst_object_unref(pad_sink);
592 g_mencoder_remove_uri(GMencoder * self, const gchar * uri)
594 // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
599 g_mencoder_play_stream(GMencoder * self)
601 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
602 g_return_if_fail(priv->ready == FALSE);
604 gst_element_set_state(priv->pipe, GST_STATE_PLAYING);
605 priv->tick_id = g_timeout_add(500, _tick_cb, self);
609 g_mencoder_pause_stream(GMencoder * self)
611 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
612 g_return_if_fail(priv->ready == TRUE);
613 gst_element_set_state(priv->pipe, GST_STATE_PAUSED);
617 g_mencoder_close_stream(GMencoder * self)
620 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
621 if (priv->tick_id != 0)
623 g_source_remove(priv->tick_id);
627 if (priv->pipe != NULL)
629 //TODO: fixe pipeline dispose
630 //gst_element_set_state (priv->pipe, GST_STATE_NULL);
631 //g_debug ("SETING STATE TO NULL: OK");
632 //gst_element_set_state (priv->pipe, GST_STATE_NULL);
633 //gst_object_unref (priv->pipe);
634 gst_object_unref(priv->src);
645 _create_pipeline(GMencoder * self,
646 const gchar * video_encode,
647 const gchar * mux_name,
648 gchar ** video_encode_prop,
653 const gchar * audio_encode,
654 gchar ** audio_encode_prop, guint audio_rate)
657 GstElement *pipe = NULL;
658 GstElement *sink = NULL;
659 GstElement *mux = NULL;
660 GstElement *abin = NULL;
661 GstElement *vbin = NULL;
662 GstElement *queue = NULL;
663 GstPad *aux_pad = NULL;
664 GstPad *mux_pad = NULL;
665 #ifdef SUPPORT_MULT_INPUT
666 GstElement *ap = NULL;
667 GstElement *vp = NULL;
669 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
671 pipe = gst_pipeline_new("pipe");
673 #ifdef SUPPORT_MULT_INPUT
674 ap = gst_element_factory_make("concatmux", "ap");
675 vp = gst_element_factory_make("concatmux", "vp");
676 gst_bin_add_many(GST_BIN(pipe), ap, vp, NULL);
679 mux = gst_element_factory_make((mux_name ? mux_name : "ffmux_mpeg"), "mux");
683 queue = gst_element_factory_make("queue", "queueu_sink");
686 sink = gst_element_factory_make("fdsink", "sink");
690 g_object_set(G_OBJECT(sink), "fd", priv->fd, "sync", FALSE, NULL);
692 abin = _create_audio_bin(audio_encode, audio_encode_prop, audio_rate);
697 _create_video_bin(video_encode, video_encode_prop, video_fps, video_rate,
698 video_width, video_height);
703 gst_bin_add_many(GST_BIN(pipe), abin, vbin, mux, queue, sink, NULL);
706 #ifdef SUPPORT_MULT_INPUT
707 if (gst_element_link(ap, abin) == FALSE)
709 g_warning("Fail to link concat and abin");
713 if (gst_element_link(vp, vbin) == FALSE)
715 g_warning("Fail to link concat and vbin");
720 aux_pad = gst_element_get_pad(abin, "src");
722 gst_element_get_compatible_pad(mux, aux_pad, GST_PAD_CAPS(aux_pad));
725 g_warning("Mux element no have audio PAD");
728 GstPadLinkReturn ret = gst_pad_link(aux_pad, mux_pad);
729 if (ret != GST_PAD_LINK_OK)
731 g_warning("Fail link audio and mux: %d", ret);
735 gst_object_unref(aux_pad);
736 gst_object_unref(mux_pad);
738 aux_pad = gst_element_get_pad(vbin, "src");
740 gst_element_get_compatible_pad(mux, aux_pad, GST_PAD_CAPS(aux_pad));
743 g_warning("Mux element no have video PAD");
746 ret = gst_pad_link(aux_pad, mux_pad);
747 if (ret != GST_PAD_LINK_OK)
749 g_warning("Fail link video and mux: %d", ret);
752 gst_object_unref(aux_pad);
753 gst_object_unref(mux_pad);
758 gst_element_link_many(mux, queue, sink, NULL);
760 bus = gst_pipeline_get_bus(GST_PIPELINE(pipe));
761 gst_bus_add_watch(bus, _pipeline_bus_cb, self);
762 gst_object_unref(bus);
766 g_warning("Invalid uri");
770 gst_object_unref(pipe);
776 gst_object_unref(mux);
781 gst_object_unref(mux_pad);
786 gst_object_unref(mux_pad);
791 gst_object_unref(sink);
796 gst_object_unref(abin);
801 gst_object_unref(vbin);
809 _close_output(GMencoder * self)
814 _create_source(const gchar * uri)
817 GstElement *bsrc = NULL;
818 GstElement *src = NULL;
819 GstElement *queue = NULL;
820 GstElement *aqueue = NULL;
821 GstElement *vqueue = NULL;
822 GstElement *decode = NULL;
823 GstPad *src_pad = NULL;
826 bsrc = gst_bin_new(NULL);
828 //src = gst_element_factory_make ("gnomevfssrc", "src");
829 //g_object_set (G_OBJECT (src), "location", uri, NULL);
830 src = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
834 decode = gst_element_factory_make("decodebin", "decode");
838 queue = gst_element_factory_make("queue", "queue_src");
839 aqueue = gst_element_factory_make("queue", "aqueue");
843 vqueue = gst_element_factory_make("queue", "vqueue");
847 gst_bin_add_many(GST_BIN(bsrc), src, queue, decode, aqueue, vqueue, NULL);
848 gst_element_link_many(src, queue, decode, NULL);
850 g_signal_connect(G_OBJECT(decode),
852 G_CALLBACK(_decodebin_new_pad_cb), bsrc);
854 g_signal_connect(G_OBJECT(decode),
856 G_CALLBACK(_decodebin_unknown_type_cb), pipe);
858 src_pad = gst_element_get_pad(aqueue, "src");
859 gst_element_add_pad(bsrc, gst_ghost_pad_new("src_audio", src_pad));
860 gst_object_unref(src_pad);
862 src_pad = gst_element_get_pad(vqueue, "src");
863 gst_element_add_pad(bsrc, gst_ghost_pad_new("src_video", src_pad));
864 gst_object_unref(src_pad);
871 gst_object_unref(src);
876 gst_object_unref(decode);
881 gst_object_unref(aqueue);
886 gst_object_unref(vqueue);
893 _open_output(GMencoder * self, const gchar * uri)
896 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(self);
898 i = g_strsplit(uri, "://", 0);
899 if (strcmp(i[0], "fd") == 0)
901 priv->fd = atoi(i[1]);
903 else if (strcmp(i[0], "file") == 0)
905 priv->fd = open(i[1], O_WRONLY | O_CREAT | O_TRUNC,
906 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
910 g_warning("Output uri not supported");
917 _pipeline_bus_cb(GstBus * bus, GstMessage * msg, gpointer user_data)
919 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
921 switch (GST_MESSAGE_TYPE(msg))
924 case GST_MESSAGE_STATE_CHANGED:
928 GstState pendingstate;
931 gst_message_parse_state_changed(msg, &oldstate,
932 &newstate, &pendingstate);
934 if (pendingstate != GST_STATE_VOID_PENDING)
937 if ((oldstate == GST_STATE_READY) && (newstate == GST_STATE_PAUSED))
940 g_signal_emit(user_data, g_mencoder_signals[PAUSED], 0);
942 else if ((oldstate == GST_STATE_PAUSED) &&
943 (newstate == GST_STATE_PLAYING))
945 g_signal_emit(user_data, g_mencoder_signals[PLAYING], 0);
947 else if ((oldstate == GST_STATE_READY) &&
948 (newstate == GST_STATE_NULL))
950 g_signal_emit(user_data, g_mencoder_signals[STOPED], 0);
955 case GST_MESSAGE_ERROR:
961 if (priv->tick_id != 0)
963 g_source_remove(priv->tick_id);
967 gst_message_parse_error(msg, &error, &debug);
968 err_str = g_strdup_printf("Error [%d] %s (%s)", error->code,
969 error->message, debug);
971 g_signal_emit(user_data, g_mencoder_signals[ERROR], 0, err_str);
973 g_clear_error(&error);
978 case GST_MESSAGE_EOS:
980 g_signal_emit(user_data, g_mencoder_signals[EOS], 0);
983 case GST_MESSAGE_DURATION:
987 gst_message_parse_duration(msg, &format, &duration);
988 if (format == GST_FORMAT_BYTES)
989 priv->duration = duration;
1003 _decodebin_new_pad_cb(GstElement * object,
1004 GstPad * pad, gboolean flag, gpointer user_data)
1007 gchar *str_caps = NULL;
1008 GstElement *sink_element;
1011 caps = gst_pad_get_caps(pad);
1012 str_caps = gst_caps_to_string(caps);
1013 if (strstr(str_caps, "audio") != NULL)
1015 sink_element = gst_bin_get_by_name(GST_BIN(user_data), "aqueue");
1017 else if (strstr(str_caps, "video") != NULL)
1019 sink_element = gst_bin_get_by_name(GST_BIN(user_data), "vqueue");
1023 g_warning("invalid caps %s", str_caps);
1026 sink_pad = gst_element_get_pad(sink_element, "sink");
1027 gst_pad_link(pad, sink_pad);
1029 gst_object_unref(sink_element);
1030 gst_object_unref(sink_pad);
1032 gst_caps_unref(caps);
1036 _decodebin_unknown_type_cb(GstElement * object,
1037 GstPad * pad, GstCaps * caps, gpointer user_data)
1039 g_warning("Unknown Type");
1040 //priv->ready = FALSE;
1044 _tick_cb(gpointer user_data)
1046 GstFormat format = GST_FORMAT_BYTES;
1049 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE(user_data);
1051 if (priv->duration == 0)
1054 if (gst_element_query_duration(priv->src, &format, &d))
1058 if (priv->duration != 0)
1060 gst_element_query_position(priv->src, &format, &cur);
1061 g_print("PROGRESS:%lli\n", (99 * cur) / priv->duration);