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 ret = gst_element_factory_make (factory_name, element_name);
241 for (i=0; i < g_strv_length (prop); i++) {
242 char** v = g_strsplit(prop[i], "=", 2);
243 if (g_strv_length (v) == 2) {
244 _obj_set_prop (G_OBJECT (ret), v[0], v[1]);
255 _create_audio_bin (const gchar* encode,
259 GstElement *abin = NULL;
260 GstElement *aqueue = NULL;
261 GstElement *aconvert = NULL;
262 GstElement *aencode = NULL;
263 GstElement *aqueue_src = NULL;
266 //audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay ! udpsink name=upd_audio host=224.0.0.1 port=5002
267 abin = gst_bin_new ("abin");
268 aqueue = gst_element_factory_make ("queue", "aqueue");
269 aconvert= gst_element_factory_make ("audioconvert", "aconvert");
270 aencode = _create_element_with_prop ((encode ? encode : "lame"), "aencode", encode_prop);
271 aqueue_src= gst_element_factory_make ("queue", "aqueue_src");
273 if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL)
274 || (aencode == NULL) || (aqueue_src == NULL)) {
275 g_warning ("Audio elements not found");
279 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
282 g_object_set (G_OBJECT (aencode), "bitrate", 32, NULL);
286 gst_bin_add_many (GST_BIN (abin), aqueue, aconvert, aencode, aqueue_src, NULL);
287 if (gst_element_link_many (aqueue, aconvert, aencode, aqueue_src, NULL) == FALSE) {
288 g_warning ("Not Link audio elements");
291 //TODO: apply audio rate
293 // ghost pad the audio bin
294 apad = gst_element_get_pad (aqueue, "sink");
295 gst_element_add_pad (abin, gst_ghost_pad_new("sink", apad));
296 gst_object_unref (apad);
298 apad = gst_element_get_pad (aqueue_src, "src");
299 gst_element_add_pad (abin, gst_ghost_pad_new("src", apad));
300 gst_object_unref (apad);
305 gst_object_unref (abin);
308 gst_object_unref (aqueue);
310 if (aconvert != NULL)
311 gst_object_unref (aconvert);
314 gst_object_unref (aencode);
316 if (aqueue_src != NULL)
317 gst_object_unref (aqueue_src);
320 gst_object_unref (apad);
328 //queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! colorspace ! rate ! encode ! queue
330 _create_video_bin (const gchar* encode,
337 GstElement *vbin = NULL;
338 GstElement *vqueue = NULL;
339 GstElement* vqueue_src = NULL;
340 GstElement *vcolorspace = NULL;
341 GstElement *vencode = NULL;
342 GstElement *vrate = NULL;
345 vbin = gst_bin_new ("vbin");
346 vqueue = gst_element_factory_make ("queue", "vqueue");
347 vcolorspace = gst_element_factory_make ("ffmpegcolorspace", "colorspace");
348 vencode = _create_element_with_prop ((encode ? encode : "ffenc_mpeg1video"), "vencode", encode_prop);
349 vrate = gst_element_factory_make ("videorate", "vrate");
350 vqueue_src = gst_element_factory_make ("queue", "queue_src");
352 if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL)
353 || (vencode == NULL) || (vqueue_src == NULL)) {
354 g_warning ("Video elements not found");
358 gst_bin_add_many (GST_BIN (vbin), vqueue, vcolorspace, vencode, vqueue_src, NULL);
362 if ((width > 0) && (height > 0)) {
365 GstElement *vscale = gst_element_factory_make ("videoscale", "vscale");
367 gst_bin_add (GST_BIN (vbin), vscale);
369 vcaps = gst_caps_new_simple ("video/x-raw-yuv",
370 "width", G_TYPE_INT, width,
371 "height", G_TYPE_INT, height,
374 gst_element_link (vqueue, vscale);
376 if (gst_element_link_filtered (vscale, vcolorspace, vcaps) == FALSE) {
377 g_warning ("Fail to resize video");
378 gst_object_unref (vcaps);
379 gst_object_unref (vscale);
382 gst_caps_unref (vcaps);
384 gst_element_link (vqueue, vcolorspace);
389 //Changing the video fps
392 gst_bin_add (GST_BIN (vbin), vrate);
394 if (gst_element_link (vcolorspace, vrate) == FALSE) {
395 g_warning ("Fail to link video elements");
399 vcaps = gst_caps_new_simple ("video/x-raw-yuv",
400 "framerate", GST_TYPE_FRACTION, (int) (fps * 1000), 1000, NULL);
402 if (gst_element_link_filtered (vrate, vencode, vcaps) == FALSE) {
403 g_warning ("Fail to link vrate with vencode.");
406 gst_caps_unref (vcaps);
408 if (gst_element_link (vcolorspace, vencode) == FALSE) {
409 g_warning ("Fail to link colorspace and video encode element.");
414 gst_element_link (vencode, vqueue_src);
416 // ghost pad the video bin
417 vpad = gst_element_get_pad (vqueue, "sink");
418 gst_element_add_pad (vbin, gst_ghost_pad_new ("sink", vpad));
419 gst_object_unref (vpad);
421 vpad = gst_element_get_pad (vqueue_src, "src");
422 gst_element_add_pad (vbin, gst_ghost_pad_new ("src", vpad));
423 gst_object_unref (vpad);
429 gst_object_unref (vpad);
432 gst_object_unref (vbin);
435 gst_object_unref (vqueue);
438 gst_object_unref (vencode);
440 if (vqueue_src != NULL)
441 gst_object_unref (vqueue_src);
443 if (vcolorspace != NULL)
444 gst_object_unref (vcolorspace);
452 g_mencoder_setup_stream (GMencoder *self,
453 const gchar* video_encode,
454 const gchar* mux_name,
455 gchar** video_encode_prop,
460 const gchar* audio_encode,
461 gchar** audio_encode_prop,
463 const gchar* out_uri)
465 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
466 if (priv->ready == TRUE) {
467 g_warning ("Stream already configured. You need close stream first.");
471 priv->pipe = _create_pipeline (self,
483 _close_output (self);
484 _open_output (self, out_uri);
489 g_mencoder_append_uri (GMencoder *self,
497 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
498 gboolean ret = FALSE;
500 g_return_val_if_fail (priv->pipe != NULL, FALSE);
501 g_return_val_if_fail (priv->ready == FALSE, FALSE);
503 src = _create_source (uri);
507 gst_bin_add (GST_BIN (priv->pipe), src);
509 ap = gst_bin_get_by_name (GST_BIN (priv->pipe), "ap");
510 vp = gst_bin_get_by_name (GST_BIN (priv->pipe), "vp");
511 if ((vp == NULL) || (ap == NULL))
514 pad_src = gst_element_get_pad (src, "src_audio");
515 pad_sink = gst_element_get_compatible_pad (ap,
517 gst_pad_get_caps (pad_src));
519 if ((pad_sink == NULL) || (pad_src == NULL))
522 GstPadLinkReturn lret = gst_pad_link (pad_src, pad_sink);
523 if (lret != GST_PAD_LINK_OK)
526 gst_object_unref (pad_src);
527 gst_object_unref (pad_sink);
529 pad_src = gst_element_get_pad (src, "src_video");
530 pad_sink = gst_element_get_compatible_pad (vp,
532 gst_pad_get_caps (pad_src));
534 if ((pad_src == NULL) || (pad_sink == NULL))
537 if (gst_pad_link (pad_src, pad_sink) != GST_PAD_LINK_OK) {
538 g_warning ("invalid source. video");
545 if ((src != NULL) && (ret == FALSE)) {
546 gst_bin_remove (GST_BIN (priv->pipe), src);
547 gst_object_unref (src);
551 gst_object_unref (ap);
554 gst_object_unref (vp);
557 gst_object_unref (pad_src);
559 if (pad_sink != NULL)
560 gst_object_unref (pad_sink);
568 g_mencoder_remove_uri (GMencoder *self,
571 // GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
576 g_mencoder_play_stream (GMencoder *self)
578 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
580 g_return_if_fail (priv->ready == FALSE);
582 gst_element_set_state (priv->pipe, GST_STATE_PLAYING);
586 g_mencoder_pause_stream (GMencoder *self)
588 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
590 g_return_if_fail (priv->ready == TRUE);
591 gst_element_set_state (priv->pipe, GST_STATE_PAUSED);
595 g_mencoder_close_stream (GMencoder *self)
598 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
600 if (priv->pipe != NULL) {
601 gst_element_set_state (priv->pipe, GST_STATE_NULL);
602 gst_object_unref (priv->pipe);
612 _sink_handoff_cb (GstElement* object,
617 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
620 size = write (priv->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
622 g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, "Fail to write output");
628 _create_pipeline (GMencoder *self,
629 const gchar* video_encode,
630 const gchar* mux_name,
631 gchar** video_encode_prop,
636 const gchar* audio_encode,
637 gchar** audio_encode_prop,
641 GstElement *pipe = NULL;
642 GstElement *sink = NULL;
643 GstElement *mux = NULL;
644 GstElement *abin = NULL;
645 GstElement *vbin = NULL;
646 GstElement *ap = NULL;
647 GstElement *vp = NULL;
648 GstPad *aux_pad = NULL;
649 GstPad *mux_pad = NULL;
651 pipe = gst_pipeline_new ("pipe");
653 ap = gst_element_factory_make ("concatmux", "ap");
654 vp = gst_element_factory_make ("concatmux", "vp");
656 mux = gst_element_factory_make ((mux_name ? mux_name : "ffmux_mpeg"), "mux");
660 sink = gst_element_factory_make ("fakesink", "sink");
664 g_object_set (G_OBJECT(sink),
666 "signal-handoffs", TRUE, NULL);
668 abin = _create_audio_bin (audio_encode, audio_encode_prop, audio_rate);
672 vbin = _create_video_bin (video_encode, video_encode_prop, video_fps, video_rate, video_width, video_height);
677 gst_bin_add_many (GST_BIN (pipe), ap, abin, vp, vbin, mux, sink, NULL);
679 if (gst_element_link (ap, abin) == FALSE) {
680 g_warning ("Fail to link concat and abin");
684 if (gst_element_link (vp, vbin) == FALSE) {
685 g_warning ("Fail to link concat and vbin");
689 aux_pad = gst_element_get_pad (abin, "src");
690 mux_pad = gst_element_get_pad (mux, "audio_0");
691 if (mux_pad == NULL) {
692 g_warning ("Mux element no have audio_0 PAD");
695 GstPadLinkReturn ret = gst_pad_link (aux_pad, mux_pad);
696 if (ret != GST_PAD_LINK_OK) {
697 g_warning ("Fail link audio and mux: %d", ret);
701 gst_object_unref (aux_pad);
702 gst_object_unref (mux_pad);
704 aux_pad = gst_element_get_pad (vbin, "src");
705 mux_pad = gst_element_get_pad (mux, "video_0");
706 if (mux_pad == NULL) {
707 g_warning ("Mux element no have video_0 PAD");
710 ret = gst_pad_link (aux_pad, mux_pad);
711 if (ret != GST_PAD_LINK_OK) {
712 g_warning ("Fail link video and mux: %d", ret);
715 gst_object_unref (aux_pad);
716 gst_object_unref (mux_pad);
721 gst_element_link (mux, sink);
723 g_signal_connect (G_OBJECT (sink),
725 G_CALLBACK (_sink_handoff_cb),
728 bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
729 gst_bus_add_watch (bus, _pipeline_bus_cb, self);
730 gst_object_unref (bus);
734 g_warning ("Invalid uri");
737 gst_object_unref (pipe);
742 gst_object_unref (mux);
745 if (mux_pad != NULL) {
746 gst_object_unref (mux_pad);
749 if (aux_pad != NULL) {
750 gst_object_unref (mux_pad);
754 gst_object_unref (sink);
758 gst_object_unref (abin);
762 gst_object_unref (vbin);
770 _close_output (GMencoder *self)
776 _create_source (const gchar* uri)
787 bsrc = gst_bin_new (NULL);
789 src = gst_element_factory_make ("gnomevfssrc", "src");
790 g_object_set (G_OBJECT (src), "location", uri, NULL);
794 decode = gst_element_factory_make ("decodebin2", "decode");
798 aqueue = gst_element_factory_make ("queue", "aqueue");
802 vqueue = gst_element_factory_make ("queue", "vqueue");
806 gst_bin_add_many (GST_BIN (bsrc), src, decode, aqueue, vqueue, NULL);
807 gst_element_link (src, decode);
809 g_signal_connect (G_OBJECT (decode),
811 G_CALLBACK (_decodebin_new_pad_cb),
814 g_signal_connect (G_OBJECT (decode),
816 G_CALLBACK (_decodebin_unknown_type_cb),
819 src_pad = gst_element_get_pad (aqueue, "src");
820 gst_element_add_pad (bsrc, gst_ghost_pad_new("src_audio", src_pad));
821 gst_object_unref (src_pad);
823 src_pad = gst_element_get_pad (vqueue, "src");
824 gst_element_add_pad (bsrc, gst_ghost_pad_new("src_video", src_pad));
825 gst_object_unref (src_pad);
831 gst_object_unref (src);
834 if (decode != NULL) {
835 gst_object_unref (decode);
838 if (aqueue != NULL) {
839 gst_object_unref (aqueue);
842 if (vqueue != NULL) {
843 gst_object_unref (vqueue);
850 _open_output (GMencoder *self,
854 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
856 i = g_strsplit (uri, "://", 0);
857 if (strcmp (i[0], "fd") == 0) {
858 priv->fd = atoi (i[1]);
859 } else if (strcmp (i[0], "file") == 0) {
860 priv->fd = open (i[1], O_WRONLY | O_CREAT | O_TRUNC);
862 g_warning ("Output uri not supported");
869 _pipeline_bus_cb (GstBus *bus,
873 GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
875 switch (GST_MESSAGE_TYPE (msg))
877 case GST_MESSAGE_STATE_CHANGED:
881 GstState pendingstate;
884 gst_message_parse_state_changed (msg, &oldstate,
885 &newstate, &pendingstate);
887 if (pendingstate != GST_STATE_VOID_PENDING)
890 if ((oldstate == GST_STATE_READY) &&
891 (newstate == GST_STATE_PAUSED)) {
893 g_signal_emit (user_data, g_mencoder_signals[PAUSED], 0);
894 } else if ((oldstate == GST_STATE_PAUSED) &&
895 (newstate == GST_STATE_PLAYING)) {
896 g_signal_emit (user_data, g_mencoder_signals[PLAYING], 0);
897 } else if ((oldstate == GST_STATE_READY) &&
898 (newstate == GST_STATE_NULL)) {
899 g_signal_emit (user_data, g_mencoder_signals[STOPED], 0);
903 case GST_MESSAGE_ERROR:
909 gst_message_parse_error (msg, &error, &debug);
910 err_str = g_strdup_printf ("Error [%d] %s (%s)", error->code,
913 g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, err_str);
916 g_clear_error (&error);
921 case GST_MESSAGE_EOS:
923 g_signal_emit (user_data, g_mencoder_signals[EOS], 0);
934 _decodebin_new_pad_cb (GstElement* object,
940 gchar *str_caps = NULL;
941 GstElement *sink_element;
944 caps = gst_pad_get_caps (pad);
945 str_caps = gst_caps_to_string (caps);
946 if (strstr (str_caps, "audio") != NULL) {
947 sink_element = gst_bin_get_by_name (GST_BIN (user_data), "aqueue");
948 } else if (strstr (str_caps, "video") != NULL) {
949 sink_element = gst_bin_get_by_name (GST_BIN (user_data), "vqueue");
951 g_warning ("invalid caps %s", str_caps);
954 sink_pad = gst_element_get_pad (sink_element, "sink");
955 gst_pad_link (pad, sink_pad);
957 gst_object_unref (sink_element);
958 gst_object_unref (sink_pad);
960 gst_caps_unref (caps);
964 _decodebin_unknown_type_cb (GstElement* object,
969 g_warning ("Unknown Type");
970 //priv->ready = FALSE;