gmyth-stream/gmemcoder/src/gmemcoder.c
author melunko
Mon Apr 23 19:16:24 2007 +0100 (2007-04-23)
branchtrunk
changeset 587 747b409e4f01
permissions -rw-r--r--
[svn r593] Fixed internal reference to gmyth.h. We can not include this header in src/gmyth_* files. Also fixed gmyth_debug link error. In the current implementation we need to include gmyth_debug.h in all files using gmyth_debug(), otherwise we will get library linking error
     1 #ifdef HAVE_CONFIG_H
     2 #include "config.h"
     3 #endif
     4 
     5 #include <glib.h>
     6 #include <gst/gst.h>
     7 #include <string.h>
     8 
     9 #include "gmemcoder.h"
    10 
    11 #define G_MENCODER_GET_PRIVATE(obj) \
    12     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), G_TYPE_MENCODER, GMencoderPrivate))
    13 
    14 
    15 typedef struct _GMencoderPrivate GMencoderPrivate;
    16 
    17 struct _GMencoderPrivate
    18 {    
    19 	GstElement *pipe;
    20 	GstElement *abin;
    21 	GstElement *vbin;
    22 	GstElement *sink;
    23 	gboolean ready;
    24 };
    25 
    26 enum {
    27   READY,
    28   PAUSED,
    29   PLAYING,
    30   STOPED,
    31   EOS,
    32   ERROR,
    33   LAST_SIGNAL
    34 };
    35 
    36 static void g_mencoder_class_init       (GMencoderClass *klass);
    37 static void g_mencoder_init             (GMencoder *object);
    38 static void g_mencoder_dispose  	    (GObject *object);
    39 static void g_mencoder_finalize 	    (GObject *object);
    40 static gboolean 
    41             _pipeline_bus_cb            (GstBus     *bus,
    42 		                                 GstMessage *msg,
    43 		                                 gpointer    user_data);
    44 
    45 static void _decodebin_new_pad_cb 		(GstElement* object,
    46 				                         GstPad* pad,
    47 				                         gboolean flag,
    48 				                         gpointer user_data);
    49 static void  _decodebin_unknown_type_cb (GstElement* object,
    50 		                         	     GstPad* pad,
    51                                          GstCaps* caps,
    52                                          gpointer user_data);
    53 
    54 static guint g_mencoder_signals[LAST_SIGNAL] = { 0 };
    55 
    56 G_DEFINE_TYPE(GMencoder, g_mencoder, G_TYPE_OBJECT)
    57 
    58 static void
    59 g_mencoder_class_init (GMencoderClass *klass)
    60 {   
    61 	GObjectClass *object_class;
    62 
    63 	object_class = (GObjectClass *) klass;
    64 
    65 	g_type_class_add_private (klass, sizeof (GMencoderPrivate));
    66         
    67 	object_class->dispose  = g_mencoder_dispose;
    68 	object_class->finalize = g_mencoder_finalize;	
    69 	
    70     g_mencoder_signals[READY] =
    71         g_signal_new ("ready",
    72     		  G_OBJECT_CLASS_TYPE (object_class),
    73     		  G_SIGNAL_RUN_FIRST,
    74     		  0, NULL, NULL,
    75     		  g_cclosure_marshal_VOID__VOID,
    76     		  G_TYPE_NONE, 0);
    77 
    78     g_mencoder_signals[PAUSED] =
    79         g_signal_new ("paused",
    80     		  G_OBJECT_CLASS_TYPE (object_class),
    81     		  G_SIGNAL_RUN_FIRST,
    82     		  0, NULL, NULL,
    83     		  g_cclosure_marshal_VOID__VOID,
    84     		  G_TYPE_NONE, 0);
    85     		  
    86     g_mencoder_signals[PLAYING] =
    87         g_signal_new ("playing",
    88     		  G_OBJECT_CLASS_TYPE (object_class),
    89     		  G_SIGNAL_RUN_FIRST,
    90     		  0, NULL, NULL,
    91               g_cclosure_marshal_VOID__VOID,
    92     		  G_TYPE_NONE, 0);
    93 
    94     g_mencoder_signals[STOPED] =
    95         g_signal_new ("stoped",
    96     		  G_OBJECT_CLASS_TYPE (object_class),
    97     		  G_SIGNAL_RUN_FIRST,
    98     		  0, NULL, NULL,
    99     		  g_cclosure_marshal_VOID__VOID,
   100     		  G_TYPE_NONE, 0);
   101 
   102     g_mencoder_signals[EOS] =
   103         g_signal_new ("eos",
   104     		  G_OBJECT_CLASS_TYPE (object_class),
   105     		  G_SIGNAL_RUN_FIRST,
   106     		  0, NULL, NULL,
   107     		  g_cclosure_marshal_VOID__VOID,
   108     		  G_TYPE_NONE, 0);
   109     		  
   110     		  
   111     g_mencoder_signals[ERROR] =
   112         g_signal_new ("error",
   113     		  G_OBJECT_CLASS_TYPE (object_class),
   114     		  G_SIGNAL_RUN_FIRST,
   115     		  0, NULL, NULL,
   116     		  g_cclosure_marshal_VOID__STRING,
   117     		  G_TYPE_NONE, 1, G_TYPE_STRING);	
   118 }
   119 
   120 static void
   121 g_mencoder_init (GMencoder *self)
   122 {
   123 }
   124 
   125 static void 
   126 g_mencoder_dispose (GObject *object)
   127 {
   128 }
   129 
   130 static void 
   131 g_mencoder_finalize (GObject *object)
   132 {
   133 	g_mencoder_close_stream (G_MENCODER (object));
   134 }
   135 
   136 GMencoder*  
   137 g_mencoder_new (void)
   138 {
   139     return g_object_new (G_TYPE_MENCODER, NULL);
   140 }
   141 
   142 
   143 gboolean
   144 g_mencoder_setup_stream (GMencoder *self, 
   145                          const gchar* uri, 
   146                          guint width, guint height,
   147                          gint out_fd)
   148 {
   149 	GstBus *bus = NULL;
   150 	GstElement *pipe = NULL;
   151 	GstElement *decode = NULL;
   152 	GstElement *fdsink = NULL;
   153     GstElement *mux = NULL;
   154 
   155 	GstCaps *vscale_caps = NULL;
   156 	GstPad *asinkpad = NULL;
   157 	GstPad *vsinkpad = NULL;
   158     GstPad *video_src_pad = NULL;
   159     GstPad *audio_src_pad = NULL;
   160     GstPad *mux_pad = NULL;
   161 	GstElement *src = NULL;
   162 	GstElement *vbin, *vqueue, *vcolorspace, *vscale, *vrate, *vencode, *vqueue_src;
   163 	GstElement *abin, *aqueue, *aconvert, *aencode, *aqueue_src;
   164 	GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   165 	
   166 	vbin = vqueue = vscale = vrate = vencode = vqueue_src = NULL;
   167 	abin = aqueue = aconvert = aencode = aqueue_src = NULL;
   168 
   169 	pipe = gst_pipeline_new ("pipe");
   170 	src = gst_element_make_from_uri (GST_URI_SRC, uri, "src");
   171 	if (src == NULL) 
   172 		goto error;
   173 
   174 	decode = gst_element_factory_make ("decodebin", "decode");
   175 	if (decode == NULL) 
   176 		goto error;
   177 	
   178     mux = gst_element_factory_make ("ffmux_mpeg", "mux");
   179     if (mux == NULL)
   180         goto error;
   181 
   182     fdsink = gst_element_factory_make ("fdsink", "sink");
   183     if (fdsink == NULL)
   184         goto error;
   185 
   186     g_debug ("Setting fd to %d", out_fd);
   187     g_object_set (G_OBJECT (fdsink), "fd", out_fd, NULL);        		
   188 	
   189 	//queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! videorate ! ffenc_h263p bitrate=256000 me-method=2 ! rtph263ppay ! udpsink  host=224.0.0.1 port=5000
   190 
   191 	vbin    = gst_bin_new ("vbin");
   192 	vqueue	= gst_element_factory_make ("queue", "vqueue");
   193 	vscale  = gst_element_factory_make ("videoscale", "vscale");
   194 	vcolorspace = gst_element_factory_make ("ffmpegcolorspace", "colorspace");
   195 	vrate   = gst_element_factory_make ("videorate", "vrate");
   196 	vencode = gst_element_factory_make ("ffenc_mpeg1video", "vencode");
   197 	vqueue_src = gst_element_factory_make ("queue", "queue_src");
   198 
   199 	
   200 	if ((vbin == NULL) || (vqueue == NULL) || (vcolorspace == NULL) 
   201 	    || (vscale == NULL) || (vrate == NULL) 
   202 		|| (vencode == NULL) || (vqueue_src == NULL)) {
   203 		g_warning ("Video elements not found");
   204 		goto error;
   205 	}
   206 
   207 	g_object_set (G_OBJECT (vencode), "bitrate", 200, "pass", 2, "quantizer", 5, NULL);
   208 		
   209 	gst_bin_add_many (GST_BIN (vbin), vqueue, vscale, vcolorspace, vrate, vencode, vqueue_src, NULL);
   210     gst_element_link (vqueue, vscale);
   211 
   212 	
   213 	vscale_caps = gst_caps_new_simple ("video/x-raw-yuv",
   214 					   "width", G_TYPE_INT, 320,
   215 					   "height", G_TYPE_INT, 288,                           
   216 					   NULL);
   217 					   	
   218 	if (gst_element_link_filtered (vscale, vcolorspace, vscale_caps) == FALSE) {
   219 	    g_warning ("Fail to resize video");
   220 	    goto error;
   221 	}
   222 	
   223 	if (gst_element_link (vcolorspace, vrate) == FALSE) {
   224 	    g_warning ("Fail to link video elements");
   225 	    goto error;
   226 	}
   227 
   228     gst_caps_unref (vscale_caps);
   229 
   230 	vscale_caps = gst_caps_new_simple ("video/x-raw-yuv",
   231 					   "framerate", GST_TYPE_FRACTION, 10, 1, NULL);
   232 
   233     if (gst_element_link_filtered (vrate, vencode, vscale_caps) == FALSE) { 
   234         g_warning ("Fail to link vrate with vencode.");
   235         goto error;
   236 
   237     }
   238 
   239     gst_element_link (vencode, vqueue_src);
   240 
   241 	// ghost pad the video  bin
   242    	vsinkpad = gst_element_get_pad (vqueue, "sink");
   243    	gst_element_add_pad (vbin, gst_ghost_pad_new ("sink", vsinkpad));	
   244 	gst_object_unref (vsinkpad);
   245 	
   246    	video_src_pad = gst_element_get_pad (vqueue_src, "src");
   247    	gst_element_add_pad (vbin, gst_ghost_pad_new ("src", video_src_pad));	
   248 	gst_object_unref (video_src_pad);
   249 
   250 
   251     //audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay !  udpsink name=upd_audio host=224.0.0.1 port=5002	
   252 	abin 	= gst_bin_new ("abin");
   253 	aqueue	= gst_element_factory_make ("queue", "aqueue");
   254 	aconvert= gst_element_factory_make ("audioconvert", "aconvert");
   255 	aencode = gst_element_factory_make ("lame", "aencode");
   256 	aqueue_src= gst_element_factory_make ("queue", "aqueue_src");	
   257 
   258 	if ((abin == NULL) || (aqueue == NULL) || (aconvert == NULL) 
   259 		|| (aencode == NULL) || (aqueue_src == NULL)) {
   260 		g_warning ("Audio elements not found");
   261 		goto error;
   262 	}
   263 
   264 	gst_bin_add_many (GST_BIN (abin), aqueue, aconvert, aencode, aqueue_src, NULL);
   265 	gst_element_link_many (aqueue, aconvert, aencode, aqueue_src, NULL);
   266 
   267 
   268 	// ghost pad the audio bin
   269    	asinkpad = gst_element_get_pad (aqueue, "sink");
   270    	gst_element_add_pad (abin, gst_ghost_pad_new("sink", asinkpad));
   271 	gst_object_unref (asinkpad);
   272 	
   273    	audio_src_pad = gst_element_get_pad (aqueue_src, "src");
   274    	gst_element_add_pad (abin, gst_ghost_pad_new("src", audio_src_pad));
   275     gst_object_unref (audio_src_pad);
   276 	
   277 	
   278 	// Finish Pipe
   279 	gst_bin_add_many (GST_BIN (pipe), src, decode, abin, vbin, mux, fdsink, NULL);
   280 	gst_element_link (src, decode);
   281 
   282     //Link bins with mux
   283     audio_src_pad = gst_element_get_pad (abin, "src");
   284     mux_pad = gst_element_get_pad (mux, "audio_0");
   285     if (gst_pad_link (audio_src_pad, mux_pad) != GST_PAD_LINK_OK) {
   286         g_warning ("Fail link audio and mux");
   287         goto error;
   288    
   289     }
   290 	gst_object_unref (audio_src_pad);
   291     gst_object_unref (mux_pad);
   292     audio_src_pad = NULL;
   293     mux_pad = NULL;
   294 
   295     video_src_pad = gst_element_get_pad (vbin, "src");
   296     mux_pad = gst_element_get_pad (mux, "video_0");
   297     if (gst_pad_link (video_src_pad, mux_pad) != GST_PAD_LINK_OK) {
   298         g_warning ("Fail link video and mux");
   299         goto error;
   300     }
   301     gst_object_unref (video_src_pad);
   302     gst_object_unref (mux_pad);
   303     video_src_pad = NULL;
   304     mux_pad = NULL;
   305 
   306     //Link mux with sink
   307     gst_element_link (mux, fdsink);
   308 
   309 	bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
   310 	gst_bus_add_watch (bus, _pipeline_bus_cb, self);
   311 	gst_object_unref (bus);
   312 
   313 	g_signal_connect (G_OBJECT (decode), 
   314 				"new-decoded-pad",
   315 				G_CALLBACK (_decodebin_new_pad_cb),
   316 				self);
   317 	
   318 	g_signal_connect (G_OBJECT (decode),
   319 				"unknown-type",
   320 				G_CALLBACK (_decodebin_unknown_type_cb),
   321 				self);
   322 
   323 	g_debug ("Setting pipe to PAUSE");
   324 
   325 	priv->pipe = pipe;
   326 	priv->abin = abin;
   327 	priv->vbin = vbin;
   328 	priv->sink = fdsink;
   329 	priv->ready = FALSE;
   330 	
   331 	gst_element_set_state (pipe, GST_STATE_PAUSED);	   	
   332     g_debug ("End SETUP");
   333 	return  TRUE;
   334 	
   335 error:
   336 	g_warning ("Invalid uri");
   337 
   338 	if (pipe != NULL)
   339 		gst_object_unref (pipe);
   340 
   341 	if (src != NULL)
   342 		gst_object_unref (src);
   343 
   344 	if (decode != NULL)
   345 		gst_object_unref (decode);
   346 
   347 	if (vscale_caps != NULL)
   348 		gst_caps_unref  (vscale_caps);
   349 
   350 	if (vbin != NULL)
   351 		gst_object_unref (vbin);
   352 
   353 	if (vqueue != NULL)
   354 		gst_object_unref (vqueue);
   355 
   356 	if (vrate != NULL)
   357 		gst_object_unref (vrate);
   358 
   359 	if (vencode != NULL)
   360 		gst_object_unref (vencode);
   361 
   362 	if (vqueue_src != NULL)
   363 		gst_object_unref (vqueue_src);
   364 
   365 	if (abin != NULL)
   366 		gst_object_unref (abin);
   367 
   368 	if (aqueue != NULL)
   369 		gst_object_unref (aqueue);
   370 
   371 	if (aconvert != NULL)
   372 		gst_object_unref (aconvert);
   373 
   374 	if (aencode != NULL)
   375 		gst_object_unref (aencode);
   376 
   377 	if (aqueue_src != NULL)
   378 		gst_object_unref (aqueue_src);
   379 
   380     if (video_src_pad != NULL) {
   381         gst_object_unref (video_src_pad);
   382     }
   383 
   384     if (audio_src_pad != NULL) {
   385         gst_object_unref (audio_src_pad);
   386     }
   387 
   388     if (mux != NULL) {
   389         gst_object_unref (mux);
   390     }
   391 
   392     if (mux_pad != NULL) {
   393         gst_object_unref (mux_pad);
   394     }
   395 
   396 	if (fdsink != NULL)
   397 		gst_object_unref (fdsink);
   398 
   399 	return FALSE;
   400 }
   401 
   402 gboolean 
   403 g_mencoder_play_stream (GMencoder *self)
   404 {
   405     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   406 
   407     g_return_val_if_fail (priv->ready == TRUE, FALSE);
   408     
   409     if (gst_element_set_state (priv->pipe, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) {
   410 			g_debug ("PLAYING");
   411 			return TRUE;
   412 	}
   413 	return FALSE;
   414 }
   415 
   416 gboolean
   417 g_mencoder_pause_stream (GMencoder *self)
   418 {
   419     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   420 
   421     g_return_val_if_fail (priv->ready == TRUE, FALSE);
   422     
   423     if (gst_element_set_state (priv->pipe, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE) {
   424 			g_debug ("PAUSED");
   425 			return TRUE;
   426 	}
   427 	return FALSE;
   428 }
   429 
   430 void
   431 g_mencoder_close_stream (GMencoder *self)
   432 {
   433 
   434     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (self);
   435 
   436     g_return_if_fail (priv->ready == TRUE);
   437     
   438     gst_element_set_state (priv->pipe, GST_STATE_NULL);
   439     gst_object_unref (priv->pipe);
   440     priv->pipe = NULL;
   441     priv->abin = NULL;
   442     priv->vbin = NULL;
   443     priv->sink = NULL;
   444     priv->ready = FALSE;
   445 }
   446 
   447 static gboolean
   448 _pipeline_bus_cb (GstBus     *bus,
   449 		  GstMessage *msg,
   450 		  gpointer    user_data)
   451 {
   452 	switch (GST_MESSAGE_TYPE (msg)) 
   453 	{
   454 		case GST_MESSAGE_STATE_CHANGED:
   455 		{
   456 			GstState oldstate;
   457 			GstState newstate;
   458 			GstState pendingstate;
   459 
   460 			GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
   461 
   462 			gst_message_parse_state_changed (msg, &oldstate,
   463 				&newstate, &pendingstate);
   464 
   465             if (pendingstate != GST_STATE_VOID_PENDING)
   466                 break;
   467 
   468             if ((oldstate == GST_STATE_READY) && 
   469                 (newstate == GST_STATE_PAUSED)) {
   470                     if (priv->ready) 
   471                         g_signal_emit (user_data, g_mencoder_signals[PAUSED], 0);
   472                     else {
   473                         priv->ready = TRUE;
   474                         g_signal_emit (user_data, g_mencoder_signals[READY], 0);
   475                     }
   476             } else if ((oldstate == GST_STATE_PAUSED) &&
   477                        (newstate == GST_STATE_PLAYING)) {
   478                         g_signal_emit (user_data, g_mencoder_signals[PLAYING], 0);
   479             } else if ((oldstate == GST_STATE_READY) &&
   480                        (newstate == GST_STATE_NULL)) {
   481                         g_signal_emit (user_data, g_mencoder_signals[STOPED], 0);
   482             }			
   483             break;
   484 		}
   485 		case GST_MESSAGE_ERROR: 
   486 		{
   487 		    GError *error;
   488 		    gchar *debug;
   489 		    gchar *err_str;
   490 		    
   491 		    gst_message_parse_error (msg, &error, &debug);
   492 		    err_str = g_strdup_printf ("Error [%d] %s (%s)", error->code,
   493 		        error->message,
   494 		        debug);
   495 		    g_signal_emit (user_data, g_mencoder_signals[ERROR], 0, err_str);
   496 		    g_free (err_str);
   497 		    g_clear_error (&error);
   498 		    g_free (debug);
   499 		    break;
   500 		}
   501 		
   502 		case GST_MESSAGE_EOS:
   503 		    g_signal_emit (user_data, g_mencoder_signals[EOS], 0);
   504 		    break;		
   505 		default:
   506 			break;
   507 	}
   508 	return TRUE;
   509 }
   510 
   511 static void 
   512 _decodebin_new_pad_cb (GstElement* object,
   513                        GstPad* pad,
   514                        gboolean flag,
   515                        gpointer user_data)
   516 {
   517 	GstCaps *caps;
   518 	gchar *str_caps = NULL;
   519     GMencoderPrivate *priv = G_MENCODER_GET_PRIVATE (user_data);
   520 
   521 	caps = gst_pad_get_caps (pad);
   522 	str_caps = gst_caps_to_string (caps);
   523     g_debug ("CAPS : %s", str_caps);
   524 
   525 	if (strstr (str_caps, "audio") != NULL) {
   526 		GstPad *apad = gst_element_get_pad (priv->abin, "sink");
   527 		g_debug ("Linked with Audio");
   528 		gst_pad_link (pad, apad);
   529 		gst_object_unref (apad);
   530 	} else if (strstr (str_caps, "video") != NULL) {
   531 		GstPad *vpad = gst_element_get_pad (priv->vbin, "sink");
   532 		g_debug ("Linked with Video");
   533 		gst_pad_link (pad, vpad);
   534 		gst_object_unref (vpad);
   535 	} else {
   536 		g_warning ("invalid caps %s", str_caps);
   537 	}
   538 
   539 	g_free (str_caps);
   540 	gst_caps_unref (caps);
   541 	g_debug ("OK");
   542 }
   543 
   544 static void 
   545 _decodebin_unknown_type_cb (GstElement* object,
   546                             GstPad* pad,
   547                             GstCaps* caps,
   548                             gpointer user_data)
   549 {
   550     g_warning  ("Unknown Type");
   551 }