summaryrefslogtreecommitdiff
path: root/libbanshee
diff options
context:
space:
mode:
authorOlivier Dufour <olivier.duff@gmail.com>2010-11-10 23:23:48 +0100
committerGabriel Burt <gabriel.burt@gmail.com>2010-12-02 16:54:43 -0600
commit9e86951d4234d3abdd25d301837f86475795687e (patch)
tree9465fe80cb0754b1347f8faeb945f6895e6301f3 /libbanshee
parentfd19891d6f233b321f3b1db22c433b00ef040c64 (diff)
Support embedded and external subtitles (bgo#534581)
Signed-off-by: Gabriel Burt <gabriel.burt@gmail.com>
Diffstat (limited to 'libbanshee')
-rw-r--r--libbanshee/banshee-player-private.h1
-rw-r--r--libbanshee/banshee-player-video.c37
-rw-r--r--libbanshee/banshee-player.c114
-rw-r--r--libbanshee/libbanshee.sln47
4 files changed, 178 insertions, 21 deletions
diff --git a/libbanshee/banshee-player-private.h b/libbanshee/banshee-player-private.h
index f3e28a77f..4d9bf44b4 100644
--- a/libbanshee/banshee-player-private.h
+++ b/libbanshee/banshee-player-private.h
@@ -41,6 +41,7 @@
#include <gdk/gdk.h>
#include <gst/fft/gstfftf32.h>
#include <gst/pbutils/pbutils.h>
+#include <gst/tag/tag.h>
#if defined(GDK_WINDOWING_X11)
# include <gdk/gdkx.h>
diff --git a/libbanshee/banshee-player-video.c b/libbanshee/banshee-player-video.c
index 831940325..b901354df 100644
--- a/libbanshee/banshee-player-video.c
+++ b/libbanshee/banshee-player-video.c
@@ -57,7 +57,7 @@ bp_video_find_xoverlay (BansheePlayer *player)
g_mutex_unlock (player->video_mutex);
return FALSE;
}
-
+
xoverlay = GST_IS_BIN (video_sink)
? gst_bin_get_by_interface (GST_BIN (video_sink), GST_TYPE_X_OVERLAY)
: video_sink;
@@ -89,6 +89,41 @@ bp_video_find_xoverlay (BansheePlayer *player)
#endif /* GDK_WINDOWING_X11 || GDK_WINDOWING_WIN32 */
+P_INVOKE int
+bp_get_subtitle_count (BansheePlayer *player)
+{
+ g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0);
+
+ int n_text;
+ g_object_get (G_OBJECT (player->playbin), "n-text", &n_text, NULL);
+ return n_text;
+}
+
+P_INVOKE void
+bp_set_subtitle (BansheePlayer *player, int index)
+{
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+
+ int n_text = bp_get_subtitle_count (player);
+
+ if (n_text == 0 || index < -1 || index >= n_text)
+ return;
+
+ bp_debug ("[subtitle]: set subtitle to %d.", index);
+
+ gint flags;
+ g_object_get (G_OBJECT (player->playbin), "flags", &flags, NULL);
+
+ if (index == -1) {
+ flags &= ~(1 << 2);//GST_PLAY_FLAG_TEXT
+ g_object_set (G_OBJECT (player->playbin), "flags", flags, NULL);
+ } else {
+ flags |= (1 << 2);//GST_PLAY_FLAG_TEXT
+ g_object_set (G_OBJECT (player->playbin), "flags", flags, NULL);
+ g_object_set (G_OBJECT (player->playbin), "current-text", index, NULL);
+ }
+}
+
static void
bp_video_sink_element_added (GstBin *videosink, GstElement *element, BansheePlayer *player)
{
diff --git a/libbanshee/banshee-player.c b/libbanshee/banshee-player.c
index ef15efd30..03a9d2d05 100644
--- a/libbanshee/banshee-player.c
+++ b/libbanshee/banshee-player.c
@@ -49,6 +49,47 @@ bp_pipeline_set_state (BansheePlayer *player, GstState state)
}
}
+static void
+bp_lookup_for_subtitle (BansheePlayer *player, const gchar *uri)
+{
+ gchar *scheme, *filename, *subfile, *dot, *suburi;
+ int j;
+ // Always enable rendering of subtitles
+ gint flags;
+ g_object_get (G_OBJECT (player->playbin), "flags", &flags, NULL);
+ flags |= (1 << 2);//GST_PLAY_FLAG_TEXT
+ g_object_set (G_OBJECT (player->playbin), "flags", flags, NULL);
+
+ bp_debug ("[subtitle]: lookup for subtitle for video file.");
+ scheme = g_uri_parse_scheme (uri);
+ static gchar *subtitle_extensions[] = { ".srt", ".sub", ".smi", ".txt", ".mpl", ".dks", ".qtx" };
+ if (scheme == NULL || strcmp (scheme, "file") != 0) {
+ g_free (scheme);
+ return;
+ }
+ g_free (scheme);
+
+ dot = g_strrstr (uri, ".");
+ if (dot == NULL)
+ return;
+ filename = g_filename_from_uri (g_strndup (uri, dot - uri), NULL, NULL);
+
+ for (j = 0; j < G_N_ELEMENTS (subtitle_extensions); j++) {
+ subfile = g_strconcat (filename, subtitle_extensions[j], NULL);
+ if (g_file_test (subfile, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+ bp_debug ("[subtitle]: Found srt file: %s", subfile);
+ suburi = g_filename_to_uri (subfile, NULL, NULL);
+ g_object_set (G_OBJECT (player->playbin), "suburi", suburi, NULL);
+ g_free (suburi);
+ g_free (subfile);
+ g_free (filename);
+ return;
+ }
+ g_free (subfile);
+ }
+ g_free (filename);
+}
+
// ---------------------------------------------------------------------------
// Public Functions
// ---------------------------------------------------------------------------
@@ -128,6 +169,9 @@ bp_open (BansheePlayer *player, const gchar *uri)
// Pass the request off to playbin
g_object_set (G_OBJECT (player->playbin), "uri", uri, NULL);
+ // Lookup for subtitle files with same name/folder
+ bp_lookup_for_subtitle (player, uri);
+
player->in_gapless_transition = FALSE;
return TRUE;
@@ -172,6 +216,7 @@ bp_set_next_track (BansheePlayer *player, const gchar *uri)
g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
g_return_val_if_fail (player->playbin != NULL, FALSE);
g_object_set (G_OBJECT (player->playbin), "uri", uri, NULL);
+ bp_lookup_for_subtitle (player, uri);
return TRUE;
}
@@ -373,3 +418,72 @@ bp_set_about_to_finish_callback (BansheePlayer *player, BansheePlayerAboutToFini
{
SET_CALLBACK (about_to_finish_cb);
}
+
+P_INVOKE void
+bp_set_subtitle_uri (BansheePlayer *player, const gchar *uri)
+{
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+ gint64 pos = -1;
+ GstState state;
+ GstFormat format = GST_FORMAT_BYTES;
+ gboolean paused = FALSE;
+
+ // Gstreamer playbin do not support to set suburi during playback
+ // so have to stop/play and seek
+ gst_element_get_state (player->playbin, &state, NULL, 0);
+ paused = (state == GST_STATE_PAUSED);
+ if (state >= GST_STATE_PAUSED) {
+ gst_element_query_position (player->playbin, &format, &pos);
+ gst_element_set_state (player->playbin, GST_STATE_READY);
+ // Force to wait asynch operation
+ gst_element_get_state (player->playbin, &state, NULL, -1);
+ }
+
+ g_object_set (G_OBJECT (player->playbin), "suburi", uri, NULL);
+ gst_element_set_state (player->playbin, paused ? GST_STATE_PAUSED : GST_STATE_PLAYING);
+
+ // Force to wait asynch operation
+ gst_element_get_state (player->playbin, &state, NULL, -1);
+
+ if (pos != -1) {
+ gst_element_seek_simple (player->playbin, format, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, pos);
+ }
+}
+
+P_INVOKE gchar *
+bp_get_subtitle_uri (BansheePlayer *player)
+{
+ gchar *uri;
+ g_return_val_if_fail (IS_BANSHEE_PLAYER (player), "");
+ g_object_get (G_OBJECT (player->playbin), "suburi", &uri, NULL);
+ return uri;
+}
+
+P_INVOKE gchar *
+bp_get_subtitle_description (BansheePlayer *player, int i)
+{
+ gchar *code;
+ gchar *desc = NULL;
+ GstTagList *tags = NULL;
+
+ g_return_val_if_fail (IS_BANSHEE_PLAYER (player), NULL);
+
+ g_signal_emit_by_name (G_OBJECT (player->playbin), "get-text-tags", i, &tags);
+ if (G_LIKELY(tags)) {
+ gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &code);
+ gst_tag_list_free (tags);
+
+ g_return_val_if_fail (code != NULL, NULL);
+
+ // ISO 639-2 undetermined language
+ if (strcmp ((const gchar *)code, "und") == 0) {
+ return NULL;
+ }
+ bp_debug ("[subtitle]: iso 639-2 subtitle code %s", code);
+ desc = (gchar *) gst_tag_get_language_name ((const gchar *)&code);
+ bp_debug ("[subtitle]: subtitle language: %s", desc);
+
+ g_free (code);
+ }
+ return desc;
+}
diff --git a/libbanshee/libbanshee.sln b/libbanshee/libbanshee.sln
index 4b058d40e..3a038179d 100644
--- a/libbanshee/libbanshee.sln
+++ b/libbanshee/libbanshee.sln
@@ -1,20 +1,27 @@
-
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual C++ Express 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbanshee", "libbanshee.vcproj", "{8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Debug|Win32.ActiveCfg = Debug|Win32
- {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Debug|Win32.Build.0 = Debug|Win32
- {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Release|Win32.ActiveCfg = Release|Win32
- {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Release|Win32.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{2857B73E-F847-4B02-9238-064979017E93}") = "libbanshee", "libbanshee.cproj", "{6B781836-AB65-49EF-BECD-CCC193C5D589}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6B781836-AB65-49EF-BECD-CCC193C5D589}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {6B781836-AB65-49EF-BECD-CCC193C5D589}.Debug|Win32.Build.0 = Debug|Any CPU
+ {6B781836-AB65-49EF-BECD-CCC193C5D589}.Release|Win32.ActiveCfg = Debug|Any CPU
+ {6B781836-AB65-49EF-BECD-CCC193C5D589}.Release|Win32.Build.0 = Debug|Any CPU
+ {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Debug|Win32.Build.0 = Debug|Win32
+ {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Release|Win32.ActiveCfg = Release|Win32
+ {8045CB14-6CFB-4CBE-9A09-77FAD23B8F83}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = libbanshee.cproj
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal