~woodrow-shen/totem/mybranch

« back to all changes in this revision

Viewing changes to src/backend/bacon-video-widget-gst-0.10.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:
16
16
 *
17
17
 * You should have received a copy of the GNU General Public License
18
18
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
20
20
 *
21
21
 * The Totem project hereby grant permission for non-gpl compatible GStreamer
22
22
 * plugins to be used and distributed together with GStreamer and Totem. This
50
50
/* for missing decoder/demuxer detection */
51
51
#include <gst/pbutils/pbutils.h>
52
52
 
 
53
/* for the cover metadata info */
 
54
#include <gst/tag/tag.h>
 
55
 
53
56
/* system */
54
57
#include <unistd.h>
55
58
#include <time.h>
56
59
#include <string.h>
57
60
#include <stdio.h>
 
61
#include <math.h>
58
62
 
59
63
/* gtk+/gnome */
60
64
#include <gdk/gdkx.h>
61
65
#include <gtk/gtk.h>
62
66
#include <glib/gi18n.h>
 
67
#include <gio/gio.h>
63
68
#include <gconf/gconf-client.h>
64
69
 
65
70
#include "bacon-video-widget.h"
66
71
#include "bacon-video-widget-common.h"
 
72
#include "bacon-video-widget-gst-missing-plugins.h"
67
73
#include "baconvideowidget-marshal.h"
68
74
#include "video-utils.h"
69
75
#include "gstscreenshot.h"
167
173
  
168
174
  gint                         video_width; /* Movie width */
169
175
  gint                         video_height; /* Movie height */
 
176
  gboolean                     window_resized; /* Whether the window has already been resized
 
177
                                                  for this media */
170
178
  const GValue                *movie_par; /* Movie pixel aspect ratio */
171
179
  gint                         video_width_pixels; /* Scaled movie width */
172
180
  gint                         video_height_pixels; /* Scaled movie height */
552
560
  get_media_size (BACON_VIDEO_WIDGET (widget), &w, &h);
553
561
  totem_widget_set_preferred_size (widget, w, h);
554
562
 
 
563
  bacon_video_widget_gst_missing_plugins_setup (bvw);
 
564
 
555
565
#ifdef HAVE_NVTV
556
566
  if (!(nvtv_simple_init() && nvtv_enable_autoresize(TRUE))) {
557
567
    nvtv_simple_enable(FALSE);
629
639
size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw)
630
640
{
631
641
  /* FIXME */
 
642
  setup_vis (bvw);
632
643
}
633
644
 
634
645
static gboolean
1108
1119
 
1109
1120
  bvw->priv->missing_plugins = NULL;
1110
1121
  bvw->priv->plugin_install_in_progress = FALSE;
 
1122
 
 
1123
  bacon_video_widget_gst_missing_plugins_blacklist ();
1111
1124
}
1112
1125
 
1113
1126
static void
1158
1171
      g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0, NULL);
1159
1172
    }
1160
1173
 
1161
 
    if (bvw->priv->auto_resize && !bvw->priv->fullscreen_mode) {
 
1174
    if (bvw->priv->auto_resize
 
1175
        && !bvw->priv->fullscreen_mode
 
1176
        && !bvw->priv->window_resized) {
1162
1177
      gint w, h;
1163
1178
 
1164
1179
      shrink_toplevel (bvw);
1178
1193
        bacon_video_widget_expose_event (GTK_WIDGET (bvw), NULL);
1179
1194
      }
1180
1195
    }
 
1196
    bvw->priv->window_resized = TRUE;
1181
1197
  } else {
1182
1198
    g_message ("Unhandled application message %s", msg_name);
1183
1199
  }
1382
1398
 
1383
1399
        error = bvw_error_from_gst_error (bvw, message);
1384
1400
 
 
1401
        bvw->priv->target_state = GST_STATE_NULL;
 
1402
        if (bvw->priv->play)
 
1403
          gst_element_set_state (bvw->priv->play, GST_STATE_NULL);
 
1404
 
 
1405
        bvw->priv->buffering = FALSE;
 
1406
 
1385
1407
        g_signal_emit (bvw, bvw_signals[SIGNAL_ERROR], 0,
1386
1408
                       error->message, TRUE, FALSE);
1387
1409
 
1388
 
        if (bvw->priv->play)
1389
 
          gst_element_set_state (bvw->priv->play, GST_STATE_NULL);
1390
 
 
1391
 
        bvw->priv->target_state = GST_STATE_NULL;
1392
 
        bvw->priv->buffering = FALSE;
1393
1410
        g_error_free (error);
1394
1411
      }
1395
1412
      break;
1441
1458
       * only later when we can be sure we got it all */
1442
1459
      if (bvw->priv->use_type == BVW_USE_TYPE_VIDEO ||
1443
1460
          bvw->priv->use_type == BVW_USE_TYPE_AUDIO) {
1444
 
        g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
 
1461
        /* If we updated metadata and we have a new title, send it
 
1462
         * using TITLE_CHANGE, so that the UI knows it has a new
 
1463
         * streaming title */
 
1464
        GValue value = { 0, };
 
1465
 
 
1466
        g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
 
1467
 
 
1468
        bacon_video_widget_get_metadata (bvw, BVW_INFO_TITLE, &value);
 
1469
        if (g_value_get_string (&value))
 
1470
          g_signal_emit (bvw, bvw_signals[SIGNAL_TITLE_CHANGE], 0, g_value_get_string (&value));
 
1471
        g_value_unset (&value);
1445
1472
      }
1446
1473
      break;
1447
1474
    }
1626
1653
 
1627
1654
  g_return_if_fail (bvw != NULL);
1628
1655
  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
1629
 
  g_return_if_fail (bvw->priv->logo_mode == FALSE);
1630
1656
 
1631
1657
  bvw->priv->current_time_nanos = time_nanos;
1632
1658
 
2238
2264
  }
2239
2265
}
2240
2266
 
 
2267
gboolean
 
2268
bacon_video_widget_can_deinterlace (BaconVideoWidget *bvw)
 
2269
{
 
2270
  return FALSE;
 
2271
}
 
2272
 
2241
2273
void
2242
2274
bacon_video_widget_set_deinterlacing (BaconVideoWidget * bvw,
2243
2275
                                      gboolean deinterlace)
2625
2657
    const gchar * mrl, const gchar *subtitle_uri, GError ** error)
2626
2658
{
2627
2659
  GstMessage *err_msg = NULL;
 
2660
  GFile *file;
2628
2661
  gboolean ret;
 
2662
  char *path;
2629
2663
 
2630
2664
  g_return_val_if_fail (bvw != NULL, FALSE);
2631
2665
  g_return_val_if_fail (mrl != NULL, FALSE);
2640
2674
  GST_DEBUG ("mrl = %s", GST_STR_NULL (mrl));
2641
2675
  GST_DEBUG ("subtitle_uri = %s", GST_STR_NULL (subtitle_uri));
2642
2676
  
2643
 
  /* hmm... */
2644
 
  if (bvw->com->mrl && strcmp (bvw->com->mrl, mrl) == 0) {
2645
 
    GST_DEBUG ("same as current mrl");
2646
 
    /* FIXME: shouldn't we ensure playing state here? */
2647
 
    return TRUE;
2648
 
  }
2649
 
 
2650
2677
  /* this allows non-URI type of files in the thumbnailer and so on */
2651
 
  g_free (bvw->com->mrl);
2652
 
  if (mrl[0] == '/') {
2653
 
    bvw->com->mrl = g_strdup_printf ("file://%s", mrl);
 
2678
  file = g_file_new_for_commandline_arg (mrl);
 
2679
 
 
2680
  /* Only use the URI when FUSE isn't available for a file */
 
2681
  path = g_file_get_path (file);
 
2682
  if (path) {
 
2683
    bvw->com->mrl = g_filename_to_uri (path, NULL, NULL);
 
2684
    g_free (path);
2654
2685
  } else {
2655
 
    if (strchr (mrl, ':')) {
2656
 
      bvw->com->mrl = g_strdup (mrl);
2657
 
    } else {
2658
 
      gchar *cur_dir = g_get_current_dir ();
2659
 
 
2660
 
      if (!cur_dir) {
2661
 
        g_set_error (error, BVW_ERROR, BVW_ERROR_GENERIC,
2662
 
                     _("Failed to retrieve working directory"));
2663
 
        return FALSE;
2664
 
      }
2665
 
      bvw->com->mrl = g_strdup_printf ("file://%s/%s", cur_dir, mrl);
2666
 
      g_free (cur_dir);
2667
 
    }
 
2686
    bvw->com->mrl = g_strdup (mrl);
2668
2687
  }
2669
2688
 
 
2689
  g_object_unref (file);
 
2690
 
2670
2691
  if (g_str_has_prefix (mrl, "icy:") != FALSE) {
2671
2692
    /* Handle "icy://" URLs from QuickTime */
2672
2693
    g_free (bvw->com->mrl);
2937
2958
  GST_LOG ("Stopping");
2938
2959
  bvw_stop_play_pipeline (bvw);
2939
2960
 
2940
 
  if (bvw->priv->logo_mode == FALSE)
2941
 
    return;
2942
 
 
2943
2961
  /* Reset position to 0 when stopping */
2944
2962
  got_time_tick (GST_ELEMENT (bvw->priv->play), 0, bvw);
2945
2963
}
2956
2974
 
2957
2975
  g_free (bvw->com->mrl);
2958
2976
  bvw->com->mrl = NULL;
 
2977
  bvw->priv->window_resized = FALSE;
2959
2978
 
2960
2979
  g_object_notify (G_OBJECT (bvw), "seekable");
2961
2980
  g_signal_emit (bvw, bvw_signals[SIGNAL_CHANNELS_CHANGE], 0);
3650
3669
  return 100;
3651
3670
}
3652
3671
 
 
3672
/* Search for the color balance channel corresponding to type and return it. */
 
3673
static GstColorBalanceChannel *
 
3674
bvw_get_color_balance_channel (GstColorBalance * color_balance,
 
3675
    BaconVideoWidgetVideoProperty type)
 
3676
{
 
3677
  const GList *channels;
 
3678
 
 
3679
  channels = gst_color_balance_list_channels (color_balance);
 
3680
 
 
3681
  for (; channels != NULL; channels = channels->next) {
 
3682
    GstColorBalanceChannel *c = channels->data;
 
3683
 
 
3684
    if (type == BVW_VIDEO_BRIGHTNESS && g_strrstr (c->label, "BRIGHTNESS"))
 
3685
      return g_object_ref (c);
 
3686
    else if (type == BVW_VIDEO_CONTRAST && g_strrstr (c->label, "CONTRAST"))
 
3687
      return g_object_ref (c);
 
3688
    else if (type == BVW_VIDEO_SATURATION && g_strrstr (c->label, "SATURATION"))
 
3689
      return g_object_ref (c);
 
3690
    else if (type == BVW_VIDEO_HUE && g_strrstr (c->label, "HUE"))
 
3691
      return g_object_ref (c);
 
3692
  }
 
3693
 
 
3694
  return NULL;
 
3695
}
 
3696
 
3653
3697
int
3654
3698
bacon_video_widget_get_video_property (BaconVideoWidget *bvw,
3655
3699
                                       BaconVideoWidgetVideoProperty type)
3663
3707
  
3664
3708
  if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance))
3665
3709
    {
3666
 
      const GList *channels_list = NULL;
3667
3710
      GstColorBalanceChannel *found_channel = NULL;
3668
3711
      
3669
 
      channels_list = gst_color_balance_list_channels (bvw->priv->balance);
 
3712
      found_channel = bvw_get_color_balance_channel (bvw->priv->balance, type);
3670
3713
      
3671
 
      while (channels_list != NULL && found_channel == NULL)
3672
 
        { /* We search for the right channel corresponding to type */
3673
 
          GstColorBalanceChannel *channel = channels_list->data;
3674
 
 
3675
 
          if (type == BVW_VIDEO_BRIGHTNESS && channel &&
3676
 
              g_strrstr (channel->label, "BRIGHTNESS"))
3677
 
            {
3678
 
              g_object_ref (channel);
3679
 
              found_channel = channel;
3680
 
            }
3681
 
          else if (type == BVW_VIDEO_CONTRAST && channel &&
3682
 
              g_strrstr (channel->label, "CONTRAST"))
3683
 
            {
3684
 
              g_object_ref (channel);
3685
 
              found_channel = channel;
3686
 
            }
3687
 
          else if (type == BVW_VIDEO_SATURATION && channel &&
3688
 
              g_strrstr (channel->label, "SATURATION"))
3689
 
            {
3690
 
              g_object_ref (channel);
3691
 
              found_channel = channel;
3692
 
            }
3693
 
          else if (type == BVW_VIDEO_HUE && channel &&
3694
 
              g_strrstr (channel->label, "HUE"))
3695
 
            {
3696
 
              g_object_ref (channel);
3697
 
              found_channel = channel;
3698
 
            }
3699
 
          channels_list = g_list_next (channels_list);
3700
 
        }
3701
 
        
3702
3714
      if (found_channel && GST_IS_COLOR_BALANCE_CHANNEL (found_channel)) {
3703
3715
        gint cur;
3704
3716
 
3708
3720
        GST_DEBUG ("channel %s: cur=%d, min=%d, max=%d", found_channel->label,
3709
3721
            cur, found_channel->min_value, found_channel->max_value);
3710
3722
 
3711
 
        ret = ((double) cur - found_channel->min_value) * 65535 /
3712
 
              ((double) found_channel->max_value - found_channel->min_value);
 
3723
        ret = floor (0.5 +
 
3724
            ((double) cur - found_channel->min_value) * 65535 /
 
3725
            ((double) found_channel->max_value - found_channel->min_value));
3713
3726
 
3714
3727
        GST_DEBUG ("channel %s: returning value %d", found_channel->label, ret);
3715
3728
        g_object_unref (found_channel);
3744
3757
 
3745
3758
  if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance))
3746
3759
    {
3747
 
      const GList *channels_list = NULL;
3748
3760
      GstColorBalanceChannel *found_channel = NULL;
3749
3761
      
3750
 
      channels_list = gst_color_balance_list_channels (bvw->priv->balance);
3751
 
 
3752
 
      while (found_channel == NULL && channels_list != NULL) {
3753
 
          /* We search for the right channel corresponding to type */
3754
 
          GstColorBalanceChannel *channel = channels_list->data;
3755
 
 
3756
 
          if (type == BVW_VIDEO_BRIGHTNESS && channel &&
3757
 
              g_strrstr (channel->label, "BRIGHTNESS"))
3758
 
            {
3759
 
              g_object_ref (channel);
3760
 
              found_channel = channel;
3761
 
            }
3762
 
          else if (type == BVW_VIDEO_CONTRAST && channel &&
3763
 
              g_strrstr (channel->label, "CONTRAST"))
3764
 
            {
3765
 
              g_object_ref (channel);
3766
 
              found_channel = channel;
3767
 
            }
3768
 
          else if (type == BVW_VIDEO_SATURATION && channel &&
3769
 
              g_strrstr (channel->label, "SATURATION"))
3770
 
            {
3771
 
              g_object_ref (channel);
3772
 
              found_channel = channel;
3773
 
            }
3774
 
          else if (type == BVW_VIDEO_HUE && channel &&
3775
 
              g_strrstr (channel->label, "HUE"))
3776
 
            {
3777
 
              g_object_ref (channel);
3778
 
              found_channel = channel;
3779
 
            }
3780
 
          channels_list = g_list_next (channels_list);
3781
 
        }
 
3762
      found_channel = bvw_get_color_balance_channel (bvw->priv->balance, type);
3782
3763
 
3783
3764
      if (found_channel && GST_IS_COLOR_BALANCE_CHANNEL (found_channel))
3784
3765
        {
3785
 
          int i_value = value * ((double) found_channel->max_value -
3786
 
              found_channel->min_value) / 65535 + found_channel->min_value;
 
3766
          int i_value;
 
3767
          
 
3768
          i_value = floor (0.5 + value * ((double) found_channel->max_value -
 
3769
              found_channel->min_value) / 65535 + found_channel->min_value);
3787
3770
 
3788
3771
          GST_DEBUG ("channel %s: set to %d/65535", found_channel->label, value);
3789
3772
 
3907
3890
  gchar *filename;
3908
3891
 
3909
3892
  filename = g_strdup(g_getenv("GST_DVB_CHANNELS_CONF"));
3910
 
  if (filename == NULL) {
 
3893
  if (filename == NULL || g_file_test (filename, G_FILE_TEST_IS_REGULAR) == FALSE) {
3911
3894
    gchar *directory;
3912
 
 
3913
3895
    guint major, minor, micro, nano;
 
3896
 
 
3897
    g_free (filename);
3914
3898
    gst_version(&major, &minor, &micro, &nano);
3915
3899
    directory = g_strdup_printf (".gstreamer-%d.%d", major, minor);
3916
3900
    filename = g_build_filename (g_get_home_dir (), directory, "dvb-channels.conf", NULL);
3917
3901
    g_free (directory);
 
3902
 
 
3903
    if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) == FALSE) {
 
3904
      g_free (filename);
 
3905
      filename = g_build_filename (g_get_home_dir (), ".xine", "channels.conf", NULL);
 
3906
    }
3918
3907
  }
3919
3908
 
3920
3909
  return filename;
3921
3910
}
3922
3911
 
3923
 
BaconVideoWidgetCanPlayStatus
3924
 
bacon_video_widget_can_play (BaconVideoWidget * bvw, TotemDiscMediaType type)
3925
 
{
3926
 
  BaconVideoWidgetCanPlayStatus res;
3927
 
 
3928
 
  g_return_val_if_fail (bvw != NULL, FALSE);
3929
 
  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
3930
 
  g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE);
3931
 
 
3932
 
  switch (type) {
3933
 
    case MEDIA_TYPE_VCD:
3934
 
      res = BVW_CAN_PLAY_SUCCESS;
3935
 
      break;
3936
 
    case MEDIA_TYPE_DVD: {
3937
 
      if (!gst_default_registry_check_feature_version ("dvdreadsrc", 0, 10, 0)) {
3938
 
        GST_DEBUG ("Missing dvdreadsrc");
3939
 
        res = BVW_CAN_PLAY_MISSING_PLUGINS;
3940
 
      } else if (gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 0) &&
3941
 
                 !gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 15)) {
3942
 
        GST_DEBUG ("flupsdemux not new enough for DVD playback");
3943
 
        res = BVW_CAN_PLAY_MISSING_PLUGINS;
3944
 
      } else {
3945
 
        res = BVW_CAN_PLAY_SUCCESS;
3946
 
      }
3947
 
      break;
3948
 
    }
3949
 
    case MEDIA_TYPE_DVB: {
3950
 
      gchar *filename;
3951
 
 
3952
 
      /* FIXME: change to 0,10,6 once gst-plugins-bad 0.10.6 has been released */
3953
 
      if (!gst_default_registry_check_feature_version ("dvbbasebin", 0, 10, 0) ||
3954
 
          !gst_default_registry_check_feature_version ("mpegtsparse", 0, 10, 0) ||
3955
 
          !gst_default_registry_check_feature_version ("dvbsrc", 0, 10, 0)) {
3956
 
        GST_DEBUG ("Missing one or all of: dvbsrc, dvbbasebin, mpegtsparse");
3957
 
        res = BVW_CAN_PLAY_MISSING_PLUGINS;
3958
 
        break;
3959
 
      }
3960
 
      if (gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 0) &&
3961
 
          !gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 15)) {
3962
 
        GST_DEBUG ("flupsdemux not new enough for DVB playback");
3963
 
        res = BVW_CAN_PLAY_MISSING_PLUGINS;
3964
 
        break;
3965
 
      }
3966
 
 
3967
 
      filename = bacon_video_widget_get_channels_file ();
3968
 
      if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
3969
 
        res = BVW_CAN_PLAY_SUCCESS;
3970
 
      } else {
3971
 
        GST_DEBUG ("no channels file '%s'", filename);
3972
 
        res = BVW_CAN_PLAY_MISSING_CHANNELS;
3973
 
      }
3974
 
      g_free(filename);
3975
 
      break;
3976
 
    }
3977
 
    case MEDIA_TYPE_CDDA:
3978
 
    default:
3979
 
      res = BVW_CAN_PLAY_UNSUPPORTED;
3980
 
      break;
3981
 
  }
3982
 
 
3983
 
  GST_DEBUG ("type=%d, can_play=%d", type, res);
3984
 
  return res;
3985
 
}
3986
 
 
3987
3912
static char
3988
3913
bacon_video_widget_dvb_get_adapter_type (const char *device)
3989
3914
{
4027
3952
            adapter_type = 'S';
4028
3953
          } else if (g_str_equal (g_value_get_string (val), "DVB-C") != FALSE) {
4029
3954
            adapter_type = 'C';
 
3955
          } else if (g_str_equal (g_value_get_string (val), "ATSC") != FALSE) {
 
3956
            adapter_type = 'A';
4030
3957
          }
4031
3958
        }
4032
3959
        gst_message_unref (msg);
4042
3969
  return adapter_type;
4043
3970
}
4044
3971
 
 
3972
static gchar **
 
3973
bacon_video_widget_get_dvd_mrls (const char *device)
 
3974
{
 
3975
  GstFormat fmt;
 
3976
  GstElement *element;
 
3977
  gint64 num_titles, i;
 
3978
  GPtrArray *array;
 
3979
 
 
3980
  element = gst_element_factory_make ("dvdreadsrc", "test_dvdsrc");
 
3981
  if (element == NULL)
 
3982
    return NULL;
 
3983
  /* We need to get the format after instantiating dvdreadsrc, as
 
3984
   * the nick is registered in that class init */
 
3985
  fmt = gst_format_get_by_nick ("title");
 
3986
  g_object_set (element, "device", device, NULL);
 
3987
  if (gst_element_set_state (element, GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
 
3988
    GST_DEBUG ("Couldn't change the state to PAUSED");
 
3989
    gst_object_unref (element);
 
3990
    return NULL;
 
3991
  }
 
3992
  if (gst_element_query_duration (element, &fmt, &num_titles) == FALSE) {
 
3993
    GST_DEBUG ("Couldn't query the \"duration\" (number of titles)");
 
3994
    gst_element_set_state (element, GST_STATE_NULL);
 
3995
    gst_object_unref (element);
 
3996
    return NULL;
 
3997
  }
 
3998
 
 
3999
  fmt = GST_FORMAT_TIME;
 
4000
  array = g_ptr_array_new ();
 
4001
  for (i = 1 ; i <= num_titles; i++) {
 
4002
    gint64 len;
 
4003
 
 
4004
    /* Reset to NULL, change the title, and go back to PAUSED */
 
4005
    if (gst_element_set_state (element, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS) {
 
4006
      GST_DEBUG ("Couldn't set state to NULL for title %"G_GINT64_FORMAT, i);
 
4007
      break;
 
4008
    }
 
4009
    g_object_set (element, "title", i, NULL);
 
4010
    if (gst_element_set_state (element, GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
 
4011
      GST_DEBUG ("Couldn't set state for title %"G_GINT64_FORMAT, i);
 
4012
      break;
 
4013
    }
 
4014
 
 
4015
    if (gst_element_query_duration (element, &fmt, &len) == FALSE) {
 
4016
      GST_DEBUG ("Couldnt' query duration for title %"G_GINT64_FORMAT, i);
 
4017
      break;
 
4018
    }
 
4019
    /* If it's less than 30 seconds long, we kick it out */
 
4020
    if (len >= (30 * GST_SECOND)) {
 
4021
      g_ptr_array_add (array, g_strdup_printf ("dvd://%"G_GINT64_FORMAT, i));
 
4022
      GST_DEBUG ("URI: dvd://%d (time: %" GST_TIME_FORMAT ")",
 
4023
                 (gint) i, GST_TIME_ARGS (len));
 
4024
    }
 
4025
  }
 
4026
 
 
4027
  gst_element_set_state (element, GST_STATE_NULL);
 
4028
  gst_object_unref (element);
 
4029
  if (array->len >= 1)
 
4030
    g_ptr_array_add (array, NULL);
 
4031
  return (char **) g_ptr_array_free (array, FALSE);
 
4032
}
 
4033
 
 
4034
static gchar **
 
4035
bacon_video_widget_get_dvb_mrls (const char *device)
 
4036
{
 
4037
  gchar* filename;
 
4038
  gchar* contents;
 
4039
  GPtrArray *array;
 
4040
  gchar adapter_type;
 
4041
 
 
4042
  adapter_type = bacon_video_widget_dvb_get_adapter_type (device);
 
4043
  filename = bacon_video_widget_get_channels_file ();
 
4044
 
 
4045
  if (g_file_get_contents (filename, &contents, NULL, NULL) != FALSE) {
 
4046
    gchar **lines, *line;
 
4047
    guint i;
 
4048
 
 
4049
    lines = g_strsplit (contents, "\n", 0);
 
4050
    array = g_ptr_array_new ();
 
4051
 
 
4052
    for (i = 0; lines[i] != NULL; i++) {
 
4053
      line = lines[i];
 
4054
 
 
4055
      if (line[0] != '#') {
 
4056
        gchar** fields = g_strsplit(line, ":", 0);
 
4057
        if ((g_strv_length (fields) == 13 && adapter_type == 'T') ||
 
4058
            (g_strv_length (fields) == 8 && adapter_type == 'S') ||
 
4059
            (g_strv_length (fields) == 9 && adapter_type == 'C') ||
 
4060
            (g_strv_length (fields) == 6 && adapter_type == 'A')) {
 
4061
          g_ptr_array_add (array, g_strdup_printf("dvb://%s", fields[0]));
 
4062
        }
 
4063
        g_strfreev(fields);
 
4064
      }
 
4065
    }
 
4066
    g_strfreev(lines);
 
4067
  } else {
 
4068
    return NULL;
 
4069
  }
 
4070
  if (array->len >= 1)
 
4071
    g_ptr_array_add (array, NULL);
 
4072
  return (char **) g_ptr_array_free (array, FALSE);
 
4073
}
 
4074
 
4045
4075
gchar **
4046
 
bacon_video_widget_get_mrls (BaconVideoWidget * bvw, TotemDiscMediaType type,
4047
 
                             const char *device)
 
4076
bacon_video_widget_get_mrls (BaconVideoWidget * bvw,
 
4077
                             TotemDiscMediaType type,
 
4078
                             const char *device,
 
4079
                             GError **error)
4048
4080
{
4049
4081
  gchar **mrls;
4050
4082
 
4055
4087
  GST_DEBUG ("type = %d", type);
4056
4088
  GST_DEBUG ("device = %s", GST_STR_NULL (device));
4057
4089
 
 
4090
  switch (type) {
 
4091
    case MEDIA_TYPE_VCD: {
 
4092
        gchar *uri[] = { NULL, NULL };
 
4093
        uri[0] = g_strdup_printf ("vcd://%s", device);
 
4094
        mrls = g_strdupv (uri);
 
4095
        g_free (uri[0]);
 
4096
        break;
 
4097
      }
 
4098
    case MEDIA_TYPE_DVD: {
 
4099
      if (!gst_default_registry_check_feature_version ("dvdreadsrc", 0, 10, 0)) {
 
4100
        GST_DEBUG ("Missing dvdreadsrc");
 
4101
        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
4102
                     "XXX Do not use XXX");
 
4103
        return NULL;
 
4104
      } else if (!gst_default_registry_check_feature_version ("mpegpsdemux", 0, 10, 0) &&
 
4105
                 gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 0) &&
 
4106
                 !gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 15)) {
 
4107
        GST_DEBUG ("flupsdemux not new enough for DVD playback");
 
4108
        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
4109
                     "XXX Do not use XXX");
 
4110
        return NULL;
 
4111
      } else {
 
4112
        mrls = bacon_video_widget_get_dvd_mrls (device);
 
4113
      }
 
4114
      break;
 
4115
    }
 
4116
    case MEDIA_TYPE_DVB: {
 
4117
      gchar *filename;
 
4118
 
 
4119
      if (!gst_default_registry_check_feature_version ("dvbbasebin", 0, 10, 6) ||
 
4120
          !gst_default_registry_check_feature_version ("mpegtsparse", 0, 10, 6) ||
 
4121
          !gst_default_registry_check_feature_version ("dvbsrc", 0, 10, 6)) {
 
4122
        GST_DEBUG ("Missing one or all of: dvbsrc, dvbbasebin, mpegtsparse");
 
4123
        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
4124
                     "XXX Do not use XXX");
 
4125
        return NULL;
 
4126
      }
 
4127
      if (!gst_default_registry_check_feature_version ("mpegpsdemux", 0, 10, 0) &&
 
4128
          gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 0) &&
 
4129
          !gst_default_registry_check_feature_version ("flupsdemux", 0, 10, 15)) {
 
4130
        GST_DEBUG ("flupsdemux not new enough for DVB playback");
 
4131
        g_set_error (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE,
 
4132
                     "XXX Do not use XXX");
 
4133
        return NULL;
 
4134
      }
 
4135
 
 
4136
      filename = g_strdup_printf ("/dev/dvb/adapter%s/frontend0", device);
 
4137
      if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
 
4138
        g_free (filename);
 
4139
        g_set_error (error, BVW_ERROR, BVW_ERROR_INVALID_DEVICE,
 
4140
                     "XXX Do not use XXX");
 
4141
        return NULL;
 
4142
      }
 
4143
      g_free (filename);
 
4144
 
 
4145
      filename = bacon_video_widget_get_channels_file ();
 
4146
      if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
 
4147
        g_free (filename);
 
4148
        mrls = bacon_video_widget_get_dvb_mrls (device);
 
4149
      } else {
 
4150
        GST_DEBUG ("no channels file '%s'", filename);
 
4151
        g_set_error (error, BVW_ERROR, BVW_ERROR_FILE_NOT_FOUND,
 
4152
                     "XXX Do not use XXX");
 
4153
        g_free (filename);
 
4154
        return NULL;
 
4155
      }
 
4156
      break;
 
4157
    }
 
4158
    case MEDIA_TYPE_CDDA:
 
4159
      g_set_error (error, BVW_ERROR, BVW_ERROR_UNVALID_LOCATION,
 
4160
                   "XXX Do not use XXX");
 
4161
      return NULL;
 
4162
    default:
 
4163
      g_assert_not_reached();
 
4164
  }
 
4165
 
 
4166
  if (mrls == NULL)
 
4167
    return NULL;
 
4168
 
4058
4169
  g_free (bvw->priv->media_device);
4059
4170
  bvw->priv->media_device = g_strdup (device);
4060
4171
 
4061
 
  switch (type) {
4062
 
    case MEDIA_TYPE_VCD: {
4063
 
      gchar *uri[] = { NULL, NULL };
4064
 
      uri[0] = g_strdup_printf ("vcd://%s", device);
4065
 
      mrls = g_strdupv (uri);
4066
 
      g_free (uri[0]);
4067
 
      break;
4068
 
    }
4069
 
 
4070
 
    case MEDIA_TYPE_DVD: {
4071
 
      GstFormat fmt;
4072
 
      GstElement *element;
4073
 
      gint64 num_titles, i;
4074
 
      GPtrArray *array;
4075
 
 
4076
 
      element = gst_element_factory_make ("dvdreadsrc", "test_dvdsrc");
4077
 
      if (element == NULL)
4078
 
        return NULL;
4079
 
      /* We need to get the format after instantiating dvdreadsrc, as
4080
 
       * the nick is registered in that class init */
4081
 
      fmt = gst_format_get_by_nick ("title");
4082
 
      g_object_set (element, "device", device, NULL);
4083
 
      if (gst_element_set_state (element, GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
4084
 
        GST_DEBUG ("Couldn't change the state to PAUSED");
4085
 
        gst_object_unref (element);
4086
 
        return NULL;
4087
 
      }
4088
 
      if (gst_element_query_duration (element, &fmt, &num_titles) == FALSE) {
4089
 
        GST_DEBUG ("Couldn't query the \"duration\" (number of titles)");
4090
 
        gst_element_set_state (element, GST_STATE_NULL);
4091
 
        gst_object_unref (element);
4092
 
        return NULL;
4093
 
      }
4094
 
 
4095
 
      fmt = GST_FORMAT_TIME;
4096
 
      array = g_ptr_array_new ();
4097
 
      for (i = 1 ; i <= num_titles; i++) {
4098
 
        gint64 len;
4099
 
 
4100
 
        /* Reset to NULL, change the title, and go back to PAUSED */
4101
 
        if (gst_element_set_state (element, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS) {
4102
 
          GST_DEBUG ("Couldn't set state to NULL for title %"G_GINT64_FORMAT, i);
4103
 
          break;
4104
 
        }
4105
 
        g_object_set (element, "title", i, NULL);
4106
 
        if (gst_element_set_state (element, GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
4107
 
          GST_DEBUG ("Couldn't set state for title %"G_GINT64_FORMAT, i);
4108
 
          break;
4109
 
        }
4110
 
 
4111
 
        if (gst_element_query_duration (element, &fmt, &len) == FALSE) {
4112
 
          GST_DEBUG ("Couldnt' query duration for title %"G_GINT64_FORMAT, i);
4113
 
          break;
4114
 
        }
4115
 
        /* If it's less than 30 seconds long, we kick it out */
4116
 
        if (len >= (30 * GST_SECOND)) {
4117
 
          g_ptr_array_add (array, g_strdup_printf ("dvd://%"G_GINT64_FORMAT, i));
4118
 
          GST_DEBUG ("URI: dvd://%d (time: %" GST_TIME_FORMAT ")",
4119
 
              (gint) i, GST_TIME_ARGS (len));
4120
 
        }
4121
 
      }
4122
 
 
4123
 
      gst_element_set_state (element, GST_STATE_NULL);
4124
 
      gst_object_unref (element);
4125
 
      if (array->len >= 1)
4126
 
        g_ptr_array_add (array, NULL);
4127
 
      mrls = (char **) g_ptr_array_free (array, FALSE);
4128
 
      break;
4129
 
    }
4130
 
    case MEDIA_TYPE_DVB: {
4131
 
      gchar* filename;
4132
 
      gchar* contents;
4133
 
      GPtrArray *array;
4134
 
      gchar adapter_type;
4135
 
 
4136
 
      adapter_type = bacon_video_widget_dvb_get_adapter_type (device);
4137
 
      filename = bacon_video_widget_get_channels_file ();
4138
 
 
4139
 
      if (g_file_get_contents (filename, &contents, NULL, NULL) != FALSE) {
4140
 
        gchar **lines, *line;
4141
 
        guint i;
4142
 
 
4143
 
        lines = g_strsplit (contents, "\n", 0);
4144
 
        array = g_ptr_array_new ();
4145
 
 
4146
 
        for (i = 0; lines[i] != NULL; i++) {
4147
 
          line = lines[i];
4148
 
 
4149
 
          if (line[0] != '#') {
4150
 
            gchar** fields = g_strsplit(line, ":", 0);
4151
 
            if ((g_strv_length (fields) == 13 && adapter_type == 'T') ||
4152
 
                (g_strv_length (fields) == 8 && adapter_type == 'S') ||
4153
 
                (g_strv_length (fields) == 9 && adapter_type == 'C')) {
4154
 
              g_ptr_array_add (array, g_strdup_printf("dvb://%s", fields[0]));
4155
 
            }
4156
 
            g_strfreev(fields);
4157
 
          }
4158
 
        }
4159
 
        g_strfreev(lines);
4160
 
      } else {
4161
 
        return NULL;
4162
 
      }
4163
 
      if (array->len >= 1)
4164
 
        g_ptr_array_add (array, NULL);
4165
 
      mrls = (char **) g_ptr_array_free (array, FALSE);
4166
 
      break;
4167
 
    }
4168
 
    default:
4169
 
      mrls = NULL;
4170
 
      break;
4171
 
  }
4172
 
 
4173
4172
  return mrls;
4174
4173
}
4175
4174
 
4571
4570
  gst_object_unref (bus);
4572
4571
}
4573
4572
 
 
4573
static GdkPixbuf *
 
4574
bacon_video_widget_get_metadata_pixbuf (BaconVideoWidget * bvw,
 
4575
                                        GstBuffer *buffer)
 
4576
{
 
4577
  GdkPixbufLoader *loader;
 
4578
  GdkPixbuf *pixbuf;
 
4579
 
 
4580
  loader = gdk_pixbuf_loader_new ();
 
4581
  if (!gdk_pixbuf_loader_write (loader, buffer->data, buffer->size, NULL)) {
 
4582
    g_object_unref (loader);
 
4583
    return NULL;
 
4584
  }
 
4585
  if (!gdk_pixbuf_loader_close (loader, NULL)) {
 
4586
    g_object_unref (loader);
 
4587
    return NULL;
 
4588
  }
 
4589
 
 
4590
  pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
 
4591
  if (pixbuf)
 
4592
    g_object_ref (pixbuf);
 
4593
  g_object_unref (loader);
 
4594
  return pixbuf;
 
4595
}
 
4596
 
 
4597
static const GValue *
 
4598
bacon_video_widget_get_best_image (BaconVideoWidget *bvw)
 
4599
{
 
4600
  const GValue *cover_value = NULL;
 
4601
  guint i;
 
4602
 
 
4603
  for (i = 0; ; i++) {
 
4604
    const GValue *value;
 
4605
    GstBuffer *buffer;
 
4606
    GstStructure *caps_struct;
 
4607
    int type;
 
4608
 
 
4609
    value = gst_tag_list_get_value_index (bvw->priv->tagcache,
 
4610
                                          GST_TAG_IMAGE,
 
4611
                                          i);
 
4612
    if (value == NULL)
 
4613
      break;
 
4614
 
 
4615
    buffer = gst_value_get_buffer (value);
 
4616
 
 
4617
    caps_struct = gst_caps_get_structure (buffer->caps, 0);
 
4618
    gst_structure_get_enum (caps_struct,
 
4619
                            "image-type",
 
4620
                            GST_TYPE_TAG_IMAGE_TYPE,
 
4621
                            &type);
 
4622
    if (type == GST_TAG_IMAGE_TYPE_UNDEFINED) {
 
4623
      if (cover_value == NULL)
 
4624
        cover_value = value;
 
4625
    } else if (type == GST_TAG_IMAGE_TYPE_FRONT_COVER) {
 
4626
      cover_value = value;
 
4627
      break;
 
4628
    }
 
4629
  }
 
4630
 
 
4631
  return cover_value;
 
4632
}
 
4633
 
4574
4634
void
4575
4635
bacon_video_widget_get_metadata (BaconVideoWidget * bvw,
4576
4636
                                 BaconVideoWidgetMetadataType type,
4606
4666
    case BVW_INFO_HAS_AUDIO:
4607
4667
      bacon_video_widget_get_metadata_bool (bvw, type, value);
4608
4668
      break;
 
4669
    case BVW_INFO_COVER:
 
4670
      {
 
4671
        const GValue *cover_value;
 
4672
 
 
4673
        g_value_init (value, G_TYPE_OBJECT);
 
4674
 
 
4675
        if (bvw->priv->tagcache == NULL)
 
4676
          break;
 
4677
        cover_value = bacon_video_widget_get_best_image (bvw);
 
4678
        if (!cover_value) {
 
4679
          cover_value = gst_tag_list_get_value_index (bvw->priv->tagcache,
 
4680
                                                      GST_TAG_PREVIEW_IMAGE,
 
4681
                                                      0);
 
4682
        }
 
4683
        if (cover_value) {
 
4684
          GstBuffer *buffer;
 
4685
          GdkPixbuf *pixbuf;
 
4686
 
 
4687
          buffer = gst_value_get_buffer (cover_value);
 
4688
          pixbuf = bacon_video_widget_get_metadata_pixbuf (bvw, buffer);
 
4689
          if (pixbuf)
 
4690
            g_value_take_object (value, pixbuf);
 
4691
        }
 
4692
      }
 
4693
      break;
4609
4694
    default:
4610
4695
      g_return_if_reached ();
4611
4696
    }
5378
5463
  }
5379
5464
}
5380
5465
 
 
5466
/*
 
5467
 * vim: sw=2 ts=8 cindent noai bs=2
 
5468
 */