[banshee] [libbanshee] Windows fixes (bgo#614046)



commit 8f924b2992e0c5375fe5819a52292e71daac5cba
Author: Julien Moutte <julien fluendo com>
Date:   Sun Apr 4 16:18:16 2010 +1000

    [libbanshee] Windows fixes (bgo#614046)
    
    There are multiple issues involved :
    
    * Does not use a proper video rendering element.
    * Does not support XOverlay interface on Windows.
    * Should not iterate through callbacks from unmanaged to managed code.
    * Does not handle the case where force-aspect-ratio might not be
      available.
    * Does not support Visual Studio varargs constraints for debugging.
    * Does not declare delegate callback correctly, producing crashes on
      Windows.
    
    Proposed patch fixes build on Windows, uses autovideosink as a fallback
    to gconf, provides a callback for video geometry information, declares
    delegate correctly and enable XOverlay for Win32.
    
    This is the first patch from Moovida merge.
    
    Signed-off-by: Alexander Kojevnikov <alexander kojevnikov com>

 libbanshee/banshee-player-cdda.c                   |   16 ++--
 libbanshee/banshee-player-equalizer.c              |   13 ++-
 libbanshee/banshee-player-missing-elements.c       |    6 +-
 libbanshee/banshee-player-pipeline.c               |   42 ++++++--
 libbanshee/banshee-player-private.h                |   34 ++++++-
 libbanshee/banshee-player-replaygain.c             |   21 +++--
 libbanshee/banshee-player-video.c                  |  103 ++++++++++++++++++--
 libbanshee/banshee-player-video.h                  |    5 +-
 libbanshee/banshee-player.c                        |   54 +----------
 libbanshee/banshee-ripper.c                        |    6 +-
 .../Banshee.GStreamer/PlayerEngine.cs              |   54 ++++++++---
 .../Banshee.GStreamer/Banshee.GStreamer/Service.cs |    1 +
 12 files changed, 239 insertions(+), 116 deletions(-)
---
diff --git a/libbanshee/banshee-player-cdda.c b/libbanshee/banshee-player-cdda.c
index 58fb14b..8be2bdd 100644
--- a/libbanshee/banshee-player-cdda.c
+++ b/libbanshee/banshee-player-cdda.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -73,7 +75,7 @@ bp_cdda_on_notify_source (GstElement *playbin, gpointer unknown, BansheePlayer *
     
     // Technically don't need to check the class, since GstCddaBaseSrc elements will always have this
     if (G_LIKELY (g_object_class_find_property (G_OBJECT_GET_CLASS (cdda_src), "device"))) {
-        bp_debug ("bp_cdda: setting device property on source (%s)", player->cdda_device);
+        bp_debug2 ("bp_cdda: setting device property on source (%s)", player->cdda_device);
         g_object_set (cdda_src, "device", player->cdda_device, NULL);
     }
     
@@ -112,7 +114,7 @@ bp_cdda_source_seek_to_track (GstElement *playbin, guint track)
     
     if (gst_element_seek (playbin, 1.0, format, GST_SEEK_FLAG_FLUSH, 
         GST_SEEK_TYPE_SET, track - 1, GST_SEEK_TYPE_NONE, -1)) {
-        bp_debug ("bp_cdda: seeking to track %d, avoiding playbin", track);
+        bp_debug2 ("bp_cdda: seeking to track %d, avoiding playbin", track);
         g_object_unref (cdda_src);
         return TRUE;
     }
@@ -149,7 +151,7 @@ _bp_cdda_handle_uri (BansheePlayer *player, const gchar *uri)
     if (player == NULL || uri == NULL || !g_str_has_prefix (uri, "cdda://")) {
         // Something is hosed or the URI isn't actually CDDA
         if (player->cdda_device != NULL) {
-            bp_debug ("bp_cdda: finished using device (%s)", player->cdda_device);
+            bp_debug2 ("bp_cdda: finished using device (%s)", player->cdda_device);
             g_free (player->cdda_device);
             player->cdda_device = NULL;
         }
@@ -163,7 +165,7 @@ _bp_cdda_handle_uri (BansheePlayer *player, const gchar *uri)
         // have its own valid device node
         g_free (player->cdda_device);
         player->cdda_device = NULL;
-        bp_debug ("bp_cdda: invalid device node in URI (%s)", uri);
+        bp_debug2 ("bp_cdda: invalid device node in URI (%s)", uri);
         return FALSE;
     }
     
@@ -173,7 +175,7 @@ _bp_cdda_handle_uri (BansheePlayer *player, const gchar *uri)
         // If we weren't already playing from a CD, cache the
         // device and allow playbin to begin playing it
         player->cdda_device = g_strdup (new_cdda_device);
-        bp_debug ("bp_cdda: storing device node for fast seeks (%s)", player->cdda_device);
+        bp_debug2 ("bp_cdda: storing device node for fast seeks (%s)", player->cdda_device);
         return FALSE;
     }
     
@@ -184,14 +186,14 @@ _bp_cdda_handle_uri (BansheePlayer *player, const gchar *uri)
         gchar *track_str = g_strndup (uri + 7, strlen (uri) - strlen (new_cdda_device) - 8);
         gint track_num = atoi (track_str);
         g_free (track_str);
-        bp_debug ("bp_cdda: fast seeking to track on already playing device (%s)", player->cdda_device);
+        bp_debug2 ("bp_cdda: fast seeking to track on already playing device (%s)", player->cdda_device);
         
         return bp_cdda_source_seek_to_track (player->playbin, track_num);
     }
     
     // We were already playing some CD, but switched to a different device node, 
     // so unset and re-cache the new device node and allow playbin to do its thing
-    bp_debug ("bp_cdda: switching devices for CDDA playback (from %s, to %s)", player->cdda_device, new_cdda_device);
+    bp_debug3 ("bp_cdda: switching devices for CDDA playback (from %s, to %s)", player->cdda_device, new_cdda_device);
     g_free (player->cdda_device);
     player->cdda_device = g_strdup(new_cdda_device);
     
diff --git a/libbanshee/banshee-player-equalizer.c b/libbanshee/banshee-player-equalizer.c
index 9e28d6d..a496ada 100644
--- a/libbanshee/banshee-player-equalizer.c
+++ b/libbanshee/banshee-player-equalizer.c
@@ -5,8 +5,10 @@
 //   Alexander Hixon <hixon alexander mediati org>
 //   Aaron Bockover <abockover novell com>
 //   Sebastian Dröge  <slomo circular-chaos org>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -67,19 +69,18 @@ _bp_equalizer_new (BansheePlayer *player)
         player->equalizer_status == BP_EQ_STATUS_USE_SYSTEM) {
         equalizer = gst_element_factory_make ("equalizer-10bands", "equalizer-10bands");
         if (equalizer != NULL) {
+            GstElementFactory *efactory = NULL;
+
             if (player->equalizer_status == BP_EQ_STATUS_USE_SYSTEM) {
                 return equalizer;
             }
             
-// TODO Windows compiler doesn't like this, I'm unsure why
-#ifndef WIN32
-            GstElementFactory *efactory = gst_element_get_factory (equalizer);
+            efactory = gst_element_get_factory (equalizer);
             if (gst_plugin_feature_check_version (GST_PLUGIN_FEATURE (efactory), 0, 10, 9)) {
                 bp_debug ("Using system (gst-plugins-good) equalizer element");
                 player->equalizer_status = BP_EQ_STATUS_USE_SYSTEM;
                 return equalizer;
             }
-#endif
             
             bp_debug ("Buggy system equalizer found. gst-plugins-good 0.10.9 or better "
                 "required, or build Banshee with the built-in equalizer.");
@@ -150,8 +151,8 @@ bp_equalizer_get_bandrange (BansheePlayer *player, gint *min, gint *max)
 
     if (pspec != NULL && G_IS_PARAM_SPEC_DOUBLE (pspec)) {
         dpspec = (GParamSpecDouble *) pspec;
-        *min = dpspec->minimum;
-        *max = dpspec->maximum;
+        *min = (gint) dpspec->minimum;
+        *max = (gint) dpspec->maximum;
         return;
     } else {
        g_warning ("Could not find valid gain range for equalizer element");
diff --git a/libbanshee/banshee-player-missing-elements.c b/libbanshee/banshee-player-missing-elements.c
index 59f43d2..20804c4 100644
--- a/libbanshee/banshee-player-missing-elements.c
+++ b/libbanshee/banshee-player-missing-elements.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -127,12 +129,12 @@ _bp_missing_elements_process_message (BansheePlayer *player, GstMessage *message
         // Only save the error if we've never encounted it before
         for (; node != NULL; node = node->next) {
             if (g_ascii_strcasecmp (node->data, detail) == 0) {
-                bp_debug ("Ignoring missing element details, already prompted ('%s')", detail);
+                bp_debug2 ("Ignoring missing element details, already prompted ('%s')", detail);
                 return;
             }
         }
         
-        bp_debug ("Saving missing element details ('%s')", detail);
+        bp_debug2 ("Saving missing element details ('%s')", detail);
         player->missing_element_details = g_slist_append (player->missing_element_details, detail);  
     }
 }
diff --git a/libbanshee/banshee-player-pipeline.c b/libbanshee/banshee-player-pipeline.c
index 90b968d..1d877c4 100644
--- a/libbanshee/banshee-player-pipeline.c
+++ b/libbanshee/banshee-player-pipeline.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -67,16 +69,28 @@ bp_pipeline_process_tag (const GstTagList *tag_list, const gchar *tag_name, Bans
     }
 }
 
+static void
+playbin_stream_changed_cb (GstElement * element, BansheePlayer *player)
+{
+    GstMessage *msg;
+
+    // We're being called from the streaming thread, so don't do anything here
+    msg = gst_message_new_application (GST_OBJECT (player->playbin), gst_structure_new ("stream-changed", NULL));
+    gst_element_post_message (player->playbin, msg);
+}
+
 static gboolean
 bp_next_track_starting (BansheePlayer *player)
 {
+    gboolean has_video;
+
     g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
     g_return_val_if_fail (GST_IS_ELEMENT (player->playbin), FALSE);
 
     // Work around BGO #602437 - gapless transition between tracks with 
     // video streams results in broken behaviour - most obviously, huge A/V
     // sync issues.
-    gboolean has_video = bp_stream_has_video (player->playbin);
+    has_video = bp_stream_has_video (player->playbin);
     if (player->in_gapless_transition && has_video) {
         gchar *uri;
     
@@ -207,6 +221,16 @@ bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
             _bp_missing_elements_process_message (player, message);
             break;
         }
+
+        case GST_MESSAGE_APPLICATION: {
+            const gchar * name;
+            const GstStructure * s = gst_message_get_structure (message);
+            name = gst_structure_get_name (s);
+            if (name && !strcmp (name, "stream-changed")) {
+                _bp_parse_stream_info (player);
+            }
+            break;
+        }
         
         default: break;
     }
@@ -236,10 +260,11 @@ static void bp_about_to_finish_callback (GstElement *playbin, BansheePlayer *pla
 
 static void bp_volume_changed_callback (GstElement *playbin, GParamSpec *spec, BansheePlayer *player)
 {
+    gdouble volume;
+
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     g_return_if_fail (GST_IS_ELEMENT (playbin));
 
-    gdouble volume;
     g_object_get (G_OBJECT (playbin), "volume", &volume, NULL);
 
     if (player->volume_changed_cb != NULL) {
@@ -276,6 +301,9 @@ _bp_pipeline_construct (BansheePlayer *player)
     g_return_val_if_fail (player->playbin != NULL, FALSE);
 
     g_signal_connect (player->playbin, "notify::volume", G_CALLBACK (bp_volume_changed_callback), player);
+    g_signal_connect (player->playbin, "video-changed", G_CALLBACK (playbin_stream_changed_cb), player);
+    g_signal_connect (player->playbin, "audio-changed", G_CALLBACK (playbin_stream_changed_cb), player);
+    g_signal_connect (player->playbin, "text-changed", G_CALLBACK (playbin_stream_changed_cb), player);
 
     // Try to find an audio sink, prefer gconf, which typically is set to auto these days,
     // fall back on auto, which should work on windows, and as a last ditch, try alsa
@@ -319,17 +347,11 @@ _bp_pipeline_construct (BansheePlayer *player)
     }
     
     // Add elements to custom audio sink
-    gst_bin_add (GST_BIN (player->audiobin), player->audiotee);
+    gst_bin_add_many (GST_BIN (player->audiobin), player->audiotee, audiosinkqueue, audiosink, NULL);
     
     if (player->equalizer != NULL) {
-        gst_bin_add (GST_BIN (player->audiobin), eq_audioconvert);
-        gst_bin_add (GST_BIN (player->audiobin), eq_audioconvert2);
-        gst_bin_add (GST_BIN (player->audiobin), player->equalizer);
-        gst_bin_add (GST_BIN (player->audiobin), player->preamp);
+        gst_bin_add_many (GST_BIN (player->audiobin), eq_audioconvert, eq_audioconvert2, player->equalizer, player->preamp, NULL);
     }
-    
-    gst_bin_add (GST_BIN (player->audiobin), audiosinkqueue);
-    gst_bin_add (GST_BIN (player->audiobin), audiosink);
    
     // Ghost pad the audio bin so audio is passed from the bin into the tee
     teepad = gst_element_get_pad (player->audiotee, "sink");
diff --git a/libbanshee/banshee-player-private.h b/libbanshee/banshee-player-private.h
index 7145b1f..3e0ad26 100644
--- a/libbanshee/banshee-player-private.h
+++ b/libbanshee/banshee-player-private.h
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -40,9 +42,12 @@
 #include <gst/fft/gstfftf32.h>
 #include <gst/pbutils/pbutils.h>
 
-#ifdef GDK_WINDOWING_X11
+#if defined(GDK_WINDOWING_X11)
 #  include <gdk/gdkx.h>
 #  include <gst/interfaces/xoverlay.h>
+#elif defined(GDK_WINDOWING_WIN32)
+#  include <gdk/gdkwin32.h>
+#  include <gst/interfaces/xoverlay.h>
 #endif
 
 #include "banshee-gst.h"
@@ -66,10 +71,17 @@
 
 
 #ifdef WIN32
-// TODO Windows doesn't like the ... varargs
-#define bp_debug(x)
+#define bp_debug(x) banshee_log_debug ("player", x)
+#define bp_debug2(x, a2) banshee_log_debug ("player", x, a2)
+#define bp_debug3(x, a2, a3) banshee_log_debug ("player", x, a2, a3)
+#define bp_debug4(x, a2, a3, a4) banshee_log_debug ("player", x, a2, a3, a4)
+#define bp_debug5(x, a2, a3, a4, a5) banshee_log_debug ("player", x, a2, a3, a4, a5)
 #else
 #define bp_debug(x...) banshee_log_debug ("player", x)
+#define bp_debug2(x...) banshee_log_debug ("player", x)
+#define bp_debug3(x...) banshee_log_debug ("player", x)
+#define bp_debug4(x...) banshee_log_debug ("player", x)
+#define bp_debug5(x...) banshee_log_debug ("player", x)
 #endif
 
 typedef struct BansheePlayer BansheePlayer;
@@ -87,6 +99,7 @@ typedef void (* BansheePlayerNextTrackStartingCallback)     (BansheePlayer *play
 typedef void (* BansheePlayerAboutToFinishCallback)         (BansheePlayer *player);
 typedef GstElement * (* BansheePlayerVideoPipelineSetupCallback) (BansheePlayer *player, GstBus *bus);
 typedef void (* BansheePlayerVolumeChangedCallback) (BansheePlayer *player, gdouble new_volume);
+typedef void (* BansheePlayerVideoGeometryNotifyCallback) (BansheePlayer *player, gint width, gint height, gint fps_n, gint fps_d, gint par_n, gint par_d);
 
 typedef enum {
     BP_VIDEO_DISPLAY_CONTEXT_UNSUPPORTED = 0,
@@ -107,6 +120,7 @@ struct BansheePlayer {
     BansheePlayerAboutToFinishCallback about_to_finish_cb;
     BansheePlayerVideoPipelineSetupCallback video_pipeline_setup_cb;
     BansheePlayerVolumeChangedCallback volume_changed_cb;
+    BansheePlayerVideoGeometryNotifyCallback video_geometry_notify_cb;
 
     // Pipeline Elements
     GstElement *playbin;
@@ -126,18 +140,28 @@ struct BansheePlayer {
     // Pipeline/Playback State
     GMutex *mutex;
     GstState target_state;
-    guint iterate_timeout_id;
     gboolean buffering;
     gchar *cdda_device;
     gboolean in_gapless_transition;
     
     // Video State
     BpVideoDisplayContextType video_display_context_type;
-    #ifdef GDK_WINDOWING_X11
+    #if defined(GDK_WINDOWING_X11)
     GstXOverlay *xoverlay;
     GdkWindow *video_window;
     XID video_window_xid;
+    #elif defined(GDK_WINDOWING_WIN32)
+    GstXOverlay *xoverlay;
+    GdkWindow *video_window;
+    HWND video_window_xid;
     #endif
+    // Video geometry
+    gint width;
+    gint height;
+    gint fps_n;
+    gint fps_d;
+    gint par_n;
+    gint par_d;
        
     // Visualization State
     GstElement *vis_resampler;
diff --git a/libbanshee/banshee-player-replaygain.c b/libbanshee/banshee-player-replaygain.c
index 8c870f1..c9e92ee 100644
--- a/libbanshee/banshee-player-replaygain.c
+++ b/libbanshee/banshee-player-replaygain.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -52,6 +54,7 @@ static gdouble bp_rg_calc_history_avg (BansheePlayer *player)
 
 static void bp_replaygain_update_history (BansheePlayer *player)
 {
+    gdouble gain;
     g_return_if_fail (player->history_size <= 10);
 
     if (player->history_size == 10) {
@@ -61,10 +64,9 @@ static void bp_replaygain_update_history (BansheePlayer *player)
         player->history_size++;
     }
 
-    gdouble gain;
     g_object_get (G_OBJECT (player->rgvolume), "target-gain", &gain, NULL);
     player->rg_gain_history[0] = gain;
-    bp_debug ("[ReplayGain] Added gain: %.2f to history.", gain);
+    bp_debug2 ("[ReplayGain] Added gain: %.2f to history.", gain);
 
     g_object_set (G_OBJECT (player->rgvolume), "fallback-gain", bp_rg_calc_history_avg (player), NULL);
 }
@@ -78,13 +80,15 @@ static void on_target_gain_changed (GstElement *rgvolume, GParamSpec *pspec, Ban
 }
 
 static void
-pad_block_cb (GstPad *srcPad, gboolean blocked, gpointer user_data) {
+pad_block_cb (GstPad *srcPad, gboolean blocked, gpointer user_data)
+{
+    BansheePlayer* player;
 
     if (!blocked) {
         return;
     }
 
-    BansheePlayer* player = (BansheePlayer*) user_data;
+    player = (BansheePlayer*) user_data;
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
 
     // The pad_block_cb can get triggered multiple times, on different threads.
@@ -170,7 +174,7 @@ void _bp_rgvolume_print_volume(BansheePlayer *player)
         g_object_get (G_OBJECT (player->rgvolume), "result-gain", &scale, NULL);
         g_object_get (G_OBJECT (player->playbin), "volume", &volume, NULL);
 
-        bp_debug ("scaled volume: %.2f (ReplayGain) * %.2f (User) = %.2f",
+        bp_debug4 ("scaled volume: %.2f (ReplayGain) * %.2f (User) = %.2f",
                   bp_replaygain_db_to_linear (scale), volume,
                   bp_replaygain_db_to_linear (scale) * volume);
     }
@@ -178,10 +182,11 @@ void _bp_rgvolume_print_volume(BansheePlayer *player)
 
 void _bp_replaygain_pipeline_rebuild (BansheePlayer* player)
 {
-    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    GstPad* srcPad;
 
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
     g_return_if_fail (GST_IS_ELEMENT (player->before_rgvolume));
-    GstPad* srcPad = gst_element_get_static_pad (player->before_rgvolume, "src");
+    srcPad = gst_element_get_static_pad (player->before_rgvolume, "src");
 
     if (gst_pad_is_active (srcPad) && !gst_pad_is_blocked (srcPad)) {
         gst_pad_set_blocked_async (srcPad, TRUE, &pad_block_cb, player);
@@ -199,7 +204,7 @@ bp_replaygain_set_enabled (BansheePlayer *player, gboolean enabled)
 {
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     player->replaygain_enabled = enabled;
-    bp_debug ("%s ReplayGain", enabled ? "Enabled" : "Disabled");
+    bp_debug2 ("%s ReplayGain", enabled ? "Enabled" : "Disabled");
     _bp_replaygain_pipeline_rebuild (player);
 }
 
diff --git a/libbanshee/banshee-player-video.c b/libbanshee/banshee-player-video.c
index cb36fd6..e757a99 100644
--- a/libbanshee/banshee-player-video.c
+++ b/libbanshee/banshee-player-video.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -32,7 +34,7 @@
 // Private Functions
 // ---------------------------------------------------------------------------
 
-#ifdef GDK_WINDOWING_X11
+#if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WIN32)
 
 static gboolean
 bp_video_find_xoverlay (BansheePlayer *player)
@@ -64,10 +66,12 @@ bp_video_find_xoverlay (BansheePlayer *player)
         gst_object_unref (previous_xoverlay);
     }
         
+#if !defined(GDK_WINDOWING_WIN32) // We can't rely on aspect ratio from dshowvideosink
     if (player->xoverlay != NULL && g_object_class_find_property (
         G_OBJECT_GET_CLASS (player->xoverlay), "force-aspect-ratio")) {
         g_object_set (G_OBJECT (player->xoverlay), "force-aspect-ratio", TRUE, NULL);
     }
+#endif
     
     if (player->xoverlay != NULL && g_object_class_find_property (
         G_OBJECT_GET_CLASS (player->xoverlay), "handle-events")) {
@@ -79,14 +83,14 @@ bp_video_find_xoverlay (BansheePlayer *player)
     return player->xoverlay != NULL;
 }
 
-#endif /* GDK_WINDOWING_X11 */
+#endif /* GDK_WINDOWING_X11 || GDK_WINDOWING_WIN32 */
 
 static void
 bp_video_sink_element_added (GstBin *videosink, GstElement *element, BansheePlayer *player)
 {
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
 
-    #ifdef GDK_WINDOWING_X11
+    #if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WIN32)
     g_mutex_lock (player->mutex);
     bp_video_find_xoverlay (player);
     g_mutex_unlock (player->mutex);    
@@ -100,7 +104,7 @@ bp_video_bus_element_sync_message (GstBus *bus, GstMessage *message, BansheePlay
     
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
 
-    #ifdef GDK_WINDOWING_X11
+    #if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WIN32)
 
     if (message->structure == NULL || !gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
         return;
@@ -121,6 +125,75 @@ bp_video_bus_element_sync_message (GstBus *bus, GstMessage *message, BansheePlay
 // Internal Functions
 // ---------------------------------------------------------------------------
 
+static void
+cb_caps_set (GObject *obj, GParamSpec *pspec, BansheePlayer *p)
+{
+    GstStructure * s = NULL;
+    GstCaps * caps = gst_pad_get_negotiated_caps (GST_PAD (obj));
+
+    if (G_UNLIKELY (!caps)) {
+        return;
+    }
+
+    /* Get video decoder caps */
+    s = gst_caps_get_structure (caps, 0);
+    if (s) {
+        const GValue *par;
+
+        /* We need at least width/height and framerate */
+        if (!(gst_structure_get_fraction (s, "framerate", &p->fps_n, &p->fps_d) &&
+            gst_structure_get_int (s, "width", &p->width) && gst_structure_get_int (s, "height", &p->height))) {
+            return;
+        }
+
+        /* Get the PAR if available */
+        par = gst_structure_get_value (s, "pixel-aspect-ratio");
+        if (par) {
+            p->par_n = gst_value_get_fraction_numerator (par);
+            p->par_d = gst_value_get_fraction_denominator (par);
+        }
+        else { /* Square pixels */
+            p->par_n = 1;
+            p->par_d = 1;
+        }
+
+        /* Notify PlayerEngine if a callback was set */
+        if (p->video_geometry_notify_cb != NULL) {
+            p->video_geometry_notify_cb (p, p->width, p->height, p->fps_n, p->fps_d, p->par_n, p->par_d);
+        }
+    }
+
+    gst_caps_unref (caps);
+}
+
+void
+_bp_parse_stream_info (BansheePlayer *player)
+{
+    gint audios_streams, video_streams, text_streams;
+    GstPad *vpad = NULL;
+
+    g_object_get (G_OBJECT (player->playbin), "n-audio", &audios_streams,
+        "n-video", &video_streams, "n-text", &text_streams, NULL);
+
+    if (video_streams) {
+        gint i;
+        /* Try to obtain a video pad */
+        for (i = 0; i < video_streams && vpad == NULL; i++) {
+            g_signal_emit_by_name (player->playbin, "get-video-pad", i, &vpad);
+        }
+    }
+
+    if (G_LIKELY (vpad)) {
+        GstCaps *caps = gst_pad_get_negotiated_caps (vpad);
+        if (G_LIKELY (caps)) {
+            cb_caps_set (G_OBJECT (vpad), NULL, player);
+            gst_caps_unref (caps);
+        }
+        g_signal_connect (vpad, "notify::caps", G_CALLBACK (cb_caps_set), player);
+        gst_object_unref (vpad);
+    }
+}
+
 void
 _bp_video_pipeline_setup (BansheePlayer *player, GstBus *bus)
 {
@@ -128,7 +201,7 @@ _bp_video_pipeline_setup (BansheePlayer *player, GstBus *bus)
     
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
-     if (player->video_pipeline_setup_cb != NULL) {
+    if (player->video_pipeline_setup_cb != NULL) {
         videosink = player->video_pipeline_setup_cb (player, bus);
         if (videosink != NULL && GST_IS_ELEMENT (videosink)) {
             g_object_set (G_OBJECT (player->playbin), "video-sink", videosink, NULL);
@@ -137,13 +210,13 @@ _bp_video_pipeline_setup (BansheePlayer *player, GstBus *bus)
         }
     }
     
-    #ifdef GDK_WINDOWING_X11
+    #if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WIN32)
 
     player->video_display_context_type = BP_VIDEO_DISPLAY_CONTEXT_GDK_WINDOW;
     
     videosink = gst_element_factory_make ("gconfvideosink", "videosink");
     if (videosink == NULL) {
-        videosink = gst_element_factory_make ("ximagesink", "videosink");
+        videosink = gst_element_factory_make ("autovideosink", "videosink");
         if (videosink == NULL) {
             player->video_display_context_type = BP_VIDEO_DISPLAY_CONTEXT_UNSUPPORTED;
             videosink = gst_element_factory_make ("fakesink", "videosink");
@@ -186,11 +259,17 @@ bp_set_video_pipeline_setup_callback (BansheePlayer *player, BansheePlayerVideoP
     SET_CALLBACK (video_pipeline_setup_cb);
 }
 
+P_INVOKE void
+bp_set_video_geometry_notify_callback (BansheePlayer *player, BansheePlayerVideoGeometryNotifyCallback cb)
+{
+    SET_CALLBACK (video_geometry_notify_cb);
+}
+
 // ---------------------------------------------------------------------------
 // Public Functions
 // ---------------------------------------------------------------------------
 
-#ifdef GDK_WINDOWING_X11
+#if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WIN32)
 
 P_INVOKE BpVideoDisplayContextType
 bp_video_get_display_context_type (BansheePlayer *player)
@@ -263,10 +342,14 @@ bp_video_window_realize (BansheePlayer *player, GdkWindow *window)
 //    }
 //#endif
 
+#if defined(GDK_WINDOWING_X11)
     player->video_window_xid = GDK_WINDOW_XID (window);
+#elif defined (GDK_WINDOWING_WIN32)
+    player->video_window_xid = GDK_WINDOW_HWND (window);
+#endif
 }
 
-#else /* GDK_WINDOWING_X11 */
+#else /* GDK_WINDOWING_X11 || GDK_WINDOWING_WIN32 */
 
 P_INVOKE BpVideoDisplayContextType
 bp_video_get_display_context_type (BansheePlayer *player)
@@ -290,4 +373,4 @@ bp_video_window_expose (BansheePlayer *player, GdkWindow *window, gboolean direc
 {
 }
 
-#endif /* GDK_WINDOWING_X11 */
+#endif /* GDK_WINDOWING_X11 || GDK_WINDOWING_WIN32 */
diff --git a/libbanshee/banshee-player-video.h b/libbanshee/banshee-player-video.h
index 40e0d77..1c143ef 100644
--- a/libbanshee/banshee-player-video.h
+++ b/libbanshee/banshee-player-video.h
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -31,6 +33,7 @@
 
 #include "banshee-player-private.h"
 
-void  _bp_video_pipeline_setup  (BansheePlayer *player, GstBus *bus);
+void _bp_video_pipeline_setup  (BansheePlayer *player, GstBus *bus);
+void _bp_parse_stream_info (BansheePlayer *player);
 
 #endif /* _BANSHEE_PLAYER_VIDEO_H */
diff --git a/libbanshee/banshee-player.c b/libbanshee/banshee-player.c
index cc22981..4b3ade5 100644
--- a/libbanshee/banshee-player.c
+++ b/libbanshee/banshee-player.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -39,57 +41,15 @@
 // Private Functions
 // ---------------------------------------------------------------------------
 
-static gboolean
-bp_iterate_timeout_handler (BansheePlayer *player)
-{
-    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
-    
-    if(player->iterate_cb != NULL) {
-        player->iterate_cb (player);
-    }
-    
-    return TRUE;
-}
-
-static void
-bp_iterate_timeout_start (BansheePlayer *player)
-{
-    g_return_if_fail (IS_BANSHEE_PLAYER(player));
-
-    if (player->iterate_timeout_id == 0) {
-        player->iterate_timeout_id = g_timeout_add (200, 
-            (GSourceFunc)bp_iterate_timeout_handler, player);
-    }
-}
-
-static void
-bp_iterate_timeout_stop (BansheePlayer *player)
-{
-    g_return_if_fail (IS_BANSHEE_PLAYER (player));
-    
-    if (player->iterate_timeout_id != 0) {
-        g_source_remove (player->iterate_timeout_id);
-        player->iterate_timeout_id = 0;
-    }
-}
-
 static void
 bp_pipeline_set_state (BansheePlayer *player, GstState state)
 {
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
-    if (state == GST_STATE_NULL || state == GST_STATE_PAUSED) {
-        bp_iterate_timeout_stop (player);
-    }
-    
     if (GST_IS_ELEMENT (player->playbin)) {
         player->target_state = state;
         gst_element_set_state (player->playbin, state);
     }
-    
-    if (state == GST_STATE_PLAYING) {
-        bp_iterate_timeout_start (player);
-    }
 }
 
 // ---------------------------------------------------------------------------
@@ -183,7 +143,7 @@ bp_stop (BansheePlayer *player, gboolean nullstate)
         state = GST_STATE_NULL;
     }
     
-    bp_debug ("bp_stop: setting state to %s",
+    bp_debug2 ("bp_stop: setting state to %s",
         state == GST_STATE_NULL ? "GST_STATE_NULL" : "GST_STATE_PAUSED");
     
     player->in_gapless_transition = FALSE;
@@ -316,9 +276,9 @@ bp_set_volume (BansheePlayer *player, gdouble volume)
 P_INVOKE gdouble
 bp_get_volume (BansheePlayer *player)
 {
+	gdouble volume;
     g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0.0);
     g_return_val_if_fail (GST_IS_ELEMENT (player->playbin), 0.0);
-    gdouble volume;
 #if BANSHEE_CHECK_GST_VERSION(0,10,25)
     if (gst_element_implements_interface (player->playbin, GST_TYPE_STREAM_VOLUME))
       volume = gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->playbin), GST_STREAM_VOLUME_FORMAT_CUBIC);
@@ -373,12 +333,6 @@ bp_set_state_changed_callback (BansheePlayer *player, BansheePlayerStateChangedC
 }
 
 P_INVOKE void
-bp_set_iterate_callback (BansheePlayer *player, BansheePlayerIterateCallback cb)
-{
-    SET_CALLBACK (iterate_cb);
-}
-
-P_INVOKE void
 bp_set_buffering_callback (BansheePlayer *player, BansheePlayerBufferingCallback cb)
 {
     SET_CALLBACK(buffering_cb);
diff --git a/libbanshee/banshee-ripper.c b/libbanshee/banshee-ripper.c
index dbc7cf8..e0e8c85 100644
--- a/libbanshee/banshee-ripper.c
+++ b/libbanshee/banshee-ripper.c
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Aaron Bockover <abockover novell com>
+//   Julien Moutte <julien fluendo com>
 //
 // Copyright (C) 2005-2008 Novell, Inc.
+// Copyright (C) 2010 Fluendo S.A.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -99,7 +101,7 @@ br_iterate_timeout (BansheeRipper *ripper)
     }
     
     if (ripper->progress_cb != NULL) {
-        ripper->progress_cb (ripper, position / GST_MSECOND, NULL);
+        ripper->progress_cb (ripper, (guint) (position / GST_MSECOND), NULL);
     }
 
     return TRUE;
@@ -130,7 +132,7 @@ br_stop_iterate_timeout (BansheeRipper *ripper)
     ripper->iterate_timeout_id = 0;
 }
 
-static const gchar const *
+static const gchar *
 br_encoder_probe_mime_type (GstBin *bin)
 {
     GstIterator *elem_iter = gst_bin_iterate_recurse (bin);
diff --git a/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs b/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
index 8d2b979..499a913 100644
--- a/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
+++ b/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
@@ -52,17 +52,26 @@ namespace Banshee.GStreamer
         Playing = 4
     }
 
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerEosCallback (IntPtr player);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerErrorCallback (IntPtr player, uint domain, int code, IntPtr error, IntPtr debug);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerStateChangedCallback (IntPtr player, GstState old_state, GstState new_state, GstState pending_state);
-    internal delegate void BansheePlayerIterateCallback (IntPtr player);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerBufferingCallback (IntPtr player, int buffering_progress);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerVisDataCallback (IntPtr player, int channels, int samples, IntPtr data, int bands, IntPtr spectrum);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerNextTrackStartingCallback (IntPtr player);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerAboutToFinishCallback (IntPtr player);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate IntPtr VideoPipelineSetupHandler (IntPtr player, IntPtr bus);
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void BansheePlayerVolumeChangedCallback (IntPtr player, double newVolume);
 
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
     internal delegate void GstTaggerTagFoundCallback (IntPtr player, string tagName, ref GLib.Value value);
 
     public class PlayerEngine : Banshee.MediaEngine.PlayerEngine,
@@ -81,7 +90,6 @@ namespace Banshee.GStreamer
         private BansheePlayerEosCallback eos_callback;
         private BansheePlayerErrorCallback error_callback;
         private BansheePlayerStateChangedCallback state_changed_callback;
-        private BansheePlayerIterateCallback iterate_callback;
         private BansheePlayerBufferingCallback buffering_callback;
         private BansheePlayerVisDataCallback vis_data_callback;
         private VideoPipelineSetupHandler video_pipeline_setup_callback;
@@ -95,6 +103,7 @@ namespace Banshee.GStreamer
 
         private bool buffering_finished;
         private bool xid_is_set = false;
+        private uint iterate_timeout_id = 0;
 
         private bool gapless_enabled;
         private EventWaitHandle next_track_set;
@@ -145,7 +154,6 @@ namespace Banshee.GStreamer
             eos_callback = new BansheePlayerEosCallback (OnEos);
             error_callback = new BansheePlayerErrorCallback (OnError);
             state_changed_callback = new BansheePlayerStateChangedCallback (OnStateChange);
-            iterate_callback = new BansheePlayerIterateCallback (OnIterate);
             buffering_callback = new BansheePlayerBufferingCallback (OnBuffering);
             vis_data_callback = new BansheePlayerVisDataCallback (OnVisualizationData);
             video_pipeline_setup_callback = new VideoPipelineSetupHandler (OnVideoPipelineSetup);
@@ -154,9 +162,6 @@ namespace Banshee.GStreamer
             about_to_finish_callback = new BansheePlayerAboutToFinishCallback (OnAboutToFinish);
             volume_changed_callback = new BansheePlayerVolumeChangedCallback (OnVolumeChanged);
             bp_set_eos_callback (handle, eos_callback);
-#if !WIN32
-            bp_set_iterate_callback (handle, iterate_callback);
-#endif
             bp_set_error_callback (handle, error_callback);
             bp_set_state_changed_callback (handle, state_changed_callback);
             bp_set_buffering_callback (handle, buffering_callback);
@@ -301,6 +306,30 @@ namespace Banshee.GStreamer
             }
         }
 
+        private bool OnIterate ()
+        {
+            // Actual iteration.
+            OnEventChanged (PlayerEvent.Iterate);
+            // Run forever until we are stopped
+            return true;
+        }
+
+        private void StartIterating ()
+        {
+            if (iterate_timeout_id > 0) {
+                GLib.Source.Remove (iterate_timeout_id);
+            }
+
+            iterate_timeout_id = GLib.Timeout.Add (200, OnIterate);
+        }
+
+        private void StopIterating ()
+        {
+            if (iterate_timeout_id > 0) {
+                GLib.Source.Remove (iterate_timeout_id);
+            }
+        }
+
         private void OnNextTrackStarting (IntPtr player)
         {
             if (GaplessEnabled) {
@@ -336,13 +365,10 @@ namespace Banshee.GStreamer
             }
         }
 
-        private void OnIterate (IntPtr player)
-        {
-            OnEventChanged (PlayerEvent.Iterate);
-        }
-
         private void OnStateChange (IntPtr player, GstState old_state, GstState new_state, GstState pending_state)
         {
+            // Start by clearing any timeout we might have
+            StopIterating ();
             if (CurrentState != PlayerState.Loaded && old_state == GstState.Ready && new_state == GstState.Paused && pending_state == GstState.Playing) {
                 if (ready_timeout != 0) {
                     Application.IdleTimeoutRemove (ready_timeout);
@@ -355,6 +381,8 @@ namespace Banshee.GStreamer
                     OnEventChanged (PlayerEvent.StartOfStream);
                 }
                 OnStateChanged (PlayerState.Playing);
+                // Start iterating only when going to playing
+                StartIterating ();
                 return;
             } else if (CurrentState == PlayerState.Playing && old_state == GstState.Playing && new_state == GstState.Paused) {
                 OnStateChanged (PlayerState.Paused);
@@ -769,10 +797,6 @@ namespace Banshee.GStreamer
             BansheePlayerStateChangedCallback cb);
 
         [DllImport ("libbanshee.dll")]
-        private static extern void bp_set_iterate_callback (HandleRef player,
-            BansheePlayerIterateCallback cb);
-
-        [DllImport ("libbanshee.dll")]
         private static extern void bp_set_buffering_callback (HandleRef player,
             BansheePlayerBufferingCallback cb);
 
diff --git a/src/Backends/Banshee.GStreamer/Banshee.GStreamer/Service.cs b/src/Backends/Banshee.GStreamer/Banshee.GStreamer/Service.cs
index 11f79c3..acacbbe 100644
--- a/src/Backends/Banshee.GStreamer/Banshee.GStreamer/Service.cs
+++ b/src/Backends/Banshee.GStreamer/Banshee.GStreamer/Service.cs
@@ -40,6 +40,7 @@ namespace Banshee.GStreamer
 {
     public class Service : IExtensionService
     {
+        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         private delegate void BansheeLogHandler (LogEntryType type, IntPtr component, IntPtr message);
 
         private BansheeLogHandler native_log_handler = null;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]