diff options
author | Olivier Dufour <olivier.duff@gmail.com> | 2010-11-10 23:23:48 +0100 |
---|---|---|
committer | Gabriel Burt <gabriel.burt@gmail.com> | 2010-12-02 16:54:43 -0600 |
commit | 9e86951d4234d3abdd25d301837f86475795687e (patch) | |
tree | 9465fe80cb0754b1347f8faeb945f6895e6301f3 /libbanshee | |
parent | fd19891d6f233b321f3b1db22c433b00ef040c64 (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.h | 1 | ||||
-rw-r--r-- | libbanshee/banshee-player-video.c | 37 | ||||
-rw-r--r-- | libbanshee/banshee-player.c | 114 | ||||
-rw-r--r-- | libbanshee/libbanshee.sln | 47 |
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
|