~woodrow-shen/totem/mybranch

« back to all changes in this revision

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

Tags: 2.24.3-3
* totem-mozilla.docs: ship README.browser-plugin which explains how to 
  disable the plugin for some MIME types.
* rules: remove the hack that only let totem-xine support VCDs and 
  DVDs, now that GStreamer supports them. Closes: #370789.
* 01_fake_keypresses.patch: new patch. Completely disable the broken 
  XTEST code that generates fake keypresses. Closes: #500330.
* 90_autotools.patch: regenerated.
* Build-depend on nautilus 2.22 to be sure to build the extension for 
  the correct version.
* totem-xine depends on libxine1-x.
* Standards version is 3.8.1.
* Upload to unstable.
* 04_tracker_build.patch: new patch, stolen upstream. Fix build with 
  latest tracker version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 *
15
15
 * You should have received a copy of the GNU General Public License
16
16
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
18
18
 *
19
 
 * $Id: bacon-video-widget-xine.c 5344 2008-04-08 13:17:29Z hadess $
 
19
 * $Id: bacon-video-widget-xine.c 5617 2008-08-30 12:02:54Z hadess $
20
20
 *
21
21
 * the xine engine in a widget - implementation
22
22
 */
40
40
#include <X11/X.h>
41
41
#include <X11/Xlib.h>
42
42
/* gtk+/gnome */
 
43
#include <gio/gio.h>
43
44
#include <gdk/gdkx.h>
44
45
#include <gtk/gtk.h>
45
46
#include <gconf/gconf-client.h>
48
49
#define XINE_ENABLE_EXPERIMENTAL_FEATURES
49
50
#include <xine.h>
50
51
 
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
 
 
57
52
#include "debug.h"
58
53
#include "bacon-video-widget.h"
59
54
#include "bacon-video-widget-common.h"
187
182
        BaconVideoWidgetAudioOutType audio_out_type;
188
183
        TvOutType tvout;
189
184
        gint64 stream_length;
 
185
        int zoom;
190
186
 
191
187
        GAsyncQueue *queue;
192
188
        int video_width, video_height;
213
209
        guint bevent_consumed : 1;
214
210
        guint fullscreen_mode : 1;
215
211
        guint cursor_shown : 1;
 
212
        /* Whether the window has already been resized for this media */
 
213
        guint window_resized : 1;
216
214
};
217
215
 
218
216
static const char *mms_bandwidth_strs[] = {
468
466
                } else if (g_ascii_strcasecmp (autoplug_list[i], "DVD") == 0) {
469
467
                        bvw->priv->can_dvd = TRUE;
470
468
                } 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);
 
469
                        bvw->priv->can_dvb = TRUE;
478
470
                }
479
471
                i++;
480
472
        }
616
608
 
617
609
                if (bvw->priv->auto_resize != FALSE
618
610
                                && bvw->priv->logo_mode == FALSE
619
 
                                && bvw->priv->fullscreen_mode == FALSE)
 
611
                                && bvw->priv->fullscreen_mode == FALSE
 
612
                                && bvw->priv->window_resized == FALSE)
620
613
                {
621
614
                        signal_data *data;
622
615
 
 
616
                        bvw->priv->window_resized = TRUE;
 
617
 
623
618
                        data = g_new0 (signal_data, 1);
624
619
                        data->signal = RATIO_ASYNC;
625
620
                        g_async_queue_push (bvw->priv->queue, data);
835
830
        entry.num_value = 0;
836
831
        xine_config_update_entry (bvw->priv->xine, &entry);
837
832
 
 
833
        /* Don't save the last viewed channel for DVB */
 
834
        bvw_config_helper_num (bvw->priv->xine,
 
835
                               "media.dvb.remember_channel", 1, &entry);
 
836
        entry.num_value = 0;
 
837
        xine_config_update_entry (bvw->priv->xine, &entry);
 
838
 
838
839
        if (bvw->priv->gc == NULL) {
839
840
                g_warning ("GConf not available, broken installation?");
840
841
                return;
1257
1258
        setup_config_stream (bvw);
1258
1259
        bvw->priv->ev_queue = xine_event_new_queue (bvw->priv->stream);
1259
1260
 
 
1261
        /* Set the zoom that might have been recorded */
 
1262
        if (bvw->priv->zoom != 0)
 
1263
                bacon_video_widget_set_zoom (bvw, bvw->priv->zoom);
 
1264
 
1260
1265
        /* Setup xine events */
1261
1266
        xine_event_create_listener_thread (bvw->priv->ev_queue,
1262
1267
                        xine_event, (void *) bvw);
1351
1356
        case XINE_MSG_NO_ERROR:
1352
1357
                return;
1353
1358
        case XINE_MSG_GENERAL_WARNING:
1354
 
                return;
 
1359
                g_message ("general warning: %s", data->messages);
 
1360
                if (data->messages != NULL && strcmp (data->messages, "DVB Signal Lost.  Please check connections.") == 0) {
 
1361
                        num = BVW_ERROR_INVALID_DEVICE;
 
1362
                        message = g_strdup (_("The TV adapter could not tune into the channel. Please check your hardware setup, and channel configuration."));
 
1363
                }
 
1364
                break;
1355
1365
        case XINE_MSG_UNKNOWN_HOST:
1356
1366
                num = BVW_ERROR_UNKNOWN_HOST;
1357
1367
                message = g_strdup (_("The server you are trying to connect to is not known."));
1572
1582
        /* Steal messages from the async queue, if there's an error,
1573
1583
         * to use as the error message rather than the crappy errors from
1574
1584
         * xine_open() */
1575
 
        while ((data = g_async_queue_try_pop (bvw->priv->queue)) != NULL)
1576
 
        {
1577
 
                if (data->signal == ERROR_ASYNC || data->signal == MESSAGE_ASYNC)
1578
 
                {
1579
 
                        if (save_data != NULL)
1580
 
                        {
 
1585
        while ((data = g_async_queue_try_pop (bvw->priv->queue)) != NULL) {
 
1586
                if (data->signal == ERROR_ASYNC || data->signal == MESSAGE_ASYNC) {
 
1587
                        if (save_data != NULL) {
1581
1588
                                g_free (save_data->msg);
1582
1589
                                g_free (save_data);
1583
1590
                        }
1588
1595
                }
1589
1596
        }
1590
1597
 
1591
 
        if (save_data != NULL)
1592
 
        {
 
1598
        if (save_data != NULL) {
1593
1599
                g_set_error (error, BVW_ERROR, save_data->num,
1594
1600
                                "%s", save_data->msg);
1595
1601
                g_free (save_data->msg);
2248
2254
static char *
2249
2255
bacon_video_widget_get_subtitled (const char *mrl, const char *subtitle_uri)
2250
2256
{
2251
 
        g_return_val_if_fail (g_str_has_prefix (subtitle_uri, "file://"), NULL);
2252
 
        return g_strdup_printf ("%s#subtitle:%s", mrl, subtitle_uri + strlen ("file://"));
 
2257
        GFile *file;
 
2258
        char *local_path, *local_uri, *retval;
 
2259
 
 
2260
        file = g_file_new_for_uri (subtitle_uri);
 
2261
        local_path = g_file_get_path (file);
 
2262
        g_object_unref (file);
 
2263
 
 
2264
        if (local_path == NULL)
 
2265
                return NULL;
 
2266
 
 
2267
        local_uri = g_filename_to_uri (local_path, NULL, NULL);
 
2268
        g_free (local_path);
 
2269
        if (local_uri == NULL)
 
2270
                return NULL;
 
2271
 
 
2272
        retval = g_strdup_printf ("%s#subtitle:%s", mrl, local_uri + strlen ("file://"));
 
2273
        g_free (local_uri);
 
2274
 
 
2275
        return retval;
2253
2276
}
2254
2277
 
2255
2278
static void
2350
2373
        return TRUE;
2351
2374
}
2352
2375
 
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
 
 
2404
2376
gboolean
2405
2377
bacon_video_widget_open_with_subtitle (BaconVideoWidget *bvw, const char *mrl,
2406
2378
                const char *subtitle_uri, GError **error)
2425
2397
                /* Handle "icyx://" URLs from Orban/Coding Technologies AAC/aacPlus Player */
2426
2398
                bvw->com->mrl = g_strdup_printf ("http:%s", mrl + 5);
2427
2399
        } else {
2428
 
                bvw->com->mrl = g_strdup (mrl);
 
2400
                GFile *file;
 
2401
                char *path;
 
2402
 
 
2403
                file = g_file_new_for_commandline_arg (mrl);
 
2404
                path = g_file_get_path (file);
 
2405
                if (path != NULL) {
 
2406
                        bvw->com->mrl = g_filename_to_uri (path, NULL, NULL);
 
2407
                        g_free (path);
 
2408
                } else {
 
2409
                        bvw->com->mrl = g_strdup (mrl);
 
2410
                }
 
2411
                g_object_unref (file);
2429
2412
        }
2430
2413
 
2431
2414
        if (g_str_has_prefix (mrl, "fd://") != FALSE) {
2448
2431
                err = xine_open (bvw->priv->stream, bvw->com->mrl);
2449
2432
        }
2450
2433
 
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) {
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
2434
        xine_plugins_garbage_collector (bvw->priv->xine);
2471
2435
 
2472
2436
        if (err == 0) {
2747
2711
        g_free (bvw->com->mrl);
2748
2712
        bvw->com->mrl = NULL;
2749
2713
        bvw->priv->stream_length = 0;
 
2714
        bvw->priv->window_resized = FALSE;
2750
2715
 
2751
2716
        g_object_notify (G_OBJECT (bvw), "seekable");
2752
2717
        bacon_video_widget_reconfigure_tick (bvw, FALSE);
3168
3133
        return entry.num_value;
3169
3134
}
3170
3135
 
 
3136
gboolean
 
3137
bacon_video_widget_can_deinterlace (BaconVideoWidget *bvw)
 
3138
{
 
3139
        return TRUE;
 
3140
}
 
3141
 
3171
3142
void
3172
3143
bacon_video_widget_set_deinterlacing (BaconVideoWidget *bvw,
3173
3144
                gboolean deinterlace)
3460
3431
                        XINE_STREAM_INFO_SEEKABLE);
3461
3432
}
3462
3433
 
3463
 
BaconVideoWidgetCanPlayStatus
3464
 
bacon_video_widget_can_play (BaconVideoWidget *bvw, TotemDiscMediaType type)
3465
 
{
3466
 
        switch (type)
3467
 
        {
3468
 
        case MEDIA_TYPE_DVD:
3469
 
                if (bvw->priv->can_dvd != FALSE)
3470
 
                        return BVW_CAN_PLAY_SUCCESS;
3471
 
                break;
3472
 
        case MEDIA_TYPE_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;
3492
 
        case MEDIA_TYPE_CDDA:
3493
 
        default:
3494
 
                return BVW_CAN_PLAY_UNSUPPORTED;
3495
 
        }
3496
 
 
3497
 
        return BVW_CAN_PLAY_MISSING_PLUGINS;
3498
 
}
3499
 
 
3500
 
static char *
3501
 
bacon_video_widget_strdupnv (const char **mrls, int num_mrls)
 
3434
static char **
 
3435
bacon_video_widget_strdupnv (const char **mrls, guint num_mrls)
3502
3436
{
3503
3437
        guint i;
3504
3438
        char **retval;
3514
3448
char **
3515
3449
bacon_video_widget_get_mrls (BaconVideoWidget *bvw,
3516
3450
                             TotemDiscMediaType type,
3517
 
                             const char *device)
 
3451
                             const char *device,
 
3452
                             GError **error)
3518
3453
{
3519
3454
        const char *plugin_id, *entry_name;
3520
3455
        int num_mrls;
3523
3458
        g_return_val_if_fail (bvw != NULL, NULL);
3524
3459
        g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
3525
3460
        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) {
 
3461
        g_return_val_if_fail (device != NULL, NULL);
 
3462
 
 
3463
        switch (type) {
 
3464
        case MEDIA_TYPE_DVD:
 
3465
                if (bvw->priv->can_dvd == FALSE) {
 
3466
                        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
3467
                                     "XXX Do not use XXX");
 
3468
                        return NULL;
 
3469
                }
3532
3470
                plugin_id = "DVD";
3533
3471
                entry_name = "media.dvd.device";
3534
 
        } else if (type == MEDIA_TYPE_VCD) {
 
3472
                break;
 
3473
        case MEDIA_TYPE_VCD:
 
3474
                if (bvw->priv->can_vcd == FALSE) {
 
3475
                        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
3476
                                     "XXX Do not use XXX");
 
3477
                        return NULL;
 
3478
                }
3535
3479
                plugin_id = "VCD";
3536
3480
                entry_name = "media.vcd.device";
3537
 
        } else if (type == MEDIA_TYPE_DVB) {
 
3481
                break;
 
3482
        case MEDIA_TYPE_DVB:
 
3483
                if (bvw->priv->can_dvb == FALSE) {
 
3484
                        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
3485
                                     "XXX Do not use XXX");
 
3486
                        return NULL;
 
3487
                } else {
 
3488
                        char *path;
 
3489
 
 
3490
                        path = g_strdup_printf ("/dev/dvb/adapter%s/frontend0", device);
 
3491
                        if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) {
 
3492
                                g_free (path);
 
3493
                                g_set_error (error, BVW_ERROR, BVW_ERROR_INVALID_DEVICE,
 
3494
                                             "XXX Do not use XXX");
 
3495
                                return NULL;
 
3496
                        }
 
3497
                        g_free (path);
 
3498
 
 
3499
                        path = g_build_filename (g_get_home_dir (),
 
3500
                                                 ".xine",
 
3501
                                                 "channels.conf",
 
3502
                                                 NULL);
 
3503
                        if (g_file_test (path, G_FILE_TEST_IS_REGULAR) == FALSE) {
 
3504
                                g_free (path);
 
3505
                                g_set_error (error, BVW_ERROR, BVW_ERROR_FILE_NOT_FOUND,
 
3506
                                             "XXX Do not use XXX");
 
3507
                                return NULL;
 
3508
                        }
 
3509
                        g_free (path);
 
3510
                }
3538
3511
                plugin_id = "DVB";
 
3512
                entry_name = "media.dvb.adapter";
 
3513
                break;
 
3514
        case MEDIA_TYPE_CDDA:
 
3515
                g_set_error (error, BVW_ERROR, BVW_ERROR_UNVALID_LOCATION,
 
3516
                             "XXX Do not use XXX");
 
3517
                return NULL;
 
3518
        default:
 
3519
                g_assert_not_reached ();
3539
3520
        }
3540
3521
 
3541
 
        if (entry_name != NULL) {
 
3522
        if (type != MEDIA_TYPE_DVB) {
3542
3523
                xine_cfg_entry_t entry;
3543
3524
                bvw_config_helper_string (bvw->priv->xine,
3544
3525
                                          entry_name,
3545
3526
                                          device, &entry);
3546
3527
                entry.str_value = (char *) device;
3547
3528
                xine_config_update_entry (bvw->priv->xine, &entry);
 
3529
        } else {
 
3530
                xine_cfg_entry_t entry;
 
3531
                bvw_config_helper_string (bvw->priv->xine,
 
3532
                                          entry_name,
 
3533
                                          0, &entry);
 
3534
                entry.num_value = atoi (device);
 
3535
                xine_config_update_entry (bvw->priv->xine, &entry);
3548
3536
        }
3549
3537
 
3550
3538
        mrls = xine_get_autoplay_mrls (bvw->priv->xine, plugin_id, &num_mrls);
3562
3550
                }
3563
3551
        } else if (type == MEDIA_TYPE_DVB) {
3564
3552
                /* 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);
 
3553
                if (g_str_has_prefix (mrls[0], "Sorry, No valid channels.conf found") != FALSE) {
 
3554
                        g_set_error (error, BVW_ERROR, BVW_ERROR_FILE_NOT_FOUND,
 
3555
                                     "XXX Do not use XXX");
 
3556
                        return NULL;
 
3557
                } else if (g_str_has_prefix (mrls[0], "Sorry, No DVB input device found.") != FALSE) {
 
3558
                        g_set_error (error, BVW_ERROR, BVW_ERROR_DEVICE_BUSY,
 
3559
                                     "XXX Do not use XXX");
 
3560
                        return NULL;
 
3561
                }
3570
3562
        }
3571
3563
 
3572
 
        return bacon_video_widget_strdupnv (mrls, num_mrls);
 
3564
        return bacon_video_widget_strdupnv ((const char **) mrls, num_mrls);
3573
3565
}
3574
3566
 
3575
3567
void
3737
3729
        g_return_if_fail (bvw->priv->xine != NULL);
3738
3730
        g_return_if_fail (zoom >= 0 && zoom <= 400);
3739
3731
 
3740
 
        if (bvw->priv->stream == NULL)
 
3732
        if (bvw->priv->stream == NULL) {
 
3733
                /* No stream yet, remember the zoom level */
 
3734
                bvw->priv->zoom = zoom;
3741
3735
                return;
 
3736
        }
3742
3737
 
3743
3738
        xine_set_param (bvw->priv->stream,
3744
3739
                        XINE_PARAM_VO_ZOOM_X, zoom);
4078
4073
        case BVW_INFO_HAS_AUDIO:
4079
4074
                bacon_video_widget_get_metadata_bool (bvw, type, value);
4080
4075
                break;
 
4076
        case BVW_INFO_COVER:
 
4077
                g_value_init (value, G_TYPE_OBJECT);
 
4078
                break;
4081
4079
        default:
4082
4080
                g_assert_not_reached ();
4083
4081
        }