play.old.c 35.1 KB
Newer Older
1 2 3 4
/* GStreamer
 * Copyright (C) 1999,2000,2001,2002 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000,2001,2002 Wim Taymans <wtay@chello.be>
 *                              2002 Steve Baker <steve@stevebaker.org>
5
 *								2003 Julien Moutte <julien@moutte.net>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * play.c: GstPlay object code
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "play.h"

enum {
	STREAM_END,
	INFORMATION,
	STATE_CHANGE,
	STREAM_LENGTH,
	TIME_TICK,
	HAVE_XID,
34
	HAVE_VIS_XID,
35 36
	HAVE_VIDEO_SIZE,
	LAST_SIGNAL,
37
	PIPELINE_ERROR,
38 39 40
};

/* this struct is used to decouple signals coming out of threaded pipelines */
41

42
typedef struct _GstPlaySignal    GstPlaySignal;
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
struct _GstPlaySignal
{
	gint signal_id;
	union {
		struct {
			gint width;
			gint height;
		} video_size;
		struct {
			gint xid;
		} video_xid;
		struct {
			GstElementState old_state;
			GstElementState new_state;
		} state;
		struct {
			GstElement* element;
			GParamSpec* param;
		} info;
63 64 65 66
		struct {
			GstElement* element;
			gchar* error;
		} error;
67 68 69 70 71 72 73 74 75 76 77 78 79 80
	} signal_data;
};

enum
{
	ARG_0,
	ARG_LOCATION,
	ARG_VOLUME,
	ARG_MUTE,
	/* FILL ME */
};

static guint gst_play_signals [LAST_SIGNAL] = { 0 };

81
static GstElementClass *parent_class = NULL;
82

83 84 85 86 87
/* ============================================================= */
/*                                                               */
/*                       Private Methods                         */
/*                                                               */
/* ============================================================= */
88

89 90 91 92 93
/* =========================================== */
/*                                             */
/*                  Tool Box                   */
/*                                             */
/* =========================================== */
94

95
static GQuark
96 97 98 99 100 101 102 103 104 105
gst_play_error_quark (void)
{
	static GQuark quark = 0;
	if (quark == 0) {
		quark = g_quark_from_static_string ("gst-play-error-quark");
	}

	return quark;
}

106 107 108 109
/* GError creation when plugin is missing
 * If we want to make error messages less
 * generic and have more errors than only
 * plug-ins, move the message creation to the switch */
110
static void
111 112
gst_play_error_plugin (	GstPlayError type,
						GError **error)
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
{
        gchar *name;

        if (error == NULL) return;

        switch (type)
        {
                case GST_PLAY_ERROR_THREAD:
                        name = g_strdup ("thread");
                        break;
                case GST_PLAY_ERROR_QUEUE:
                        name = g_strdup ("queue");
                        break;
                case GST_PLAY_ERROR_FAKESINK:
                        name = g_strdup ("fakesink");
                        break;
                case GST_PLAY_ERROR_VOLUME:
                        name = g_strdup ("volume");
                        break;
                case GST_PLAY_ERROR_COLORSPACE:
                        name = g_strdup ("colorspace");
                        break;
                case GST_PLAY_ERROR_GNOMEVFSSRC:
                        name = g_strdup ("gnomevfssrc");
                        break;
                default:
                        name = g_strdup ("unknown");
                        break;
        }
142 143 144 145 146 147 148 149
		
        *error = g_error_new (	GST_PLAY_ERROR,
								type,
								"The %s plug-in could not be found. "
								"This plug-in is essential for gst-player. "
								"Please install it and verify that it works "
								"by running 'gst-inspect %s'",
								name, name);
150 151 152 153
        g_free (name);
        return;
}

154 155 156 157 158
static void
gst_play_set_property (	GObject *object,
						guint prop_id,
						const GValue *value,
						GParamSpec *pspec)
159
{
160 161
	GstPlay *play;
	g_return_if_fail (object != NULL);
162
	g_return_if_fail (GST_IS_PLAY (object));
163
	play = GST_PLAY (object);
164
	
165 166 167 168 169 170 171 172 173 174 175 176 177
	switch (prop_id) {
	case ARG_LOCATION:
		gst_play_set_location(play, g_value_get_string (value));
		break;
	case ARG_VOLUME:
		gst_play_set_volume(play, g_value_get_float (value));
		break;
	case ARG_MUTE:
		gst_play_set_mute(play, g_value_get_boolean (value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
178 179 180 181
	}
}

static void
182 183 184 185
gst_play_get_property (	GObject *object,
						guint prop_id,
						GValue *value,
						GParamSpec *pspec)
186
{
187 188
	GstPlay *play;
	g_return_if_fail (object != NULL);
189
	g_return_if_fail (GST_IS_PLAY (object));
190
	play = GST_PLAY (object);
191

192 193 194 195 196 197 198 199 200 201 202 203 204 205
	switch (prop_id) {
	case ARG_LOCATION:
		g_value_set_string (value, gst_play_get_location(play));
		break;
	case ARG_VOLUME:
		g_value_set_float(value, gst_play_get_volume(play));
		break;
	case ARG_MUTE:
		g_value_set_boolean (value, gst_play_get_mute(play));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
206 207
}

208 209 210 211 212
/* =========================================== */
/*                                             */
/*          Event Handlers, Callbacks          */
/*                                             */
/* =========================================== */
213

214 215
static gboolean
gst_play_get_length_callback (GstPlay *play)
216
{
217 218 219
	gint64 value;
	GstFormat format = GST_FORMAT_TIME;
	gboolean query_worked = FALSE;
220

221
	g_print("trying to get length\n");
222 223
	if (	(play->audio_sink_element != NULL) &&
			(GST_IS_ELEMENT (play->audio_sink_element)) ) {
224 225 226
		g_mutex_lock(play->audio_bin_mutex);
		query_worked = gst_element_query (play->audio_sink_element, GST_QUERY_TOTAL, &format, &value);
		g_mutex_unlock(play->audio_bin_mutex);
227
		g_message ("getting length from audio sink");
228
	}
229 230
	else if (	(play->video_sink_element != NULL) &&
				(GST_IS_ELEMENT (play->video_sink_element)) ) {
231 232 233
		g_mutex_lock(play->video_bin_mutex);
		query_worked = gst_element_query (play->video_sink_element, GST_QUERY_TOTAL, &format, &value);
		g_mutex_unlock(play->video_bin_mutex);
234
	}
235 236 237 238 239
	if (query_worked){
		g_print("got length %" G_GINT64_FORMAT "\n", value);
		g_signal_emit (G_OBJECT (play), gst_play_signals [STREAM_LENGTH], 0, value);
		play->length_nanos = value;
		return FALSE;
240
	}
241 242 243 244
	else {
		if (play->get_length_attempt-- < 1){
			/* we've tried enough times, give up */
			return FALSE;
245 246
		}
	}
247 248 249 250 251 252 253
	return (gst_element_get_state(play->pipeline) == GST_STATE_PLAYING);
}

static gboolean
gst_play_tick_callback (GstPlay *play)
{
	gint secs;
254
	
255 256
	g_return_val_if_fail (play != NULL, FALSE); 
	g_return_val_if_fail (GST_IS_PLAY(play), FALSE);
257 258 259 260 261 262 263 264
	
	play->clock = gst_bin_get_clock (GST_BIN (play->pipeline));
	play->time_nanos = gst_clock_get_time(play->clock);
	secs = (gint) (play->time_nanos / GST_SECOND);
	if (secs != play->time_seconds){
		play->time_seconds = secs;
		g_signal_emit (G_OBJECT (play), gst_play_signals [TIME_TICK], 0, play->time_nanos);
	}
265

266
	return (gst_element_get_state(play->pipeline) == GST_STATE_PLAYING);
267 268
}

269 270
static gboolean
gst_play_default_idle (GstPlayIdleData *idle_data)
271
{
272 273 274
	if(idle_data->func(idle_data->data)){
		/* call this function again in the future */
		return TRUE;
275
	}
276 277 278
	/* this function should no longer be called */
	g_free(idle_data);
	return FALSE;
279 280
}

281 282 283 284
static guint
gst_play_default_timeout_add (	guint interval,
								GSourceFunc function,
								gpointer data)
285
{
286 287 288
	GstPlayIdleData *idle_data = g_new0(GstPlayIdleData, 1);
	idle_data->func = function;
	idle_data->data = data;
289

290 291
	return g_timeout_add (interval, (GSourceFunc)gst_play_default_idle, idle_data);
}
292

293 294 295 296 297 298 299 300 301 302
static guint
gst_play_default_idle_add (	GSourceFunc function,
							gpointer data)
{
	GstPlayIdleData *idle_data = g_new0(GstPlayIdleData, 1);
	idle_data->func = function;
	idle_data->data = data;
	
	return g_idle_add ((GSourceFunc)gst_play_default_idle, idle_data);
}
303

304 305 306
static gboolean
gst_play_idle_callback (GstPlay *play)
{
307 308
	g_return_val_if_fail (play != NULL, FALSE);
	g_return_val_if_fail (GST_IS_PLAY(play), FALSE);
309 310
	
	return gst_bin_iterate (GST_BIN (play->pipeline));
311 312 313 314 315 316 317
}

static gboolean
gst_play_idle_signal (GstPlay *play)
{
	GstPlaySignal *signal;
	gint queue_length;
318
	
319 320
	g_return_val_if_fail (play != NULL, FALSE);
	g_return_val_if_fail (GST_IS_PLAY(play), FALSE);
321
	
322 323 324 325 326 327 328 329 330 331
	signal = g_async_queue_try_pop(play->signal_queue);
	if (signal == NULL){
		return FALSE;
	}

	switch (signal->signal_id){
	case HAVE_XID:
		g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_XID], 0,
		               signal->signal_data.video_xid.xid);
		break;
332 333 334 335
	case HAVE_VIS_XID:
		g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIS_XID], 0,
		               signal->signal_data.video_xid.xid);
		break;
336 337 338 339 340 341 342 343 344 345 346
	case HAVE_VIDEO_SIZE:
		g_signal_emit (G_OBJECT (play), gst_play_signals[HAVE_VIDEO_SIZE], 0, 
		               signal->signal_data.video_size.width, signal->signal_data.video_size.height);
		break;
	case STATE_CHANGE:
		g_signal_emit (G_OBJECT (play), gst_play_signals[STATE_CHANGE], 0, 
		               signal->signal_data.state.old_state, signal->signal_data.state.new_state);
		break;
	case INFORMATION:
		g_signal_emit (G_OBJECT (play), gst_play_signals[INFORMATION], 0, 
		               signal->signal_data.info.element, signal->signal_data.info.param);
347 348 349 350 351 352 353 354
		gst_object_unref (GST_OBJECT(signal->signal_data.info.element));
		break;
	case PIPELINE_ERROR:
		if (gst_element_get_state(play->pipeline) == GST_STATE_PLAYING)
			gst_element_set_state(play->pipeline, GST_STATE_READY);
		g_signal_emit (G_OBJECT (play), gst_play_signals[PIPELINE_ERROR], 0, 
		               signal->signal_data.error.element, signal->signal_data.error.error);
		gst_object_unref (GST_OBJECT(signal->signal_data.error.element));
355 356 357 358 359 360 361
		break;
	default:
		break;
	}

	g_free(signal);
	queue_length = g_async_queue_length (play->signal_queue);
362
		
363 364 365 366 367 368 369 370 371 372 373
	return (queue_length > 0);
}

static gboolean
gst_play_idle_eos (GstPlay* play)
{
	g_signal_emit (G_OBJECT (play), gst_play_signals [STREAM_END], 0);
	return FALSE;
}

static void
374 375
callback_audio_sink_eos (	GstElement *element,
							GstPlay *play)
376 377 378 379 380
{
	play->idle_add_func ((GSourceFunc) gst_play_idle_eos, play);
}

static void
381 382 383
callback_video_have_xid (	GstElement *element,
							gint xid,
							GstPlay *play)
384 385
{
	GstPlaySignal *signal;
386
	
387 388 389
	signal = g_new0(GstPlaySignal, 1);
	signal->signal_id = HAVE_XID;
	signal->signal_data.video_xid.xid = xid;
390
	
391
	g_async_queue_push(play->signal_queue, signal);
392 393
	
	play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play);
394 395
}

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
static void
callback_video_have_vis_xid (	GstElement *element,
								gint xid,
								GstPlay *play)
{
	GstPlaySignal *signal;
	
	signal = g_new0(GstPlaySignal, 1);
	signal->signal_id = HAVE_VIS_XID;
	signal->signal_data.video_xid.xid = xid;
	
	g_async_queue_push(play->signal_queue, signal);
	
	play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play);
}

412
static void
413 414 415 416
callback_video_have_size (	GstElement *element,
							gint width,
							gint height,
							GstPlay *play)
417 418
{
	GstPlaySignal *signal;
419
	
420 421 422 423
	signal = g_new0(GstPlaySignal, 1);
	signal->signal_id = HAVE_VIDEO_SIZE;
	signal->signal_data.video_size.width = width;
	signal->signal_data.video_size.height = height;
424
	
425
	g_async_queue_push(play->signal_queue, signal);
426 427
	
	play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play);
428 429 430
}

static void 
431 432
callback_bin_pre_iterate (	GstBin *bin,
							GMutex *mutex)
433 434 435 436 437
{
	g_mutex_lock(mutex);
}

static void 
438 439
callback_bin_post_iterate (	GstBin *bin,
							GMutex *mutex)
440 441 442 443
{
	g_mutex_unlock(mutex);
}

444
static void
445 446
callback_pipeline_error (	GstElement *object,
							GstElement *orig,
447 448 449
							gchar *error,
							GstPlay* play)
{ 
450 451 452 453 454 455 456 457 458 459 460 461
	GstPlaySignal *signal;
	
	signal = g_new0(GstPlaySignal, 1);
	signal->signal_id = PIPELINE_ERROR;
	signal->signal_data.error.element = orig;
	signal->signal_data.error.error = error;
	
	gst_object_ref (GST_OBJECT(orig));
	
	g_async_queue_push(play->signal_queue, signal);
	
	play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play);
462
} 
463

464 465 466 467 468
static void
callback_pipeline_deep_notify (	GstElement *element,
								GstElement *orig,
								GParamSpec *param,
								GstPlay* play)
469
{
470
	GstPlaySignal *signal;
471
	
472 473 474 475
	signal = g_new0(GstPlaySignal, 1);
	signal->signal_id = INFORMATION;
	signal->signal_data.info.element = orig;
	signal->signal_data.info.param = param;
476 477

	gst_object_ref (GST_OBJECT(orig));
478
	
479 480 481
	g_async_queue_push(play->signal_queue, signal);
	
	play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play);
482 483
}

484 485 486 487 488
static void
callback_pipeline_state_change (	GstElement *element,
									GstElementState old,
									GstElementState state,
									GstPlay* play)
489
{
490 491
	GstPlaySignal *signal;

492 493
	g_return_if_fail (play != NULL);
	g_return_if_fail (element != NULL);
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
	g_return_if_fail (GST_IS_ELEMENT (element));
	g_return_if_fail (GST_IS_PLAY (play));
	g_return_if_fail (element == play->pipeline);

	/*g_print ("got state change %s to %s\n", gst_element_state_get_name (old), gst_element_state_get_name (state));*/

	/* do additional stuff depending on state */
	if (GST_IS_PIPELINE (play->pipeline)){
		switch (state) {
		case GST_STATE_PLAYING:
			play->idle_add_func (	(GSourceFunc) gst_play_idle_callback,
									play);
			play->timeout_add_func (	200,
										(GSourceFunc) gst_play_tick_callback,
										play);
			if (play->length_nanos == 0LL){
				/* try to get the length up to 16 times */
				play->get_length_attempt = 16;
				play->timeout_add_func (200, (GSourceFunc) gst_play_get_length_callback, play); 
			}
			break;
		default:
			break;
		}
	}	
	signal = g_new0(GstPlaySignal, 1);
	signal->signal_id = STATE_CHANGE;
	signal->signal_data.state.old_state = old;
	signal->signal_data.state.new_state = state;

	g_async_queue_push(play->signal_queue, signal);

	play->idle_add_func ((GSourceFunc) gst_play_idle_signal, play);
527 528
}

529 530 531 532 533 534 535 536 537
/* split static pipeline functions to a seperate file */
#include "playpipelines.c"

/* =========================================== */
/*                                             */
/*              Init & Class init              */
/*                                             */
/* =========================================== */

538
static void
539
gst_play_dispose (GObject *object)
540
{
541 542
	g_return_if_fail (object != NULL);
	g_return_if_fail (GST_IS_PLAY(object));
543 544
	GstPlay *play = GST_PLAY (object);

545 546 547 548 549 550
	/* Removing all sources */
	while (g_source_remove_by_user_data (play));
		
	G_OBJECT_CLASS (parent_class)->dispose (object);
	g_mutex_free(play->audio_bin_mutex);
	g_mutex_free(play->video_bin_mutex);
551 552 553
}

static void
554
gst_play_class_init (GstPlayClass *klass)
555
{
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  
	parent_class = g_type_class_ref(GST_TYPE_OBJECT);

	klass->information = NULL;
	klass->state_changed = NULL;
	klass->stream_end = NULL;
  
	gobject_class->dispose = gst_play_dispose;
	gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_play_set_property);
	gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_play_get_property);

	g_object_class_install_property (
			gobject_class,
			ARG_LOCATION,
			g_param_spec_string (
						"location",
						"location of file", 
						"location of the file to play",
						NULL, G_PARAM_READWRITE));
	
	g_object_class_install_property (
			gobject_class,
			ARG_VOLUME,
			g_param_spec_float (
						"volume",
						"Playing volume", 
			            "Playing volume", 
						0, 1.0, 0, G_PARAM_READWRITE));
						
	g_object_class_install_property (
			gobject_class,
			ARG_MUTE,
			g_param_spec_boolean (
						"mute",
						"Volume muted",
						"Playing volume muted",
						FALSE, G_PARAM_READWRITE));
  
	gst_play_signals [INFORMATION] = 
		g_signal_new ("information", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, information), 
			      NULL, NULL,
			      gst_marshal_VOID__OBJECT_PARAM, 
			      G_TYPE_NONE, 2, 
			      G_TYPE_OBJECT, G_TYPE_PARAM);
	
605 606 607 608 609 610 611 612 613 614
	gst_play_signals [PIPELINE_ERROR] = 
		g_signal_new ("pipeline_error", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, pipeline_error), 
			      NULL, NULL,
			      gst_marshal_VOID__OBJECT_PARAM, 
			      G_TYPE_NONE, 2, 
			      G_TYPE_OBJECT, G_TYPE_PARAM);
	
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
	gst_play_signals [STATE_CHANGE] = 
		g_signal_new ("state_change", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, state_changed), 
			      NULL, NULL,
			      gst_marshal_VOID__INT_INT,
			      G_TYPE_NONE, 2, 
			      G_TYPE_INT, G_TYPE_INT);
	
	gst_play_signals [STREAM_END] =
		g_signal_new ("stream_end",
			      G_TYPE_FROM_CLASS (klass),
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, stream_end),
			      NULL, NULL,
			      gst_marshal_VOID__VOID,
			      G_TYPE_NONE, 0);

	gst_play_signals [TIME_TICK] = 
		g_signal_new ("time_tick", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, time_tick), 
			      NULL, NULL,
			      gst_marshal_VOID__INT64,
			      G_TYPE_NONE, 1, 
			      G_TYPE_INT64);

	gst_play_signals [STREAM_LENGTH] = 
		g_signal_new ("stream_length", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, stream_length), 
			      NULL, NULL,
			      gst_marshal_VOID__INT64,
			      G_TYPE_NONE, 1, 
			      G_TYPE_INT64);

	gst_play_signals [HAVE_XID] = 
		g_signal_new ("have_xid", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, have_xid), 
			      NULL, NULL,
			      gst_marshal_VOID__INT,
			      G_TYPE_NONE, 1, 
			      G_TYPE_INT);
663 664 665 666 667 668 669 670 671 672
				  
	gst_play_signals [HAVE_VIS_XID] = 
		g_signal_new ("have_vis_xid", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, have_vis_xid), 
			      NULL, NULL,
			      gst_marshal_VOID__INT,
			      G_TYPE_NONE, 1, 
			      G_TYPE_INT);
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707

	gst_play_signals [HAVE_VIDEO_SIZE] = 
		g_signal_new ("have_video_size", 
			      G_TYPE_FROM_CLASS (klass), 
			      G_SIGNAL_RUN_FIRST,
			      G_STRUCT_OFFSET (GstPlayClass, have_video_size), 
			      NULL, NULL,
			      gst_marshal_VOID__INT_INT,
			      G_TYPE_NONE, 2, 
			      G_TYPE_INT, G_TYPE_INT);

	gst_control_init(NULL,NULL);
}



static void 
gst_play_init (GstPlay *play) 
{
	play->pipeline				= NULL;
	play->source				= NULL;
	play->autoplugger			= NULL;
	play->audio_sink			= NULL;
	play->audio_sink_element	= NULL;
	play->video_sink			= NULL;
	play->video_sink_element	= NULL;
	play->volume				= NULL;
	play->other_elements		= g_hash_table_new(g_str_hash, g_str_equal);
	play->audio_bin_mutex		= g_mutex_new();
	play->video_bin_mutex		= g_mutex_new();
	
	gst_play_set_idle_timeout_funcs(	play,
										gst_play_default_timeout_add,
										gst_play_default_idle_add);
}
708

709 710 711 712 713
/* ============================================================= */
/*                                                               */
/*                       Public Methods                          */
/*                                                               */
/* ============================================================= */
714

715 716 717 718 719
/* =========================================== */
/*                                             */
/*                   Toolbox                   */
/*                                             */
/* =========================================== */
720

721 722 723 724 725 726 727
/**
 * gst_play_seek_to_time:
 * @play: a #GstPlay.
 * @time_nanos: a #gint64 indicating a time position.
 *
 * Performs a seek on @play until @time_nanos.
 */
728
void
729 730
gst_play_seek_to_time (	GstPlay *play,
						gint64 time_nanos)
731 732
{
	GstEvent *s_event;
733
        guint8   prev_state;
734 735
	gboolean audio_seek_worked = FALSE;
	gboolean video_seek_worked = FALSE;
736
	gboolean visualisation_seek_worked = FALSE;
737

738
	g_return_if_fail (play != NULL);
739 740 741 742 743 744 745 746 747 748 749 750
	g_return_if_fail (GST_IS_PLAY (play));
	if (time_nanos < 0LL){
		play->seek_time = 0LL;
	}
	else if (time_nanos < 0LL){
		play->seek_time = play->length_nanos;
	}
	else {
		play->seek_time = time_nanos;
	}

	/*g_print("doing seek to %lld\n", play->seek_time);*/
751
        prev_state = GST_STATE(play->pipeline);
752 753 754 755 756 757 758
	gst_element_set_state(play->pipeline, GST_STATE_PAUSED);

	s_event = gst_event_new_seek (GST_FORMAT_TIME |
	                              GST_SEEK_METHOD_SET |
	                              GST_SEEK_FLAG_FLUSH, play->seek_time);
	if (play->audio_sink_element != NULL){
		gst_event_ref (s_event);
759 760 761 762 763 764 765
		audio_seek_worked = gst_element_send_event (
										play->audio_sink_element, s_event);
	}
	if (play->visualisation_sink_element != NULL){
		gst_event_ref (s_event);
		visualisation_seek_worked = gst_element_send_event (
										play->visualisation_sink_element, s_event);
766 767 768
	}
	if (play->video_sink_element != NULL){
		gst_event_ref (s_event);
769 770
		video_seek_worked = gst_element_send_event (
										play->video_sink_element, s_event);
771 772 773 774 775 776 777
	}
	gst_event_unref (s_event);

	if (audio_seek_worked || video_seek_worked){
		play->time_nanos = gst_clock_get_time(play->clock);
		g_signal_emit (G_OBJECT (play), gst_play_signals [TIME_TICK], 0, play->time_nanos);
	}
778
	gst_element_set_state(play->pipeline, prev_state);
779 780
}

781 782 783 784 785 786
/**
 * gst_play_need_new_video_window:
 * @play: a #GstPlay.
 *
 * Request a new video window for @play.
 */
787
void
788
gst_play_need_new_video_window (GstPlay *play)
789
{
790
	g_return_if_fail (play != NULL);
791 792
	g_return_if_fail (GST_IS_PLAY (play));
	if (GST_IS_ELEMENT(play->video_sink_element)){
793 794
		g_object_set(	G_OBJECT(play->video_sink_element),
						"need_new_window", TRUE, NULL);
795
	}
796 797 798 799
	if (GST_IS_ELEMENT(play->visualisation_sink_element)){
		g_object_set(	G_OBJECT(play->visualisation_sink_element),
						"need_new_window", TRUE, NULL);
	}
800 801 802
}

void
803 804 805
gst_play_set_idle_timeout_funcs (	GstPlay *play,
									GstPlayTimeoutAdd timeout_add_func,
									GstPlayIdleAdd idle_add_func)
806
{
807
	g_return_if_fail (play != NULL);
808 809 810 811 812
	g_return_if_fail (GST_IS_PLAY (play));
	play->timeout_add_func = timeout_add_func;
	play->idle_add_func = idle_add_func;
}

813 814 815 816
/**
 * gst_play_get_sink_element:
 * @play: a #GstPlay.
 * @element: a #GstElement.
817
 * @sink_type: a #GstPlaySinkType.
818
 *
819 820
 * Searches recursively for a sink #GstElement with
 * type @sink_type in @element which is supposed to be a #GstBin.
821 822 823
 *
 * Returns: the sink #GstElement of @element.
 */
824
GstElement*
825
gst_play_get_sink_element (	GstPlay *play,
826 827
							GstElement *element,
							GstPlaySinkType sink_type)
828
{
829 830
	GList *elements = NULL;
	const GList *pads = NULL;
831
	gboolean has_src, has_correct_type;
832

833 834
	g_return_val_if_fail (play != NULL, NULL);
	g_return_val_if_fail (element != NULL, NULL);
835 836 837 838 839 840 841 842
	g_return_val_if_fail (GST_IS_PLAY (play), NULL);
	g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);

	if (!GST_IS_BIN(element)){
		/* since its not a bin, we'll presume this 
		 * element is a sink element */		
		return element;
	}
843
	
844
	elements = (GList *) gst_bin_get_list (GST_BIN(element));
845
	
846
	/* traverse all elements looking for a src pad */
847 848 849
	
	while (elements) {
		
850
		element = GST_ELEMENT (elements->data);
851 852 853 854 855 856 857
		
		/* Recursivity :) */
		
		if (GST_IS_BIN(element)) {
			element = gst_play_get_sink_element(play,element,sink_type);
			if (GST_IS_ELEMENT (element)) {
				return element;
858 859
			}
		}
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
		else {
		
			pads = gst_element_get_pad_list (element);
			has_src = FALSE;
			has_correct_type = FALSE;
			while (pads) {
				/* check for src pad */
				if (GST_PAD_DIRECTION (GST_PAD (pads->data)) == GST_PAD_SRC) {
					has_src = TRUE;
					break;
				}
				else {
					/* If not a src pad checking caps */
					GstCaps *caps;
					caps = gst_pad_get_caps (GST_PAD (pads->data));
					while (caps) {
						gboolean has_video_cap = FALSE, has_audio_cap = FALSE;
						if (g_ascii_strcasecmp(	gst_caps_get_mime (caps),
														"audio/raw") == 0)
						{
							has_audio_cap = TRUE;
						}
						if (g_ascii_strcasecmp(	gst_caps_get_mime (caps),
														"video/raw") == 0)
						{
							has_video_cap = TRUE;
						}
					
						switch (sink_type) {
							case GST_PLAY_SINK_TYPE_AUDIO:
								if (has_audio_cap)
									has_correct_type = TRUE;
								break;;
							case GST_PLAY_SINK_TYPE_VIDEO:
								if (has_video_cap)
									has_correct_type = TRUE;
								break;;
							case GST_PLAY_SINK_TYPE_ANY:
								if ( (has_video_cap) || (has_audio_cap) )
									has_correct_type = TRUE;
								break;;
							default:
								has_correct_type = FALSE;
						}
						caps = caps->next;
					}
				}
				pads = g_list_next (pads);
			}
			if ( (!has_src) && (has_correct_type) ){
				return element;
			}
912 913 914 915 916 917 918
		}
		elements = g_list_next (elements);
	}
	/* we didn't find a sink element */
	return NULL;
}

919 920 921 922 923
/* =========================================== */
/*                                             */
/*      State, Mute, Volume, Location          */
/*                                             */
/* =========================================== */
924

925 926 927 928 929 930 931 932 933
/**
 * gst_play_set_state:
 * @play: a #GstPlay.
 * @state: a #GstElementState.
 *
 * Set state of @play 's pipeline to @state.
 *
 * Returns: a #GstElementStateReturn indicating if the operation succeeded.
 */
934
GstElementStateReturn
935 936
gst_play_set_state (	GstPlay *play,
						GstElementState state)
937
{
938
	g_return_val_if_fail (play != NULL, GST_STATE_FAILURE);
939 940 941 942 943 944
	g_return_val_if_fail (GST_IS_PLAY (play), GST_STATE_FAILURE);
	g_return_val_if_fail (GST_IS_ELEMENT(play->pipeline), GST_STATE_FAILURE);

	return gst_element_set_state(play->pipeline, state);
}

945 946 947 948 949 950 951 952
/**
 * gst_play_get_state:
 * @play: a #GstPlay.
 *
 * Get state of @play 's pipeline.
 *
 * Returns: a #GstElementState indicating @play 's pipeline current state.
 */
953 954 955
GstElementState
gst_play_get_state (GstPlay *play)
{
956
	g_return_val_if_fail (play != NULL, GST_STATE_FAILURE);
957 958 959 960 961 962
	g_return_val_if_fail (GST_IS_PLAY (play), GST_STATE_FAILURE);
	g_return_val_if_fail (play->pipeline, GST_STATE_FAILURE);

	return gst_element_get_state(play->pipeline);
}

963 964 965 966 967 968 969 970 971
/**
 * gst_play_set_location:
 * @play: a #GstPlay.
 * @location: a const #gchar indicating location to play
 *
 * Set location of @play to @location.
 *
 * Returns: TRUE if location was set successfully.
 */
972
gboolean
973 974
gst_play_set_location (	GstPlay *play,
						const gchar *location)
975 976
{
	GstElementState current_state;
977
	g_return_val_if_fail (play != NULL, FALSE);
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
	g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
	g_return_val_if_fail (location != NULL, FALSE);

	current_state = gst_play_get_state (play);
	if (current_state != GST_STATE_READY){
		gst_play_set_state (play, GST_STATE_READY);
	}

	if (play->set_autoplugger){
		if (! play->set_autoplugger(play, gst_element_factory_make ("spider", "autoplugger"))){
			g_warning ("couldn't replace autoplugger\n");
			return FALSE;
		}
	}

	/* FIXME check for valid location (somehow) */
	g_object_set (G_OBJECT (play->source), "location", location, NULL);

	/* reset time/length values */
	play->time_seconds = 0;
	play->length_nanos = 0LL;
	play->time_nanos = 0LL;
	g_signal_emit (G_OBJECT (play), gst_play_signals [STREAM_LENGTH], 0, 0LL);
	g_signal_emit (G_OBJECT (play), gst_play_signals [TIME_TICK], 0, 0LL);
	play->need_stream_length = TRUE;

	return TRUE;
}

1007 1008 1009 1010 1011 1012 1013 1014
/**
 * gst_play_get_location:
 * @play: a #GstPlay.
 *
 * Get current location of @play.
 *
 * Returns: a #gchar pointer to current location.
 */
1015 1016 1017 1018
gchar*
gst_play_get_location (GstPlay *play)
{
	gchar* location;
1019
	g_return_val_if_fail (play != NULL, NULL);
1020 1021 1022 1023 1024 1025
	g_return_val_if_fail (GST_IS_PLAY (play), NULL);
	g_return_val_if_fail (GST_IS_ELEMENT(play->source), NULL);
	g_object_get (G_OBJECT (play->source), "location", &location, NULL);
	return location;
}

1026 1027 1028 1029 1030 1031 1032
/**
 * gst_play_set_volume:
 * @play: a #GstPlay.
 * @volume: a #gfloat indicating volume level.
 *
 * Set current volume of @play.
 */
1033
void
1034 1035
gst_play_set_volume (	GstPlay *play,
						gfloat volume)
1036
{
1037
	g_return_if_fail (play != NULL);
1038 1039 1040 1041 1042
	g_return_if_fail (GST_IS_PLAY (play));

	g_object_set(G_OBJECT(play->vol_dparam), "value_float", volume, NULL);
}

1043 1044 1045 1046 1047 1048 1049 1050
/**
 * gst_play_get_volume:
 * @play: a #GstPlay.
 *
 * Get current volume of @play.
 *
 * Returns: a #gfloat indicating current volume level.
 */
1051 1052 1053 1054 1055
gfloat
gst_play_get_volume (GstPlay *play)
{
	gfloat volume;

1056
	g_return_val_if_fail (play != NULL, 0);
1057 1058 1059 1060 1061 1062 1063
	g_return_val_if_fail (GST_IS_PLAY (play), 0);

	g_object_get(G_OBJECT(play->vol_dparam), "value_float", &volume, NULL);

	return volume;
}

1064 1065 1066 1067 1068 1069 1070
/**
 * gst_play_set_mute:
 * @play: a #GstPlay.
 * @mute: a #gboolean indicating wether audio is muted or not.
 *
 * Mutes/Unmutes audio playback of @play.
 */
1071
void
1072 1073
gst_play_set_mute (	GstPlay *play,
					gboolean mute)
1074
{
1075
	g_return_if_fail (play != NULL);
1076 1077 1078 1079
	g_return_if_fail (GST_IS_PLAY (play));

	g_object_set (G_OBJECT (play->volume), "mute", mute, NULL);
}
1080 1081 1082 1083 1084 1085 1086 1087 1088

/**
 * gst_play_get_mute:
 * @play: a #GstPlay.
 *
 * Get current muted status of @play.
 *
 * Returns: a #gboolean indicating if audio is muted or not.
 */
1089 1090 1091 1092 1093
gboolean
gst_play_get_mute (GstPlay *play)
{
	gboolean mute;

1094
	g_return_val_if_fail (play != NULL, 0);
1095 1096 1097 1098 1099 1100 1101
	g_return_val_if_fail (GST_IS_PLAY (play), 0);

	g_object_get (G_OBJECT (play->volume), "mute", &mute, NULL);

	return mute;
}

1102 1103 1104 1105 1106 1107
/* =========================================== */
/*                                             */
/*    Audio sink, Video sink, Data src         */
/*                                             */
/* =========================================== */

1108 1109 1110 1111 1112 1113 1114 1115 1116
/**
 * gst_play_set_data_src:
 * @play: a #GstPlay.
 * @data_src: a #GstElement.
 *
 * Set @data_src as the source element of @play.
 *
 * Returns: TRUE if call succeeded.
 */
1117 1118 1119 1120
gboolean
gst_play_set_data_src (	GstPlay *play,
						GstElement *data_src)
{
1121 1122
	g_return_val_if_fail (play != NULL, FALSE);
	g_return_val_if_fail (data_src != NULL, FALSE);
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
	g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
	g_return_val_if_fail (GST_IS_ELEMENT (data_src), FALSE);

	if (gst_play_get_state (play) != GST_STATE_READY){
		gst_play_set_state (play, GST_STATE_READY);
	}

	if (play->set_data_src){
		return play->set_data_src(play, data_src);
	}

	/* if there is no set_data_src func, fail quietly */
	return FALSE;
}

1138 1139 1140 1141 1142 1143 1144 1145 1146
/**
 * gst_play_set_video_sink:
 * @play: a #GstPlay.
 * @video_sink: a #GstElement.
 *
 * Set @video_sink as the video sink element of @play.
 *
 * Returns: TRUE if call succeeded.
 */
1147 1148 1149 1150
gboolean
gst_play_set_video_sink (	GstPlay *play,
							GstElement *video_sink)
{
1151 1152
	g_return_val_if_fail (play != NULL, FALSE);
	g_return_val_if_fail (video_sink != NULL, FALSE);
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
	g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
	g_return_val_if_fail (GST_IS_ELEMENT (video_sink), FALSE);

	if (gst_play_get_state (play) != GST_STATE_READY){
		gst_play_set_state (play, GST_STATE_READY);
	}

	if (play->set_video_sink){
		return play->set_video_sink(play, video_sink);
	}

	/* if there is no set_video_sink func, fail quietly */
	return FALSE;
}

1168 1169 1170 1171 1172 1173 1174 1175 1176
/**
 * gst_play_set_audio_sink:
 * @play: a #GstPlay.
 * @audio_sink: a #GstElement.
 *
 * Set @audio_sink as the audio sink element of @play.
 *
 * Returns: TRUE if call succeeded.
 */
1177 1178 1179 1180
gboolean
gst_play_set_audio_sink (	GstPlay *play,
							GstElement *audio_sink)
{
1181 1182
	g_return_val_if_fail (play != NULL, FALSE);
	g_return_val_if_fail (audio_sink != NULL, FALSE);
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
	g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
	g_return_val_if_fail (GST_IS_ELEMENT (audio_sink), FALSE);

	if (gst_play_get_state (play) != GST_STATE_READY){
		gst_play_set_state (play, GST_STATE_READY);
	}

	if (play->set_audio_sink){
		return play->set_audio_sink(play, audio_sink);
	}

	/* if there is no set_audio_sink func, fail quietly */
	return FALSE;
}

/* =========================================== */
/*                                             */
/*          Object typing & Creation           */
/*                                             */
/* =========================================== */

GType
gst_play_get_type (void)
{
	static GType play_type = 0;
	
	if (!play_type)
	{
		static const GTypeInfo play_info = {
			sizeof (GstPlayClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) gst_play_class_init,
			NULL, NULL, sizeof (GstPlay),
			0, (GInstanceInitFunc) gst_play_init,
			NULL
		};
      
		play_type = g_type_register_static (G_TYPE_OBJECT, "GstPlay", &play_info, 0);
	}

	return play_type;
}


GstPlay *
gst_play_new (	GstPlayPipeType pipe_type,
				GError **error)
{
	GstPlay *play;

	play = g_object_new (GST_TYPE_PLAY, NULL);

	/* FIXME: looks like only VIDEO ever gets used ! */
	switch (pipe_type){
		case GST_PLAY_PIPE_VIDEO:
			play->setup_pipeline = gst_play_video_setup;
			play->teardown_pipeline = NULL;
			play->set_data_src = gst_play_video_set_data_src;
			play->set_autoplugger = gst_play_video_set_auto;
			play->set_video_sink = gst_play_video_set_video;
			play->set_audio_sink = gst_play_video_set_audio;
			break;
1246 1247 1248 1249 1250 1251 1252 1253
		case GST_PLAY_PIPE_VIDEO_VISUALISATION:
			play->setup_pipeline = gst_play_video_vis_setup;
			play->teardown_pipeline = NULL;
			play->set_data_src = gst_play_video_set_data_src;
			play->set_autoplugger = gst_play_video_set_auto;
			play->set_video_sink = gst_play_video_vis_set_video;
			play->set_audio_sink = gst_play_video_vis_set_audio;
			break;
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276