12 #include "gmencoder.h"
14 #define G_MENCODER_GET_PRIVATE(obj) \
15 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_TYPE_MENCODER, GMencoderPrivate))
18 typedef struct _GMencoderPrivate GMencoderPrivate;
19 typedef struct _SetupInfo SetupInfo;
25 gchar** video_encode_prop;
31 gchar** audio_encode_prop;
36 struct _GMencoderPrivate
58 static void g_mencoder_class_init (GMencoderClass *klass);
59 static void g_mencoder_init (GMencoder *object);
60 static void g_mencoder_dispose (GObject *object);
61 static void g_mencoder_finalize (GObject *object);
63 _create_audio_bin (const gchar* encode,
67 _create_video_bin (const gchar* encode,
75 _pipeline_bus_cb (GstBus *bus,
78 static void _decodebin_new_pad_cb (GstElement* object,
82 static void _decodebin_unknown_type_cb (GstElement* object,
86 static void _close_output (GMencoder *self);
87 static void _open_output (GMencoder *self,
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,
106 static guint g_mencoder_signals[LAST_SIGNAL] = { 0 };
108 G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT)
111 g_mencoder_class_init (GMencoderClass *klass)
113 GObjectClass *object_class;
115 object_class = (GObjectClass *) klass;
117 g_type_class_add_private (klass, sizeof (GMencoderPrivate));
119 object_class->dispose = g_mencoder_dispose;
120 object_class->finalize = g_mencoder_finalize;
122 g_mencoder_signals[PAUSED] =
123 g_signal_new ("paused",
124 G_OBJECT_CLASS_TYPE (object_class),
127 g_cclosure_marshal_VOID__VOID,
130 g_mencoder_signals[PLAYING] =
131 g_signal_new ("playing",
132 G_OBJECT_CLASS_TYPE (object_class),
135 g_cclosure_marshal_VOID__VOID,
138 g_mencoder_signals[STOPED] =
139 g_signal_new ("stoped",
140 G_OBJECT_CLASS_TYPE (object_class),
143 g_cclosure_marshal_VOID__VOID,
146 g_mencoder_signals[EOS] =
148 G_OBJECT_CLASS_TYPE (object_class),
151 g_cclosure_marshal_VOID__VOID,
155 g_mencoder_signals[ERROR] =
156 g_signal_new ("error",
157 G_OBJECT_CLASS_TYPE (object_class),
160 g_cclosure_marshal_VOID__STRING,
161 G_TYPE_NONE, 1, G_TYPE_STRING);
165 g_mencoder_init (GMencoder *self)
167 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
168 priv->info = g_new0 (SetupInfo, 1);
172 g_mencoder_dispose (GObject *object)
177 g_mencoder_finalize (GObject *object)
180 g_mencoder_close_stream (G_MENCODER (object));
184 g_mencoder_new (void)
186 return g_object_new (G_TYPE_MENCODER, NULL);
191 _obj_set_prop (GObject *obj,
192 const gchar *prop_name,
193 const gchar *prop_val)
197 GParamSpec *s = NULL;
198 GObjectClass *k = G_OBJECT_GET_CLASS (obj);
201 g_value_init (&v, G_TYPE_STRING);
202 g_value_set_string (&v, prop_val);
204 s = g_object_class_find_property (k, prop_name);
206 g_print ("Invalid property name: %s\n", prop_name);
210 g_value_init (&p, s->value_type);
211 switch (s->value_type)
214 g_value_set_int (&p, atoi (prop_val));
217 g_value_set_string (&p, prop_val);
223 g_object_set_property (obj, prop_name, &p);
229 _create_element_with_prop (const gchar* factory_name,
230 const gchar* element_name,
236 g_debug ("Creating element: %s", factory_name);
238 ret = gst_element_factory_make (factory_name, element_name);
243 for (i=0; i < g_strv_length (prop); i++) {
244 char** v = g_strsplit(prop[i], "=", 2);
245 if (g_strv_length (v) == 2) {
246 _obj_set_prop (G_OBJECT (ret), v[0], v[1]);
257 _create_audio_bin (const gchar* encode,
261 GstElement *abin = NULL;
262 GstElement *aqueue = NULL;
263 GstElement *aconvert = NULL;
264 GstElement *aencode = NULL;
265 GstElement *aqueue_src = NULL;
268 //audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay ! udpsink name=upd_audio host=224.0.0.1 port=5002
269 abin = gst_bin_new ("abin");
270 aqueue = gst_element_factory_make ("queue", "aqueue");
271 aconvert= gst_element_factory_make ("audioconvert", "aconvert");
272 aencode = _create_element_with_prop ((encode ? encode : "lame"), "aencode", encode_prop);
273 aqueue_src= gst_element_factory_make ("queue", "aqueue_src");
275 if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL)
276 || (aencode == NULL) || (aqueue_src == NULL)) {
277 g_warning ("Audio elements not found");
281 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
284 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
288 gst_bin_add_many (GST_BIN (abin), aqueue, aconvert, aencode, aqueue_src, NULL);
289 if (gst_element_link_many (aqueue, aconvert, aencode, aqueue_src, NULL) == FALSE) {
290 g_warning ("Not Link audio elements");
293 //TODO: apply audio rate
295 // ghost pad the audio bin
296 apad = gst_element_get_pad (aqueue, "sink");
297 gst_element_add_pad (abin, gst_ghost_pad_new("sink", apad));
298 gst_object_unref (apad);
300 apad = gst_element_get_pad (aqueue_src, "src");
301 gst_element_add_pad (abin, gst_ghost_pad_new("src", apad));
302 gst_object_unref (apad);
307 gst_object_unref (abin);
310 gst_object_unref (aqueue);
312 if (aconvert != NULL)
313 gst_object_unref (aconvert);
316 gst_object_unref (aencode);
318 if (aqueue_src != NULL)
319 gst_object_unref (aqueue_src);
322 gst_object_unref (apad);
330 //queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace ! rate ! encode ! queue
332 _create_video_bin (const gchar* encode,
339 GstElement *vbin = NULL;
340 GstElement *vqueue = NULL;
341 GstElement* vqueue_src = NULL;
342 GstElement *vcolorspace = NULL;
343 GstElement *vencode = NULL;
344 GstElement *vrate = NULL;
347 vbin = gst_bin_new ("vbin");
348 vqueue = gst_element_factory_make ("queue", "vqueue");
349 vcolorspace = gst_element_factory_make ("ffmpegcolorspace", "colorspace");
351 vencode = _create_element_with_prop (
352 (encode != NULL ? encode : "ffenc_mpeg1video"),
353 "vencode", encode_prop);
354 vqueue_src = gst_element_factory_make ("queue", "queue_src");
356 if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL)
357 || (vencode == NULL) || (vqueue_src == NULL)) {
358 g_warning ("Video elements not found");
362 gst_bin_add_many (GST_BIN (vbin), vqueue, vcolorspace, vencode, vqueue_src, NULL);
365 if ((width > 0) && (height > 0)) {
368 GstElement *vscale = gst_element_factory_make ("videoscale", "vscale");
370 gst_bin_add (GST_BIN (vbin), vscale);
372 vcaps = gst_caps_new_simple ("video/x-raw-yuv",
373 "width", G_TYPE_INT, width,
374 "height", G_TYPE_INT, height,
377 gst_element_link (vqueue, vscale);
379 if (gst_element_link_filtered (vscale, vcolorspace, vcaps) == FALSE) {
380 g_warning ("Fail to resize video");
381 gst_object_unref (vcaps);
382 gst_object_unref (vscale);
385 gst_caps_unref (vcaps);
387 gst_element_link (vqueue, vcolorspace);
392 //Changing the video fps
394 vrate = gst_element_factory_make ("videorate", "vrate");
396 g_debug ("Setting FPS: %.2f", fps);
397 gst_bin_add (GST_BIN (vbin), vrate);
399 if (gst_element_link (vcolorspace, vrate) == FALSE) {
400 g_warning ("Fail to link video elements");
404 vcaps = gst_caps_new_simple ("video/x-raw-yuv",
405 "framerate", GST_TYPE_FRACTION, (int) (fps * 1000), 1000, NULL);
407 if (gst_element_link_filtered (vrate, vencode, vcaps) == FALSE) {
408 g_warning ("Fail to link vrate with vencode.");
411 gst_caps_unref (vcaps);
413 if (gst_element_link (vcolorspace, vencode) == FALSE) {
414 g_warning ("Fail to link colorspace and video encode element.");
419 gst_element_link (vencode, vqueue_src);
421 // ghost pad the video bin
422 vpad = gst_element_get_pad (vqueue, "sink");
423 gst_element_add_pad (vbin, gst_ghost_pad_new ("sink", vpad));
424 gst_object_unref (vpad);
426 vpad = gst_element_get_pad (vqueue_src, "src");
427 gst_element_add_pad (vbin, gst_ghost_pad_new ("src", vpad));
428 gst_object_unref (vpad);
434 gst_object_unref (vpad);
437 gst_object_unref (vbin);
440 gst_object_unref (vqueue);
443 gst_object_unref (vencode);
445 if (vqueue_src != NULL)
446 gst_object_unref (vqueue_src);
448 if (vcolorspace != NULL)
449 gst_object_unref (vcolorspace);
457 g_mencoder_setup_stream (GMencoder *self,
458 const gchar* mux_name,
459 const gchar* video_encode,
460 gchar** video_encode_prop,
465 const gchar* audio_encode,
466 gchar** audio_encode_prop,
468 const gchar* out_uri)
470 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
471 if (priv->ready == TRUE) {
472 g_warning ("Stream already configured. You need close stream first.");
476 priv->pipe = _create_pipeline (self,
488 _close_output (self);
489 _open_output (self, out_uri);
494 g_mencoder_append_uri (GMencoder *self,
502 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
503 gboolean ret = FALSE;
505 g_return_val_if_fail (priv->pipe != NULL, FALSE);
506 g_return_val_if_fail (priv->ready == FALSE, FALSE);
508 src = _create_source (uri);
512 gst_bin_add (GST_BIN (priv->pipe), src);
514 ap = gst_bin_get_by_name (GST_BIN (priv->pipe), "ap");
515 vp = gst_bin_get_by_name (GST_BIN (priv->pipe), "vp");
516 if ((vp == NULL) || (ap == NULL))
519 pad_src = gst_element_get_pad (src, "src_audio");
520 pad_sink = gst_element_get_compatible_pad (ap,
522 gst_pad_get_caps (pad_src));
524 if ((pad_sink == NULL) || (pad_src == NULL))
527 GstPadLinkReturn lret = gst_pad_link (pad_src, pad_sink);
528 if (lret != GST_PAD_LINK_OK)
531 gst_object_unref (pad_src);
532 gst_object_unref (pad_sink);
534 pad_src = gst_element_get_pad (src, "src_video");
535 pad_sink = gst_element_get_compatible_pad (vp,
537 gst_pad_get_caps (pad_src));
539 if ((pad_src == NULL) || (pad_sink == NULL))
542 if (gst_pad_link (pad_src, pad_sink) != GST_PAD_LINK_OK) {
543 g_warning ("invalid source. video");
550 if ((src != NULL) && (ret == FALSE)) {
551 gst_bin_remove (GST_BIN (priv->pipe), src);
552 gst_object_unref (src);
556 gst_object_unref (ap);
559 gst_object_unref (vp);
562 gst_object_unref (pad_src);
564 if (pad_sink != NULL)
565 gst_object_unref (pad_sink);
573 g_mencoder_remove_uri (GMencoder *self,
576 // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
581 g_mencoder_play_stream (GMencoder *self)
583 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
585 g_return_if_fail (priv->ready == FALSE);
587 gst_element_set_state (priv->pipe, GST_STATE_PLAYING);
591 g_mencoder_pause_stream (GMencoder *self)
593 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
595 g_return_if_fail (priv->ready == TRUE);
596 gst_element_set_state (priv->pipe, GST_STATE_PAUSED);
600 g_mencoder_close_stream (GMencoder *self)
603 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
605 if (priv->pipe != NULL) {
606 gst_element_set_state (priv->pipe, GST_STATE_NULL);
607 gst_object_unref (priv->pipe);
617 _sink_handoff_cb (GstElement* object,
622 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
625 size = write (priv->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
627 g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, "Fail to write output");
633 _create_pipeline (GMencoder *self,
634 const gchar* video_encode,
635 const gchar* mux_name,
636 gchar** video_encode_prop,
641 const gchar* audio_encode,
642 gchar** audio_encode_prop,
646 GstElement *pipe = NULL;
647 GstElement *sink = NULL;
648 GstElement *mux = NULL;
649 GstElement *abin = NULL;
650 GstElement *vbin = NULL;
651 GstElement *ap = NULL;
652 GstElement *vp = NULL;
653 GstPad *aux_pad = NULL;
654 GstPad *mux_pad = NULL;
656 pipe = gst_pipeline_new ("pipe");
658 ap = gst_element_factory_make ("concatmux", "ap");
659 vp = gst_element_factory_make ("concatmux", "vp");
661 mux = gst_element_factory_make ((mux_name ? mux_name : "ffmux_mpeg"), "mux");
665 sink = gst_element_factory_make ("fakesink", "sink");
669 g_object_set (G_OBJECT(sink),
671 "signal-handoffs", TRUE, NULL);
673 abin = _create_audio_bin (audio_encode, audio_encode_prop, audio_rate);
677 vbin = _create_video_bin (video_encode, video_encode_prop, video_fps, video_rate, video_width, video_height);
682 gst_bin_add_many (GST_BIN (pipe), ap, abin, vp, vbin, mux, sink, NULL);
684 if (gst_element_link (ap, abin) == FALSE) {
685 g_warning ("Fail to link concat and abin");
689 if (gst_element_link (vp, vbin) == FALSE) {
690 g_warning ("Fail to link concat and vbin");
694 aux_pad = gst_element_get_pad (abin, "src");
695 mux_pad = gst_element_get_compatible_pad (mux, aux_pad, GST_PAD_CAPS (aux_pad));
696 if (mux_pad == NULL) {
697 g_warning ("Mux element no have audio PAD");
700 GstPadLinkReturn ret = gst_pad_link (aux_pad, mux_pad);
701 if (ret != GST_PAD_LINK_OK) {
702 g_warning ("Fail link audio and mux: %d", ret);
706 gst_object_unref (aux_pad);
707 gst_object_unref (mux_pad);
709 aux_pad = gst_element_get_pad (vbin, "src");
710 mux_pad = gst_element_get_compatible_pad (mux, aux_pad, GST_PAD_CAPS (aux_pad));
711 if (mux_pad == NULL) {
712 g_warning ("Mux element no have video PAD");
715 ret = gst_pad_link (aux_pad, mux_pad);
716 if (ret != GST_PAD_LINK_OK) {
717 g_warning ("Fail link video and mux: %d", ret);
720 gst_object_unref (aux_pad);
721 gst_object_unref (mux_pad);
726 gst_element_link (mux, sink);
728 g_signal_connect (G_OBJECT (sink),
730 G_CALLBACK (_sink_handoff_cb),
733 bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
734 gst_bus_add_watch (bus, _pipeline_bus_cb, self);
735 gst_object_unref (bus);
739 g_warning ("Invalid uri");
742 gst_object_unref (pipe);
747 gst_object_unref (mux);
750 if (mux_pad != NULL) {
751 gst_object_unref (mux_pad);
754 if (aux_pad != NULL) {
755 gst_object_unref (mux_pad);
759 gst_object_unref (sink);
763 gst_object_unref (abin);
767 gst_object_unref (vbin);
775 _close_output (GMencoder *self)
781 _create_source (const gchar* uri)
792 bsrc = gst_bin_new (NULL);
794 src = gst_element_factory_make ("gnomevfssrc", "src");
795 g_object_set (G_OBJECT (src), "location", uri, NULL);
799 decode = gst_element_factory_make ("decodebin2", "decode");
803 aqueue = gst_element_factory_make ("queue", "aqueue");
807 vqueue = gst_element_factory_make ("queue", "vqueue");
811 gst_bin_add_many (GST_BIN (bsrc), src, decode, aqueue, vqueue, NULL);
812 gst_element_link (src, decode);
814 g_signal_connect (G_OBJECT (decode),
816 G_CALLBACK (_decodebin_new_pad_cb),
819 g_signal_connect (G_OBJECT (decode),
821 G_CALLBACK (_decodebin_unknown_type_cb),
824 src_pad = gst_element_get_pad (aqueue, "src");
825 gst_element_add_pad (bsrc, gst_ghost_pad_new("src_audio", src_pad));
826 gst_object_unref (src_pad);
828 src_pad = gst_element_get_pad (vqueue, "src");
829 gst_element_add_pad (bsrc, gst_ghost_pad_new("src_video", src_pad));
830 gst_object_unref (src_pad);
836 gst_object_unref (src);
839 if (decode != NULL) {
840 gst_object_unref (decode);
843 if (aqueue != NULL) {
844 gst_object_unref (aqueue);
847 if (vqueue != NULL) {
848 gst_object_unref (vqueue);
855 _open_output (GMencoder *self,
859 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
861 i = g_strsplit (uri, "://", 0);
862 if (strcmp (i[0], "fd") == 0) {
863 priv->fd = atoi (i[1]);
864 } else if (strcmp (i[0], "file") == 0) {
865 priv->fd = open (i[1], O_WRONLY | O_CREAT | O_TRUNC);
867 g_warning ("Output uri not supported");
874 _pipeline_bus_cb (GstBus *bus,
878 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
880 switch (GST_MESSAGE_TYPE (msg))
882 case GST_MESSAGE_STATE_CHANGED:
886 GstState pendingstate;
889 gst_message_parse_state_changed (msg, &oldstate,
890 &newstate, &pendingstate);
892 if (pendingstate != GST_STATE_VOID_PENDING)
895 if ((oldstate == GST_STATE_READY) &&
896 (newstate == GST_STATE_PAUSED)) {
898 g_signal_emit (user_data, g_mencoder_signals[PAUSED], 0);
899 } else if ((oldstate == GST_STATE_PAUSED) &&
900 (newstate == GST_STATE_PLAYING)) {
901 g_signal_emit (user_data, g_mencoder_signals[PLAYING], 0);
902 } else if ((oldstate == GST_STATE_READY) &&
903 (newstate == GST_STATE_NULL)) {
904 g_signal_emit (user_data, g_mencoder_signals[STOPED], 0);
908 case GST_MESSAGE_ERROR:
914 gst_message_parse_error (msg, &error, &debug);
915 err_str = g_strdup_printf ("Error [%d] %s (%s)", error->code,
918 g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, err_str);
921 g_clear_error (&error);
926 case GST_MESSAGE_EOS:
928 g_signal_emit (user_data, g_mencoder_signals[EOS], 0);
939 _decodebin_new_pad_cb (GstElement* object,
945 gchar *str_caps = NULL;
946 GstElement *sink_element;
949 caps = gst_pad_get_caps (pad);
950 str_caps = gst_caps_to_string (caps);
951 if (strstr (str_caps, "audio") != NULL) {
952 sink_element = gst_bin_get_by_name (GST_BIN (user_data), "aqueue");
953 } else if (strstr (str_caps, "video") != NULL) {
954 sink_element = gst_bin_get_by_name (GST_BIN (user_data), "vqueue");
956 g_warning ("invalid caps %s", str_caps);
959 sink_pad = gst_element_get_pad (sink_element, "sink");
960 gst_pad_link (pad, sink_pad);
962 gst_object_unref (sink_element);
963 gst_object_unref (sink_pad);
965 gst_caps_unref (caps);
969 _decodebin_unknown_type_cb (GstElement* object,
974 g_warning ("Unknown Type");
975 //priv->ready = FALSE;