Some leftover fixes from Michael.
[platform/upstream/gstreamer.git] / gstplay / gstplay.c
1 #include <config.h>
2
3 #include <string.h>
4 #include <gtk/gtkobject.h>
5 #include <gtk/gtksignal.h>
6 #include <gtk/gtksocket.h>
7 #include <gtk/gtkmain.h>
8
9 #include "gstplay.h"
10 #include "gstplayprivate.h"
11
12 static void gst_play_class_init         (GstPlayClass *klass);
13 static void gst_play_init               (GstPlay *play);
14
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);
17
18 static void gst_play_realize            (GtkWidget *play);
19
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);
23
24 /* signals and args */
25 enum {
26         SIGNAL_STATE_CHANGED,
27         SIGNAL_FRAME_DISPLAYED,
28         SIGNAL_AUDIO_PLAYED,
29         LAST_SIGNAL
30 };
31
32 enum {
33         ARG_0,
34         ARG_URI,
35         ARG_MUTE,
36         ARG_STATE,
37         ARG_MEDIA_SIZE,
38         ARG_MEDIA_OFFSET,
39         ARG_MEDIA_TOTAL_TIME,
40         ARG_MEDIA_CURRENT_TIME,
41 };
42
43 static GtkObject *parent_class = NULL;
44 static guint gst_play_signals[LAST_SIGNAL] = {0};
45
46 GtkType
47 gst_play_get_type (void)
48 {
49         static GtkType play_type = 0;
50
51         if (!play_type) {
52                 static const GtkTypeInfo play_info = {
53                         "GstPlay",
54                         sizeof (GstPlay),
55                         sizeof (GstPlayClass),
56                         (GtkClassInitFunc) gst_play_class_init,
57                         (GtkObjectInitFunc) gst_play_init,
58                         NULL,
59                         NULL,
60                         (GtkClassInitFunc)NULL,
61                 };
62                 play_type = gtk_type_unique (gtk_hbox_get_type (), &play_info);
63         }
64         return play_type;
65 }
66
67 static void
68 gst_play_class_init (GstPlayClass *klass)
69 {
70         GtkObjectClass *object_class;
71         GtkWidgetClass *widget_class;
72
73         parent_class = gtk_type_class (gtk_hbox_get_type ());
74
75         object_class = (GtkObjectClass*)klass;
76         widget_class = (GtkWidgetClass*)klass;
77
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,
83                                 GTK_TYPE_INT);
84
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);
89
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);
94
95 #ifndef USE_GLIB2
96         gtk_object_class_add_signals (object_class, gst_play_signals, LAST_SIGNAL);
97 #endif
98
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);
105 #ifdef USE_GLIB2
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);
114 #else
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);
123 #endif
124
125         object_class->set_arg = gst_play_set_arg;
126         object_class->get_arg = gst_play_get_arg;
127
128         widget_class->realize = gst_play_realize;
129
130 }
131
132 static void
133 gst_play_init (GstPlay *play)
134 {
135         GstPlayPrivate *priv = g_new0 (GstPlayPrivate, 1);
136         GstElement *colorspace;
137
138         play->priv = priv;
139
140         /* create a new bin to hold the elements */
141         priv->pipeline = gst_pipeline_new ("main_pipeline");
142         g_assert (priv->pipeline != NULL);
143
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);
148
149         priv->video_element = gst_elementfactory_make ("bin", "video_bin");
150   
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);
158
159         gst_bin_add (GST_BIN (priv->video_element), priv->video_show);
160
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"),
166                                    "sink");
167         }
168         else {
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"),
174                                    "sink");
175         }
176
177         play->state = GST_PLAY_STOPPED;
178         play->flags = 0;
179
180         priv->src = NULL;
181         priv->muted = FALSE;
182         priv->can_seek = TRUE;
183         priv->uri = NULL;
184         priv->offset_element = NULL;
185         priv->bit_rate_element = NULL;
186         priv->media_time_element = NULL;
187
188         priv->source_width = 0;
189         priv->source_height = 0;
190 }
191
192 GstPlay *
193 gst_play_new ()
194 {
195         return GST_PLAY (gtk_type_new (GST_TYPE_PLAY));
196 }
197
198 static gboolean
199 gst_play_idle_func (gpointer data)
200 {
201         gboolean busy;
202
203         busy = gst_bin_iterate (GST_BIN (data));
204
205         return busy;
206 }
207
208 static void
209 gst_play_eos (GstElement *element,
210               GstPlay *play)
211 {
212         GST_DEBUG(0, "gstplay: eos reached\n");
213         gst_play_stop (play);
214 }
215
216 static void
217 gst_play_have_size (GstElement *element, guint width, guint height,
218                     GstPlay *play)
219 {
220         GstPlayPrivate *priv;
221
222         priv = (GstPlayPrivate *) play->priv;
223
224         priv->source_width = width;
225         priv->source_height = height;
226
227         gtk_widget_set_usize (priv->video_widget, width, height);
228 }
229
230 static void
231 gst_play_frame_displayed (GstElement *element, GstPlay *play)
232 {
233         GstPlayPrivate *priv;
234         static int stolen = FALSE;
235
236         priv = (GstPlayPrivate *)play->priv;
237
238         gdk_threads_enter ();
239         if (!stolen) {
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);
244                 stolen = TRUE;
245         }
246         gdk_threads_leave ();
247
248         gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_FRAME_DISPLAYED],
249                          NULL);
250 }
251
252 static void
253 gst_play_audio_handoff (GstElement *element, GstPlay *play)
254 {
255         gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_AUDIO_PLAYED],
256                          NULL);
257 }
258
259 #ifdef USE_GLIB2
260 static void
261 gst_play_object_introspect (GstObject *object, const gchar *property, GstElement **target)
262 {
263         GParamSpec *pspec;
264         GstElement *element;
265
266         if (!GST_IS_ELEMENT (object) && !GST_IS_BIN (object))
267                 return;
268
269         element = GST_ELEMENT (object);
270
271 #warning this looks grim, did I port it right ?
272         pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), property);
273
274         if (!pspec) {
275                 *target = element;
276                 GST_DEBUG(0, "gstplay: using element \"%s\" for %s property\n", 
277                           gst_element_get_name(element), property);
278         }
279 }
280 #else
281 static void
282 gst_play_object_introspect (GstObject *object, const gchar *property, GstElement **target)
283 {
284         gchar *info;
285         GtkArgInfo *arg;
286         GstElement *element;
287
288         if (!GST_IS_ELEMENT (object) && !GST_IS_BIN (object))
289                 return;
290
291         element = GST_ELEMENT (object);
292
293         info = gtk_object_arg_get_info (GTK_OBJECT_TYPE (element), property, &arg);
294
295         if (info) {
296                 g_free(info);
297         }
298         else {
299                 *target = element;
300                 GST_DEBUG(0, "gstplay: using element \"%s\" for %s property\n", 
301                           gst_element_get_name(element), property);
302         }
303 }
304 #endif
305
306 /* Dumb introspection of the interface...
307  * this will change with glib 1.4
308  * */
309 static void
310 gst_play_object_added (GstAutoplug* autoplug, GstObject *object, GstPlay *play)
311 {
312         GstPlayPrivate *priv;
313
314         g_return_if_fail (play != NULL);
315
316         priv = (GstPlayPrivate *)play->priv;
317
318         if (GST_FLAG_IS_SET (object, GST_ELEMENT_NO_SEEK)) {
319                 priv->can_seek = FALSE;
320         }
321
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);
331
332 }
333
334 static void
335 gst_play_cache_empty (GstElement *element, GstPlay *play)
336 {
337         GstPlayPrivate *priv;
338         GstElement *new_element;
339
340         priv = (GstPlayPrivate *)play->priv;
341
342         gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
343
344         new_element = gst_bin_get_by_name (GST_BIN (priv->pipeline), "new_element");
345
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");
350
351         gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
352 }
353
354 static void
355 gst_play_have_type (GstElement *sink, GstCaps *caps, GstPlay *play)
356 {
357         GstPlayPrivate *priv;
358         GstElement *new_element;
359         GstAutoplug *autoplug;
360
361         GST_DEBUG (0,"GstPipeline: play have type\n");
362
363         priv = (GstPlayPrivate *)play->priv;
364
365         gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
366
367         gst_element_disconnect (priv->cache, "src", priv->typefind, "sink");
368         gst_bin_remove (GST_BIN (priv->pipeline), priv->typefind);
369
370         autoplug = gst_autoplugfactory_make ("staticrender");
371         g_assert (autoplug != NULL);
372
373         g_signal_connect (G_OBJECT (autoplug), "new_object",
374                           G_CALLBACK (gst_play_object_added), play);
375
376         new_element = gst_autoplug_to_renderers (autoplug,
377                                                  caps,
378                                                  priv->video_element,
379                                                  priv->audio_element,
380                                                  NULL);
381
382         if (!new_element) {
383                 // FIXME, signal a suitable error
384                 return;
385         }
386
387         gst_element_set_name (new_element, "new_element");
388
389         gst_bin_add (GST_BIN (priv->pipeline), new_element);
390
391         g_object_set (G_OBJECT (priv->cache), "reset", TRUE, NULL);
392
393         gst_element_connect (priv->cache, "src", new_element, "sink");
394
395         g_signal_connect (G_OBJECT (priv->pipeline), "eos", G_CALLBACK (gst_play_eos), play);
396
397         gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
398 }
399
400 static gboolean
401 connect_pads (GstElement *new_element, GstElement *target, gboolean add)
402 {
403         GList *pads = gst_element_get_pad_list (new_element);
404         GstPad *targetpad = gst_element_get_pad (target, "sink");
405
406         while (pads) {
407                 GstPad *pad = GST_PAD (pads->data);
408
409                 if (gst_pad_check_compatibility (pad, targetpad)) {
410                         if (add) {
411                                 gst_bin_add (GST_BIN (gst_element_get_parent (
412                                         GST_ELEMENT (gst_pad_get_real_parent (pad)))),
413                                              target);
414                         }
415                         gst_pad_connect (pad, targetpad);
416                         return TRUE;
417                 }
418                 pads = g_list_next (pads);
419         }
420         return FALSE;
421 }
422
423 GstPlayReturn
424 gst_play_set_uri (GstPlay *play, const guchar *uri)
425 {
426         gchar          *uriloc;
427         GstPlayPrivate *priv;
428
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);
432         
433         priv = (GstPlayPrivate *)play->priv;
434
435         if (priv->uri)
436                 g_free (priv->uri);
437         
438         /* see if it looks like an URI */
439         if ((uriloc = strstr (uri, ":/"))) {
440                 priv->src = gst_elementfactory_make ("gnomevfssrc", "srcelement");
441                 
442                 if (!priv->src) {
443                         if (strstr (uri, "file:/")) {
444               uri += strlen ("file:/");
445                         }
446                         else
447                                 return GST_PLAY_CANNOT_PLAY;
448                 }
449         }
450         
451         if (priv->src == NULL) {
452                 priv->src = gst_elementfactory_make ("filesrc", "srcelement");
453         }
454         
455         priv->uri = g_strdup (uri);
456         
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);
460         
461         g_object_set (G_OBJECT (priv->src), "location", priv->uri, NULL);
462         
463         priv->cache = gst_elementfactory_make ("autoplugcache", "cache");
464         g_return_val_if_fail (priv->cache != NULL, GST_PLAY_CANNOT_PLAY);
465         
466         g_signal_connect (G_OBJECT (priv->cache), "cache_empty", 
467                           G_CALLBACK (gst_play_cache_empty), play);
468         
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);
473         
474         
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);
478         
479         gst_element_connect (priv->src, "src", priv->cache, "sink");
480         gst_element_connect (priv->cache, "src", priv->typefind, "sink");
481         
482         return GST_PLAY_OK;
483 }
484
485 static void
486 gst_play_realize (GtkWidget *widget)
487 {
488         GstPlay *play;
489         GstPlayPrivate *priv;
490
491         g_return_if_fail (GST_IS_PLAY (widget));
492
493         //g_print ("realize\n");
494
495         play = GST_PLAY (widget);
496         priv = (GstPlayPrivate *)play->priv;
497
498         priv->video_widget = gtk_socket_new ();
499
500         gtk_container_add (GTK_CONTAINER (widget), priv->video_widget);
501         
502         if (GTK_WIDGET_CLASS (parent_class)->realize) {
503                 GTK_WIDGET_CLASS (parent_class)->realize (widget);
504         }
505
506         //gtk_socket_steal (GTK_SOCKET (priv->video_widget),
507         //             gst_util_get_int_arg (GTK_OBJECT(priv->video_element), "xid"));
508
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"));
512 }
513
514 void
515 gst_play_play (GstPlay *play)
516 {
517         GstPlayPrivate *priv;
518
519         g_return_if_fail (play != NULL);
520         g_return_if_fail (GST_IS_PLAY (play));
521
522         priv = (GstPlayPrivate *)play->priv;
523
524         if (play->state == GST_PLAY_PLAYING) return;
525
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);
529
530         play->state = GST_PLAY_PLAYING;
531         gtk_idle_add (gst_play_idle_func, priv->pipeline);
532
533         gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
534                          play->state);
535 }
536
537 void
538 gst_play_pause (GstPlay *play)
539 {
540         GstPlayPrivate *priv;
541
542         g_return_if_fail (play != NULL);
543         g_return_if_fail (GST_IS_PLAY (play));
544
545         priv = (GstPlayPrivate *)play->priv;
546
547         if (play->state != GST_PLAY_PLAYING) return;
548
549         gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PAUSED);
550
551         play->state = GST_PLAY_PAUSED;
552         g_idle_remove_by_data (priv->pipeline);
553
554         gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
555                          play->state);
556 }
557
558 void
559 gst_play_stop (GstPlay *play)
560 {
561         GstPlayPrivate *priv;
562
563         g_return_if_fail (play != NULL);
564         g_return_if_fail (GST_IS_PLAY (play));
565
566         priv = (GstPlayPrivate *)play->priv;
567
568         if (play->state == GST_PLAY_STOPPED) return;
569
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);
574
575         play->state = GST_PLAY_STOPPED;
576         g_idle_remove_by_data (priv->pipeline);
577
578         gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
579                          play->state);
580 }
581
582 GtkWidget *
583 gst_play_get_video_widget (GstPlay *play)
584 {
585         GstPlayPrivate *priv;
586
587         g_return_val_if_fail (play != NULL, 0);
588         g_return_val_if_fail (GST_IS_PLAY (play), 0);
589
590         priv = (GstPlayPrivate *)play->priv;
591
592         return priv->video_widget;
593 }
594
595 gint
596 gst_play_get_source_width (GstPlay *play)
597 {
598         GstPlayPrivate *priv;
599
600         g_return_val_if_fail (play != NULL, 0);
601         g_return_val_if_fail (GST_IS_PLAY (play), 0);
602
603         priv = (GstPlayPrivate *)play->priv;
604
605         return priv->source_width;
606 }
607
608 gint
609 gst_play_get_source_height (GstPlay *play)
610 {
611         GstPlayPrivate *priv;
612
613         g_return_val_if_fail (play != NULL, 0);
614         g_return_val_if_fail (GST_IS_PLAY (play), 0);
615
616         priv = (GstPlayPrivate *)play->priv;
617
618         return priv->source_height;
619 }
620
621 gulong
622 gst_play_get_media_size (GstPlay *play)
623 {
624         GstPlayPrivate *priv;
625
626         g_return_val_if_fail (play != NULL, 0);
627         g_return_val_if_fail (GST_IS_PLAY (play), 0);
628
629         priv = (GstPlayPrivate *)play->priv;
630
631         return gst_util_get_long_arg (G_OBJECT (priv->src), "filesize");
632 }
633
634 gulong
635 gst_play_get_media_offset (GstPlay *play)
636 {
637         GstPlayPrivate *priv;
638
639         g_return_val_if_fail (play != NULL, 0);
640         g_return_val_if_fail (GST_IS_PLAY (play), 0);
641
642         priv = (GstPlayPrivate *)play->priv;
643
644         if (priv->offset_element)
645                 return gst_util_get_long_arg (G_OBJECT (priv->offset_element), "offset");
646         else
647                 return 0;
648 }
649
650 gulong
651 gst_play_get_media_total_time (GstPlay *play)
652 {
653         gulong total_time, bit_rate;
654         GstPlayPrivate *priv;
655
656         g_return_val_if_fail (play != NULL, 0);
657         g_return_val_if_fail (GST_IS_PLAY (play), 0);
658
659         priv = (GstPlayPrivate *)play->priv;
660
661         if (priv->media_time_element) {
662                 return gst_util_get_long_arg (G_OBJECT (priv->media_time_element), "media_time");
663         }
664
665         if (priv->bit_rate_element == NULL) return 0;
666
667         bit_rate = gst_util_get_long_arg (G_OBJECT (priv->bit_rate_element), "bit_rate");
668
669         if (bit_rate)
670                 total_time = (gst_play_get_media_size (play) * 8) / bit_rate;
671         else
672                 total_time = 0;
673
674         return total_time;
675 }
676
677 gulong
678 gst_play_get_media_current_time (GstPlay *play)
679 {
680         gulong current_time, bit_rate;
681         GstPlayPrivate *priv;
682
683         g_return_val_if_fail (play != NULL, 0);
684         g_return_val_if_fail (GST_IS_PLAY (play), 0);
685
686         priv = (GstPlayPrivate *)play->priv;
687
688         if (priv->current_time_element) {
689                 return gst_util_get_long_arg (G_OBJECT (priv->current_time_element), "current_time");
690         }
691
692         if (priv->bit_rate_element == NULL) return 0;
693
694         bit_rate = gst_util_get_long_arg (G_OBJECT (priv->bit_rate_element), "bit_rate");
695
696         if (bit_rate)
697                 current_time = (gst_play_get_media_offset (play) * 8) / bit_rate;
698         else
699                 current_time = 0;
700
701         return current_time;
702 }
703
704 gboolean
705 gst_play_media_can_seek (GstPlay *play)
706 {
707         GstPlayPrivate *priv;
708
709         g_return_val_if_fail (play != NULL, FALSE);
710         g_return_val_if_fail (GST_IS_PLAY (play), FALSE);
711
712         priv = (GstPlayPrivate *)play->priv;
713
714         return priv->can_seek;
715 }
716
717 void
718 gst_play_media_seek (GstPlay *play, gulong offset)
719 {
720         GstPlayPrivate *priv;
721
722         g_return_if_fail (play != NULL);
723         g_return_if_fail (GST_IS_PLAY (play));
724
725         priv = (GstPlayPrivate *)play->priv;
726
727         gtk_object_set (GTK_OBJECT (priv->src), "offset", offset, NULL);
728 }
729
730 GstElement*
731 gst_play_get_pipeline (GstPlay *play)
732 {
733         GstPlayPrivate *priv;
734
735         g_return_val_if_fail (play != NULL, NULL);
736         g_return_val_if_fail (GST_IS_PLAY (play), NULL);
737
738         priv = (GstPlayPrivate *)play->priv;
739
740         return GST_ELEMENT (priv->pipeline);
741 }
742
743 static void
744 gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id)
745 {
746         GstPlay *play;
747
748         g_return_if_fail (object != NULL);
749         g_return_if_fail (arg != NULL);
750
751         play = GST_PLAY (object);
752
753         switch (id) {
754         case ARG_MUTE:
755                 break;
756         default:
757                 g_warning ("GstPlay: unknown arg!");
758                 break;
759         }
760 }
761
762 static void
763 gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id)
764 {
765         GstPlay *play;
766         GstPlayPrivate *priv;
767
768         g_return_if_fail (object != NULL);
769         g_return_if_fail (arg != NULL);
770
771         play = GST_PLAY (object);
772         priv = (GstPlayPrivate *)play->priv;
773
774         switch (id) {
775         case ARG_URI:
776                 GTK_VALUE_STRING (*arg) = priv->uri;
777                 break;
778         case ARG_MUTE:
779                 GTK_VALUE_BOOL (*arg) = priv->muted;
780                 break;
781         case ARG_STATE:
782                 GTK_VALUE_INT (*arg) = play->state;
783                 break;
784 #ifdef USE_GLIB2
785         case ARG_MEDIA_SIZE:
786                 GTK_VALUE_UINT (*arg) = gst_play_get_media_size(play);
787                 break;
788         case ARG_MEDIA_OFFSET:
789                 GTK_VALUE_UINT (*arg) = gst_play_get_media_offset(play);
790                 break;
791 #else
792         case ARG_MEDIA_SIZE:
793                 GTK_VALUE_LONG (*arg) = gst_play_get_media_size(play);
794                 break;
795         case ARG_MEDIA_OFFSET:
796                 GTK_VALUE_LONG (*arg) = gst_play_get_media_offset(play);
797                 break;
798 #endif
799         case ARG_MEDIA_TOTAL_TIME:
800                 break;
801         case ARG_MEDIA_CURRENT_TIME:
802                 break;
803         default:
804                 arg->type = GTK_TYPE_INVALID;
805                 break;
806         }
807 }