summaryrefslogtreecommitdiff
path: root/libbanshee
diff options
context:
space:
mode:
authorBertrand Lorentz <bertrand.lorentz@gmail.com>2011-09-25 12:48:18 +0200
committerBertrand Lorentz <bertrand.lorentz@gmail.com>2011-09-25 22:34:57 +0200
commit598335571a324b4a8a334d154ed30b1a53dfc184 (patch)
tree03ea75787c6273946794c5b8328b55be5dc92a12 /libbanshee
parent92e40e0ccb30bfb0b9373f7b32e09e65c1f8b284 (diff)
Add initial support for DVD playing
Add the necessary bits to support DVD playing in both libbanshee and GStreamerSharp, including menu navigation. Rework the AudioCD extension into an OpticalDisc extension that supports both audio CDs and video DVDs. Adapt the NowPlaying extension to forward mouse and keyboard events to the player engine when appropriate, to implement menu navigation for DVDs. This is the result of a collaboration between Alex Launi and Olivier Dufour, with a few changes and cleanups by me.
Diffstat (limited to 'libbanshee')
-rw-r--r--libbanshee/Makefile.am2
-rw-r--r--libbanshee/banshee-player-dvd.c310
-rw-r--r--libbanshee/banshee-player-dvd.h39
-rw-r--r--libbanshee/banshee-player-pipeline.c4
-rw-r--r--libbanshee/banshee-player-private.h6
-rw-r--r--libbanshee/banshee-player-vis.c4
-rw-r--r--libbanshee/banshee-player.c7
-rw-r--r--libbanshee/libbanshee.cproj3
8 files changed, 373 insertions, 2 deletions
diff --git a/libbanshee/Makefile.am b/libbanshee/Makefile.am
index 415b329fb..6ed369a94 100644
--- a/libbanshee/Makefile.am
+++ b/libbanshee/Makefile.am
@@ -19,6 +19,7 @@ libbanshee_la_SOURCES = \
banshee-gst.c \
banshee-player.c \
banshee-player-cdda.c \
+ banshee-player-dvd.c \
banshee-player-equalizer.c \
banshee-player-missing-elements.c \
banshee-player-pipeline.c \
@@ -39,6 +40,7 @@ endif
noinst_HEADERS = \
banshee-gst.h \
banshee-player-cdda.h \
+ banshee-player-dvd.h \
banshee-player-equalizer.h \
banshee-player-missing-elements.h \
banshee-player-pipeline.h \
diff --git a/libbanshee/banshee-player-dvd.c b/libbanshee/banshee-player-dvd.c
new file mode 100644
index 000000000..844b386e2
--- /dev/null
+++ b/libbanshee/banshee-player-dvd.c
@@ -0,0 +1,310 @@
+//
+// banshee-player-dvd.c
+//
+// Author:
+// Alex Launi <alex.launi@canonical.com>
+//
+// Copyright (C) 2010 Alex Launi
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include "banshee-player-dvd.h"
+
+// ---------------------------------------------------------------------------
+// Private Functions
+// ---------------------------------------------------------------------------
+
+static void
+bp_dvd_on_notify_source (GstElement *playbin, gpointer unknown, BansheePlayer *player)
+{
+ GstElement *dvd_src = NULL;
+
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+
+ if (player->dvd_device == NULL) {
+ return;
+ }
+
+ g_object_get (playbin, "source", &dvd_src, NULL);
+ if (dvd_src == NULL) {
+ return;
+ }
+
+ if (G_LIKELY (g_object_class_find_property (G_OBJECT_GET_CLASS (dvd_src), "device"))) {
+ bp_debug2 ("bp_dvd: setting device property on source (%s)", player->dvd_device);
+ g_object_set (dvd_src, "device", player->dvd_device, NULL);
+ }
+
+ g_object_unref (dvd_src);
+}
+
+// ---------------------------------------------------------------------------
+// Internal Functions
+// ---------------------------------------------------------------------------
+
+void
+_bp_dvd_pipeline_setup (BansheePlayer *player)
+{
+ if (player != NULL && player->playbin != NULL) {
+ g_signal_connect (player->playbin, "notify::source", G_CALLBACK (bp_dvd_on_notify_source), player);
+ }
+}
+
+void
+_bp_dvd_elements_process_message (BansheePlayer *player, GstMessage *message)
+{
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+ g_return_if_fail (message != NULL);
+
+ player->is_menu = FALSE;
+ // Get available command to know if player is in menu
+ GstQuery *query = gst_navigation_query_new_commands();
+
+ guint n_cmds, i;
+ //execute query over playbin or navigation ?
+ if (gst_element_query (player->playbin, query)
+ && gst_navigation_query_parse_commands_length (query, &n_cmds)) {
+ gst_query_unref (query);
+ return;
+ }
+
+ for (i = 0; i < n_cmds; i++) {
+ GstNavigationCommand cmd;
+ if (gst_navigation_query_parse_commands_nth (query, i, &cmd)) {
+ switch (cmd) {
+ case GST_NAVIGATION_COMMAND_ACTIVATE:
+ case GST_NAVIGATION_COMMAND_LEFT:
+ case GST_NAVIGATION_COMMAND_RIGHT:
+ case GST_NAVIGATION_COMMAND_UP:
+ case GST_NAVIGATION_COMMAND_DOWN:
+ player->is_menu = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ gst_query_unref (query);
+}
+
+gboolean
+_bp_dvd_handle_uri (BansheePlayer *player, const gchar *uri)
+{
+ // Processes URIs like dvd://<track-number>#<device-node> and overrides
+ // track transitioning through playbin if playback was already happening
+ // from the device node by seeking directly to the track since the disc
+ // is already spinning; playbin doesn't handle DVD URIs with device nodes
+ // so we have to handle setting the device property through the
+ // notify::source signal on playbin
+
+ const gchar *new_dvd_device;
+
+ if (player == NULL || uri == NULL || !g_str_has_prefix (uri, "dvd://")) {
+ // Something is hosed or the URI isn't actually DVD
+ if (player->dvd_device != NULL) {
+ bp_debug2 ("bp_dvd: finished using device (%s)", player->dvd_device);
+ g_free (player->dvd_device);
+ player->dvd_device = NULL;
+ }
+
+ return FALSE;
+ }
+
+ // 6 is the size of "dvd://"
+ // so we skip this part to only get the device
+ new_dvd_device = uri + 6;
+
+ if (player->dvd_device == NULL) {
+ // If we weren't already playing from a DVD, cache the
+ // device and allow playbin to begin playing it
+ player->dvd_device = g_strdup (new_dvd_device);
+ bp_debug2 ("bp_dvd: storing device node (%s)", player->dvd_device);
+ return FALSE;
+ }
+
+ if (strcmp (new_dvd_device, player->dvd_device) == 0) {
+ bp_debug2 ("bp_dvd: Already playing device (%s)", player->dvd_device);
+ return TRUE;
+ }
+
+ // We were already playing some DVD, but switched to a different device node,
+ // so unset and re-cache the new device node and allow playbin to do its thing
+ bp_debug3 ("bp_dvd: switching devices for DVD playback (from %s, to %s)", player->dvd_device, new_dvd_device);
+ g_free (player->dvd_device);
+ player->dvd_device = g_strdup (new_dvd_device);
+
+ return FALSE;
+}
+
+void _bp_dvd_find_navigation (BansheePlayer *player)
+{
+ GstElement *video_sink = NULL;
+ GstElement *navigation = NULL;
+ GstNavigation *previous_navigation;
+
+ previous_navigation = player->navigation;
+ g_object_get (player->playbin, "video-sink", &video_sink, NULL);
+
+ if (video_sink == NULL) {
+ player->navigation = NULL;
+ if (previous_navigation != NULL) {
+ gst_object_unref (previous_navigation);
+ }
+ }
+
+ navigation = GST_IS_BIN (video_sink)
+ ? gst_bin_get_by_interface (GST_BIN (video_sink), GST_TYPE_NAVIGATION)
+ : video_sink;
+
+ player->navigation = GST_IS_NAVIGATION (navigation) ? GST_NAVIGATION (navigation) : NULL;
+
+ if (previous_navigation != NULL) {
+ gst_object_unref (previous_navigation);
+ }
+
+ gst_object_unref (video_sink);
+}
+
+P_INVOKE gboolean
+bp_dvd_is_menu (BansheePlayer *player)
+{
+ return player->is_menu;
+}
+
+P_INVOKE void
+bp_dvd_mouse_move_notify (BansheePlayer *player, double x, double y)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_mouse_event (player->navigation, "mouse-move", 0, x, y);
+ }
+}
+
+P_INVOKE void
+bp_dvd_mouse_button_pressed_notify (BansheePlayer *player, int button, double x, double y)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_mouse_event (player->navigation, "mouse-button-press", button, x, y);
+ }
+}
+
+P_INVOKE void
+bp_dvd_mouse_button_released_notify (BansheePlayer *player, int button, double x, double y)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_mouse_event (player->navigation, "mouse-button-release", button, x, y);
+ }
+}
+
+P_INVOKE void
+bp_dvd_left_notify (BansheePlayer *player)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_command (player->navigation, GST_NAVIGATION_COMMAND_LEFT);
+ }
+}
+
+P_INVOKE void
+bp_dvd_right_notify (BansheePlayer *player)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_command (player->navigation, GST_NAVIGATION_COMMAND_RIGHT);
+ }
+}
+
+P_INVOKE void
+bp_dvd_up_notify (BansheePlayer *player)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_command (player->navigation, GST_NAVIGATION_COMMAND_UP);
+ }
+}
+
+P_INVOKE void
+bp_dvd_down_notify (BansheePlayer *player)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_command (player->navigation, GST_NAVIGATION_COMMAND_DOWN);
+ }
+}
+
+P_INVOKE void
+bp_dvd_activate_notify (BansheePlayer *player)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_command (player->navigation, GST_NAVIGATION_COMMAND_ACTIVATE);
+ }
+}
+
+P_INVOKE void
+bp_dvd_go_to_menu (BansheePlayer *player)
+{
+ if (!player->navigation) {
+ _bp_dvd_find_navigation (player);
+ }
+ if (player->navigation) {
+ gst_navigation_send_command (player->navigation, GST_NAVIGATION_COMMAND_DVD_MENU);
+ }
+}
+
+P_INVOKE void
+bp_dvd_go_to_next_chapter (BansheePlayer *player)
+{
+ gint64 index;
+ GstFormat format = gst_format_get_by_nick ("chapter");
+ gst_element_query_position (player->playbin, &format, &index);
+ gst_element_seek (player->playbin, 1.0, format, GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, index + 1, GST_SEEK_TYPE_NONE, 0);
+}
+
+P_INVOKE void
+bp_dvd_go_to_previous_chapter (BansheePlayer *player)
+{
+ gint64 index;
+ GstFormat format = gst_format_get_by_nick ("chapter");
+ gst_element_query_position (player->playbin, &format, &index);
+ gst_element_seek (player->playbin, 1.0, format, GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, index - 1, GST_SEEK_TYPE_NONE, 0);
+}
diff --git a/libbanshee/banshee-player-dvd.h b/libbanshee/banshee-player-dvd.h
new file mode 100644
index 000000000..d7f0ec53f
--- /dev/null
+++ b/libbanshee/banshee-player-dvd.h
@@ -0,0 +1,39 @@
+//
+// banshee-player-dvd.h
+//
+// Author:
+// Alex Launi <alex.launi@canonical.com>
+//
+// Copyright (C) 2010 Alex Launi
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#ifndef _BANSHEE_PLAYER_DVD_H
+#define _BANSHEE_PLAYER_DVD_H
+
+#include "banshee-player-private.h"
+
+void _bp_dvd_pipeline_setup (BansheePlayer *player);
+gboolean _bp_dvd_handle_uri (BansheePlayer *player, const gchar *uri);
+void _bp_dvd_find_navigation (BansheePlayer *player);
+void _bp_dvd_elements_process_message (BansheePlayer *player, GstMessage *message);
+
+#endif /* _BANSHEE_PLAYER_DVD_H */
diff --git a/libbanshee/banshee-player-pipeline.c b/libbanshee/banshee-player-pipeline.c
index e25f55f82..dcfb4edf6 100644
--- a/libbanshee/banshee-player-pipeline.c
+++ b/libbanshee/banshee-player-pipeline.c
@@ -30,6 +30,7 @@
#include "banshee-player-pipeline.h"
#include "banshee-player-cdda.h"
+#include "banshee-player-dvd.h"
#include "banshee-player-video.h"
#include "banshee-player-equalizer.h"
#include "banshee-player-missing-elements.h"
@@ -213,6 +214,7 @@ bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
bp_next_track_starting (player);
}
_bp_missing_elements_process_message (player, message);
+ _bp_dvd_elements_process_message (player, message);
break;
}
@@ -413,7 +415,9 @@ _bp_pipeline_construct (BansheePlayer *player)
// Now allow specialized pipeline setups
_bp_cdda_pipeline_setup (player);
+ _bp_dvd_pipeline_setup (player);
_bp_video_pipeline_setup (player, bus);
+ _bp_dvd_find_navigation (player);
return TRUE;
}
diff --git a/libbanshee/banshee-player-private.h b/libbanshee/banshee-player-private.h
index 24eb5eb82..9fed3568c 100644
--- a/libbanshee/banshee-player-private.h
+++ b/libbanshee/banshee-player-private.h
@@ -42,6 +42,7 @@
#include <gst/fft/gstfftf32.h>
#include <gst/pbutils/pbutils.h>
#include <gst/tag/tag.h>
+#include <gst/interfaces/navigation.h>
#if defined(GDK_WINDOWING_X11)
# include <gdk/gdkx.h>
@@ -147,6 +148,7 @@ struct BansheePlayer {
GstState target_state;
gboolean buffering;
gchar *cdda_device;
+ gchar *dvd_device;
gboolean in_gapless_transition;
gboolean audiosink_has_volume;
@@ -195,6 +197,10 @@ struct BansheePlayer {
// http://replaygain.hydrogenaudio.org/player_scale.html
gdouble rg_gain_history[10];
gint history_size;
+
+ //dvd navigation
+ GstNavigation *navigation;
+ gboolean is_menu;
};
#endif /* _BANSHEE_PLAYER_PRIVATE_H */
diff --git a/libbanshee/banshee-player-vis.c b/libbanshee/banshee-player-vis.c
index 5c7d5fe74..18c71c7bd 100644
--- a/libbanshee/banshee-player-vis.c
+++ b/libbanshee/banshee-player-vis.c
@@ -168,6 +168,7 @@ _bp_vis_pipeline_event_probe (GstPad *pad, GstEvent *event, gpointer data)
case GST_EVENT_FLUSH_STOP:
case GST_EVENT_SEEK:
case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
player->vis_thawing = TRUE;
default: break;
@@ -178,9 +179,10 @@ _bp_vis_pipeline_event_probe (GstPad *pad, GstEvent *event, gpointer data)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
+ case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
_bp_vis_pipeline_set_blocked (player, FALSE);
break;
-
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
case GST_EVENT_NEWSEGMENT:
_bp_vis_pipeline_set_blocked (player, TRUE);
break;
diff --git a/libbanshee/banshee-player.c b/libbanshee/banshee-player.c
index 0ce8ed1d2..c655a72fd 100644
--- a/libbanshee/banshee-player.c
+++ b/libbanshee/banshee-player.c
@@ -31,6 +31,7 @@
#include "banshee-player-private.h"
#include "banshee-player-pipeline.h"
#include "banshee-player-cdda.h"
+#include "banshee-player-dvd.h"
#include "banshee-player-missing-elements.h"
#include "banshee-player-replaygain.h"
@@ -110,6 +111,10 @@ bp_destroy (BansheePlayer *player)
if (player->cdda_device != NULL) {
g_free (player->cdda_device);
}
+
+ if (player->dvd_device != NULL) {
+ g_free (player->dvd_device);
+ }
_bp_pipeline_destroy (player);
_bp_missing_elements_destroy (player);
@@ -155,6 +160,8 @@ bp_open (BansheePlayer *player, const gchar *uri, gboolean maybe_video)
// in case it is able to perform a fast seek to a track
if (_bp_cdda_handle_uri (player, uri)) {
return TRUE;
+ } else if (_bp_dvd_handle_uri (player, uri)) {
+ return TRUE;
} else if (player->playbin == NULL) {
return FALSE;
}
diff --git a/libbanshee/libbanshee.cproj b/libbanshee/libbanshee.cproj
index a98b09019..e59480786 100644
--- a/libbanshee/libbanshee.cproj
+++ b/libbanshee/libbanshee.cproj
@@ -11,7 +11,6 @@
<Language>C</Language>
<Target>Bin</Target>
<SchemaVersion>2.0</SchemaVersion>
- <ReleaseVersion>1.3</ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -43,6 +42,7 @@
<Compile Include="banshee-player-replaygain.c" />
<Compile Include="banshee-player-vis.c" />
<Compile Include="banshee-bpmdetector.c" />
+ <Compile Include="banshee-player-dvd.c" />
</ItemGroup>
<ItemGroup>
<None Include="banshee-player-private.h" />
@@ -55,6 +55,7 @@
<None Include="banshee-player-equalizer.h" />
<None Include="banshee-player-replaygain.h" />
<None Include="banshee-player-vis.h" />
+ <None Include="banshee-player-dvd.h" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>