4 #include <gtk/gtkobject.h>
5 #include <gtk/gtksignal.h>
6 #include <gtk/gtksocket.h>
7 #include <gtk/gtkmain.h>
10 #include "gstplayprivate.h"
12 static void gst_play_class_init (GstPlayClass *klass);
13 static void gst_play_init (GstPlay *play);
15 static void gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id);
16 static void gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id);
18 static void gst_play_realize (GtkWidget *play);
20 static void gst_play_frame_displayed (GstElement *element, GstPlay *play);
21 static void gst_play_have_size (GstElement *element, guint width, guint height, GstPlay *play);
22 static void gst_play_audio_handoff (GstElement *element, GstPlay *play);
24 /* signals and args */
27 SIGNAL_FRAME_DISPLAYED,
40 ARG_MEDIA_CURRENT_TIME,
43 static GtkObject *parent_class = NULL;
44 static guint gst_play_signals[LAST_SIGNAL] = {0};
47 gst_play_get_type (void)
49 static GtkType play_type = 0;
52 static const GtkTypeInfo play_info = {
55 sizeof (GstPlayClass),
56 (GtkClassInitFunc) gst_play_class_init,
57 (GtkObjectInitFunc) gst_play_init,
60 (GtkClassInitFunc)NULL,
62 play_type = gtk_type_unique (gtk_hbox_get_type (), &play_info);
68 gst_play_class_init (GstPlayClass *klass)
70 GtkObjectClass *object_class;
71 GtkWidgetClass *widget_class;
73 parent_class = gtk_type_class (gtk_hbox_get_type ());
75 object_class = (GtkObjectClass*)klass;
76 widget_class = (GtkWidgetClass*)klass;
78 gst_play_signals[SIGNAL_STATE_CHANGED] =
79 gtk_signal_new ("playing_state_changed", GTK_RUN_FIRST,
80 G_TYPE_FROM_CLASS (object_class),
81 GTK_SIGNAL_OFFSET (GstPlayClass, state_changed),
82 gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1,
85 gst_play_signals[SIGNAL_FRAME_DISPLAYED] =
86 gtk_signal_new ("frame_displayed",GTK_RUN_FIRST, G_TYPE_FROM_CLASS (object_class),
87 GTK_SIGNAL_OFFSET (GstPlayClass, frame_displayed),
88 gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
90 gst_play_signals[SIGNAL_AUDIO_PLAYED] =
91 gtk_signal_new ("audio_played",GTK_RUN_FIRST, G_TYPE_FROM_CLASS (object_class),
92 GTK_SIGNAL_OFFSET (GstPlayClass, audio_played),
93 gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
96 gtk_object_class_add_signals (object_class, gst_play_signals, LAST_SIGNAL);
99 gtk_object_add_arg_type ("GstPlay::uri", GTK_TYPE_STRING,
100 GTK_ARG_READABLE, ARG_URI);
101 gtk_object_add_arg_type ("GstPlay::mute", GTK_TYPE_BOOL,
102 GTK_ARG_READWRITE, ARG_MUTE);
103 gtk_object_add_arg_type ("GstPlay::state", GTK_TYPE_INT,
104 GTK_ARG_READABLE, ARG_STATE);
106 gtk_object_add_arg_type ("GstPlay::media_size", GTK_TYPE_UINT,
107 GTK_ARG_READABLE, ARG_MEDIA_SIZE);
108 gtk_object_add_arg_type ("GstPlay::media_offset", GTK_TYPE_UINT,
109 GTK_ARG_READABLE, ARG_MEDIA_OFFSET);
110 gtk_object_add_arg_type ("GstPlay::media_total_time", GTK_TYPE_UINT,
111 GTK_ARG_READABLE, ARG_MEDIA_TOTAL_TIME);
112 gtk_object_add_arg_type ("GstPlay::media_current_time", GTK_TYPE_UINT,
113 GTK_ARG_READABLE, ARG_MEDIA_CURRENT_TIME);
115 gtk_object_add_arg_type ("GstPlay::media_size", GTK_TYPE_ULONG,
116 GTK_ARG_READABLE, ARG_MEDIA_SIZE);
117 gtk_object_add_arg_type ("GstPlay::media_offset", GTK_TYPE_ULONG,
118 GTK_ARG_READABLE, ARG_MEDIA_OFFSET);
119 gtk_object_add_arg_type ("GstPlay::media_total_time", GTK_TYPE_ULONG,
120 GTK_ARG_READABLE, ARG_MEDIA_TOTAL_TIME);
121 gtk_object_add_arg_type ("GstPlay::media_current_time", GTK_TYPE_ULONG,
122 GTK_ARG_READABLE, ARG_MEDIA_CURRENT_TIME);
125 object_class->set_arg = gst_play_set_arg;
126 object_class->get_arg = gst_play_get_arg;
128 widget_class->realize = gst_play_realize;
133 gst_play_init (GstPlay *play)
135 GstPlayPrivate *priv = g_new0 (GstPlayPrivate, 1);
136 GstElement *colorspace;
140 /* create a new bin to hold the elements */
141 priv->pipeline = gst_pipeline_new ("main_pipeline");
142 g_assert (priv->pipeline != NULL);
144 priv->audio_element = gst_elementfactory_make ("osssink", "play_audio");
145 g_return_if_fail (priv->audio_element != NULL);
146 g_signal_connect (G_OBJECT (priv->audio_element), "handoff",
147 G_CALLBACK (gst_play_audio_handoff), play);
149 priv->video_element = gst_elementfactory_make ("bin", "video_bin");
151 priv->video_show = gst_elementfactory_make ("xvideosink", "show");
152 g_return_if_fail (priv->video_show != NULL);
153 //gtk_object_set (GTK_OBJECT (priv->video_element), "xv_enabled", FALSE, NULL);
154 g_signal_connect (G_OBJECT (priv->video_show), "frame_displayed",
155 G_CALLBACK (gst_play_frame_displayed), play);
156 g_signal_connect (G_OBJECT (priv->video_show), "have_size",
157 G_CALLBACK (gst_play_have_size), play);
159 gst_bin_add (GST_BIN (priv->video_element), priv->video_show);
161 colorspace = gst_elementfactory_make ("colorspace", "colorspace");
162 if (colorspace == NULL) {
163 g_warning ("could not create the 'colorspace' element, doing without");
164 gst_element_add_ghost_pad (priv->video_element,
165 gst_element_get_pad (priv->video_show, "sink"),
169 GST_FLAG_SET (priv->video_element, GST_ELEMENT_THREAD_SUGGESTED);
170 gst_bin_add (GST_BIN (priv->video_element), colorspace);
171 gst_element_connect (colorspace, "src", priv->video_show, "sink");
172 gst_element_add_ghost_pad (priv->video_element,
173 gst_element_get_pad (colorspace, "sink"),
177 play->state = GST_PLAY_STOPPED;
182 priv->can_seek = TRUE;
184 priv->offset_element = NULL;
185 priv->bit_rate_element = NULL;
186 priv->media_time_element = NULL;
188 priv->source_width = 0;
189 priv->source_height = 0;
195 return GST_PLAY (gtk_type_new (GST_TYPE_PLAY));
199 gst_play_idle_func (gpointer data)
203 busy = gst_bin_iterate (GST_BIN (data));
209 gst_play_eos (GstElement *element,
212 GST_DEBUG(0, "gstplay: eos reached\n");
213 gst_play_stop (play);
217 gst_play_have_size (GstElement *element, guint width, guint height,
220 GstPlayPrivate *priv;
222 priv = (GstPlayPrivate *) play->priv;
224 priv->source_width = width;
225 priv->source_height = height;
227 gtk_widget_set_usize (priv->video_widget, width, height);
231 gst_play_frame_displayed (GstElement *element, GstPlay *play)
233 GstPlayPrivate *priv;
234 static int stolen = FALSE;
236 priv = (GstPlayPrivate *)play->priv;
238 gdk_threads_enter ();
240 gtk_widget_realize (priv->video_widget);
241 gtk_socket_steal (GTK_SOCKET (priv->video_widget),
242 gst_util_get_int_arg (G_OBJECT (priv->video_show), "xid"));
243 gtk_widget_show (priv->video_widget);
246 gdk_threads_leave ();
248 gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_FRAME_DISPLAYED],
253 gst_play_audio_handoff (GstElement *element, GstPlay *play)
255 gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_AUDIO_PLAYED],
261 gst_play_object_introspect (GstObject *object, const gchar *property, GstElement **target)
266 if (!GST_IS_ELEMENT (object) && !GST_IS_BIN (object))
269 element = GST_ELEMENT (object);
271 #warning this looks grim, did I port it right ?
272 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), property);
276 GST_DEBUG(0, "gstplay: using element \"%s\" for %s property\n",
277 gst_element_get_name(element), property);
282 gst_play_object_introspect (GstObject *object, const gchar *property, GstElement **target)
288 if (!GST_IS_ELEMENT (object) && !GST_IS_BIN (object))
291 element = GST_ELEMENT (object);
293 info = gtk_object_arg_get_info (GTK_OBJECT_TYPE (element), property, &arg);
300 GST_DEBUG(0, "gstplay: using element \"%s\" for %s property\n",
301 gst_element_get_name(element), property);
306 /* Dumb introspection of the interface...
307 * this will change with glib 1.4
310 gst_play_object_added (GstAutoplug* autoplug, GstObject *object, GstPlay *play)
312 GstPlayPrivate *priv;
314 g_return_if_fail (play != NULL);
316 priv = (GstPlayPrivate *)play->priv;
318 if (GST_FLAG_IS_SET (object, GST_ELEMENT_NO_SEEK)) {
319 priv->can_seek = FALSE;
322 // first come first serve here...
323 if (!priv->offset_element)
324 gst_play_object_introspect (object, "offset", &priv->offset_element);
325 if (!priv->bit_rate_element)
326 gst_play_object_introspect (object, "bit_rate", &priv->bit_rate_element);
327 if (!priv->media_time_element)
328 gst_play_object_introspect (object, "media_time", &priv->media_time_element);
329 if (!priv->current_time_element)
330 gst_play_object_introspect (object, "current_time", &priv->current_time_element);
335 gst_play_cache_empty (GstElement *element, GstPlay *play)
337 GstPlayPrivate *priv;
338 GstElement *new_element;
340 priv = (GstPlayPrivate *)play->priv;
342 gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
344 new_element = gst_bin_get_by_name (GST_BIN (priv->pipeline), "new_element");
346 gst_element_disconnect (priv->src, "src", priv->cache, "sink");
347 gst_element_disconnect (priv->cache, "src", new_element, "sink");
348 gst_bin_remove (GST_BIN (priv->pipeline), priv->cache);
349 gst_element_connect (priv->src, "src", new_element, "sink");
351 gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
355 gst_play_have_type (GstElement *sink, GstCaps *caps, GstPlay *play)
357 GstPlayPrivate *priv;
358 GstElement *new_element;
359 GstAutoplug *autoplug;
361 GST_DEBUG (0,"GstPipeline: play have type\n");
363 priv = (GstPlayPrivate *)play->priv;
365 gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
367 gst_element_disconnect (priv->cache, "src", priv->typefind, "sink");
368 gst_bin_remove (GST_BIN (priv->pipeline), priv->typefind);
370 autoplug = gst_autoplugfactory_make ("staticrender");
371 g_assert (autoplug != NULL);
373 g_signal_connect (G_OBJECT (autoplug), "new_object",
374 G_CALLBACK (gst_play_object_added), play);
376 new_element = gst_autoplug_to_renderers (autoplug,
383 // FIXME, signal a suitable error
387 gst_element_set_name (new_element, "new_element");
389 gst_bin_add (GST_BIN (priv->pipeline), new_element);
391 g_object_set (G_OBJECT (priv->cache), "reset", TRUE, NULL);
393 gst_element_connect (priv->cache, "src", new_element, "sink");
395 g_signal_connect (G_OBJECT (priv->pipeline), "eos", G_CALLBACK (gst_play_eos), play);
397 gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
401 connect_pads (GstElement *new_element, GstElement *target, gboolean add)
403 GList *pads = gst_element_get_pad_list (new_element);
404 GstPad *targetpad = gst_element_get_pad (target, "sink");
407 GstPad *pad = GST_PAD (pads->data);
409 if (gst_pad_check_compatibility (pad, targetpad)) {
411 gst_bin_add (GST_BIN (gst_element_get_parent (
412 GST_ELEMENT (gst_pad_get_real_parent (pad)))),
415 gst_pad_connect (pad, targetpad);
418 pads = g_list_next (pads);
424 gst_play_set_uri (GstPlay *play, const guchar *uri)
427 GstPlayPrivate *priv;
429 g_return_val_if_fail (play != NULL, GST_PLAY_ERROR);
430 g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR);
431 g_return_val_if_fail (uri != NULL, GST_PLAY_ERROR);
433 priv = (GstPlayPrivate *)play->priv;
438 /* see if it looks like an URI */
439 if ((uriloc = strstr (uri, ":/"))) {
440 priv->src = gst_elementfactory_make ("gnomevfssrc", "srcelement");
443 if (strstr (uri, "file:/")) {
444 uri += strlen ("file:/");
447 return GST_PLAY_CANNOT_PLAY;
451 if (priv->src == NULL) {
452 priv->src = gst_elementfactory_make ("filesrc", "srcelement");
455 priv->uri = g_strdup (uri);
457 //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
458 priv->offset_element = priv->src;
459 g_return_val_if_fail (priv->src != NULL, GST_PLAY_CANNOT_PLAY);
461 g_object_set (G_OBJECT (priv->src), "location", priv->uri, NULL);
463 priv->cache = gst_elementfactory_make ("autoplugcache", "cache");
464 g_return_val_if_fail (priv->cache != NULL, GST_PLAY_CANNOT_PLAY);
466 g_signal_connect (G_OBJECT (priv->cache), "cache_empty",
467 G_CALLBACK (gst_play_cache_empty), play);
469 priv->typefind = gst_elementfactory_make ("typefind", "typefind");
470 g_return_val_if_fail (priv->typefind != NULL, GST_PLAY_CANNOT_PLAY);
471 g_signal_connect (G_OBJECT (priv->typefind), "have_type",
472 G_CALLBACK (gst_play_have_type), play);
475 gst_bin_add (GST_BIN (priv->pipeline), priv->src);
476 gst_bin_add (GST_BIN (priv->pipeline), priv->cache);
477 gst_bin_add (GST_BIN (priv->pipeline), priv->typefind);
479 gst_element_connect (priv->src, "src", priv->cache, "sink");
480 gst_element_connect (priv->cache, "src", priv->typefind, "sink");
486 gst_play_realize (GtkWidget *widget)
489 GstPlayPrivate *priv;
491 g_return_if_fail (GST_IS_PLAY (widget));
493 //g_print ("realize\n");
495 play = GST_PLAY (widget);
496 priv = (GstPlayPrivate *)play->priv;
498 priv->video_widget = gtk_socket_new ();
500 gtk_container_add (GTK_CONTAINER (widget), priv->video_widget);
502 if (GTK_WIDGET_CLASS (parent_class)->realize) {
503 GTK_WIDGET_CLASS (parent_class)->realize (widget);
506 //gtk_socket_steal (GTK_SOCKET (priv->video_widget),
507 // gst_util_get_int_arg (GTK_OBJECT(priv->video_element), "xid"));
509 //gtk_widget_realize (priv->video_widget);
510 //gtk_socket_steal (GTK_SOCKET (priv->video_widget),
511 // gst_util_get_int_arg (GTK_OBJECT(priv->video_element), "xid"));
515 gst_play_play (GstPlay *play)
517 GstPlayPrivate *priv;
519 g_return_if_fail (play != NULL);
520 g_return_if_fail (GST_IS_PLAY (play));
522 priv = (GstPlayPrivate *)play->priv;
524 if (play->state == GST_PLAY_PLAYING) return;
526 if (play->state == GST_PLAY_STOPPED)
527 gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
528 gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PLAYING);
530 play->state = GST_PLAY_PLAYING;
531 gtk_idle_add (gst_play_idle_func, priv->pipeline);
533 gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
538 gst_play_pause (GstPlay *play)
540 GstPlayPrivate *priv;
542 g_return_if_fail (play != NULL);
543 g_return_if_fail (GST_IS_PLAY (play));
545 priv = (GstPlayPrivate *)play->priv;
547 if (play->state != GST_PLAY_PLAYING) return;
549 gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PAUSED);
551 play->state = GST_PLAY_PAUSED;
552 g_idle_remove_by_data (priv->pipeline);
554 gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
559 gst_play_stop (GstPlay *play)
561 GstPlayPrivate *priv;
563 g_return_if_fail (play != NULL);
564 g_return_if_fail (GST_IS_PLAY (play));
566 priv = (GstPlayPrivate *)play->priv;
568 if (play->state == GST_PLAY_STOPPED) return;
570 // FIXME until state changes are handled properly
571 gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_READY);
572 gtk_object_set (GTK_OBJECT (priv->src), "offset", 0, NULL);
573 //gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_NULL);
575 play->state = GST_PLAY_STOPPED;
576 g_idle_remove_by_data (priv->pipeline);
578 gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
583 gst_play_get_video_widget (GstPlay *play)
585 GstPlayPrivate *priv;
587 g_return_val_if_fail (play != NULL, 0);
588 g_return_val_if_fail (GST_IS_PLAY (play), 0);
590 priv = (GstPlayPrivate *)play->priv;
592 return priv->video_widget;
596 gst_play_get_source_width (GstPlay *play)
598 GstPlayPrivate *priv;
600 g_return_val_if_fail (play != NULL, 0);
601 g_return_val_if_fail (GST_IS_PLAY (play), 0);
603 priv = (GstPlayPrivate *)play->priv;
605 return priv->source_width;
609 gst_play_get_source_height (GstPlay *play)
611 GstPlayPrivate *priv;
613 g_return_val_if_fail (play != NULL, 0);
614 g_return_val_if_fail (GST_IS_PLAY (play), 0);
616 priv = (GstPlayPrivate *)play->priv;
618 return priv->source_height;
622 gst_play_get_media_size (GstPlay *play)
624 GstPlayPrivate *priv;
626 g_return_val_if_fail (play != NULL, 0);
627 g_return_val_if_fail (GST_IS_PLAY (play), 0);
629 priv = (GstPlayPrivate *)play->priv;
631 return gst_util_get_long_arg (G_OBJECT (priv->src), "filesize");
635 gst_play_get_media_offset (GstPlay *play)
637 GstPlayPrivate *priv;
639 g_return_val_if_fail (play != NULL, 0);
640 g_return_val_if_fail (GST_IS_PLAY (play), 0);
642 priv = (GstPlayPrivate *)play->priv;
644 if (priv->offset_element)
645 return gst_util_get_long_arg (G_OBJECT (priv->offset_element), "offset");
651 gst_play_get_media_total_time (GstPlay *play)
653 gulong total_time, bit_rate;
654 GstPlayPrivate *priv;
656 g_return_val_if_fail (play != NULL, 0);
657 g_return_val_if_fail (GST_IS_PLAY (play), 0);
659 priv = (GstPlayPrivate *)play->priv;
661 if (priv->media_time_element) {
662 return gst_util_get_long_arg (G_OBJECT (priv->media_time_element), "media_time");
665 if (priv->bit_rate_element == NULL) return 0;
667 bit_rate = gst_util_get_long_arg (G_OBJECT (priv->bit_rate_element), "bit_rate");
670 total_time = (gst_play_get_media_size (play) * 8) / bit_rate;
678 gst_play_get_media_current_time (GstPlay *play)
680 gulong current_time, bit_rate;
681 GstPlayPrivate *priv;
683 g_return_val_if_fail (play != NULL, 0);
684 g_return_val_if_fail (GST_IS_PLAY (play), 0);
686 priv = (GstPlayPrivate *)play->priv;
688 if (priv->current_time_element) {
689 return gst_util_get_long_arg (G_OBJECT (priv->current_time_element), "current_time");
692 if (priv->bit_rate_element == NULL) return 0;
694 bit_rate = gst_util_get_long_arg (G_OBJECT (priv->bit_rate_element), "bit_rate");
697 current_time = (gst_play_get_media_offset (play) * 8) / bit_rate;
705 gst_play_media_can_seek (GstPlay *play)
707 GstPlayPrivate *priv;
709 g_return_val_if_fail (play != NULL, FALSE);
710 g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
712 priv = (GstPlayPrivate *)play->priv;
714 return priv->can_seek;
718 gst_play_media_seek (GstPlay *play, gulong offset)
720 GstPlayPrivate *priv;
722 g_return_if_fail (play != NULL);
723 g_return_if_fail (GST_IS_PLAY (play));
725 priv = (GstPlayPrivate *)play->priv;
727 gtk_object_set (GTK_OBJECT (priv->src), "offset", offset, NULL);
731 gst_play_get_pipeline (GstPlay *play)
733 GstPlayPrivate *priv;
735 g_return_val_if_fail (play != NULL, NULL);
736 g_return_val_if_fail (GST_IS_PLAY (play), NULL);
738 priv = (GstPlayPrivate *)play->priv;
740 return GST_ELEMENT (priv->pipeline);
744 gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id)
748 g_return_if_fail (object != NULL);
749 g_return_if_fail (arg != NULL);
751 play = GST_PLAY (object);
757 g_warning ("GstPlay: unknown arg!");
763 gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id)
766 GstPlayPrivate *priv;
768 g_return_if_fail (object != NULL);
769 g_return_if_fail (arg != NULL);
771 play = GST_PLAY (object);
772 priv = (GstPlayPrivate *)play->priv;
776 GTK_VALUE_STRING (*arg) = priv->uri;
779 GTK_VALUE_BOOL (*arg) = priv->muted;
782 GTK_VALUE_INT (*arg) = play->state;
786 GTK_VALUE_UINT (*arg) = gst_play_get_media_size(play);
788 case ARG_MEDIA_OFFSET:
789 GTK_VALUE_UINT (*arg) = gst_play_get_media_offset(play);
793 GTK_VALUE_LONG (*arg) = gst_play_get_media_size(play);
795 case ARG_MEDIA_OFFSET:
796 GTK_VALUE_LONG (*arg) = gst_play_get_media_offset(play);
799 case ARG_MEDIA_TOTAL_TIME:
801 case ARG_MEDIA_CURRENT_TIME:
804 arg->type = GTK_TYPE_INVALID;