[banshee] [libbanshee] Windows fixes (bgo#614046)
- From: Alexander Kojevnikov <alexk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee] [libbanshee] Windows fixes (bgo#614046)
- Date: Sun, 4 Apr 2010 06:21:41 +0000 (UTC)
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]