~ubuntu-branches/ubuntu/trusty/totem/trusty-proposed

« back to all changes in this revision

Viewing changes to src/backend/bacon-video-widget-xine.c

  • Committer: Bazaar Package Importer
  • Author(s): Josselin Mouette, Josselin Mouette, Loic Minier, Sjoerd Simons
  • Date: 2008-09-10 15:38:34 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080910153834-kxne946nj2b5squf
Tags: 2.22.2-4
[ Josselin Mouette ]
* Change the recommends on g-c-c to one on g-s-d. Also move it to
  totem-plugins, which is the package providing the media keys
  functionality.
* Change the depends on dbus to dbus-x11.

[ Loic Minier ]
* Let totem-gstreamer recommend gnome-app-install for easy codec
  installation.

[ Josselin Mouette ]
* 02_flv.patch: the canonical MIME type for Flash videos is 
  video/x-flv, not video/flv. Closes: #486468.

[ Sjoerd Simons ]
* 30_fix_youtube_plugin.patch: Set the server as a keyword argument to be
  compatible with both old and new versions of python-gdata. Fixes searching
  for youtube videos
* debian/control.in: Fix double Recommend field for totem-gstreamer

[ Josselin Mouette ]
* rules: rally disable the vala plugin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 * along with this program; if not, write to the Free Software
17
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
18
 *
19
 
 * $Id: bacon-video-widget-xine.c 3398 2006-08-10 09:09:08Z hadess $
 
19
 * $Id: bacon-video-widget-xine.c 5344 2008-04-08 13:17:29Z hadess $
20
20
 *
21
21
 * the xine engine in a widget - implementation
22
22
 */
35
35
#include <stdlib.h>
36
36
#include <unistd.h>
37
37
#include <sched.h>
 
38
#include <pthread.h>
38
39
/* X11 */
39
40
#include <X11/X.h>
40
41
#include <X11/Xlib.h>
44
45
#include <gconf/gconf-client.h>
45
46
#include <glib/gi18n.h>
46
47
/* xine */
 
48
#define XINE_ENABLE_EXPERIMENTAL_FEATURES
47
49
#include <xine.h>
48
50
 
 
51
#ifndef HAVE_GTK_ONLY
 
52
/* gnome keyring and vfs */
 
53
#include <libgnomevfs/gnome-vfs.h>
 
54
#include <gnome-keyring.h>
 
55
#endif /* !HAVE_GTK_ONLY */
 
56
 
49
57
#include "debug.h"
50
58
#include "bacon-video-widget.h"
51
 
#include "bacon-video-widget-private.h"
 
59
#include "bacon-video-widget-common.h"
52
60
#include "baconvideowidget-marshal.h"
53
61
#include "video-utils.h"
54
62
#include "bacon-resize.h"
55
63
 
56
64
#define DEFAULT_HEIGHT 180
57
65
#define DEFAULT_WIDTH 240
58
 
#define CONFIG_FILE ".gnome2"G_DIR_SEPARATOR_S"totem_config"
 
66
/* This is built into a path with g_get_user_config_dir(), so the full
 
67
 * path is something like ~/.config/totem/xine_config */
 
68
#define CONFIG_FILE "totem"G_DIR_SEPARATOR_S"xine_config"
59
69
 
60
70
/* Signals */
61
71
enum {
64
74
        REDIRECT,
65
75
        TITLE_CHANGE,
66
76
        CHANNELS_CHANGE,
67
 
        TICK,
 
77
        SIGNAL_TICK,
68
78
        GOT_METADATA,
69
79
        BUFFERING,
70
 
        SPEED_WARNING,
71
80
        LAST_SIGNAL
72
81
};
73
82
 
80
89
        CHANNELS_CHANGE_ASYNC,
81
90
        BUFFERING_ASYNC,
82
91
        MESSAGE_ASYNC,
83
 
        SPEED_WARNING_ASYNC,
84
92
        ERROR_ASYNC
85
93
};
86
94
 
91
99
        gboolean fatal;
92
100
} signal_data;
93
101
 
 
102
enum {
 
103
        SEEKING_BY_INVALID,
 
104
        SEEKING_BY_TIME,
 
105
        SEEKING_BY_FRACTION
 
106
};
 
107
 
94
108
/* Arguments */
95
109
enum {
96
110
        PROP_0,
102
116
        PROP_PLAYING,
103
117
        PROP_SEEKABLE,
104
118
        PROP_SHOWCURSOR,
105
 
        PROP_MEDIADEV,
106
 
        PROP_SHOW_VISUALS
 
119
        PROP_SHOW_VISUALS,
 
120
        PROP_VOLUME
107
121
};
108
122
 
109
123
static int video_props[4] = {
120
134
        GCONF_PREFIX"/hue"
121
135
};
122
136
 
 
137
enum {
 
138
        BVW_XINE_PLAY,
 
139
        BVW_XINE_PAUSE
 
140
};
 
141
 
123
142
struct BaconVideoWidgetPrivate {
124
143
        /* Xine stuff */
125
144
        xine_t *xine;
126
145
        xine_stream_t *stream;
127
146
        xine_video_port_t *vo_driver;
128
 
        gboolean vo_driver_none;
129
147
        xine_audio_port_t *ao_driver;
130
 
        gboolean ao_driver_none;
131
148
        xine_event_queue_t *ev_queue;
132
149
        double display_ratio;
133
150
 
134
151
        /* Configuration */
135
152
        GConfClient *gc;
136
 
        char *mrl;
137
153
        BvwUseType type;
138
 
        char *mediadev;
139
154
 
140
155
        /* X stuff */
141
156
        Display *display;
142
157
        int screen;
143
 
        GdkWindow *video_window;
144
158
        GdkCursor *cursor;
145
159
 
 
160
        /* Opening thread for fd://0 */
 
161
        pthread_t open_thread;
 
162
        pthread_mutex_t queued_actions_mutex;
 
163
        GList *queued_actions;
 
164
 
146
165
        /* Visual effects */
147
166
        char *vis_name;
148
 
        gboolean show_vfx;
149
 
        gboolean using_vfx;
150
167
        xine_post_t *vis;
151
168
        GList *visuals;
152
169
        char *queued_vis;
154
171
 
155
172
        /* Seeking stuff */
156
173
        int seeking;
157
 
        float seek_dest;
 
174
        double seek_dest;
158
175
        gint64 seek_dest_time;
159
176
 
160
177
        /* Logo */
161
 
        gboolean logo_mode;
162
178
        GdkPixbuf *logo_pixbuf;
163
179
        /* Logo, save frame_output_cb members */
164
180
        int dest_x, dest_y, dest_width, dest_height, win_x, win_y;
166
182
 
167
183
        /* Other stuff */
168
184
        int xpos, ypos;
169
 
        gboolean can_dvd, can_vcd, can_cdda;
170
185
        guint tick_id;
171
 
        gboolean have_xvidmode;
172
 
        gboolean auto_resize;
173
 
        int volume;
 
186
        double volume;
174
187
        BaconVideoWidgetAudioOutType audio_out_type;
175
188
        TvOutType tvout;
176
 
        gboolean is_live;
177
 
        char *codecs_path;
178
 
        gboolean got_redirect;
179
 
        gboolean has_subtitle;
 
189
        gint64 stream_length;
180
190
 
181
191
        GAsyncQueue *queue;
182
192
        int video_width, video_height;
183
193
        int init_width, init_height;
184
194
 
185
195
        /* fullscreen stuff */
186
 
        gboolean fullscreen_mode;
187
 
        gboolean cursor_shown;
188
196
        int screenid;
 
197
 
 
198
        /* Bacon resize */
 
199
        BaconResize *bacon_resize;
 
200
 
 
201
        guint ao_driver_none : 1;
 
202
        guint show_vfx : 1;
 
203
        guint using_vfx : 1;
 
204
        guint logo_mode : 1;
 
205
        guint can_dvd : 1;
 
206
        guint can_vcd : 1;
 
207
        guint can_dvb : 1;
 
208
        guint auto_resize : 1;
 
209
        guint is_live : 1;
 
210
        guint got_redirect : 1;
 
211
        guint has_subtitle : 1;
 
212
        /* Whether the last button event was consumed internally */
 
213
        guint bevent_consumed : 1;
 
214
        guint fullscreen_mode : 1;
 
215
        guint cursor_shown : 1;
189
216
};
190
217
 
191
218
static const char *mms_bandwidth_strs[] = {
257
284
static void bacon_video_widget_size_allocate (GtkWidget *widget,
258
285
                GtkAllocation *allocation);
259
286
static xine_video_port_t * load_video_out_driver (BaconVideoWidget *bvw,
260
 
                gboolean null_out);
 
287
                BvwUseType type);
261
288
static xine_audio_port_t * load_audio_out_driver (BaconVideoWidget *bvw,
262
289
                gboolean null_out, GError **error);
263
290
static gboolean bacon_video_widget_tick_send (BaconVideoWidget *bvw);
 
291
static void bacon_video_widget_reconfigure_tick (BaconVideoWidget *bvw, gboolean enable);
264
292
static void bacon_video_widget_set_visuals_quality_size (BaconVideoWidget *bvw,
265
293
                int h, int w, int fps);
266
294
 
267
 
static GtkWidgetClass *parent_class = NULL;
 
295
static GObjectClass *parent_class = NULL;
268
296
 
269
297
static void xine_event (void *user_data, const xine_event_t *event);
270
298
static gboolean bacon_video_widget_idle_signal (BaconVideoWidget *bvw);
272
300
 
273
301
static int bvw_table_signals[LAST_SIGNAL] = { 0 };
274
302
 
275
 
G_DEFINE_TYPE(BaconVideoWidget, bacon_video_widget, GTK_TYPE_BOX)
 
303
G_DEFINE_TYPE(BaconVideoWidget, bacon_video_widget, GTK_TYPE_EVENT_BOX)
276
304
 
277
305
static void
278
306
bacon_video_widget_class_init (BaconVideoWidgetClass *klass)
279
307
{
280
 
 
281
308
        GObjectClass *object_class;
282
309
        GtkWidgetClass *widget_class;
283
310
 
284
311
        object_class = (GObjectClass *) klass;
285
312
        widget_class = (GtkWidgetClass *) klass;
286
313
 
287
 
        parent_class = gtk_type_class (gtk_box_get_type ());
 
314
        parent_class = g_type_class_peek_parent (klass);
288
315
 
289
316
        /* GtkWidget */
290
317
        widget_class->realize = bacon_video_widget_realize;
307
334
                        g_param_spec_boolean ("logo_mode", NULL, NULL,
308
335
                                FALSE, G_PARAM_READWRITE));
309
336
        g_object_class_install_property (object_class, PROP_POSITION,
310
 
                        g_param_spec_int64 ("position", NULL, NULL,
311
 
                                0, G_MAXINT64, 0, G_PARAM_READABLE));
 
337
                        g_param_spec_double ("position", NULL, NULL,
 
338
                                0, 1.0, 0, G_PARAM_READABLE));
312
339
        g_object_class_install_property (object_class, PROP_STREAM_LENGTH,
313
340
                        g_param_spec_int64 ("stream_length", NULL, NULL,
314
341
                                0, G_MAXINT64, 0, G_PARAM_READABLE));
318
345
        g_object_class_install_property (object_class, PROP_SEEKABLE,
319
346
                        g_param_spec_boolean ("seekable", NULL, NULL,
320
347
                                FALSE, G_PARAM_READABLE));
 
348
        g_object_class_install_property (object_class, PROP_VOLUME,
 
349
                        g_param_spec_double ("volume", NULL, NULL,
 
350
                                0.0, 1.0, 0.0,
 
351
                                G_PARAM_READWRITE));
321
352
        g_object_class_install_property (object_class, PROP_SHOWCURSOR,
322
353
                        g_param_spec_boolean ("showcursor", NULL, NULL,
323
354
                                FALSE, G_PARAM_READWRITE));
324
 
        g_object_class_install_property (object_class, PROP_MEDIADEV,
325
 
                        g_param_spec_string ("mediadev", NULL, NULL,
326
 
                                FALSE, G_PARAM_READWRITE));
327
355
        g_object_class_install_property (object_class, PROP_SHOW_VISUALS,
328
356
                        g_param_spec_boolean ("showvisuals", NULL, NULL,
329
357
                                FALSE, G_PARAM_WRITABLE));
382
410
                                g_cclosure_marshal_VOID__VOID,
383
411
                                G_TYPE_NONE, 0);
384
412
 
385
 
        bvw_table_signals[TICK] =
 
413
        bvw_table_signals[SIGNAL_TICK] =
386
414
                g_signal_new ("tick",
387
415
                                G_TYPE_FROM_CLASS (object_class),
388
416
                                G_SIGNAL_RUN_LAST,
389
417
                                G_STRUCT_OFFSET (BaconVideoWidgetClass, tick),
390
418
                                NULL, NULL,
391
 
                                baconvideowidget_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN,
 
419
                                baconvideowidget_marshal_VOID__INT64_INT64_DOUBLE_BOOLEAN,
392
420
                                G_TYPE_NONE, 4, G_TYPE_INT64, G_TYPE_INT64,
393
 
                                G_TYPE_FLOAT, G_TYPE_BOOLEAN);
 
421
                                G_TYPE_DOUBLE, G_TYPE_BOOLEAN);
394
422
 
395
423
        bvw_table_signals[BUFFERING] =
396
424
                g_signal_new ("buffering",
400
428
                                NULL, NULL,
401
429
                                g_cclosure_marshal_VOID__INT,
402
430
                                G_TYPE_NONE, 1, G_TYPE_INT);
403
 
 
404
 
        bvw_table_signals[SPEED_WARNING] =
405
 
                g_signal_new ("speed-warning",
406
 
                                G_TYPE_FROM_CLASS (object_class),
407
 
                                G_SIGNAL_RUN_LAST,
408
 
                                G_STRUCT_OFFSET (BaconVideoWidgetClass, speed_warning),
409
 
                                NULL, NULL,
410
 
                                g_cclosure_marshal_VOID__VOID,
411
 
                                G_TYPE_NONE, 0);
412
431
}
413
432
 
414
433
static void
423
442
        GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_CAN_FOCUS);
424
443
        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
425
444
 
 
445
        bvw->com = g_new0 (BaconVideoWidgetCommon, 1);
426
446
        bvw->priv = g_new0 (BaconVideoWidgetPrivate, 1);
427
447
        bvw->priv->xine = xine_new ();
428
448
        bvw->priv->cursor_shown = TRUE;
429
 
        bvw->priv->volume = -1;
 
449
        bvw->priv->volume = 0.0;
430
450
 
431
451
        bvw->priv->init_width = 0;
432
452
        bvw->priv->init_height = 0;
443
463
        autoplug_list = xine_get_autoplay_input_plugin_ids (bvw->priv->xine);
444
464
        while (autoplug_list && autoplug_list[i])
445
465
        {
446
 
                if (g_ascii_strcasecmp (autoplug_list[i], "VCD") == 0)
447
 
                        bvw->priv->can_vcd = TRUE;
448
 
                else if (g_ascii_strcasecmp (autoplug_list[i], "VCDO") == 0)
449
 
                        bvw->priv->can_vcd = TRUE;
450
 
                else if (g_ascii_strcasecmp (autoplug_list[i], "DVD") == 0)
 
466
                if (g_ascii_strcasecmp (autoplug_list[i], "VCD") == 0) {
 
467
                        bvw->priv->can_vcd = TRUE;
 
468
                } else if (g_ascii_strcasecmp (autoplug_list[i], "DVD") == 0) {
451
469
                        bvw->priv->can_dvd = TRUE;
452
 
                else if (g_ascii_strcasecmp (autoplug_list[i], "CD") == 0)
453
 
                        bvw->priv->can_cdda = TRUE;
 
470
                } else if (g_ascii_strcasecmp (autoplug_list[i], "DVB") == 0) {
 
471
                        char *path;
 
472
 
 
473
                        path = g_build_filename (g_get_home_dir (),
 
474
                                                 ".xine", "channels.conf", NULL);
 
475
                        if (g_file_test (path, G_FILE_TEST_IS_REGULAR) != FALSE)
 
476
                                bvw->priv->can_dvb = TRUE;
 
477
                        g_free (path);
 
478
                }
454
479
                i++;
455
480
        }
456
 
 
457
 
        bvw->priv->tick_id = g_timeout_add (140,
458
 
                        (GSourceFunc) bacon_video_widget_tick_send, bvw);
459
481
}
460
482
 
461
483
static void
463
485
{
464
486
        BaconVideoWidget *bvw = (BaconVideoWidget *) object;
465
487
 
 
488
        if (&bvw->priv->queued_actions_mutex != NULL)
 
489
                pthread_mutex_destroy (&bvw->priv->queued_actions_mutex);
 
490
 
466
491
        if (bvw->priv->gc)
467
492
                g_object_unref (G_OBJECT (bvw->priv->gc));
468
493
 
476
501
                bvw->priv->cursor = NULL;
477
502
        }
478
503
        if (bvw->priv->logo_pixbuf != NULL) {
479
 
                gdk_pixbuf_unref (bvw->priv->logo_pixbuf);
 
504
                g_object_unref (bvw->priv->logo_pixbuf);
480
505
                bvw->priv->logo_pixbuf = NULL;
481
506
        }
482
507
        g_free (bvw->priv->vis_name);
483
 
        g_free (bvw->priv->mediadev);
484
508
        g_object_unref (G_OBJECT (bvw->priv->gc));
485
 
        g_free (bvw->priv->codecs_path);
486
509
 
487
510
        g_list_foreach (bvw->priv->visuals, (GFunc) g_free, NULL);
488
511
        g_list_free (bvw->priv->visuals);
492
515
        G_OBJECT_CLASS (parent_class)->finalize (object);
493
516
 
494
517
        g_free (bvw->priv);
 
518
        g_free (bvw->com);
 
519
}
 
520
 
 
521
static gboolean
 
522
bacon_video_widget_draw_logo (BaconVideoWidget *bvw)
 
523
{
 
524
        gboolean draw_logo, has_video;
 
525
 
 
526
        /* draw the logo in logo mode */
 
527
        if (bvw->priv->logo_mode != FALSE)
 
528
                return TRUE;
 
529
 
 
530
        /* We're probably shutting down when this happens */
 
531
        if (bvw->priv->stream == NULL)
 
532
                return TRUE;
 
533
 
 
534
        /* if there's only audio and no visualisation, draw the logo as well */
 
535
        has_video = xine_get_stream_info(bvw->priv->stream,
 
536
                                         XINE_STREAM_INFO_HAS_VIDEO);
 
537
        draw_logo = !has_video && !bvw->priv->using_vfx;
 
538
 
 
539
        return draw_logo;
495
540
}
496
541
 
497
542
static void
529
574
 
530
575
        if (bvw == NULL || bvw->priv == NULL)
531
576
                return;
532
 
        if (bvw->priv->logo_mode != FALSE) {
533
 
                *dest_x = bvw->priv->dest_x;
534
 
                *dest_y = bvw->priv->dest_y;
 
577
 
 
578
        if (bacon_video_widget_draw_logo (bvw) != FALSE) {
 
579
                /* display the video outside the window,
 
580
                 * otherwise xine-lib will show stuff on top
 
581
                 * of our logo */
 
582
                *dest_x = - bvw->priv->dest_width;
 
583
                *dest_y = - bvw->priv->dest_height;
535
584
                *dest_width = bvw->priv->dest_width;
536
585
                *dest_height = bvw->priv->dest_height;
537
586
                *win_x = bvw->priv->win_x;
592
641
}
593
642
 
594
643
static xine_video_port_t *
595
 
load_video_out_driver (BaconVideoWidget *bvw, gboolean null_out)
 
644
load_video_out_driver (BaconVideoWidget *bvw, BvwUseType type)
596
645
{
597
646
        double res_h, res_v;
598
647
        x11_visual_t vis;
601
650
        static char *drivers[] = { "xv", "xshm" };
602
651
        guint i;
603
652
 
604
 
        if (null_out != FALSE)
605
 
        {
606
 
                bvw->priv->vo_driver_none = TRUE;
 
653
        if (type == BVW_USE_TYPE_METADATA) {
607
654
                return xine_open_video_driver (bvw->priv->xine,
608
655
                                "none", XINE_VISUAL_TYPE_NONE, NULL);
 
656
        } else if (type == BVW_USE_TYPE_CAPTURE) {
 
657
                return xine_new_framegrab_video_port (bvw->priv->xine);
609
658
        }
610
659
 
611
660
        vis.display = bvw->priv->display;
612
661
        vis.screen = bvw->priv->screen;
613
 
        vis.d = GDK_WINDOW_XID (bvw->priv->video_window);
 
662
        vis.d = GDK_WINDOW_XID (GTK_WIDGET(bvw)->window);
614
663
        res_h = (DisplayWidth (bvw->priv->display, bvw->priv->screen) * 1000 /
615
664
                        DisplayWidthMM (bvw->priv->display,
616
665
                                bvw->priv->screen));
617
666
        res_v = (DisplayHeight (bvw->priv->display, bvw->priv->screen) * 1000 /
618
667
                        DisplayHeightMM (bvw->priv->display,
619
668
                                bvw->priv->screen));
620
 
        bvw->priv->display_ratio = res_v / res_h;
 
669
 
 
670
        /* FIXME this should be fixed with proper multi-head handling in
 
671
         * the xine-lib backend */
 
672
        if (res_h == 0 || res_v == 0)
 
673
                bvw->priv->display_ratio = 1.0;
 
674
        else
 
675
                bvw->priv->display_ratio = res_v / res_h;
621
676
 
622
677
        if (fabs (bvw->priv->display_ratio - 1.0) < 0.01) {
623
678
                bvw->priv->display_ratio = 1.0;
634
689
 
635
690
        /* Don't try to load anything but the xshm plugin if we're not
636
691
         * on a local display */
637
 
        if (totem_display_is_local () == FALSE)
 
692
        if (totem_display_is_local () == FALSE ||
 
693
            (bvw->priv->init_width < SMALL_STREAM_WIDTH
 
694
             && bvw->priv->init_width > 0
 
695
             && bvw->priv->init_height < SMALL_STREAM_HEIGHT
 
696
             && bvw->priv->init_height > 0))
638
697
        {
639
698
                return xine_open_video_driver (bvw->priv->xine, "xshm",
640
699
                                XINE_VISUAL_TYPE_X11, (void *) &vis); 
750
809
        xine_cfg_entry_t entry;
751
810
 
752
811
        path = g_build_path (G_DIR_SEPARATOR_S,
753
 
                        g_get_home_dir (), CONFIG_FILE, NULL);
 
812
                        g_get_user_config_dir (), CONFIG_FILE, NULL);
754
813
        xine_config_load (bvw->priv->xine, path);
755
814
        g_free (path);
756
815
 
770
829
        if (bvw->priv->gc == NULL)
771
830
                return;
772
831
 
773
 
        /* Disable CDDB, we'll use Musicbrainz instead */
 
832
        /* Disable the mixer polling for ALSA */
774
833
        bvw_config_helper_num (bvw->priv->xine,
775
 
                        "media.audio_cd.use_cddb", 1, &entry);
 
834
                        "audio.alsa_hw_mixer", 1, &entry);
776
835
        entry.num_value = 0;
777
836
        xine_config_update_entry (bvw->priv->xine, &entry);
778
837
 
888
947
}
889
948
 
890
949
static gboolean
891
 
bacon_video_widget_plugin_exists (BaconVideoWidget *bvw, const char *filename)
892
 
{
893
 
        char *path;
894
 
        gboolean res;
895
 
 
896
 
        path = g_build_filename (bvw->priv->codecs_path, filename, NULL);
897
 
        res = g_file_test (path, G_FILE_TEST_IS_REGULAR);
898
 
        g_free (path);
899
 
        return res;
900
 
}
901
 
 
902
 
static gboolean
903
950
video_window_translate_point (BaconVideoWidget *bvw, int gui_x, int gui_y,
904
951
                int *video_x, int *video_y)
905
952
{
1091
1138
size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw)
1092
1139
{
1093
1140
        double res_h, res_v, vis_width;
 
1141
        int vis_height, fps;
1094
1142
 
1095
1143
        res_h = gdk_screen_get_width (screen) * 1000 /
1096
1144
                gdk_screen_get_width_mm (screen);
1097
1145
        res_v = gdk_screen_get_height (screen) * 1000 /
1098
1146
                gdk_screen_get_height_mm (screen);
1099
1147
 
1100
 
        vis_width = vis_qualities[bvw->priv->quality].height *
1101
 
                gdk_screen_get_width (screen) /
 
1148
        if (bacon_video_widget_common_get_vis_quality (bvw->priv->quality, &vis_height, &fps) == FALSE)
 
1149
                return;
 
1150
 
 
1151
        vis_width = vis_height * gdk_screen_get_width (screen) /
1102
1152
                gdk_screen_get_height (screen);
1103
1153
 
1104
1154
        bvw->priv->display_ratio = res_v / res_h;
1108
1158
        }
1109
1159
 
1110
1160
        bacon_video_widget_set_visuals_quality_size (bvw,
1111
 
                        vis_width,
1112
 
                        vis_qualities[bvw->priv->quality].height,
1113
 
                        vis_qualities[bvw->priv->quality].fps);
 
1161
                        vis_width, vis_height, fps);
1114
1162
}
1115
1163
 
1116
1164
static void
1117
1165
bacon_video_widget_realize (GtkWidget *widget)
1118
1166
{
1119
1167
        GdkWindowAttr attr;
 
1168
        GdkColor black;
1120
1169
        BaconVideoWidget *bvw;
1121
1170
 
1122
1171
        bvw = BACON_VIDEO_WIDGET (widget);
1147
1196
        gdk_flush ();
1148
1197
        gdk_window_set_user_data (widget->window, bvw);
1149
1198
 
1150
 
        bvw->priv->video_window = widget->window;
1151
 
 
 
1199
        gdk_color_parse ("Black", &black);
 
1200
        gdk_colormap_alloc_color (gtk_widget_get_colormap (widget),
 
1201
                                  &black, TRUE, TRUE);
 
1202
        gdk_window_set_background (widget->window, &black);
1152
1203
        widget->style = gtk_style_attach (widget->style, widget->window);
1153
1204
 
1154
 
        /* Set a black background */
1155
 
        gdk_draw_rectangle (widget->window, widget->style->black_gc, TRUE,
1156
 
                        attr.x, attr.y,
1157
 
                        attr.width, attr.height);
1158
 
 
1159
1205
        /* track configure events of toplevel window */
1160
1206
        g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
1161
1207
                        "configure-event",
1162
1208
                        G_CALLBACK (configure_cb), bvw);
1163
1209
 
1164
1210
        /* get screen size changes */
1165
 
        g_signal_connect (G_OBJECT (gdk_screen_get_default ()),
 
1211
        g_signal_connect (G_OBJECT (gtk_widget_get_screen (widget)),
1166
1212
                        "size-changed", G_CALLBACK (size_changed_cb), bvw);
1167
1213
 
1168
1214
        /* Now onto the video out driver */
1170
1216
                        (gdk_display_get_default ()));
1171
1217
        bvw->priv->screen = DefaultScreen (bvw->priv->display);
1172
1218
 
1173
 
        bvw->priv->vo_driver = load_video_out_driver
1174
 
                (bvw, FALSE);
 
1219
        bvw->priv->vo_driver = load_video_out_driver (bvw, bvw->priv->type);
1175
1220
 
1176
1221
        if (bvw->priv->vo_driver == NULL)
1177
1222
        {
1178
1223
                signal_data *sigdata;
1179
1224
 
1180
 
                bvw->priv->vo_driver = load_video_out_driver (bvw, TRUE);
 
1225
                bvw->priv->vo_driver = load_video_out_driver
 
1226
                        (bvw, BVW_USE_TYPE_METADATA);
1181
1227
 
1182
1228
                /* We need to use an async signal, otherwise we try to
1183
1229
                 * unrealize the widget before it's finished realizing */
1205
1251
                bvw->priv->vis_name = NULL;
1206
1252
        }
1207
1253
 
1208
 
        bvw->priv->have_xvidmode = bacon_resize_init ();
 
1254
        bvw->priv->bacon_resize = bacon_resize_new (widget);
1209
1255
        bvw->priv->stream = xine_stream_new (bvw->priv->xine,
1210
1256
                        bvw->priv->ao_driver, bvw->priv->vo_driver);
1211
1257
        setup_config_stream (bvw);
1252
1298
                                0, data->msg);
1253
1299
                break;
1254
1300
        case EOS_ASYNC:
 
1301
                bacon_video_widget_reconfigure_tick (bvw, FALSE);
1255
1302
                g_signal_emit (G_OBJECT (bvw),
1256
1303
                                bvw_table_signals[EOS], 0, NULL);
 
1304
                g_object_notify (G_OBJECT (bvw), "seekable");
1257
1305
                break;
1258
1306
        case CHANNELS_CHANGE_ASYNC:
1259
1307
                g_signal_emit (G_OBJECT (bvw),
1260
1308
                                bvw_table_signals[CHANNELS_CHANGE], 0, NULL);
 
1309
                g_object_notify (G_OBJECT (bvw), "seekable");
1261
1310
                break;
1262
1311
        case BUFFERING_ASYNC:
1263
1312
                g_signal_emit (G_OBJECT (bvw),
1269
1318
                                bvw_table_signals[ERROR],
1270
1319
                                0, data->msg, TRUE, FALSE);
1271
1320
                break;
1272
 
        case SPEED_WARNING_ASYNC:
1273
 
                g_signal_emit (G_OBJECT (bvw),
1274
 
                                bvw_table_signals[SPEED_WARNING],
1275
 
                                0, NULL);
1276
 
                break;
1277
1321
        case ERROR_ASYNC:
1278
1322
                g_signal_emit (G_OBJECT (bvw),
1279
1323
                                bvw_table_signals[ERROR], 0,
1329
1373
                message = g_strdup (_("The specified movie could not be found."));
1330
1374
                break;
1331
1375
        case XINE_MSG_READ_ERROR:
1332
 
                if (g_str_has_prefix (bvw->priv->mrl, "dvd:") != FALSE)
 
1376
                if (g_str_has_prefix (bvw->com->mrl, "dvd:") != FALSE)
1333
1377
                {
1334
1378
                        num = BVW_ERROR_DVD_ENCRYPTED;
1335
1379
                        message = g_strdup (_("The source seems encrypted, and can't be read. Are you trying to play an encrypted DVD without libdvdcss?"));
1340
1384
                break;
1341
1385
        case XINE_MSG_LIBRARY_LOAD_ERROR:
1342
1386
                params = (char *) data + data->parameters;
1343
 
                if (bacon_video_widget_plugin_exists (bvw, params) == FALSE)
1344
 
                        return;
1345
1387
                /* Only if the file could really not be loaded */
1346
1388
                num = BVW_ERROR_PLUGIN_LOAD;
1347
1389
                message = g_strdup_printf (_("A problem occurred while loading a library or a decoder (%s)."), params);
1348
1390
                break;
1349
1391
        case XINE_MSG_ENCRYPTED_SOURCE:
1350
 
                if (g_str_has_prefix (bvw->priv->mrl, "dvd:") != FALSE)
 
1392
                if (g_str_has_prefix (bvw->com->mrl, "dvd:") != FALSE)
1351
1393
                {
1352
1394
                        num = BVW_ERROR_DVD_ENCRYPTED;
1353
1395
                        message = g_strdup (_("The source seems encrypted, and can't be read. Are you trying to play an encrypted DVD without libdvdcss?"));
1365
1407
                num = BVW_ERROR_AUDIO_BUSY;
1366
1408
                message = g_strdup (_("The audio device is busy. Is another application using it?"));
1367
1409
                break;
 
1410
#ifdef XINE_MSG_AUTHENTICATION_NEEDED /* xine-lib 1.2 */
 
1411
        case XINE_MSG_AUTHENTICATION_NEEDED:
 
1412
                num = BVW_ERROR_FILE_PERMISSION;
 
1413
                if (g_str_has_prefix (bvw->com->mrl, "file:") != FALSE)
 
1414
                        message = g_strdup (_("Authentication is required to access this file."));
 
1415
                else
 
1416
                        message = g_strdup (_("Authentication is required to access this file or stream."));
 
1417
                break;
 
1418
#endif /* XINE_MSG_AUTHENTICATION_NEEDED */
1368
1419
        case XINE_MSG_PERMISSION_ERROR:
1369
1420
                num = BVW_ERROR_FILE_PERMISSION;
1370
 
                if (g_str_has_prefix (bvw->priv->mrl, "file:") != FALSE)
 
1421
                if (g_str_has_prefix (bvw->com->mrl, "file:") != FALSE)
1371
1422
                        message = g_strdup (_("You are not allowed to open this file."));
1372
1423
                else
1373
1424
                        message = g_strdup (_("The server refused access to this file or stream."));
1374
1425
                break;
1375
 
 
1376
 
/* FIXME missing stuff from libxine includes (<= 1.1.x) */
1377
 
#ifndef XINE_MSG_FILE_EMPTY
1378
 
#define XINE_MSG_FILE_EMPTY 13
1379
 
#endif
1380
1426
        case XINE_MSG_FILE_EMPTY:
1381
1427
                num = BVW_ERROR_EMPTY_FILE;
1382
1428
                message  = g_strdup (_("The file you tried to play is an empty file."));
1419
1465
                                bvw->priv->cursor = NULL;
1420
1466
                        }
1421
1467
                }
1422
 
                gdk_window_set_cursor (bvw->priv->video_window,
1423
 
                                bvw->priv->cursor);
 
1468
                gdk_window_set_cursor (GTK_WIDGET(bvw)->window,
 
1469
                                       bvw->priv->cursor);
1424
1470
                break;
1425
1471
        case XINE_EVENT_UI_PLAYBACK_FINISHED:
1426
1472
                if (bvw->priv->got_redirect != FALSE)
1439
1485
                break;
1440
1486
        case XINE_EVENT_UI_SET_TITLE:
1441
1487
                ui_data = event->data;
1442
 
 
1443
 
                data = g_new0 (signal_data, 1);
1444
 
                data->signal = TITLE_CHANGE_ASYNC;
1445
 
                data->msg = g_strdup (ui_data->str);
1446
 
                g_async_queue_push (bvw->priv->queue, data);
1447
 
                g_idle_add ((GSourceFunc) bacon_video_widget_idle_signal, bvw);
 
1488
                data = NULL;
 
1489
 
 
1490
                if (g_utf8_validate (ui_data->str, -1, NULL) == FALSE) {
 
1491
                        char *utf8;
 
1492
 
 
1493
                        g_warning ("Metadata for updated title not in UTF-8 for mrl '%s'", bvw->com->mrl);
 
1494
                        utf8 = g_locale_to_utf8 (ui_data->str, -1, NULL, NULL, NULL);
 
1495
                        if (utf8 != NULL) {
 
1496
                                data = g_new0 (signal_data, 1);
 
1497
                                data->msg = utf8;
 
1498
                        }
 
1499
                } else {
 
1500
                        data = g_new0 (signal_data, 1);
 
1501
                        data->msg = g_strdup (ui_data->str);
 
1502
                }
 
1503
 
 
1504
                if (data != NULL) {
 
1505
                        data->signal = TITLE_CHANGE_ASYNC;
 
1506
                        g_async_queue_push (bvw->priv->queue, data);
 
1507
                        g_idle_add ((GSourceFunc) bacon_video_widget_idle_signal, bvw);
 
1508
                }
1448
1509
                break;
1449
1510
        case XINE_EVENT_PROGRESS:
1450
1511
                prg = event->data;
1451
1512
 
1452
1513
                data = g_new0 (signal_data, 1);
1453
1514
                data->signal = BUFFERING_ASYNC;
1454
 
                data->num = prg->percent;
 
1515
                if (prg->percent < 0)
 
1516
                        data->num = 0;
 
1517
                else if (prg->percent > 100)
 
1518
                        data->num = 100;
 
1519
                else
 
1520
                        data->num = prg->percent;
1455
1521
                g_async_queue_push (bvw->priv->queue, data);
1456
1522
                g_idle_add ((GSourceFunc) bacon_video_widget_idle_signal, bvw);
1457
1523
                break;
1468
1534
                xine_event_message (bvw, (xine_ui_message_data_t *)event->data);
1469
1535
                break;
1470
1536
        case XINE_EVENT_DROPPED_FRAMES:
1471
 
                data = g_new0 (signal_data, 1);
1472
 
                data->signal = SPEED_WARNING_ASYNC;
1473
 
                g_async_queue_push (bvw->priv->queue, data);
1474
 
                g_idle_add ((GSourceFunc) bacon_video_widget_idle_signal, bvw);
1475
1537
                break;
1476
1538
        case XINE_EVENT_AUDIO_LEVEL:
1477
1539
                /* Unhandled, we use the software mixer, not the hardware one */
1494
1556
        return 1;
1495
1557
}
1496
1558
 
1497
 
#if (!(GLIB_CHECK_VERSION(2,9,1)))
1498
 
static void
1499
 
bacon_video_widget_queue_sort (GAsyncQueue *queue)
1500
 
{
1501
 
        GList *list = NULL, *l;
1502
 
        signal_data *data;
1503
 
 
1504
 
        while ((data = g_async_queue_try_pop (queue)) != NULL) {
1505
 
                list = g_list_insert_sorted (list, data, (GCompareFunc) bacon_video_widget_sort_queue);
1506
 
        }
1507
 
 
1508
 
        if (list == NULL)
1509
 
                return;
1510
 
 
1511
 
        for (l = list; l != NULL; l = l->next) {
1512
 
                g_async_queue_push (queue, l->data);
1513
 
        }
1514
 
        g_list_free (list);
1515
 
}
1516
 
 
1517
 
#endif /* ! GLIB_CHECK_VERSION 2.9.1 */
1518
 
 
1519
1559
static void
1520
1560
xine_try_error (BaconVideoWidget *bvw, gboolean probe_error, GError **error)
1521
1561
{
1527
1567
        sched_yield ();
1528
1568
 
1529
1569
        /* Sort the queue with the errors first */
1530
 
#if GLIB_CHECK_VERSION(2,9,1)
1531
1570
        g_async_queue_sort (bvw->priv->queue, bacon_video_widget_sort_queue, NULL);
1532
 
#else
1533
 
        bacon_video_widget_queue_sort (bvw->priv->queue);
1534
 
#endif
1535
1571
 
1536
1572
        /* Steal messages from the async queue, if there's an error,
1537
1573
         * to use as the error message rather than the crappy errors from
1616
1652
 
1617
1653
        bvw = BACON_VIDEO_WIDGET (widget);
1618
1654
 
1619
 
        g_source_remove (bvw->priv->tick_id);
 
1655
        if (bvw->priv->tick_id > 0)
 
1656
                g_source_remove (bvw->priv->tick_id);
1620
1657
 
1621
1658
        speed = xine_get_param (bvw->priv->stream, XINE_PARAM_SPEED);
1622
1659
        if (speed != XINE_SPEED_PAUSE)
1629
1666
        /* Save the current volume */
1630
1667
        if (bacon_video_widget_can_set_volume (bvw) != FALSE)
1631
1668
        {
 
1669
                int vol;
 
1670
 
 
1671
                vol = (bvw->priv->volume * 100.0 + 0.5);
1632
1672
                gconf_client_set_int (bvw->priv->gc, GCONF_PREFIX"/volume",
1633
 
                                bvw->priv->volume, NULL);
 
1673
                                CLAMP (vol, 0, 100), NULL);
1634
1674
        }
1635
1675
 
1636
1676
        /* Kill the TV out */
1640
1680
 
1641
1681
        xine_port_send_gui_data (bvw->priv->vo_driver,
1642
1682
                        XINE_GUI_SEND_WILL_DESTROY_DRAWABLE,
1643
 
                        (void*)bvw->priv->video_window);
 
1683
                        (void*)widget->window);
 
1684
 
 
1685
        g_object_unref (bvw->priv->bacon_resize);
1644
1686
 
1645
1687
        /* Hide all windows */
1646
1688
        if (GTK_WIDGET_MAPPED (widget))
1654
1696
 
1655
1697
        /* save config */
1656
1698
        configfile = g_build_path (G_DIR_SEPARATOR_S,
1657
 
                        g_get_home_dir (), CONFIG_FILE, NULL);
 
1699
                        g_get_user_config_dir (), CONFIG_FILE, NULL);
1658
1700
        xine_config_save (bvw->priv->xine, configfile);
1659
1701
        g_free (configfile);
1660
1702
 
1679
1721
                (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1680
1722
}
1681
1723
 
1682
 
static struct poptOption xine_options[] = {
1683
 
        POPT_TABLEEND
1684
 
};
1685
 
 
1686
 
struct poptOption *
1687
 
bacon_video_widget_get_popt_table (void)
 
1724
GOptionGroup *
 
1725
bacon_video_widget_get_option_group (void)
1688
1726
{
1689
 
        /* Xine backend does not need any options */
1690
 
        return (struct poptOption *) xine_options;
 
1727
        return g_option_group_new ("xine", "Show xine-lib Options",
 
1728
                        "xine-lib Options", NULL, NULL);
1691
1729
}
1692
1730
 
1693
1731
void
1694
1732
bacon_video_widget_init_backend (int *argc, char ***argv)
1695
1733
{
1696
 
  /* no-op */
 
1734
        /* no-op */
1697
1735
}
1698
1736
 
1699
1737
GQuark
1720
1758
        bvw->priv->type = type;
1721
1759
        bvw->priv->audio_out_type = -1;
1722
1760
 
 
1761
        if (type == BVW_USE_TYPE_AUDIO || type == BVW_USE_TYPE_VIDEO)
 
1762
                pthread_mutex_init (&bvw->priv->queued_actions_mutex, NULL);
 
1763
 
1723
1764
        /* Don't load anything yet if we're looking for proper video
1724
1765
         * output */
1725
1766
        if (type == BVW_USE_TYPE_VIDEO)
1751
1792
         * load a video output with screen output, and capture is the
1752
1793
         * only one actually needing a video output */
1753
1794
        if (type == BVW_USE_TYPE_CAPTURE || type == BVW_USE_TYPE_METADATA) {
1754
 
                bvw->priv->vo_driver = load_video_out_driver (bvw, TRUE);
 
1795
                bvw->priv->vo_driver = load_video_out_driver (bvw, type);
1755
1796
        }
1756
1797
 
1757
1798
        /* Be extra careful about exiting out nicely when a video output
1767
1808
                bvw->priv->xine = NULL;
1768
1809
 
1769
1810
                /* get rid of all our crappety crap */
1770
 
                g_source_remove (bvw->priv->tick_id);
 
1811
                if (bvw->priv->tick_id > 0)
 
1812
                        g_source_remove (bvw->priv->tick_id);
1771
1813
                g_idle_remove_by_data (bvw);
1772
1814
                g_async_queue_unref (bvw->priv->queue);
1773
1815
                g_free (bvw->priv->vis_name);
1799
1841
bacon_video_widget_expose (GtkWidget *widget, GdkEventExpose *event)
1800
1842
{
1801
1843
        BaconVideoWidget *bvw = (BaconVideoWidget *) widget;
1802
 
        gboolean draw_logo, has_video;
1803
 
 
1804
 
        /* if there's only audio and no visualisation, draw the logo as well */
1805
 
        has_video = xine_get_stream_info(bvw->priv->stream,
1806
 
                        XINE_STREAM_INFO_HAS_VIDEO);
1807
 
        draw_logo = !has_video && !bvw->priv->using_vfx;
1808
 
 
1809
 
        if (bvw->priv->logo_mode == FALSE && draw_logo == FALSE) {
 
1844
 
 
1845
        if (bacon_video_widget_draw_logo (bvw) == FALSE) {
1810
1846
                XExposeEvent *expose;
1811
1847
 
1812
1848
                if (event->count != 0)
1813
 
                        return FALSE;
 
1849
                        return TRUE;
1814
1850
 
1815
1851
                expose = g_new0 (XExposeEvent, 1);
1816
1852
                expose->count = event->count;
1823
1859
                int s_width, s_height, w_width, w_height;
1824
1860
                GdkPixbuf *logo = NULL;
1825
1861
                gfloat ratio;
1826
 
 
1827
 
                /* Start with a nice black canvas */
1828
 
                gdk_draw_rectangle (widget->window, widget->style->black_gc,
1829
 
                                TRUE, 0, 0,
1830
 
                                widget->allocation.width,
1831
 
                                widget->allocation.height);
1832
 
 
1833
 
                if (bvw->priv->logo_pixbuf == NULL)
 
1862
                GdkRegion *region;
 
1863
                GdkRectangle rect;
 
1864
 
 
1865
                rect.x = rect.y = 0;
 
1866
                rect.width = widget->allocation.width;
 
1867
                rect.height = widget->allocation.height;
 
1868
                region = gdk_region_rectangle (&rect);
 
1869
 
 
1870
                gdk_window_begin_paint_region (widget->window,
 
1871
                                               region);
 
1872
                gdk_region_destroy (region);
 
1873
 
 
1874
                gdk_window_clear_area (widget->window,
 
1875
                                       0, 0,
 
1876
                                       widget->allocation.width,
 
1877
                                       widget->allocation.height);
 
1878
 
 
1879
                if (bvw->priv->logo_pixbuf == NULL) {
 
1880
                        gdk_window_end_paint (widget->window);
1834
1881
                        return FALSE;
 
1882
                }
1835
1883
 
1836
1884
                s_width = gdk_pixbuf_get_width (bvw->priv->logo_pixbuf);
1837
1885
                s_height = gdk_pixbuf_get_height (bvw->priv->logo_pixbuf);
1847
1895
                s_width *= ratio;
1848
1896
                s_height *= ratio;
1849
1897
 
 
1898
                if (s_width <= 1 || s_height <= 1) {
 
1899
                        gdk_window_end_paint (widget->window);
 
1900
                        return FALSE;
 
1901
                }
 
1902
 
1850
1903
                logo = gdk_pixbuf_scale_simple (bvw->priv->logo_pixbuf,
1851
1904
                                s_width, s_height, GDK_INTERP_BILINEAR);
1852
1905
 
1856
1909
                                (w_height - s_height) / 2,
1857
1910
                                s_width, s_height, GDK_RGB_DITHER_NONE, 0, 0);
1858
1911
 
1859
 
                gdk_pixbuf_unref (logo);
 
1912
                gdk_window_end_paint (widget->window);
 
1913
                g_object_unref (logo);
1860
1914
        }
1861
1915
 
1862
 
        return FALSE;
 
1916
        return TRUE;
1863
1917
}
1864
1918
 
1865
1919
static gboolean
1880
1934
{
1881
1935
        BaconVideoWidget *bvw = (BaconVideoWidget *) widget;
1882
1936
 
1883
 
        generate_mouse_event (bvw, (GdkEvent *)event, FALSE);
 
1937
        /* Don't propagate double-click events if we just had a button
 
1938
         * event consumed internally */
 
1939
        if (event->type == GDK_2BUTTON_PRESS && bvw->priv->bevent_consumed != FALSE) {
 
1940
                bvw->priv->bevent_consumed = FALSE;
 
1941
                return TRUE;
 
1942
        }
 
1943
 
 
1944
        /* If the event was consumed, mark it as such */
 
1945
        if (generate_mouse_event (bvw, (GdkEvent *)event, FALSE) != FALSE && bvw->priv->cursor != NULL) {
 
1946
                bvw->priv->bevent_consumed = TRUE;
 
1947
                return FALSE;
 
1948
        }
1884
1949
 
1885
1950
        if (GTK_WIDGET_CLASS (parent_class)->button_press_event != NULL)
1886
1951
                                (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
1891
1956
static void
1892
1957
bacon_video_widget_show (GtkWidget *widget)
1893
1958
{
1894
 
        BaconVideoWidget *bvw = (BaconVideoWidget *) widget;
1895
 
 
1896
 
        gdk_window_show (bvw->priv->video_window);
 
1959
        if (widget->window != NULL)
 
1960
                gdk_window_show (widget->window);
1897
1961
 
1898
1962
        if (GTK_WIDGET_CLASS (parent_class)->show != NULL)
1899
1963
                (* GTK_WIDGET_CLASS (parent_class)->show) (widget);
1902
1966
static void
1903
1967
bacon_video_widget_hide (GtkWidget *widget)
1904
1968
{
1905
 
        BaconVideoWidget *bvw = (BaconVideoWidget *) widget;
1906
 
 
1907
 
        gdk_window_hide (bvw->priv->video_window);
 
1969
        if (widget->window != NULL)
 
1970
                gdk_window_hide (widget->window);
1908
1971
 
1909
1972
        if (GTK_WIDGET_CLASS (parent_class)->hide != NULL)
1910
1973
                (* GTK_WIDGET_CLASS (parent_class)->hide) (widget);
1950
2013
        }
1951
2014
}
1952
2015
 
 
2016
static void
 
2017
bacon_video_widget_reconfigure_tick (BaconVideoWidget *bvw, gboolean enable)
 
2018
{
 
2019
        if (bvw->priv->tick_id != 0 && enable != FALSE)
 
2020
                return;
 
2021
        if (bvw->priv->tick_id == 0 && enable == FALSE)
 
2022
                return;
 
2023
 
 
2024
        if (enable == FALSE) {
 
2025
                g_source_remove (bvw->priv->tick_id);
 
2026
                bvw->priv->tick_id = 0;
 
2027
        } else {
 
2028
                bvw->priv->tick_id = g_timeout_add (140,
 
2029
                                                    (GSourceFunc) bacon_video_widget_tick_send,
 
2030
                                                    bvw);
 
2031
        }
 
2032
        bacon_video_widget_tick_send (bvw);
 
2033
}
 
2034
 
1953
2035
static gboolean
1954
2036
bacon_video_widget_tick_send (BaconVideoWidget *bvw)
1955
2037
{
1956
2038
        int current_time, stream_length, current_position;
1957
 
        float current_position_f;
 
2039
        double current_position_f;
1958
2040
        gboolean ret = TRUE, seekable;
1959
2041
 
1960
 
        if (bvw->priv->stream == NULL || bvw->priv->logo_mode != FALSE)
1961
 
                return TRUE;
 
2042
        g_return_val_if_fail (bvw->priv->stream != NULL, FALSE);
 
2043
        g_return_val_if_fail (bvw->priv->logo_mode == FALSE, FALSE);
1962
2044
 
1963
 
        if (bvw->priv->mrl == NULL)
 
2045
        if (bvw->com->mrl == NULL)
1964
2046
        {
1965
2047
                current_time = 0;
1966
2048
                stream_length = 0;
1975
2057
        if (ret == FALSE)
1976
2058
                return TRUE;
1977
2059
 
1978
 
        if (bvw->priv->seeking == 1)
 
2060
        if (bvw->priv->seeking == SEEKING_BY_FRACTION)
1979
2061
        {
1980
2062
                current_position_f = bvw->priv->seek_dest;
1981
2063
                current_time = bvw->priv->seek_dest * stream_length;
1982
 
        } else if (bvw->priv->seeking == 2) {
 
2064
        } else if (bvw->priv->seeking == SEEKING_BY_TIME) {
1983
2065
                current_time = bvw->priv->seek_dest_time;
1984
 
                current_position_f = (float) current_time / stream_length;
 
2066
                if (stream_length == 0)
 
2067
                        stream_length = current_time;
 
2068
                current_position_f = (double) current_time / stream_length;
1985
2069
        } else {
1986
 
                current_position_f = (float) current_position / 65535;
 
2070
                /* xine-lib doesn't update current_position if the stream
 
2071
                 * isn't seekable */
 
2072
                if ((current_position == 0 || current_position == 65535) && current_time > 0) {
 
2073
                        if (stream_length == 0)
 
2074
                                stream_length = current_time;
 
2075
                        current_position_f = (double) current_time / stream_length;
 
2076
                } else {
 
2077
                        current_position_f = ((double) current_position) / 65535;
 
2078
                }
1987
2079
        }
1988
2080
 
1989
2081
        if (stream_length > 0)
1991
2083
        else
1992
2084
                bvw->priv->is_live = TRUE;
1993
2085
 
1994
 
        if (stream_length != 0 && bvw->priv->mrl != NULL) {
 
2086
        if (stream_length != 0 && bvw->com->mrl != NULL) {
1995
2087
                seekable = xine_get_stream_info (bvw->priv->stream,
1996
2088
                                XINE_STREAM_INFO_SEEKABLE);
 
2089
                if (stream_length != bvw->priv->stream_length)
 
2090
                        g_object_notify (G_OBJECT (bvw), "seekable");
1997
2091
        } else {
1998
2092
                seekable = FALSE;
1999
2093
        }
2000
2094
 
 
2095
        bvw->priv->stream_length = stream_length;
 
2096
 
2001
2097
        g_signal_emit (G_OBJECT (bvw),
2002
 
                        bvw_table_signals[TICK], 0,
 
2098
                        bvw_table_signals[SIGNAL_TICK], 0,
2003
2099
                        (gint64) (current_time),
2004
2100
                        (gint64) (stream_length),
2005
2101
                        current_position_f,
2023
2119
 
2024
2120
        /* Already has video, and we were showing visual effects */
2025
2121
        if (has_video != FALSE && show_visuals != FALSE
2026
 
                        && bvw->priv->using_vfx != FALSE)
2027
 
        {
 
2122
                        && bvw->priv->using_vfx != FALSE) {
2028
2123
                enable = FALSE;
 
2124
                GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
2029
2125
        /* Doesn't have video, should show visual effects, and wasn't doing
2030
2126
         * so before */
2031
2127
        } else if (has_video == FALSE && show_visuals != FALSE
2032
 
                        && bvw->priv->using_vfx == FALSE)
2033
 
        {
 
2128
                        && bvw->priv->using_vfx == FALSE) {
2034
2129
                if (bvw->priv->vis == NULL) {
2035
2130
                        bvw->priv->vis = xine_post_init (bvw->priv->xine,
2036
2131
                                        bvw->priv->vis_name, 0,
2037
2132
                                        &bvw->priv->ao_driver,
2038
2133
                                        &bvw->priv->vo_driver);
2039
2134
                }
 
2135
                if (bvw->priv->vis == NULL && strcmp (bvw->priv->vis_name, "goom") != 0) {
 
2136
                        bvw->priv->vis = xine_post_init (bvw->priv->xine,
 
2137
                                        "goom", 0,
 
2138
                                        &bvw->priv->ao_driver,
 
2139
                                        &bvw->priv->vo_driver);
 
2140
                }
2040
2141
                if (bvw->priv->vis != NULL) {
2041
2142
                        enable = TRUE;
 
2143
                        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
2042
2144
                }
2043
2145
        /* Doesn't have video, but visual effects are disabled */
2044
2146
        } else if (has_video == FALSE && show_visuals == FALSE) {
2045
2147
                enable = FALSE;
2046
 
        /* No changes */
 
2148
                GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
 
2149
        /* No changes, but has video */
 
2150
        } else if (has_video != FALSE) {
 
2151
                GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
 
2152
                return;
 
2153
        /* No changes but doesn't have video */
2047
2154
        } else {
 
2155
                GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
2048
2156
                return;
2049
2157
        }
2050
2158
 
2144
2252
        return g_strdup_printf ("%s#subtitle:%s", mrl, subtitle_uri + strlen ("file://"));
2145
2253
}
2146
2254
 
 
2255
static void
 
2256
bacon_video_widget_open_async_error (BaconVideoWidget *bvw, GError *error)
 
2257
{
 
2258
        signal_data *sigdata;
 
2259
 
 
2260
        sigdata = g_new0 (signal_data, 1); 
 
2261
        sigdata->signal = ERROR_ASYNC;
 
2262
        sigdata->msg = g_strdup (error->message);
 
2263
        sigdata->fatal = FALSE;
 
2264
        g_async_queue_push (bvw->priv->queue, sigdata);
 
2265
        g_idle_add ((GSourceFunc) bacon_video_widget_idle_signal, bvw);
 
2266
}
 
2267
 
 
2268
static gpointer
 
2269
bacon_video_widget_open_thread (gpointer data)
 
2270
{
 
2271
        BaconVideoWidget *bvw = (BaconVideoWidget *) data;
 
2272
        GError *error = NULL;
 
2273
        int err;
 
2274
 
 
2275
        pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
 
2276
        err = xine_open (bvw->priv->stream, bvw->com->mrl);
 
2277
        pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
 
2278
        if (err == 0) {
 
2279
                xine_error (bvw, &error);
 
2280
                bacon_video_widget_close (bvw);
 
2281
                bacon_video_widget_open_async_error (bvw, error);
 
2282
                g_error_free (error);
 
2283
        } else {
 
2284
                xine_try_error (bvw, TRUE, &error);
 
2285
                if (error != NULL) {
 
2286
                        bacon_video_widget_close (bvw);
 
2287
                        bacon_video_widget_open_async_error (bvw, error);
 
2288
                        g_error_free (error);
 
2289
                } else {
 
2290
                        GList *l;
 
2291
 
 
2292
                        /* A few known commands before we crack on */
 
2293
                        xine_plugins_garbage_collector (bvw->priv->xine);
 
2294
                        show_vfx_update (bvw, bvw->priv->show_vfx);
 
2295
                        g_signal_emit (G_OBJECT (bvw),
 
2296
                                       bvw_table_signals[GOT_METADATA], 0, NULL);
 
2297
                        g_object_notify (G_OBJECT (bvw), "seekable");
 
2298
                        bacon_video_widget_tick_send (bvw);
 
2299
 
 
2300
                        pthread_mutex_lock (&bvw->priv->queued_actions_mutex);
 
2301
 
 
2302
                        /* This is so that we don't deadlock when calling the
 
2303
                         * real play() */
 
2304
                        bvw->priv->open_thread = 0;
 
2305
 
 
2306
                        for (l = bvw->priv->queued_actions; l != NULL; l = l->next) {
 
2307
                                int action;
 
2308
 
 
2309
                                action = GPOINTER_TO_INT (l->data);
 
2310
                                switch (action) {
 
2311
                                case BVW_XINE_PLAY:
 
2312
                                        bacon_video_widget_play (bvw, &error);
 
2313
                                        if (error != NULL) {
 
2314
                                                bacon_video_widget_close (bvw);
 
2315
                                                bacon_video_widget_open_async_error (bvw, error);
 
2316
                                                g_error_free (error);
 
2317
                                        }
 
2318
                                        break;
 
2319
                                case BVW_XINE_PAUSE:
 
2320
                                        bacon_video_widget_pause (bvw);
 
2321
                                        break;
 
2322
                                default:
 
2323
                                        g_assert_not_reached ();
 
2324
                                }
 
2325
                        }
 
2326
 
 
2327
                        g_list_free (bvw->priv->queued_actions);
 
2328
                        bvw->priv->queued_actions = NULL;
 
2329
                        pthread_mutex_unlock (&bvw->priv->queued_actions_mutex);
 
2330
                }
 
2331
        }
 
2332
 
 
2333
        bvw->priv->open_thread = 0;
 
2334
        return NULL;
 
2335
}
 
2336
 
 
2337
static gboolean
 
2338
bacon_video_widget_open_async (BaconVideoWidget *bvw, const char *mrl,
 
2339
                GError **error)
 
2340
{
 
2341
        if (pthread_create (&bvw->priv->open_thread, NULL, bacon_video_widget_open_thread, bvw) != 0) {
 
2342
                g_assert_not_reached ();
 
2343
                return FALSE;
 
2344
        }
 
2345
 
 
2346
        /* Make it so that the thread we just started is executed straight away,
 
2347
         * otherwise other events can occur before we start the open */
 
2348
        sched_yield ();
 
2349
 
 
2350
        return TRUE;
 
2351
}
 
2352
 
 
2353
#ifndef HAVE_GTK_ONLY
 
2354
/* Return a new MRL with a username and password embedded into it from the GNOME keychain.
 
2355
 * This function should be called right before sending a URL to xine-lib. */
 
2356
static char *
 
2357
add_auth_to_uri (const char* mrl)
 
2358
{
 
2359
        if (g_str_has_prefix (mrl, "http:") != FALSE) {
 
2360
                guint port;
 
2361
                const char *host, *scheme, *user;
 
2362
                GList *items;
 
2363
                GnomeKeyringResult result;
 
2364
                GnomeVFSURI* uri;
 
2365
                
 
2366
                uri = gnome_vfs_uri_new (mrl);
 
2367
                if (uri == NULL)
 
2368
                        return NULL;
 
2369
 
 
2370
                host = gnome_vfs_uri_get_host_name (uri);
 
2371
                user = gnome_vfs_uri_get_user_name (uri);
 
2372
                port = gnome_vfs_uri_get_host_port (uri);
 
2373
                scheme = gnome_vfs_uri_get_scheme (uri);
 
2374
 
 
2375
                result = gnome_keyring_find_network_password_sync (user, NULL,
 
2376
                                                                   host ,NULL,
 
2377
                                                                   scheme, NULL,
 
2378
                                                                   port, &items);
 
2379
 
 
2380
                if (result == GNOME_KEYRING_RESULT_OK && items != NULL) {
 
2381
                        char *parsed_uri;
 
2382
                        GnomeKeyringNetworkPasswordData *pwd_data;
 
2383
 
 
2384
                        pwd_data = items->data;
 
2385
 
 
2386
                        gnome_vfs_uri_set_user_name (uri, pwd_data->user);
 
2387
                        gnome_vfs_uri_set_password (uri, pwd_data->password);
 
2388
 
 
2389
                        parsed_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
 
2390
 
 
2391
                        gnome_keyring_network_password_list_free (items);
 
2392
                        gnome_vfs_uri_unref (uri);
 
2393
 
 
2394
                        return parsed_uri;
 
2395
                } else {
 
2396
                        gnome_vfs_uri_unref (uri);
 
2397
                }
 
2398
        }
 
2399
 
 
2400
        return NULL;
 
2401
}
 
2402
#endif /* !HAVE_GTK_ONLY */
 
2403
 
2147
2404
gboolean
2148
2405
bacon_video_widget_open_with_subtitle (BaconVideoWidget *bvw, const char *mrl,
2149
2406
                const char *subtitle_uri, GError **error)
2150
2407
{
2151
2408
        int err;
2152
 
        const char *layer;
2153
2409
 
2154
2410
        g_return_val_if_fail (mrl != NULL, FALSE);
2155
2411
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
2156
2412
        g_return_val_if_fail (bvw->priv->xine != NULL, FALSE);
2157
 
        g_return_val_if_fail (bvw->priv->mrl == NULL, FALSE);
 
2413
        g_return_val_if_fail (bvw->com->mrl == NULL, FALSE);
2158
2414
 
2159
2415
        bvw->priv->got_redirect = FALSE;
2160
2416
 
2161
2417
        /* Hack to get VCD playback from .cue files */
2162
2418
        if (g_str_has_prefix (mrl, "vcd:/") != FALSE
2163
2419
                        && g_str_has_suffix (mrl, ".cue") != FALSE) {
2164
 
                bvw->priv->mrl = g_strdup_printf ("%s@", mrl);
 
2420
                bvw->com->mrl = g_strdup_printf ("%s@", mrl);
 
2421
        } else if (g_str_has_prefix (mrl, "icy:") != FALSE) {
 
2422
                /* Handle "icy://" URLs from QuickTime */
 
2423
                bvw->com->mrl = g_strdup_printf ("http:%s", mrl + 4);
 
2424
        } else if (g_str_has_prefix (mrl, "icyx:") != FALSE) {
 
2425
                /* Handle "icyx://" URLs from Orban/Coding Technologies AAC/aacPlus Player */
 
2426
                bvw->com->mrl = g_strdup_printf ("http:%s", mrl + 5);
2165
2427
        } else {
2166
 
                bvw->priv->mrl = g_strdup (mrl);
2167
 
        }
2168
 
 
2169
 
        if (subtitle_uri != NULL)
2170
 
        {
 
2428
                bvw->com->mrl = g_strdup (mrl);
 
2429
        }
 
2430
 
 
2431
        if (g_str_has_prefix (mrl, "fd://") != FALSE) {
 
2432
                if (subtitle_uri != NULL)
 
2433
                        g_warning ("%s passed along with a subtitle URI", mrl);
 
2434
                return bacon_video_widget_open_async (bvw, mrl, error);
 
2435
        }
 
2436
 
 
2437
        if (subtitle_uri != NULL) {
2171
2438
                char *subtitled;
2172
2439
                subtitled = bacon_video_widget_get_subtitled (mrl, subtitle_uri);
2173
2440
                if (subtitled != NULL) {
2175
2442
                        bvw->priv->has_subtitle = TRUE;
2176
2443
                        g_free (subtitled);
2177
2444
                } else {
2178
 
                        err = xine_open (bvw->priv->stream, mrl);
 
2445
                        err = xine_open (bvw->priv->stream, bvw->com->mrl);
2179
2446
                }
2180
2447
        } else {
2181
 
                err = xine_open (bvw->priv->stream, mrl);
 
2448
                err = xine_open (bvw->priv->stream, bvw->com->mrl);
2182
2449
        }
2183
2450
 
2184
 
        xine_plugins_garbage_collector (bvw->priv->xine);
2185
 
 
2186
 
        if (err == 0)
2187
 
        {
2188
 
                bacon_video_widget_close (bvw);
 
2451
#ifndef HAVE_GTK_ONLY
 
2452
        /* If xine-lib reported a permission error, try to fetch credentials from the keychain and
 
2453
         * try xine_open again. This only applies to HTTP for now */
 
2454
        if (err == 0 && g_str_has_prefix (mrl, "http:") != FALSE) {
2189
2455
                xine_error (bvw, error);
 
2456
                
 
2457
                if (error != NULL && *error != NULL && g_error_matches (*error, BVW_ERROR, BVW_ERROR_FILE_PERMISSION)) {
 
2458
                        char *authed_mrl;
 
2459
 
 
2460
                        authed_mrl = add_auth_to_uri (bvw->com->mrl);
 
2461
                        if (authed_mrl != NULL) {
 
2462
                                g_clear_error (error);
 
2463
                                xine_close (bvw->priv->stream);
 
2464
                                err = xine_open (bvw->priv->stream, authed_mrl);
 
2465
                                g_free (authed_mrl);
 
2466
                        }
 
2467
                }
 
2468
        }
 
2469
#endif /* !HAVE_GTK_ONLY */
 
2470
        xine_plugins_garbage_collector (bvw->priv->xine);
 
2471
 
 
2472
        if (err == 0) {
 
2473
                bacon_video_widget_close (bvw);
 
2474
                if (error == NULL || *error == NULL)
 
2475
                        xine_error (bvw, error);
2190
2476
                return FALSE;
2191
2477
        } else {
2192
 
                xine_try_error (bvw, TRUE, error);
 
2478
                if (error == NULL || *error == NULL)
 
2479
                        xine_try_error (bvw, TRUE, error);
2193
2480
                if (error != NULL && *error != NULL) {
2194
2481
                        bacon_video_widget_close (bvw);
2195
2482
                        return FALSE;
2196
2483
                }
2197
2484
        }
2198
2485
 
2199
 
        layer = xine_get_meta_info (bvw->priv->stream,
2200
 
                        XINE_META_INFO_SYSTEMLAYER);
2201
 
        if ((strcmp (layer, "MNG") == 0 || strcmp (layer, "imagedmx") == 0)&& bvw->priv->logo_mode == FALSE)
2202
 
        {
2203
 
                bacon_video_widget_close (bvw);
2204
 
                g_set_error (error, BVW_ERROR, BVW_ERROR_STILL_IMAGE,
2205
 
                                _("This movie is a still image. You can open it with an image viewer."));
2206
 
                return FALSE;
2207
 
        }
2208
 
 
2209
 
        if (xine_get_stream_info (bvw->priv->stream,
2210
 
                                XINE_STREAM_INFO_VIDEO_HANDLED) == FALSE
 
2486
        if ((xine_get_stream_info (bvw->priv->stream,
 
2487
                                        XINE_STREAM_INFO_HAS_VIDEO) &&
 
2488
                xine_get_stream_info (bvw->priv->stream,
 
2489
                                XINE_STREAM_INFO_VIDEO_HANDLED) == FALSE)
2211
2490
                        || (xine_get_stream_info (bvw->priv->stream,
2212
2491
                                        XINE_STREAM_INFO_HAS_VIDEO) == FALSE
2213
2492
                                && xine_get_stream_info (bvw->priv->stream,
2238
2517
                return FALSE;
2239
2518
        }
2240
2519
 
2241
 
        if (xine_get_stream_info (bvw->priv->stream,
2242
 
                                XINE_STREAM_INFO_HAS_VIDEO) == FALSE
2243
 
                && bvw->priv->type != BVW_USE_TYPE_METADATA
2244
 
                && bvw->priv->ao_driver == NULL)
2245
 
        {
 
2520
        if (xine_get_stream_info (bvw->priv->stream, XINE_STREAM_INFO_HAS_VIDEO) == FALSE
 
2521
            && bvw->priv->type != BVW_USE_TYPE_METADATA
 
2522
            && bvw->priv->ao_driver == NULL) {
2246
2523
                bacon_video_widget_close (bvw);
2247
2524
 
2248
2525
                g_set_error (error, BVW_ERROR, BVW_ERROR_AUDIO_ONLY,
2253
2530
 
2254
2531
        show_vfx_update (bvw, bvw->priv->show_vfx);
2255
2532
 
 
2533
        /* Update metadata in the UI */
2256
2534
        g_signal_emit (G_OBJECT (bvw),
2257
2535
                        bvw_table_signals[GOT_METADATA], 0, NULL);
 
2536
        g_object_notify (G_OBJECT (bvw), "seekable");
 
2537
        bacon_video_widget_tick_send (bvw);
2258
2538
 
2259
2539
        return TRUE;
2260
2540
}
2264
2544
{
2265
2545
        int error;
2266
2546
 
2267
 
        g_return_val_if_fail (bvw != NULL, -1);
2268
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), -1);
2269
 
        g_return_val_if_fail (bvw->priv->xine != NULL, -1);
 
2547
        g_return_val_if_fail (bvw != NULL, FALSE);
 
2548
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
 
2549
        g_return_val_if_fail (bvw->priv->xine != NULL, FALSE);
2270
2550
 
2271
2551
        error = 1;
2272
2552
 
2273
 
        if (bvw->priv->seeking == 1)
2274
 
        {
2275
 
                error = xine_play (bvw->priv->stream,
2276
 
                                bvw->priv->seek_dest * 65535, 0);
2277
 
                bvw->priv->seeking = 0;
2278
 
        } else if (bvw->priv->seeking == 2) {
 
2553
        if (bvw->priv->open_thread != 0) {
 
2554
                pthread_mutex_lock (&bvw->priv->queued_actions_mutex);
 
2555
                bvw->priv->queued_actions = g_list_append (bvw->priv->queued_actions,
 
2556
                                                           GINT_TO_POINTER (BVW_XINE_PLAY));
 
2557
                pthread_mutex_unlock (&bvw->priv->queued_actions_mutex);
 
2558
                return TRUE;
 
2559
        }
 
2560
 
 
2561
        if (bvw->priv->seeking == SEEKING_BY_FRACTION) {
 
2562
                if (bvw->priv->stream_length != 0) {
 
2563
                        error = xine_play (bvw->priv->stream,
 
2564
                                           0, bvw->priv->seek_dest * bvw->priv->stream_length);
 
2565
                } else {
 
2566
                        error = xine_play (bvw->priv->stream,
 
2567
                                           bvw->priv->seek_dest * 65535, 0);
 
2568
                }
 
2569
                bvw->priv->seeking = SEEKING_BY_INVALID;
 
2570
        } else if (bvw->priv->seeking == SEEKING_BY_TIME) {
2279
2571
                error = xine_play (bvw->priv->stream, 0,
2280
2572
                                bvw->priv->seek_dest_time);
2281
 
                bvw->priv->seeking = 0;
 
2573
                bvw->priv->seeking = SEEKING_BY_INVALID;
2282
2574
        } else {
2283
2575
                int speed, status;
2284
2576
 
2292
2584
                        error = xine_play (bvw->priv->stream, 0, 0);
2293
2585
                }
2294
2586
 
2295
 
                bvw->priv->seeking = 0;
 
2587
                bvw->priv->seeking = SEEKING_BY_INVALID;
2296
2588
        }
2297
2589
 
2298
 
        if (error == 0)
2299
 
        {
 
2590
        if (error == 0) {
2300
2591
                xine_error (bvw, gerror);
2301
2592
                return FALSE;
2302
2593
        }
2303
2594
 
2304
 
        if (bvw->priv->queued_vis != NULL)
2305
 
        {
 
2595
        if (bvw->priv->queued_vis != NULL) {
2306
2596
                bacon_video_widget_set_visuals (bvw, bvw->priv->queued_vis);
2307
2597
                g_free (bvw->priv->queued_vis);
2308
2598
                bvw->priv->queued_vis = NULL;
2322
2612
                                        XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -1);
2323
2613
        }
2324
2614
 
 
2615
        bacon_video_widget_reconfigure_tick (bvw, TRUE);
 
2616
        g_object_notify (G_OBJECT (bvw), "seekable");
 
2617
 
2325
2618
        return TRUE;
2326
2619
}
2327
2620
 
2328
2621
gboolean
2329
2622
bacon_video_widget_can_direct_seek (BaconVideoWidget *bvw)
2330
2623
{
2331
 
        return FALSE;
 
2624
        g_return_val_if_fail (bvw != NULL, FALSE);
 
2625
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
 
2626
 
 
2627
        return bacon_video_widget_common_can_direct_seek (bvw->com);
2332
2628
}
2333
2629
 
2334
 
gboolean bacon_video_widget_seek (BaconVideoWidget *bvw, float position,
2335
 
                GError **gerror)
 
2630
gboolean bacon_video_widget_seek (BaconVideoWidget *bvw,
 
2631
                                  double position,
 
2632
                                  GError **gerror)
2336
2633
{
2337
2634
        int error, speed;
2338
2635
 
2343
2640
        speed = xine_get_param (bvw->priv->stream, XINE_PARAM_SPEED);
2344
2641
        if (speed == XINE_SPEED_PAUSE)
2345
2642
        {
2346
 
                bvw->priv->seeking = 1;
 
2643
                bvw->priv->seeking = SEEKING_BY_FRACTION;
2347
2644
                bvw->priv->seek_dest = position;
 
2645
                bacon_video_widget_tick_send (bvw);
2348
2646
                return TRUE;
2349
2647
        }
2350
2648
 
2351
 
        error = xine_play (bvw->priv->stream, position * 65535, 0);
 
2649
        if (bvw->priv->stream_length != 0) {
 
2650
                error = xine_play (bvw->priv->stream, 0,
 
2651
                                   position * bvw->priv->stream_length);
 
2652
        } else {
 
2653
                error = xine_play (bvw->priv->stream, position * 65535, 0);
 
2654
        }
2352
2655
 
2353
2656
        if (error == 0)
2354
2657
        {
2356
2659
                return FALSE;
2357
2660
        }
2358
2661
 
 
2662
        bacon_video_widget_reconfigure_tick (bvw, TRUE);
 
2663
 
2359
2664
        return TRUE;
2360
2665
}
2361
2666
 
2375
2680
        status = xine_get_status (bvw->priv->stream);
2376
2681
        if (speed == XINE_SPEED_PAUSE || status == XINE_STATUS_STOP)
2377
2682
        {
2378
 
                bvw->priv->seeking = 2;
 
2683
                bvw->priv->seeking = SEEKING_BY_TIME;
2379
2684
                bvw->priv->seek_dest_time = CLAMP (time, 0, length);
 
2685
                bacon_video_widget_tick_send (bvw);
2380
2686
                return TRUE;
2381
2687
        }
2382
2688
 
2383
 
        if (time > length && g_str_has_prefix (bvw->priv->mrl, "dvd:") == FALSE && g_str_has_prefix (bvw->priv->mrl, "vcd:") == FALSE) {
 
2689
        if (time > length && g_str_has_prefix (bvw->com->mrl, "dvd:") == FALSE && g_str_has_prefix (bvw->com->mrl, "vcd:") == FALSE) {
2384
2690
                signal_data *data;
2385
2691
 
2386
2692
                data = g_new0 (signal_data, 1);
2398
2704
                return FALSE;
2399
2705
        }
2400
2706
 
 
2707
        bacon_video_widget_reconfigure_tick (bvw, TRUE);
 
2708
 
2401
2709
        return TRUE;
2402
2710
}
2403
2711
 
2408
2716
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2409
2717
        g_return_if_fail (bvw->priv->xine != NULL);
2410
2718
 
 
2719
        pthread_mutex_lock (&bvw->priv->queued_actions_mutex);
 
2720
        g_list_free (bvw->priv->queued_actions);
 
2721
        bvw->priv->queued_actions = NULL;
 
2722
        pthread_mutex_unlock (&bvw->priv->queued_actions_mutex);
 
2723
 
2411
2724
        xine_stop (bvw->priv->stream);
 
2725
        bacon_video_widget_reconfigure_tick (bvw, FALSE);
 
2726
        g_object_notify (G_OBJECT (bvw), "seekable");
2412
2727
}
2413
2728
 
2414
2729
void
2418
2733
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2419
2734
        g_return_if_fail (bvw->priv->xine != NULL);
2420
2735
 
2421
 
        xine_stop (bvw->priv->stream);
 
2736
        if (bvw->priv->open_thread != 0
 
2737
                        && pthread_self () != bvw->priv->open_thread) {
 
2738
                /* Nicely wait for the timeout */
 
2739
                pthread_cancel (bvw->priv->open_thread);
 
2740
                pthread_join (bvw->priv->open_thread, NULL);
 
2741
                bvw->priv->open_thread = 0;
 
2742
        }
 
2743
 
 
2744
        bacon_video_widget_stop (bvw);
2422
2745
        xine_close (bvw->priv->stream);
2423
2746
        bvw->priv->has_subtitle = FALSE;
2424
 
        g_free (bvw->priv->mrl);
2425
 
        bvw->priv->mrl = NULL;
 
2747
        g_free (bvw->com->mrl);
 
2748
        bvw->com->mrl = NULL;
 
2749
        bvw->priv->stream_length = 0;
 
2750
 
 
2751
        g_object_notify (G_OBJECT (bvw), "seekable");
 
2752
        bacon_video_widget_reconfigure_tick (bvw, FALSE);
2426
2753
 
2427
2754
        if (bvw->priv->logo_mode == FALSE)
2428
2755
                g_signal_emit (G_OBJECT (bvw),
2448
2775
                bacon_video_widget_set_show_cursor (bvw,
2449
2776
                                g_value_get_boolean (value));
2450
2777
                break;
2451
 
        case PROP_MEDIADEV:
2452
 
                bacon_video_widget_set_media_device (bvw,
2453
 
                                g_value_get_string (value));
2454
 
                break;
2455
2778
        case PROP_SHOW_VISUALS:
2456
2779
                bacon_video_widget_set_show_visuals (bvw,
2457
2780
                                g_value_get_boolean (value));
2458
2781
                break;
 
2782
        case PROP_VOLUME:
 
2783
                bacon_video_widget_set_volume (bvw, g_value_get_double (value));
 
2784
                break;
2459
2785
        default:
2460
2786
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2461
2787
        }
2476
2802
                                bacon_video_widget_get_logo_mode (bvw));
2477
2803
                break;
2478
2804
        case PROP_POSITION:
2479
 
                g_value_set_int64 (value, bacon_video_widget_get_position (bvw));
 
2805
                g_value_set_double (value, bacon_video_widget_get_position (bvw));
2480
2806
                break;
2481
2807
        case PROP_STREAM_LENGTH:
2482
2808
                g_value_set_int64 (value,
2494
2820
                g_value_set_boolean (value,
2495
2821
                                bacon_video_widget_get_show_cursor (bvw));
2496
2822
                break;
2497
 
        case PROP_MEDIADEV:
2498
 
                g_value_set_string (value, bvw->priv->mediadev);
 
2823
        case PROP_VOLUME:
 
2824
                g_value_set_double (value, bvw->priv->volume);
2499
2825
                break;
2500
2826
        default:
2501
2827
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2515
2841
                /* Queue a redraw of the widget */
2516
2842
                gtk_widget_queue_draw (GTK_WIDGET (bvw));
2517
2843
 
 
2844
                if (logo_mode == FALSE)
 
2845
                        GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
 
2846
                else
 
2847
                        GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
 
2848
 
2518
2849
                /* And set a decent size for the video output */
2519
2850
                if (logo_mode != FALSE && bvw->priv->logo_pixbuf != NULL) {
2520
2851
                        bvw->priv->video_width = gdk_pixbuf_get_width (bvw->priv->logo_pixbuf);
2524
2855
                        bvw->priv->video_height = DEFAULT_HEIGHT;
2525
2856
                }
2526
2857
        }
 
2858
        g_object_notify (G_OBJECT (bvw), "logo_mode");
2527
2859
}
2528
2860
 
2529
2861
void
2535
2867
        g_return_if_fail (BACON_IS_VIDEO_WIDGET(bvw));
2536
2868
        g_return_if_fail (bvw->priv->xine != NULL);
2537
2869
        g_return_if_fail (filename != NULL);
2538
 
        g_return_if_fail (bvw->priv->logo_pixbuf == NULL);
 
2870
 
 
2871
        if (bvw->priv->logo_pixbuf != NULL)
 
2872
                g_object_unref (bvw->priv->logo_pixbuf);
2539
2873
 
2540
2874
        bvw->priv->logo_pixbuf = gdk_pixbuf_new_from_file (filename, &err);
2541
2875
        if (err) {
2545
2879
        }
2546
2880
}
2547
2881
 
 
2882
void
 
2883
bacon_video_widget_set_logo_pixbuf (BaconVideoWidget *bvw, GdkPixbuf *logo)
 
2884
{
 
2885
        g_return_if_fail (bvw != NULL);
 
2886
        g_return_if_fail (BACON_IS_VIDEO_WIDGET(bvw));
 
2887
        g_return_if_fail (bvw->priv->xine != NULL);
 
2888
        g_return_if_fail (logo != NULL);
 
2889
 
 
2890
        if (bvw->priv->logo_pixbuf != NULL)
 
2891
                g_object_unref (bvw->priv->logo_pixbuf);
 
2892
 
 
2893
        g_object_ref (logo);
 
2894
        bvw->priv->logo_pixbuf = logo;
 
2895
}
 
2896
 
2548
2897
gboolean
2549
2898
bacon_video_widget_get_logo_mode (BaconVideoWidget *bvw)
2550
2899
{
2562
2911
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2563
2912
        g_return_if_fail (bvw->priv->xine != NULL);
2564
2913
 
 
2914
        if (bvw->priv->open_thread != 0) {
 
2915
                pthread_mutex_lock (&bvw->priv->queued_actions_mutex);
 
2916
                bvw->priv->queued_actions = g_list_append (bvw->priv->queued_actions,
 
2917
                                                           GINT_TO_POINTER (BVW_XINE_PAUSE));
 
2918
                pthread_mutex_unlock (&bvw->priv->queued_actions_mutex);
 
2919
                return;
 
2920
        }
 
2921
 
2565
2922
        xine_set_param (bvw->priv->stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
2566
2923
 
2567
2924
        if (bvw->priv->is_live != FALSE)
2570
2927
        /* Close the audio device when on pause */
2571
2928
        xine_set_param (bvw->priv->stream,
2572
2929
                        XINE_PARAM_AUDIO_CLOSE_DEVICE, 1);
 
2930
 
 
2931
        bacon_video_widget_reconfigure_tick (bvw, FALSE);
2573
2932
}
2574
2933
 
2575
 
float
 
2934
double
2576
2935
bacon_video_widget_get_position (BaconVideoWidget *bvw)
2577
2936
{
2578
2937
        int pos_stream = 0, i = 0;
2583
2942
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
2584
2943
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
2585
2944
 
2586
 
        if (bvw->priv->mrl == NULL)
 
2945
        if (bvw->com->mrl == NULL)
2587
2946
                return 0;
2588
2947
 
2589
2948
        if (bacon_video_widget_is_playing (bvw) == FALSE)
2600
2959
                i++;
2601
2960
        }
2602
2961
 
2603
 
        if (bvw->priv->seeking == 1)
2604
 
        {
2605
 
                return bvw->priv->seek_dest * length_time;
2606
 
        } else if (bvw->priv->seeking == 2) {
2607
 
                return bvw->priv->seek_dest_time;
 
2962
        if (bvw->priv->seeking == SEEKING_BY_FRACTION) {
 
2963
                return bvw->priv->seek_dest;
 
2964
        } else if (bvw->priv->seeking == SEEKING_BY_TIME) {
 
2965
                return (double) bvw->priv->seek_dest_time / bvw->priv->stream_length;
2608
2966
        }
2609
2967
 
2610
2968
        if (ret == FALSE)
2611
2969
                return -1;
2612
2970
 
2613
 
        return pos_stream / 65535;
 
2971
        return (double) pos_stream / 65535;
2614
2972
}
2615
2973
 
2616
2974
gboolean
2617
2975
bacon_video_widget_can_set_volume (BaconVideoWidget *bvw)
2618
2976
{
2619
 
        g_return_val_if_fail (bvw != NULL, 0);
2620
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
2621
 
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
 
2977
        g_return_val_if_fail (bvw != NULL, FALSE);
 
2978
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
 
2979
        g_return_val_if_fail (bvw->priv->xine != NULL, FALSE);
2622
2980
 
2623
2981
        if (bvw->priv->ao_driver == NULL || bvw->priv->ao_driver_none != FALSE)
2624
2982
                return FALSE;
2634
2992
}
2635
2993
 
2636
2994
void
2637
 
bacon_video_widget_set_volume (BaconVideoWidget *bvw, int volume)
 
2995
bacon_video_widget_set_volume (BaconVideoWidget *bvw, double volume)
2638
2996
{
2639
 
        g_return_if_fail (bvw != NULL);
2640
2997
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2641
2998
        g_return_if_fail (bvw->priv->xine != NULL);
2642
2999
 
2643
3000
        if (bacon_video_widget_can_set_volume (bvw) != FALSE)
2644
3001
        {
 
3002
                bvw->priv->volume = volume;
 
3003
 
 
3004
                volume = volume * 100 + 0.5;
2645
3005
                volume = CLAMP (volume, 0, 100);
2646
3006
                xine_set_param (bvw->priv->stream,
2647
3007
                                XINE_PARAM_AUDIO_AMP_LEVEL, volume);
2648
 
                bvw->priv->volume = volume;
 
3008
                g_object_notify (G_OBJECT (bvw), "volume");
2649
3009
        }
2650
3010
}
2651
3011
 
2652
 
int
 
3012
double
2653
3013
bacon_video_widget_get_volume (BaconVideoWidget *bvw)
2654
3014
{
2655
 
        g_return_val_if_fail (bvw != NULL, 0);
2656
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
2657
 
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
 
3015
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0.0);
 
3016
        g_return_val_if_fail (bvw->priv->xine != NULL, 0.0);
2658
3017
 
2659
3018
        if (bacon_video_widget_can_set_volume (bvw) == FALSE)
2660
 
                return 0;
 
3019
                return 0.0;
2661
3020
 
2662
3021
        return bvw->priv->volume;
2663
3022
}
2692
3051
void
2693
3052
bacon_video_widget_set_fullscreen (BaconVideoWidget *bvw, gboolean fullscreen)
2694
3053
{
 
3054
        gboolean have_xvidmode;
 
3055
 
2695
3056
        g_return_if_fail (bvw != NULL);
2696
3057
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2697
3058
 
2698
 
        if (bvw->priv->have_xvidmode == FALSE &&
 
3059
        g_object_get (G_OBJECT (bvw->priv->bacon_resize),
 
3060
                                "have-xvidmode", &have_xvidmode,
 
3061
                                NULL);
 
3062
 
 
3063
        if (have_xvidmode == FALSE &&
2699
3064
                        bvw->priv->tvout != TV_OUT_NVTV_NTSC &&
2700
3065
                        bvw->priv->tvout != TV_OUT_NVTV_PAL)
2701
3066
                return;
2712
3077
                        /* Else if just auto resize is used */
2713
3078
                } else if (bvw->priv->auto_resize != FALSE) {
2714
3079
#endif
2715
 
                        bacon_restore ();
 
3080
                        bacon_resize_restore (bvw->priv->bacon_resize);
2716
3081
#ifdef HAVE_NVTV
2717
3082
                }
2718
3083
                /* Turn fullscreen on with NVTV if that option is on */
2723
3088
                                bvw->priv->video_height);
2724
3089
#endif
2725
3090
                /* Turn fullscreen on when we have xvidmode */
2726
 
        } else if (bvw->priv->have_xvidmode != FALSE) {
2727
 
                bacon_resize ();
 
3091
        } else if (have_xvidmode != FALSE) {
 
3092
                bacon_resize_resize (bvw->priv->bacon_resize);
2728
3093
        }
2729
3094
}
2730
3095
 
2731
3096
void
2732
3097
bacon_video_widget_set_show_cursor (BaconVideoWidget *bvw,
2733
 
                gboolean show_cursor)
 
3098
                                    gboolean show_cursor)
2734
3099
{
2735
3100
        g_return_if_fail (bvw != NULL);
2736
3101
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2737
3102
 
2738
3103
        if (show_cursor == FALSE)
2739
3104
        {
2740
 
                totem_gdk_window_set_invisible_cursor (bvw->priv->video_window);
 
3105
                totem_gdk_window_set_invisible_cursor (GTK_WIDGET(bvw)->window);
2741
3106
        } else {
2742
 
                gdk_window_set_cursor (bvw->priv->video_window,
2743
 
                                bvw->priv->cursor);
 
3107
                gdk_window_set_cursor (GTK_WIDGET(bvw)->window,
 
3108
                                       bvw->priv->cursor);
2744
3109
        }
2745
3110
 
2746
3111
        bvw->priv->cursor_shown = show_cursor;
2757
3122
}
2758
3123
 
2759
3124
void
2760
 
bacon_video_widget_set_media_device (BaconVideoWidget *bvw, const char *path)
2761
 
{
2762
 
        xine_cfg_entry_t entry;
2763
 
 
2764
 
        g_return_if_fail (bvw != NULL);
2765
 
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2766
 
        g_return_if_fail (path != NULL);
2767
 
 
2768
 
        g_free (bvw->priv->mediadev);
2769
 
 
2770
 
        /* DVD device */
2771
 
        bvw_config_helper_string (bvw->priv->xine, "media.dvd.device",
2772
 
                        path, &entry);
2773
 
        entry.str_value = (char *) path;
2774
 
        xine_config_update_entry (bvw->priv->xine, &entry);
2775
 
 
2776
 
        /* VCD device */
2777
 
        bvw_config_helper_string (bvw->priv->xine, "media.vcd.device",
2778
 
                        path, &entry);
2779
 
        entry.str_value = (char *) path;
2780
 
        xine_config_update_entry (bvw->priv->xine, &entry);
2781
 
 
2782
 
        /* VCD device for the new input plugin */
2783
 
        bvw_config_helper_string (bvw->priv->xine, "media.vcd.device",
2784
 
                        path, &entry);
2785
 
        entry.str_value = (char *) path;
2786
 
        xine_config_update_entry (bvw->priv->xine, &entry);
2787
 
 
2788
 
        /* CDDA device */
2789
 
        bvw_config_helper_string (bvw->priv->xine, "media.audio_cd.device",
2790
 
                        path, &entry);
2791
 
        entry.str_value = (char *) path;
2792
 
        xine_config_update_entry (bvw->priv->xine, &entry);
2793
 
 
2794
 
        bvw->priv->mediadev = g_strdup (path);
2795
 
}
2796
 
 
2797
 
void
2798
3125
bacon_video_widget_set_connection_speed (BaconVideoWidget *bvw, int speed)
2799
3126
{
2800
3127
        xine_cfg_entry_t entry;
2811
3138
                        6,
2812
3139
                        (char **) mms_bandwidth_strs,
2813
3140
                        "Network bandwidth",
2814
 
                        NULL, 0, NULL, NULL);
 
3141
                        NULL, 11, NULL, NULL);
2815
3142
 
2816
3143
        xine_config_lookup_entry (bvw->priv->xine,
2817
3144
                        "media.network.bandwidth", &entry);
2833
3160
                        6,
2834
3161
                        (char **) mms_bandwidth_strs,
2835
3162
                        "Network bandwidth",
2836
 
                        NULL, 0, NULL, NULL);
 
3163
                        NULL, 11, NULL, NULL);
2837
3164
 
2838
3165
        xine_config_lookup_entry (bvw->priv->xine,
2839
3166
                        "media.network.bandwidth", &entry);
2863
3190
        return xine_get_param (bvw->priv->stream, XINE_PARAM_VO_DEINTERLACE);
2864
3191
}
2865
3192
 
2866
 
gboolean
 
3193
void
2867
3194
bacon_video_widget_set_tv_out (BaconVideoWidget *bvw, TvOutType tvout)
2868
3195
{
2869
 
        g_return_val_if_fail (bvw != NULL, FALSE);
2870
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
2871
 
        g_return_val_if_fail (bvw->priv->xine != NULL, FALSE);
 
3196
        g_return_if_fail (bvw != NULL);
 
3197
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
3198
        g_return_if_fail (bvw->priv->xine != NULL);
2872
3199
 
2873
3200
#ifdef HAVE_NVTV
2874
3201
        if (tvout == TV_OUT_NVTV_PAL) {
2879
3206
#endif
2880
3207
 
2881
3208
        bvw->priv->tvout = tvout;
2882
 
 
2883
 
        return FALSE;
2884
3209
}
2885
3210
 
2886
3211
TvOutType
3009
3334
        g_return_if_fail (bvw != NULL);
3010
3335
        g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
3011
3336
        g_return_if_fail (bvw->priv->xine != NULL);
3012
 
        g_return_if_fail (quality < NUM_VISUAL_QUALITIES);
3013
3337
 
3014
 
        fps = vis_qualities[quality].fps;
3015
 
        h = vis_qualities[quality].height;
 
3338
        if (bacon_video_widget_common_get_vis_quality (quality, &h, &fps) == FALSE)
 
3339
                return;
3016
3340
 
3017
3341
        screen = gtk_widget_get_screen (GTK_WIDGET (bvw));
3018
 
        w = vis_qualities[quality].height *
3019
 
                gdk_screen_get_width (screen) /
3020
 
                gdk_screen_get_height (screen);
 
3342
        w = h * gdk_screen_get_width (screen) / gdk_screen_get_height (screen);
3021
3343
        bacon_video_widget_set_visuals_quality_size (bvw, w, h, fps);
3022
3344
 
3023
3345
        bvw->priv->quality = quality;
3071
3393
                i++;
3072
3394
        }
3073
3395
 
3074
 
        if (bvw->priv->seeking == 1)
 
3396
        if (bvw->priv->seeking == SEEKING_BY_FRACTION)
3075
3397
        {
3076
3398
                return bvw->priv->seek_dest * length_time;
3077
 
        } else if (bvw->priv->seeking == 2) {
 
3399
        } else if (bvw->priv->seeking == SEEKING_BY_TIME) {
3078
3400
                return bvw->priv->seek_dest_time;
3079
3401
        }
3080
3402
 
3094
3416
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
3095
3417
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
3096
3418
 
3097
 
        if (bvw->priv->mrl == NULL)
 
3419
        if (bvw->com->mrl == NULL)
3098
3420
                return 0;
3099
3421
 
3100
 
        xine_get_pos_length (bvw->priv->stream, &pos_stream,
3101
 
                        &pos_time, &length_time);
 
3422
        if (xine_get_pos_length (bvw->priv->stream, &pos_stream,
 
3423
                        &pos_time, &length_time) == FALSE) {
 
3424
                return (gint64) bvw->priv->stream_length;
 
3425
        }
 
3426
 
 
3427
        if (length_time != bvw->priv->stream_length)
 
3428
                bvw->priv->stream_length = length_time;
3102
3429
 
3103
3430
        return length_time;
3104
3431
}
3106
3433
gboolean
3107
3434
bacon_video_widget_is_playing (BaconVideoWidget *bvw)
3108
3435
{
3109
 
        g_return_val_if_fail (bvw != NULL, 0);
3110
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
3111
 
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
 
3436
        g_return_val_if_fail (bvw != NULL, FALSE);
 
3437
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
 
3438
        g_return_val_if_fail (bvw->priv->xine != NULL, FALSE);
3112
3439
 
3113
3440
        if (bvw->priv->stream == NULL)
3114
3441
                return FALSE;
3115
3442
 
3116
 
        return (xine_get_status (bvw->priv->stream) == XINE_STATUS_PLAY && xine_get_param (bvw->priv->stream, XINE_PARAM_SPEED) == XINE_SPEED_NORMAL);
 
3443
        return (xine_get_status (bvw->priv->stream) == XINE_STATUS_PLAY && xine_get_param (bvw->priv->stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE);
3117
3444
}
3118
3445
 
3119
3446
gboolean
3120
3447
bacon_video_widget_is_seekable (BaconVideoWidget *bvw)
3121
3448
{
3122
 
        g_return_val_if_fail (bvw != NULL, 0);
3123
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
3124
 
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
 
3449
        g_return_val_if_fail (bvw != NULL, FALSE);
 
3450
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
 
3451
        g_return_val_if_fail (bvw->priv->xine != NULL, FALSE);
3125
3452
 
3126
 
        if (bvw->priv->mrl == NULL)
 
3453
        if (bvw->com->mrl == NULL)
3127
3454
                return FALSE;
3128
3455
 
3129
3456
        if (bacon_video_widget_get_stream_length (bvw) == 0)
3133
3460
                        XINE_STREAM_INFO_SEEKABLE);
3134
3461
}
3135
3462
 
3136
 
gboolean
3137
 
bacon_video_widget_can_play (BaconVideoWidget *bvw, MediaType type)
 
3463
BaconVideoWidgetCanPlayStatus
 
3464
bacon_video_widget_can_play (BaconVideoWidget *bvw, TotemDiscMediaType type)
3138
3465
{
3139
3466
        switch (type)
3140
3467
        {
3141
3468
        case MEDIA_TYPE_DVD:
3142
 
                return bvw->priv->can_dvd;
 
3469
                if (bvw->priv->can_dvd != FALSE)
 
3470
                        return BVW_CAN_PLAY_SUCCESS;
 
3471
                break;
3143
3472
        case MEDIA_TYPE_VCD:
3144
 
                return bvw->priv->can_vcd;
 
3473
                if (bvw->priv->can_vcd != FALSE)
 
3474
                        return BVW_CAN_PLAY_SUCCESS;
 
3475
                break;
 
3476
        case MEDIA_TYPE_DVB:
 
3477
                if (bvw->priv->can_dvb != FALSE) {
 
3478
                        char *path;
 
3479
 
 
3480
                        path = g_build_filename (g_get_home_dir (),
 
3481
                                                 ".xine",
 
3482
                                                 "channels.conf",
 
3483
                                                 NULL);
 
3484
                        if (g_file_test (path, G_FILE_TEST_IS_REGULAR) == FALSE) {
 
3485
                                g_free (path);
 
3486
                                return BVW_CAN_PLAY_MISSING_CHANNELS;
 
3487
                        }
 
3488
                        g_free (path);
 
3489
                        return BVW_CAN_PLAY_SUCCESS;
 
3490
                }
 
3491
                break;
3145
3492
        case MEDIA_TYPE_CDDA:
3146
 
                return bvw->priv->can_cdda;
3147
3493
        default:
3148
 
                return FALSE;
 
3494
                return BVW_CAN_PLAY_UNSUPPORTED;
3149
3495
        }
3150
 
}
3151
 
 
3152
 
char
3153
 
**bacon_video_widget_get_mrls (BaconVideoWidget *bvw, MediaType type)
3154
 
{
3155
 
        char *plugin_id;
 
3496
 
 
3497
        return BVW_CAN_PLAY_MISSING_PLUGINS;
 
3498
}
 
3499
 
 
3500
static char *
 
3501
bacon_video_widget_strdupnv (const char **mrls, int num_mrls)
 
3502
{
 
3503
        guint i;
 
3504
        char **retval;
 
3505
 
 
3506
        retval = g_new (gchar*, num_mrls + 1);
 
3507
        for (i = 0; i < num_mrls; i++)
 
3508
                retval[i] = g_strdup (mrls[i]);
 
3509
        retval[num_mrls] = NULL;
 
3510
 
 
3511
        return retval;
 
3512
}
 
3513
 
 
3514
char **
 
3515
bacon_video_widget_get_mrls (BaconVideoWidget *bvw,
 
3516
                             TotemDiscMediaType type,
 
3517
                             const char *device)
 
3518
{
 
3519
        const char *plugin_id, *entry_name;
3156
3520
        int num_mrls;
3157
 
 
3158
 
        g_return_val_if_fail (bvw != NULL, 0);
3159
 
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 0);
3160
 
        g_return_val_if_fail (bvw->priv->xine != NULL, 0);
3161
 
 
3162
 
        if (type == MEDIA_TYPE_DVD)
 
3521
        char **mrls;
 
3522
 
 
3523
        g_return_val_if_fail (bvw != NULL, NULL);
 
3524
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
 
3525
        g_return_val_if_fail (bvw->priv->xine != NULL, NULL);
 
3526
        //FIXME enable when we use devices for DVB
 
3527
        //g_return_val_if_fail (device != NULL, NULL);
 
3528
 
 
3529
        entry_name = plugin_id = NULL;
 
3530
 
 
3531
        if (type == MEDIA_TYPE_DVD) {
3163
3532
                plugin_id = "DVD";
3164
 
        else if (type == MEDIA_TYPE_VCD)
 
3533
                entry_name = "media.dvd.device";
 
3534
        } else if (type == MEDIA_TYPE_VCD) {
3165
3535
                plugin_id = "VCD";
3166
 
        else if (type == MEDIA_TYPE_CDDA)
3167
 
                plugin_id = "CD";
3168
 
        else
 
3536
                entry_name = "media.vcd.device";
 
3537
        } else if (type == MEDIA_TYPE_DVB) {
 
3538
                plugin_id = "DVB";
 
3539
        }
 
3540
 
 
3541
        if (entry_name != NULL) {
 
3542
                xine_cfg_entry_t entry;
 
3543
                bvw_config_helper_string (bvw->priv->xine,
 
3544
                                          entry_name,
 
3545
                                          device, &entry);
 
3546
                entry.str_value = (char *) device;
 
3547
                xine_config_update_entry (bvw->priv->xine, &entry);
 
3548
        }
 
3549
 
 
3550
        mrls = xine_get_autoplay_mrls (bvw->priv->xine, plugin_id, &num_mrls);
 
3551
        if (mrls == NULL)
3169
3552
                return NULL;
3170
3553
 
3171
 
        return g_strdupv (xine_get_autoplay_mrls
3172
 
                (bvw->priv->xine, plugin_id, &num_mrls));
 
3554
        /* Add the device to the MRL for DVD,
 
3555
         * VCD already does that for us */
 
3556
        if (type == MEDIA_TYPE_DVD) {
 
3557
                if (strcmp (mrls[0], "dvd:/") == 0) {
 
3558
                        char *uris[] = { NULL, NULL };
 
3559
                        uris[0] = g_strdup_printf ("dvd://%s", device);
 
3560
                        mrls = g_strdupv (uris);
 
3561
                        return mrls;
 
3562
                }
 
3563
        } else if (type == MEDIA_TYPE_DVB) {
 
3564
                /* No channels.conf, and we couldn't find it */
 
3565
                if (g_str_has_prefix (mrls[0], "Sorry") != FALSE)
 
3566
                        return NULL;
 
3567
                /* The first channel can be the last channel played,
 
3568
                 * or a copy of the first one, ignore it */
 
3569
                return bacon_video_widget_strdupnv (mrls++, num_mrls - 1);
 
3570
        }
 
3571
 
 
3572
        return bacon_video_widget_strdupnv (mrls, num_mrls);
3173
3573
}
3174
3574
 
3175
3575
void
3176
3576
bacon_video_widget_set_subtitle_font (BaconVideoWidget *bvw, const char *font)
3177
3577
{
3178
 
        //FIXME
 
3578
        xine_cfg_entry_t entry;
 
3579
        int fontsize, size_index;
 
3580
        PangoFontDescription *desc;
 
3581
#if 0
 
3582
        const char *font_family;
 
3583
#endif
 
3584
        desc = pango_font_description_from_string (font);
 
3585
        fontsize = pango_font_description_get_size (desc) / PANGO_SCALE;
 
3586
 
 
3587
        if (fontsize <= 18) {
 
3588
                size_index = 0;
 
3589
        } else if (fontsize <= 22) {
 
3590
                size_index = 1;
 
3591
        } else if (fontsize <= 28) {
 
3592
                size_index = 2;
 
3593
        } else if (fontsize <= 40) {
 
3594
                size_index = 3;
 
3595
        } else if (fontsize <= 56) {
 
3596
                size_index = 4;
 
3597
        } else {
 
3598
                size_index = 5;
 
3599
        }
 
3600
 
 
3601
        bvw_config_helper_num (bvw->priv->xine, "subtitles.separate.subtitle_size", size_index, &entry);
 
3602
        entry.num_value = size_index;
 
3603
        xine_config_update_entry (bvw->priv->xine, &entry);
 
3604
 
 
3605
        //FIXME disabled, because Freetype isn't default in xine-lib yet
 
3606
#if 0
 
3607
        font_family = pango_font_description_get_family (desc);
 
3608
        if (font_family == NULL)
 
3609
                font_family = "Sans";
 
3610
 
 
3611
        bvw_config_helper_string (bvw->priv->xine,
 
3612
                        "subtitles.separate.font", font_family, &entry);
 
3613
        entry.str_value = (char *) font_family;
 
3614
        xine_config_update_entry (bvw->priv->xine, &entry);
 
3615
#endif
 
3616
        pango_font_description_free (desc);
3179
3617
}
3180
3618
 
3181
3619
void
3199
3637
}
3200
3638
 
3201
3639
void
3202
 
bacon_video_widget_set_video_device (BaconVideoWidget *bvw, const char *path)
3203
 
{
3204
 
        xine_cfg_entry_t entry;
3205
 
 
3206
 
        bvw_config_helper_string (bvw->priv->xine,
3207
 
                        "media.video4linux.video_device", path, &entry);
3208
 
        entry.str_value = (char *) path;
3209
 
        xine_config_update_entry (bvw->priv->xine, &entry);
3210
 
}
3211
 
 
3212
 
void
3213
3640
bacon_video_widget_set_aspect_ratio (BaconVideoWidget *bvw,
3214
3641
                BaconVideoWidgetAspectRatio ratio)
3215
3642
{
3245
3672
                        || bvw->priv->logo_mode != FALSE)
3246
3673
                return;
3247
3674
 
 
3675
        widget = GTK_WIDGET (bvw);
 
3676
 
3248
3677
        /* Try best fit for the screen */
3249
3678
        if (ratio == 0)
3250
3679
        {
3251
 
                if (totem_ratio_fits_screen (bvw->priv->video_window, bvw->priv->video_width, bvw->priv->video_height, 2) != FALSE)
3252
 
                {
 
3680
                if (totem_ratio_fits_screen (widget->window, bvw->priv->video_width, bvw->priv->video_height, 2) != FALSE) {
3253
3681
                        ratio = 2;
3254
 
                } else if (totem_ratio_fits_screen (bvw->priv->video_window, bvw->priv->video_width, bvw->priv->video_height, 1)
3255
 
                                != FALSE) {
 
3682
                } else if (totem_ratio_fits_screen (widget->window, bvw->priv->video_width, bvw->priv->video_height, 1) != FALSE) {
3256
3683
                        ratio = 1;
3257
 
                } else if (totem_ratio_fits_screen (bvw->priv->video_window, bvw->priv->video_width, bvw->priv->video_height, 0.5)
3258
 
                                != FALSE) {
 
3684
                } else if (totem_ratio_fits_screen (widget->window, bvw->priv->video_width, bvw->priv->video_height, 0.5) != FALSE) {
3259
3685
                        ratio = 0.5;
3260
3686
                } else {
3261
3687
                        return;
3263
3689
        } else {
3264
3690
                /* don't scale to something bigger than the screen, and leave
3265
3691
                 * us some room */
3266
 
                if (totem_ratio_fits_screen (bvw->priv->video_window, bvw->priv->video_width, bvw->priv->video_height, ratio) == FALSE)
 
3692
                if (totem_ratio_fits_screen (widget->window, bvw->priv->video_width, bvw->priv->video_height, ratio) == FALSE)
3267
3693
                        return;
3268
3694
        }
3269
3695
 
3270
 
        widget = GTK_WIDGET (bvw);
3271
 
 
3272
3696
        toplevel = gtk_widget_get_toplevel (widget);
3273
3697
 
3274
3698
        /* Get the size of the toplevel window */
3463
3887
                string = xine_get_meta_info (bvw->priv->stream,
3464
3888
                                XINE_META_INFO_YEAR);
3465
3889
                break;
 
3890
        case BVW_INFO_COMMENT:
 
3891
                string = xine_get_meta_info (bvw->priv->stream,
 
3892
                                XINE_META_INFO_COMMENT);
 
3893
                break;
3466
3894
        case BVW_INFO_VIDEO_CODEC:
3467
3895
                string = xine_get_meta_info (bvw->priv->stream,
3468
3896
                                XINE_META_INFO_VIDEOCODEC);
3471
3899
                string = xine_get_meta_info (bvw->priv->stream,
3472
3900
                                XINE_META_INFO_AUDIOCODEC);
3473
3901
                break;
 
3902
         case BVW_INFO_AUDIO_CHANNELS:
 
3903
                {
 
3904
                //FIXME xine-lib sucks at this, it gives the
 
3905
                //mode of the output, not the one of the file
 
3906
#if 0
 
3907
                        int mode;
 
3908
 
 
3909
                        mode = xine_get_stream_info (bvw->priv->stream,
 
3910
                                        XINE_STREAM_INFO_AUDIO_MODE);
 
3911
                        switch (mode)
 
3912
#endif
 
3913
                }
 
3914
                break;
3474
3915
        default:
3475
3916
                g_assert_not_reached ();
3476
3917
        }
3484
3925
                {
3485
3926
                        char *utf8;
3486
3927
 
3487
 
                        g_warning ("Metadata for index %d not in UTF-8 for mrl '%s'", type, bvw->priv->mrl);
 
3928
                        g_warning ("Metadata for index %d not in UTF-8 for mrl '%s'", type, bvw->com->mrl);
3488
3929
                        utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL);
3489
3930
                        g_value_set_string (value, utf8);
3490
3931
                        g_free (utf8);
3554
3995
                        integer = (int) g_ascii_strtod (string, NULL);
3555
3996
                }
3556
3997
                break;
 
3998
         case BVW_INFO_AUDIO_SAMPLE_RATE:
 
3999
                integer = xine_get_stream_info (bvw->priv->stream,
 
4000
                                XINE_STREAM_INFO_AUDIO_SAMPLERATE);
 
4001
                break;
3557
4002
         default:
3558
4003
                g_assert_not_reached ();
3559
4004
         }
3613
4058
        case BVW_INFO_ARTIST:
3614
4059
        case BVW_INFO_ALBUM:
3615
4060
        case BVW_INFO_YEAR:
 
4061
        case BVW_INFO_COMMENT:
3616
4062
        case BVW_INFO_VIDEO_CODEC:
3617
4063
        case BVW_INFO_AUDIO_CODEC:
 
4064
        case BVW_INFO_AUDIO_CHANNELS:
3618
4065
                bacon_video_widget_get_metadata_string (bvw, type, value);
3619
4066
                break;
3620
4067
        case BVW_INFO_DURATION:
3624
4071
        case BVW_INFO_AUDIO_BITRATE:
3625
4072
        case BVW_INFO_VIDEO_BITRATE:
3626
4073
        case BVW_INFO_TRACK_NUMBER:
 
4074
        case BVW_INFO_AUDIO_SAMPLE_RATE:
3627
4075
                bacon_video_widget_get_metadata_int (bvw, type, value);
3628
4076
                break;
3629
4077
        case BVW_INFO_HAS_VIDEO:
3647
4095
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
3648
4096
        g_return_val_if_fail (bvw->priv->stream != NULL, NULL);
3649
4097
 
3650
 
        if (bvw->priv->mrl == NULL)
 
4098
        if (bvw->com->mrl == NULL)
3651
4099
                return NULL;
3652
4100
 
3653
4101
        num_channels = xine_get_stream_info
3710
4158
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
3711
4159
        g_return_val_if_fail (bvw->priv->stream != NULL, NULL);
3712
4160
 
3713
 
        if (bvw->priv->mrl == NULL)
 
4161
        if (bvw->com->mrl == NULL)
3714
4162
                return NULL;
3715
4163
 
3716
4164
        num_channels = xine_get_stream_info
3768
4216
}
3769
4217
 
3770
4218
gboolean
 
4219
bacon_video_widget_has_next_track (BaconVideoWidget *bvw)
 
4220
{
 
4221
        int num, current;
 
4222
 
 
4223
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), TRUE);
 
4224
        g_return_val_if_fail (bvw->priv->stream != NULL, TRUE);
 
4225
 
 
4226
        if (g_str_has_prefix (bvw->com->mrl, "dvd:") == FALSE
 
4227
                        || bvw->com->mrl == NULL)
 
4228
                return TRUE;
 
4229
 
 
4230
        /* Check whether there's additional chapters first */
 
4231
        num = xine_get_stream_info (bvw->priv->stream,
 
4232
                        XINE_STREAM_INFO_DVD_CHAPTER_COUNT);
 
4233
        if (num == 0)
 
4234
                return FALSE;
 
4235
 
 
4236
        current = xine_get_stream_info (bvw->priv->stream,
 
4237
                        XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
 
4238
        if (current < num)
 
4239
                return TRUE;
 
4240
 
 
4241
        /* And now with titles */
 
4242
        num = xine_get_stream_info (bvw->priv->stream,
 
4243
                        XINE_STREAM_INFO_DVD_TITLE_COUNT);
 
4244
        current = xine_get_stream_info (bvw->priv->stream,
 
4245
                        XINE_STREAM_INFO_DVD_TITLE_NUMBER);
 
4246
 
 
4247
        return (current < num);
 
4248
}
 
4249
 
 
4250
gboolean
 
4251
bacon_video_widget_has_previous_track (BaconVideoWidget *bvw)
 
4252
{
 
4253
        int current;
 
4254
 
 
4255
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), TRUE);
 
4256
        g_return_val_if_fail (bvw->priv->stream != NULL, TRUE);
 
4257
 
 
4258
        if (g_str_has_prefix (bvw->com->mrl, "dvd:") == FALSE
 
4259
                        || bvw->com->mrl == NULL)
 
4260
                return TRUE;
 
4261
 
 
4262
        current = xine_get_stream_info (bvw->priv->stream,
 
4263
                        XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
 
4264
 
 
4265
        /* We can't go back across titles */
 
4266
 
 
4267
        return (current > 1);
 
4268
}
 
4269
 
 
4270
gboolean
3771
4271
bacon_video_widget_can_get_frames (BaconVideoWidget *bvw, GError **error)
3772
4272
{
3773
4273
        g_return_val_if_fail (bvw != NULL, FALSE);
3791
4291
                return FALSE;
3792
4292
        }
3793
4293
 
 
4294
        if (bvw->priv->type == BVW_USE_TYPE_CAPTURE)
 
4295
                return TRUE;
 
4296
 
3794
4297
        if (xine_get_status (bvw->priv->stream) != XINE_STATUS_PLAY
3795
4298
                        && bvw->priv->logo_mode == FALSE)
3796
4299
        {
3807
4310
{
3808
4311
        GdkPixbuf *pixbuf = NULL;
3809
4312
        uint8_t *yuv, *y, *u, *v, *rgb;
3810
 
        int width, height, ratio, format;
 
4313
        int width, height, ratio, format, image_ratio, desired_ratio;
 
4314
        xine_video_frame_t *frame = NULL;
3811
4315
 
3812
4316
        g_return_val_if_fail (bvw != NULL, NULL);
3813
4317
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
3814
4318
        g_return_val_if_fail (bvw->priv->xine != NULL, NULL);
3815
4319
 
3816
 
        if (xine_get_current_frame (bvw->priv->stream, &width, &height,
3817
 
                        &ratio, &format, NULL) == 0)
3818
 
                return NULL;
3819
 
 
3820
 
        if (width == 0 || height == 0)
3821
 
                return NULL;
3822
 
 
3823
 
        yuv = g_malloc ((width + 8) * (height + 1) * 2);
3824
 
        if (yuv == NULL)
3825
 
                return NULL;
3826
 
 
3827
 
        if (xine_get_current_frame (bvw->priv->stream, &width, &height,
3828
 
                        &ratio, &format, yuv) == 0)
3829
 
        {
3830
 
                g_free (yuv);
3831
 
                return NULL;
 
4320
        if (bvw->priv->type != BVW_USE_TYPE_CAPTURE) {
 
4321
 
 
4322
                if (xine_get_current_frame (bvw->priv->stream, &width, &height,
 
4323
                        &ratio, &format, NULL) == 0) {
 
4324
                        return NULL;
 
4325
                }
 
4326
 
 
4327
                if (width == 0 || height == 0)
 
4328
                        return NULL;
 
4329
 
 
4330
                yuv = g_malloc ((width + 8) * (height + 1) * 2);
 
4331
                if (yuv == NULL)
 
4332
                        return NULL;
 
4333
 
 
4334
                if (xine_get_current_frame (bvw->priv->stream, &width, &height,
 
4335
                                        &ratio, &format, yuv) == 0) {
 
4336
                        g_free (yuv);
 
4337
                        return NULL;
 
4338
                }
 
4339
        } else {
 
4340
                frame = g_new0 (xine_video_frame_t, 1);
 
4341
                if (xine_get_next_video_frame (bvw->priv->vo_driver, frame) != 1) {
 
4342
                        g_free (frame);
 
4343
                        return NULL;
 
4344
                }
 
4345
                format = frame->colorspace;
 
4346
                width = frame->width;
 
4347
                height = frame->height;
 
4348
                yuv = frame->data;
 
4349
                ratio = frame->aspect_ratio;
3832
4350
        }
3833
4351
 
3834
4352
        /* Convert to yv12 */
3849
4367
                break;
3850
4368
        case XINE_IMGFMT_YV12:
3851
4369
                y = yuv;
3852
 
                u = yuv + width * height;
3853
 
                v = yuv + width * height * 5 / 4;
 
4370
                /* XXX Work-around xine-lib bug, u and v channels are swapped
 
4371
                 * when using xine_get_current_frame */
 
4372
                if (bvw->priv->type != BVW_USE_TYPE_CAPTURE) {
 
4373
                        u = yuv + width * height;
 
4374
                        v = yuv + width * height * 5 / 4;
 
4375
                } else {
 
4376
                        v = yuv + width * height;
 
4377
                        u = yuv + width * height * 5 / 4;
 
4378
                }
3854
4379
                break;
3855
4380
        default:
3856
4381
                g_warning ("Format '%.4s' unsupported", (char *) &format);
3858
4383
                return NULL;
3859
4384
        }
3860
4385
 
 
4386
        image_ratio = (double) width / (double) height * 10000.0;
 
4387
 
3861
4388
        switch (ratio) {
3862
4389
        case XINE_VO_ASPECT_SQUARE:
3863
 
                ratio = 10000.0;
 
4390
        case XINE_VO_ASPECT_DONT_TOUCH:
 
4391
                desired_ratio = image_ratio;
3864
4392
                break;
3865
4393
        case XINE_VO_ASPECT_4_3:
3866
 
                ratio = 10000.0 * 4 / 3;
 
4394
                desired_ratio = 10000.0 * 4 / 3;
3867
4395
                break;
3868
4396
        case XINE_VO_ASPECT_ANAMORPHIC:
3869
 
                ratio = 10000.0 * 16 / 9;
 
4397
                desired_ratio = 10000.0 * 16 / 9;
3870
4398
                break;
3871
4399
        case XINE_VO_ASPECT_DVB:
3872
 
                ratio = 10000.0 * 2.11;
 
4400
                desired_ratio = 10000.0 * 2.11;
3873
4401
                break;
3874
4402
        default:
3875
 
                ratio = 0.0;
 
4403
                desired_ratio = 0.0;
3876
4404
        }
3877
4405
 
3878
4406
        /* Convert to rgb */
3883
4411
                        8, width, height, 3 * width,
3884
4412
                        (GdkPixbufDestroyNotify) g_free, NULL);
3885
4413
 
3886
 
        if (ratio != 10000.0 && ratio != 0.0)
 
4414
        if (frame != NULL) {
 
4415
                xine_free_video_frame (bvw->priv->vo_driver, frame);
 
4416
                g_free (frame);
 
4417
        }
 
4418
 
 
4419
        if (desired_ratio != 0)
3887
4420
        {
3888
4421
                GdkPixbuf *tmp;
3889
4422
 
 
4423
                ratio = (double) desired_ratio / (double) image_ratio * 10000.0;
 
4424
 
3890
4425
                if (ratio > 10000.0)
3891
4426
                        tmp = gdk_pixbuf_scale_simple (pixbuf,
3892
 
                                        (int) (height * ratio / 10000), height,
 
4427
                                        (int) (width * ratio / 10000), height,
3893
4428
                                        GDK_INTERP_BILINEAR);
3894
4429
                else
3895
4430
                        tmp = gdk_pixbuf_scale_simple (pixbuf,
3896
 
                                        width, (int) (width * ratio / 10000),
 
4431
                                        width, (int) (height * ratio / 10000),
3897
4432
                                        GDK_INTERP_BILINEAR);
3898
4433
 
3899
 
                gdk_pixbuf_unref (pixbuf);
 
4434
                g_object_unref (pixbuf);
3900
4435
 
3901
4436
                return tmp;
3902
4437
        }