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,
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));
443
463
autoplug_list = xine_get_autoplay_input_plugin_ids (bvw->priv->xine);
444
464
while (autoplug_list && autoplug_list[i])
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) {
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;
457
bvw->priv->tick_id = g_timeout_add (140,
458
(GSourceFunc) bacon_video_widget_tick_send, bvw);
601
650
static char *drivers[] = { "xv", "xshm" };
604
if (null_out != FALSE)
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);
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;
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;
675
bvw->priv->display_ratio = res_v / res_h;
622
677
if (fabs (bvw->priv->display_ratio - 1.0) < 0.01) {
623
678
bvw->priv->display_ratio = 1.0;
1148
1197
gdk_window_set_user_data (widget->window, bvw);
1150
bvw->priv->video_window = widget->window;
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);
1154
/* Set a black background */
1155
gdk_draw_rectangle (widget->window, widget->style->black_gc, TRUE,
1157
attr.width, attr.height);
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);
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);
1168
1214
/* Now onto the video out driver */
1365
1407
num = BVW_ERROR_AUDIO_BUSY;
1366
1408
message = g_strdup (_("The audio device is busy. Is another application using it?"));
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."));
1416
message = g_strdup (_("Authentication is required to access this file or stream."));
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."));
1373
1424
message = g_strdup (_("The server refused access to this file or stream."));
1376
/* FIXME missing stuff from libxine includes (<= 1.1.x) */
1377
#ifndef XINE_MSG_FILE_EMPTY
1378
#define XINE_MSG_FILE_EMPTY 13
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."));
1440
1486
case XINE_EVENT_UI_SET_TITLE:
1441
1487
ui_data = event->data;
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);
1490
if (g_utf8_validate (ui_data->str, -1, NULL) == FALSE) {
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);
1496
data = g_new0 (signal_data, 1);
1500
data = g_new0 (signal_data, 1);
1501
data->msg = g_strdup (ui_data->str);
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);
1449
1510
case XINE_EVENT_PROGRESS:
1450
1511
prg = event->data;
1452
1513
data = g_new0 (signal_data, 1);
1453
1514
data->signal = BUFFERING_ASYNC;
1454
data->num = prg->percent;
1515
if (prg->percent < 0)
1517
else if (prg->percent > 100)
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);
1823
1859
int s_width, s_height, w_width, w_height;
1824
1860
GdkPixbuf *logo = NULL;
1827
/* Start with a nice black canvas */
1828
gdk_draw_rectangle (widget->window, widget->style->black_gc,
1830
widget->allocation.width,
1831
widget->allocation.height);
1833
if (bvw->priv->logo_pixbuf == NULL)
1865
rect.x = rect.y = 0;
1866
rect.width = widget->allocation.width;
1867
rect.height = widget->allocation.height;
1868
region = gdk_region_rectangle (&rect);
1870
gdk_window_begin_paint_region (widget->window,
1872
gdk_region_destroy (region);
1874
gdk_window_clear_area (widget->window,
1876
widget->allocation.width,
1877
widget->allocation.height);
1879
if (bvw->priv->logo_pixbuf == NULL) {
1880
gdk_window_end_paint (widget->window);
1836
1884
s_width = gdk_pixbuf_get_width (bvw->priv->logo_pixbuf);
1837
1885
s_height = gdk_pixbuf_get_height (bvw->priv->logo_pixbuf);
2017
bacon_video_widget_reconfigure_tick (BaconVideoWidget *bvw, gboolean enable)
2019
if (bvw->priv->tick_id != 0 && enable != FALSE)
2021
if (bvw->priv->tick_id == 0 && enable == FALSE)
2024
if (enable == FALSE) {
2025
g_source_remove (bvw->priv->tick_id);
2026
bvw->priv->tick_id = 0;
2028
bvw->priv->tick_id = g_timeout_add (140,
2029
(GSourceFunc) bacon_video_widget_tick_send,
2032
bacon_video_widget_tick_send (bvw);
1953
2035
static gboolean
1954
2036
bacon_video_widget_tick_send (BaconVideoWidget *bvw)
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;
1960
if (bvw->priv->stream == NULL || bvw->priv->logo_mode != FALSE)
2042
g_return_val_if_fail (bvw->priv->stream != NULL, FALSE);
2043
g_return_val_if_fail (bvw->priv->logo_mode == FALSE, FALSE);
1963
if (bvw->priv->mrl == NULL)
2045
if (bvw->com->mrl == NULL)
1965
2047
current_time = 0;
1966
2048
stream_length = 0;
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)
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
2031
2127
} else if (has_video == FALSE && show_visuals != FALSE
2032
&& bvw->priv->using_vfx == FALSE)
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);
2135
if (bvw->priv->vis == NULL && strcmp (bvw->priv->vis_name, "goom") != 0) {
2136
bvw->priv->vis = xine_post_init (bvw->priv->xine,
2138
&bvw->priv->ao_driver,
2139
&bvw->priv->vo_driver);
2040
2141
if (bvw->priv->vis != NULL) {
2143
GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
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;
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);
2153
/* No changes but doesn't have video */
2155
GTK_WIDGET_SET_FLAGS (GTK_WIDGET (bvw), GTK_DOUBLE_BUFFERED);
2144
2252
return g_strdup_printf ("%s#subtitle:%s", mrl, subtitle_uri + strlen ("file://"));
2256
bacon_video_widget_open_async_error (BaconVideoWidget *bvw, GError *error)
2258
signal_data *sigdata;
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);
2269
bacon_video_widget_open_thread (gpointer data)
2271
BaconVideoWidget *bvw = (BaconVideoWidget *) data;
2272
GError *error = NULL;
2275
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
2276
err = xine_open (bvw->priv->stream, bvw->com->mrl);
2277
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
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);
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);
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);
2300
pthread_mutex_lock (&bvw->priv->queued_actions_mutex);
2302
/* This is so that we don't deadlock when calling the
2304
bvw->priv->open_thread = 0;
2306
for (l = bvw->priv->queued_actions; l != NULL; l = l->next) {
2309
action = GPOINTER_TO_INT (l->data);
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);
2319
case BVW_XINE_PAUSE:
2320
bacon_video_widget_pause (bvw);
2323
g_assert_not_reached ();
2327
g_list_free (bvw->priv->queued_actions);
2328
bvw->priv->queued_actions = NULL;
2329
pthread_mutex_unlock (&bvw->priv->queued_actions_mutex);
2333
bvw->priv->open_thread = 0;
2338
bacon_video_widget_open_async (BaconVideoWidget *bvw, const char *mrl,
2341
if (pthread_create (&bvw->priv->open_thread, NULL, bacon_video_widget_open_thread, bvw) != 0) {
2342
g_assert_not_reached ();
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 */
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. */
2357
add_auth_to_uri (const char* mrl)
2359
if (g_str_has_prefix (mrl, "http:") != FALSE) {
2361
const char *host, *scheme, *user;
2363
GnomeKeyringResult result;
2366
uri = gnome_vfs_uri_new (mrl);
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);
2375
result = gnome_keyring_find_network_password_sync (user, NULL,
2380
if (result == GNOME_KEYRING_RESULT_OK && items != NULL) {
2382
GnomeKeyringNetworkPasswordData *pwd_data;
2384
pwd_data = items->data;
2386
gnome_vfs_uri_set_user_name (uri, pwd_data->user);
2387
gnome_vfs_uri_set_password (uri, pwd_data->password);
2389
parsed_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
2391
gnome_keyring_network_password_list_free (items);
2392
gnome_vfs_uri_unref (uri);
2396
gnome_vfs_uri_unref (uri);
2402
#endif /* !HAVE_GTK_ONLY */
2148
2405
bacon_video_widget_open_with_subtitle (BaconVideoWidget *bvw, const char *mrl,
2149
2406
const char *subtitle_uri, GError **error)
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);
2159
2415
bvw->priv->got_redirect = FALSE;
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);
2166
bvw->priv->mrl = g_strdup (mrl);
2169
if (subtitle_uri != NULL)
2428
bvw->com->mrl = g_strdup (mrl);
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);
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);
2178
err = xine_open (bvw->priv->stream, mrl);
2445
err = xine_open (bvw->priv->stream, bvw->com->mrl);
2181
err = xine_open (bvw->priv->stream, mrl);
2448
err = xine_open (bvw->priv->stream, bvw->com->mrl);
2184
xine_plugins_garbage_collector (bvw->priv->xine);
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);
2457
if (error != NULL && *error != NULL && g_error_matches (*error, BVW_ERROR, BVW_ERROR_FILE_PERMISSION)) {
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);
2469
#endif /* !HAVE_GTK_ONLY */
2470
xine_plugins_garbage_collector (bvw->priv->xine);
2473
bacon_video_widget_close (bvw);
2474
if (error == NULL || *error == NULL)
2475
xine_error (bvw, error);
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);
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)
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."));
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,
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);
2273
if (bvw->priv->seeking == 1)
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);
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);
2566
error = xine_play (bvw->priv->stream,
2567
bvw->priv->seek_dest * 65535, 0);
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;
2283
2575
int speed, status;
2603
if (bvw->priv->seeking == 1)
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;
2610
2968
if (ret == FALSE)
2613
return pos_stream / 65535;
2971
return (double) pos_stream / 65535;
2617
2975
bacon_video_widget_can_set_volume (BaconVideoWidget *bvw)
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);
2623
2981
if (bvw->priv->ao_driver == NULL || bvw->priv->ao_driver_none != FALSE)
2637
bacon_video_widget_set_volume (BaconVideoWidget *bvw, int volume)
2995
bacon_video_widget_set_volume (BaconVideoWidget *bvw, double volume)
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);
2643
3000
if (bacon_video_widget_can_set_volume (bvw) != FALSE)
3002
bvw->priv->volume = volume;
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");
2653
3013
bacon_video_widget_get_volume (BaconVideoWidget *bvw)
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);
2659
3018
if (bacon_video_widget_can_set_volume (bvw) == FALSE)
2662
3021
return bvw->priv->volume;
2760
bacon_video_widget_set_media_device (BaconVideoWidget *bvw, const char *path)
2762
xine_cfg_entry_t entry;
2764
g_return_if_fail (bvw != NULL);
2765
g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
2766
g_return_if_fail (path != NULL);
2768
g_free (bvw->priv->mediadev);
2771
bvw_config_helper_string (bvw->priv->xine, "media.dvd.device",
2773
entry.str_value = (char *) path;
2774
xine_config_update_entry (bvw->priv->xine, &entry);
2777
bvw_config_helper_string (bvw->priv->xine, "media.vcd.device",
2779
entry.str_value = (char *) path;
2780
xine_config_update_entry (bvw->priv->xine, &entry);
2782
/* VCD device for the new input plugin */
2783
bvw_config_helper_string (bvw->priv->xine, "media.vcd.device",
2785
entry.str_value = (char *) path;
2786
xine_config_update_entry (bvw->priv->xine, &entry);
2789
bvw_config_helper_string (bvw->priv->xine, "media.audio_cd.device",
2791
entry.str_value = (char *) path;
2792
xine_config_update_entry (bvw->priv->xine, &entry);
2794
bvw->priv->mediadev = g_strdup (path);
2798
3125
bacon_video_widget_set_connection_speed (BaconVideoWidget *bvw, int speed)
2800
3127
xine_cfg_entry_t entry;
3107
3434
bacon_video_widget_is_playing (BaconVideoWidget *bvw)
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);
3113
3440
if (bvw->priv->stream == NULL)
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);
3120
3447
bacon_video_widget_is_seekable (BaconVideoWidget *bvw)
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);
3126
if (bvw->priv->mrl == NULL)
3453
if (bvw->com->mrl == NULL)
3129
3456
if (bacon_video_widget_get_stream_length (bvw) == 0)
3133
3460
XINE_STREAM_INFO_SEEKABLE);
3137
bacon_video_widget_can_play (BaconVideoWidget *bvw, MediaType type)
3463
BaconVideoWidgetCanPlayStatus
3464
bacon_video_widget_can_play (BaconVideoWidget *bvw, TotemDiscMediaType type)
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;
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;
3476
case MEDIA_TYPE_DVB:
3477
if (bvw->priv->can_dvb != FALSE) {
3480
path = g_build_filename (g_get_home_dir (),
3484
if (g_file_test (path, G_FILE_TEST_IS_REGULAR) == FALSE) {
3486
return BVW_CAN_PLAY_MISSING_CHANNELS;
3489
return BVW_CAN_PLAY_SUCCESS;
3145
3492
case MEDIA_TYPE_CDDA:
3146
return bvw->priv->can_cdda;
3494
return BVW_CAN_PLAY_UNSUPPORTED;
3153
**bacon_video_widget_get_mrls (BaconVideoWidget *bvw, MediaType type)
3497
return BVW_CAN_PLAY_MISSING_PLUGINS;
3501
bacon_video_widget_strdupnv (const char **mrls, int num_mrls)
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;
3515
bacon_video_widget_get_mrls (BaconVideoWidget *bvw,
3516
TotemDiscMediaType type,
3519
const char *plugin_id, *entry_name;
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);
3162
if (type == MEDIA_TYPE_DVD)
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);
3529
entry_name = plugin_id = NULL;
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)
3536
entry_name = "media.vcd.device";
3537
} else if (type == MEDIA_TYPE_DVB) {
3541
if (entry_name != NULL) {
3542
xine_cfg_entry_t entry;
3543
bvw_config_helper_string (bvw->priv->xine,
3546
entry.str_value = (char *) device;
3547
xine_config_update_entry (bvw->priv->xine, &entry);
3550
mrls = xine_get_autoplay_mrls (bvw->priv->xine, plugin_id, &num_mrls);
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);
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)
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);
3572
return bacon_video_widget_strdupnv (mrls, num_mrls);
3176
3576
bacon_video_widget_set_subtitle_font (BaconVideoWidget *bvw, const char *font)
3578
xine_cfg_entry_t entry;
3579
int fontsize, size_index;
3580
PangoFontDescription *desc;
3582
const char *font_family;
3584
desc = pango_font_description_from_string (font);
3585
fontsize = pango_font_description_get_size (desc) / PANGO_SCALE;
3587
if (fontsize <= 18) {
3589
} else if (fontsize <= 22) {
3591
} else if (fontsize <= 28) {
3593
} else if (fontsize <= 40) {
3595
} else if (fontsize <= 56) {
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);
3605
//FIXME disabled, because Freetype isn't default in xine-lib yet
3607
font_family = pango_font_description_get_family (desc);
3608
if (font_family == NULL)
3609
font_family = "Sans";
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);
3616
pango_font_description_free (desc);
4219
bacon_video_widget_has_next_track (BaconVideoWidget *bvw)
4223
g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), TRUE);
4224
g_return_val_if_fail (bvw->priv->stream != NULL, TRUE);
4226
if (g_str_has_prefix (bvw->com->mrl, "dvd:") == FALSE
4227
|| bvw->com->mrl == NULL)
4230
/* Check whether there's additional chapters first */
4231
num = xine_get_stream_info (bvw->priv->stream,
4232
XINE_STREAM_INFO_DVD_CHAPTER_COUNT);
4236
current = xine_get_stream_info (bvw->priv->stream,
4237
XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
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);
4247
return (current < num);
4251
bacon_video_widget_has_previous_track (BaconVideoWidget *bvw)
4255
g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), TRUE);
4256
g_return_val_if_fail (bvw->priv->stream != NULL, TRUE);
4258
if (g_str_has_prefix (bvw->com->mrl, "dvd:") == FALSE
4259
|| bvw->com->mrl == NULL)
4262
current = xine_get_stream_info (bvw->priv->stream,
4263
XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
4265
/* We can't go back across titles */
4267
return (current > 1);
3771
4271
bacon_video_widget_can_get_frames (BaconVideoWidget *bvw, GError **error)
3773
4273
g_return_val_if_fail (bvw != NULL, FALSE);
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;
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);
3816
if (xine_get_current_frame (bvw->priv->stream, &width, &height,
3817
&ratio, &format, NULL) == 0)
3820
if (width == 0 || height == 0)
3823
yuv = g_malloc ((width + 8) * (height + 1) * 2);
3827
if (xine_get_current_frame (bvw->priv->stream, &width, &height,
3828
&ratio, &format, yuv) == 0)
4320
if (bvw->priv->type != BVW_USE_TYPE_CAPTURE) {
4322
if (xine_get_current_frame (bvw->priv->stream, &width, &height,
4323
&ratio, &format, NULL) == 0) {
4327
if (width == 0 || height == 0)
4330
yuv = g_malloc ((width + 8) * (height + 1) * 2);
4334
if (xine_get_current_frame (bvw->priv->stream, &width, &height,
4335
&ratio, &format, yuv) == 0) {
4340
frame = g_new0 (xine_video_frame_t, 1);
4341
if (xine_get_next_video_frame (bvw->priv->vo_driver, frame) != 1) {
4345
format = frame->colorspace;
4346
width = frame->width;
4347
height = frame->height;
4349
ratio = frame->aspect_ratio;
3834
4352
/* Convert to yv12 */