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
63 static void g_mencoder_class_init (GMencoderClass *klass);
64 static void g_mencoder_init (GMencoder *object);
65 static void g_mencoder_dispose (GObject *object);
66 static void g_mencoder_finalize (GObject *object);
68 _create_audio_bin (const gchar* encode,
72 _create_video_bin (const gchar* encode,
80 _pipeline_bus_cb (GstBus *bus,
83 static void _decodebin_new_pad_cb (GstElement* object,
87 static void _decodebin_unknown_type_cb (GstElement* object,
91 static void _close_output (GMencoder *self);
92 static void _open_output (GMencoder *self,
94 static GstElement* _create_source (const gchar* uri);
95 static GstElement*_create_pipeline (GMencoder *self,
96 const gchar* video_encode,
97 const gchar* mux_name,
98 gchar** video_encode_prop,
103 const gchar* audio_encode,
104 gchar** audio_encode_prop,
106 static gboolean _tick_cb (gpointer data);
113 static guint g_mencoder_signals[LAST_SIGNAL] = { 0 };
115 G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT)
118 g_mencoder_class_init (GMencoderClass *klass)
120 GObjectClass *object_class;
122 object_class = (GObjectClass *) klass;
124 g_type_class_add_private (klass, sizeof (GMencoderPrivate));
126 object_class->dispose = g_mencoder_dispose;
127 object_class->finalize = g_mencoder_finalize;
129 g_mencoder_signals[PAUSED] =
130 g_signal_new ("paused",
131 G_OBJECT_CLASS_TYPE (object_class),
134 g_cclosure_marshal_VOID__VOID,
137 g_mencoder_signals[PLAYING] =
138 g_signal_new ("playing",
139 G_OBJECT_CLASS_TYPE (object_class),
142 g_cclosure_marshal_VOID__VOID,
145 g_mencoder_signals[STOPED] =
146 g_signal_new ("stoped",
147 G_OBJECT_CLASS_TYPE (object_class),
150 g_cclosure_marshal_VOID__VOID,
153 g_mencoder_signals[EOS] =
155 G_OBJECT_CLASS_TYPE (object_class),
158 g_cclosure_marshal_VOID__VOID,
162 g_mencoder_signals[ERROR] =
163 g_signal_new ("error",
164 G_OBJECT_CLASS_TYPE (object_class),
167 g_cclosure_marshal_VOID__STRING,
168 G_TYPE_NONE, 1, G_TYPE_STRING);
172 g_mencoder_init (GMencoder *self)
174 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
175 priv->info = g_new0 (SetupInfo, 1);
179 g_mencoder_dispose (GObject *object)
184 g_mencoder_finalize (GObject *object)
187 g_mencoder_close_stream (G_MENCODER (object));
191 g_mencoder_new (void)
193 return g_object_new (G_TYPE_MENCODER, NULL);
198 _obj_set_prop (GObject *obj,
199 const gchar *prop_name,
200 const gchar *prop_val)
204 GParamSpec *s = NULL;
205 GObjectClass *k = G_OBJECT_GET_CLASS (obj);
208 g_value_init (&v, G_TYPE_STRING);
209 g_value_set_string (&v, prop_val);
211 s = g_object_class_find_property (k, prop_name);
213 g_print ("Invalid property name: %s\n", prop_name);
217 g_value_init (&p, s->value_type);
218 switch (s->value_type)
221 g_value_set_int (&p, atoi (prop_val));
224 g_value_set_string (&p, prop_val);
230 g_object_set_property (obj, prop_name, &p);
236 _create_element_with_prop (const gchar* factory_name,
237 const gchar* element_name,
243 ret = gst_element_factory_make (factory_name, element_name);
248 for (i=0; i < g_strv_length (prop); i++) {
249 if (prop[i] != NULL) {
250 char** v = g_strsplit(prop[i], "=", 2);
251 if (g_strv_length (v) == 2) {
252 _obj_set_prop (G_OBJECT (ret), v[0], v[1]);
264 _create_audio_bin (const gchar* encode,
268 GstElement *abin = NULL;
269 GstElement *aqueue = NULL;
270 GstElement *aconvert = NULL;
271 GstElement *aencode = NULL;
272 GstElement *aqueue_src = NULL;
275 //audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay ! udpsink name=upd_audio host=224.0.0.1 port=5002
276 abin = gst_bin_new ("abin");
277 aqueue = gst_element_factory_make ("queue", "aqueue");
278 aconvert= gst_element_factory_make ("audioconvert", "aconvert");
279 aencode = _create_element_with_prop ((encode ? encode : "lame"), "aencode", encode_prop);
280 aqueue_src= gst_element_factory_make ("queue", "aqueue_src");
282 if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL)
283 || (aencode == NULL) || (aqueue_src == NULL)) {
284 g_warning ("Audio elements not found");
288 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
291 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
295 gst_bin_add_many (GST_BIN (abin), aqueue, aconvert, aencode, aqueue_src, NULL);
296 if (gst_element_link_many (aqueue, aconvert, aencode, aqueue_src, NULL) == FALSE) {
297 g_warning ("Not Link audio elements");
300 //TODO: apply audio rate
302 // ghost pad the audio bin
303 apad = gst_element_get_pad (aqueue, "sink");
304 gst_element_add_pad (abin, gst_ghost_pad_new("sink", apad));
305 gst_object_unref (apad);
307 apad = gst_element_get_pad (aqueue_src, "src");
308 gst_element_add_pad (abin, gst_ghost_pad_new("src", apad));
309 gst_object_unref (apad);
314 gst_object_unref (abin);
317 gst_object_unref (aqueue);
319 if (aconvert != NULL)
320 gst_object_unref (aconvert);
323 gst_object_unref (aencode);
325 if (aqueue_src != NULL)
326 gst_object_unref (aqueue_src);
329 gst_object_unref (apad);
337 //queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace ! rate ! encode ! queue
339 _create_video_bin (const gchar* encode,
346 GstElement *vbin = NULL;
347 GstElement *vqueue = NULL;
348 GstElement* vqueue_src = NULL;
349 GstElement *vcolorspace = NULL;
350 GstElement *vencode = NULL;
351 GstElement *vrate = NULL;
354 vbin = gst_bin_new ("vbin");
355 vqueue = gst_element_factory_make ("queue", "vqueue");
356 vcolorspace = gst_element_factory_make ("ffmpegcolorspace", "colorspace");
358 vencode = _create_element_with_prop (
359 (encode != NULL ? encode : "ffenc_mpeg1video"),
360 "vencode", encode_prop);
361 vqueue_src = gst_element_factory_make ("queue", "queue_src");
363 if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL)
364 || (vencode == NULL) || (vqueue_src == NULL)) {
365 g_warning ("Video elements not found");
369 gst_bin_add_many (GST_BIN (vbin), vqueue, vcolorspace, vencode, vqueue_src, NULL);
372 if ((width > 0) && (height > 0)) {
375 GstElement *vscale = gst_element_factory_make ("videoscale", "vscale");
377 gst_bin_add (GST_BIN (vbin), vscale);
379 vcaps = gst_caps_new_simple ("video/x-raw-yuv",
380 "width", G_TYPE_INT, width,
381 "height", G_TYPE_INT, height,
384 gst_element_link (vqueue, vscale);
386 if (gst_element_link_filtered (vscale, vcolorspace, vcaps) == FALSE) {
387 g_warning ("Fail to resize video");
388 gst_object_unref (vcaps);
389 gst_object_unref (vscale);
392 gst_caps_unref (vcaps);
394 gst_element_link (vqueue, vcolorspace);
399 //Changing the video fps
401 vrate = gst_element_factory_make ("videorate", "vrate");
403 gst_bin_add (GST_BIN (vbin), vrate);
405 if (gst_element_link (vcolorspace, vrate) == FALSE) {
406 g_warning ("Fail to link video elements");
410 vcaps = gst_caps_new_simple ("video/x-raw-yuv",
411 "framerate", GST_TYPE_FRACTION, (int) (fps * 1000), 1000, NULL);
413 if (gst_element_link_filtered (vrate, vencode, vcaps) == FALSE) {
414 g_warning ("Fail to link vrate with vencode.");
417 gst_caps_unref (vcaps);
419 if (gst_element_link (vcolorspace, vencode) == FALSE) {
420 g_warning ("Fail to link colorspace and video encode element.");
425 gst_element_link (vencode, vqueue_src);
427 // ghost pad the video bin
428 vpad = gst_element_get_pad (vqueue, "sink");
429 gst_element_add_pad (vbin, gst_ghost_pad_new ("sink", vpad));
430 gst_object_unref (vpad);
432 vpad = gst_element_get_pad (vqueue_src, "src");
433 gst_element_add_pad (vbin, gst_ghost_pad_new ("src", vpad));
434 gst_object_unref (vpad);
440 gst_object_unref (vpad);
443 gst_object_unref (vbin);
446 gst_object_unref (vqueue);
449 gst_object_unref (vencode);
451 if (vqueue_src != NULL)
452 gst_object_unref (vqueue_src);
454 if (vcolorspace != NULL)
455 gst_object_unref (vcolorspace);
463 g_mencoder_setup_stream (GMencoder *self,
464 const gchar* mux_name,
465 const gchar* video_encode,
466 gchar** video_encode_prop,
471 const gchar* audio_encode,
472 gchar** audio_encode_prop,
474 const gchar* out_uri)
476 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
477 if (priv->ready == TRUE) {
478 g_warning ("Stream already configured. You need close stream first.");
482 _close_output (self);
483 _open_output (self, out_uri);
486 priv->pipe = _create_pipeline (self,
502 g_mencoder_append_uri (GMencoder *self,
508 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
509 gboolean ret = FALSE;
510 GstElement *ap = NULL;
511 GstElement *vp = NULL;
514 g_return_val_if_fail (priv->pipe != NULL, FALSE);
515 g_return_val_if_fail (priv->ready == FALSE, FALSE);
517 #ifndef SUPPORT_MULT_INPUT
518 g_return_val_if_fail (priv->sources < 1, FALSE);
521 src = _create_source (uri);
525 priv->src = gst_bin_get_by_name (GST_BIN (src), "src");
527 gst_bin_add (GST_BIN (priv->pipe), src);
529 #ifdef SUPPORT_MULT_INPUT
530 ap = gst_bin_get_by_name (GST_BIN (priv->pipe), "ap");
531 vp = gst_bin_get_by_name (GST_BIN (priv->pipe), "vp");
533 ap = gst_bin_get_by_name (GST_BIN (priv->pipe), "abin");
534 vp = gst_bin_get_by_name (GST_BIN (priv->pipe), "vbin");
537 if ((vp == NULL) || (ap == NULL)) {
538 g_warning ("Fail to get output bin");
542 pad_src = gst_element_get_pad (src, "src_audio");
543 pad_sink = gst_element_get_compatible_pad (ap,
545 gst_pad_get_caps (pad_src));
547 if ((pad_sink == NULL) || (pad_src == NULL))
550 GstPadLinkReturn lret = gst_pad_link (pad_src, pad_sink);
551 if (lret != GST_PAD_LINK_OK)
554 gst_object_unref (pad_src);
555 gst_object_unref (pad_sink);
557 pad_src = gst_element_get_pad (src, "src_video");
558 pad_sink = gst_element_get_compatible_pad (vp,
560 gst_pad_get_caps (pad_src));
562 if ((pad_src == NULL) || (pad_sink == NULL))
565 if (gst_pad_link (pad_src, pad_sink) != GST_PAD_LINK_OK) {
566 g_warning ("invalid source. video");
574 if ((src != NULL) && (ret == FALSE)) {
575 gst_bin_remove (GST_BIN (priv->pipe), src);
576 gst_object_unref (src);
580 gst_object_unref (ap);
583 gst_object_unref (vp);
586 gst_object_unref (pad_src);
588 if (pad_sink != NULL)
589 gst_object_unref (pad_sink);
597 g_mencoder_remove_uri (GMencoder *self,
600 // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
605 g_mencoder_play_stream (GMencoder *self)
607 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
609 g_return_if_fail (priv->ready == FALSE);
611 gst_element_set_state (priv->pipe, GST_STATE_PLAYING);
613 priv->tick_id = g_timeout_add (500, _tick_cb, self);
617 g_mencoder_pause_stream (GMencoder *self)
619 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
621 g_return_if_fail (priv->ready == TRUE);
622 gst_element_set_state (priv->pipe, GST_STATE_PAUSED);
626 g_mencoder_close_stream (GMencoder *self)
629 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
631 if (priv->tick_id != 0) {
632 g_source_remove (priv->tick_id);
636 if (priv->pipe != NULL) {
637 //TODO: fixe pipeline dispose
638 g_debug ("SETING STATE TO NULL");
639 //gst_element_set_state (priv->pipe, GST_STATE_NULL);
640 g_debug ("SETING STATE TO NULL: OK");
641 //gst_object_unref (priv->pipe);
642 gst_object_unref (priv->src);
653 _create_pipeline (GMencoder *self,
654 const gchar* video_encode,
655 const gchar* mux_name,
656 gchar** video_encode_prop,
661 const gchar* audio_encode,
662 gchar** audio_encode_prop,
666 GstElement *pipe = NULL;
667 GstElement *sink = NULL;
668 GstElement *mux = NULL;
669 GstElement *abin = NULL;
670 GstElement *vbin = NULL;
671 GstElement *queue= NULL;
672 GstPad *aux_pad = NULL;
673 GstPad *mux_pad = NULL;
674 #ifdef SUPPORT_MULT_INPUT
675 GstElement *ap = NULL;
676 GstElement *vp = NULL;
678 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
680 pipe = gst_pipeline_new ("pipe");
682 #ifdef SUPPORT_MULT_INPUT
683 ap = gst_element_factory_make ("concatmux", "ap");
684 vp = gst_element_factory_make ("concatmux", "vp");
685 gst_bin_add_many (GST_BIN (pipe), ap, vp, NULL);
688 mux = gst_element_factory_make ((mux_name ? mux_name : "ffmux_mpeg"), "mux");
692 queue = gst_element_factory_make ("queue", "queueu_sink");
695 sink = gst_element_factory_make ("fdsink", "sink");
699 g_object_set (G_OBJECT(sink),
704 abin = _create_audio_bin (audio_encode, audio_encode_prop, audio_rate);
708 vbin = _create_video_bin (video_encode, video_encode_prop, video_fps, video_rate, video_width, video_height);
713 gst_bin_add_many (GST_BIN (pipe), abin, vbin, mux, queue, sink, NULL);
716 #ifdef SUPPORT_MULT_INPUT
717 if (gst_element_link (ap, abin) == FALSE) {
718 g_warning ("Fail to link concat and abin");
722 if (gst_element_link (vp, vbin) == FALSE) {
723 g_warning ("Fail to link concat and vbin");
728 aux_pad = gst_element_get_pad (abin, "src");
729 mux_pad = gst_element_get_compatible_pad (mux, aux_pad, GST_PAD_CAPS (aux_pad));
730 if (mux_pad == NULL) {
731 g_warning ("Mux element no have audio PAD");
734 GstPadLinkReturn ret = gst_pad_link (aux_pad, mux_pad);
735 if (ret != GST_PAD_LINK_OK) {
736 g_warning ("Fail link audio and mux: %d", ret);
740 gst_object_unref (aux_pad);
741 gst_object_unref (mux_pad);
743 aux_pad = gst_element_get_pad (vbin, "src");
744 mux_pad = gst_element_get_compatible_pad (mux, aux_pad, GST_PAD_CAPS (aux_pad));
745 if (mux_pad == NULL) {
746 g_warning ("Mux element no have video PAD");
749 ret = gst_pad_link (aux_pad, mux_pad);
750 if (ret != GST_PAD_LINK_OK) {
751 g_warning ("Fail link video and mux: %d", ret);
754 gst_object_unref (aux_pad);
755 gst_object_unref (mux_pad);
760 gst_element_link_many (mux, queue, sink, NULL);
762 bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
763 gst_bus_add_watch (bus, _pipeline_bus_cb, self);
764 gst_object_unref (bus);
768 g_warning ("Invalid uri");
771 gst_object_unref (pipe);
776 gst_object_unref (mux);
779 if (mux_pad != NULL) {
780 gst_object_unref (mux_pad);
783 if (aux_pad != NULL) {
784 gst_object_unref (mux_pad);
788 gst_object_unref (sink);
792 gst_object_unref (abin);
796 gst_object_unref (vbin);
804 _close_output (GMencoder *self)
810 _create_source (const gchar* uri)
813 GstElement *bsrc = NULL;
814 GstElement *src = NULL;
815 GstElement *queue = NULL;
816 GstElement *aqueue = NULL;
817 GstElement *vqueue = NULL;
818 GstElement *decode = NULL;
819 GstPad *src_pad = NULL;
822 bsrc = gst_bin_new (NULL);
824 //src = gst_element_factory_make ("gnomevfssrc", "src");
825 //g_object_set (G_OBJECT (src), "location", uri, NULL);
826 src = gst_element_make_from_uri (GST_URI_SRC, uri, "src");
830 decode = gst_element_factory_make ("decodebin", "decode");
834 queue = gst_element_factory_make ("queue", "queue_src");
835 aqueue = gst_element_factory_make ("queue", "aqueue");
839 vqueue = gst_element_factory_make ("queue", "vqueue");
843 gst_bin_add_many (GST_BIN (bsrc), src, queue, decode, aqueue, vqueue, NULL);
844 gst_element_link_many (src, queue, decode, NULL);
846 g_signal_connect (G_OBJECT (decode),
848 G_CALLBACK (_decodebin_new_pad_cb),
851 g_signal_connect (G_OBJECT (decode),
853 G_CALLBACK (_decodebin_unknown_type_cb),
856 src_pad = gst_element_get_pad (aqueue, "src");
857 gst_element_add_pad (bsrc, gst_ghost_pad_new("src_audio", src_pad));
858 gst_object_unref (src_pad);
860 src_pad = gst_element_get_pad (vqueue, "src");
861 gst_element_add_pad (bsrc, gst_ghost_pad_new("src_video", src_pad));
862 gst_object_unref (src_pad);
868 gst_object_unref (src);
871 if (decode != NULL) {
872 gst_object_unref (decode);
875 if (aqueue != NULL) {
876 gst_object_unref (aqueue);
879 if (vqueue != NULL) {
880 gst_object_unref (vqueue);
887 _open_output (GMencoder *self,
891 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
893 i = g_strsplit (uri, "://", 0);
894 if (strcmp (i[0], "fd") == 0) {
895 priv->fd = atoi (i[1]);
896 } else if (strcmp (i[0], "file") == 0) {
897 priv->fd = open (i[1], O_WRONLY | O_CREAT | O_TRUNC);
899 g_warning ("Output uri not supported");
906 _pipeline_bus_cb (GstBus *bus,
910 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
912 switch (GST_MESSAGE_TYPE (msg))
914 case GST_MESSAGE_STATE_CHANGED:
918 GstState pendingstate;
921 gst_message_parse_state_changed (msg, &oldstate,
922 &newstate, &pendingstate);
924 if (pendingstate != GST_STATE_VOID_PENDING)
927 if ((oldstate == GST_STATE_READY) &&
928 (newstate == GST_STATE_PAUSED)) {
930 g_signal_emit (user_data, g_mencoder_signals[PAUSED], 0);
931 } else if ((oldstate == GST_STATE_PAUSED) &&
932 (newstate == GST_STATE_PLAYING)) {
933 g_signal_emit (user_data, g_mencoder_signals[PLAYING], 0);
934 } else if ((oldstate == GST_STATE_READY) &&
935 (newstate == GST_STATE_NULL)) {
936 g_signal_emit (user_data, g_mencoder_signals[STOPED], 0);
940 case GST_MESSAGE_ERROR:
946 if (priv->tick_id != 0) {
947 g_source_remove (priv->tick_id);
951 gst_message_parse_error (msg, &error, &debug);
952 err_str = g_strdup_printf ("Error [%d] %s (%s)", error->code,
956 g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, err_str);
958 g_clear_error (&error);
963 case GST_MESSAGE_EOS:
965 g_signal_emit (user_data, g_mencoder_signals[EOS], 0);
967 case GST_MESSAGE_DURATION:
971 gst_message_parse_duration (msg, &format, &duration);
972 if (format == GST_FORMAT_BYTES)
973 priv->duration = duration;
987 _decodebin_new_pad_cb (GstElement* object,
993 gchar *str_caps = NULL;
994 GstElement *sink_element;
997 caps = gst_pad_get_caps (pad);
998 str_caps = gst_caps_to_string (caps);
999 if (strstr (str_caps, "audio") != NULL) {
1000 sink_element = gst_bin_get_by_name (GST_BIN (user_data), "aqueue");
1001 } else if (strstr (str_caps, "video") != NULL) {
1002 sink_element = gst_bin_get_by_name (GST_BIN (user_data), "vqueue");
1004 g_warning ("invalid caps %s", str_caps);
1007 sink_pad = gst_element_get_pad (sink_element, "sink");
1008 gst_pad_link (pad, sink_pad);
1010 gst_object_unref (sink_element);
1011 gst_object_unref (sink_pad);
1013 gst_caps_unref (caps);
1017 _decodebin_unknown_type_cb (GstElement* object,
1022 g_warning ("Unknown Type");
1023 //priv->ready = FALSE;
1027 _tick_cb (gpointer user_data)
1029 GstFormat format = GST_FORMAT_BYTES;
1032 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
1034 if (priv->duration == 0) {
1036 if (gst_element_query_duration (priv->src, &format, &d))
1040 if (priv->duration != 0) {
1041 gst_element_query_position (priv->src, &format, &cur);
1042 g_print ("PROGRESS:%lli\n", (99 * cur) / priv->duration);