From 5c289ec20a7b9f5e1e2a692881c46ec98dad6cbd Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 27 Jul 2014 17:58:35 +0200 Subject: playback/player: Port gst-play from gst-plugins-base to GstPlayer --- playback/player/gst-play/gst-play-kb.c | 143 +++++++++ playback/player/gst-play/gst-play-kb.h | 35 +++ playback/player/gst-play/gst-play.c | 514 +++++++++++++++++++++++++++++++++ 3 files changed, 692 insertions(+) create mode 100644 playback/player/gst-play/gst-play-kb.c create mode 100644 playback/player/gst-play/gst-play-kb.h create mode 100644 playback/player/gst-play/gst-play.c diff --git a/playback/player/gst-play/gst-play-kb.c b/playback/player/gst-play/gst-play-kb.c new file mode 100644 index 0000000..791269d --- /dev/null +++ b/playback/player/gst-play/gst-play-kb.c @@ -0,0 +1,143 @@ +/* GStreamer command line playback testing utility - keyboard handling helpers + * + * Copyright (C) 2013 Tim-Philipp Müller + * Copyright (C) 2013 Centricular Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gst-play-kb.h" + +#include +#include +#include + +#ifdef G_OS_UNIX +#include +#include +#endif + +#include + +/* This is all not thread-safe, but doesn't have to be really */ + +#ifdef G_OS_UNIX + +static struct termios term_settings; +static gboolean term_settings_saved = FALSE; +static GstPlayKbFunc kb_callback; +static gpointer kb_callback_data; +static gulong io_watch_id; + +static gboolean +gst_play_kb_io_cb (GIOChannel * ioc, GIOCondition cond, gpointer user_data) +{ + GIOStatus status; + + if (cond & G_IO_IN) { + gchar buf[16] = { 0, }; + gsize read; + + status = g_io_channel_read_chars (ioc, buf, sizeof (buf) - 1, &read, NULL); + if (status == G_IO_STATUS_ERROR) + return FALSE; + if (status == G_IO_STATUS_NORMAL) { + if (kb_callback) + kb_callback (buf, kb_callback_data); + } + } + + return TRUE; /* call us again */ +} + +gboolean +gst_play_kb_set_key_handler (GstPlayKbFunc kb_func, gpointer user_data) +{ + GIOChannel *ioc; + int flags; + + if (!isatty (STDIN_FILENO)) { + GST_INFO ("stdin is not connected to a terminal"); + return FALSE; + } + + if (io_watch_id > 0) { + g_source_remove (io_watch_id); + io_watch_id = 0; + } + + if (kb_func == NULL && term_settings_saved) { + /* restore terminal settings */ + if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_settings) == 0) + term_settings_saved = FALSE; + else + g_warning ("could not restore terminal attributes"); + + setvbuf (stdin, NULL, _IOLBF, 0); + } + + if (kb_func != NULL) { + struct termios new_settings; + + if (!term_settings_saved) { + if (tcgetattr (STDIN_FILENO, &term_settings) != 0) { + g_warning ("could not save terminal attributes"); + return FALSE; + } + term_settings_saved = TRUE; + + /* Echo off, canonical mode off, extended input processing off */ + new_settings = term_settings; + new_settings.c_lflag &= ~(ECHO | ICANON | IEXTEN); + + if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &new_settings) != 0) { + g_warning ("Could not set terminal state"); + return FALSE; + } + setvbuf (stdin, NULL, _IONBF, 0); + } + } + + ioc = g_io_channel_unix_new (STDIN_FILENO); + + /* make non-blocking */ + flags = g_io_channel_get_flags (ioc); + g_io_channel_set_flags (ioc, flags | G_IO_FLAG_NONBLOCK, NULL); + + io_watch_id = g_io_add_watch_full (ioc, G_PRIORITY_DEFAULT, G_IO_IN, + (GIOFunc) gst_play_kb_io_cb, user_data, NULL); + g_io_channel_unref (ioc); + + kb_callback = kb_func; + kb_callback_data = user_data; + + return TRUE; +} + +#else /* !G_OS_UNIX */ + +gboolean +gst_play_kb_set_key_handler (GstPlayKbFunc key_func, gpointer user_data) +{ + GST_FIXME ("Keyboard handling for this OS needs to be implemented"); + return FALSE; +} + +#endif /* !G_OS_UNIX */ diff --git a/playback/player/gst-play/gst-play-kb.h b/playback/player/gst-play/gst-play-kb.h new file mode 100644 index 0000000..7dab0ed --- /dev/null +++ b/playback/player/gst-play/gst-play-kb.h @@ -0,0 +1,35 @@ +/* GStreamer command line playback testing utility - keyboard handling helpers + * + * Copyright (C) 2013 Tim-Philipp Müller + * Copyright (C) 2013 Centricular Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef __GST_PLAY_KB_INCLUDED__ +#define __GST_PLAY_KB_INCLUDED__ + +#include + +#define GST_PLAY_KB_ARROW_UP "\033[A" +#define GST_PLAY_KB_ARROW_DOWN "\033[B" +#define GST_PLAY_KB_ARROW_RIGHT "\033[C" +#define GST_PLAY_KB_ARROW_LEFT "\033[D" + +typedef void (*GstPlayKbFunc) (const gchar * kb_input, gpointer user_data); + +gboolean gst_play_kb_set_key_handler (GstPlayKbFunc kb_func, gpointer user_data); + +#endif /* __GST_PLAY_KB_INCLUDED__ */ diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c new file mode 100644 index 0000000..b5572d6 --- /dev/null +++ b/playback/player/gst-play/gst-play.c @@ -0,0 +1,514 @@ +/* GStreamer command line playback testing utility + * + * Copyright (C) 2013-2014 Tim-Philipp Müller + * Copyright (C) 2013 Collabora Ltd. + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include + +#include "gst-play-kb.h" +#include "gstplayer.h" + +#define VOLUME_STEPS 20 + +GST_DEBUG_CATEGORY (play_debug); +#define GST_CAT_DEFAULT play_debug + +typedef struct +{ + gchar **uris; + guint num_uris; + gint cur_idx; + + GstPlayer *player; + GstState desired_state; + + GMainLoop *loop; +} GstPlay; + +static gboolean play_next (GstPlay * play); +static gboolean play_prev (GstPlay * play); +static void play_reset (GstPlay * play); +static void play_set_relative_volume (GstPlay * play, gdouble volume_step); + +static void +end_of_stream_cb (GstPlayer * player, GstPlay * play) +{ + g_print ("\n"); + /* and switch to next item in list */ + if (!play_next (play)) { + g_print ("Reached end of play list.\n"); + g_main_loop_quit (play->loop); + } +} + +static void +error_cb (GstPlayer * player, GError * err, GstPlay * play) +{ + g_printerr ("ERROR %s for %s\n", err->message, play->uris[play->cur_idx]); + + /* try next item in list then */ + if (!play_next (play)) { + g_print ("Reached end of play list.\n"); + g_main_loop_quit (play->loop); + } +} + +static gboolean +position_updated_cb (GstPlayer * player, GstClockTime pos, GstPlay * play) +{ + GstClockTime dur = -1; + gchar status[64] = { 0, }; + + g_object_get (play->player, "duration", &dur, NULL); + + if (play->desired_state == GST_STATE_PAUSED) + g_snprintf (status, sizeof (status), "Paused"); + else + memset (status, ' ', sizeof (status) - 1); + + if (pos >= 0 && dur > 0) { + gchar dstr[32], pstr[32]; + + /* FIXME: pretty print in nicer format */ + g_snprintf (pstr, 32, "%" GST_TIME_FORMAT, GST_TIME_ARGS (pos)); + pstr[9] = '\0'; + g_snprintf (dstr, 32, "%" GST_TIME_FORMAT, GST_TIME_ARGS (dur)); + dstr[9] = '\0'; + g_print ("%s / %s %s\r", pstr, dstr, status); + } + + return TRUE; +} + +static GstPlay * +play_new (gchar ** uris, gdouble initial_volume) +{ + GstPlay *play; + + play = g_new0 (GstPlay, 1); + + play->uris = uris; + play->num_uris = g_strv_length (uris); + play->cur_idx = -1; + + play->player = gst_player_new (TRUE); + + g_signal_connect (play->player, "position-updated", + G_CALLBACK (position_updated_cb), play); + g_signal_connect (play->player, "end-of-stream", + G_CALLBACK (end_of_stream_cb), play); + g_signal_connect (play->player, "error", G_CALLBACK (error_cb), play); + + play->loop = g_main_loop_new (NULL, FALSE); + play->desired_state = GST_STATE_PLAYING; + + play_set_relative_volume (play, initial_volume - 1.0); + + return play; +} + +static void +play_free (GstPlay * play) +{ + play_reset (play); + + g_object_unref (play->player); + + g_main_loop_unref (play->loop); + + g_strfreev (play->uris); + g_free (play); +} + +/* reset for new file/stream */ +static void +play_reset (GstPlay * play) +{ +} + +static void +play_set_relative_volume (GstPlay * play, gdouble volume_step) +{ + gdouble volume; + + g_object_get (play->player, "volume", &volume, NULL); + volume = round ((volume + volume_step) * VOLUME_STEPS) / VOLUME_STEPS; + volume = CLAMP (volume, 0.0, 10.0); + + g_object_set (play->player, "volume", volume, NULL); + + g_print ("Volume: %.0f%% \n", volume * 100); +} + +static gchar * +play_uri_get_display_name (GstPlay * play, const gchar * uri) +{ + gchar *loc; + + if (gst_uri_has_protocol (uri, "file")) { + loc = g_filename_from_uri (uri, NULL, NULL); + } else if (gst_uri_has_protocol (uri, "pushfile")) { + loc = g_filename_from_uri (uri + 4, NULL, NULL); + } else { + loc = g_strdup (uri); + } + + /* Maybe additionally use glib's filename to display name function */ + return loc; +} + +static void +play_uri (GstPlay * play, const gchar * next_uri) +{ + gchar *loc; + + play_reset (play); + + loc = play_uri_get_display_name (play, next_uri); + g_print ("Now playing %s\n", loc); + g_free (loc); + + g_object_set (play->player, "uri", next_uri, NULL); + gst_player_play (play->player); +} + +/* returns FALSE if we have reached the end of the playlist */ +static gboolean +play_next (GstPlay * play) +{ + if ((play->cur_idx + 1) >= play->num_uris) + return FALSE; + + play_uri (play, play->uris[++play->cur_idx]); + return TRUE; +} + +/* returns FALSE if we have reached the beginning of the playlist */ +static gboolean +play_prev (GstPlay * play) +{ + if (play->cur_idx == 0 || play->num_uris <= 1) + return FALSE; + + play_uri (play, play->uris[--play->cur_idx]); + return TRUE; +} + +static void +do_play (GstPlay * play) +{ + gint i; + + /* dump playlist */ + for (i = 0; i < play->num_uris; ++i) + GST_INFO ("%4u : %s", i, play->uris[i]); + + if (!play_next (play)) + return; + + g_main_loop_run (play->loop); +} + +static void +add_to_playlist (GPtrArray * playlist, const gchar * filename) +{ + GDir *dir; + gchar *uri; + + if (gst_uri_is_valid (filename)) { + g_ptr_array_add (playlist, g_strdup (filename)); + return; + } + + if ((dir = g_dir_open (filename, 0, NULL))) { + const gchar *entry; + + /* FIXME: sort entries for each directory? */ + while ((entry = g_dir_read_name (dir))) { + gchar *path; + + path = g_strconcat (filename, G_DIR_SEPARATOR_S, entry, NULL); + add_to_playlist (playlist, path); + g_free (path); + } + + g_dir_close (dir); + return; + } + + uri = gst_filename_to_uri (filename, NULL); + if (uri != NULL) + g_ptr_array_add (playlist, uri); + else + g_warning ("Could not make URI out of filename '%s'", filename); +} + +static void +shuffle_uris (gchar ** uris, guint num) +{ + gchar *tmp; + guint i, j; + + if (num < 2) + return; + + for (i = 0; i < num; i++) { + /* gets equally distributed random number in 0..num-1 [0;num[ */ + j = g_random_int_range (0, num); + tmp = uris[j]; + uris[j] = uris[i]; + uris[i] = tmp; + } +} + +static void +restore_terminal (void) +{ + gst_play_kb_set_key_handler (NULL, NULL); +} + +static void +toggle_paused (GstPlay * play) +{ + if (play->desired_state == GST_STATE_PLAYING) + play->desired_state = GST_STATE_PAUSED; + else + play->desired_state = GST_STATE_PLAYING; + + if (play->desired_state == GST_STATE_PLAYING) + gst_player_play (play->player); + else + gst_player_pause (play->player); +} + +static void +relative_seek (GstPlay * play, gdouble percent) +{ + gint64 dur = -1, pos = -1; + + g_return_if_fail (percent >= -1.0 && percent <= 1.0); + + g_object_get (play->player, "position", &pos, "duration", &dur, NULL); + + if (dur <= 0) + goto seek_failed; + + pos = pos + dur * percent; + if (pos > dur) { + if (!play_next (play)) { + g_print ("\nReached end of play list.\n"); + g_main_loop_quit (play->loop); + } + } else { + if (pos < 0) + pos = 0; + gst_player_seek (play->player, pos); + } + + return; + +seek_failed: + { + g_print ("\nCould not seek.\n"); + } +} + +static void +keyboard_cb (const gchar * key_input, gpointer user_data) +{ + GstPlay *play = (GstPlay *) user_data; + + switch (g_ascii_tolower (key_input[0])) { + case ' ': + toggle_paused (play); + break; + case 'q': + case 'Q': + g_main_loop_quit (play->loop); + break; + case '>': + if (!play_next (play)) { + g_print ("\nReached end of play list.\n"); + g_main_loop_quit (play->loop); + } + break; + case '<': + play_prev (play); + break; + case 27: /* ESC */ + if (key_input[1] == '\0') { + g_main_loop_quit (play->loop); + break; + } + /* fall through */ + default: + if (strcmp (key_input, GST_PLAY_KB_ARROW_RIGHT) == 0) { + relative_seek (play, +0.08); + } else if (strcmp (key_input, GST_PLAY_KB_ARROW_LEFT) == 0) { + relative_seek (play, -0.01); + } else if (strcmp (key_input, GST_PLAY_KB_ARROW_UP) == 0) { + play_set_relative_volume (play, +1.0 / VOLUME_STEPS); + } else if (strcmp (key_input, GST_PLAY_KB_ARROW_DOWN) == 0) { + play_set_relative_volume (play, -1.0 / VOLUME_STEPS); + } else { + GST_INFO ("keyboard input:"); + for (; *key_input != '\0'; ++key_input) + GST_INFO (" code %3d", *key_input); + } + break; + } +} + +int +main (int argc, char **argv) +{ + GstPlay *play; + GPtrArray *playlist; + gboolean print_version = FALSE; + gboolean interactive = FALSE; /* FIXME: maybe enable by default? */ + gboolean shuffle = FALSE; + gdouble volume = 1.0; + gchar **filenames = NULL; + gchar **uris; + guint num, i; + GError *err = NULL; + GOptionContext *ctx; + gchar *playlist_file = NULL; + GOptionEntry options[] = { + {"version", 0, 0, G_OPTION_ARG_NONE, &print_version, + "Print version information and exit", NULL}, + {"shuffle", 0, 0, G_OPTION_ARG_NONE, &shuffle, + "Shuffle playlist", NULL}, + {"interactive", 0, 0, G_OPTION_ARG_NONE, &interactive, + "Interactive control via keyboard", NULL}, + {"volume", 0, 0, G_OPTION_ARG_DOUBLE, &volume, + "Volume", NULL}, + {"playlist", 0, 0, G_OPTION_ARG_FILENAME, &playlist_file, + "Playlist file containing input media files", NULL}, + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL}, + {NULL} + }; + + g_set_prgname ("gst-play"); + + ctx = g_option_context_new ("FILE1|URI1 [FILE2|URI2] [FILE3|URI3] ..."); + g_option_context_add_main_entries (ctx, options, NULL); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); + return 1; + } + g_option_context_free (ctx); + + if (print_version) { + gchar *version_str; + + version_str = gst_version_string (); + g_print ("%s version %s\n", g_get_prgname (), "1.0"); + g_print ("%s\n", version_str); + g_free (version_str); + + g_free (playlist_file); + + return 0; + } + + playlist = g_ptr_array_new (); + + if (playlist_file != NULL) { + gchar *playlist_contents = NULL; + gchar **lines = NULL; + + if (g_file_get_contents (playlist_file, &playlist_contents, NULL, &err)) { + lines = g_strsplit (playlist_contents, "\n", 0); + num = g_strv_length (lines); + + for (i = 0; i < num; i++) { + if (lines[i][0] != '\0') { + GST_LOG ("Playlist[%d]: %s", i + 1, lines[i]); + add_to_playlist (playlist, lines[i]); + } + } + g_strfreev (lines); + g_free (playlist_contents); + } else { + g_printerr ("Could not read playlist: %s\n", err->message); + g_clear_error (&err); + } + g_free (playlist_file); + playlist_file = NULL; + } + + if (playlist->len == 0 && (filenames == NULL || *filenames == NULL)) { + g_printerr ("Usage: %s FILE1|URI1 [FILE2|URI2] [FILE3|URI3] ...", + "gst-play"); + g_printerr ("\n\n"), + g_printerr ("%s\n\n", + "You must provide at least one filename or URI to play."); + /* No input provided. Free array */ + g_ptr_array_free (playlist, TRUE); + + return 1; + } + + /* fill playlist */ + if (filenames != NULL && *filenames != NULL) { + num = g_strv_length (filenames); + for (i = 0; i < num; ++i) { + GST_LOG ("command line argument: %s", filenames[i]); + add_to_playlist (playlist, filenames[i]); + } + g_strfreev (filenames); + } + + num = playlist->len; + g_ptr_array_add (playlist, NULL); + + uris = (gchar **) g_ptr_array_free (playlist, FALSE); + + if (shuffle) + shuffle_uris (uris, num); + + /* prepare */ + play = play_new (uris, volume); + + if (interactive) { + if (gst_play_kb_set_key_handler (keyboard_cb, play)) { + atexit (restore_terminal); + } else { + g_print ("Interactive keyboard handling in terminal not available.\n"); + } + } + + /* play */ + do_play (play); + + /* clean up */ + play_free (play); + + g_print ("\n"); + return 0; +} -- cgit v1.2.3 From 153efa0077b1c1eceb191e7e5024874a0af61d8d Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 27 Jul 2014 18:10:49 +0200 Subject: playback/player: Add a simple Makefile for gst-play --- playback/player/gst-play/Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 playback/player/gst-play/Makefile diff --git a/playback/player/gst-play/Makefile b/playback/player/gst-play/Makefile new file mode 100644 index 0000000..6044c42 --- /dev/null +++ b/playback/player/gst-play/Makefile @@ -0,0 +1,21 @@ +CFLAGS ?= -Wall -O2 -g +PKGCONFIG ?= pkg-config +LIBS := $(shell $(PKGCONFIG) --libs --cflags gstreamer-1.0 gstreamer-video-1.0) -lm + +all: gst-play + +clean: + rm -f gst-play + +SOURCES = \ + gst-play.c \ + gst-play-kb.c \ + ../lib/gstplayer.c + +HEADERS = \ + gst-play-kb.h \ + ../lib/gstplayer.h + +gst-play: $(SOURCES) $(HEADERS) + $(CC) -o $@ $(SOURCES) $(CFLAGS) $(LIBS) -I../lib + -- cgit v1.2.3 From 10eabda41b057b493887b5207b2970aa87a69529 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 28 Jul 2014 12:08:12 +0200 Subject: playback/player: Add debug logging --- playback/player/gst-play/gst-play.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index b5572d6..7981146 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -135,7 +135,7 @@ play_free (GstPlay * play) { play_reset (play); - g_object_unref (play->player); + gst_object_unref (play->player); g_main_loop_unref (play->loop); @@ -423,6 +423,8 @@ main (int argc, char **argv) } g_option_context_free (ctx); + GST_DEBUG_CATEGORY_INIT (play_debug, "play", 0, "gst-play"); + if (print_version) { gchar *version_str; -- cgit v1.2.3 From be4f88ef41b685b2b960ff7c47083cfa48b53197 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 28 Jul 2014 20:09:55 +0200 Subject: playback/player: Add start of an Android player --- playback/player/android/AndroidManifest.xml | 79 ++++ playback/player/android/jni/Android.mk | 24 + playback/player/android/jni/player.c | 489 +++++++++++++++++++++ .../src/org/freedesktop/gstreamer/Player.java | 216 +++++++++ .../gstreamer/player/GStreamerSurfaceView.java | 105 +++++ .../src/org/freedesktop/gstreamer/player/Play.java | 196 +++++++++ 6 files changed, 1109 insertions(+) create mode 100644 playback/player/android/AndroidManifest.xml create mode 100644 playback/player/android/jni/Android.mk create mode 100644 playback/player/android/jni/player.c create mode 100644 playback/player/android/src/org/freedesktop/gstreamer/Player.java create mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java create mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/Play.java diff --git a/playback/player/android/AndroidManifest.xml b/playback/player/android/AndroidManifest.xml new file mode 100644 index 0000000..8b156d4 --- /dev/null +++ b/playback/player/android/AndroidManifest.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk new file mode 100644 index 0000000..378685f --- /dev/null +++ b/playback/player/android/jni/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := gstplayer +LOCAL_SRC_FILES := player.c ../../lib/gstplayer.c +LOCAL_SHARED_LIBRARIES := gstreamer_android +LOCAL_LDLIBS := -llog -landroid +include $(BUILD_SHARED_LIBRARY) + +ifndef GSTREAMER_ROOT +ifndef GSTREAMER_ROOT_ANDROID +$(error GSTREAMER_ROOT_ANDROID is not defined!) +endif +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID) +endif + +GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ + +include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk +GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) +GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 + +include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c new file mode 100644 index 0000000..b77d170 --- /dev/null +++ b/playback/player/android/jni/player.c @@ -0,0 +1,489 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "../../lib/gstplayer.h" + +GST_DEBUG_CATEGORY_STATIC (debug_category); +#define GST_CAT_DEFAULT debug_category + +/* + * These macros provide a way to store the native pointer to Player, which might be 32 or 64 bits, into + * a jlong, which is always 64 bits, without warnings. + */ +#if GLIB_SIZEOF_VOID_P == 8 +# define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(*env)->GetLongField (env, thiz, fieldID) +# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)data) +#else +# define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(jint)(*env)->GetLongField (env, thiz, fieldID) +# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(jint)data) +#endif + +typedef struct _Player +{ + jobject java_player; + GstPlayer *player; + ANativeWindow *native_window; +} Player; + +static pthread_t gst_app_thread; +static pthread_key_t current_jni_env; +static JavaVM *java_vm; +static jfieldID native_player_field_id; +static jmethodID on_position_updated_method_id; +static jmethodID on_duration_changed_method_id; +static jmethodID on_end_of_stream_method_id; +static jmethodID on_seek_finished_method_id; +static jmethodID on_error_method_id; +static jmethodID on_video_dimensions_changed_method_id; + +/* Register this thread with the VM */ +static JNIEnv * +attach_current_thread (void) +{ + JNIEnv *env; + JavaVMAttachArgs args; + + GST_DEBUG ("Attaching thread %p", g_thread_self ()); + args.version = JNI_VERSION_1_4; + args.name = NULL; + args.group = NULL; + + if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { + GST_ERROR ("Failed to attach current thread"); + return NULL; + } + + return env; +} + +/* Unregister this thread from the VM */ +static void +detach_current_thread (void *env) +{ + GST_DEBUG ("Detaching thread %p", g_thread_self ()); + (*java_vm)->DetachCurrentThread (java_vm); +} + +/* Retrieve the JNI environment for this thread */ +static JNIEnv * +get_jni_env (void) +{ + JNIEnv *env; + + if ((env = pthread_getspecific (current_jni_env)) == NULL) { + env = attach_current_thread (); + pthread_setspecific (current_jni_env, env); + } + + return env; +} + +/* + * Java Bindings + */ +static void +on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_position_updated_method_id, position); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_duration_changed_method_id, duration); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_end_of_stream (GstPlayer * unused, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_seek_finished (GstPlayer * unused, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, on_seek_finished_method_id); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_error (GstPlayer * unused, GError * err, Player * player) +{ + JNIEnv *env = get_jni_env (); + jstring error_msg; + + // FIXME + error_msg = err ? (*env)->NewStringUTF (env, err->message) : NULL; + + (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, + error_msg); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + + (*env)->DeleteLocalRef (env, error_msg); +} + +static void +on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, + Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_video_dimensions_changed_method_id, width, height); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +native_new (JNIEnv * env, jobject thiz) +{ + Player *player = g_slice_new0 (Player); + + player->player = gst_player_new (FALSE); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); + player->java_player = (*env)->NewGlobalRef (env, thiz); + + g_signal_connect (player->player, "position-updated", + G_CALLBACK (on_position_updated), player); + g_signal_connect (player->player, "duration-changed", + G_CALLBACK (on_duration_changed), player); + g_signal_connect (player->player, "end-of-stream", + G_CALLBACK (on_end_of_stream), player); + g_signal_connect (player->player, "seek-finished", + G_CALLBACK (on_seek_finished), player); + g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); + g_signal_connect (player->player, "video-dimensions-changed", + G_CALLBACK (on_video_dimensions_changed), player); +} + +static void +native_free (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + (*env)->DeleteGlobalRef (env, player->java_player); + g_slice_free (Player, player); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); +} + +static void +native_play (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_play (player->player); +} + +static void +native_pause (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_pause (player->player); +} + +static void +native_stop (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_stop (player->player); +} + +static void +native_seek (JNIEnv * env, jobject thiz, jlong position) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_seek (player->player, position); +} + +static void +native_set_uri (JNIEnv * env, jobject thiz, jobject uri) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + const gchar *uri_str; + + if (!player) + return; + + uri_str = (*env)->GetStringUTFChars (env, uri, NULL); + g_object_set (player->player, "uri", uri_str, NULL); + (*env)->ReleaseStringUTFChars (env, uri, uri_str); +} + +static jobject +native_get_uri (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jobject uri; + gchar *uri_str; + + if (!player) + return NULL; + + g_object_get (player->player, "uri", &uri_str, NULL); + + uri = (*env)->NewStringUTF (env, uri_str); + g_free (uri_str); + + return uri; +} + +static jboolean +native_is_playing (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jboolean is_playing; + + if (!player) + return FALSE; + + g_object_get (player->player, "is-playing", &is_playing, NULL); + + return is_playing; +} + +static jlong +native_get_position (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble position; + + if (!player) + return -1; + + g_object_get (player->player, "position", &position, NULL); + + return position; +} + +static jlong +native_get_duration (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jlong duration; + + if (!player) + return -1; + + g_object_get (player->player, "duration", &duration, NULL); + + return duration; +} + +static jdouble +native_get_volume (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble volume; + + if (!player) + return 1.0; + + g_object_get (player->player, "volume", &volume, NULL); + + return volume; +} + +static void +native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "volume", volume, NULL); +} + +static jboolean +native_get_mute (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jboolean mute; + + if (!player) + return FALSE; + + g_object_get (player->player, "mute", &mute, NULL); + + return mute; +} + +static void +native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "mute", mute, NULL); +} + +static void +native_set_surface (JNIEnv * env, jobject thiz, jobject surface) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + ANativeWindow *new_native_window; + + if (!player) + return; + + new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; + GST_DEBUG ("Received surface %p (native window %p)", surface, + new_native_window); + + if (player->native_window) { + ANativeWindow_release (player->native_window); + } + + player->native_window = new_native_window; + g_object_set (player->player, "window-handle", (gpointer) new_native_window, + NULL); +} + +static void +native_class_init (JNIEnv * env, jclass klass) +{ + native_player_field_id = + (*env)->GetFieldID (env, klass, "native_player", "J"); + on_position_updated_method_id = + (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); + on_duration_changed_method_id = + (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); + on_end_of_stream_method_id = + (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); + on_seek_finished_method_id = + (*env)->GetMethodID (env, klass, "onSeekFinished", "()V"); + on_error_method_id = + (*env)->GetMethodID (env, klass, "onError", "(Ljava/lang/String;)V"); + on_video_dimensions_changed_method_id = + (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); + + if (!native_player_field_id || + !on_position_updated_method_id || !on_duration_changed_method_id || + !on_end_of_stream_method_id || !on_seek_finished_method_id || + !on_error_method_id || !on_video_dimensions_changed_method_id) { + static const gchar *message = + "The calling class does not implement all necessary interface methods"; + jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); + (*env)->ThrowNew (env, exception_class, message); + } + + gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); +} + +/* List of implemented native methods */ +static JNINativeMethod native_methods[] = { + {"nativeClassInit", "()V", (void *) native_class_init}, + {"nativeNew", "()V", (void *) native_new}, + {"nativePlay", "()V", (void *) native_play}, + {"nativePause", "()V", (void *) native_pause}, + {"nativeSeek", "(J)V", (void *) native_seek}, + {"nativeFree", "()V", (void *) native_free}, + {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, + {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, + {"nativeIsPlaying", "()Z", (void *) native_is_playing}, + {"nativeGetPosition", "()J", (void *) native_get_position}, + {"nativeGetDuration", "()J", (void *) native_get_duration}, + {"nativeGetVolume", "()D", (void *) native_get_volume}, + {"nativeSetVolume", "(D)V", (void *) native_set_volume}, + {"nativeGetMute", "()Z", (void *) native_get_mute}, + {"nativeSetMute", "(Z)V", (void *) native_set_mute}, + {"nativeSetSurface", "(Landroid/view/Surface;)V", + (void *) native_set_surface} +}; + +/* Library initializer */ +jint +JNI_OnLoad (JavaVM * vm, void *reserved) +{ + JNIEnv *env = NULL; + + java_vm = vm; + + if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve JNIEnv"); + return 0; + } + jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); + (*env)->RegisterNatives (env, klass, native_methods, + G_N_ELEMENTS (native_methods)); + + pthread_key_create (¤t_jni_env, detach_current_thread); + + return JNI_VERSION_1_4; +} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java new file mode 100644 index 0000000..862444b --- /dev/null +++ b/playback/player/android/src/org/freedesktop/gstreamer/Player.java @@ -0,0 +1,216 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer; + +import java.io.Closeable; +import android.view.Surface; +import android.content.Context; +import org.freedesktop.gstreamer.GStreamer; + +public class Player implements Closeable { + private static native void nativeClassInit(); + public static void init(Context context) throws Exception { + System.loadLibrary("gstreamer_android"); + GStreamer.init(context); + + System.loadLibrary("gstplayer"); + nativeClassInit(); + } + + private long native_player; + private native void nativeNew(); + public Player() { + nativeNew(); + } + + private native void nativeFree(); + @Override + public void close() { + nativeFree(); + } + + private native void nativePlay(); + public void play() { + nativePlay(); + } + + private native void nativePause(); + public void pause() { + nativePause(); + } + + private native void nativeStop(); + public void stop() { + nativeStop(); + } + + private native void nativeSeek(long position); + public void seek(long position) { + nativeSeek(position); + } + + private native String nativeGetUri(); + public String getUri() { + return nativeGetUri(); + } + + private native void nativeSetUri(String uri); + public void setUri(String uri) { + nativeSetUri(uri); + } + + private native boolean nativeIsPlaying(); + public boolean isPlaying() { + return nativeIsPlaying(); + } + + private native long nativeGetPosition(); + public long getPosition() { + return nativeGetPosition(); + } + + private native long nativeGetDuration(); + public long getDuration() { + return nativeGetDuration(); + } + + private native double nativeGetVolume(); + public double getVolume() { + return nativeGetVolume(); + } + + private native void nativeSetVolume(double volume); + public void setVolume(double volume) { + nativeSetVolume(volume); + } + + private native boolean nativeGetMute(); + public boolean getMute() { + return nativeGetMute(); + } + + private native void nativeSetMute(boolean mute); + public void setMute(boolean mute) { + nativeSetMute(mute); + } + + private Surface surface; + private native void nativeSetSurface(Surface surface); + public void setSurface(Surface surface) { + this.surface = surface; + nativeSetSurface(surface); + } + + public Surface getSurface() { + return surface; + } + + public static interface PositionUpdatedListener { + abstract void positionUpdated(Player player, long position); + } + + private PositionUpdatedListener positionUpdatedListener; + public void setPositionUpdatedListener(PositionUpdatedListener listener) { + positionUpdatedListener = listener; + } + + private void onPositionUpdated(long position) { + if (positionUpdatedListener != null) { + positionUpdatedListener.positionUpdated(this, position); + } + } + + public static interface DurationChangedListener { + abstract void durationChanged(Player player, long duration); + } + + private DurationChangedListener durationChangedListener; + public void setDurationChangedListener(DurationChangedListener listener) { + durationChangedListener = listener; + } + + private void onDurationChanged(long duration) { + if (durationChangedListener != null) { + durationChangedListener.durationChanged(this, duration); + } + } + + public static interface EndOfStreamListener { + abstract void endOfStream(Player player); + } + + private EndOfStreamListener endOfStreamListener; + public void setEndOfStreamListener(EndOfStreamListener listener) { + endOfStreamListener = listener; + } + + private void onEndOfStream() { + if (endOfStreamListener != null) { + endOfStreamListener.endOfStream(this); + } + } + + public static interface SeekFinishedListener { + abstract void seekFinished(Player player); + } + + private SeekFinishedListener seekFinishedListener; + public void setSeekFinishedListener(SeekFinishedListener listener) { + seekFinishedListener = listener; + } + + private void onSeekFinished() { + if (seekFinishedListener != null) { + seekFinishedListener.seekFinished(this); + } + } + + public static interface ErrorListener { + // FIXME: enums + abstract void error(Player player, String errorMessage); + } + + private ErrorListener errorListener; + public void setErrorListener(ErrorListener listener) { + errorListener = listener; + } + + private void onError(String errorMessage) { + if (errorListener != null) { + errorListener.error(this, errorMessage); + } + } + + public static interface VideoDimensionsChangedListener { + abstract void videoDimensionsChanged(Player player, int width, int height); + } + + private VideoDimensionsChangedListener videoDimensionsChangedListener; + public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { + videoDimensionsChangedListener = listener; + } + + private void onVideoDimensionsChanged(int width, int height) { + if (videoDimensionsChangedListener != null) { + videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); + } + } +} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java new file mode 100644 index 0000000..f2dd8a9 --- /dev/null +++ b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java @@ -0,0 +1,105 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceView; +import android.view.View; + +// A simple SurfaceView whose width and height can be set from the outside +public class GStreamerSurfaceView extends SurfaceView { + public int media_width = 320; + public int media_height = 240; + + // Mandatory constructors, they do not do much + public GStreamerSurfaceView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public GStreamerSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public GStreamerSurfaceView (Context context) { + super(context); + } + + // Called by the layout manager to find out our size and give us some rules. + // We will try to maximize our size, and preserve the media's aspect ratio if + // we are given the freedom to do so. + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = 0, height = 0; + int wmode = View.MeasureSpec.getMode(widthMeasureSpec); + int hmode = View.MeasureSpec.getMode(heightMeasureSpec); + int wsize = View.MeasureSpec.getSize(widthMeasureSpec); + int hsize = View.MeasureSpec.getSize(heightMeasureSpec); + + Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); + // Obey width rules + switch (wmode) { + case View.MeasureSpec.AT_MOST: + if (hmode == View.MeasureSpec.EXACTLY) { + width = Math.min(hsize * media_width / media_height, wsize); + break; + } + case View.MeasureSpec.EXACTLY: + width = wsize; + break; + case View.MeasureSpec.UNSPECIFIED: + width = media_width; + } + + // Obey height rules + switch (hmode) { + case View.MeasureSpec.AT_MOST: + if (wmode == View.MeasureSpec.EXACTLY) { + height = Math.min(wsize * media_height / media_width, hsize); + break; + } + case View.MeasureSpec.EXACTLY: + height = hsize; + break; + case View.MeasureSpec.UNSPECIFIED: + height = media_height; + } + + // Finally, calculate best size when both axis are free + if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { + int correct_height = width * media_height / media_width; + int correct_width = height * media_width / media_height; + + if (correct_height < height) + height = correct_height; + else + width = correct_width; + } + + // Obey minimum size + width = Math.max (getSuggestedMinimumWidth(), width); + height = Math.max (getSuggestedMinimumHeight(), height); + setMeasuredDimension(width, height); + } + +} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java b/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java new file mode 100644 index 0000000..2874f05 --- /dev/null +++ b/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java @@ -0,0 +1,196 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.PowerManager; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; +import android.widget.Toast; + +import org.freedesktop.gstreamer.Player; + +public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener { + private PowerManager.WakeLock wake_lock; + private Player player; + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + try { + Player.init(this); + } catch (Exception e) { + Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); + finish(); + return; + } + + setContentView(R.layout.main); + + player = new Player(); + + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); + wake_lock.setReferenceCounted(false); + + ImageButton play = (ImageButton) this.findViewById(R.id.button_play); + play.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.play(); + wake_lock.acquire(); + } + }); + + ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); + pause.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.pause(); + wake_lock.release(); + } + }); + + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + sb.setOnSeekBarChangeListener(this); + + player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { + public void positionUpdated(Player player, final long position) { + runOnUiThread (new Runnable() { + public void run() { + sb.setProgress((int) (position / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + player.setDurationChangedListener(new Player.DurationChangedListener() { + public void durationChanged(Player player, final long duration) { + runOnUiThread (new Runnable() { + public void run() { + sb.setMax((int) (duration / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); + player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { + public void videoDimensionsChanged(Player player, final int width, final int height) { + runOnUiThread (new Runnable() { + public void run() { + Log.i ("GStreamer", "Media size changed to " + width + "x" + height); + gsv.media_width = width; + gsv.media_height = height; + runOnUiThread(new Runnable() { + public void run() { + gsv.requestLayout(); + } + }); + } + }); + } + }); + + SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video); + SurfaceHolder sh = sv.getHolder(); + sh.addCallback(this); + + String mediaUri = null; + Intent intent = getIntent(); + android.net.Uri uri = intent.getData(); + Log.i ("GStreamer", "Received URI: " + uri); + if (uri.getScheme().equals("content")) { + android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); + cursor.close(); + } else { + mediaUri = uri.toString(); + } + player.setUri(mediaUri); + + updateTimeWidget(); + } + + protected void onDestroy() { + player.close(); + super.onDestroy(); + } + + private void updateTimeWidget () { + final TextView tv = (TextView) this.findViewById(R.id.textview_time); + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + final int pos = sb.getProgress(); + final int max = sb.getMax(); + + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max)); + tv.setText(message); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + Log.d("GStreamer", "Surface changed to format " + format + " width " + + width + " height " + height); + player.setSurface(holder.getSurface()); + } + + public void surfaceCreated(SurfaceHolder holder) { + Log.d("GStreamer", "Surface created: " + holder.getSurface()); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d("GStreamer", "Surface destroyed"); + player.setSurface(null); + } + + public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { + if (!fromUser) return; + + updateTimeWidget(); + } + + public void onStartTrackingTouch(SeekBar sb) { + } + + public void onStopTrackingTouch(SeekBar sb) { + Log.d("GStreamer", "Seek to " + sb.getProgress()); + player.seek(((long) sb.getProgress()) * 1000000); + } +} -- cgit v1.2.3 From 3352d5aee08ca42367746388e1eb46abe195e2f0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 30 Jul 2014 16:18:01 +0200 Subject: playback/player: Add GTK+ sample application --- playback/player/gtk/Makefile | 19 ++++ playback/player/gtk/gtk-play.c | 216 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 playback/player/gtk/Makefile create mode 100644 playback/player/gtk/gtk-play.c diff --git a/playback/player/gtk/Makefile b/playback/player/gtk/Makefile new file mode 100644 index 0000000..0fffb37 --- /dev/null +++ b/playback/player/gtk/Makefile @@ -0,0 +1,19 @@ +CFLAGS ?= -Wall -O2 -g +PKGCONFIG ?= pkg-config +LIBS := $(shell $(PKGCONFIG) --libs --cflags gstreamer-1.0 gstreamer-video-1.0 gtk+-3.0) -lm + +all: gtk-play + +clean: + rm -f gtk-play + +SOURCES = \ + gtk-play.c \ + ../lib/gstplayer.c + +HEADERS = \ + ../lib/gstplayer.h + +gtk-play: $(SOURCES) $(HEADERS) + $(CC) -o $@ $(SOURCES) $(CFLAGS) $(LIBS) -I../lib + diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c new file mode 100644 index 0000000..437fc36 --- /dev/null +++ b/playback/player/gtk/gtk-play.c @@ -0,0 +1,216 @@ +#include + +#include +#include + +#include +#if defined (GDK_WINDOWING_X11) +#include +#elif defined (GDK_WINDOWING_WIN32) +#include +#elif defined (GDK_WINDOWING_QUARTZ) +#include +#endif + +#include + +#include "../lib/gstplayer.h" + +typedef struct +{ + GstPlayer *player; + gchar *uri; + + GtkWidget *window; + GtkWidget *play_button, *pause_button; + GtkWidget *seekbar; + GtkWidget *video_area; + gulong seekbar_value_changed_signal_id; +} GtkPlay; + +static void +delete_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +{ + gst_player_stop (play->player); + gtk_main_quit (); +} + +static void +video_area_realize_cb (GtkWidget * widget, GtkPlay * play) +{ + GdkWindow *window = gtk_widget_get_window (widget); + guintptr window_handle; + + if (!gdk_window_ensure_native (window)) + g_error ("Couldn't create native window needed for GstXOverlay!"); + +#if defined (GDK_WINDOWING_WIN32) + window_handle = (guintptr) GDK_WINDOW_HWND (window); +#elif defined (GDK_WINDOWING_QUARTZ) + window_handle = gdk_quartz_window_get_nsview (window); +#elif defined (GDK_WINDOWING_X11) + window_handle = GDK_WINDOW_XID (window); +#endif + g_object_set (play->player, "window-handle", (gpointer) window_handle, NULL); +} + +static void +play_clicked_cb (GtkButton * button, GtkPlay * play) +{ + gst_player_play (play->player); +} + +static void +pause_clicked_cb (GtkButton * button, GtkPlay * play) +{ + gst_player_pause (play->player); +} + +static void +seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) +{ + gdouble value = gtk_range_get_value (GTK_RANGE (play->seekbar)); + gst_player_seek (play->player, gst_util_uint64_scale (value, GST_SECOND, 1)); +} + +static void +create_ui (GtkPlay * play) +{ + GtkWidget *controls, *main_hbox, *main_vbox; + + play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (G_OBJECT (play->window), "delete-event", + G_CALLBACK (delete_event_cb), play); + + play->video_area = gtk_drawing_area_new (); + gtk_widget_set_double_buffered (play->video_area, FALSE); + g_signal_connect (play->video_area, "realize", + G_CALLBACK (video_area_realize_cb), play); + + play->play_button = + gtk_button_new_from_icon_name ("media-playback-start", + GTK_ICON_SIZE_BUTTON); + g_signal_connect (G_OBJECT (play->play_button), "clicked", + G_CALLBACK (play_clicked_cb), play); + + play->pause_button = + gtk_button_new_from_icon_name ("media-playback-pause", + GTK_ICON_SIZE_BUTTON); + g_signal_connect (G_OBJECT (play->pause_button), "clicked", + G_CALLBACK (pause_clicked_cb), play); + + play->seekbar = + gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 100, 1); + gtk_scale_set_draw_value (GTK_SCALE (play->seekbar), 0); + play->seekbar_value_changed_signal_id = + g_signal_connect (G_OBJECT (play->seekbar), "value-changed", + G_CALLBACK (seekbar_value_changed_cb), play); + + controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start (GTK_BOX (controls), play->play_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->pause_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); + + main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); + + main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (main_vbox), controls, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (play->window), main_vbox); + + gtk_widget_realize (play->video_area); + + gtk_widget_show_all (play->window); + + gtk_widget_hide (play->video_area); +} + +static void +play_clear (GtkPlay * play) +{ + g_free (play->uri); + g_object_unref (play->player); +} + +static void +duration_changed_cb (GstPlayer * unused, GstClockTime duration, GtkPlay * play) +{ + gtk_range_set_range (GTK_RANGE (play->seekbar), 0, + (gdouble) duration / GST_SECOND); +} + +static void +position_updated_cb (GstPlayer * unused, GstClockTime position, GtkPlay * play) +{ + g_signal_handler_block (play->seekbar, play->seekbar_value_changed_signal_id); + gtk_range_set_value (GTK_RANGE (play->seekbar), + (gdouble) position / GST_SECOND); + g_signal_handler_unblock (play->seekbar, + play->seekbar_value_changed_signal_id); +} + +static void +video_dimensions_changed_cb (GstPlayer * unused, gint width, gint height, + GtkPlay * play) +{ + gtk_widget_show (play->video_area); +} + +int +main (gint argc, gchar ** argv) +{ + GtkPlay play; + GOptionContext *ctx; + GOptionEntry options[] = { + {NULL} + }; + GError *err = NULL; + + memset (&play, 0, sizeof (play)); + + g_set_prgname ("gtk-play"); + + ctx = g_option_context_new ("FILE|URI"); + g_option_context_add_main_entries (ctx, options, NULL); + g_option_context_add_group (ctx, gtk_get_option_group (TRUE)); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); + return 1; + } + g_option_context_free (ctx); + + // FIXME: Add support for playlists and stuff + play.uri = g_strdup (argv[1]); + if (!play.uri) { + g_print ("Usage: %s FILE|URI\n", argv[0]); + return 1; + } + + play.player = gst_player_new (TRUE); + + if (!gst_uri_is_valid (play.uri)) { + gchar *uri = gst_filename_to_uri (play.uri, NULL); + g_free (play.uri); + play.uri = uri; + } + g_object_set (play.player, "uri", play.uri, NULL); + + create_ui (&play); + + g_signal_connect (play.player, "position-updated", + G_CALLBACK (position_updated_cb), &play); + g_signal_connect (play.player, "duration-changed", + G_CALLBACK (duration_changed_cb), &play); + g_signal_connect (play.player, "video-dimensions-changed", + G_CALLBACK (video_dimensions_changed_cb), &play); + + gst_player_pause (play.player); + + gtk_main (); + + play_clear (&play); + + return 0; +} -- cgit v1.2.3 From b34e62884c80ccdf4b0dcd6f71231dc23a6a6f9c Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 2 Aug 2014 20:33:38 +0200 Subject: playback/player: Move library around into a proper directory --- playback/player/android/jni/Android.mk | 2 +- playback/player/android/jni/player.c | 2 +- playback/player/gst-play/Makefile | 4 ++-- playback/player/gst-play/gst-play.c | 2 +- playback/player/gtk/Makefile | 4 ++-- playback/player/gtk/gtk-play.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 378685f..39ad84e 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -3,7 +3,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := player.c ../../lib/gstplayer.c +LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c LOCAL_SHARED_LIBRARIES := gstreamer_android LOCAL_LDLIBS := -llog -landroid include $(BUILD_SHARED_LIBRARY) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index b77d170..e0e2d22 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -25,7 +25,7 @@ #include #include -#include "../../lib/gstplayer.h" +#include "../../lib/gst/player/gstplayer.h" GST_DEBUG_CATEGORY_STATIC (debug_category); #define GST_CAT_DEFAULT debug_category diff --git a/playback/player/gst-play/Makefile b/playback/player/gst-play/Makefile index 6044c42..ff88941 100644 --- a/playback/player/gst-play/Makefile +++ b/playback/player/gst-play/Makefile @@ -10,11 +10,11 @@ clean: SOURCES = \ gst-play.c \ gst-play-kb.c \ - ../lib/gstplayer.c + ../lib/gst/player/gstplayer.c HEADERS = \ gst-play-kb.h \ - ../lib/gstplayer.h + ../lib/gst/player/gstplayer.h gst-play: $(SOURCES) $(HEADERS) $(CC) -o $@ $(SOURCES) $(CFLAGS) $(LIBS) -I../lib diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 7981146..5154d7a 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -29,7 +29,7 @@ #include #include "gst-play-kb.h" -#include "gstplayer.h" +#include #define VOLUME_STEPS 20 diff --git a/playback/player/gtk/Makefile b/playback/player/gtk/Makefile index 0fffb37..a17c45e 100644 --- a/playback/player/gtk/Makefile +++ b/playback/player/gtk/Makefile @@ -9,10 +9,10 @@ clean: SOURCES = \ gtk-play.c \ - ../lib/gstplayer.c + ../lib/gst/player/gstplayer.c HEADERS = \ - ../lib/gstplayer.h + ../lib/gst/player/gstplayer.h gtk-play: $(SOURCES) $(HEADERS) $(CC) -o $@ $(SOURCES) $(CFLAGS) $(LIBS) -I../lib diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 437fc36..7bbc7a8 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -14,7 +14,7 @@ #include -#include "../lib/gstplayer.h" +#include typedef struct { -- cgit v1.2.3 From 7071c121b6953fd99ab8593bda23dfa55ca759ab Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 2 Aug 2014 20:19:09 +0200 Subject: playback/player: Add iOS app --- .../player/ios/GstPlay.xcodeproj/project.pbxproj | 437 +++++++++ .../project.xcworkspace/contents.xcworkspacedata | 7 + .../slomo.xcuserdatad/xcschemes/GstPlay.xcscheme | 96 ++ .../xcschemes/xcschememanagement.plist | 27 + playback/player/ios/GstPlay/AppDelegate.h | 15 + playback/player/ios/GstPlay/AppDelegate.m | 45 + playback/player/ios/GstPlay/EaglUIVIew.h | 11 + playback/player/ios/GstPlay/EaglUIVIew.m | 13 + playback/player/ios/GstPlay/GstPlay-Info.plist | 49 + playback/player/ios/GstPlay/GstPlay-Prefix.pch | 16 + .../player/ios/GstPlay/LibraryViewController.h | 12 + .../player/ios/GstPlay/LibraryViewController.m | 165 ++++ .../ios/GstPlay/MainStoryboard_iPad.storyboard | 180 ++++ .../ios/GstPlay/MainStoryboard_iPhone.storyboard | 185 ++++ playback/player/ios/GstPlay/Ubuntu-R.ttf | Bin 0 -> 353824 bytes playback/player/ios/GstPlay/VideoViewController.h | 23 + playback/player/ios/GstPlay/VideoViewController.m | 204 +++++ .../player/ios/GstPlay/en.lproj/InfoPlist.strings | 2 + playback/player/ios/GstPlay/fonts.conf | 126 +++ playback/player/ios/GstPlay/gst_ios_init.h | 39 + playback/player/ios/GstPlay/gst_ios_init.m | 988 +++++++++++++++++++++ playback/player/ios/GstPlay/main.m | 12 + 22 files changed, 2652 insertions(+) create mode 100644 playback/player/ios/GstPlay.xcodeproj/project.pbxproj create mode 100644 playback/player/ios/GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/GstPlay.xcscheme create mode 100644 playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 playback/player/ios/GstPlay/AppDelegate.h create mode 100644 playback/player/ios/GstPlay/AppDelegate.m create mode 100644 playback/player/ios/GstPlay/EaglUIVIew.h create mode 100644 playback/player/ios/GstPlay/EaglUIVIew.m create mode 100644 playback/player/ios/GstPlay/GstPlay-Info.plist create mode 100644 playback/player/ios/GstPlay/GstPlay-Prefix.pch create mode 100644 playback/player/ios/GstPlay/LibraryViewController.h create mode 100644 playback/player/ios/GstPlay/LibraryViewController.m create mode 100644 playback/player/ios/GstPlay/MainStoryboard_iPad.storyboard create mode 100644 playback/player/ios/GstPlay/MainStoryboard_iPhone.storyboard create mode 100644 playback/player/ios/GstPlay/Ubuntu-R.ttf create mode 100644 playback/player/ios/GstPlay/VideoViewController.h create mode 100644 playback/player/ios/GstPlay/VideoViewController.m create mode 100644 playback/player/ios/GstPlay/en.lproj/InfoPlist.strings create mode 100644 playback/player/ios/GstPlay/fonts.conf create mode 100644 playback/player/ios/GstPlay/gst_ios_init.h create mode 100644 playback/player/ios/GstPlay/gst_ios_init.m create mode 100644 playback/player/ios/GstPlay/main.m diff --git a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj new file mode 100644 index 0000000..14facf3 --- /dev/null +++ b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj @@ -0,0 +1,437 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + AD2B881F198D631B0070367B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B881E198D631B0070367B /* Foundation.framework */; }; + AD2B8821198D631B0070367B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B8820198D631B0070367B /* CoreGraphics.framework */; }; + AD2B8823198D631B0070367B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B8822198D631B0070367B /* UIKit.framework */; }; + AD2B8825198D631B0070367B /* GStreamer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B8824198D631B0070367B /* GStreamer.framework */; }; + AD2B882B198D631B0070367B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AD2B8829198D631B0070367B /* InfoPlist.strings */; }; + AD2B882D198D631B0070367B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B882C198D631B0070367B /* main.m */; }; + AD2B8831198D631B0070367B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B8830198D631B0070367B /* AppDelegate.m */; }; + AD2B8833198D631B0070367B /* fonts.conf in Resources */ = {isa = PBXBuildFile; fileRef = AD2B8832198D631B0070367B /* fonts.conf */; }; + AD2B8835198D631B0070367B /* Ubuntu-R.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AD2B8834198D631B0070367B /* Ubuntu-R.ttf */; }; + AD2B8837198D631B0070367B /* gst_ios_init.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B8836198D631B0070367B /* gst_ios_init.m */; }; + AD2B8858198D637A0070367B /* EaglUIVIew.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B8857198D637A0070367B /* EaglUIVIew.m */; }; + AD2B885B198D65470070367B /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD2B8859198D65470070367B /* MainStoryboard_iPhone.storyboard */; }; + AD2B885C198D65470070367B /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD2B885A198D65470070367B /* MainStoryboard_iPad.storyboard */; }; + AD2B8861198D65780070367B /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B885E198D65780070367B /* LibraryViewController.m */; }; + AD2B8862198D65780070367B /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B8860198D65780070367B /* VideoViewController.m */; }; + AD2B886C198D69ED0070367B /* gstplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = AD2B886A198D69ED0070367B /* gstplayer.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + AD2B881B198D631B0070367B /* GstPlay.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GstPlay.app; sourceTree = BUILT_PRODUCTS_DIR; }; + AD2B881E198D631B0070367B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + AD2B8820198D631B0070367B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + AD2B8822198D631B0070367B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + AD2B8824198D631B0070367B /* GStreamer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GStreamer.framework; path = Library/Frameworks/GStreamer.framework; sourceTree = DEVELOPER_DIR; }; + AD2B8828198D631B0070367B /* GstPlay-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GstPlay-Info.plist"; sourceTree = ""; }; + AD2B882A198D631B0070367B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + AD2B882C198D631B0070367B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + AD2B882E198D631B0070367B /* GstPlay-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GstPlay-Prefix.pch"; sourceTree = ""; }; + AD2B882F198D631B0070367B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + AD2B8830198D631B0070367B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + AD2B8832198D631B0070367B /* fonts.conf */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = fonts.conf; sourceTree = ""; }; + AD2B8834198D631B0070367B /* Ubuntu-R.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Ubuntu-R.ttf"; sourceTree = ""; }; + AD2B8836198D631B0070367B /* gst_ios_init.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = gst_ios_init.m; sourceTree = ""; }; + AD2B8838198D631B0070367B /* gst_ios_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gst_ios_init.h; sourceTree = ""; }; + AD2B8840198D631B0070367B /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + AD2B8856198D637A0070367B /* EaglUIVIew.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EaglUIVIew.h; sourceTree = ""; }; + AD2B8857198D637A0070367B /* EaglUIVIew.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EaglUIVIew.m; sourceTree = ""; }; + AD2B8859198D65470070367B /* MainStoryboard_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MainStoryboard_iPhone.storyboard; sourceTree = ""; }; + AD2B885A198D65470070367B /* MainStoryboard_iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MainStoryboard_iPad.storyboard; sourceTree = ""; }; + AD2B885D198D65780070367B /* LibraryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibraryViewController.h; sourceTree = ""; }; + AD2B885E198D65780070367B /* LibraryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LibraryViewController.m; sourceTree = ""; }; + AD2B885F198D65780070367B /* VideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoViewController.h; sourceTree = ""; }; + AD2B8860198D65780070367B /* VideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; }; + AD2B886A198D69ED0070367B /* gstplayer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gstplayer.c; sourceTree = ""; }; + AD2B886B198D69ED0070367B /* gstplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gstplayer.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + AD2B8818198D631B0070367B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AD2B8821198D631B0070367B /* CoreGraphics.framework in Frameworks */, + AD2B8825198D631B0070367B /* GStreamer.framework in Frameworks */, + AD2B8823198D631B0070367B /* UIKit.framework in Frameworks */, + AD2B881F198D631B0070367B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + AD2B8812198D631B0070367B = { + isa = PBXGroup; + children = ( + AD2B8868198D69ED0070367B /* gst */, + AD2B8826198D631B0070367B /* GstPlay */, + AD2B881D198D631B0070367B /* Frameworks */, + AD2B881C198D631B0070367B /* Products */, + ); + sourceTree = ""; + }; + AD2B881C198D631B0070367B /* Products */ = { + isa = PBXGroup; + children = ( + AD2B881B198D631B0070367B /* GstPlay.app */, + ); + name = Products; + sourceTree = ""; + }; + AD2B881D198D631B0070367B /* Frameworks */ = { + isa = PBXGroup; + children = ( + AD2B881E198D631B0070367B /* Foundation.framework */, + AD2B8820198D631B0070367B /* CoreGraphics.framework */, + AD2B8822198D631B0070367B /* UIKit.framework */, + AD2B8824198D631B0070367B /* GStreamer.framework */, + AD2B8840198D631B0070367B /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + AD2B8826198D631B0070367B /* GstPlay */ = { + isa = PBXGroup; + children = ( + AD2B8856198D637A0070367B /* EaglUIVIew.h */, + AD2B8857198D637A0070367B /* EaglUIVIew.m */, + AD2B882F198D631B0070367B /* AppDelegate.h */, + AD2B8830198D631B0070367B /* AppDelegate.m */, + AD2B8859198D65470070367B /* MainStoryboard_iPhone.storyboard */, + AD2B885A198D65470070367B /* MainStoryboard_iPad.storyboard */, + AD2B885D198D65780070367B /* LibraryViewController.h */, + AD2B885E198D65780070367B /* LibraryViewController.m */, + AD2B885F198D65780070367B /* VideoViewController.h */, + AD2B8860198D65780070367B /* VideoViewController.m */, + AD2B8827198D631B0070367B /* Supporting Files */, + ); + path = GstPlay; + sourceTree = ""; + }; + AD2B8827198D631B0070367B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + AD2B8828198D631B0070367B /* GstPlay-Info.plist */, + AD2B8829198D631B0070367B /* InfoPlist.strings */, + AD2B882C198D631B0070367B /* main.m */, + AD2B882E198D631B0070367B /* GstPlay-Prefix.pch */, + AD2B8832198D631B0070367B /* fonts.conf */, + AD2B8834198D631B0070367B /* Ubuntu-R.ttf */, + AD2B8836198D631B0070367B /* gst_ios_init.m */, + AD2B8838198D631B0070367B /* gst_ios_init.h */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + AD2B8868198D69ED0070367B /* gst */ = { + isa = PBXGroup; + children = ( + AD2B8869198D69ED0070367B /* player */, + ); + name = gst; + path = ../lib/gst; + sourceTree = ""; + }; + AD2B8869198D69ED0070367B /* player */ = { + isa = PBXGroup; + children = ( + AD2B886A198D69ED0070367B /* gstplayer.c */, + AD2B886B198D69ED0070367B /* gstplayer.h */, + ); + path = player; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + AD2B881A198D631B0070367B /* GstPlay */ = { + isa = PBXNativeTarget; + buildConfigurationList = AD2B8850198D631B0070367B /* Build configuration list for PBXNativeTarget "GstPlay" */; + buildPhases = ( + AD2B8817198D631B0070367B /* Sources */, + AD2B8818198D631B0070367B /* Frameworks */, + AD2B8819198D631B0070367B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GstPlay; + productName = GstPlay; + productReference = AD2B881B198D631B0070367B /* GstPlay.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + AD2B8813198D631B0070367B /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0510; + ORGANIZATIONNAME = "Sebastian Dröge"; + }; + buildConfigurationList = AD2B8816198D631B0070367B /* Build configuration list for PBXProject "GstPlay" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = AD2B8812198D631B0070367B; + productRefGroup = AD2B881C198D631B0070367B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + AD2B881A198D631B0070367B /* GstPlay */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + AD2B8819198D631B0070367B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AD2B885C198D65470070367B /* MainStoryboard_iPad.storyboard in Resources */, + AD2B885B198D65470070367B /* MainStoryboard_iPhone.storyboard in Resources */, + AD2B8835198D631B0070367B /* Ubuntu-R.ttf in Resources */, + AD2B8833198D631B0070367B /* fonts.conf in Resources */, + AD2B882B198D631B0070367B /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + AD2B8817198D631B0070367B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AD2B8861198D65780070367B /* LibraryViewController.m in Sources */, + AD2B8831198D631B0070367B /* AppDelegate.m in Sources */, + AD2B8862198D65780070367B /* VideoViewController.m in Sources */, + AD2B8858198D637A0070367B /* EaglUIVIew.m in Sources */, + AD2B882D198D631B0070367B /* main.m in Sources */, + AD2B8837198D631B0070367B /* gst_ios_init.m in Sources */, + AD2B886C198D69ED0070367B /* gstplayer.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + AD2B8829198D631B0070367B /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + AD2B882A198D631B0070367B /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + AD2B884E198D631B0070367B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + AD2B884F198D631B0070367B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + AD2B8851198D631B0070367B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = armv7; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "~/Library/Developer/GStreamer/iPhone.sdk", + "$(DEVELOPER_FRAMEWORKS_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "GstPlay/GstPlay-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "\"~/Library/Developer/GStreamer/iPhone.sdk/GStreamer.framework/Headers\"", + ../lib, + ); + INFOPLIST_FILE = "GstPlay/GstPlay-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + OTHER_LDFLAGS = ( + "-lresolv", + "-lstdc++", + "-framework", + CoreFoundation, + "-framework", + Foundation, + "-framework", + AVFoundation, + "-framework", + CoreMedia, + "-framework", + CoreVideo, + "-framework", + CoreAudio, + "-framework", + AudioToolbox, + "-framework", + OpenGLES, + "-framework", + AssetsLibrary, + "-framework", + QuartzCore, + "-framework", + AssetsLibrary, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + AD2B8852198D631B0070367B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = armv7; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + FRAMEWORK_SEARCH_PATHS = ( + "~/Library/Developer/GStreamer/iPhone.sdk", + "$(DEVELOPER_FRAMEWORKS_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "GstPlay/GstPlay-Prefix.pch"; + HEADER_SEARCH_PATHS = ( + "\"~/Library/Developer/GStreamer/iPhone.sdk/GStreamer.framework/Headers\"", + ../lib, + ); + INFOPLIST_FILE = "GstPlay/GstPlay-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + OTHER_LDFLAGS = ( + "-lresolv", + "-lstdc++", + "-framework", + CoreFoundation, + "-framework", + Foundation, + "-framework", + AVFoundation, + "-framework", + CoreMedia, + "-framework", + CoreVideo, + "-framework", + CoreAudio, + "-framework", + AudioToolbox, + "-framework", + OpenGLES, + "-framework", + AssetsLibrary, + "-framework", + QuartzCore, + "-framework", + AssetsLibrary, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + AD2B8816198D631B0070367B /* Build configuration list for PBXProject "GstPlay" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AD2B884E198D631B0070367B /* Debug */, + AD2B884F198D631B0070367B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AD2B8850198D631B0070367B /* Build configuration list for PBXNativeTarget "GstPlay" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AD2B8851198D631B0070367B /* Debug */, + AD2B8852198D631B0070367B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = AD2B8813198D631B0070367B /* Project object */; +} diff --git a/playback/player/ios/GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/playback/player/ios/GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..955a731 --- /dev/null +++ b/playback/player/ios/GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/GstPlay.xcscheme b/playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/GstPlay.xcscheme new file mode 100644 index 0000000..c536703 --- /dev/null +++ b/playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/GstPlay.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/xcschememanagement.plist b/playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..c980ecf --- /dev/null +++ b/playback/player/ios/GstPlay.xcodeproj/xcuserdata/slomo.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + GstPlay.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + AD2B881A198D631B0070367B + + primary + + + AD2B883E198D631B0070367B + + primary + + + + + diff --git a/playback/player/ios/GstPlay/AppDelegate.h b/playback/player/ios/GstPlay/AppDelegate.h new file mode 100644 index 0000000..767a22d --- /dev/null +++ b/playback/player/ios/GstPlay/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// GstPlay +// +// Created by Sebastian Dröge on 02/08/14. +// Copyright (c) 2014 Sebastian Dröge. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/playback/player/ios/GstPlay/AppDelegate.m b/playback/player/ios/GstPlay/AppDelegate.m new file mode 100644 index 0000000..cb500b2 --- /dev/null +++ b/playback/player/ios/GstPlay/AppDelegate.m @@ -0,0 +1,45 @@ +// +// AppDelegate.m +// GstPlay +// +// Created by Sebastian Dröge on 02/08/14. +// Copyright (c) 2014 Sebastian Dröge. All rights reserved. +// + +#import "AppDelegate.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/playback/player/ios/GstPlay/EaglUIVIew.h b/playback/player/ios/GstPlay/EaglUIVIew.h new file mode 100644 index 0000000..ac4e798 --- /dev/null +++ b/playback/player/ios/GstPlay/EaglUIVIew.h @@ -0,0 +1,11 @@ +#import +#import +#include +#include + +@interface EaglUIView : UIView +{ +} + +@end + diff --git a/playback/player/ios/GstPlay/EaglUIVIew.m b/playback/player/ios/GstPlay/EaglUIVIew.m new file mode 100644 index 0000000..91cdd9d --- /dev/null +++ b/playback/player/ios/GstPlay/EaglUIVIew.m @@ -0,0 +1,13 @@ +#import "EaglUIVIew.h" + +#import + +@implementation EaglUIView + + ++ (Class) layerClass +{ + return [CAEAGLLayer class]; +} + +@end diff --git a/playback/player/ios/GstPlay/GstPlay-Info.plist b/playback/player/ios/GstPlay/GstPlay-Info.plist new file mode 100644 index 0000000..180da25 --- /dev/null +++ b/playback/player/ios/GstPlay/GstPlay-Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.freedesktop.gstreamer.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIMainStoryboardFile + MainStoryboard_iPhone + UIMainStoryboardFile~ipad + MainStoryboard_iPad + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/playback/player/ios/GstPlay/GstPlay-Prefix.pch b/playback/player/ios/GstPlay/GstPlay-Prefix.pch new file mode 100644 index 0000000..743435c --- /dev/null +++ b/playback/player/ios/GstPlay/GstPlay-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iOS SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/playback/player/ios/GstPlay/LibraryViewController.h b/playback/player/ios/GstPlay/LibraryViewController.h new file mode 100644 index 0000000..6950b19 --- /dev/null +++ b/playback/player/ios/GstPlay/LibraryViewController.h @@ -0,0 +1,12 @@ +#import + +@interface LibraryViewController : UITableViewController +{ + NSArray *libraryEntries; + NSArray *mediaEntries; + NSArray *onlineEntries; +} + +- (IBAction)refresh:(id)sender; + +@end diff --git a/playback/player/ios/GstPlay/LibraryViewController.m b/playback/player/ios/GstPlay/LibraryViewController.m new file mode 100644 index 0000000..f1aead5 --- /dev/null +++ b/playback/player/ios/GstPlay/LibraryViewController.m @@ -0,0 +1,165 @@ +#import "LibraryViewController.h" +#import "VideoViewController.h" +#import + +@interface LibraryViewController () + +@end + +@implementation LibraryViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [super setTitle:@"Library"]; + [self refreshMediaItems]; +} + +- (IBAction)refresh:(id)sender +{ + [self refreshMediaItems]; + [self.tableView reloadData]; +} + +static NSString *CellIdentifier = @"CellIdentifier"; + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 3; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + switch (section) + { + case 0: return @"Photo library"; + case 1: return @"iTunes file sharing"; + default: return @"Online files"; + } +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + switch (section) { + case 0: + return [self->libraryEntries count]; + case 1: + return [self->mediaEntries count]; + case 2: + return [self->onlineEntries count]; + default: + return 0; + } +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + // Configure Cell + UILabel *title = (UILabel *)[cell.contentView viewWithTag:10]; + UILabel *subtitle = (UILabel *)[cell.contentView viewWithTag:11]; + + switch (indexPath.section) { + case 0: subtitle.text = [self->libraryEntries objectAtIndex:indexPath.item]; + break; + case 1: subtitle.text = [self->mediaEntries objectAtIndex:indexPath.item]; + break; + case 2: subtitle.text = [self->onlineEntries objectAtIndex:indexPath.item]; + break; + default: + break; + } + + NSArray *components = [subtitle.text pathComponents]; + title.text = components.lastObject; + + return cell; +} + +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + return NO; +} + +- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { + return NO; +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + if ([segue.identifier isEqualToString:@"playVideo"]) { + NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; + VideoViewController *destViewController = segue.destinationViewController; + UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath]; + UILabel *label = (UILabel *)[cell.contentView viewWithTag:10]; + destViewController.title = label.text; + label = (UILabel *)[cell.contentView viewWithTag:11]; + destViewController.uri = label.text; + } +} + +- (void)refreshMediaItems { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSAllDomainsMask, YES); + NSString *docsPath = [paths objectAtIndex:0]; + + /* Entries from the Photo Library */ + NSMutableArray *entries = [[NSMutableArray alloc] init]; + ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; + [library enumerateGroupsWithTypes:ALAssetsGroupAll + usingBlock:^(ALAssetsGroup *group, BOOL *stop) + { + if (group) { + [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) + { + if(result) { + [entries addObject:[NSString stringWithFormat:@"%@",[result valueForProperty:ALAssetPropertyAssetURL]]]; + *stop = NO; + + } + }]; + } else { + [self.tableView reloadData]; + } + } + failureBlock:^(NSError *error) + { + NSLog(@"ERROR"); + } + ]; + self->libraryEntries = entries; + + /* Retrieve entries from iTunes file sharing */ + entries = [[NSMutableArray alloc] init]; + for (NSString *e in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:nil]) + { + [entries addObject:[NSString stringWithFormat:@"file://%@/%@", docsPath, e]]; + } + self->mediaEntries = entries; + + /* Hardcoded list of Online media files */ + entries = [[NSMutableArray alloc] init]; + + // Big Buck Bunny + [entries addObject:@"http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi"]; + [entries addObject:@"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov"]; + [entries addObject:@"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg"]; + [entries addObject:@"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.avi"]; + + // Sintel + [entries addObject:@"http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/Sintel_Trailer1.480p.DivX_Plus_HD.mkv"]; + [entries addObject:@"http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.mp4"]; + [entries addObject:@"http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.ogv"]; + [entries addObject:@"http://mirrorblender.top-ix.org/movies/sintel-1024-surround.mp4"]; + + // Tears of Steel + [entries addObject:@"http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mkv"]; + [entries addObject:@"http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mov"]; + [entries addObject:@"http://media.xiph.org/mango/tears_of_steel_1080p.webm"]; + + // Radio stations + [entries addObject:@"http://radio.hbr1.com:19800/trance.ogg"]; + [entries addObject:@"http://radio.hbr1.com:19800/tronic.aac"]; + + // Non-existing entries (to debug error reporting facilities) + [entries addObject:@"http://non-existing.org/Non_Existing_Server"]; + [entries addObject:@"http://docs.gstreamer.com/Non_Existing_File"]; + + self->onlineEntries = entries; +} + +@end diff --git a/playback/player/ios/GstPlay/MainStoryboard_iPad.storyboard b/playback/player/ios/GstPlay/MainStoryboard_iPad.storyboard new file mode 100644 index 0000000..d1ea519 --- /dev/null +++ b/playback/player/ios/GstPlay/MainStoryboard_iPad.storyboard @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/ios/GstPlay/MainStoryboard_iPhone.storyboard b/playback/player/ios/GstPlay/MainStoryboard_iPhone.storyboard new file mode 100644 index 0000000..8f43065 --- /dev/null +++ b/playback/player/ios/GstPlay/MainStoryboard_iPhone.storyboard @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/ios/GstPlay/Ubuntu-R.ttf b/playback/player/ios/GstPlay/Ubuntu-R.ttf new file mode 100644 index 0000000..45a038b Binary files /dev/null and b/playback/player/ios/GstPlay/Ubuntu-R.ttf differ diff --git a/playback/player/ios/GstPlay/VideoViewController.h b/playback/player/ios/GstPlay/VideoViewController.h new file mode 100644 index 0000000..97ee6e7 --- /dev/null +++ b/playback/player/ios/GstPlay/VideoViewController.h @@ -0,0 +1,23 @@ +#import + +@interface VideoViewController : UIViewController { + IBOutlet UIBarButtonItem *play_button; + IBOutlet UIBarButtonItem *pause_button; + IBOutlet UIView *video_view; + IBOutlet UIView *video_container_view; + IBOutlet NSLayoutConstraint *video_width_constraint; + IBOutlet NSLayoutConstraint *video_height_constraint; + IBOutlet UIToolbar *toolbar; + IBOutlet UITextField *time_label; + IBOutlet UISlider *time_slider; +} + +@property (retain,nonatomic) NSString *uri; + +-(IBAction) play:(id)sender; +-(IBAction) pause:(id)sender; +-(IBAction) sliderValueChanged:(id)sender; +-(IBAction) sliderTouchDown:(id)sender; +-(IBAction) sliderTouchUp:(id)sender; + +@end diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m new file mode 100644 index 0000000..7863f90 --- /dev/null +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -0,0 +1,204 @@ +#import "VideoViewController.h" +#import +#import + +@interface VideoViewController () { + GstPlayer *player; + int media_width; /* Width of the clip */ + int media_height; /* height ofthe clip */ + Boolean dragging_slider; /* Whether the time slider is being dragged or not */ + Boolean is_local_media; /* Whether this clip is stored locally or is being streamed */ + Boolean is_playing_desired; /* Whether the user asked to go to PLAYING */ +} + +@end + +@implementation VideoViewController + +@synthesize uri; + +/* + * Private methods + */ + +/* The text widget acts as an slave for the seek bar, so it reflects what the seek bar shows, whether + * it is an actual pipeline position or the position the user is currently dragging to. */ +- (void) updateTimeWidget +{ + NSInteger position = time_slider.value / 1000; + NSInteger duration = time_slider.maximumValue / 1000; + NSString *position_txt = @" -- "; + NSString *duration_txt = @" -- "; + + if (duration > 0) { + NSUInteger hours = duration / (60 * 60); + NSUInteger minutes = (duration / 60) % 60; + NSUInteger seconds = duration % 60; + + duration_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds]; + } + if (position > 0) { + NSUInteger hours = position / (60 * 60); + NSUInteger minutes = (position / 60) % 60; + NSUInteger seconds = position % 60; + + position_txt = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds]; + } + + NSString *text = [NSString stringWithFormat:@"%@ / %@", + position_txt, duration_txt]; + + time_label.text = text; +} + +/* + * Methods from UIViewController + */ + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + /* As soon as the GStreamer backend knows the real values, these ones will be replaced */ + media_width = 320; + media_height = 240; + + player = gst_player_new(FALSE); + g_object_set (player, "window-handle", video_view, NULL); + g_object_set (player, "uri", [uri UTF8String], NULL); + + gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE); + + g_signal_connect (player, "position-updated", G_CALLBACK (position_updated), (__bridge gpointer) self); + g_signal_connect (player, "duration-changed", G_CALLBACK (duration_changed), (__bridge gpointer) self); + g_signal_connect (player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed), (__bridge gpointer) self); + + is_local_media = [uri hasPrefix:@"file://"]; + is_playing_desired = NO; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + if (player) + { + gst_object_unref (player); + } + [UIApplication sharedApplication].idleTimerDisabled = NO; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* Called when the Play button is pressed */ +-(IBAction) play:(id)sender +{ + gst_player_play (player); + is_playing_desired = YES; + [UIApplication sharedApplication].idleTimerDisabled = YES; +} + +/* Called when the Pause button is pressed */ +-(IBAction) pause:(id)sender +{ + gst_player_pause(player); + is_playing_desired = NO; + [UIApplication sharedApplication].idleTimerDisabled = NO; +} + +/* Called when the time slider position has changed, either because the user dragged it or + * we programmatically changed its position. dragging_slider tells us which one happened */ +- (IBAction)sliderValueChanged:(id)sender { + if (!dragging_slider) return; + // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved. + if (is_local_media) + gst_player_seek (player, ((long)time_slider.value) * 1000000); + [self updateTimeWidget]; +} + +/* Called when the user starts to drag the time slider */ +- (IBAction)sliderTouchDown:(id)sender { + gst_player_pause (player); + dragging_slider = YES; +} + +/* Called when the user stops dragging the time slider */ +- (IBAction)sliderTouchUp:(id)sender { + dragging_slider = NO; + // If this is a remote file, scrub seeking is probably not going to work smoothly enough. + // Therefore, perform only the seek when the slider is released. + if (!is_local_media) + gst_player_seek (player, ((long)time_slider.value) * 1000000); + if (is_playing_desired) + gst_player_play (player); +} + +/* Called when the size of the main view has changed, so we can + * resize the sub-views in ways not allowed by storyboarding. */ +- (void)viewDidLayoutSubviews +{ + CGFloat view_width = video_container_view.bounds.size.width; + CGFloat view_height = video_container_view.bounds.size.height; + + CGFloat correct_height = view_width * media_height / media_width; + CGFloat correct_width = view_height * media_width / media_height; + + if (correct_height < view_height) { + video_height_constraint.constant = correct_height; + video_width_constraint.constant = view_width; + } else { + video_width_constraint.constant = correct_width; + video_height_constraint.constant = view_height; + } + + time_slider.frame = CGRectMake(time_slider.frame.origin.x, time_slider.frame.origin.y, toolbar.frame.size.width - time_slider.frame.origin.x - 8, time_slider.frame.size.height); +} + +static void video_dimensions_changed (GstPlayer * unused, gint width, gint height, VideoViewController * self) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self videoDimensionsChanged:width height:height]; + }); +} + +-(void) videoDimensionsChanged:(NSInteger)width height:(NSInteger)height +{ + media_width = width; + media_height = height; + [self viewDidLayoutSubviews]; + [video_view setNeedsLayout]; + [video_view layoutIfNeeded]; +} + +static void position_updated (GstPlayer * unused, GstClockTime position, VideoViewController *self) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self positionUpdated:(int) (position / 1000000)]; + }); +} + +-(void) positionUpdated:(NSInteger)position +{ + /* Ignore messages from the pipeline if the time sliders is being dragged */ + if (dragging_slider) return; + + time_slider.value = position; + [self updateTimeWidget]; +} + +static void duration_changed (GstPlayer * unused, GstClockTime duration, VideoViewController *self) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self durationChanged:(int) (duration / 1000000)]; + }); +} + +-(void) durationChanged:(NSInteger)duration +{ + time_slider.maximumValue = duration; + [self updateTimeWidget]; +} + +@end diff --git a/playback/player/ios/GstPlay/en.lproj/InfoPlist.strings b/playback/player/ios/GstPlay/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/playback/player/ios/GstPlay/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/playback/player/ios/GstPlay/fonts.conf b/playback/player/ios/GstPlay/fonts.conf new file mode 100644 index 0000000..6b780ea --- /dev/null +++ b/playback/player/ios/GstPlay/fonts.conf @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + mono + + + monospace + + + + + + + sans serif + + + sans-serif + + + + + + + sans + + + sans-serif + + + + + + + 0x0020 + 0x00A0 + 0x00AD + 0x034F + 0x0600 + 0x0601 + 0x0602 + 0x0603 + 0x06DD + 0x070F + 0x115F + 0x1160 + 0x1680 + 0x17B4 + 0x17B5 + 0x180E + 0x2000 + 0x2001 + 0x2002 + 0x2003 + 0x2004 + 0x2005 + 0x2006 + 0x2007 + 0x2008 + 0x2009 + 0x200A + 0x200B + 0x200C + 0x200D + 0x200E + 0x200F + 0x2028 + 0x2029 + 0x202A + 0x202B + 0x202C + 0x202D + 0x202E + 0x202F + 0x205F + 0x2060 + 0x2061 + 0x2062 + 0x2063 + 0x206A + 0x206B + 0x206C + 0x206D + 0x206E + 0x206F + 0x2800 + 0x3000 + 0x3164 + 0xFEFF + 0xFFA0 + 0xFFF9 + 0xFFFA + 0xFFFB + + + + 30 + + + + + diff --git a/playback/player/ios/GstPlay/gst_ios_init.h b/playback/player/ios/GstPlay/gst_ios_init.h new file mode 100644 index 0000000..a880bf6 --- /dev/null +++ b/playback/player/ios/GstPlay/gst_ios_init.h @@ -0,0 +1,39 @@ +#ifndef __GST_IOS_INIT_H__ +#define __GST_IOS_INIT_H__ + +#include + +G_BEGIN_DECLS + +#define GST_G_IO_MODULE_DECLARE(name) \ +extern void G_PASTE(g_io_module_, G_PASTE(name, _load_static)) (void) + +#define GST_G_IO_MODULE_LOAD(name) \ +G_PASTE(g_io_module_, G_PASTE(name, _load_static)) () + +/* Uncomment each line to enable the plugin categories that your application needs. + * You can also enable individual plugins. See gst_ios_init.c to see their names + */ + +#define GST_IOS_PLUGINS_CORE +//#define GST_IOS_PLUGINS_CAPTURE +#define GST_IOS_PLUGINS_CODECS_RESTRICTED +//#define GST_IOS_PLUGINS_ENCODING +#define GST_IOS_PLUGINS_CODECS_GPL +#define GST_IOS_PLUGINS_NET_RESTRICTED +#define GST_IOS_PLUGINS_SYS +#define GST_IOS_PLUGINS_VIS +#define GST_IOS_PLUGINS_PLAYBACK +#define GST_IOS_PLUGINS_EFFECTS +#define GST_IOS_PLUGINS_CODECS +#define GST_IOS_PLUGINS_NET +//#define GST_IOS_PLUGINS_EDITING + + +#define GST_IOS_GIO_MODULE_GNUTLS + +void gst_ios_init (); + +G_END_DECLS + +#endif diff --git a/playback/player/ios/GstPlay/gst_ios_init.m b/playback/player/ios/GstPlay/gst_ios_init.m new file mode 100644 index 0000000..403f9f9 --- /dev/null +++ b/playback/player/ios/GstPlay/gst_ios_init.m @@ -0,0 +1,988 @@ +#include "gst_ios_init.h" + +#if defined(GST_IOS_PLUGIN_COREELEMENTS) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(coreelements); +#endif +#if defined(GST_IOS_PLUGIN_ADDER) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(adder); +#endif +#if defined(GST_IOS_PLUGIN_APP) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(app); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOCONVERT) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(audioconvert); +#endif +#if defined(GST_IOS_PLUGIN_AUDIORATE) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(audiorate); +#endif +#if defined(GST_IOS_PLUGIN_AUDIORESAMPLE) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(audioresample); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOTESTSRC) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(audiotestsrc); +#endif +#if defined(GST_IOS_PLUGIN_GIO) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(gio); +#endif +#if defined(GST_IOS_PLUGIN_PANGO) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(pango); +#endif +#if defined(GST_IOS_PLUGIN_TYPEFINDFUNCTIONS) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(typefindfunctions); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOCONVERT) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(videoconvert); +#endif +#if defined(GST_IOS_PLUGIN_VIDEORATE) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(videorate); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOSCALE) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(videoscale); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOTESTSRC) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(videotestsrc); +#endif +#if defined(GST_IOS_PLUGIN_VOLUME) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(volume); +#endif +#if defined(GST_IOS_PLUGIN_AUTODETECT) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(autodetect); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOFILTER) || defined(GST_IOS_PLUGINS_CORE) +GST_PLUGIN_STATIC_DECLARE(videofilter); +#endif +#if defined(GST_IOS_PLUGIN_CAMERABIN) || defined(GST_IOS_PLUGINS_CAPTURE) +GST_PLUGIN_STATIC_DECLARE(camerabin); +#endif +#if defined(GST_IOS_PLUGIN_ASFMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(asfmux); +#endif +#if defined(GST_IOS_PLUGIN_DTSDEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(dtsdec); +#endif +#if defined(GST_IOS_PLUGIN_FAAD) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(faad); +#endif +#if defined(GST_IOS_PLUGIN_MPEGPSDEMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mpegpsdemux); +#endif +#if defined(GST_IOS_PLUGIN_MPEGPSMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mpegpsmux); +#endif +#if defined(GST_IOS_PLUGIN_MPEGTSDEMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mpegtsdemux); +#endif +#if defined(GST_IOS_PLUGIN_MPEGTSMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mpegtsmux); +#endif +#if defined(GST_IOS_PLUGIN_VOAACENC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(voaacenc); +#endif +#if defined(GST_IOS_PLUGIN_A52DEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(a52dec); +#endif +#if defined(GST_IOS_PLUGIN_AMRNB) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(amrnb); +#endif +#if defined(GST_IOS_PLUGIN_AMRWBDEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(amrwbdec); +#endif +#if defined(GST_IOS_PLUGIN_ASF) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(asf); +#endif +#if defined(GST_IOS_PLUGIN_DVDSUB) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(dvdsub); +#endif +#if defined(GST_IOS_PLUGIN_DVDLPCMDEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(dvdlpcmdec); +#endif +#if defined(GST_IOS_PLUGIN_MAD) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mad); +#endif +#if defined(GST_IOS_PLUGIN_MPEG2DEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mpeg2dec); +#endif +#if defined(GST_IOS_PLUGIN_XINGMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(xingmux); +#endif +#if defined(GST_IOS_PLUGIN_REALMEDIA) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(realmedia); +#endif +#if defined(GST_IOS_PLUGIN_X264) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(x264); +#endif +#if defined(GST_IOS_PLUGIN_LIBAV) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(libav); +#endif +#if defined(GST_IOS_PLUGIN_ENCODING) || defined(GST_IOS_PLUGINS_ENCODING) +GST_PLUGIN_STATIC_DECLARE(encoding); +#endif +#if defined(GST_IOS_PLUGIN_ASSRENDER) || defined(GST_IOS_PLUGINS_CODECS_GPL) +GST_PLUGIN_STATIC_DECLARE(assrender); +#endif +#if defined(GST_IOS_PLUGIN_MMS) || defined(GST_IOS_PLUGINS_NET_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mms); +#endif +#if defined(GST_IOS_PLUGIN_RTMP) || defined(GST_IOS_PLUGINS_NET_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(rtmp); +#endif +#if defined(GST_IOS_PLUGIN_OSXAUDIO) || defined(GST_IOS_PLUGINS_SYS) +GST_PLUGIN_STATIC_DECLARE(osxaudio); +#endif +#if defined(GST_IOS_PLUGIN_APPLEMEDIA) || defined(GST_IOS_PLUGINS_SYS) +GST_PLUGIN_STATIC_DECLARE(applemedia); +#endif +#if defined(GST_IOS_PLUGIN_SHM) || defined(GST_IOS_PLUGINS_SYS) +GST_PLUGIN_STATIC_DECLARE(shm); +#endif +#if defined(GST_IOS_PLUGIN_OPENGL) || defined(GST_IOS_PLUGINS_SYS) +GST_PLUGIN_STATIC_DECLARE(opengl); +#endif +#if defined(GST_IOS_PLUGIN_LIBVISUAL) || defined(GST_IOS_PLUGINS_VIS) +GST_PLUGIN_STATIC_DECLARE(libvisual); +#endif +#if defined(GST_IOS_PLUGIN_GOOM) || defined(GST_IOS_PLUGINS_VIS) +GST_PLUGIN_STATIC_DECLARE(goom); +#endif +#if defined(GST_IOS_PLUGIN_GOOM2K1) || defined(GST_IOS_PLUGINS_VIS) +GST_PLUGIN_STATIC_DECLARE(goom2k1); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOVISUALIZERS) || defined(GST_IOS_PLUGINS_VIS) +GST_PLUGIN_STATIC_DECLARE(audiovisualizers); +#endif +#if defined(GST_IOS_PLUGIN_PLAYBACK) || defined(GST_IOS_PLUGINS_PLAYBACK) +GST_PLUGIN_STATIC_DECLARE(playback); +#endif +#if defined(GST_IOS_PLUGIN_ALPHA) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(alpha); +#endif +#if defined(GST_IOS_PLUGIN_ALPHACOLOR) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(alphacolor); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOFX) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(audiofx); +#endif +#if defined(GST_IOS_PLUGIN_CAIRO) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(cairo); +#endif +#if defined(GST_IOS_PLUGIN_CUTTER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(cutter); +#endif +#if defined(GST_IOS_PLUGIN_DEBUG) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(debug); +#endif +#if defined(GST_IOS_PLUGIN_DEINTERLACE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(deinterlace); +#endif +#if defined(GST_IOS_PLUGIN_DTMF) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(dtmf); +#endif +#if defined(GST_IOS_PLUGIN_EFFECTV) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(effectv); +#endif +#if defined(GST_IOS_PLUGIN_EQUALIZER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(equalizer); +#endif +#if defined(GST_IOS_PLUGIN_GDKPIXBUF) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(gdkpixbuf); +#endif +#if defined(GST_IOS_PLUGIN_IMAGEFREEZE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(imagefreeze); +#endif +#if defined(GST_IOS_PLUGIN_INTERLEAVE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(interleave); +#endif +#if defined(GST_IOS_PLUGIN_LEVEL) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(level); +#endif +#if defined(GST_IOS_PLUGIN_MULTIFILE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(multifile); +#endif +#if defined(GST_IOS_PLUGIN_REPLAYGAIN) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(replaygain); +#endif +#if defined(GST_IOS_PLUGIN_SHAPEWIPE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(shapewipe); +#endif +#if defined(GST_IOS_PLUGIN_SMPTE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(smpte); +#endif +#if defined(GST_IOS_PLUGIN_SPECTRUM) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(spectrum); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOBOX) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(videobox); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOCROP) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(videocrop); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOMIXER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(videomixer); +#endif +#if defined(GST_IOS_PLUGIN_ACCURIP) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(accurip); +#endif +#if defined(GST_IOS_PLUGIN_AIFF) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(aiff); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOFXBAD) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(audiofxbad); +#endif +#if defined(GST_IOS_PLUGIN_AUTOCONVERT) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(autoconvert); +#endif +#if defined(GST_IOS_PLUGIN_BAYER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(bayer); +#endif +#if defined(GST_IOS_PLUGIN_COLOREFFECTS) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(coloreffects); +#endif +#if defined(GST_IOS_PLUGIN_DEBUGUTILSBAD) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(debugutilsbad); +#endif +#if defined(GST_IOS_PLUGIN_FIELDANALYSIS) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(fieldanalysis); +#endif +#if defined(GST_IOS_PLUGIN_FREEVERB) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(freeverb); +#endif +#if defined(GST_IOS_PLUGIN_FREI0R) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(frei0r); +#endif +#if defined(GST_IOS_PLUGIN_GAUDIEFFECTS) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(gaudieffects); +#endif +#if defined(GST_IOS_PLUGIN_GEOMETRICTRANSFORM) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(geometrictransform); +#endif +#if defined(GST_IOS_PLUGIN_INTERLACE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(interlace); +#endif +#if defined(GST_IOS_PLUGIN_IVTC) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(ivtc); +#endif +#if defined(GST_IOS_PLUGIN_LIVEADDER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(liveadder); +#endif +#if defined(GST_IOS_PLUGIN_RAWPARSE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(rawparse); +#endif +#if defined(GST_IOS_PLUGIN_REMOVESILENCE) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(removesilence); +#endif +#if defined(GST_IOS_PLUGIN_SEGMENTCLIP) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(segmentclip); +#endif +#if defined(GST_IOS_PLUGIN_SMOOTH) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(smooth); +#endif +#if defined(GST_IOS_PLUGIN_SPEED) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(speed); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOFILTERSBAD) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(videofiltersbad); +#endif +#if defined(GST_IOS_PLUGIN_SUBPARSE) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(subparse); +#endif +#if defined(GST_IOS_PLUGIN_OGG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(ogg); +#endif +#if defined(GST_IOS_PLUGIN_THEORA) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(theora); +#endif +#if defined(GST_IOS_PLUGIN_VORBIS) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(vorbis); +#endif +#if defined(GST_IOS_PLUGIN_IVORBISDEC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(ivorbisdec); +#endif +#if defined(GST_IOS_PLUGIN_ALAW) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(alaw); +#endif +#if defined(GST_IOS_PLUGIN_APETAG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(apetag); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOPARSERS) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(audioparsers); +#endif +#if defined(GST_IOS_PLUGIN_AUPARSE) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(auparse); +#endif +#if defined(GST_IOS_PLUGIN_AVI) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(avi); +#endif +#if defined(GST_IOS_PLUGIN_DV) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(dv); +#endif +#if defined(GST_IOS_PLUGIN_FLAC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(flac); +#endif +#if defined(GST_IOS_PLUGIN_FLV) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(flv); +#endif +#if defined(GST_IOS_PLUGIN_FLXDEC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(flxdec); +#endif +#if defined(GST_IOS_PLUGIN_ICYDEMUX) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(icydemux); +#endif +#if defined(GST_IOS_PLUGIN_ID3DEMUX) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(id3demux); +#endif +#if defined(GST_IOS_PLUGIN_ISOMP4) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(isomp4); +#endif +#if defined(GST_IOS_PLUGIN_JPEG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(jpeg); +#endif +#if defined(GST_IOS_PLUGIN_MATROSKA) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(matroska); +#endif +#if defined(GST_IOS_PLUGIN_MULAW) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(mulaw); +#endif +#if defined(GST_IOS_PLUGIN_MULTIPART) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(multipart); +#endif +#if defined(GST_IOS_PLUGIN_PNG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(png); +#endif +#if defined(GST_IOS_PLUGIN_SPEEX) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(speex); +#endif +#if defined(GST_IOS_PLUGIN_TAGLIB) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(taglib); +#endif +#if defined(GST_IOS_PLUGIN_VPX) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(vpx); +#endif +#if defined(GST_IOS_PLUGIN_WAVENC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(wavenc); +#endif +#if defined(GST_IOS_PLUGIN_WAVPACK) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(wavpack); +#endif +#if defined(GST_IOS_PLUGIN_WAVPARSE) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(wavparse); +#endif +#if defined(GST_IOS_PLUGIN_Y4MENC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(y4menc); +#endif +#if defined(GST_IOS_PLUGIN_ADPCMDEC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(adpcmdec); +#endif +#if defined(GST_IOS_PLUGIN_ADPCMENC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(adpcmenc); +#endif +#if defined(GST_IOS_PLUGIN_DASHDEMUX) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(dashdemux); +#endif +#if defined(GST_IOS_PLUGIN_DVBSUBOVERLAY) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(dvbsuboverlay); +#endif +#if defined(GST_IOS_PLUGIN_DVDSPU) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(dvdspu); +#endif +#if defined(GST_IOS_PLUGIN_FRAGMENTED) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(fragmented); +#endif +#if defined(GST_IOS_PLUGIN_ID3TAG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(id3tag); +#endif +#if defined(GST_IOS_PLUGIN_KATE) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(kate); +#endif +#if defined(GST_IOS_PLUGIN_MIDI) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(midi); +#endif +#if defined(GST_IOS_PLUGIN_MXF) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(mxf); +#endif +#if defined(GST_IOS_PLUGIN_OPUS) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(opus); +#endif +#if defined(GST_IOS_PLUGIN_PCAPPARSE) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(pcapparse); +#endif +#if defined(GST_IOS_PLUGIN_PNM) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(pnm); +#endif +#if defined(GST_IOS_PLUGIN_RFBSRC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(rfbsrc); +#endif +#if defined(GST_IOS_PLUGIN_SCHRO) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(schro); +#endif +#if defined(GST_IOS_PLUGIN_GSTSIREN) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(gstsiren); +#endif +#if defined(GST_IOS_PLUGIN_SMOOTHSTREAMING) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(smoothstreaming); +#endif +#if defined(GST_IOS_PLUGIN_SUBENC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(subenc); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOPARSERSBAD) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(videoparsersbad); +#endif +#if defined(GST_IOS_PLUGIN_Y4MDEC) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(y4mdec); +#endif +#if defined(GST_IOS_PLUGIN_JPEGFORMAT) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(jpegformat); +#endif +#if defined(GST_IOS_PLUGIN_GDP) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(gdp); +#endif +#if defined(GST_IOS_PLUGIN_RSVG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(rsvg); +#endif +#if defined(GST_IOS_PLUGIN_TCP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(tcp); +#endif +#if defined(GST_IOS_PLUGIN_RTSP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(rtsp); +#endif +#if defined(GST_IOS_PLUGIN_RTP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(rtp); +#endif +#if defined(GST_IOS_PLUGIN_RTPMANAGER) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(rtpmanager); +#endif +#if defined(GST_IOS_PLUGIN_SOUP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(soup); +#endif +#if defined(GST_IOS_PLUGIN_UDP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(udp); +#endif +#if defined(GST_IOS_PLUGIN_DATAURISRC) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(dataurisrc); +#endif +#if defined(GST_IOS_PLUGIN_SDP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(sdp); +#endif +#if defined(GST_IOS_PLUGIN_GNONLIN) || defined(GST_IOS_PLUGINS_EDITING) +GST_PLUGIN_STATIC_DECLARE(gnonlin); +#endif + +#if defined(GST_IOS_GIO_MODULE_GNUTLS) + #include + GST_G_IO_MODULE_DECLARE(gnutls); +#endif + +void +gst_ios_init (void) +{ + GstPluginFeature *plugin; + GstRegistry *reg; + NSString *resources = [[NSBundle mainBundle] resourcePath]; + NSString *tmp = NSTemporaryDirectory(); + NSString *cache = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"]; + NSString *docs = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; + + const gchar *resources_dir = [resources UTF8String]; + const gchar *tmp_dir = [tmp UTF8String]; + const gchar *cache_dir = [cache UTF8String]; + const gchar *docs_dir = [docs UTF8String]; + gchar *ca_certificates; + + g_setenv ("TMP", tmp_dir, TRUE); + g_setenv ("TEMP", tmp_dir, TRUE); + g_setenv ("TMPDIR", tmp_dir, TRUE); + g_setenv ("XDG_RUNTIME_DIR", resources_dir, TRUE); + g_setenv ("XDG_CACHE_HOME", cache_dir, TRUE); + + g_setenv ("HOME", docs_dir, TRUE); + g_setenv ("XDG_DATA_DIRS", resources_dir, TRUE); + g_setenv ("XDG_CONFIG_DIRS", resources_dir, TRUE); + g_setenv ("XDG_CONFIG_HOME", cache_dir, TRUE); + g_setenv ("XDG_DATA_HOME", resources_dir, TRUE); + g_setenv ("FONTCONFIG_PATH", resources_dir, TRUE); + + ca_certificates = g_build_filename (resources_dir, "ssl", "certs", "ca-certifcates.crt", NULL); + g_setenv ("CA_CERTIFICATES", ca_certificates, TRUE); + g_free (ca_certificates); + + gst_init (NULL, NULL); + + #if defined(GST_IOS_PLUGIN_COREELEMENTS) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(coreelements); +#endif +#if defined(GST_IOS_PLUGIN_ADDER) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(adder); +#endif +#if defined(GST_IOS_PLUGIN_APP) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(app); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOCONVERT) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(audioconvert); +#endif +#if defined(GST_IOS_PLUGIN_AUDIORATE) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(audiorate); +#endif +#if defined(GST_IOS_PLUGIN_AUDIORESAMPLE) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(audioresample); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOTESTSRC) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(audiotestsrc); +#endif +#if defined(GST_IOS_PLUGIN_GIO) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(gio); +#endif +#if defined(GST_IOS_PLUGIN_PANGO) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(pango); +#endif +#if defined(GST_IOS_PLUGIN_TYPEFINDFUNCTIONS) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(typefindfunctions); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOCONVERT) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(videoconvert); +#endif +#if defined(GST_IOS_PLUGIN_VIDEORATE) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(videorate); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOSCALE) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(videoscale); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOTESTSRC) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(videotestsrc); +#endif +#if defined(GST_IOS_PLUGIN_VOLUME) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(volume); +#endif +#if defined(GST_IOS_PLUGIN_AUTODETECT) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(autodetect); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOFILTER) || defined(GST_IOS_PLUGINS_CORE) + GST_PLUGIN_STATIC_REGISTER(videofilter); +#endif +#if defined(GST_IOS_PLUGIN_CAMERABIN) || defined(GST_IOS_PLUGINS_CAPTURE) + GST_PLUGIN_STATIC_REGISTER(camerabin); +#endif +#if defined(GST_IOS_PLUGIN_ASFMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(asfmux); +#endif +#if defined(GST_IOS_PLUGIN_DTSDEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(dtsdec); +#endif +#if defined(GST_IOS_PLUGIN_FAAD) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(faad); +#endif +#if defined(GST_IOS_PLUGIN_MPEGPSDEMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mpegpsdemux); +#endif +#if defined(GST_IOS_PLUGIN_MPEGPSMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mpegpsmux); +#endif +#if defined(GST_IOS_PLUGIN_MPEGTSDEMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mpegtsdemux); +#endif +#if defined(GST_IOS_PLUGIN_MPEGTSMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mpegtsmux); +#endif +#if defined(GST_IOS_PLUGIN_VOAACENC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(voaacenc); +#endif +#if defined(GST_IOS_PLUGIN_A52DEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(a52dec); +#endif +#if defined(GST_IOS_PLUGIN_AMRNB) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(amrnb); +#endif +#if defined(GST_IOS_PLUGIN_AMRWBDEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(amrwbdec); +#endif +#if defined(GST_IOS_PLUGIN_ASF) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(asf); +#endif +#if defined(GST_IOS_PLUGIN_DVDSUB) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(dvdsub); +#endif +#if defined(GST_IOS_PLUGIN_DVDLPCMDEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(dvdlpcmdec); +#endif +#if defined(GST_IOS_PLUGIN_MAD) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mad); +#endif +#if defined(GST_IOS_PLUGIN_MPEG2DEC) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mpeg2dec); +#endif +#if defined(GST_IOS_PLUGIN_XINGMUX) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(xingmux); +#endif +#if defined(GST_IOS_PLUGIN_REALMEDIA) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(realmedia); +#endif +#if defined(GST_IOS_PLUGIN_X264) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(x264); +#endif +#if defined(GST_IOS_PLUGIN_LIBAV) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(libav); +#endif +#if defined(GST_IOS_PLUGIN_ENCODING) || defined(GST_IOS_PLUGINS_ENCODING) + GST_PLUGIN_STATIC_REGISTER(encoding); +#endif +#if defined(GST_IOS_PLUGIN_ASSRENDER) || defined(GST_IOS_PLUGINS_CODECS_GPL) + GST_PLUGIN_STATIC_REGISTER(assrender); +#endif +#if defined(GST_IOS_PLUGIN_MMS) || defined(GST_IOS_PLUGINS_NET_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mms); +#endif +#if defined(GST_IOS_PLUGIN_RTMP) || defined(GST_IOS_PLUGINS_NET_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(rtmp); +#endif +#if defined(GST_IOS_PLUGIN_OSXAUDIO) || defined(GST_IOS_PLUGINS_SYS) + GST_PLUGIN_STATIC_REGISTER(osxaudio); +#endif +#if defined(GST_IOS_PLUGIN_APPLEMEDIA) || defined(GST_IOS_PLUGINS_SYS) + GST_PLUGIN_STATIC_REGISTER(applemedia); +#endif +#if defined(GST_IOS_PLUGIN_SHM) || defined(GST_IOS_PLUGINS_SYS) + GST_PLUGIN_STATIC_REGISTER(shm); +#endif +#if defined(GST_IOS_PLUGIN_OPENGL) || defined(GST_IOS_PLUGINS_SYS) + GST_PLUGIN_STATIC_REGISTER(opengl); +#endif +#if defined(GST_IOS_PLUGIN_LIBVISUAL) || defined(GST_IOS_PLUGINS_VIS) + GST_PLUGIN_STATIC_REGISTER(libvisual); +#endif +#if defined(GST_IOS_PLUGIN_GOOM) || defined(GST_IOS_PLUGINS_VIS) + GST_PLUGIN_STATIC_REGISTER(goom); +#endif +#if defined(GST_IOS_PLUGIN_GOOM2K1) || defined(GST_IOS_PLUGINS_VIS) + GST_PLUGIN_STATIC_REGISTER(goom2k1); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOVISUALIZERS) || defined(GST_IOS_PLUGINS_VIS) + GST_PLUGIN_STATIC_REGISTER(audiovisualizers); +#endif +#if defined(GST_IOS_PLUGIN_PLAYBACK) || defined(GST_IOS_PLUGINS_PLAYBACK) + GST_PLUGIN_STATIC_REGISTER(playback); +#endif +#if defined(GST_IOS_PLUGIN_ALPHA) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(alpha); +#endif +#if defined(GST_IOS_PLUGIN_ALPHACOLOR) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(alphacolor); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOFX) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(audiofx); +#endif +#if defined(GST_IOS_PLUGIN_CAIRO) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(cairo); +#endif +#if defined(GST_IOS_PLUGIN_CUTTER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(cutter); +#endif +#if defined(GST_IOS_PLUGIN_DEBUG) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(debug); +#endif +#if defined(GST_IOS_PLUGIN_DEINTERLACE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(deinterlace); +#endif +#if defined(GST_IOS_PLUGIN_DTMF) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(dtmf); +#endif +#if defined(GST_IOS_PLUGIN_EFFECTV) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(effectv); +#endif +#if defined(GST_IOS_PLUGIN_EQUALIZER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(equalizer); +#endif +#if defined(GST_IOS_PLUGIN_GDKPIXBUF) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(gdkpixbuf); +#endif +#if defined(GST_IOS_PLUGIN_IMAGEFREEZE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(imagefreeze); +#endif +#if defined(GST_IOS_PLUGIN_INTERLEAVE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(interleave); +#endif +#if defined(GST_IOS_PLUGIN_LEVEL) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(level); +#endif +#if defined(GST_IOS_PLUGIN_MULTIFILE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(multifile); +#endif +#if defined(GST_IOS_PLUGIN_REPLAYGAIN) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(replaygain); +#endif +#if defined(GST_IOS_PLUGIN_SHAPEWIPE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(shapewipe); +#endif +#if defined(GST_IOS_PLUGIN_SMPTE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(smpte); +#endif +#if defined(GST_IOS_PLUGIN_SPECTRUM) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(spectrum); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOBOX) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(videobox); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOCROP) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(videocrop); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOMIXER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(videomixer); +#endif +#if defined(GST_IOS_PLUGIN_ACCURIP) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(accurip); +#endif +#if defined(GST_IOS_PLUGIN_AIFF) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(aiff); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOFXBAD) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(audiofxbad); +#endif +#if defined(GST_IOS_PLUGIN_AUTOCONVERT) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(autoconvert); +#endif +#if defined(GST_IOS_PLUGIN_BAYER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(bayer); +#endif +#if defined(GST_IOS_PLUGIN_COLOREFFECTS) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(coloreffects); +#endif +#if defined(GST_IOS_PLUGIN_DEBUGUTILSBAD) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(debugutilsbad); +#endif +#if defined(GST_IOS_PLUGIN_FIELDANALYSIS) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(fieldanalysis); +#endif +#if defined(GST_IOS_PLUGIN_FREEVERB) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(freeverb); +#endif +#if defined(GST_IOS_PLUGIN_FREI0R) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(frei0r); +#endif +#if defined(GST_IOS_PLUGIN_GAUDIEFFECTS) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(gaudieffects); +#endif +#if defined(GST_IOS_PLUGIN_GEOMETRICTRANSFORM) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(geometrictransform); +#endif +#if defined(GST_IOS_PLUGIN_INTERLACE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(interlace); +#endif +#if defined(GST_IOS_PLUGIN_IVTC) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(ivtc); +#endif +#if defined(GST_IOS_PLUGIN_LIVEADDER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(liveadder); +#endif +#if defined(GST_IOS_PLUGIN_RAWPARSE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(rawparse); +#endif +#if defined(GST_IOS_PLUGIN_REMOVESILENCE) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(removesilence); +#endif +#if defined(GST_IOS_PLUGIN_SEGMENTCLIP) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(segmentclip); +#endif +#if defined(GST_IOS_PLUGIN_SMOOTH) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(smooth); +#endif +#if defined(GST_IOS_PLUGIN_SPEED) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(speed); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOFILTERSBAD) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(videofiltersbad); +#endif +#if defined(GST_IOS_PLUGIN_SUBPARSE) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(subparse); +#endif +#if defined(GST_IOS_PLUGIN_OGG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(ogg); +#endif +#if defined(GST_IOS_PLUGIN_THEORA) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(theora); +#endif +#if defined(GST_IOS_PLUGIN_VORBIS) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(vorbis); +#endif +#if defined(GST_IOS_PLUGIN_IVORBISDEC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(ivorbisdec); +#endif +#if defined(GST_IOS_PLUGIN_ALAW) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(alaw); +#endif +#if defined(GST_IOS_PLUGIN_APETAG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(apetag); +#endif +#if defined(GST_IOS_PLUGIN_AUDIOPARSERS) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(audioparsers); +#endif +#if defined(GST_IOS_PLUGIN_AUPARSE) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(auparse); +#endif +#if defined(GST_IOS_PLUGIN_AVI) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(avi); +#endif +#if defined(GST_IOS_PLUGIN_DV) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(dv); +#endif +#if defined(GST_IOS_PLUGIN_FLAC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(flac); +#endif +#if defined(GST_IOS_PLUGIN_FLV) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(flv); +#endif +#if defined(GST_IOS_PLUGIN_FLXDEC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(flxdec); +#endif +#if defined(GST_IOS_PLUGIN_ICYDEMUX) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(icydemux); +#endif +#if defined(GST_IOS_PLUGIN_ID3DEMUX) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(id3demux); +#endif +#if defined(GST_IOS_PLUGIN_ISOMP4) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(isomp4); +#endif +#if defined(GST_IOS_PLUGIN_JPEG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(jpeg); +#endif +#if defined(GST_IOS_PLUGIN_MATROSKA) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(matroska); +#endif +#if defined(GST_IOS_PLUGIN_MULAW) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(mulaw); +#endif +#if defined(GST_IOS_PLUGIN_MULTIPART) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(multipart); +#endif +#if defined(GST_IOS_PLUGIN_PNG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(png); +#endif +#if defined(GST_IOS_PLUGIN_SPEEX) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(speex); +#endif +#if defined(GST_IOS_PLUGIN_TAGLIB) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(taglib); +#endif +#if defined(GST_IOS_PLUGIN_VPX) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(vpx); +#endif +#if defined(GST_IOS_PLUGIN_WAVENC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(wavenc); +#endif +#if defined(GST_IOS_PLUGIN_WAVPACK) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(wavpack); +#endif +#if defined(GST_IOS_PLUGIN_WAVPARSE) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(wavparse); +#endif +#if defined(GST_IOS_PLUGIN_Y4MENC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(y4menc); +#endif +#if defined(GST_IOS_PLUGIN_ADPCMDEC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(adpcmdec); +#endif +#if defined(GST_IOS_PLUGIN_ADPCMENC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(adpcmenc); +#endif +#if defined(GST_IOS_PLUGIN_DASHDEMUX) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(dashdemux); +#endif +#if defined(GST_IOS_PLUGIN_DVBSUBOVERLAY) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(dvbsuboverlay); +#endif +#if defined(GST_IOS_PLUGIN_DVDSPU) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(dvdspu); +#endif +#if defined(GST_IOS_PLUGIN_FRAGMENTED) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(fragmented); +#endif +#if defined(GST_IOS_PLUGIN_ID3TAG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(id3tag); +#endif +#if defined(GST_IOS_PLUGIN_KATE) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(kate); +#endif +#if defined(GST_IOS_PLUGIN_MIDI) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(midi); +#endif +#if defined(GST_IOS_PLUGIN_MXF) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(mxf); +#endif +#if defined(GST_IOS_PLUGIN_OPUS) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(opus); +#endif +#if defined(GST_IOS_PLUGIN_PCAPPARSE) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(pcapparse); +#endif +#if defined(GST_IOS_PLUGIN_PNM) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(pnm); +#endif +#if defined(GST_IOS_PLUGIN_RFBSRC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(rfbsrc); +#endif +#if defined(GST_IOS_PLUGIN_SCHRO) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(schro); +#endif +#if defined(GST_IOS_PLUGIN_GSTSIREN) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(gstsiren); +#endif +#if defined(GST_IOS_PLUGIN_SMOOTHSTREAMING) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(smoothstreaming); +#endif +#if defined(GST_IOS_PLUGIN_SUBENC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(subenc); +#endif +#if defined(GST_IOS_PLUGIN_VIDEOPARSERSBAD) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(videoparsersbad); +#endif +#if defined(GST_IOS_PLUGIN_Y4MDEC) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(y4mdec); +#endif +#if defined(GST_IOS_PLUGIN_JPEGFORMAT) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(jpegformat); +#endif +#if defined(GST_IOS_PLUGIN_GDP) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(gdp); +#endif +#if defined(GST_IOS_PLUGIN_RSVG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(rsvg); +#endif +#if defined(GST_IOS_PLUGIN_TCP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(tcp); +#endif +#if defined(GST_IOS_PLUGIN_RTSP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(rtsp); +#endif +#if defined(GST_IOS_PLUGIN_RTP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(rtp); +#endif +#if defined(GST_IOS_PLUGIN_RTPMANAGER) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(rtpmanager); +#endif +#if defined(GST_IOS_PLUGIN_SOUP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(soup); +#endif +#if defined(GST_IOS_PLUGIN_UDP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(udp); +#endif +#if defined(GST_IOS_PLUGIN_DATAURISRC) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(dataurisrc); +#endif +#if defined(GST_IOS_PLUGIN_SDP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(sdp); +#endif +#if defined(GST_IOS_PLUGIN_GNONLIN) || defined(GST_IOS_PLUGINS_EDITING) + GST_PLUGIN_STATIC_REGISTER(gnonlin); +#endif + +#if defined(GST_IOS_GIO_MODULE_GNUTLS) + GST_G_IO_MODULE_LOAD(gnutls); +#endif + + /* Lower the ranks of filesrc and giosrc so iosavassetsrc is + * tried first in gst_element_make_from_uri() for file:// */ + reg = gst_registry_get(); + plugin = gst_registry_lookup_feature(reg, "filesrc"); + if (plugin) + gst_plugin_feature_set_rank(plugin, GST_RANK_SECONDARY); + plugin = gst_registry_lookup_feature(reg, "giosrc"); + if (plugin) + gst_plugin_feature_set_rank(plugin, GST_RANK_SECONDARY-1); +} diff --git a/playback/player/ios/GstPlay/main.m b/playback/player/ios/GstPlay/main.m new file mode 100644 index 0000000..6cf4e0f --- /dev/null +++ b/playback/player/ios/GstPlay/main.m @@ -0,0 +1,12 @@ +#import + +#import "AppDelegate.h" +#include "gst_ios_init.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + gst_ios_init(); + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} -- cgit v1.2.3 From 090c7665629026ddb3429ed18c696c64216fb587 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Aug 2014 12:35:39 +0200 Subject: playback/player: Add initial build system with docs and tests and magic --- playback/player/android/Makefile.am | 10 ++++++++++ playback/player/gst-play/Makefile | 21 --------------------- playback/player/gst-play/Makefile.am | 10 ++++++++++ playback/player/gtk/Makefile | 19 ------------------- playback/player/gtk/Makefile.am | 10 ++++++++++ playback/player/ios/Makefile.am | 22 ++++++++++++++++++++++ 6 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 playback/player/android/Makefile.am delete mode 100644 playback/player/gst-play/Makefile create mode 100644 playback/player/gst-play/Makefile.am delete mode 100644 playback/player/gtk/Makefile create mode 100644 playback/player/gtk/Makefile.am create mode 100644 playback/player/ios/Makefile.am diff --git a/playback/player/android/Makefile.am b/playback/player/android/Makefile.am new file mode 100644 index 0000000..2664abb --- /dev/null +++ b/playback/player/android/Makefile.am @@ -0,0 +1,10 @@ +EXTRA_DIST = \ + AndroidManifest.xml \ + jni/Android.mk \ + jni/player.c \ + res/layout/main.xml \ + res/values/strings.xml \ + src/org/freedesktop/gstreamer/Player.java \ + src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ + src/org/freedesktop/gstreamer/player/Play.java + diff --git a/playback/player/gst-play/Makefile b/playback/player/gst-play/Makefile deleted file mode 100644 index ff88941..0000000 --- a/playback/player/gst-play/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -CFLAGS ?= -Wall -O2 -g -PKGCONFIG ?= pkg-config -LIBS := $(shell $(PKGCONFIG) --libs --cflags gstreamer-1.0 gstreamer-video-1.0) -lm - -all: gst-play - -clean: - rm -f gst-play - -SOURCES = \ - gst-play.c \ - gst-play-kb.c \ - ../lib/gst/player/gstplayer.c - -HEADERS = \ - gst-play-kb.h \ - ../lib/gst/player/gstplayer.h - -gst-play: $(SOURCES) $(HEADERS) - $(CC) -o $@ $(SOURCES) $(CFLAGS) $(LIBS) -I../lib - diff --git a/playback/player/gst-play/Makefile.am b/playback/player/gst-play/Makefile.am new file mode 100644 index 0000000..534e0df --- /dev/null +++ b/playback/player/gst-play/Makefile.am @@ -0,0 +1,10 @@ +bin_PROGRAMS = gst-play + +gst_play_SOURCES = gst-play.c gst-play-kb.c gst-play-kb.h + +LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ + $(GSTREAMER_LIBS) $(GLIB_LIBS) $(LIBM) + +AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GLIB_CFLAGS) $(WARNING_CFLAGS) + +noinst_HEADERS = gst-play-kb.h diff --git a/playback/player/gtk/Makefile b/playback/player/gtk/Makefile deleted file mode 100644 index a17c45e..0000000 --- a/playback/player/gtk/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -CFLAGS ?= -Wall -O2 -g -PKGCONFIG ?= pkg-config -LIBS := $(shell $(PKGCONFIG) --libs --cflags gstreamer-1.0 gstreamer-video-1.0 gtk+-3.0) -lm - -all: gtk-play - -clean: - rm -f gtk-play - -SOURCES = \ - gtk-play.c \ - ../lib/gst/player/gstplayer.c - -HEADERS = \ - ../lib/gst/player/gstplayer.h - -gtk-play: $(SOURCES) $(HEADERS) - $(CC) -o $@ $(SOURCES) $(CFLAGS) $(LIBS) -I../lib - diff --git a/playback/player/gtk/Makefile.am b/playback/player/gtk/Makefile.am new file mode 100644 index 0000000..03068e6 --- /dev/null +++ b/playback/player/gtk/Makefile.am @@ -0,0 +1,10 @@ +bin_PROGRAMS = gtk-play + +gtk_play_SOURCES = gtk-play.c + +LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ + $(GSTREAMER_LIBS) $(GTK_LIBS) $(GLIB_LIBS) $(LIBM) + +AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GLIB_CFLAGS) + +noinst_HEADERS = diff --git a/playback/player/ios/Makefile.am b/playback/player/ios/Makefile.am new file mode 100644 index 0000000..c6da505 --- /dev/null +++ b/playback/player/ios/Makefile.am @@ -0,0 +1,22 @@ +EXTRA_DIST = \ + GstPlay/AppDelegate.h \ + GstPlay/AppDelegate.m \ + GstPlay/EaglUIVIew.h \ + GstPlay/EaglUIVIew.m \ + GstPlay/en.lproj/InfoPlist.strings \ + GstPlay/fonts.conf \ + GstPlay/gst_ios_init.h \ + GstPlay/gst_ios_init.m \ + GstPlay/GstPlay-Info.plist \ + GstPlay/GstPlay-Prefix.pch \ + GstPlay/LibraryViewController.h \ + GstPlay/LibraryViewController.m \ + GstPlay/main.m \ + GstPlay/MainStoryboard_iPad.storyboard \ + GstPlay/MainStoryboard_iPhone.storyboard \ + GstPlay/Ubuntu-R.ttf \ + GstPlay/VideoViewController.h \ + GstPlay/VideoViewController.m \ + GstPlay.xcodeproj/project.xcworkspace/contents.xcworkspacedata \ + GstPlay.xcodeproj/project.pbxproj + -- cgit v1.2.3 From 4b9da857c08f97095e037319b9e42261a57ca794 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Aug 2014 12:47:27 +0200 Subject: playback/player: Add a single-include header --- playback/player/gst-play/gst-play.c | 2 +- playback/player/gtk/gtk-play.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 5154d7a..0e3dda1 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -29,7 +29,7 @@ #include #include "gst-play-kb.h" -#include +#include #define VOLUME_STEPS 20 diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 7bbc7a8..5076ff6 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -14,7 +14,7 @@ #include -#include +#include typedef struct { -- cgit v1.2.3 From e644c61286078ecde967e631c76aefaebbe3c2dc Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Aug 2014 15:10:13 +0200 Subject: playback/player: Always notify about video dimension changes Without video we will notify width=height=0 --- playback/player/gtk/gtk-play.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 5076ff6..61af9ba 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -154,7 +154,10 @@ static void video_dimensions_changed_cb (GstPlayer * unused, gint width, gint height, GtkPlay * play) { - gtk_widget_show (play->video_area); + if (width > 0 && height > 0) + gtk_widget_show (play->video_area); + else + gtk_widget_hide (play->video_area); } int -- cgit v1.2.3 From e85d26115a0a35e0d843b504964f93eb200a5b9b Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Aug 2014 16:08:14 +0200 Subject: playback/player: Move dispatch-to-main-context out of the constructor and make it a normal property --- playback/player/android/jni/player.c | 2 +- playback/player/gst-play/gst-play.c | 3 ++- playback/player/gtk/gtk-play.c | 4 +++- playback/player/ios/GstPlay/VideoViewController.m | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index e0e2d22..bdf8e31 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -193,7 +193,7 @@ native_new (JNIEnv * env, jobject thiz) { Player *player = g_slice_new0 (Player); - player->player = gst_player_new (FALSE); + player->player = gst_player_new (); SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); player->java_player = (*env)->NewGlobalRef (env, thiz); diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 0e3dda1..b9acb65 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -114,8 +114,9 @@ play_new (gchar ** uris, gdouble initial_volume) play->num_uris = g_strv_length (uris); play->cur_idx = -1; - play->player = gst_player_new (TRUE); + play->player = gst_player_new (); + g_object_set (play->player, "dispatch-to-main-context", TRUE, NULL); g_signal_connect (play->player, "position-updated", G_CALLBACK (position_updated_cb), play); g_signal_connect (play->player, "end-of-stream", diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 61af9ba..d4f8e1a 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -191,7 +191,9 @@ main (gint argc, gchar ** argv) return 1; } - play.player = gst_player_new (TRUE); + play.player = gst_player_new (); + + g_object_set (play.player, "dispatch-to-main-context", TRUE, NULL); if (!gst_uri_is_valid (play.uri)) { gchar *uri = gst_filename_to_uri (play.uri, NULL); diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index 7863f90..150c72a 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -63,7 +63,7 @@ media_width = 320; media_height = 240; - player = gst_player_new(FALSE); + player = gst_player_new(); g_object_set (player, "window-handle", video_view, NULL); g_object_set (player, "uri", [uri UTF8String], NULL); -- cgit v1.2.3 From 038cd47bfb94987432760c09d074ba0fed8acdd5 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 3 Aug 2014 16:54:27 +0200 Subject: playback/player: Add our own error domain and code --- playback/player/android/build.xml | 92 ++++++++++++++++++++++ playback/player/android/jni/player.c | 7 +- playback/player/android/res/layout/main.xml | 62 +++++++++++++++ playback/player/android/res/values/strings.xml | 6 ++ .../src/org/freedesktop/gstreamer/Player.java | 14 +++- 5 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 playback/player/android/build.xml create mode 100644 playback/player/android/res/layout/main.xml create mode 100644 playback/player/android/res/values/strings.xml diff --git a/playback/player/android/build.xml b/playback/player/android/build.xml new file mode 100644 index 0000000..4ef18c8 --- /dev/null +++ b/playback/player/android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index bdf8e31..fe7f29d 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -161,11 +161,10 @@ on_error (GstPlayer * unused, GError * err, Player * player) JNIEnv *env = get_jni_env (); jstring error_msg; - // FIXME - error_msg = err ? (*env)->NewStringUTF (env, err->message) : NULL; + error_msg =(*env)->NewStringUTF (env, err->message); (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, - error_msg); + err->code, error_msg); if ((*env)->ExceptionCheck (env)) { (*env)->ExceptionDescribe (env); (*env)->ExceptionClear (env); @@ -427,7 +426,7 @@ native_class_init (JNIEnv * env, jclass klass) on_seek_finished_method_id = (*env)->GetMethodID (env, klass, "onSeekFinished", "()V"); on_error_method_id = - (*env)->GetMethodID (env, klass, "onError", "(Ljava/lang/String;)V"); + (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); on_video_dimensions_changed_method_id = (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); diff --git a/playback/player/android/res/layout/main.xml b/playback/player/android/res/layout/main.xml new file mode 100644 index 0000000..b745d80 --- /dev/null +++ b/playback/player/android/res/layout/main.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/res/values/strings.xml b/playback/player/android/res/values/strings.xml new file mode 100644 index 0000000..9587e3c --- /dev/null +++ b/playback/player/android/res/values/strings.xml @@ -0,0 +1,6 @@ + + + GStreamer Play + Play + Pause + diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java index 862444b..993001a 100644 --- a/playback/player/android/src/org/freedesktop/gstreamer/Player.java +++ b/playback/player/android/src/org/freedesktop/gstreamer/Player.java @@ -183,9 +183,14 @@ public class Player implements Closeable { } } + // Keep these in sync with gstplayer.h + private static final Error[] errorMap = {Error.FAILED}; + public enum Error { + FAILED + } + public static interface ErrorListener { - // FIXME: enums - abstract void error(Player player, String errorMessage); + abstract void error(Player player, Error error, String errorMessage); } private ErrorListener errorListener; @@ -193,9 +198,10 @@ public class Player implements Closeable { errorListener = listener; } - private void onError(String errorMessage) { + private void onError(int errorCode, String errorMessage) { if (errorListener != null) { - errorListener.error(this, errorMessage); + Error error = errorMap[errorCode]; + errorListener.error(this, error, errorMessage); } } -- cgit v1.2.3 From 7cb352aaa6868bc9ce1bd09f58f9403f592d3b75 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 5 Aug 2014 19:12:02 +0200 Subject: playback/player: Implement seek throttling --- playback/player/android/jni/player.c | 19 +------------------ .../android/src/org/freedesktop/gstreamer/Player.java | 15 --------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index fe7f29d..d9f520c 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -56,7 +56,6 @@ static jfieldID native_player_field_id; static jmethodID on_position_updated_method_id; static jmethodID on_duration_changed_method_id; static jmethodID on_end_of_stream_method_id; -static jmethodID on_seek_finished_method_id; static jmethodID on_error_method_id; static jmethodID on_video_dimensions_changed_method_id; @@ -143,18 +142,6 @@ on_end_of_stream (GstPlayer * unused, Player * player) } } -static void -on_seek_finished (GstPlayer * unused, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, on_seek_finished_method_id); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - static void on_error (GstPlayer * unused, GError * err, Player * player) { @@ -202,8 +189,6 @@ native_new (JNIEnv * env, jobject thiz) G_CALLBACK (on_duration_changed), player); g_signal_connect (player->player, "end-of-stream", G_CALLBACK (on_end_of_stream), player); - g_signal_connect (player->player, "seek-finished", - G_CALLBACK (on_seek_finished), player); g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); g_signal_connect (player->player, "video-dimensions-changed", G_CALLBACK (on_video_dimensions_changed), player); @@ -423,8 +408,6 @@ native_class_init (JNIEnv * env, jclass klass) (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); on_end_of_stream_method_id = (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); - on_seek_finished_method_id = - (*env)->GetMethodID (env, klass, "onSeekFinished", "()V"); on_error_method_id = (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); on_video_dimensions_changed_method_id = @@ -432,7 +415,7 @@ native_class_init (JNIEnv * env, jclass klass) if (!native_player_field_id || !on_position_updated_method_id || !on_duration_changed_method_id || - !on_end_of_stream_method_id || !on_seek_finished_method_id || + !on_end_of_stream_method_id || !on_error_method_id || !on_video_dimensions_changed_method_id) { static const gchar *message = "The calling class does not implement all necessary interface methods"; diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java index 993001a..d93304d 100644 --- a/playback/player/android/src/org/freedesktop/gstreamer/Player.java +++ b/playback/player/android/src/org/freedesktop/gstreamer/Player.java @@ -168,21 +168,6 @@ public class Player implements Closeable { } } - public static interface SeekFinishedListener { - abstract void seekFinished(Player player); - } - - private SeekFinishedListener seekFinishedListener; - public void setSeekFinishedListener(SeekFinishedListener listener) { - seekFinishedListener = listener; - } - - private void onSeekFinished() { - if (seekFinishedListener != null) { - seekFinishedListener.seekFinished(this); - } - } - // Keep these in sync with gstplayer.h private static final Error[] errorMap = {Error.FAILED}; public enum Error { -- cgit v1.2.3 From a622cb0d2cacdca40cedb2232b555097546c9cf8 Mon Sep 17 00:00:00 2001 From: Parthasarathi Susarla Date: Wed, 6 Aug 2014 17:37:33 +1000 Subject: playback/player: GTK: Improvements to the GTK+ player This patch contains a few improvements to the gtk-player: * Uses unified play/pause button. * Adds a Skip Previous/Next button. * Volume control * Takes multiple files/uri's as arguments. * Switches to the next track (if any) when the current track reaches and end. https://github.com/sdroege/gst-player/pull/1 --- playback/player/gtk/gtk-play.c | 202 +++++++++++++++++++++++++++++++++++------ 1 file changed, 175 insertions(+), 27 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index d4f8e1a..502e854 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -16,18 +16,35 @@ #include +#define APP_NAME "gtk-play" + typedef struct { GstPlayer *player; gchar *uri; + GList *uris; + GtkWidget *window; - GtkWidget *play_button, *pause_button; + GtkWidget *play_pause_button; + GtkWidget *prev_button, *next_button; GtkWidget *seekbar; GtkWidget *video_area; + GtkWidget *volume_button; gulong seekbar_value_changed_signal_id; } GtkPlay; + +static void +set_title (GtkPlay *play, const gchar *title) +{ + if (title == NULL) { + gtk_window_set_title (GTK_WINDOW (play->window), APP_NAME); + } else { + gtk_window_set_title (GTK_WINDOW (play->window), title); + } +} + static void delete_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) { @@ -55,15 +72,70 @@ video_area_realize_cb (GtkWidget * widget, GtkPlay * play) } static void -play_clicked_cb (GtkButton * button, GtkPlay * play) +play_pause_clicked_cb (GtkButton *button, GtkPlay *play) { - gst_player_play (play->player); + GtkWidget *image; + + if (gst_player_is_playing (play->player)) { + gst_player_pause (play->player); + image = gtk_image_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON(play->play_pause_button), image); + } else { + gchar *title; + + gst_player_play (play->player); + image = gtk_image_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON(play->play_pause_button), image); + + title = gst_player_get_uri (play->player); + set_title (play, title); + g_free (title); + } +} + +static void +skip_prev_clicked_cb (GtkButton *button, GtkPlay *play) +{ + GList *prev; + gchar *cur_uri; + + prev = g_list_find_custom (play->uris, + gst_player_get_uri (play->player), + (GCompareFunc)strcmp); + if (prev != NULL) { + prev = g_list_previous (prev); + + if (prev != NULL) { + gtk_widget_set_sensitive (play->next_button, TRUE); + gst_player_set_uri (play->player, prev->data); + gst_player_play (play->player); + set_title (play, prev->data); + } else { + gtk_widget_set_sensitive (play->prev_button, FALSE); + } + } } static void -pause_clicked_cb (GtkButton * button, GtkPlay * play) +skip_next_clicked_cb (GtkButton *button, GtkPlay *play) { - gst_player_pause (play->player); + GList *next, *l; + gchar *cur_uri; + + next = g_list_find_custom (play->uris, + gst_player_get_uri (play->player), + (GCompareFunc)strcmp); + if (next != NULL) { + next = g_list_next (next); + if (next != NULL) { + gtk_widget_set_sensitive (play->prev_button, TRUE); + gst_player_set_uri (play->player, next->data); + gst_player_play (play->player); + set_title (play, next->data); + } else { + gtk_widget_set_sensitive (play->next_button, FALSE); + } + } } static void @@ -73,6 +145,14 @@ seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) gst_player_seek (play->player, gst_util_uint64_scale (value, GST_SECOND, 1)); } +void +volume_changed_cb (GtkScaleButton *button, + gdouble value, + GtkPlay *play) +{ + gst_player_set_volume (play->player, value); +} + static void create_ui (GtkPlay * play) { @@ -81,23 +161,19 @@ create_ui (GtkPlay * play) play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (play->window), "delete-event", G_CALLBACK (delete_event_cb), play); + set_title (play, APP_NAME); play->video_area = gtk_drawing_area_new (); gtk_widget_set_double_buffered (play->video_area, FALSE); g_signal_connect (play->video_area, "realize", G_CALLBACK (video_area_realize_cb), play); - play->play_button = - gtk_button_new_from_icon_name ("media-playback-start", - GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->play_button), "clicked", - G_CALLBACK (play_clicked_cb), play); - - play->pause_button = + /* Unified play/pause button */ + play->play_pause_button = gtk_button_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->pause_button), "clicked", - G_CALLBACK (pause_clicked_cb), play); + g_signal_connect (G_OBJECT (play->play_pause_button), "clicked", + G_CALLBACK (play_pause_clicked_cb), play); play->seekbar = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 100, 1); @@ -106,10 +182,35 @@ create_ui (GtkPlay * play) g_signal_connect (G_OBJECT (play->seekbar), "value-changed", G_CALLBACK (seekbar_value_changed_cb), play); + /* Skip backward button */ + play->prev_button = + gtk_button_new_from_icon_name ("media-skip-backward", + GTK_ICON_SIZE_BUTTON); + g_signal_connect (G_OBJECT (play->prev_button), "clicked", + G_CALLBACK (skip_prev_clicked_cb), play); + gtk_widget_set_sensitive (play->prev_button, FALSE); + + /* Skip forward button */ + play->next_button = + gtk_button_new_from_icon_name ("media-skip-forward", + GTK_ICON_SIZE_BUTTON); + g_signal_connect (G_OBJECT (play->next_button), "clicked", + G_CALLBACK (skip_next_clicked_cb), play); + gtk_widget_set_sensitive (play->next_button, FALSE); + + /* Volume control button */ + play->volume_button = gtk_volume_button_new (); + gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), + gst_player_get_volume (play->player)); + g_signal_connect (G_OBJECT (play->volume_button), "value-changed", + G_CALLBACK (volume_changed_cb), play); + controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_start (GTK_BOX (controls), play->play_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->pause_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); @@ -130,6 +231,7 @@ static void play_clear (GtkPlay * play) { g_free (play->uri); + g_list_free_full (play->uris, g_free); g_object_unref (play->player); } @@ -160,19 +262,49 @@ video_dimensions_changed_cb (GstPlayer * unused, gint width, gint height, gtk_widget_hide (play->video_area); } +static void +eos_cb (GstPlayer * unused, GtkPlay * play) +{ + if (gst_player_is_playing (play->player)) { + GList *next = NULL; + gchar *uri; + + next = g_list_find_custom (play->uris, + gst_player_get_uri (play->player), + (GCompareFunc) strcmp); + if (next) { + next = g_list_next (next); + if (next) { + if (!gtk_widget_is_sensitive(play->prev_button)) + gtk_widget_set_sensitive (play->prev_button, TRUE); + gst_player_set_uri (play->player, next->data); + gst_player_play (play->player); + set_title (play, next->data); + } + else + gst_player_stop (play->player); + } + } +} + int main (gint argc, gchar ** argv) { GtkPlay play; + gchar **file_names = NULL; GOptionContext *ctx; GOptionEntry options[] = { + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, + "Files to play" }, {NULL} }; + guint list_length = 0; GError *err = NULL; + GList *l; memset (&play, 0, sizeof (play)); - g_set_prgname ("gtk-play"); + g_set_prgname (APP_NAME); ctx = g_option_context_new ("FILE|URI"); g_option_context_add_main_entries (ctx, options, NULL); @@ -185,33 +317,49 @@ main (gint argc, gchar ** argv) g_option_context_free (ctx); // FIXME: Add support for playlists and stuff - play.uri = g_strdup (argv[1]); - if (!play.uri) { - g_print ("Usage: %s FILE|URI\n", argv[0]); + /* Parse the list of the file names we have to play. */ + if (!file_names) { + g_print ("Usage: %s FILE(s)|URI(s)\n", APP_NAME); return 1; + } else { + guint i; + + list_length = g_strv_length (file_names); + for (i = 0; i < list_length; i++) { + play.uris = + g_list_append (play.uris, + gst_uri_is_valid (file_names[i]) ? + g_strdup (file_names[i]) : + gst_filename_to_uri (file_names[i], NULL)); + } + + g_strfreev (file_names); + file_names = NULL; } play.player = gst_player_new (); g_object_set (play.player, "dispatch-to-main-context", TRUE, NULL); - if (!gst_uri_is_valid (play.uri)) { - gchar *uri = gst_filename_to_uri (play.uri, NULL); - g_free (play.uri); - play.uri = uri; - } - g_object_set (play.player, "uri", play.uri, NULL); + gst_player_set_uri (play.player, g_list_first (play.uris)->data); create_ui (&play); + if (list_length > 1) + gtk_widget_set_sensitive (play.next_button, TRUE); + g_signal_connect (play.player, "position-updated", G_CALLBACK (position_updated_cb), &play); g_signal_connect (play.player, "duration-changed", G_CALLBACK (duration_changed_cb), &play); g_signal_connect (play.player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed_cb), &play); + g_signal_connect (play.player, "end-of-stream", + G_CALLBACK (eos_cb), &play); - gst_player_pause (play.player); + /* We have file(s) that need playing. */ + set_title (&play, g_list_first (play.uris)->data); + gst_player_play (play.player); gtk_main (); -- cgit v1.2.3 From ead64d43fa5c5cb3f31ec9dae2999967ad29f17c Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 6 Aug 2014 16:41:58 +0200 Subject: playback/player: GTK: Fix logic for setting the prev/next button insensitive at the end/beginning of the playlist --- playback/player/gtk/gtk-play.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 502e854..0395504 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -110,8 +110,7 @@ skip_prev_clicked_cb (GtkButton *button, GtkPlay *play) gst_player_set_uri (play->player, prev->data); gst_player_play (play->player); set_title (play, prev->data); - } else { - gtk_widget_set_sensitive (play->prev_button, FALSE); + gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); } } } @@ -132,8 +131,7 @@ skip_next_clicked_cb (GtkButton *button, GtkPlay *play) gst_player_set_uri (play->player, next->data); gst_player_play (play->player); set_title (play, next->data); - } else { - gtk_widget_set_sensitive (play->next_button, FALSE); + gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); } } } -- cgit v1.2.3 From ad694a24eaf934f03c7d1a708f9c1f042003d377 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 6 Aug 2014 16:44:24 +0200 Subject: playback/player: GTK: Turn checks that must not fail into assertions in prev/next logic --- playback/player/gtk/gtk-play.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 0395504..5f31f10 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -102,17 +102,16 @@ skip_prev_clicked_cb (GtkButton *button, GtkPlay *play) prev = g_list_find_custom (play->uris, gst_player_get_uri (play->player), (GCompareFunc)strcmp); - if (prev != NULL) { - prev = g_list_previous (prev); - - if (prev != NULL) { - gtk_widget_set_sensitive (play->next_button, TRUE); - gst_player_set_uri (play->player, prev->data); - gst_player_play (play->player); - set_title (play, prev->data); - gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); - } - } + + g_return_if_fail (prev != NULL); + prev = g_list_previous (prev); + g_return_if_fail (prev != NULL); + + gtk_widget_set_sensitive (play->next_button, TRUE); + gst_player_set_uri (play->player, prev->data); + gst_player_play (play->player); + set_title (play, prev->data); + gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); } static void @@ -124,16 +123,16 @@ skip_next_clicked_cb (GtkButton *button, GtkPlay *play) next = g_list_find_custom (play->uris, gst_player_get_uri (play->player), (GCompareFunc)strcmp); - if (next != NULL) { - next = g_list_next (next); - if (next != NULL) { - gtk_widget_set_sensitive (play->prev_button, TRUE); - gst_player_set_uri (play->player, next->data); - gst_player_play (play->player); - set_title (play, next->data); - gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); - } - } + + g_return_if_fail (next != NULL); + next = g_list_next (next); + g_return_if_fail (next != NULL); + + gtk_widget_set_sensitive (play->prev_button, TRUE); + gst_player_set_uri (play->player, next->data); + gst_player_play (play->player); + set_title (play, next->data); + gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); } static void -- cgit v1.2.3 From adf40eeefe6d81913a6939541447cfd5c6141982 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 6 Aug 2014 16:52:22 +0200 Subject: playback/player: GTK: Fix prev/next button insensitivity logic in the EOS handler --- playback/player/gtk/gtk-play.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 5f31f10..2df76e1 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -269,16 +269,19 @@ eos_cb (GstPlayer * unused, GtkPlay * play) next = g_list_find_custom (play->uris, gst_player_get_uri (play->player), (GCompareFunc) strcmp); + + g_return_if_fail (next != NULL); + + next = g_list_next (next); if (next) { - next = g_list_next (next); - if (next) { - if (!gtk_widget_is_sensitive(play->prev_button)) - gtk_widget_set_sensitive (play->prev_button, TRUE); - gst_player_set_uri (play->player, next->data); - gst_player_play (play->player); - set_title (play, next->data); - } - else + if (!gtk_widget_is_sensitive(play->prev_button)) + gtk_widget_set_sensitive (play->prev_button, TRUE); + gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); + + gst_player_set_uri (play->player, next->data); + gst_player_play (play->player); + set_title (play, next->data); + } else { gst_player_stop (play->player); } } -- cgit v1.2.3 From d0dc785d7730a51a8de61d30efa5915a8ec0196e Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 7 Aug 2014 10:59:37 +0200 Subject: playback/player: Fix indention with gst-indent --- playback/player/android/jni/player.c | 2 +- playback/player/gtk/gtk-play.c | 74 ++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index d9f520c..8b3ff24 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -148,7 +148,7 @@ on_error (GstPlayer * unused, GError * err, Player * player) JNIEnv *env = get_jni_env (); jstring error_msg; - error_msg =(*env)->NewStringUTF (env, err->message); + error_msg = (*env)->NewStringUTF (env, err->message); (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, err->code, error_msg); diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 2df76e1..f015077 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -36,7 +36,7 @@ typedef struct static void -set_title (GtkPlay *play, const gchar *title) +set_title (GtkPlay * play, const gchar * title) { if (title == NULL) { gtk_window_set_title (GTK_WINDOW (play->window), APP_NAME); @@ -72,20 +72,24 @@ video_area_realize_cb (GtkWidget * widget, GtkPlay * play) } static void -play_pause_clicked_cb (GtkButton *button, GtkPlay *play) +play_pause_clicked_cb (GtkButton * button, GtkPlay * play) { GtkWidget *image; if (gst_player_is_playing (play->player)) { gst_player_pause (play->player); - image = gtk_image_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_BUTTON); - gtk_button_set_image (GTK_BUTTON(play->play_pause_button), image); + image = + gtk_image_new_from_icon_name ("media-playback-start", + GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); } else { gchar *title; gst_player_play (play->player); - image = gtk_image_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_BUTTON); - gtk_button_set_image (GTK_BUTTON(play->play_pause_button), image); + image = + gtk_image_new_from_icon_name ("media-playback-pause", + GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); title = gst_player_get_uri (play->player); set_title (play, title); @@ -94,14 +98,13 @@ play_pause_clicked_cb (GtkButton *button, GtkPlay *play) } static void -skip_prev_clicked_cb (GtkButton *button, GtkPlay *play) +skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) { GList *prev; gchar *cur_uri; prev = g_list_find_custom (play->uris, - gst_player_get_uri (play->player), - (GCompareFunc)strcmp); + gst_player_get_uri (play->player), (GCompareFunc) strcmp); g_return_if_fail (prev != NULL); prev = g_list_previous (prev); @@ -115,14 +118,13 @@ skip_prev_clicked_cb (GtkButton *button, GtkPlay *play) } static void -skip_next_clicked_cb (GtkButton *button, GtkPlay *play) +skip_next_clicked_cb (GtkButton * button, GtkPlay * play) { GList *next, *l; gchar *cur_uri; next = g_list_find_custom (play->uris, - gst_player_get_uri (play->player), - (GCompareFunc)strcmp); + gst_player_get_uri (play->player), (GCompareFunc) strcmp); g_return_if_fail (next != NULL); next = g_list_next (next); @@ -143,9 +145,7 @@ seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) } void -volume_changed_cb (GtkScaleButton *button, - gdouble value, - GtkPlay *play) +volume_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) { gst_player_set_volume (play->player, value); } @@ -181,30 +181,31 @@ create_ui (GtkPlay * play) /* Skip backward button */ play->prev_button = - gtk_button_new_from_icon_name ("media-skip-backward", - GTK_ICON_SIZE_BUTTON); + gtk_button_new_from_icon_name ("media-skip-backward", + GTK_ICON_SIZE_BUTTON); g_signal_connect (G_OBJECT (play->prev_button), "clicked", - G_CALLBACK (skip_prev_clicked_cb), play); + G_CALLBACK (skip_prev_clicked_cb), play); gtk_widget_set_sensitive (play->prev_button, FALSE); /* Skip forward button */ - play->next_button = - gtk_button_new_from_icon_name ("media-skip-forward", - GTK_ICON_SIZE_BUTTON); + play->next_button = + gtk_button_new_from_icon_name ("media-skip-forward", + GTK_ICON_SIZE_BUTTON); g_signal_connect (G_OBJECT (play->next_button), "clicked", - G_CALLBACK (skip_next_clicked_cb), play); + G_CALLBACK (skip_next_clicked_cb), play); gtk_widget_set_sensitive (play->next_button, FALSE); /* Volume control button */ play->volume_button = gtk_volume_button_new (); gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), - gst_player_get_volume (play->player)); + gst_player_get_volume (play->player)); g_signal_connect (G_OBJECT (play->volume_button), "value-changed", - G_CALLBACK (volume_changed_cb), play); + G_CALLBACK (volume_changed_cb), play); controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, + 2); gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); @@ -267,14 +268,13 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gchar *uri; next = g_list_find_custom (play->uris, - gst_player_get_uri (play->player), - (GCompareFunc) strcmp); + gst_player_get_uri (play->player), (GCompareFunc) strcmp); g_return_if_fail (next != NULL); next = g_list_next (next); if (next) { - if (!gtk_widget_is_sensitive(play->prev_button)) + if (!gtk_widget_is_sensitive (play->prev_button)) gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); @@ -282,7 +282,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gst_player_play (play->player); set_title (play, next->data); } else { - gst_player_stop (play->player); + gst_player_stop (play->player); } } } @@ -294,8 +294,8 @@ main (gint argc, gchar ** argv) gchar **file_names = NULL; GOptionContext *ctx; GOptionEntry options[] = { - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, - "Files to play" }, + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, + "Files to play"}, {NULL} }; guint list_length = 0; @@ -327,10 +327,9 @@ main (gint argc, gchar ** argv) list_length = g_strv_length (file_names); for (i = 0; i < list_length; i++) { play.uris = - g_list_append (play.uris, - gst_uri_is_valid (file_names[i]) ? - g_strdup (file_names[i]) : - gst_filename_to_uri (file_names[i], NULL)); + g_list_append (play.uris, + gst_uri_is_valid (file_names[i]) ? + g_strdup (file_names[i]) : gst_filename_to_uri (file_names[i], NULL)); } g_strfreev (file_names); @@ -346,7 +345,7 @@ main (gint argc, gchar ** argv) create_ui (&play); if (list_length > 1) - gtk_widget_set_sensitive (play.next_button, TRUE); + gtk_widget_set_sensitive (play.next_button, TRUE); g_signal_connect (play.player, "position-updated", G_CALLBACK (position_updated_cb), &play); @@ -354,8 +353,7 @@ main (gint argc, gchar ** argv) G_CALLBACK (duration_changed_cb), &play); g_signal_connect (play.player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed_cb), &play); - g_signal_connect (play.player, "end-of-stream", - G_CALLBACK (eos_cb), &play); + g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); /* We have file(s) that need playing. */ set_title (&play, g_list_first (play.uris)->data); -- cgit v1.2.3 From 97c4cfc6708f5891962718af33e9f5ebd1f7c1ed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Nov 2014 16:18:28 +0100 Subject: playback/player: android: Link against GLib 2.0 as it is necessary --- playback/player/android/jni/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 39ad84e..439baa9 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -19,6 +19,6 @@ GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) -GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 +GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk -- cgit v1.2.3 From ae46c50138d378bd4dcddaca37e7ee36f51830c6 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 7 Feb 2015 11:14:42 +0100 Subject: playback/player: Make state handling more robust and notify the application about our states The application now will get one of 4 states via a signal: STOPPED: After EOS, error and when explicitely stopped BUFFERING: When moving to the lower states, or we get buffering messages, also when seeking. PAUSED and PLAYING: When having reached that state and it's our target Also we now always first go to PAUSED state before we seek, and also before we go to PLAYING. This allows us to deterministically change states and makes everything a bit more robust. As a side-effect, get rid of the is-playing property. Applications can now get this from the corresponding signal if they need to know. Additionally now notify the application about the buffering percentage. Also fix a few bugs related to state handling and buffering. --- playback/player/gst-play/gst-play.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index b9acb65..998a991 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -76,7 +76,7 @@ error_cb (GstPlayer * player, GError * err, GstPlay * play) } } -static gboolean +static void position_updated_cb (GstPlayer * player, GstClockTime pos, GstPlay * play) { GstClockTime dur = -1; @@ -84,10 +84,7 @@ position_updated_cb (GstPlayer * player, GstClockTime pos, GstPlay * play) g_object_get (play->player, "duration", &dur, NULL); - if (play->desired_state == GST_STATE_PAUSED) - g_snprintf (status, sizeof (status), "Paused"); - else - memset (status, ' ', sizeof (status) - 1); + memset (status, ' ', sizeof (status) - 1); if (pos >= 0 && dur > 0) { gchar dstr[32], pstr[32]; @@ -99,8 +96,18 @@ position_updated_cb (GstPlayer * player, GstClockTime pos, GstPlay * play) dstr[9] = '\0'; g_print ("%s / %s %s\r", pstr, dstr, status); } +} - return TRUE; +static void +state_changed_cb (GstPlayer * player, GstPlayerState state, GstPlay * play) +{ + g_print ("State changed: %s\n", gst_player_state_get_name (state)); +} + +static void +buffering_cb (GstPlayer * player, gint percent, GstPlay * play) +{ + g_print ("Buffering: %d\n", percent); } static GstPlay * @@ -119,6 +126,10 @@ play_new (gchar ** uris, gdouble initial_volume) g_object_set (play->player, "dispatch-to-main-context", TRUE, NULL); g_signal_connect (play->player, "position-updated", G_CALLBACK (position_updated_cb), play); + g_signal_connect (play->player, "state-changed", + G_CALLBACK (state_changed_cb), play); + g_signal_connect (play->player, "buffering", + G_CALLBACK (buffering_cb), play); g_signal_connect (play->player, "end-of-stream", G_CALLBACK (end_of_stream_cb), play); g_signal_connect (play->player, "error", G_CALLBACK (error_cb), play); -- cgit v1.2.3 From d8287305919ef467cf1cdc56ba912167989d9f34 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 8 Feb 2015 11:38:47 +0100 Subject: playback/player: Don't skip to next track immediately in gst-play when seeking after the duration Instead wait for end-of-stream for switching. --- playback/player/gst-play/gst-play.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 998a991..6fc73bb 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -329,16 +329,9 @@ relative_seek (GstPlay * play, gdouble percent) goto seek_failed; pos = pos + dur * percent; - if (pos > dur) { - if (!play_next (play)) { - g_print ("\nReached end of play list.\n"); - g_main_loop_quit (play->loop); - } - } else { - if (pos < 0) - pos = 0; - gst_player_seek (play->player, pos); - } + if (pos < 0) + pos = 0; + gst_player_seek (play->player, pos); return; -- cgit v1.2.3 From d0ef447da9dba57b1d1e31a1969c606aa1a3458e Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Thu, 26 Feb 2015 17:17:05 +0000 Subject: playback/player: gtk-play: show a file chooser if no URIs were passed --- playback/player/gtk/gtk-play.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index f015077..9766a72 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -319,8 +319,32 @@ main (gint argc, gchar ** argv) // FIXME: Add support for playlists and stuff /* Parse the list of the file names we have to play. */ if (!file_names) { - g_print ("Usage: %s FILE(s)|URI(s)\n", APP_NAME); - return 1; + GtkWidget *chooser; + int res; + + chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL); + g_object_set (chooser, + "local-only", FALSE, + "select-multiple", TRUE, + NULL); + + res = gtk_dialog_run (GTK_DIALOG (chooser)); + if (res == GTK_RESPONSE_ACCEPT) { + GSList *l; + + l = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); + while (l) { + play.uris = g_list_append (play.uris, l->data); + l = g_slist_delete_link (l, l); + } + } else { + return 0; + } + gtk_widget_destroy (chooser); } else { guint i; -- cgit v1.2.3 From 6f88388819cb74538788d976f4094986925fced0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 27 Feb 2015 09:46:02 +0200 Subject: playback/player: Remove gst_player_is_playing() The current state is now notified via the state-changed signal, and in the GTK UI it was only used to keep track of the desired state. --- playback/player/gtk/gtk-play.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 9766a72..f405c38 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -32,9 +32,9 @@ typedef struct GtkWidget *video_area; GtkWidget *volume_button; gulong seekbar_value_changed_signal_id; + gboolean playing; } GtkPlay; - static void set_title (GtkPlay * play, const gchar * title) { @@ -76,12 +76,13 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) { GtkWidget *image; - if (gst_player_is_playing (play->player)) { + if (play->playing) { gst_player_pause (play->player); image = gtk_image_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); + play->playing = FALSE; } else { gchar *title; @@ -94,6 +95,7 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) title = gst_player_get_uri (play->player); set_title (play, title); g_free (title); + play->playing = TRUE; } } @@ -263,7 +265,7 @@ video_dimensions_changed_cb (GstPlayer * unused, gint width, gint height, static void eos_cb (GstPlayer * unused, GtkPlay * play) { - if (gst_player_is_playing (play->player)) { + if (play->playing) { GList *next = NULL; gchar *uri; @@ -361,6 +363,7 @@ main (gint argc, gchar ** argv) } play.player = gst_player_new (); + play.playing = TRUE; g_object_set (play.player, "dispatch-to-main-context", TRUE, NULL); -- cgit v1.2.3 From 63421594400cba9402fbf243fb85c5222a617e00 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 1 Mar 2015 13:59:03 +0100 Subject: playback/player: Fix indention --- playback/player/gtk/gtk-play.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index f405c38..dbb4d72 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -325,14 +325,9 @@ main (gint argc, gchar ** argv) int res; chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, - GTK_FILE_CHOOSER_ACTION_OPEN, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Open", GTK_RESPONSE_ACCEPT, - NULL); - g_object_set (chooser, - "local-only", FALSE, - "select-multiple", TRUE, - NULL); + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); + g_object_set (chooser, "local-only", FALSE, "select-multiple", TRUE, NULL); res = gtk_dialog_run (GTK_DIALOG (chooser)); if (res == GTK_RESPONSE_ACCEPT) { -- cgit v1.2.3 From 0b7383c104b55327127b1a9ba276932732d986db Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 1 Mar 2015 13:59:08 +0100 Subject: playback/player: Make it possible to call play()/pause() after EOS to restart playback from the beginning --- playback/player/gtk/gtk-play.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index dbb4d72..0a557be 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -284,7 +284,14 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gst_player_play (play->player); set_title (play, next->data); } else { - gst_player_stop (play->player); + GtkWidget *image; + + gst_player_pause (play->player); + image = + gtk_image_new_from_icon_name ("media-playback-start", + GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); + play->playing = FALSE; } } } -- cgit v1.2.3 From b7a1198170c13ac4d091feaacb0e8a60e55ac62d Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 1 Mar 2015 14:04:00 +0100 Subject: playback/player: Add copyright header to GTK player --- playback/player/gtk/gtk-play.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 0a557be..e3ebea1 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1,3 +1,23 @@ +/* GStreamer + * + * Copyright (C) 2014-2015 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + #include #include -- cgit v1.2.3 From 503512405055d873d7ef4d4ca80f61345d10757c Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 1 Mar 2015 14:20:17 +0100 Subject: playback/player: Update Android bindings to the latest API --- playback/player/android/jni/player.c | 52 +++++++++++++++------- .../src/org/freedesktop/gstreamer/Player.java | 46 ++++++++++++++++--- 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index 8b3ff24..50978d9 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -55,6 +55,8 @@ static JavaVM *java_vm; static jfieldID native_player_field_id; static jmethodID on_position_updated_method_id; static jmethodID on_duration_changed_method_id; +static jmethodID on_state_changed_method_id; +static jmethodID on_buffering_method_id; static jmethodID on_end_of_stream_method_id; static jmethodID on_error_method_id; static jmethodID on_video_dimensions_changed_method_id; @@ -130,6 +132,32 @@ on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) } } +static void +on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_state_changed_method_id, state); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_buffering (GstPlayer * unused, gint percent, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_buffering_method_id, percent); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + static void on_end_of_stream (GstPlayer * unused, Player * player) { @@ -187,6 +215,10 @@ native_new (JNIEnv * env, jobject thiz) G_CALLBACK (on_position_updated), player); g_signal_connect (player->player, "duration-changed", G_CALLBACK (on_duration_changed), player); + g_signal_connect (player->player, "state-changed", + G_CALLBACK (on_state_changed), player); + g_signal_connect (player->player, "buffering", + G_CALLBACK (on_buffering), player); g_signal_connect (player->player, "end-of-stream", G_CALLBACK (on_end_of_stream), player); g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); @@ -283,20 +315,6 @@ native_get_uri (JNIEnv * env, jobject thiz) return uri; } -static jboolean -native_is_playing (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jboolean is_playing; - - if (!player) - return FALSE; - - g_object_get (player->player, "is-playing", &is_playing, NULL); - - return is_playing; -} - static jlong native_get_position (JNIEnv * env, jobject thiz) { @@ -406,6 +424,10 @@ native_class_init (JNIEnv * env, jclass klass) (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); on_duration_changed_method_id = (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); + on_state_changed_method_id = + (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); + on_buffering_method_id = + (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); on_end_of_stream_method_id = (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); on_error_method_id = @@ -415,6 +437,7 @@ native_class_init (JNIEnv * env, jclass klass) if (!native_player_field_id || !on_position_updated_method_id || !on_duration_changed_method_id || + !on_state_changed_method_id || !on_buffering_method_id || !on_end_of_stream_method_id || !on_error_method_id || !on_video_dimensions_changed_method_id) { static const gchar *message = @@ -437,7 +460,6 @@ static JNINativeMethod native_methods[] = { {"nativeFree", "()V", (void *) native_free}, {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, - {"nativeIsPlaying", "()Z", (void *) native_is_playing}, {"nativeGetPosition", "()J", (void *) native_get_position}, {"nativeGetDuration", "()J", (void *) native_get_duration}, {"nativeGetVolume", "()D", (void *) native_get_volume}, diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java index d93304d..e2bef8c 100644 --- a/playback/player/android/src/org/freedesktop/gstreamer/Player.java +++ b/playback/player/android/src/org/freedesktop/gstreamer/Player.java @@ -1,6 +1,6 @@ /* GStreamer * - * Copyright (C) 2014 Sebastian Dröge + * Copyright (C) 2014-2015 Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -77,11 +77,6 @@ public class Player implements Closeable { nativeSetUri(uri); } - private native boolean nativeIsPlaying(); - public boolean isPlaying() { - return nativeIsPlaying(); - } - private native long nativeGetPosition(); public long getPosition() { return nativeGetPosition(); @@ -153,6 +148,45 @@ public class Player implements Closeable { } } + private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; + public enum State { + STOPPED, + BUFFERING, + PAUSED, + PLAYING + } + + public static interface StateChangedListener { + abstract void stateChanged(Player player, State state); + } + + private StateChangedListener stateChangedListener; + public void setStateChangedListener(StateChangedListener listener) { + stateChangedListener = listener; + } + + private void onStateChanged(int stateIdx) { + if (stateChangedListener != null) { + State state = stateMap[stateIdx]; + stateChangedListener.stateChanged(this, state); + } + } + + public static interface BufferingListener { + abstract void buffering(Player player, int percent); + } + + private BufferingListener bufferingListener; + public void setBufferingListener(BufferingListener listener) { + bufferingListener = listener; + } + + private void onBuffering(int percent) { + if (bufferingListener != null) { + bufferingListener.buffering(this, percent); + } + } + public static interface EndOfStreamListener { abstract void endOfStream(Player player); } -- cgit v1.2.3 From 8b41422c77ed01b647c9f38926d56c2bd1e90ec6 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 3 Mar 2015 11:56:31 -0500 Subject: playback/player: android: Cast pointers to gintptr to simplify code --- playback/player/android/jni/player.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index 50978d9..2597db4 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -30,17 +30,8 @@ GST_DEBUG_CATEGORY_STATIC (debug_category); #define GST_CAT_DEFAULT debug_category -/* - * These macros provide a way to store the native pointer to Player, which might be 32 or 64 bits, into - * a jlong, which is always 64 bits, without warnings. - */ -#if GLIB_SIZEOF_VOID_P == 8 -# define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(*env)->GetLongField (env, thiz, fieldID) -# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)data) -#else -# define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(jint)(*env)->GetLongField (env, thiz, fieldID) -# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(jint)data) -#endif +#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) +#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) typedef struct _Player { -- cgit v1.2.3 From 8ba8714b20a5f53af34417d2990db7ce8505ed0e Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 6 Mar 2015 09:38:16 +0100 Subject: playback/player: Stop using GSlice for allocations, it's deprecated soon and slower than malloc in most places --- playback/player/android/jni/player.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index 2597db4..577fab9 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -196,7 +196,7 @@ on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, static void native_new (JNIEnv * env, jobject thiz) { - Player *player = g_slice_new0 (Player); + Player *player = g_new0 (Player, 1); player->player = gst_player_new (); SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); @@ -226,7 +226,7 @@ native_free (JNIEnv * env, jobject thiz) return; (*env)->DeleteGlobalRef (env, player->java_player); - g_slice_free (Player, player); + g_free (player); SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); } -- cgit v1.2.3 From 7638d52c47827a78e2e165c108f3baf2e6ed84c3 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 22 Apr 2015 09:35:01 +0200 Subject: playback/player: Add VideoToolbox to the iOS project linker flags --- playback/player/ios/GstPlay.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj index 14facf3..6b1d3fa 100644 --- a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj +++ b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj @@ -347,6 +347,8 @@ CoreAudio, "-framework", AudioToolbox, + "-weak_framework", + VideoToolbox, "-framework", OpenGLES, "-framework", @@ -396,6 +398,8 @@ CoreAudio, "-framework", AudioToolbox, + "-weak_framework", + VideoToolbox, "-framework", OpenGLES, "-framework", -- cgit v1.2.3 From 109e63d7d77d5b60e63368e5ce6e9f70b463cfc5 Mon Sep 17 00:00:00 2001 From: Jan Berkel Date: Wed, 22 Apr 2015 14:43:07 +0100 Subject: playback/player: ios: Extract online media into plist https://github.com/sdroege/gst-player/pull/20 --- .../player/ios/GstPlay.xcodeproj/project.pbxproj | 4 +++ .../player/ios/GstPlay/LibraryViewController.m | 31 +--------------------- playback/player/ios/GstPlay/OnlineMedia.plist | 30 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 playback/player/ios/GstPlay/OnlineMedia.plist diff --git a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj index 6b1d3fa..ee94d2d 100644 --- a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj +++ b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 19A17EFC8D41A75E8D3DB72E /* OnlineMedia.plist in Resources */ = {isa = PBXBuildFile; fileRef = 19A176455D27298FE4041DC3 /* OnlineMedia.plist */; }; AD2B881F198D631B0070367B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B881E198D631B0070367B /* Foundation.framework */; }; AD2B8821198D631B0070367B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B8820198D631B0070367B /* CoreGraphics.framework */; }; AD2B8823198D631B0070367B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2B8822198D631B0070367B /* UIKit.framework */; }; @@ -26,6 +27,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 19A176455D27298FE4041DC3 /* OnlineMedia.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = OnlineMedia.plist; sourceTree = ""; }; AD2B881B198D631B0070367B /* GstPlay.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GstPlay.app; sourceTree = BUILT_PRODUCTS_DIR; }; AD2B881E198D631B0070367B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; AD2B8820198D631B0070367B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; @@ -113,6 +115,7 @@ AD2B885F198D65780070367B /* VideoViewController.h */, AD2B8860198D65780070367B /* VideoViewController.m */, AD2B8827198D631B0070367B /* Supporting Files */, + 19A176455D27298FE4041DC3 /* OnlineMedia.plist */, ); path = GstPlay; sourceTree = ""; @@ -206,6 +209,7 @@ AD2B8835198D631B0070367B /* Ubuntu-R.ttf in Resources */, AD2B8833198D631B0070367B /* fonts.conf in Resources */, AD2B882B198D631B0070367B /* InfoPlist.strings in Resources */, + 19A17EFC8D41A75E8D3DB72E /* OnlineMedia.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/playback/player/ios/GstPlay/LibraryViewController.m b/playback/player/ios/GstPlay/LibraryViewController.m index f1aead5..330328f 100644 --- a/playback/player/ios/GstPlay/LibraryViewController.m +++ b/playback/player/ios/GstPlay/LibraryViewController.m @@ -130,36 +130,7 @@ static NSString *CellIdentifier = @"CellIdentifier"; [entries addObject:[NSString stringWithFormat:@"file://%@/%@", docsPath, e]]; } self->mediaEntries = entries; - - /* Hardcoded list of Online media files */ - entries = [[NSMutableArray alloc] init]; - - // Big Buck Bunny - [entries addObject:@"http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi"]; - [entries addObject:@"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov"]; - [entries addObject:@"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg"]; - [entries addObject:@"http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.avi"]; - - // Sintel - [entries addObject:@"http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/Sintel_Trailer1.480p.DivX_Plus_HD.mkv"]; - [entries addObject:@"http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.mp4"]; - [entries addObject:@"http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.ogv"]; - [entries addObject:@"http://mirrorblender.top-ix.org/movies/sintel-1024-surround.mp4"]; - - // Tears of Steel - [entries addObject:@"http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mkv"]; - [entries addObject:@"http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mov"]; - [entries addObject:@"http://media.xiph.org/mango/tears_of_steel_1080p.webm"]; - - // Radio stations - [entries addObject:@"http://radio.hbr1.com:19800/trance.ogg"]; - [entries addObject:@"http://radio.hbr1.com:19800/tronic.aac"]; - - // Non-existing entries (to debug error reporting facilities) - [entries addObject:@"http://non-existing.org/Non_Existing_Server"]; - [entries addObject:@"http://docs.gstreamer.com/Non_Existing_File"]; - - self->onlineEntries = entries; + self->onlineEntries = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"OnlineMedia" withExtension:@"plist"]]; } @end diff --git a/playback/player/ios/GstPlay/OnlineMedia.plist b/playback/player/ios/GstPlay/OnlineMedia.plist new file mode 100644 index 0000000..3a1c6c4 --- /dev/null +++ b/playback/player/ios/GstPlay/OnlineMedia.plist @@ -0,0 +1,30 @@ + + + + + + http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_surround-fix.avi + http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov + http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg + http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.avi + + + http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/Sintel_Trailer1.480p.DivX_Plus_HD.mkv + http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.mp4 + http://ftp.nluug.nl/ftp/graphics/blender/apricot/trailer/sintel_trailer-480p.ogv + http://mirrorblender.top-ix.org/movies/sintel-1024-surround.mp4 + + + http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mkv + http://blender-mirror.kino3d.org/mango/download.blender.org/demo/movies/ToS/tears_of_steel_720p.mov + http://media.xiph.org/mango/tears_of_steel_1080p.webm + + + http://radio.hbr1.com:19800/trance.ogg + http://radio.hbr1.com:19800/tronic.aac + + + http://non-existing.org/Non_Existing_Server + http://docs.gstreamer.com/Non_Existing_File + + -- cgit v1.2.3 From d270aec9d139c6201e405fac7b0a3781fdb460d3 Mon Sep 17 00:00:00 2001 From: Jan Berkel Date: Thu, 23 Apr 2015 13:02:34 +0100 Subject: playback/player: ios: Make sure dimensions are valid Layouting code crashes if 0/0 get passed https://github.com/sdroege/gst-player/pull/22 --- playback/player/ios/GstPlay/VideoViewController.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index 150c72a..5c752f2 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -159,7 +159,9 @@ static void video_dimensions_changed (GstPlayer * unused, gint width, gint height, VideoViewController * self) { dispatch_async(dispatch_get_main_queue(), ^{ - [self videoDimensionsChanged:width height:height]; + if (width > 0 && height > 0) { + [self videoDimensionsChanged:width height:height]; + } }); } -- cgit v1.2.3 From 7ca4b495c239228f8ce0c4fa1588000945c0e407 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 25 Apr 2015 14:03:12 +0200 Subject: playback/player: gst-play: Fix compiler warning gst-play.c:89:11: error: comparison of unsigned expression >= 0 is always true [-Werror,-Wtautological-compare] if (pos >= 0 && dur > 0) { ~~~ ^ ~ --- playback/player/gst-play/gst-play.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 6fc73bb..9db6d55 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -86,7 +86,7 @@ position_updated_cb (GstPlayer * player, GstClockTime pos, GstPlay * play) memset (status, ' ', sizeof (status) - 1); - if (pos >= 0 && dur > 0) { + if (pos != -1 && dur > 0 && dur != -1) { gchar dstr[32], pstr[32]; /* FIXME: pretty print in nicer format */ -- cgit v1.2.3 From 34c7b459066832e516933ec9168284fd5f4c8f4d Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 22 Apr 2015 17:39:50 -0500 Subject: playback/player: player: Add media information API https://github.com/sdroege/gst-player/pull/21 --- playback/player/gst-play/gst-play.c | 234 +++++++++++++++++++++++++++++++++++- 1 file changed, 232 insertions(+), 2 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 9db6d55..0b5c5b8 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -110,6 +110,224 @@ buffering_cb (GstPlayer * player, gint percent, GstPlay * play) g_print ("Buffering: %d\n", percent); } +static void +print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data) +{ + gint i, num; + + num = gst_tag_list_get_tag_size (list, tag); + for (i = 0; i < num; ++i) { + const GValue *val; + + val = gst_tag_list_get_value_index (list, tag, i); + if (G_VALUE_HOLDS_STRING (val)) { + g_print (" %s : %s \n", tag, g_value_get_string (val)); + } else if (G_VALUE_HOLDS_UINT (val)) { + g_print (" %s : %u \n", tag, g_value_get_uint (val)); + } else if (G_VALUE_HOLDS_DOUBLE (val)) { + g_print (" %s : %g \n", tag, g_value_get_double (val)); + } else if (G_VALUE_HOLDS_BOOLEAN (val)) { + g_print (" %s : %s \n", tag, + g_value_get_boolean (val) ? "true" : "false"); + } else if (GST_VALUE_HOLDS_DATE_TIME (val)) { + GstDateTime *dt = g_value_get_boxed (val); + gchar *dt_str = gst_date_time_to_iso8601_string (dt); + + g_print (" %s : %s \n", tag, dt_str); + g_free (dt_str); + } else { + g_print (" %s : tag of type '%s' \n", tag, G_VALUE_TYPE_NAME (val)); + } + } +} + +static void +print_video_info (GstPlayerVideoInfo * info) +{ + gint fps_n, fps_d; + guint par_n, par_d; + + if (info == NULL) + return; + + g_print (" width : %d\n", gst_player_video_info_get_width (info)); + g_print (" height : %d\n", gst_player_video_info_get_height (info)); + g_print (" max_bitrate : %d\n", + gst_player_video_info_get_max_bitrate (info)); + g_print (" bitrate : %d\n", gst_player_video_info_get_bitrate (info)); + gst_player_video_info_get_framerate (info, &fps_n, &fps_d); + g_print (" frameate : %.2f\n", (gdouble) fps_n / fps_d); + gst_player_video_info_get_pixel_aspect_ratio (info, &par_n, &par_d); + g_print (" pixel-aspect-ratio %u:%u\n", par_n, par_d); +} + +static void +print_audio_info (GstPlayerAudioInfo * info) +{ + if (info == NULL) + return; + + g_print (" sample rate : %d\n", + gst_player_audio_info_get_sample_rate (info)); + g_print (" channels : %d\n", gst_player_audio_info_get_channels (info)); + g_print (" max_bitrate : %d\n", + gst_player_audio_info_get_max_bitrate (info)); + g_print (" bitrate : %d\n", gst_player_audio_info_get_bitrate (info)); + g_print (" language : %s\n", gst_player_audio_info_get_language (info)); +} + +static void +print_subtitle_info (GstPlayerSubtitleInfo * info) +{ + if (info == NULL) + return; + + g_print (" language : %s\n", gst_player_subtitle_get_language (info)); +} + +static void +print_all_stream_info (GstPlayerMediaInfo * media_info) +{ + guint count = 0; + GList *l, *list; + + list = gst_player_media_info_get_stream_list (media_info); + g_print ("URI : %s\n", gst_player_media_info_get_uri (media_info)); + g_print ("Duration: %" GST_TIME_FORMAT "\n", + GST_TIME_ARGS (gst_player_media_info_get_duration (media_info))); + for (l = list; l != NULL; l = l->next) { + GstTagList *tags = NULL; + GstPlayerStreamInfo *stream = (GstPlayerStreamInfo *) l->data; + + g_print (" Stream # %u \n", count++); + g_print (" type : %s_%u\n", + gst_player_stream_info_get_stream_type_nick (stream), + gst_player_stream_info_get_stream_index (stream)); + tags = gst_player_stream_info_get_stream_tags (stream); + g_print (" taglist : \n"); + if (tags) { + gst_tag_list_foreach (tags, print_one_tag, NULL); + } + + if (GST_IS_PLAYER_VIDEO_INFO (stream)) + print_video_info ((GstPlayerVideoInfo *) stream); + else if (GST_IS_PLAYER_AUDIO_INFO (stream)) + print_audio_info ((GstPlayerAudioInfo *) stream); + else + print_subtitle_info ((GstPlayerSubtitleInfo *) stream); + } +} + +static void +print_all_video_stream (GstPlayerMediaInfo * media_info) +{ + GList *list = NULL, *l; + + list = gst_player_get_video_streams (media_info); + if (!list) + return; + + g_print ("All video streams\n"); + for (l = list; l != NULL; l = l->next) { + GstPlayerVideoInfo *info = (GstPlayerVideoInfo *) l->data; + GstPlayerStreamInfo *sinfo = (GstPlayerStreamInfo *) info; + g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type_nick (sinfo), + gst_player_stream_info_get_stream_index (sinfo)); + print_video_info (info); + } +} + +static void +print_all_subtitle_stream (GstPlayerMediaInfo * media_info) +{ + GList *list = NULL, *l; + + list = gst_player_get_subtitle_streams (media_info); + if (!list) + return; + + g_print ("All subtitle streams:\n"); + for (l = list; l != NULL; l = l->next) { + GstPlayerSubtitleInfo *info = (GstPlayerSubtitleInfo *) l->data; + GstPlayerStreamInfo *sinfo = (GstPlayerStreamInfo *) info; + g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type_nick (sinfo), + gst_player_stream_info_get_stream_index (sinfo)); + print_subtitle_info (info); + } +} + +static void +print_all_audio_stream (GstPlayerMediaInfo * media_info) +{ + GList *list = NULL, *l; + + list = gst_player_get_audio_streams (media_info); + if (!list) + return; + + g_print ("All audio streams: \n"); + for (l = list; l != NULL; l = l->next) { + GstPlayerAudioInfo *info = (GstPlayerAudioInfo *) l->data; + GstPlayerStreamInfo *sinfo = (GstPlayerStreamInfo *) info; + g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type_nick (sinfo), + gst_player_stream_info_get_stream_index (sinfo)); + print_audio_info (info); + } +} + +static void +print_current_tracks (GstPlay * play) +{ + GstPlayerAudioInfo *audio = NULL; + GstPlayerVideoInfo *video = NULL; + GstPlayerSubtitleInfo *subtitle = NULL; + + g_print ("Current video track: \n"); + video = gst_player_get_current_video_track (play->player); + print_video_info (video); + + g_print ("Current audio track: \n"); + audio = gst_player_get_current_audio_track (play->player); + print_audio_info (audio); + + g_print ("Current subtitle track: \n"); + subtitle = gst_player_get_current_subtitle_track (play->player); + print_subtitle_info (subtitle); + + if (audio) + g_object_unref (audio); + + if (video) + g_object_unref (video); + + if (subtitle) + g_object_unref (subtitle); +} + +static void +print_media_info (GstPlayerMediaInfo * media_info) +{ + print_all_stream_info (media_info); + g_print ("\n"); + print_all_video_stream (media_info); + g_print ("\n"); + print_all_audio_stream (media_info); + g_print ("\n"); + print_all_subtitle_stream (media_info); +} + +static void +media_info_cb (GstPlayer * player, GstPlayerMediaInfo * info, GstPlay * play) +{ + static int once = 0; + + if (!once) { + print_media_info (info); + print_current_tracks (play); + once = 1; + } +} + static GstPlay * play_new (gchar ** uris, gdouble initial_volume) { @@ -128,12 +346,14 @@ play_new (gchar ** uris, gdouble initial_volume) G_CALLBACK (position_updated_cb), play); g_signal_connect (play->player, "state-changed", G_CALLBACK (state_changed_cb), play); - g_signal_connect (play->player, "buffering", - G_CALLBACK (buffering_cb), play); + g_signal_connect (play->player, "buffering", G_CALLBACK (buffering_cb), play); g_signal_connect (play->player, "end-of-stream", G_CALLBACK (end_of_stream_cb), play); g_signal_connect (play->player, "error", G_CALLBACK (error_cb), play); + g_signal_connect (play->player, "media-info-updated", + G_CALLBACK (media_info_cb), play); + play->loop = g_main_loop_new (NULL, FALSE); play->desired_state = GST_STATE_PLAYING; @@ -347,6 +567,16 @@ keyboard_cb (const gchar * key_input, gpointer user_data) GstPlay *play = (GstPlay *) user_data; switch (g_ascii_tolower (key_input[0])) { + case 'i': + { + GstPlayerMediaInfo *media_info = gst_player_get_media_info (play->player); + if (media_info) { + print_media_info (media_info); + g_object_unref (media_info); + print_current_tracks (play); + } + break; + } case ' ': toggle_paused (play); break; -- cgit v1.2.3 From da76b893c7f09aef7de03c9282c9a304d32157af Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 25 Apr 2015 14:32:52 +0200 Subject: playback/player: gst-play: Add copyright notice for Brijesh Singh --- playback/player/gst-play/gst-play.c | 1 + 1 file changed, 1 insertion(+) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 0b5c5b8..57e2ecf 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -3,6 +3,7 @@ * Copyright (C) 2013-2014 Tim-Philipp Müller * Copyright (C) 2013 Collabora Ltd. * Copyright (C) 2014 Sebastian Dröge + * Copyright (C) 2015 Brijesh Singh * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public -- cgit v1.2.3 From 2cfa987d8981436ea43faafeccd49d0eb82952d8 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 25 Apr 2015 19:30:55 +0200 Subject: playback/player: player: Rename gst_player_subtitle_get_language() to gst_player_subtitle_info_get_language() --- playback/player/gst-play/gst-play.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 57e2ecf..36f4889 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -157,7 +157,7 @@ print_video_info (GstPlayerVideoInfo * info) gst_player_video_info_get_max_bitrate (info)); g_print (" bitrate : %d\n", gst_player_video_info_get_bitrate (info)); gst_player_video_info_get_framerate (info, &fps_n, &fps_d); - g_print (" frameate : %.2f\n", (gdouble) fps_n / fps_d); + g_print (" framerate : %.2f\n", (gdouble) fps_n / fps_d); gst_player_video_info_get_pixel_aspect_ratio (info, &par_n, &par_d); g_print (" pixel-aspect-ratio %u:%u\n", par_n, par_d); } @@ -183,7 +183,7 @@ print_subtitle_info (GstPlayerSubtitleInfo * info) if (info == NULL) return; - g_print (" language : %s\n", gst_player_subtitle_get_language (info)); + g_print (" language : %s\n", gst_player_subtitle_info_get_language (info)); } static void -- cgit v1.2.3 From 3180177fc7af7ed62c1aec2813daf164749fc3e0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 25 Apr 2015 19:37:39 +0200 Subject: playback/player: player: Rename some more functions for consistency --- playback/player/gst-play/gst-play.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 36f4889..299f00f 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -202,9 +202,9 @@ print_all_stream_info (GstPlayerMediaInfo * media_info) g_print (" Stream # %u \n", count++); g_print (" type : %s_%u\n", - gst_player_stream_info_get_stream_type_nick (stream), - gst_player_stream_info_get_stream_index (stream)); - tags = gst_player_stream_info_get_stream_tags (stream); + gst_player_stream_info_get_stream_type (stream), + gst_player_stream_info_get_index (stream)); + tags = gst_player_stream_info_get_tags (stream); g_print (" taglist : \n"); if (tags) { gst_tag_list_foreach (tags, print_one_tag, NULL); @@ -232,8 +232,8 @@ print_all_video_stream (GstPlayerMediaInfo * media_info) for (l = list; l != NULL; l = l->next) { GstPlayerVideoInfo *info = (GstPlayerVideoInfo *) l->data; GstPlayerStreamInfo *sinfo = (GstPlayerStreamInfo *) info; - g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type_nick (sinfo), - gst_player_stream_info_get_stream_index (sinfo)); + g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type (sinfo), + gst_player_stream_info_get_index (sinfo)); print_video_info (info); } } @@ -251,8 +251,8 @@ print_all_subtitle_stream (GstPlayerMediaInfo * media_info) for (l = list; l != NULL; l = l->next) { GstPlayerSubtitleInfo *info = (GstPlayerSubtitleInfo *) l->data; GstPlayerStreamInfo *sinfo = (GstPlayerStreamInfo *) info; - g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type_nick (sinfo), - gst_player_stream_info_get_stream_index (sinfo)); + g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type (sinfo), + gst_player_stream_info_get_index (sinfo)); print_subtitle_info (info); } } @@ -270,8 +270,8 @@ print_all_audio_stream (GstPlayerMediaInfo * media_info) for (l = list; l != NULL; l = l->next) { GstPlayerAudioInfo *info = (GstPlayerAudioInfo *) l->data; GstPlayerStreamInfo *sinfo = (GstPlayerStreamInfo *) info; - g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type_nick (sinfo), - gst_player_stream_info_get_stream_index (sinfo)); + g_print (" %s_%d #\n", gst_player_stream_info_get_stream_type (sinfo), + gst_player_stream_info_get_index (sinfo)); print_audio_info (info); } } -- cgit v1.2.3 From 81238fdbcd73026497fe3ffd8bbf0c71c78288df Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Sun, 26 Apr 2015 11:01:44 -0500 Subject: playback/player: gtk-play: add media information window --- playback/player/gtk/gtk-play.c | 359 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 357 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index e3ebea1..8705f96 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1,6 +1,7 @@ /* GStreamer * * Copyright (C) 2014-2015 Sebastian Dröge + * Copyright (C) 2015 Brijesh Singh * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -51,10 +52,37 @@ typedef struct GtkWidget *seekbar; GtkWidget *video_area; GtkWidget *volume_button; + GtkWidget *media_info; gulong seekbar_value_changed_signal_id; gboolean playing; } GtkPlay; +enum { + COL_TEXT = 0, + COL_NUM +}; + +enum { + VIDEO_INFO_START, + VIDEO_INFO_RESOLUTION, + VIDEO_INFO_FPS, + VIDEO_INFO_PAR, + VIDEO_INFO_CODEC, + VIDEO_INFO_MAX_BITRATE, + VIDEO_INFO_END, + AUDIO_INFO_START, + AUDIO_INFO_CHANNELS, + AUDIO_INFO_RATE, + AUDIO_INFO_LANGUAGE, + AUDIO_INFO_CODEC, + AUDIO_INFO_MAX_BITRATE, + AUDIO_INFO_END, + SUBTITLE_INFO_START, + SUBTITLE_INFO_LANGUAGE, + SUBTITLE_INFO_CODEC, + SUBTITLE_INFO_END, +}; + static void set_title (GtkPlay * play, const gchar * title) { @@ -133,6 +161,7 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) g_return_if_fail (prev != NULL); gtk_widget_set_sensitive (play->next_button, TRUE); + gtk_widget_set_sensitive (play->media_info, FALSE); gst_player_set_uri (play->player, prev->data); gst_player_play (play->player); set_title (play, prev->data); @@ -153,12 +182,318 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) g_return_if_fail (next != NULL); gtk_widget_set_sensitive (play->prev_button, TRUE); + gtk_widget_set_sensitive (play->media_info, FALSE); gst_player_set_uri (play->player, next->data); gst_player_play (play->player); set_title (play, next->data); gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); } +static gchar* +stream_info_get_string (GstPlayerStreamInfo *stream, gint type, + gboolean label) +{ + switch (type) { + case AUDIO_INFO_RATE: + { + gchar *buffer; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + buffer = g_strdup_printf ("%s%d", label ? "Sample rate : " : "", + gst_player_audio_info_get_sample_rate (audio)); + return buffer; + } + case AUDIO_INFO_LANGUAGE: + { + gchar *buffer; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", + gst_player_audio_info_get_language (audio)); + return buffer; + } + case AUDIO_INFO_CHANNELS: + { + gchar *buffer; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + buffer = g_strdup_printf ("%s%d", label ? "Channels : " : "", + gst_player_audio_info_get_channels (audio)); + return buffer; + } + case SUBTITLE_INFO_CODEC: + case VIDEO_INFO_CODEC: + case AUDIO_INFO_CODEC: + { + gchar *buffer; + buffer = g_strdup_printf ("%s%s", label ? "Codec : " : "", + gst_player_stream_info_get_codec (stream)); + return buffer; + } + case AUDIO_INFO_MAX_BITRATE: + { + gchar *buffer = NULL; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + gint bitrate = gst_player_audio_info_get_max_bitrate (audio); + + if (bitrate > 0) + buffer = g_strdup_printf ("%s%d", label ? "Max bitrate : " : "", + bitrate); + return buffer; + } + case VIDEO_INFO_MAX_BITRATE: + { + gchar *buffer = NULL; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + gint bitrate = gst_player_video_info_get_max_bitrate (video); + + if (bitrate > 0) + buffer = g_strdup_printf ("%s%d", label ? "Max bitrate : " : "", + bitrate); + return buffer; + } + case VIDEO_INFO_PAR: + { + gint par_d, par_n; + gchar *buffer; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + + gst_player_video_info_get_pixel_aspect_ratio (video, &par_n, &par_d); + buffer = g_strdup_printf ("%s%d:%d", label ? "pixel-aspect-ratio : " : + "", par_n, par_d); + return buffer; + } + case VIDEO_INFO_FPS: + { + gint fps_d, fps_n; + gchar *buffer; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + + gst_player_video_info_get_framerate (video, &fps_n, &fps_d); + buffer = g_strdup_printf ("%s%.2f", label ? "Framerate : " : "", + (gdouble)fps_n/fps_d); + return buffer; + } + case VIDEO_INFO_RESOLUTION: + { + gchar *buffer; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + buffer = g_strdup_printf ("%s%dx%d", label ? "Resolution : " : "", + gst_player_video_info_get_width (video), + gst_player_video_info_get_height (video)); + return buffer; + } + case SUBTITLE_INFO_LANGUAGE: + { + gchar *buffer; + GstPlayerSubtitleInfo *sub = (GstPlayerSubtitleInfo*)stream; + buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", + gst_player_subtitle_info_get_language (sub)); + return buffer; + } + default: + { + return NULL; + } + } +} + +static gboolean +is_current_stream (GtkPlay *play, GstPlayerStreamInfo *stream) +{ + gboolean ret = FALSE; + GstPlayerStreamInfo *s; + GstPlayerVideoInfo *video = gst_player_get_current_video_track(play->player); + GstPlayerAudioInfo *audio = gst_player_get_current_audio_track(play->player); + GstPlayerSubtitleInfo *sub = gst_player_get_current_subtitle_track(play->player); + + if (GST_IS_PLAYER_VIDEO_INFO(stream)) + s = (GstPlayerStreamInfo*) video; + else if (GST_IS_PLAYER_AUDIO_INFO(stream)) + s = (GstPlayerStreamInfo*) audio; + else + s = (GstPlayerStreamInfo*) sub; + + if (s) + if (gst_player_stream_info_get_index (stream) == + gst_player_stream_info_get_index (s)) + ret = TRUE; + + if (audio) + g_object_unref (audio); + + if (video) + g_object_unref (video); + + if (sub) + g_object_unref (sub); + + return ret; +} + +static GtkTreeModel* +create_and_fill_model (GtkPlay *play, GstPlayerMediaInfo *info) +{ + GList *l; + guint count; + GtkTreeStore *tree; + GtkTreeIter child, parent; + + count = 0; + tree = gtk_tree_store_new (COL_NUM, G_TYPE_STRING); + + for (l = gst_player_media_info_get_stream_list(info); + l != NULL; l = l->next) { + gchar *buffer; + gint i, start, end; + GstPlayerStreamInfo *stream = (GstPlayerStreamInfo*) l->data; + + /* define the field range based on stream type */ + if (GST_IS_PLAYER_VIDEO_INFO(stream)) { + start = VIDEO_INFO_START + 1; + end = VIDEO_INFO_END; + } else if (GST_IS_PLAYER_AUDIO_INFO(stream)) { + start = AUDIO_INFO_START + 1; + end = AUDIO_INFO_END; + } else { + start = SUBTITLE_INFO_START + 1; + end = SUBTITLE_INFO_END; + } + + buffer = g_strdup_printf ("Stream %u %s", count++, + is_current_stream (play, stream) ? "(current)" : ""); + gtk_tree_store_append (tree, &parent, NULL); + gtk_tree_store_set (tree, &parent, COL_TEXT, buffer, -1); + g_free (buffer); + + buffer = g_strdup_printf ("Type : %s", + gst_player_stream_info_get_stream_type (stream)); + gtk_tree_store_append (tree, &child, &parent ); + gtk_tree_store_set (tree, &child, COL_TEXT, buffer, -1); + g_free (buffer); + + for (i = start; i < end; i++) { + buffer = stream_info_get_string (stream, i, TRUE); + if (buffer) { + gtk_tree_store_append (tree, &child, &parent); + gtk_tree_store_set (tree, &child, COL_TEXT, buffer, -1); + g_free (buffer); + } + } + } + + return GTK_TREE_MODEL(tree); +} + +static GtkWidget* +create_view_and_model (GtkPlay *play, GstPlayerMediaInfo *info) +{ + GtkWidget *view; + GtkTreeModel *model; + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + + view = gtk_tree_view_new (); + col = gtk_tree_view_column_new (); + gtk_tree_view_append_column (GTK_TREE_VIEW(view), col); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (col, renderer, TRUE); + gtk_tree_view_column_add_attribute (col, renderer, "text", COL_TEXT); + + model = create_and_fill_model (play, info); + gtk_tree_view_set_model (GTK_TREE_VIEW(view), model); + g_object_unref (model); + + return view; +} + +static void +delete_media_info_window (GtkWidget *button, GtkWindow *window) +{ + gtk_window_close (window); +} + +static void +create_media_info_window (GtkPlay *play, GstPlayerMediaInfo *info) +{ + GtkWidget *sw; + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *view; + GtkWidget *hbox; + GtkWidget *uri; + GtkWidget *loc; + GtkTextIter iter; + GtkWidget *window; + GtkTextBuffer *buffer; + GtkWidget *hbox_close; + GtkWidget *button_close; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW(window), "Media information"); + gtk_window_set_default_size (GTK_WINDOW(window), 550, 450); + gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_container_set_border_width (GTK_CONTAINER(window), 10); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); + gtk_container_add (GTK_CONTAINER(window), vbox); + + label = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL(label), + "Information about all the streams contains in your media. \n" + "Current selected streams are marked as (current)."); + gtk_label_set_justify (GTK_LABEL(label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 2); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), + GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start (GTK_BOX(vbox), sw, TRUE, TRUE, 0); + + view = create_view_and_model (play, info); + gtk_container_add (GTK_CONTAINER(sw), view); + g_signal_connect (view, "realize", + G_CALLBACK(gtk_tree_view_expand_all), NULL); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); + gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + + loc = gtk_label_new ("Location : "); + gtk_box_pack_start (GTK_BOX(hbox), loc, FALSE, FALSE, 2); + + buffer = gtk_text_buffer_new (NULL); + gtk_text_buffer_get_start_iter (buffer, &iter); + gtk_text_buffer_insert (buffer, &iter, + gst_player_media_info_get_uri (info), -1); + uri = gtk_text_view_new_with_buffer (buffer); + gtk_box_pack_start (GTK_BOX(hbox), uri, FALSE, FALSE, 2); + gtk_text_view_set_editable (GTK_TEXT_VIEW(uri), FALSE); + g_object_unref (buffer); + + hbox_close = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); + gtk_box_pack_start (GTK_BOX(vbox), hbox_close, FALSE, FALSE, 2); + button_close = gtk_button_new_with_label (" Close "); + g_signal_connect (button_close, "clicked", + G_CALLBACK(delete_media_info_window), window); + gtk_box_pack_end (GTK_BOX(hbox_close), button_close, FALSE, FALSE, 3); + + gtk_widget_show_all (window); +} + +static void +media_info_clicked_cb (GtkButton *button, GtkPlay *play) +{ + GstPlayerMediaInfo *info; + + info = gst_player_get_media_info (play->player); + if (!info) + return; + + create_media_info_window (play, info); + + g_object_unref (info); +} + static void seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) { @@ -224,13 +559,21 @@ create_ui (GtkPlay * play) g_signal_connect (G_OBJECT (play->volume_button), "value-changed", G_CALLBACK (volume_changed_cb), play); + /* media information button */ + play->media_info = gtk_button_new_from_icon_name ("dialog-information", + GTK_ICON_SIZE_BUTTON); + g_signal_connect (G_OBJECT (play->media_info), "clicked", + G_CALLBACK (media_info_clicked_cb), play); + gtk_widget_set_sensitive (play->media_info, FALSE); + controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, - 2); + gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, + FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->media_info, FALSE, FALSE, 2); main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); @@ -300,6 +643,8 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); + gtk_widget_set_sensitive (play->media_info, FALSE); + gst_player_set_uri (play->player, next->data); gst_player_play (play->player); set_title (play, next->data); @@ -316,6 +661,14 @@ eos_cb (GstPlayer * unused, GtkPlay * play) } } +static void +media_info_updated_cb (GstPlayer *player, GstPlayerMediaInfo *media_info, + GtkPlay *play) +{ + if (!gtk_widget_is_sensitive (play->media_info)) + gtk_widget_set_sensitive (play->media_info, TRUE); +} + int main (gint argc, gchar ** argv) { @@ -403,6 +756,8 @@ main (gint argc, gchar ** argv) g_signal_connect (play.player, "video-dimensions-changed", G_CALLBACK (video_dimensions_changed_cb), &play); g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); + g_signal_connect (play.player, "media-info-updated", + G_CALLBACK (media_info_updated_cb), &play); /* We have file(s) that need playing. */ set_title (&play, g_list_first (play.uris)->data); -- cgit v1.2.3 From bf8604dcf352948e3b6926290539cc716ff0d263 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sun, 26 Apr 2015 18:31:30 +0200 Subject: playback/player: player/gtk: Fix indention --- playback/player/gtk/gtk-play.c | 153 +++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 8705f96..c14967f 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -57,12 +57,14 @@ typedef struct gboolean playing; } GtkPlay; -enum { +enum +{ COL_TEXT = 0, COL_NUM }; -enum { +enum +{ VIDEO_INFO_START, VIDEO_INFO_RESOLUTION, VIDEO_INFO_FPS, @@ -189,33 +191,32 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); } -static gchar* -stream_info_get_string (GstPlayerStreamInfo *stream, gint type, - gboolean label) +static gchar * +stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) { switch (type) { case AUDIO_INFO_RATE: { gchar *buffer; - GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; buffer = g_strdup_printf ("%s%d", label ? "Sample rate : " : "", - gst_player_audio_info_get_sample_rate (audio)); + gst_player_audio_info_get_sample_rate (audio)); return buffer; } case AUDIO_INFO_LANGUAGE: { gchar *buffer; - GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", - gst_player_audio_info_get_language (audio)); + gst_player_audio_info_get_language (audio)); return buffer; } case AUDIO_INFO_CHANNELS: { gchar *buffer; - GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; buffer = g_strdup_printf ("%s%d", label ? "Channels : " : "", - gst_player_audio_info_get_channels (audio)); + gst_player_audio_info_get_channels (audio)); return buffer; } case SUBTITLE_INFO_CODEC: @@ -224,13 +225,13 @@ stream_info_get_string (GstPlayerStreamInfo *stream, gint type, { gchar *buffer; buffer = g_strdup_printf ("%s%s", label ? "Codec : " : "", - gst_player_stream_info_get_codec (stream)); + gst_player_stream_info_get_codec (stream)); return buffer; } case AUDIO_INFO_MAX_BITRATE: { gchar *buffer = NULL; - GstPlayerAudioInfo *audio = (GstPlayerAudioInfo*)stream; + GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; gint bitrate = gst_player_audio_info_get_max_bitrate (audio); if (bitrate > 0) @@ -241,7 +242,7 @@ stream_info_get_string (GstPlayerStreamInfo *stream, gint type, case VIDEO_INFO_MAX_BITRATE: { gchar *buffer = NULL; - GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gint bitrate = gst_player_video_info_get_max_bitrate (video); if (bitrate > 0) @@ -253,7 +254,7 @@ stream_info_get_string (GstPlayerStreamInfo *stream, gint type, { gint par_d, par_n; gchar *buffer; - GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gst_player_video_info_get_pixel_aspect_ratio (video, &par_n, &par_d); buffer = g_strdup_printf ("%s%d:%d", label ? "pixel-aspect-ratio : " : @@ -264,28 +265,28 @@ stream_info_get_string (GstPlayerStreamInfo *stream, gint type, { gint fps_d, fps_n; gchar *buffer; - GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gst_player_video_info_get_framerate (video, &fps_n, &fps_d); buffer = g_strdup_printf ("%s%.2f", label ? "Framerate : " : "", - (gdouble)fps_n/fps_d); + (gdouble) fps_n / fps_d); return buffer; } case VIDEO_INFO_RESOLUTION: { gchar *buffer; - GstPlayerVideoInfo *video = (GstPlayerVideoInfo*)stream; + GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; buffer = g_strdup_printf ("%s%dx%d", label ? "Resolution : " : "", - gst_player_video_info_get_width (video), - gst_player_video_info_get_height (video)); + gst_player_video_info_get_width (video), + gst_player_video_info_get_height (video)); return buffer; } case SUBTITLE_INFO_LANGUAGE: { gchar *buffer; - GstPlayerSubtitleInfo *sub = (GstPlayerSubtitleInfo*)stream; + GstPlayerSubtitleInfo *sub = (GstPlayerSubtitleInfo *) stream; buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", - gst_player_subtitle_info_get_language (sub)); + gst_player_subtitle_info_get_language (sub)); return buffer; } default: @@ -296,20 +297,21 @@ stream_info_get_string (GstPlayerStreamInfo *stream, gint type, } static gboolean -is_current_stream (GtkPlay *play, GstPlayerStreamInfo *stream) +is_current_stream (GtkPlay * play, GstPlayerStreamInfo * stream) { gboolean ret = FALSE; GstPlayerStreamInfo *s; - GstPlayerVideoInfo *video = gst_player_get_current_video_track(play->player); - GstPlayerAudioInfo *audio = gst_player_get_current_audio_track(play->player); - GstPlayerSubtitleInfo *sub = gst_player_get_current_subtitle_track(play->player); - - if (GST_IS_PLAYER_VIDEO_INFO(stream)) - s = (GstPlayerStreamInfo*) video; - else if (GST_IS_PLAYER_AUDIO_INFO(stream)) - s = (GstPlayerStreamInfo*) audio; + GstPlayerVideoInfo *video = gst_player_get_current_video_track (play->player); + GstPlayerAudioInfo *audio = gst_player_get_current_audio_track (play->player); + GstPlayerSubtitleInfo *sub = + gst_player_get_current_subtitle_track (play->player); + + if (GST_IS_PLAYER_VIDEO_INFO (stream)) + s = (GstPlayerStreamInfo *) video; + else if (GST_IS_PLAYER_AUDIO_INFO (stream)) + s = (GstPlayerStreamInfo *) audio; else - s = (GstPlayerStreamInfo*) sub; + s = (GstPlayerStreamInfo *) sub; if (s) if (gst_player_stream_info_get_index (stream) == @@ -328,8 +330,8 @@ is_current_stream (GtkPlay *play, GstPlayerStreamInfo *stream) return ret; } -static GtkTreeModel* -create_and_fill_model (GtkPlay *play, GstPlayerMediaInfo *info) +static GtkTreeModel * +create_and_fill_model (GtkPlay * play, GstPlayerMediaInfo * info) { GList *l; guint count; @@ -339,17 +341,16 @@ create_and_fill_model (GtkPlay *play, GstPlayerMediaInfo *info) count = 0; tree = gtk_tree_store_new (COL_NUM, G_TYPE_STRING); - for (l = gst_player_media_info_get_stream_list(info); - l != NULL; l = l->next) { + for (l = gst_player_media_info_get_stream_list (info); l != NULL; l = l->next) { gchar *buffer; gint i, start, end; - GstPlayerStreamInfo *stream = (GstPlayerStreamInfo*) l->data; + GstPlayerStreamInfo *stream = (GstPlayerStreamInfo *) l->data; /* define the field range based on stream type */ - if (GST_IS_PLAYER_VIDEO_INFO(stream)) { + if (GST_IS_PLAYER_VIDEO_INFO (stream)) { start = VIDEO_INFO_START + 1; end = VIDEO_INFO_END; - } else if (GST_IS_PLAYER_AUDIO_INFO(stream)) { + } else if (GST_IS_PLAYER_AUDIO_INFO (stream)) { start = AUDIO_INFO_START + 1; end = AUDIO_INFO_END; } else { @@ -364,8 +365,8 @@ create_and_fill_model (GtkPlay *play, GstPlayerMediaInfo *info) g_free (buffer); buffer = g_strdup_printf ("Type : %s", - gst_player_stream_info_get_stream_type (stream)); - gtk_tree_store_append (tree, &child, &parent ); + gst_player_stream_info_get_stream_type (stream)); + gtk_tree_store_append (tree, &child, &parent); gtk_tree_store_set (tree, &child, COL_TEXT, buffer, -1); g_free (buffer); @@ -379,11 +380,11 @@ create_and_fill_model (GtkPlay *play, GstPlayerMediaInfo *info) } } - return GTK_TREE_MODEL(tree); + return GTK_TREE_MODEL (tree); } -static GtkWidget* -create_view_and_model (GtkPlay *play, GstPlayerMediaInfo *info) +static GtkWidget * +create_view_and_model (GtkPlay * play, GstPlayerMediaInfo * info) { GtkWidget *view; GtkTreeModel *model; @@ -392,28 +393,28 @@ create_view_and_model (GtkPlay *play, GstPlayerMediaInfo *info) view = gtk_tree_view_new (); col = gtk_tree_view_column_new (); - gtk_tree_view_append_column (GTK_TREE_VIEW(view), col); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (col, renderer, TRUE); gtk_tree_view_column_add_attribute (col, renderer, "text", COL_TEXT); model = create_and_fill_model (play, info); - gtk_tree_view_set_model (GTK_TREE_VIEW(view), model); + gtk_tree_view_set_model (GTK_TREE_VIEW (view), model); g_object_unref (model); return view; } static void -delete_media_info_window (GtkWidget *button, GtkWindow *window) +delete_media_info_window (GtkWidget * button, GtkWindow * window) { gtk_window_close (window); } static void -create_media_info_window (GtkPlay *play, GstPlayerMediaInfo *info) +create_media_info_window (GtkPlay * play, GstPlayerMediaInfo * info) { GtkWidget *sw; GtkWidget *vbox; @@ -429,61 +430,61 @@ create_media_info_window (GtkPlay *play, GstPlayerMediaInfo *info) GtkWidget *button_close; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW(window), "Media information"); - gtk_window_set_default_size (GTK_WINDOW(window), 550, 450); - gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); - gtk_container_set_border_width (GTK_CONTAINER(window), 10); + gtk_window_set_title (GTK_WINDOW (window), "Media information"); + gtk_window_set_default_size (GTK_WINDOW (window), 550, 450); + gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER); + gtk_container_set_border_width (GTK_CONTAINER (window), 10); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); - gtk_container_add (GTK_CONTAINER(window), vbox); + gtk_container_add (GTK_CONTAINER (window), vbox); label = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL(label), - "Information about all the streams contains in your media. \n" - "Current selected streams are marked as (current)."); - gtk_label_set_justify (GTK_LABEL(label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 2); + gtk_label_set_markup (GTK_LABEL (label), + "Information about all the streams contains in your media. \n" + "Current selected streams are marked as (current)."); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 2); sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); - gtk_box_pack_start (GTK_BOX(vbox), sw, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); view = create_view_and_model (play, info); - gtk_container_add (GTK_CONTAINER(sw), view); + gtk_container_add (GTK_CONTAINER (sw), view); g_signal_connect (view, "realize", - G_CALLBACK(gtk_tree_view_expand_all), NULL); + G_CALLBACK (gtk_tree_view_expand_all), NULL); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); - gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); loc = gtk_label_new ("Location : "); - gtk_box_pack_start (GTK_BOX(hbox), loc, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (hbox), loc, FALSE, FALSE, 2); buffer = gtk_text_buffer_new (NULL); gtk_text_buffer_get_start_iter (buffer, &iter); gtk_text_buffer_insert (buffer, &iter, gst_player_media_info_get_uri (info), -1); uri = gtk_text_view_new_with_buffer (buffer); - gtk_box_pack_start (GTK_BOX(hbox), uri, FALSE, FALSE, 2); - gtk_text_view_set_editable (GTK_TEXT_VIEW(uri), FALSE); + gtk_box_pack_start (GTK_BOX (hbox), uri, FALSE, FALSE, 2); + gtk_text_view_set_editable (GTK_TEXT_VIEW (uri), FALSE); g_object_unref (buffer); hbox_close = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); - gtk_box_pack_start (GTK_BOX(vbox), hbox_close, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox_close, FALSE, FALSE, 2); button_close = gtk_button_new_with_label (" Close "); g_signal_connect (button_close, "clicked", - G_CALLBACK(delete_media_info_window), window); - gtk_box_pack_end (GTK_BOX(hbox_close), button_close, FALSE, FALSE, 3); + G_CALLBACK (delete_media_info_window), window); + gtk_box_pack_end (GTK_BOX (hbox_close), button_close, FALSE, FALSE, 3); gtk_widget_show_all (window); } static void -media_info_clicked_cb (GtkButton *button, GtkPlay *play) +media_info_clicked_cb (GtkButton * button, GtkPlay * play) { - GstPlayerMediaInfo *info; + GstPlayerMediaInfo *info; info = gst_player_get_media_info (play->player); if (!info) @@ -561,7 +562,7 @@ create_ui (GtkPlay * play) /* media information button */ play->media_info = gtk_button_new_from_icon_name ("dialog-information", - GTK_ICON_SIZE_BUTTON); + GTK_ICON_SIZE_BUTTON); g_signal_connect (G_OBJECT (play->media_info), "clicked", G_CALLBACK (media_info_clicked_cb), play); gtk_widget_set_sensitive (play->media_info, FALSE); @@ -662,8 +663,8 @@ eos_cb (GstPlayer * unused, GtkPlay * play) } static void -media_info_updated_cb (GstPlayer *player, GstPlayerMediaInfo *media_info, - GtkPlay *play) +media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, + GtkPlay * play) { if (!gtk_widget_is_sensitive (play->media_info)) gtk_widget_set_sensitive (play->media_info, TRUE); -- cgit v1.2.3 From 2a5ba6574f5f2bab44448c54cc1820dd0cbd5ab4 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 4 May 2015 22:37:34 +0200 Subject: playback/player: android: Add gstplayer-media-info.c to the build JNI bindings still need updating for the new media info API. https://github.com/sdroege/gst-player/issues/30 --- playback/player/android/jni/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 439baa9..1925009 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -3,7 +3,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c +LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c ../../lib/gst/player/gstplayer-media-info.c LOCAL_SHARED_LIBRARIES := gstreamer_android LOCAL_LDLIBS := -llog -landroid include $(BUILD_SHARED_LIBRARY) -- cgit v1.2.3 From c3928830cf3a3219ab351b7ca7576ff50262f34d Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Wed, 6 May 2015 10:33:53 +0800 Subject: playback/player: android: remove unused variable 'gst_app_thread' --- playback/player/android/jni/player.c | 1 - 1 file changed, 1 deletion(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index 577fab9..ebfd034 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -40,7 +40,6 @@ typedef struct _Player ANativeWindow *native_window; } Player; -static pthread_t gst_app_thread; static pthread_key_t current_jni_env; static JavaVM *java_vm; static jfieldID native_player_field_id; -- cgit v1.2.3 From 261081aade429107f76755788eab8abd44cab796 Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Wed, 6 May 2015 10:38:25 +0800 Subject: playback/player: android: check return values from JNI methods in 'JNI_OnLoad' --- playback/player/android/jni/player.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index ebfd034..f9fcaea 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -474,8 +474,17 @@ JNI_OnLoad (JavaVM * vm, void *reserved) return 0; } jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); - (*env)->RegisterNatives (env, klass, native_methods, - G_N_ELEMENTS (native_methods)); + if (!klass) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve class org.freedesktop.gstreamer.Player"); + return 0; + } + if ((*env)->RegisterNatives (env, klass, native_methods, + G_N_ELEMENTS (native_methods))) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not register native methods for org.freedesktop.gstreamer.Player"); + return 0; + } pthread_key_create (¤t_jni_env, detach_current_thread); -- cgit v1.2.3 From 696e1c9ab834f00128d0de7260eb8b3b69ef76fd Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Wed, 6 May 2015 10:52:26 +0800 Subject: playback/player: android: fixed compilation error --- playback/player/android/jni/Android.mk | 1 + playback/player/android/jni/player.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 1925009..fe4d50a 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := gstplayer LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c ../../lib/gst/player/gstplayer-media-info.c +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../lib LOCAL_SHARED_LIBRARIES := gstreamer_android LOCAL_LDLIBS := -llog -landroid include $(BUILD_SHARED_LIBRARY) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index f9fcaea..8670b17 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -25,7 +25,7 @@ #include #include -#include "../../lib/gst/player/gstplayer.h" +#include "gst/player/gstplayer.h" GST_DEBUG_CATEGORY_STATIC (debug_category); #define GST_CAT_DEFAULT debug_category -- cgit v1.2.3 From ef751e3dfdf138d84c05d775a057bce4bc9678ac Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 29 Apr 2015 21:56:17 -0500 Subject: playback/player: gst-play: display global taglist --- playback/player/gst-play/gst-play.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 299f00f..ae65092 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -196,6 +196,12 @@ print_all_stream_info (GstPlayerMediaInfo * media_info) g_print ("URI : %s\n", gst_player_media_info_get_uri (media_info)); g_print ("Duration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (gst_player_media_info_get_duration (media_info))); + g_print ("Global taglist:\n"); + if (gst_player_media_info_get_tags (media_info)) + gst_tag_list_foreach (gst_player_media_info_get_tags (media_info), + print_one_tag, NULL); + else + g_print (" (nil) \n"); for (l = list; l != NULL; l = l->next) { GstTagList *tags = NULL; GstPlayerStreamInfo *stream = (GstPlayerStreamInfo *) l->data; -- cgit v1.2.3 From 544c51fe11fe7f4d57c5fccf2466864430f179c0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 6 May 2015 10:58:27 +0200 Subject: playback/player: Fix indention --- playback/player/gst-play/gst-play.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index ae65092..02a36f5 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -199,7 +199,7 @@ print_all_stream_info (GstPlayerMediaInfo * media_info) g_print ("Global taglist:\n"); if (gst_player_media_info_get_tags (media_info)) gst_tag_list_foreach (gst_player_media_info_get_tags (media_info), - print_one_tag, NULL); + print_one_tag, NULL); else g_print (" (nil) \n"); for (l = list; l != NULL; l = l->next) { -- cgit v1.2.3 From 611f3cde4b5619e178fad1bb4ab9b51eff1a484b Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 6 May 2015 06:41:06 -0500 Subject: playback/player: gtk-play: remove gtk deprecated API. --- playback/player/gtk/gtk-play.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index c14967f..246adea 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -443,7 +443,6 @@ create_media_info_window (GtkPlay * play, GstPlayerMediaInfo * info) "Information about all the streams contains in your media. \n" "Current selected streams are marked as (current)."); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 2); sw = gtk_scrolled_window_new (NULL, NULL); @@ -519,7 +518,6 @@ create_ui (GtkPlay * play) set_title (play, APP_NAME); play->video_area = gtk_drawing_area_new (); - gtk_widget_set_double_buffered (play->video_area, FALSE); g_signal_connect (play->video_area, "realize", G_CALLBACK (video_area_realize_cb), play); -- cgit v1.2.3 From 88e7131ae7d060e2aefd6a619fd854e6d0920ef2 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 6 May 2015 06:45:23 -0500 Subject: playback/player: gtk-play: set window title from media information If media contains title then use it to set player window title. --- playback/player/gtk/gtk-play.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 246adea..961fda1 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -664,8 +664,15 @@ static void media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, GtkPlay * play) { - if (!gtk_widget_is_sensitive (play->media_info)) + if (!gtk_widget_is_sensitive (play->media_info)) { + const gchar *title; + + title = gst_player_media_info_get_title (media_info); + if (title) + set_title (play, title); + gtk_widget_set_sensitive (play->media_info, TRUE); + } } int -- cgit v1.2.3 From 653c8c973e6933dad9adc4ab0872e422d587bb2c Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 6 May 2015 06:54:48 -0500 Subject: playback/player: gtk-play: handle duplicate uri in playlist current logic does not play all the files from playlist if the list contains a duplicate uris. --- playback/player/gtk/gtk-play.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 961fda1..b6ff403 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -45,6 +45,7 @@ typedef struct gchar *uri; GList *uris; + GList *current_uri; GtkWidget *window; GtkWidget *play_pause_button; @@ -155,16 +156,13 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) GList *prev; gchar *cur_uri; - prev = g_list_find_custom (play->uris, - gst_player_get_uri (play->player), (GCompareFunc) strcmp); - - g_return_if_fail (prev != NULL); - prev = g_list_previous (prev); + prev = g_list_previous (play->current_uri); g_return_if_fail (prev != NULL); gtk_widget_set_sensitive (play->next_button, TRUE); gtk_widget_set_sensitive (play->media_info, FALSE); gst_player_set_uri (play->player, prev->data); + play->current_uri = prev; gst_player_play (play->player); set_title (play, prev->data); gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); @@ -176,16 +174,13 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) GList *next, *l; gchar *cur_uri; - next = g_list_find_custom (play->uris, - gst_player_get_uri (play->player), (GCompareFunc) strcmp); - - g_return_if_fail (next != NULL); - next = g_list_next (next); + next = g_list_next (play->current_uri); g_return_if_fail (next != NULL); gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->media_info, FALSE); gst_player_set_uri (play->player, next->data); + play->current_uri = next; gst_player_play (play->player); set_title (play, next->data); gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); @@ -631,12 +626,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) GList *next = NULL; gchar *uri; - next = g_list_find_custom (play->uris, - gst_player_get_uri (play->player), (GCompareFunc) strcmp); - - g_return_if_fail (next != NULL); - - next = g_list_next (next); + next = g_list_next (play->current_uri); if (next) { if (!gtk_widget_is_sensitive (play->prev_button)) gtk_widget_set_sensitive (play->prev_button, TRUE); @@ -645,6 +635,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gtk_widget_set_sensitive (play->media_info, FALSE); gst_player_set_uri (play->player, next->data); + play->current_uri = next; gst_player_play (play->player); set_title (play, next->data); } else { @@ -768,6 +759,7 @@ main (gint argc, gchar ** argv) /* We have file(s) that need playing. */ set_title (&play, g_list_first (play.uris)->data); gst_player_play (play.player); + play.current_uri = g_list_first (play.uris); gtk_main (); -- cgit v1.2.3 From bbc6f056b13e4cd3f7f7eabe9b11d5a2b25e88a3 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 6 May 2015 07:04:28 -0500 Subject: playback/player: gtk-play: variable rename for consistency rename media_info varible holding button state to be consistent with others. --- playback/player/gtk/gtk-play.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index b6ff403..8f6a77c 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -53,7 +53,7 @@ typedef struct GtkWidget *seekbar; GtkWidget *video_area; GtkWidget *volume_button; - GtkWidget *media_info; + GtkWidget *media_info_button; gulong seekbar_value_changed_signal_id; gboolean playing; } GtkPlay; @@ -160,7 +160,7 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) g_return_if_fail (prev != NULL); gtk_widget_set_sensitive (play->next_button, TRUE); - gtk_widget_set_sensitive (play->media_info, FALSE); + gtk_widget_set_sensitive (play->media_info_button, FALSE); gst_player_set_uri (play->player, prev->data); play->current_uri = prev; gst_player_play (play->player); @@ -178,7 +178,7 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) g_return_if_fail (next != NULL); gtk_widget_set_sensitive (play->prev_button, TRUE); - gtk_widget_set_sensitive (play->media_info, FALSE); + gtk_widget_set_sensitive (play->media_info_button, FALSE); gst_player_set_uri (play->player, next->data); play->current_uri = next; gst_player_play (play->player); @@ -554,11 +554,11 @@ create_ui (GtkPlay * play) G_CALLBACK (volume_changed_cb), play); /* media information button */ - play->media_info = gtk_button_new_from_icon_name ("dialog-information", + play->media_info_button = gtk_button_new_from_icon_name ("dialog-information", GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->media_info), "clicked", + g_signal_connect (G_OBJECT (play->media_info_button), "clicked", G_CALLBACK (media_info_clicked_cb), play); - gtk_widget_set_sensitive (play->media_info, FALSE); + gtk_widget_set_sensitive (play->media_info_button, FALSE); controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); @@ -567,7 +567,8 @@ create_ui (GtkPlay * play) gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->media_info, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->media_info_button, + FALSE, FALSE, 2); main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); @@ -632,7 +633,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); - gtk_widget_set_sensitive (play->media_info, FALSE); + gtk_widget_set_sensitive (play->media_info_button, FALSE); gst_player_set_uri (play->player, next->data); play->current_uri = next; @@ -655,14 +656,14 @@ static void media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, GtkPlay * play) { - if (!gtk_widget_is_sensitive (play->media_info)) { + if (!gtk_widget_is_sensitive (play->media_info_button)) { const gchar *title; title = gst_player_media_info_get_title (media_info); if (title) set_title (play, title); - gtk_widget_set_sensitive (play->media_info, TRUE); + gtk_widget_set_sensitive (play->media_info_button, TRUE); } } -- cgit v1.2.3 From 1232e80e202d6bd2d9c9d84c6c47e65249bbf0e3 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 6 May 2015 11:56:14 -0500 Subject: playback/player: gtk-play: add track selection menu --- playback/player/gtk/gtk-play.c | 273 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 257 insertions(+), 16 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 8f6a77c..7706b92 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -186,6 +186,18 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); } +static const gchar * +audio_channels_string (gint num) +{ + if (num == 1) + return "mono"; + else if (num == 2) + return "stereo"; + else if (num > 2) + return "surround"; + else + return "unknown"; +} static gchar * stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) { @@ -202,6 +214,8 @@ stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) { gchar *buffer; GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; + if (!gst_player_audio_info_get_language (audio)) + return NULL; buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", gst_player_audio_info_get_language (audio)); return buffer; @@ -210,8 +224,8 @@ stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) { gchar *buffer; GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; - buffer = g_strdup_printf ("%s%d", label ? "Channels : " : "", - gst_player_audio_info_get_channels (audio)); + buffer = g_strdup_printf ("%s%s", label ? "Channels : " : "", + audio_channels_string (gst_player_audio_info_get_channels (audio))); return buffer; } case SUBTITLE_INFO_CODEC: @@ -502,6 +516,240 @@ volume_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) gst_player_set_volume (play->player, value); } +static gint +_get_current_track_index (GtkPlay * play, void * (*func) (GstPlayer * player)) +{ + void *obj; + gint index = -1; + + obj = func (play->player); + if (obj) { + index = gst_player_stream_info_get_index ((GstPlayerStreamInfo*) obj); + g_object_unref (obj); + } + + return index; +} + +static gint +get_current_track_index (GtkPlay * play, GType type) +{ + if (type == GST_TYPE_PLAYER_VIDEO_INFO) + return _get_current_track_index (play, + (void*) gst_player_get_current_video_track); + else if (type == GST_TYPE_PLAYER_AUDIO_INFO) + return _get_current_track_index (play, + (void*) gst_player_get_current_audio_track); + else + return _get_current_track_index (play, + (void*) gst_player_get_current_subtitle_track); +} + +static gchar * +get_menu_label (GstPlayerStreamInfo *stream, GType type) +{ + if (type == GST_TYPE_PLAYER_AUDIO_INFO) { + gchar *label = NULL; + gchar *lang, *codec, *channels; + + /* label format: [language] */ + lang = stream_info_get_string (stream, AUDIO_INFO_LANGUAGE, FALSE); + codec = stream_info_get_string (stream, AUDIO_INFO_CODEC, FALSE); + channels = stream_info_get_string (stream, AUDIO_INFO_CHANNELS, FALSE); + + if (lang) { + label = g_strdup_printf ("%s %s [%s]", codec ? codec : "", + channels ? channels : "", lang); + g_free (lang); + } + else + label = g_strdup_printf ("%s %s", codec ? codec : "", + channels ? channels : ""); + + g_free (codec); + g_free (channels); + return label; + } else if (type == GST_TYPE_PLAYER_VIDEO_INFO) { + /* label format: */ + return stream_info_get_string (stream, VIDEO_INFO_CODEC, FALSE); + } else { + /* label format: */ + return stream_info_get_string (stream, SUBTITLE_INFO_LANGUAGE, FALSE); + } + + return NULL; +} + +static void +disable_track (GtkPlay * play, GType type) +{ + if (type == GST_TYPE_PLAYER_VIDEO_INFO) + gst_player_set_video_track_enabled (play->player, FALSE); + else if (type == GST_TYPE_PLAYER_AUDIO_INFO) + gst_player_set_audio_track_enabled (play->player, FALSE); + else + gst_player_set_subtitle_track_enabled (play->player, FALSE); +} + +static void +change_track (GtkPlay * play, gint index, GType type) +{ + if (type == GST_TYPE_PLAYER_VIDEO_INFO) { + gst_player_set_video_track (play->player, index); + gst_player_set_video_track_enabled (play->player, TRUE); + } else if (type == GST_TYPE_PLAYER_AUDIO_INFO) { + gst_player_set_audio_track (play->player, index); + gst_player_set_audio_track_enabled (play->player, TRUE); + } else { + gst_player_set_subtitle_track (play->player, index); + gst_player_set_subtitle_track_enabled (play->player, TRUE); + } +} + +static void +track_changed_cb (GtkWidget * widget, GtkPlay * play) +{ + GType type; + gint index; + + /* check if button is toggled */ + if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget))) + return; + + index = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(widget), "index")); + type = GPOINTER_TO_SIZE (g_object_get_data(G_OBJECT(widget), "type")); + + if (index == -1) + disable_track (play, type); + else + change_track (play, index, type); +} + +static GtkWidget * +create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, + GType type) +{ + GtkWidget *menu; + GtkWidget *item; + GList *list, *l; + gint current_index; + GSList *group = NULL; + + current_index = get_current_track_index (play, type); + + if (type == GST_TYPE_PLAYER_VIDEO_INFO) + list = gst_player_get_video_streams (media_info); + else if (type == GST_TYPE_PLAYER_AUDIO_INFO) + list = gst_player_get_audio_streams (media_info); + else + list = gst_player_get_subtitle_streams (media_info); + + menu = gtk_menu_new (); + + for (l = list; l != NULL; l = l->next) { + gint index; + gchar *buffer; + GstPlayerStreamInfo *s = (GstPlayerStreamInfo*) l->data; + + buffer = get_menu_label (s, type); + item = gtk_radio_menu_item_new_with_label (group, buffer); + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM(item)); + index = gst_player_stream_info_get_index (s); + g_object_set_data (G_OBJECT(item), "index", GINT_TO_POINTER (index)); + g_object_set_data (G_OBJECT(item), "type", GSIZE_TO_POINTER (type)); + if (current_index == index) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + g_free (buffer); + g_signal_connect (G_OBJECT(item), "toggled", + G_CALLBACK (track_changed_cb), play); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); + } + item = gtk_radio_menu_item_new_with_label (group, "Disable"); + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM(item)); + g_object_set_data (G_OBJECT(item), "index", GINT_TO_POINTER (-1)); + g_object_set_data (G_OBJECT(item), "type", GSIZE_TO_POINTER (type)); + if (current_index == -1) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + g_signal_connect (G_OBJECT(item), "toggled", + G_CALLBACK (track_changed_cb), play); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); + return menu; +} + +static void +gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) +{ + GtkWidget *menu; + GtkWidget *info; + GtkWidget *audio; + GtkWidget *video; + GtkWidget *sub; + GtkWidget *submenu; + + GstPlayerMediaInfo *media_info; + + media_info = gst_player_get_media_info (play->player); + if (!media_info) + return; + + menu = gtk_menu_new (); + info = gtk_menu_item_new_with_label ("Media Information"); + audio = gtk_menu_item_new_with_label ("Audio"); + video = gtk_menu_item_new_with_label ("Video"); + sub = gtk_menu_item_new_with_label ("Subtitle"); + + if (!gst_player_get_video_streams (media_info)) + gtk_widget_set_sensitive (video, FALSE); + else { + submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_VIDEO_INFO); + if (submenu) + gtk_menu_item_set_submenu (GTK_MENU_ITEM(video), submenu); + } + + if (!gst_player_get_audio_streams (media_info)) + gtk_widget_set_sensitive (audio, FALSE); + else { + submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_AUDIO_INFO); + if (submenu) + gtk_menu_item_set_submenu (GTK_MENU_ITEM(audio), submenu); + } + + if (!gst_player_get_subtitle_streams (media_info)) + gtk_widget_set_sensitive (sub, FALSE); + else { + submenu = create_tracks_menu (play, media_info, + GST_TYPE_PLAYER_SUBTITLE_INFO); + if (submenu) + gtk_menu_item_set_submenu (GTK_MENU_ITEM(sub), submenu); + } + + g_signal_connect (G_OBJECT (info), "activate", + G_CALLBACK (media_info_clicked_cb), play); + + gtk_menu_shell_append (GTK_MENU_SHELL(menu), video); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), audio); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), sub); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), info); + + gtk_widget_show_all (menu); + gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, + (event != NULL) ? event->button : 0, + gdk_event_get_time((GdkEvent*)event)); + + g_object_unref (media_info); +} + +static void +mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, + GtkPlay *play) +{ + /* we only care about right button pressed event */ + if (event->button != 3) + return; + + gtk_player_popup_menu_create (play, event); +} + static void create_ui (GtkPlay * play) { @@ -515,6 +763,13 @@ create_ui (GtkPlay * play) play->video_area = gtk_drawing_area_new (); g_signal_connect (play->video_area, "realize", G_CALLBACK (video_area_realize_cb), play); + g_signal_connect (play->video_area, "button-press-event", + G_CALLBACK (mouse_button_pressed_cb), play); + gtk_widget_set_events (play->video_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); /* Unified play/pause button */ play->play_pause_button = @@ -581,8 +836,6 @@ create_ui (GtkPlay * play) gtk_widget_realize (play->video_area); gtk_widget_show_all (play->window); - - gtk_widget_hide (play->video_area); } static void @@ -610,16 +863,6 @@ position_updated_cb (GstPlayer * unused, GstClockTime position, GtkPlay * play) play->seekbar_value_changed_signal_id); } -static void -video_dimensions_changed_cb (GstPlayer * unused, gint width, gint height, - GtkPlay * play) -{ - if (width > 0 && height > 0) - gtk_widget_show (play->video_area); - else - gtk_widget_hide (play->video_area); -} - static void eos_cb (GstPlayer * unused, GtkPlay * play) { @@ -751,8 +994,6 @@ main (gint argc, gchar ** argv) G_CALLBACK (position_updated_cb), &play); g_signal_connect (play.player, "duration-changed", G_CALLBACK (duration_changed_cb), &play); - g_signal_connect (play.player, "video-dimensions-changed", - G_CALLBACK (video_dimensions_changed_cb), &play); g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); g_signal_connect (play.player, "media-info-updated", G_CALLBACK (media_info_updated_cb), &play); -- cgit v1.2.3 From 7396c221ed2ea822bf6b24e52d34b00919d0fd31 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 7 May 2015 13:21:02 +0200 Subject: playback/player: Fix indention --- playback/player/gtk/gtk-play.c | 82 +++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 7706b92..245db87 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -198,6 +198,7 @@ audio_channels_string (gint num) else return "unknown"; } + static gchar * stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) { @@ -517,14 +518,14 @@ volume_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) } static gint -_get_current_track_index (GtkPlay * play, void * (*func) (GstPlayer * player)) +_get_current_track_index (GtkPlay * play, void *(*func) (GstPlayer * player)) { void *obj; gint index = -1; obj = func (play->player); if (obj) { - index = gst_player_stream_info_get_index ((GstPlayerStreamInfo*) obj); + index = gst_player_stream_info_get_index ((GstPlayerStreamInfo *) obj); g_object_unref (obj); } @@ -536,17 +537,17 @@ get_current_track_index (GtkPlay * play, GType type) { if (type == GST_TYPE_PLAYER_VIDEO_INFO) return _get_current_track_index (play, - (void*) gst_player_get_current_video_track); + (void *) gst_player_get_current_video_track); else if (type == GST_TYPE_PLAYER_AUDIO_INFO) return _get_current_track_index (play, - (void*) gst_player_get_current_audio_track); + (void *) gst_player_get_current_audio_track); else return _get_current_track_index (play, - (void*) gst_player_get_current_subtitle_track); + (void *) gst_player_get_current_subtitle_track); } static gchar * -get_menu_label (GstPlayerStreamInfo *stream, GType type) +get_menu_label (GstPlayerStreamInfo * stream, GType type) { if (type == GST_TYPE_PLAYER_AUDIO_INFO) { gchar *label = NULL; @@ -559,12 +560,11 @@ get_menu_label (GstPlayerStreamInfo *stream, GType type) if (lang) { label = g_strdup_printf ("%s %s [%s]", codec ? codec : "", - channels ? channels : "", lang); + channels ? channels : "", lang); g_free (lang); - } - else + } else label = g_strdup_printf ("%s %s", codec ? codec : "", - channels ? channels : ""); + channels ? channels : ""); g_free (codec); g_free (channels); @@ -613,11 +613,11 @@ track_changed_cb (GtkWidget * widget, GtkPlay * play) gint index; /* check if button is toggled */ - if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM(widget))) + if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) return; - index = GPOINTER_TO_INT (g_object_get_data(G_OBJECT(widget), "index")); - type = GPOINTER_TO_SIZE (g_object_get_data(G_OBJECT(widget), "type")); + index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "index")); + type = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (widget), "type")); if (index == -1) disable_track (play, type); @@ -626,8 +626,7 @@ track_changed_cb (GtkWidget * widget, GtkPlay * play) } static GtkWidget * -create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, - GType type) +create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) { GtkWidget *menu; GtkWidget *item; @@ -649,30 +648,30 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, for (l = list; l != NULL; l = l->next) { gint index; gchar *buffer; - GstPlayerStreamInfo *s = (GstPlayerStreamInfo*) l->data; + GstPlayerStreamInfo *s = (GstPlayerStreamInfo *) l->data; buffer = get_menu_label (s, type); item = gtk_radio_menu_item_new_with_label (group, buffer); - group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM(item)); + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); index = gst_player_stream_info_get_index (s); - g_object_set_data (G_OBJECT(item), "index", GINT_TO_POINTER (index)); - g_object_set_data (G_OBJECT(item), "type", GSIZE_TO_POINTER (type)); + g_object_set_data (G_OBJECT (item), "index", GINT_TO_POINTER (index)); + g_object_set_data (G_OBJECT (item), "type", GSIZE_TO_POINTER (type)); if (current_index == index) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); g_free (buffer); - g_signal_connect (G_OBJECT(item), "toggled", + g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (track_changed_cb), play); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); } item = gtk_radio_menu_item_new_with_label (group, "Disable"); - group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM(item)); - g_object_set_data (G_OBJECT(item), "index", GINT_TO_POINTER (-1)); - g_object_set_data (G_OBJECT(item), "type", GSIZE_TO_POINTER (type)); + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); + g_object_set_data (G_OBJECT (item), "index", GINT_TO_POINTER (-1)); + g_object_set_data (G_OBJECT (item), "type", GSIZE_TO_POINTER (type)); if (current_index == -1) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); - g_signal_connect (G_OBJECT(item), "toggled", + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (track_changed_cb), play); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); return menu; } @@ -703,7 +702,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) else { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_VIDEO_INFO); if (submenu) - gtk_menu_item_set_submenu (GTK_MENU_ITEM(video), submenu); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (video), submenu); } if (!gst_player_get_audio_streams (media_info)) @@ -711,7 +710,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) else { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_AUDIO_INFO); if (submenu) - gtk_menu_item_set_submenu (GTK_MENU_ITEM(audio), submenu); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (audio), submenu); } if (!gst_player_get_subtitle_streams (media_info)) @@ -720,28 +719,28 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_SUBTITLE_INFO); if (submenu) - gtk_menu_item_set_submenu (GTK_MENU_ITEM(sub), submenu); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub), submenu); } g_signal_connect (G_OBJECT (info), "activate", G_CALLBACK (media_info_clicked_cb), play); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), video); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), audio); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), sub); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), info); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), video); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), audio); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), info); gtk_widget_show_all (menu); - gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, - (event != NULL) ? event->button : 0, - gdk_event_get_time((GdkEvent*)event)); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + (event != NULL) ? event->button : 0, + gdk_event_get_time ((GdkEvent *) event)); g_object_unref (media_info); } static void mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, - GtkPlay *play) + GtkPlay * play) { /* we only care about right button pressed event */ if (event->button != 3) @@ -766,10 +765,9 @@ create_ui (GtkPlay * play) g_signal_connect (play->video_area, "button-press-event", G_CALLBACK (mouse_button_pressed_cb), play); gtk_widget_set_events (play->video_area, GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK); + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); /* Unified play/pause button */ play->play_pause_button = -- cgit v1.2.3 From 59d822fc2b493e8600bf89557d56ed59a80af620 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 7 May 2015 13:21:52 +0200 Subject: playback/player: gtk-play: Fix compiler warning gtk-play.c:269:60: warning: passing 'gint *' (aka 'int *') to parameter of type 'guint *' (aka 'unsigned int *') converts between pointers to integer types with different sign [-Wpointer-sign] gst_player_video_info_get_pixel_aspect_ratio (video, &par_n, &par_d); ^~~~~~ ../lib/gst/player/gstplayer-media-info.h:92:57: note: passing argument to parameter 'par_n' here (const GstPlayerVideoInfo* info, guint *par_n, guint *par_d); ^ gtk-play.c:269:68: warning: passing 'gint *' (aka 'int *') to parameter of type 'guint *' (aka 'unsigned int *') converts between pointers to integer types with different sign [-Wpointer-sign] gst_player_video_info_get_pixel_aspect_ratio (video, &par_n, &par_d); ^~~~~~ ../lib/gst/player/gstplayer-media-info.h:92:71: note: passing argument to parameter 'par_d' here (const GstPlayerVideoInfo* info, guint *par_n, guint *par_d); ^ --- playback/player/gtk/gtk-play.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 245db87..5b0b41b 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -262,12 +262,12 @@ stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) } case VIDEO_INFO_PAR: { - gint par_d, par_n; + guint par_d, par_n; gchar *buffer; GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gst_player_video_info_get_pixel_aspect_ratio (video, &par_n, &par_d); - buffer = g_strdup_printf ("%s%d:%d", label ? "pixel-aspect-ratio : " : + buffer = g_strdup_printf ("%s%u:%u", label ? "pixel-aspect-ratio : " : "", par_n, par_d); return buffer; } -- cgit v1.2.3 From a31f95d06dfc67dd1331c0f5d9e575701a1644c9 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 5 May 2015 16:08:18 +0800 Subject: playback/player: android: Use gradle & ndk-build combo to generate the Android App Also add a video List selector. --- playback/player/android/AndroidManifest.xml | 79 ---- playback/player/android/Makefile.am | 32 +- playback/player/android/README.md | 50 +++ playback/player/android/app/app.iml | 97 ++++ playback/player/android/app/build.gradle | 68 +++ .../android/app/src/main/AndroidManifest.xml | 97 ++++ .../java/org/freedesktop/gstreamer/Player.java | 241 ++++++++++ .../gstreamer/play/GStreamerSurfaceView.java | 105 +++++ .../java/org/freedesktop/gstreamer/play/Play.java | 196 ++++++++ .../freedesktop/gstreamer/play/VideoSelector.java | 151 +++++++ .../player/android/app/src/main/jni/Android.mk | 32 ++ .../player/android/app/src/main/jni/Application.mk | 2 + playback/player/android/app/src/main/jni/player.c | 492 +++++++++++++++++++++ .../app/src/main/res/layout/activity_player.xml | 70 +++ .../main/res/layout/activity_video_selector.xml | 15 + .../app/src/main/res/menu/menu_video_selector.xml | 17 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../android/app/src/main/res/values/dimens.xml | 5 + .../android/app/src/main/res/values/strings.xml | 9 + .../android/app/src/main/res/values/styles.xml | 7 + playback/player/android/build.gradle | 15 + playback/player/android/build.xml | 92 ---- .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + playback/player/android/gradlew | 164 +++++++ playback/player/android/gradlew.bat | 90 ++++ playback/player/android/jni/Android.mk | 25 -- playback/player/android/jni/player.c | 492 --------------------- playback/player/android/res/layout/main.xml | 62 --- playback/player/android/res/values/strings.xml | 6 - playback/player/android/settings.gradle | 1 + .../src/org/freedesktop/gstreamer/Player.java | 241 ---------- .../gstreamer/player/GStreamerSurfaceView.java | 105 ----- .../src/org/freedesktop/gstreamer/player/Play.java | 196 -------- 34 files changed, 1959 insertions(+), 1307 deletions(-) delete mode 100644 playback/player/android/AndroidManifest.xml create mode 100644 playback/player/android/README.md create mode 100644 playback/player/android/app/app.iml create mode 100644 playback/player/android/app/build.gradle create mode 100644 playback/player/android/app/src/main/AndroidManifest.xml create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java create mode 100644 playback/player/android/app/src/main/jni/Android.mk create mode 100644 playback/player/android/app/src/main/jni/Application.mk create mode 100644 playback/player/android/app/src/main/jni/player.c create mode 100644 playback/player/android/app/src/main/res/layout/activity_player.xml create mode 100644 playback/player/android/app/src/main/res/layout/activity_video_selector.xml create mode 100644 playback/player/android/app/src/main/res/menu/menu_video_selector.xml create mode 100644 playback/player/android/app/src/main/res/values-w820dp/dimens.xml create mode 100644 playback/player/android/app/src/main/res/values/dimens.xml create mode 100644 playback/player/android/app/src/main/res/values/strings.xml create mode 100644 playback/player/android/app/src/main/res/values/styles.xml create mode 100644 playback/player/android/build.gradle delete mode 100644 playback/player/android/build.xml create mode 100644 playback/player/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 playback/player/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 playback/player/android/gradlew create mode 100644 playback/player/android/gradlew.bat delete mode 100644 playback/player/android/jni/Android.mk delete mode 100644 playback/player/android/jni/player.c delete mode 100644 playback/player/android/res/layout/main.xml delete mode 100644 playback/player/android/res/values/strings.xml create mode 100644 playback/player/android/settings.gradle delete mode 100644 playback/player/android/src/org/freedesktop/gstreamer/Player.java delete mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java delete mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/Play.java diff --git a/playback/player/android/AndroidManifest.xml b/playback/player/android/AndroidManifest.xml deleted file mode 100644 index 8b156d4..0000000 --- a/playback/player/android/AndroidManifest.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/Makefile.am b/playback/player/android/Makefile.am index 2664abb..e9e4c74 100644 --- a/playback/player/android/Makefile.am +++ b/playback/player/android/Makefile.am @@ -1,10 +1,24 @@ EXTRA_DIST = \ - AndroidManifest.xml \ - jni/Android.mk \ - jni/player.c \ - res/layout/main.xml \ - res/values/strings.xml \ - src/org/freedesktop/gstreamer/Player.java \ - src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ - src/org/freedesktop/gstreamer/player/Play.java - + build.gradle \ + gradlew \ + gradlew.bat \ + README.md \ + settings.gradle \ + app/build.gradle \ + app/src/main/AndroidManifest.xml \ + app/src/main/java/org/freedesktop/gstreamer/Player.java \ + app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ + app/src/main/java/org/freedesktop/gstreamer/player/Play.java \ + app/src/main/java/org/freedesktop/gstreamer/player/VideoSelector.java \ + app/src/main/jni/Android.mk \ + app/src/main/jni/Application.mk \ + app/src/main/jni/player.c \ + app/src/main/res/layout/activity_player.xml \ + app/src/main/res/layout/activity_video_selector.xml \ + app/src/main/res/menu/menu_video_selector.xml \ + app/src/main/res/values/dimens.xml \ + app/src/main/res/values/strings.xml \ + app/src/main/res/values/styles.xml \ + app/src/main/res/values-w820dp/styles.xml \ + gradle/wrapper/gradle-wrapper.jar \ + gradle/wrapper/gradle-wrapper.properties \ No newline at end of file diff --git a/playback/player/android/README.md b/playback/player/android/README.md new file mode 100644 index 0000000..cf331f7 --- /dev/null +++ b/playback/player/android/README.md @@ -0,0 +1,50 @@ +GST Player Android port +======================= + +Prerequisites +------------- + +1. Install Android SDK from https://developer.android.com/sdk/ & set `sdk.dir` in **local.properties** to the installation path +2. Install Android NDK from https://developer.android.com/tools/sdk/ndk/index.html & set `ndk.dir` in **local.properties** to the installation path +3. If you have a different special directory for pkg-config or other tools (e.g. on OSX when using Homebrew), then also set this path using the `ndk.extraPath` variable in **local.properties** +4. Download the GStreamer android ports http://gstreamer.freedesktop.org/data/pkg/android/ and set `gstreamer.$ABI.dir` properties in **local.properties**: + + gstreamer.arm.dir=/path/to/gstreamer-1.0-android-arm-release-1.4.5/ + gstreamer.armv7.dir=/path/to/gstreamer-1.0-android-armv7-release-1.4.5/ + gstreamer.x86.dir=/path/to/gstreamer-1.0-android-x86-release-1.4.5/ + +Compiling the sample +-------------------- + +Use + + ./gradlew installDebug + +to compile and install a debug version onto all connected devices. + +Please note this component is using the new Android build system based on Gradle. More information about this is available on http://tools.android.com/tech-docs/new-build-system. + +Android Studio +-------------- + +Android Studio builds will work out of the box. Simply open `build.gradle` in this folder to import the project. + +Manual NDK build +---------------- + +It is still possible to build just the NDK portion. This will speed up the process a bit as you don't need to start gradle first and compile the complete App. +First, make sure to set `NDK_PROJECT_PATH` to this projects main source path. Additionally the SDK & NDK tools are available in `$PATH`. + + export NDK_PROJECT_PATH=$PWD/app/src/main + +Second, set the following environment variables to the GStreamer installation folders: + + export GSTREAMER_ROOT_ARM=/path/to/gstreamer-1.0-android-arm-release-1.4.5/ + export GSTREAMER_ROOT_ARMV7=/path/to/tmp/gstreamer-1.0-android-armv7-release-1.4.5/ + export GSTREAMER_ROOT_X86=/path/to/gstreamer-1.0-android-x86-release-1.4.5/ + +If you don't want to build all architectures, please modify the file `app/src/main/jni/Application.mk` + +Finally, within the `app/src/main/` directory, invoke: + + ndk-build \ No newline at end of file diff --git a/playback/player/android/app/app.iml b/playback/player/android/app/app.iml new file mode 100644 index 0000000..86e3b56 --- /dev/null +++ b/playback/player/android/app/app.iml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/playback/player/android/app/build.gradle b/playback/player/android/app/build.gradle new file mode 100644 index 0000000..6039b5b --- /dev/null +++ b/playback/player/android/app/build.gradle @@ -0,0 +1,68 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "org.freedesktop.gstreamer.play" + minSdkVersion 9 + targetSdkVersion 22 + + ndk { + moduleName "gstplayer" + } + } + + sourceSets { + main { + // GStreamer will generate these files. + java { + srcDir 'src/main/jni/src' + } + assets { + srcDir 'src/main/jni/assets' + } + + //Tell Gradle where to put the compiled shared library + jniLibs.srcDir 'src/main/libs' + + //disable automatic ndk-build call + jni.srcDirs = []; + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + + // Thank you http://stackoverflow.com/q/28878689/375209 + tasks.withType(JavaCompile) { + compileTask -> compileTask.dependsOn ndkBuild + } + + task ndkBuild(type: Exec) { + Properties properties = new Properties() + properties.load(project.rootProject.file('local.properties').newDataInputStream()) + def ndkDir = properties.getProperty('ndk.dir') + environment GSTREAMER_ROOT_ARM: properties.getProperty('gstreamer.arm.dir') + environment GSTREAMER_ROOT_ARMV7: properties.getProperty('gstreamer.armv7.dir') + environment GSTREAMER_ROOT_X86: properties.getProperty('gstreamer.x86.dir') + + def ndkExtraPath = properties.getProperty('ndk.extraPath') + if (! "".equalsIgnoreCase(ndkExtraPath)) { + environment PATH: "${System.getenv("PATH")}${File.pathSeparator}${ndkExtraPath}" + } + + commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' // Enable V=1 for debugging messages. + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:22.1.1' + compile "com.android.support:recyclerview-v7:22.1.1" + compile "com.android.support:support-annotations:22.1.1" +} diff --git a/playback/player/android/app/src/main/AndroidManifest.xml b/playback/player/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6de668c --- /dev/null +++ b/playback/player/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java new file mode 100644 index 0000000..e2bef8c --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java @@ -0,0 +1,241 @@ +/* GStreamer + * + * Copyright (C) 2014-2015 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer; + +import java.io.Closeable; +import android.view.Surface; +import android.content.Context; +import org.freedesktop.gstreamer.GStreamer; + +public class Player implements Closeable { + private static native void nativeClassInit(); + public static void init(Context context) throws Exception { + System.loadLibrary("gstreamer_android"); + GStreamer.init(context); + + System.loadLibrary("gstplayer"); + nativeClassInit(); + } + + private long native_player; + private native void nativeNew(); + public Player() { + nativeNew(); + } + + private native void nativeFree(); + @Override + public void close() { + nativeFree(); + } + + private native void nativePlay(); + public void play() { + nativePlay(); + } + + private native void nativePause(); + public void pause() { + nativePause(); + } + + private native void nativeStop(); + public void stop() { + nativeStop(); + } + + private native void nativeSeek(long position); + public void seek(long position) { + nativeSeek(position); + } + + private native String nativeGetUri(); + public String getUri() { + return nativeGetUri(); + } + + private native void nativeSetUri(String uri); + public void setUri(String uri) { + nativeSetUri(uri); + } + + private native long nativeGetPosition(); + public long getPosition() { + return nativeGetPosition(); + } + + private native long nativeGetDuration(); + public long getDuration() { + return nativeGetDuration(); + } + + private native double nativeGetVolume(); + public double getVolume() { + return nativeGetVolume(); + } + + private native void nativeSetVolume(double volume); + public void setVolume(double volume) { + nativeSetVolume(volume); + } + + private native boolean nativeGetMute(); + public boolean getMute() { + return nativeGetMute(); + } + + private native void nativeSetMute(boolean mute); + public void setMute(boolean mute) { + nativeSetMute(mute); + } + + private Surface surface; + private native void nativeSetSurface(Surface surface); + public void setSurface(Surface surface) { + this.surface = surface; + nativeSetSurface(surface); + } + + public Surface getSurface() { + return surface; + } + + public static interface PositionUpdatedListener { + abstract void positionUpdated(Player player, long position); + } + + private PositionUpdatedListener positionUpdatedListener; + public void setPositionUpdatedListener(PositionUpdatedListener listener) { + positionUpdatedListener = listener; + } + + private void onPositionUpdated(long position) { + if (positionUpdatedListener != null) { + positionUpdatedListener.positionUpdated(this, position); + } + } + + public static interface DurationChangedListener { + abstract void durationChanged(Player player, long duration); + } + + private DurationChangedListener durationChangedListener; + public void setDurationChangedListener(DurationChangedListener listener) { + durationChangedListener = listener; + } + + private void onDurationChanged(long duration) { + if (durationChangedListener != null) { + durationChangedListener.durationChanged(this, duration); + } + } + + private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; + public enum State { + STOPPED, + BUFFERING, + PAUSED, + PLAYING + } + + public static interface StateChangedListener { + abstract void stateChanged(Player player, State state); + } + + private StateChangedListener stateChangedListener; + public void setStateChangedListener(StateChangedListener listener) { + stateChangedListener = listener; + } + + private void onStateChanged(int stateIdx) { + if (stateChangedListener != null) { + State state = stateMap[stateIdx]; + stateChangedListener.stateChanged(this, state); + } + } + + public static interface BufferingListener { + abstract void buffering(Player player, int percent); + } + + private BufferingListener bufferingListener; + public void setBufferingListener(BufferingListener listener) { + bufferingListener = listener; + } + + private void onBuffering(int percent) { + if (bufferingListener != null) { + bufferingListener.buffering(this, percent); + } + } + + public static interface EndOfStreamListener { + abstract void endOfStream(Player player); + } + + private EndOfStreamListener endOfStreamListener; + public void setEndOfStreamListener(EndOfStreamListener listener) { + endOfStreamListener = listener; + } + + private void onEndOfStream() { + if (endOfStreamListener != null) { + endOfStreamListener.endOfStream(this); + } + } + + // Keep these in sync with gstplayer.h + private static final Error[] errorMap = {Error.FAILED}; + public enum Error { + FAILED + } + + public static interface ErrorListener { + abstract void error(Player player, Error error, String errorMessage); + } + + private ErrorListener errorListener; + public void setErrorListener(ErrorListener listener) { + errorListener = listener; + } + + private void onError(int errorCode, String errorMessage) { + if (errorListener != null) { + Error error = errorMap[errorCode]; + errorListener.error(this, error, errorMessage); + } + } + + public static interface VideoDimensionsChangedListener { + abstract void videoDimensionsChanged(Player player, int width, int height); + } + + private VideoDimensionsChangedListener videoDimensionsChangedListener; + public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { + videoDimensionsChangedListener = listener; + } + + private void onVideoDimensionsChanged(int width, int height) { + if (videoDimensionsChangedListener != null) { + videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); + } + } +} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java new file mode 100644 index 0000000..f2dd8a9 --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java @@ -0,0 +1,105 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceView; +import android.view.View; + +// A simple SurfaceView whose width and height can be set from the outside +public class GStreamerSurfaceView extends SurfaceView { + public int media_width = 320; + public int media_height = 240; + + // Mandatory constructors, they do not do much + public GStreamerSurfaceView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public GStreamerSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public GStreamerSurfaceView (Context context) { + super(context); + } + + // Called by the layout manager to find out our size and give us some rules. + // We will try to maximize our size, and preserve the media's aspect ratio if + // we are given the freedom to do so. + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = 0, height = 0; + int wmode = View.MeasureSpec.getMode(widthMeasureSpec); + int hmode = View.MeasureSpec.getMode(heightMeasureSpec); + int wsize = View.MeasureSpec.getSize(widthMeasureSpec); + int hsize = View.MeasureSpec.getSize(heightMeasureSpec); + + Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); + // Obey width rules + switch (wmode) { + case View.MeasureSpec.AT_MOST: + if (hmode == View.MeasureSpec.EXACTLY) { + width = Math.min(hsize * media_width / media_height, wsize); + break; + } + case View.MeasureSpec.EXACTLY: + width = wsize; + break; + case View.MeasureSpec.UNSPECIFIED: + width = media_width; + } + + // Obey height rules + switch (hmode) { + case View.MeasureSpec.AT_MOST: + if (wmode == View.MeasureSpec.EXACTLY) { + height = Math.min(wsize * media_height / media_width, hsize); + break; + } + case View.MeasureSpec.EXACTLY: + height = hsize; + break; + case View.MeasureSpec.UNSPECIFIED: + height = media_height; + } + + // Finally, calculate best size when both axis are free + if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { + int correct_height = width * media_height / media_width; + int correct_width = height * media_width / media_height; + + if (correct_height < height) + height = correct_height; + else + width = correct_width; + } + + // Obey minimum size + width = Math.max (getSuggestedMinimumWidth(), width); + height = Math.max (getSuggestedMinimumHeight(), height); + setMeasuredDimension(width, height); + } + +} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java new file mode 100644 index 0000000..9be9d78 --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java @@ -0,0 +1,196 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.PowerManager; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; +import android.widget.Toast; + +import org.freedesktop.gstreamer.Player; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class Play extends AppCompatActivity implements SurfaceHolder.Callback, OnSeekBarChangeListener { + private PowerManager.WakeLock wake_lock; + private Player player; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + try { + Player.init(this); + } catch (Exception e) { + Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); + finish(); + return; + } + + setContentView(R.layout.activity_player); + + player = new Player(); + + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); + wake_lock.setReferenceCounted(false); + + ImageButton play = (ImageButton) this.findViewById(R.id.button_play); + play.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.play(); + wake_lock.acquire(); + } + }); + + ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); + pause.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.pause(); + wake_lock.release(); + } + }); + + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + sb.setOnSeekBarChangeListener(this); + + player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { + public void positionUpdated(Player player, final long position) { + runOnUiThread(new Runnable() { + public void run() { + sb.setProgress((int) (position / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + player.setDurationChangedListener(new Player.DurationChangedListener() { + public void durationChanged(Player player, final long duration) { + runOnUiThread(new Runnable() { + public void run() { + sb.setMax((int) (duration / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); + + player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { + public void videoDimensionsChanged(Player player, final int width, final int height) { + runOnUiThread(new Runnable() { + public void run() { + Log.i("GStreamer", "Media size changed to " + width + "x" + height); + if (width > 0 && height > 0) { + gsv.media_width = width; + gsv.media_height = height; + runOnUiThread(new Runnable() { + public void run() { + gsv.requestLayout(); + } + }); + } else { + Log.i("GStreamer", "Ignoring media size."); + } + } + }); + } + }); + + SurfaceHolder sh = gsv.getHolder(); + sh.addCallback(this); + + String mediaUri = null; + Intent intent = getIntent(); + android.net.Uri uri = intent.getData(); + Log.i("GStreamer", "Received URI: " + uri); + if (uri.getScheme().equals("content")) { + android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); + cursor.close(); + } else { + mediaUri = uri.toString(); + } + player.setUri(mediaUri); + + updateTimeWidget(); + } + + protected void onDestroy() { + player.close(); + super.onDestroy(); + } + + private void updateTimeWidget() { + final TextView tv = (TextView) this.findViewById(R.id.textview_time); + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + final int pos = sb.getProgress(); + final int max = sb.getMax(); + + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + final String message = df.format(new Date(pos)) + " / " + df.format(new Date(max)); + tv.setText(message); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.d("GStreamer", "Surface changed to format " + format + " width " + width + " height " + height); + player.setSurface(holder.getSurface()); + } + + public void surfaceCreated(SurfaceHolder holder) { + Log.d("GStreamer", "Surface created: " + holder.getSurface()); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d("GStreamer", "Surface destroyed"); + player.setSurface(null); + } + + public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { + if (!fromUser) return; + + updateTimeWidget(); + } + + public void onStartTrackingTouch(SeekBar sb) { + } + + public void onStopTrackingTouch(SeekBar sb) { + Log.d("GStreamer", "Seek to " + sb.getProgress()); + player.seek(((long) sb.getProgress()) * 1000000); + } +} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java new file mode 100644 index 0000000..38739f7 --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java @@ -0,0 +1,151 @@ +/* GStreamer + * + * Copyright (C) 2015 Sebastian Roth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.widget.SimpleCursorAdapter; +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; + + +public class VideoSelector extends AppCompatActivity implements LoaderManager.LoaderCallbacks { + + VideoAdapter adapter; + boolean sortByName = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_video_selector); + + ListView videoList = (ListView) findViewById(R.id.videoList); + adapter = new VideoAdapter(this); + videoList.setAdapter(adapter); + videoList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, final int position, final long id) { + final String videoPath = adapter.getVideoPath(position); + if (!TextUtils.isEmpty(videoPath)) { + Intent intent = new Intent(VideoSelector.this, Play.class); + intent.setData(Uri.parse("file://" + videoPath)); + startActivity(intent); + } + } + }); + + getSupportLoaderManager().initLoader(1, null, this); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_video_selector, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_about) { + return true; + } + + //noinspection SimplifiableIfStatement + if (id == R.id.action_sort) { + sortByName = !sortByName; + getSupportLoaderManager().restartLoader(1, null, this); + return true; + } + + + return super.onOptionsItemSelected(item); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + if (sortByName) { + return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null, + "UPPER(" + MediaStore.Video.Media.DATA + ")"); + } else { + return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null, + "UPPER(" + MediaStore.Video.Media.DISPLAY_NAME + ")"); + } + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + adapter.swapCursor(data); + } + + @Override + public void onLoaderReset(Loader loader) { + + } + + + class VideoAdapter extends SimpleCursorAdapter { + public VideoAdapter(Context context) { + super(context, android.R.layout.simple_list_item_2, null, + new String[]{MediaStore.Video.Media.DISPLAY_NAME, MediaStore.Video.Media.DATA}, + new int[]{android.R.id.text1, android.R.id.text2}, 0); + } + + @Override + public long getItemId(int position) { + final Cursor cursor = getCursor(); + if (cursor.getCount() == 0 || position >= cursor.getCount()) { + return 0; + } + cursor.moveToPosition(position); + + return cursor.getLong(0); + } + + public String getVideoPath(int position) { + final Cursor cursor = getCursor(); + if (cursor.getCount() == 0) { + return ""; + } + cursor.moveToPosition(position); + + return cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA)); + } + } +} diff --git a/playback/player/android/app/src/main/jni/Android.mk b/playback/player/android/app/src/main/jni/Android.mk new file mode 100644 index 0000000..7afe062 --- /dev/null +++ b/playback/player/android/app/src/main/jni/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +GST_PATH := $(LOCAL_PATH)/../../../../../ + +LOCAL_MODULE := gstplayer +LOCAL_SRC_FILES := player.c \ + $(GST_PATH)/lib/gst/player/gstplayer.c \ + $(GST_PATH)/lib/gst/player/gstplayer-media-info.c +LOCAL_C_INCLUDES := $(GST_PATH)/lib +LOCAL_SHARED_LIBRARIES := gstreamer_android +LOCAL_LDLIBS := -llog -landroid +include $(BUILD_SHARED_LIBRARY) + +ifeq ($(TARGET_ARCH_ABI),armeabi) + GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM) +else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7) +else ifeq ($(TARGET_ARCH_ABI),x86) + GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86) +else + $(error Target arch ABI $(TARGET_ARCH_ABI) not supported) +endif + +GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ + +include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk +GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) +GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 + +include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/app/src/main/jni/Application.mk b/playback/player/android/app/src/main/jni/Application.mk new file mode 100644 index 0000000..f665244 --- /dev/null +++ b/playback/player/android/app/src/main/jni/Application.mk @@ -0,0 +1,2 @@ +APP_ABI := armeabi armeabi-v7a x86 +APP_PLATFORM := android-9 \ No newline at end of file diff --git a/playback/player/android/app/src/main/jni/player.c b/playback/player/android/app/src/main/jni/player.c new file mode 100644 index 0000000..951f2c6 --- /dev/null +++ b/playback/player/android/app/src/main/jni/player.c @@ -0,0 +1,492 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "gst/player/player.h" + +GST_DEBUG_CATEGORY_STATIC (debug_category); +#define GST_CAT_DEFAULT debug_category + +#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) +#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) + +typedef struct _Player +{ + jobject java_player; + GstPlayer *player; + ANativeWindow *native_window; +} Player; + +static pthread_key_t current_jni_env; +static JavaVM *java_vm; +static jfieldID native_player_field_id; +static jmethodID on_position_updated_method_id; +static jmethodID on_duration_changed_method_id; +static jmethodID on_state_changed_method_id; +static jmethodID on_buffering_method_id; +static jmethodID on_end_of_stream_method_id; +static jmethodID on_error_method_id; +static jmethodID on_video_dimensions_changed_method_id; + +/* Register this thread with the VM */ +static JNIEnv * +attach_current_thread (void) +{ + JNIEnv *env; + JavaVMAttachArgs args; + + GST_DEBUG ("Attaching thread %p", g_thread_self ()); + args.version = JNI_VERSION_1_4; + args.name = NULL; + args.group = NULL; + + if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { + GST_ERROR ("Failed to attach current thread"); + return NULL; + } + + return env; +} + +/* Unregister this thread from the VM */ +static void +detach_current_thread (void *env) +{ + GST_DEBUG ("Detaching thread %p", g_thread_self ()); + (*java_vm)->DetachCurrentThread (java_vm); +} + +/* Retrieve the JNI environment for this thread */ +static JNIEnv * +get_jni_env (void) +{ + JNIEnv *env; + + if ((env = pthread_getspecific (current_jni_env)) == NULL) { + env = attach_current_thread (); + pthread_setspecific (current_jni_env, env); + } + + return env; +} + +/* + * Java Bindings + */ +static void +on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_position_updated_method_id, position); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_duration_changed_method_id, duration); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_state_changed_method_id, state); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_buffering (GstPlayer * unused, gint percent, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_buffering_method_id, percent); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_end_of_stream (GstPlayer * unused, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_error (GstPlayer * unused, GError * err, Player * player) +{ + JNIEnv *env = get_jni_env (); + jstring error_msg; + + error_msg = (*env)->NewStringUTF (env, err->message); + + (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, + err->code, error_msg); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + + (*env)->DeleteLocalRef (env, error_msg); +} + +static void +on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, + Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_video_dimensions_changed_method_id, width, height); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +native_new (JNIEnv * env, jobject thiz) +{ + Player *player = g_new0 (Player, 1); + + player->player = gst_player_new (); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); + player->java_player = (*env)->NewGlobalRef (env, thiz); + + g_signal_connect (player->player, "position-updated", + G_CALLBACK (on_position_updated), player); + g_signal_connect (player->player, "duration-changed", + G_CALLBACK (on_duration_changed), player); + g_signal_connect (player->player, "state-changed", + G_CALLBACK (on_state_changed), player); + g_signal_connect (player->player, "buffering", + G_CALLBACK (on_buffering), player); + g_signal_connect (player->player, "end-of-stream", + G_CALLBACK (on_end_of_stream), player); + g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); + g_signal_connect (player->player, "video-dimensions-changed", + G_CALLBACK (on_video_dimensions_changed), player); +} + +static void +native_free (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + (*env)->DeleteGlobalRef (env, player->java_player); + g_free (player); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); +} + +static void +native_play (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_play (player->player); +} + +static void +native_pause (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_pause (player->player); +} + +static void +native_stop (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_stop (player->player); +} + +static void +native_seek (JNIEnv * env, jobject thiz, jlong position) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_seek (player->player, position); +} + +static void +native_set_uri (JNIEnv * env, jobject thiz, jobject uri) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + const gchar *uri_str; + + if (!player) + return; + + uri_str = (*env)->GetStringUTFChars (env, uri, NULL); + g_object_set (player->player, "uri", uri_str, NULL); + (*env)->ReleaseStringUTFChars (env, uri, uri_str); +} + +static jobject +native_get_uri (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jobject uri; + gchar *uri_str; + + if (!player) + return NULL; + + g_object_get (player->player, "uri", &uri_str, NULL); + + uri = (*env)->NewStringUTF (env, uri_str); + g_free (uri_str); + + return uri; +} + +static jlong +native_get_position (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble position; + + if (!player) + return -1; + + g_object_get (player->player, "position", &position, NULL); + + return position; +} + +static jlong +native_get_duration (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jlong duration; + + if (!player) + return -1; + + g_object_get (player->player, "duration", &duration, NULL); + + return duration; +} + +static jdouble +native_get_volume (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble volume; + + if (!player) + return 1.0; + + g_object_get (player->player, "volume", &volume, NULL); + + return volume; +} + +static void +native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "volume", volume, NULL); +} + +static jboolean +native_get_mute (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jboolean mute; + + if (!player) + return FALSE; + + g_object_get (player->player, "mute", &mute, NULL); + + return mute; +} + +static void +native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "mute", mute, NULL); +} + +static void +native_set_surface (JNIEnv * env, jobject thiz, jobject surface) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + ANativeWindow *new_native_window; + + if (!player) + return; + + new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; + GST_DEBUG ("Received surface %p (native window %p)", surface, + new_native_window); + + if (player->native_window) { + ANativeWindow_release (player->native_window); + } + + player->native_window = new_native_window; + g_object_set (player->player, "window-handle", (gpointer) new_native_window, + NULL); +} + +static void +native_class_init (JNIEnv * env, jclass klass) +{ + native_player_field_id = + (*env)->GetFieldID (env, klass, "native_player", "J"); + on_position_updated_method_id = + (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); + on_duration_changed_method_id = + (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); + on_state_changed_method_id = + (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); + on_buffering_method_id = + (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); + on_end_of_stream_method_id = + (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); + on_error_method_id = + (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); + on_video_dimensions_changed_method_id = + (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); + + if (!native_player_field_id || + !on_position_updated_method_id || !on_duration_changed_method_id || + !on_state_changed_method_id || !on_buffering_method_id || + !on_end_of_stream_method_id || + !on_error_method_id || !on_video_dimensions_changed_method_id) { + static const gchar *message = + "The calling class does not implement all necessary interface methods"; + jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); + (*env)->ThrowNew (env, exception_class, message); + } + + gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); +} + +/* List of implemented native methods */ +static JNINativeMethod native_methods[] = { + {"nativeClassInit", "()V", (void *) native_class_init}, + {"nativeNew", "()V", (void *) native_new}, + {"nativePlay", "()V", (void *) native_play}, + {"nativePause", "()V", (void *) native_pause}, + {"nativeSeek", "(J)V", (void *) native_seek}, + {"nativeFree", "()V", (void *) native_free}, + {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, + {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, + {"nativeGetPosition", "()J", (void *) native_get_position}, + {"nativeGetDuration", "()J", (void *) native_get_duration}, + {"nativeGetVolume", "()D", (void *) native_get_volume}, + {"nativeSetVolume", "(D)V", (void *) native_set_volume}, + {"nativeGetMute", "()Z", (void *) native_get_mute}, + {"nativeSetMute", "(Z)V", (void *) native_set_mute}, + {"nativeSetSurface", "(Landroid/view/Surface;)V", + (void *) native_set_surface} +}; + +/* Library initializer */ +jint +JNI_OnLoad (JavaVM * vm, void *reserved) +{ + JNIEnv *env = NULL; + + java_vm = vm; + + if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve JNIEnv"); + return 0; + } + jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); + if (!klass) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve class org.freedesktop.gstreamer.Player"); + return 0; + } + if ((*env)->RegisterNatives (env, klass, native_methods, + G_N_ELEMENTS (native_methods))) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not register native methods for org.freedesktop.gstreamer.Player"); + return 0; + } + + pthread_key_create (¤t_jni_env, detach_current_thread); + + return JNI_VERSION_1_4; +} diff --git a/playback/player/android/app/src/main/res/layout/activity_player.xml b/playback/player/android/app/src/main/res/layout/activity_player.xml new file mode 100644 index 0000000..cd4a933 --- /dev/null +++ b/playback/player/android/app/src/main/res/layout/activity_player.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/app/src/main/res/layout/activity_video_selector.xml b/playback/player/android/app/src/main/res/layout/activity_video_selector.xml new file mode 100644 index 0000000..229ae17 --- /dev/null +++ b/playback/player/android/app/src/main/res/layout/activity_video_selector.xml @@ -0,0 +1,15 @@ + + + + diff --git a/playback/player/android/app/src/main/res/menu/menu_video_selector.xml b/playback/player/android/app/src/main/res/menu/menu_video_selector.xml new file mode 100644 index 0000000..93f4437 --- /dev/null +++ b/playback/player/android/app/src/main/res/menu/menu_video_selector.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/playback/player/android/app/src/main/res/values-w820dp/dimens.xml b/playback/player/android/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/playback/player/android/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/playback/player/android/app/src/main/res/values/dimens.xml b/playback/player/android/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/playback/player/android/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/playback/player/android/app/src/main/res/values/strings.xml b/playback/player/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..d3af9a3 --- /dev/null +++ b/playback/player/android/app/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + + GStreamer Play + Play + Pause + + About + Sort + diff --git a/playback/player/android/app/src/main/res/values/styles.xml b/playback/player/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..540f2fe --- /dev/null +++ b/playback/player/android/app/src/main/res/values/styles.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/playback/player/android/build.gradle b/playback/player/android/build.gradle new file mode 100644 index 0000000..01de6ef --- /dev/null +++ b/playback/player/android/build.gradle @@ -0,0 +1,15 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.2' + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/playback/player/android/build.xml b/playback/player/android/build.xml deleted file mode 100644 index 4ef18c8..0000000 --- a/playback/player/android/build.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.jar b/playback/player/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8c0fb64 Binary files /dev/null and b/playback/player/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.properties b/playback/player/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c71e76 --- /dev/null +++ b/playback/player/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/playback/player/android/gradlew b/playback/player/android/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/playback/player/android/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/playback/player/android/gradlew.bat b/playback/player/android/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/playback/player/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk deleted file mode 100644 index fe4d50a..0000000 --- a/playback/player/android/jni/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c ../../lib/gst/player/gstplayer-media-info.c -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../lib -LOCAL_SHARED_LIBRARIES := gstreamer_android -LOCAL_LDLIBS := -llog -landroid -include $(BUILD_SHARED_LIBRARY) - -ifndef GSTREAMER_ROOT -ifndef GSTREAMER_ROOT_ANDROID -$(error GSTREAMER_ROOT_ANDROID is not defined!) -endif -GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID) -endif - -GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ - -include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk -GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) -GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 - -include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c deleted file mode 100644 index 8670b17..0000000 --- a/playback/player/android/jni/player.c +++ /dev/null @@ -1,492 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "gst/player/gstplayer.h" - -GST_DEBUG_CATEGORY_STATIC (debug_category); -#define GST_CAT_DEFAULT debug_category - -#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) -#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) - -typedef struct _Player -{ - jobject java_player; - GstPlayer *player; - ANativeWindow *native_window; -} Player; - -static pthread_key_t current_jni_env; -static JavaVM *java_vm; -static jfieldID native_player_field_id; -static jmethodID on_position_updated_method_id; -static jmethodID on_duration_changed_method_id; -static jmethodID on_state_changed_method_id; -static jmethodID on_buffering_method_id; -static jmethodID on_end_of_stream_method_id; -static jmethodID on_error_method_id; -static jmethodID on_video_dimensions_changed_method_id; - -/* Register this thread with the VM */ -static JNIEnv * -attach_current_thread (void) -{ - JNIEnv *env; - JavaVMAttachArgs args; - - GST_DEBUG ("Attaching thread %p", g_thread_self ()); - args.version = JNI_VERSION_1_4; - args.name = NULL; - args.group = NULL; - - if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { - GST_ERROR ("Failed to attach current thread"); - return NULL; - } - - return env; -} - -/* Unregister this thread from the VM */ -static void -detach_current_thread (void *env) -{ - GST_DEBUG ("Detaching thread %p", g_thread_self ()); - (*java_vm)->DetachCurrentThread (java_vm); -} - -/* Retrieve the JNI environment for this thread */ -static JNIEnv * -get_jni_env (void) -{ - JNIEnv *env; - - if ((env = pthread_getspecific (current_jni_env)) == NULL) { - env = attach_current_thread (); - pthread_setspecific (current_jni_env, env); - } - - return env; -} - -/* - * Java Bindings - */ -static void -on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_position_updated_method_id, position); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_duration_changed_method_id, duration); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_state_changed_method_id, state); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_buffering (GstPlayer * unused, gint percent, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_buffering_method_id, percent); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_end_of_stream (GstPlayer * unused, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_error (GstPlayer * unused, GError * err, Player * player) -{ - JNIEnv *env = get_jni_env (); - jstring error_msg; - - error_msg = (*env)->NewStringUTF (env, err->message); - - (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, - err->code, error_msg); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - - (*env)->DeleteLocalRef (env, error_msg); -} - -static void -on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, - Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_video_dimensions_changed_method_id, width, height); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -native_new (JNIEnv * env, jobject thiz) -{ - Player *player = g_new0 (Player, 1); - - player->player = gst_player_new (); - SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); - player->java_player = (*env)->NewGlobalRef (env, thiz); - - g_signal_connect (player->player, "position-updated", - G_CALLBACK (on_position_updated), player); - g_signal_connect (player->player, "duration-changed", - G_CALLBACK (on_duration_changed), player); - g_signal_connect (player->player, "state-changed", - G_CALLBACK (on_state_changed), player); - g_signal_connect (player->player, "buffering", - G_CALLBACK (on_buffering), player); - g_signal_connect (player->player, "end-of-stream", - G_CALLBACK (on_end_of_stream), player); - g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); - g_signal_connect (player->player, "video-dimensions-changed", - G_CALLBACK (on_video_dimensions_changed), player); -} - -static void -native_free (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - (*env)->DeleteGlobalRef (env, player->java_player); - g_free (player); - SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); -} - -static void -native_play (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_play (player->player); -} - -static void -native_pause (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_pause (player->player); -} - -static void -native_stop (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_stop (player->player); -} - -static void -native_seek (JNIEnv * env, jobject thiz, jlong position) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_seek (player->player, position); -} - -static void -native_set_uri (JNIEnv * env, jobject thiz, jobject uri) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - const gchar *uri_str; - - if (!player) - return; - - uri_str = (*env)->GetStringUTFChars (env, uri, NULL); - g_object_set (player->player, "uri", uri_str, NULL); - (*env)->ReleaseStringUTFChars (env, uri, uri_str); -} - -static jobject -native_get_uri (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jobject uri; - gchar *uri_str; - - if (!player) - return NULL; - - g_object_get (player->player, "uri", &uri_str, NULL); - - uri = (*env)->NewStringUTF (env, uri_str); - g_free (uri_str); - - return uri; -} - -static jlong -native_get_position (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jdouble position; - - if (!player) - return -1; - - g_object_get (player->player, "position", &position, NULL); - - return position; -} - -static jlong -native_get_duration (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jlong duration; - - if (!player) - return -1; - - g_object_get (player->player, "duration", &duration, NULL); - - return duration; -} - -static jdouble -native_get_volume (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jdouble volume; - - if (!player) - return 1.0; - - g_object_get (player->player, "volume", &volume, NULL); - - return volume; -} - -static void -native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_set (player->player, "volume", volume, NULL); -} - -static jboolean -native_get_mute (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jboolean mute; - - if (!player) - return FALSE; - - g_object_get (player->player, "mute", &mute, NULL); - - return mute; -} - -static void -native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_set (player->player, "mute", mute, NULL); -} - -static void -native_set_surface (JNIEnv * env, jobject thiz, jobject surface) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - ANativeWindow *new_native_window; - - if (!player) - return; - - new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; - GST_DEBUG ("Received surface %p (native window %p)", surface, - new_native_window); - - if (player->native_window) { - ANativeWindow_release (player->native_window); - } - - player->native_window = new_native_window; - g_object_set (player->player, "window-handle", (gpointer) new_native_window, - NULL); -} - -static void -native_class_init (JNIEnv * env, jclass klass) -{ - native_player_field_id = - (*env)->GetFieldID (env, klass, "native_player", "J"); - on_position_updated_method_id = - (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); - on_duration_changed_method_id = - (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); - on_state_changed_method_id = - (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); - on_buffering_method_id = - (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); - on_end_of_stream_method_id = - (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); - on_error_method_id = - (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); - on_video_dimensions_changed_method_id = - (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); - - if (!native_player_field_id || - !on_position_updated_method_id || !on_duration_changed_method_id || - !on_state_changed_method_id || !on_buffering_method_id || - !on_end_of_stream_method_id || - !on_error_method_id || !on_video_dimensions_changed_method_id) { - static const gchar *message = - "The calling class does not implement all necessary interface methods"; - jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); - (*env)->ThrowNew (env, exception_class, message); - } - - gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); -} - -/* List of implemented native methods */ -static JNINativeMethod native_methods[] = { - {"nativeClassInit", "()V", (void *) native_class_init}, - {"nativeNew", "()V", (void *) native_new}, - {"nativePlay", "()V", (void *) native_play}, - {"nativePause", "()V", (void *) native_pause}, - {"nativeSeek", "(J)V", (void *) native_seek}, - {"nativeFree", "()V", (void *) native_free}, - {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, - {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, - {"nativeGetPosition", "()J", (void *) native_get_position}, - {"nativeGetDuration", "()J", (void *) native_get_duration}, - {"nativeGetVolume", "()D", (void *) native_get_volume}, - {"nativeSetVolume", "(D)V", (void *) native_set_volume}, - {"nativeGetMute", "()Z", (void *) native_get_mute}, - {"nativeSetMute", "(Z)V", (void *) native_set_mute}, - {"nativeSetSurface", "(Landroid/view/Surface;)V", - (void *) native_set_surface} -}; - -/* Library initializer */ -jint -JNI_OnLoad (JavaVM * vm, void *reserved) -{ - JNIEnv *env = NULL; - - java_vm = vm; - - if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not retrieve JNIEnv"); - return 0; - } - jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); - if (!klass) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not retrieve class org.freedesktop.gstreamer.Player"); - return 0; - } - if ((*env)->RegisterNatives (env, klass, native_methods, - G_N_ELEMENTS (native_methods))) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not register native methods for org.freedesktop.gstreamer.Player"); - return 0; - } - - pthread_key_create (¤t_jni_env, detach_current_thread); - - return JNI_VERSION_1_4; -} diff --git a/playback/player/android/res/layout/main.xml b/playback/player/android/res/layout/main.xml deleted file mode 100644 index b745d80..0000000 --- a/playback/player/android/res/layout/main.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/res/values/strings.xml b/playback/player/android/res/values/strings.xml deleted file mode 100644 index 9587e3c..0000000 --- a/playback/player/android/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - GStreamer Play - Play - Pause - diff --git a/playback/player/android/settings.gradle b/playback/player/android/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/playback/player/android/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java deleted file mode 100644 index e2bef8c..0000000 --- a/playback/player/android/src/org/freedesktop/gstreamer/Player.java +++ /dev/null @@ -1,241 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014-2015 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer; - -import java.io.Closeable; -import android.view.Surface; -import android.content.Context; -import org.freedesktop.gstreamer.GStreamer; - -public class Player implements Closeable { - private static native void nativeClassInit(); - public static void init(Context context) throws Exception { - System.loadLibrary("gstreamer_android"); - GStreamer.init(context); - - System.loadLibrary("gstplayer"); - nativeClassInit(); - } - - private long native_player; - private native void nativeNew(); - public Player() { - nativeNew(); - } - - private native void nativeFree(); - @Override - public void close() { - nativeFree(); - } - - private native void nativePlay(); - public void play() { - nativePlay(); - } - - private native void nativePause(); - public void pause() { - nativePause(); - } - - private native void nativeStop(); - public void stop() { - nativeStop(); - } - - private native void nativeSeek(long position); - public void seek(long position) { - nativeSeek(position); - } - - private native String nativeGetUri(); - public String getUri() { - return nativeGetUri(); - } - - private native void nativeSetUri(String uri); - public void setUri(String uri) { - nativeSetUri(uri); - } - - private native long nativeGetPosition(); - public long getPosition() { - return nativeGetPosition(); - } - - private native long nativeGetDuration(); - public long getDuration() { - return nativeGetDuration(); - } - - private native double nativeGetVolume(); - public double getVolume() { - return nativeGetVolume(); - } - - private native void nativeSetVolume(double volume); - public void setVolume(double volume) { - nativeSetVolume(volume); - } - - private native boolean nativeGetMute(); - public boolean getMute() { - return nativeGetMute(); - } - - private native void nativeSetMute(boolean mute); - public void setMute(boolean mute) { - nativeSetMute(mute); - } - - private Surface surface; - private native void nativeSetSurface(Surface surface); - public void setSurface(Surface surface) { - this.surface = surface; - nativeSetSurface(surface); - } - - public Surface getSurface() { - return surface; - } - - public static interface PositionUpdatedListener { - abstract void positionUpdated(Player player, long position); - } - - private PositionUpdatedListener positionUpdatedListener; - public void setPositionUpdatedListener(PositionUpdatedListener listener) { - positionUpdatedListener = listener; - } - - private void onPositionUpdated(long position) { - if (positionUpdatedListener != null) { - positionUpdatedListener.positionUpdated(this, position); - } - } - - public static interface DurationChangedListener { - abstract void durationChanged(Player player, long duration); - } - - private DurationChangedListener durationChangedListener; - public void setDurationChangedListener(DurationChangedListener listener) { - durationChangedListener = listener; - } - - private void onDurationChanged(long duration) { - if (durationChangedListener != null) { - durationChangedListener.durationChanged(this, duration); - } - } - - private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; - public enum State { - STOPPED, - BUFFERING, - PAUSED, - PLAYING - } - - public static interface StateChangedListener { - abstract void stateChanged(Player player, State state); - } - - private StateChangedListener stateChangedListener; - public void setStateChangedListener(StateChangedListener listener) { - stateChangedListener = listener; - } - - private void onStateChanged(int stateIdx) { - if (stateChangedListener != null) { - State state = stateMap[stateIdx]; - stateChangedListener.stateChanged(this, state); - } - } - - public static interface BufferingListener { - abstract void buffering(Player player, int percent); - } - - private BufferingListener bufferingListener; - public void setBufferingListener(BufferingListener listener) { - bufferingListener = listener; - } - - private void onBuffering(int percent) { - if (bufferingListener != null) { - bufferingListener.buffering(this, percent); - } - } - - public static interface EndOfStreamListener { - abstract void endOfStream(Player player); - } - - private EndOfStreamListener endOfStreamListener; - public void setEndOfStreamListener(EndOfStreamListener listener) { - endOfStreamListener = listener; - } - - private void onEndOfStream() { - if (endOfStreamListener != null) { - endOfStreamListener.endOfStream(this); - } - } - - // Keep these in sync with gstplayer.h - private static final Error[] errorMap = {Error.FAILED}; - public enum Error { - FAILED - } - - public static interface ErrorListener { - abstract void error(Player player, Error error, String errorMessage); - } - - private ErrorListener errorListener; - public void setErrorListener(ErrorListener listener) { - errorListener = listener; - } - - private void onError(int errorCode, String errorMessage) { - if (errorListener != null) { - Error error = errorMap[errorCode]; - errorListener.error(this, error, errorMessage); - } - } - - public static interface VideoDimensionsChangedListener { - abstract void videoDimensionsChanged(Player player, int width, int height); - } - - private VideoDimensionsChangedListener videoDimensionsChangedListener; - public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { - videoDimensionsChangedListener = listener; - } - - private void onVideoDimensionsChanged(int width, int height) { - if (videoDimensionsChangedListener != null) { - videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); - } - } -} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java deleted file mode 100644 index f2dd8a9..0000000 --- a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java +++ /dev/null @@ -1,105 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.SurfaceView; -import android.view.View; - -// A simple SurfaceView whose width and height can be set from the outside -public class GStreamerSurfaceView extends SurfaceView { - public int media_width = 320; - public int media_height = 240; - - // Mandatory constructors, they do not do much - public GStreamerSurfaceView(Context context, AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - } - - public GStreamerSurfaceView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public GStreamerSurfaceView (Context context) { - super(context); - } - - // Called by the layout manager to find out our size and give us some rules. - // We will try to maximize our size, and preserve the media's aspect ratio if - // we are given the freedom to do so. - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = 0, height = 0; - int wmode = View.MeasureSpec.getMode(widthMeasureSpec); - int hmode = View.MeasureSpec.getMode(heightMeasureSpec); - int wsize = View.MeasureSpec.getSize(widthMeasureSpec); - int hsize = View.MeasureSpec.getSize(heightMeasureSpec); - - Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); - // Obey width rules - switch (wmode) { - case View.MeasureSpec.AT_MOST: - if (hmode == View.MeasureSpec.EXACTLY) { - width = Math.min(hsize * media_width / media_height, wsize); - break; - } - case View.MeasureSpec.EXACTLY: - width = wsize; - break; - case View.MeasureSpec.UNSPECIFIED: - width = media_width; - } - - // Obey height rules - switch (hmode) { - case View.MeasureSpec.AT_MOST: - if (wmode == View.MeasureSpec.EXACTLY) { - height = Math.min(wsize * media_height / media_width, hsize); - break; - } - case View.MeasureSpec.EXACTLY: - height = hsize; - break; - case View.MeasureSpec.UNSPECIFIED: - height = media_height; - } - - // Finally, calculate best size when both axis are free - if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { - int correct_height = width * media_height / media_width; - int correct_width = height * media_width / media_height; - - if (correct_height < height) - height = correct_height; - else - width = correct_width; - } - - // Obey minimum size - width = Math.max (getSuggestedMinimumWidth(), width); - height = Math.max (getSuggestedMinimumHeight(), height); - setMeasuredDimension(width, height); - } - -} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java b/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java deleted file mode 100644 index 2874f05..0000000 --- a/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java +++ /dev/null @@ -1,196 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.PowerManager; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; -import android.widget.Toast; - -import org.freedesktop.gstreamer.Player; - -public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener { - private PowerManager.WakeLock wake_lock; - private Player player; - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - try { - Player.init(this); - } catch (Exception e) { - Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); - finish(); - return; - } - - setContentView(R.layout.main); - - player = new Player(); - - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); - wake_lock.setReferenceCounted(false); - - ImageButton play = (ImageButton) this.findViewById(R.id.button_play); - play.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - player.play(); - wake_lock.acquire(); - } - }); - - ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); - pause.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - player.pause(); - wake_lock.release(); - } - }); - - final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); - sb.setOnSeekBarChangeListener(this); - - player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { - public void positionUpdated(Player player, final long position) { - runOnUiThread (new Runnable() { - public void run() { - sb.setProgress((int) (position / 1000000)); - updateTimeWidget(); - } - }); - } - }); - - player.setDurationChangedListener(new Player.DurationChangedListener() { - public void durationChanged(Player player, final long duration) { - runOnUiThread (new Runnable() { - public void run() { - sb.setMax((int) (duration / 1000000)); - updateTimeWidget(); - } - }); - } - }); - - final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); - player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { - public void videoDimensionsChanged(Player player, final int width, final int height) { - runOnUiThread (new Runnable() { - public void run() { - Log.i ("GStreamer", "Media size changed to " + width + "x" + height); - gsv.media_width = width; - gsv.media_height = height; - runOnUiThread(new Runnable() { - public void run() { - gsv.requestLayout(); - } - }); - } - }); - } - }); - - SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video); - SurfaceHolder sh = sv.getHolder(); - sh.addCallback(this); - - String mediaUri = null; - Intent intent = getIntent(); - android.net.Uri uri = intent.getData(); - Log.i ("GStreamer", "Received URI: " + uri); - if (uri.getScheme().equals("content")) { - android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); - cursor.moveToFirst(); - mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); - cursor.close(); - } else { - mediaUri = uri.toString(); - } - player.setUri(mediaUri); - - updateTimeWidget(); - } - - protected void onDestroy() { - player.close(); - super.onDestroy(); - } - - private void updateTimeWidget () { - final TextView tv = (TextView) this.findViewById(R.id.textview_time); - final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); - final int pos = sb.getProgress(); - final int max = sb.getMax(); - - SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max)); - tv.setText(message); - } - - public void surfaceChanged(SurfaceHolder holder, int format, int width, - int height) { - Log.d("GStreamer", "Surface changed to format " + format + " width " - + width + " height " + height); - player.setSurface(holder.getSurface()); - } - - public void surfaceCreated(SurfaceHolder holder) { - Log.d("GStreamer", "Surface created: " + holder.getSurface()); - } - - public void surfaceDestroyed(SurfaceHolder holder) { - Log.d("GStreamer", "Surface destroyed"); - player.setSurface(null); - } - - public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { - if (!fromUser) return; - - updateTimeWidget(); - } - - public void onStartTrackingTouch(SeekBar sb) { - } - - public void onStopTrackingTouch(SeekBar sb) { - Log.d("GStreamer", "Seek to " + sb.getProgress()); - player.seek(((long) sb.getProgress()) * 1000000); - } -} -- cgit v1.2.3 From d33cc6c876263381eeaa7557639713435fec42c7 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 8 May 2015 14:54:45 +0800 Subject: playback/player: android: Fix Windows build of the app Fixes #36 --- playback/player/android/app/build.gradle | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/playback/player/android/app/build.gradle b/playback/player/android/app/build.gradle index 6039b5b..18e68bd 100644 --- a/playback/player/android/app/build.gradle +++ b/playback/player/android/app/build.gradle @@ -1,3 +1,5 @@ +import org.apache.tools.ant.taskdefs.condition.Os + apply plugin: 'com.android.application' android { @@ -57,7 +59,12 @@ android { environment PATH: "${System.getenv("PATH")}${File.pathSeparator}${ndkExtraPath}" } - commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' // Enable V=1 for debugging messages. + // Enable V=1 for debugging messages. + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine "${ndkDir}/ndk-build.cmd", '-C', file('src/main/jni').absolutePath //, 'V=1' + } else { + commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' + } } } -- cgit v1.2.3 From 1b1aed87c59ee069a0548401c1b197cd7a4d8e06 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Thu, 7 May 2015 07:38:05 -0500 Subject: playback/player: gtk-play: display cover art We maintain two drawing widgets, image and video. Cover art is drawn in image widget and video is rendered in video widget. Based on the following conditions we show either image or video widget: - if media info does not have active video stream then hide video widget and show image widget. - if media info contains active video stream then show video widget and hide the image widget. --- playback/player/gtk/gtk-play.c | 201 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 200 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 5b0b41b..4252a84 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -22,7 +22,9 @@ #include #include +#include #include +#include #include #if defined (GDK_WINDOWING_X11) @@ -52,9 +54,11 @@ typedef struct GtkWidget *prev_button, *next_button; GtkWidget *seekbar; GtkWidget *video_area; + GtkWidget *image_area; GtkWidget *volume_button; GtkWidget *media_info_button; gulong seekbar_value_changed_signal_id; + GdkPixbuf *image_pixbuf; gboolean playing; } GtkPlay; @@ -86,6 +90,8 @@ enum SUBTITLE_INFO_END, }; +static void display_cover_art (GtkPlay * play, GstPlayerMediaInfo * media_info); + static void set_title (GtkPlay * play, const gchar * title) { @@ -159,6 +165,9 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) prev = g_list_previous (play->current_uri); g_return_if_fail (prev != NULL); + if (play->image_pixbuf) + g_object_unref (play->image_pixbuf); + play->image_pixbuf = NULL; gtk_widget_set_sensitive (play->next_button, TRUE); gtk_widget_set_sensitive (play->media_info_button, FALSE); gst_player_set_uri (play->player, prev->data); @@ -177,6 +186,9 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) next = g_list_next (play->current_uri); g_return_if_fail (next != NULL); + if (play->image_pixbuf) + g_object_unref (play->image_pixbuf); + play->image_pixbuf = NULL; gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->media_info_button, FALSE); gst_player_set_uri (play->player, next->data); @@ -583,8 +595,10 @@ get_menu_label (GstPlayerStreamInfo * stream, GType type) static void disable_track (GtkPlay * play, GType type) { - if (type == GST_TYPE_PLAYER_VIDEO_INFO) + if (type == GST_TYPE_PLAYER_VIDEO_INFO) { gst_player_set_video_track_enabled (play->player, FALSE); + display_cover_art (play, NULL); /* display cover art */ + } else if (type == GST_TYPE_PLAYER_AUDIO_INFO) gst_player_set_audio_track_enabled (play->player, FALSE); else @@ -597,6 +611,11 @@ change_track (GtkPlay * play, gint index, GType type) if (type == GST_TYPE_PLAYER_VIDEO_INFO) { gst_player_set_video_track (play->player, index); gst_player_set_video_track_enabled (play->player, TRUE); + /* if video area widget is not visible then make it visible */ + if (!gtk_widget_is_visible (play->video_area)) { + gtk_widget_hide (play->image_area); + gtk_widget_show (play->video_area); + } } else if (type == GST_TYPE_PLAYER_AUDIO_INFO) { gst_player_set_audio_track (play->player, index); gst_player_set_audio_track_enabled (play->player, TRUE); @@ -749,6 +768,50 @@ mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, gtk_player_popup_menu_create (play, event); } +static gboolean +image_area_draw_cb (GtkWidget * widget, cairo_t * cr, GtkPlay * play) +{ + if (play->image_pixbuf) { + gint width, height; + gint pix_width, pix_height; + gint x = 0, y = 0; + gdouble scalex = 0.0, scaley = 0.0; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + pix_width = gdk_pixbuf_get_width (play->image_pixbuf); + pix_height = gdk_pixbuf_get_height (play->image_pixbuf); + + /* if image is bigger than widget then scale down otherwise center it. */ + if (width <= pix_width) + scalex = (gdouble)width / (gdouble)pix_width; + else + x = (width - pix_width) / 2; + if (height <= pix_height) + scaley = (gdouble)height / (gdouble)pix_height; + else + y = (height - pix_height) / 2; + + /* fill background with black */ + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + if (scalex > 0.0 && scaley > 0.0) + cairo_scale (cr, scalex, scaley); + + gdk_cairo_set_source_pixbuf(cr, play->image_pixbuf, x, y); + cairo_paint (cr); + } else { + /* fill background with black */ + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + } + + return FALSE; +} + + static void create_ui (GtkPlay * play) { @@ -769,6 +832,17 @@ create_ui (GtkPlay * play) | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); + play->image_area = gtk_drawing_area_new (); + g_signal_connect (play->image_area, "button-press-event", + G_CALLBACK (mouse_button_pressed_cb), play); + g_signal_connect (play->image_area, "draw", + G_CALLBACK (image_area_draw_cb), play); + gtk_widget_set_events (play->image_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + /* Unified play/pause button */ play->play_pause_button = gtk_button_new_from_icon_name ("media-playback-pause", @@ -825,6 +899,7 @@ create_ui (GtkPlay * play) main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (main_hbox), play->image_area, TRUE, TRUE, 0); main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); @@ -832,6 +907,7 @@ create_ui (GtkPlay * play) gtk_container_add (GTK_CONTAINER (play->window), main_vbox); gtk_widget_realize (play->video_area); + gtk_widget_hide (play->video_area); gtk_widget_show_all (play->window); } @@ -873,6 +949,9 @@ eos_cb (GstPlayer * unused, GtkPlay * play) if (!gtk_widget_is_sensitive (play->prev_button)) gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); + if (play->image_pixbuf) + g_object_unref (play->image_pixbuf); + play->image_pixbuf = NULL; gtk_widget_set_sensitive (play->media_info_button, FALSE); @@ -893,6 +972,116 @@ eos_cb (GstPlayer * unused, GtkPlay * play) } } +static gboolean +_has_active_stream (GtkPlay * play, void * (*func) (GstPlayer * player)) +{ + void *obj; + + obj = func (play->player); + if (obj) { + g_object_unref (obj); + return TRUE; + } + + return FALSE; +} + +static GdkPixbuf * +gst_sample_to_pixbuf (GtkPlay * play, GstSample * sample) +{ + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf = NULL; + GError *err = NULL; + GstMapInfo info; + GstBuffer *buffer; + const GstStructure *caps_struct; + GstTagImageType type = GST_TAG_IMAGE_TYPE_UNDEFINED; + + buffer = gst_sample_get_buffer (sample); + caps_struct = gst_sample_get_info (sample); + + /* if sample is retrieved from preview-image tag then caps struct + * will not be defined. */ + if (caps_struct) + gst_structure_get_enum (caps_struct, "image-type", + GST_TYPE_TAG_IMAGE_TYPE, &type); + + /* FIXME: Should we check more type ?? */ + if ((type != GST_TAG_IMAGE_TYPE_FRONT_COVER) && + (type != GST_TAG_IMAGE_TYPE_UNDEFINED) && + (type != GST_TAG_IMAGE_TYPE_NONE)) { + g_print ("unsupport type ... %d \n", type); + return NULL; + } + + if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) { + g_print ("failed to map gst buffer \n"); + return NULL; + } + + loader = gdk_pixbuf_loader_new (); + if (gdk_pixbuf_loader_write (loader, info.data, info.size, &err) && + gdk_pixbuf_loader_close (loader, &err)) { + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf) { + g_object_ref (pixbuf); + } + else { + g_print ("failed to convert gst buffer to pixbuf %s \n", err->message); + g_error_free (err); + } + } + + g_object_unref (loader); + gst_buffer_unmap (buffer, &info); + + return pixbuf; +} + +static void +display_cover_art (GtkPlay * play, GstPlayerMediaInfo * media_info) +{ + GstSample *sample; + GstPlayerMediaInfo *temp_media_info = NULL; + + /* hide the video widget and show image widget */ + gtk_widget_hide (play->video_area); + gtk_widget_show (play->image_area); + + /* if media information is not passed then get it from player */ + if (!media_info) + temp_media_info = media_info = gst_player_get_media_info (play->player); + + sample = gst_player_media_info_get_image_sample (media_info); + if (!sample) + goto cleanup; + + if (play->image_pixbuf) + g_object_unref (play->image_pixbuf); + + play->image_pixbuf = gst_sample_to_pixbuf (play, sample); + +cleanup: + gtk_widget_queue_draw (play->image_area); /* send expose event to widget */ + + if (temp_media_info) + g_object_unref (temp_media_info); +} + +static gboolean +has_active_stream (GtkPlay * play, GType type) +{ + if (type == GST_TYPE_PLAYER_VIDEO_INFO) + return _has_active_stream (play, + (void *) gst_player_get_current_video_track); + else if (type == GST_TYPE_PLAYER_AUDIO_INFO) + return _has_active_stream (play, + (void *) gst_player_get_current_audio_track); + else + return _has_active_stream (play, + (void *) gst_player_get_current_subtitle_track); +} + static void media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, GtkPlay * play) @@ -905,6 +1094,16 @@ media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, set_title (play, title); gtk_widget_set_sensitive (play->media_info_button, TRUE); + + /* if we have active video stream then hide image widget + * and show video widget otherwise show the cover art. + */ + if (has_active_stream (play, GST_TYPE_PLAYER_VIDEO_INFO)) { + gtk_widget_hide (play->image_area); + gtk_widget_show (play->video_area); + } else { + display_cover_art (play, media_info); + } } } -- cgit v1.2.3 From 15b1167746ae8c171df5e2e98117c723df365891 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Thu, 7 May 2015 15:21:28 -0500 Subject: playback/player: gtk-play: do not set window title in resume button cb. Window title is set from media-info-updated signal hence updating the window title in resume button callback will override the title set from media-info-updated signal. --- playback/player/gtk/gtk-play.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 4252a84..7521792 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -141,17 +141,11 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); play->playing = FALSE; } else { - gchar *title; - gst_player_play (play->player); image = gtk_image_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); - - title = gst_player_get_uri (play->player); - set_title (play, title); - g_free (title); play->playing = TRUE; } } -- cgit v1.2.3 From 9a7d2f031fa000bd3f516d20d1ae60bda6159849 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Fri, 8 May 2015 07:34:33 -0500 Subject: playback/player: gtk-play: add playlist loop button. --- playback/player/gtk/gtk-play.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 7521792..53b111b 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -57,9 +57,11 @@ typedef struct GtkWidget *image_area; GtkWidget *volume_button; GtkWidget *media_info_button; + GtkWidget *repeat_button; gulong seekbar_value_changed_signal_id; GdkPixbuf *image_pixbuf; gboolean playing; + gboolean loop; } GtkPlay; enum @@ -164,6 +166,7 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) play->image_pixbuf = NULL; gtk_widget_set_sensitive (play->next_button, TRUE); gtk_widget_set_sensitive (play->media_info_button, FALSE); + gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); gst_player_set_uri (play->player, prev->data); play->current_uri = prev; gst_player_play (play->player); @@ -185,6 +188,7 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) play->image_pixbuf = NULL; gtk_widget_set_sensitive (play->prev_button, TRUE); gtk_widget_set_sensitive (play->media_info_button, FALSE); + gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); gst_player_set_uri (play->player, next->data); play->current_uri = next; gst_player_play (play->player); @@ -809,6 +813,7 @@ image_area_draw_cb (GtkWidget * widget, cairo_t * cr, GtkPlay * play) static void create_ui (GtkPlay * play) { + GtkWidget *image; GtkWidget *controls, *main_hbox, *main_vbox; play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); @@ -847,6 +852,7 @@ create_ui (GtkPlay * play) play->seekbar = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 100, 1); gtk_scale_set_draw_value (GTK_SCALE (play->seekbar), 0); + gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); play->seekbar_value_changed_signal_id = g_signal_connect (G_OBJECT (play->seekbar), "value-changed", G_CALLBACK (seekbar_value_changed_cb), play); @@ -867,6 +873,15 @@ create_ui (GtkPlay * play) G_CALLBACK (skip_next_clicked_cb), play); gtk_widget_set_sensitive (play->next_button, FALSE); + /* Playlist repeat button */ + play->repeat_button = gtk_toggle_button_new (); + image = gtk_image_new_from_icon_name ("media-playlist-repeat", + GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (play->repeat_button), image); + if (play->loop) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->repeat_button), + TRUE); + /* Volume control button */ play->volume_button = gtk_volume_button_new (); gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), @@ -886,6 +901,8 @@ create_ui (GtkPlay * play) gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->repeat_button, + FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->media_info_button, @@ -939,6 +956,10 @@ eos_cb (GstPlayer * unused, GtkPlay * play) gchar *uri; next = g_list_next (play->current_uri); + if (!next && gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(play->repeat_button))) + next = g_list_first (play->uris); + if (next) { if (!gtk_widget_is_sensitive (play->prev_button)) gtk_widget_set_sensitive (play->prev_button, TRUE); @@ -948,6 +969,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) play->image_pixbuf = NULL; gtk_widget_set_sensitive (play->media_info_button, FALSE); + gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); gst_player_set_uri (play->player, next->data); play->current_uri = next; @@ -1110,6 +1132,7 @@ main (gint argc, gchar ** argv) GOptionEntry options[] = { {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, "Files to play"}, + {"loop", 'l', 0, G_OPTION_ARG_NONE, &play.loop, "Repeat all"}, {NULL} }; guint list_length = 0; -- cgit v1.2.3 From eb42154608738ac6fc1c999799655b64d01eaa85 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Fri, 8 May 2015 07:34:55 -0500 Subject: playback/player: gst-play: add playlist loop command line option --- playback/player/gst-play/gst-play.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 02a36f5..f22e3f2 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -46,6 +46,8 @@ typedef struct GstPlayer *player; GstState desired_state; + gboolean repeat; + GMainLoop *loop; } GstPlay; @@ -70,6 +72,9 @@ error_cb (GstPlayer * player, GError * err, GstPlay * play) { g_printerr ("ERROR %s for %s\n", err->message, play->uris[play->cur_idx]); + /* if looping is enabled, then disable it else will keep looping forever */ + play->repeat = FALSE; + /* try next item in list then */ if (!play_next (play)) { g_print ("Reached end of play list.\n"); @@ -438,8 +443,14 @@ play_uri (GstPlay * play, const gchar * next_uri) static gboolean play_next (GstPlay * play) { - if ((play->cur_idx + 1) >= play->num_uris) + if ((play->cur_idx + 1) >= play->num_uris) { + if (play->repeat) { + g_print ("Looping playlist \n"); + play->cur_idx = -1; + } + else return FALSE; + } play_uri (play, play->uris[++play->cur_idx]); return TRUE; @@ -632,6 +643,7 @@ main (int argc, char **argv) gboolean print_version = FALSE; gboolean interactive = FALSE; /* FIXME: maybe enable by default? */ gboolean shuffle = FALSE; + gboolean repeat = FALSE; gdouble volume = 1.0; gchar **filenames = NULL; gchar **uris; @@ -650,6 +662,7 @@ main (int argc, char **argv) "Volume", NULL}, {"playlist", 0, 0, G_OPTION_ARG_FILENAME, &playlist_file, "Playlist file containing input media files", NULL}, + {"loop", 0, 0, G_OPTION_ARG_NONE, &repeat, "Repeat all", NULL}, {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL}, {NULL} }; @@ -738,6 +751,7 @@ main (int argc, char **argv) /* prepare */ play = play_new (uris, volume); + play->repeat = repeat; if (interactive) { if (gst_play_kb_set_key_handler (keyboard_cb, play)) { -- cgit v1.2.3 From f9048974938e707ebf7220382751d37bd2789699 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Fri, 8 May 2015 08:30:32 -0500 Subject: playback/player: gtk-play: add fullscreen button --- playback/player/gtk/gtk-play.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 53b111b..3770da6 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -58,10 +58,12 @@ typedef struct GtkWidget *volume_button; GtkWidget *media_info_button; GtkWidget *repeat_button; + GtkWidget *fullscreen_button; gulong seekbar_value_changed_signal_id; GdkPixbuf *image_pixbuf; gboolean playing; gboolean loop; + gboolean fullscreen; } GtkPlay; enum @@ -514,6 +516,25 @@ media_info_clicked_cb (GtkButton * button, GtkPlay * play) g_object_unref (info); } +static void +fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) +{ + GtkWidget *image; + + if (gtk_toggle_button_get_active (widget)) { + image = gtk_image_new_from_icon_name ("view-restore", + GTK_ICON_SIZE_BUTTON); + gtk_window_fullscreen (GTK_WINDOW(play->window)); + gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); + } + else { + image = gtk_image_new_from_icon_name ("view-fullscreen", + GTK_ICON_SIZE_BUTTON); + gtk_window_unfullscreen (GTK_WINDOW(play->window)); + gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); + } +} + static void seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) { @@ -896,6 +917,17 @@ create_ui (GtkPlay * play) G_CALLBACK (media_info_clicked_cb), play); gtk_widget_set_sensitive (play->media_info_button, FALSE); + /* Full screen button */ + play->fullscreen_button = gtk_toggle_button_new (); + image = gtk_image_new_from_icon_name ("view-fullscreen", + GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); + g_signal_connect (G_OBJECT (play->fullscreen_button), "toggled", + G_CALLBACK (fullscreen_toggle_cb), play); + if (play->fullscreen) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->fullscreen_button), + TRUE); + controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, @@ -907,6 +939,8 @@ create_ui (GtkPlay * play) gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->media_info_button, FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->fullscreen_button, + FALSE, FALSE, 2); main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); @@ -1133,6 +1167,8 @@ main (gint argc, gchar ** argv) {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, "Files to play"}, {"loop", 'l', 0, G_OPTION_ARG_NONE, &play.loop, "Repeat all"}, + {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, &play.fullscreen, + "Show the player in fullscreen"}, {NULL} }; guint list_length = 0; -- cgit v1.2.3 From 329902bcda79ef6df829bf17a4faf9c6e54ff433 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Sun, 10 May 2015 10:18:06 -0500 Subject: playback/player: gtk-play: hide toolbar in fullscreen mode. --- playback/player/gtk/gtk-play.c | 96 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 3770da6..36d25c7 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -59,11 +59,14 @@ typedef struct GtkWidget *media_info_button; GtkWidget *repeat_button; GtkWidget *fullscreen_button; + GtkWidget *toolbar; + GdkCursor *default_cursor; gulong seekbar_value_changed_signal_id; GdkPixbuf *image_pixbuf; gboolean playing; gboolean loop; gboolean fullscreen; + gint toolbar_hide_timeout; } GtkPlay; enum @@ -516,6 +519,24 @@ media_info_clicked_cb (GtkButton * button, GtkPlay * play) g_object_unref (info); } +static gboolean +toolbar_hide_func (GtkPlay * play) +{ + GdkCursor *cursor; + + /* TODO: add some animation while hiding the toolbar. */ + gtk_widget_hide (play->toolbar); + + /* hide the mouse pointer */ + cursor = gdk_cursor_new_for_display ( + gtk_widget_get_display (play->window), GDK_BLANK_CURSOR); + gdk_window_set_cursor (gtk_widget_get_window (play->window), cursor); + g_object_unref (cursor); + + play->toolbar_hide_timeout = 0; + return FALSE; +} + static void fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) { @@ -526,8 +547,20 @@ fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) GTK_ICON_SIZE_BUTTON); gtk_window_fullscreen (GTK_WINDOW(play->window)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); + + /* start timer to hide toolbar */ + if (play->toolbar_hide_timeout) + g_source_remove (play->toolbar_hide_timeout); + play->toolbar_hide_timeout = g_timeout_add_seconds (5, + (GSourceFunc) toolbar_hide_func, play); } else { + /* if toolbar hide timer is running then kill it */ + if (play->toolbar_hide_timeout) { + g_source_remove (play->toolbar_hide_timeout); + play->toolbar_hide_timeout = 0; + } + image = gtk_image_new_from_icon_name ("view-fullscreen", GTK_ICON_SIZE_BUTTON); gtk_window_unfullscreen (GTK_WINDOW(play->window)); @@ -780,11 +813,19 @@ static void mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, GtkPlay * play) { - /* we only care about right button pressed event */ - if (event->button != 3) - return; - - gtk_player_popup_menu_create (play, event); + if (event->type == GDK_2BUTTON_PRESS) { + /* toggle fullscreen on double button click */ + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (play->fullscreen_button))) + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (play->fullscreen_button), FALSE); + else + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); + } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) { + /* popup menu on right button click */ + gtk_player_popup_menu_create (play, event); + } } static gboolean @@ -830,6 +871,31 @@ image_area_draw_cb (GtkWidget * widget, cairo_t * cr, GtkPlay * play) return FALSE; } +static gboolean +gtk_show_toolbar_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +{ + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (play->fullscreen_button))) { + + GdkCursor *cursor; + + /* if timer is running then kill it */ + if (play->toolbar_hide_timeout) { + g_source_remove (play->toolbar_hide_timeout); + play->toolbar_hide_timeout = 0; + } + + /* show mouse pointer */ + gdk_window_set_cursor (gtk_widget_get_window (play->window), + play->default_cursor); + + gtk_widget_show (play->toolbar); + play->toolbar_hide_timeout = g_timeout_add_seconds (5, + (GSourceFunc) toolbar_hide_func, play); + } + + return TRUE; +} static void create_ui (GtkPlay * play) @@ -847,21 +913,32 @@ create_ui (GtkPlay * play) G_CALLBACK (video_area_realize_cb), play); g_signal_connect (play->video_area, "button-press-event", G_CALLBACK (mouse_button_pressed_cb), play); + g_signal_connect (play->video_area, "motion-notify-event", + G_CALLBACK (gtk_show_toolbar_cb), play); + g_signal_connect (play->video_area, "scroll-event", + G_CALLBACK (gtk_show_toolbar_cb), play); gtk_widget_set_events (play->video_area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK + | GDK_ENTER_NOTIFY_MASK); play->image_area = gtk_drawing_area_new (); g_signal_connect (play->image_area, "button-press-event", G_CALLBACK (mouse_button_pressed_cb), play); g_signal_connect (play->image_area, "draw", G_CALLBACK (image_area_draw_cb), play); + g_signal_connect (play->image_area, "motion-notify-event", + G_CALLBACK (gtk_show_toolbar_cb), play); + g_signal_connect (play->image_area, "scroll-event", + G_CALLBACK (gtk_show_toolbar_cb), play); gtk_widget_set_events (play->image_area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK); + | GDK_POINTER_MOTION_HINT_MASK + | GDK_ENTER_NOTIFY_MASK); /* Unified play/pause button */ play->play_pause_button = @@ -928,7 +1005,7 @@ create_ui (GtkPlay * play) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); - controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + play->toolbar = controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, 2); @@ -955,6 +1032,9 @@ create_ui (GtkPlay * play) gtk_widget_hide (play->video_area); gtk_widget_show_all (play->window); + + play->default_cursor = gdk_window_get_cursor + (gtk_widget_get_window (play->toolbar)); } static void -- cgit v1.2.3 From 562c06c1506cc8dee4a5fc65036f1422ea73cb25 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Sun, 10 May 2015 22:04:07 -0500 Subject: playback/player: gtk-play: add Open, Quit, Next and Previous menu items in popup menu. --- playback/player/gtk/gtk-play.c | 136 ++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 29 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 36d25c7..35ce102 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -179,6 +179,61 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); } +static GList * +open_file_dialog (GtkPlay *play) +{ + int res; + GList *uris = NULL; + GtkWidget *chooser; + GtkWidget *parent; + + parent = gtk_window_new(GTK_WINDOW_TOPLEVEL); + chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); + g_object_set (chooser, "local-only", FALSE, "select-multiple", TRUE, NULL); + gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (parent)); + + res = gtk_dialog_run (GTK_DIALOG (chooser)); + if (res == GTK_RESPONSE_ACCEPT) { + GSList *l; + + l = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); + while (l) { + uris = g_list_append (uris, l->data); + l = g_slist_delete_link (l, l); + } + } + + gtk_widget_destroy (chooser); + return uris; +} + +static void +open_file_clicked_cb (GtkWidget * unused, GtkPlay *play) +{ + GList * uris, *current; + + uris = open_file_dialog (play); + if (uris) { + g_list_free_full (play->uris, g_free); + play->uris = uris; + current = g_list_first (play->uris); + + if (play->image_pixbuf) + g_object_unref (play->image_pixbuf); + play->image_pixbuf = NULL; + gtk_widget_set_sensitive (play->prev_button, FALSE); + gtk_widget_set_sensitive (play->media_info_button, FALSE); + gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); + gst_player_set_uri (play->player, current->data); + play->current_uri = current; + gst_player_play (play->player); + set_title (play, current->data); + gtk_widget_set_sensitive (play->next_button, g_list_next (current) != NULL); + } +} + static void skip_next_clicked_cb (GtkButton * button, GtkPlay * play) { @@ -705,6 +760,9 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) gint current_index; GSList *group = NULL; + if (!media_info) + return NULL; + current_index = get_current_track_index (play, type); if (type == GST_TYPE_PLAYER_VIDEO_INFO) @@ -746,6 +804,13 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) return menu; } +static void +player_quit_clicked_cb (GtkButton * button, GtkPlay * play) +{ + gst_player_stop (play->player); + gtk_main_quit (); +} + static void gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) { @@ -754,59 +819,90 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) GtkWidget *audio; GtkWidget *video; GtkWidget *sub; + GtkWidget *quit; + GtkWidget *next; + GtkWidget *prev; + GtkWidget *open; + GtkWidget *image; GtkWidget *submenu; - GstPlayerMediaInfo *media_info; - media_info = gst_player_get_media_info (play->player); - if (!media_info) - return; - menu = gtk_menu_new (); info = gtk_menu_item_new_with_label ("Media Information"); audio = gtk_menu_item_new_with_label ("Audio"); video = gtk_menu_item_new_with_label ("Video"); sub = gtk_menu_item_new_with_label ("Subtitle"); + open = gtk_menu_item_new_with_label ("Open"); + next = gtk_menu_item_new_with_label ("Next"); + prev = gtk_menu_item_new_with_label ("Prev"); + quit = gtk_menu_item_new_with_label ("Quit"); + + media_info = gst_player_get_media_info (play->player); - if (!gst_player_get_video_streams (media_info)) + if (media_info && !gst_player_get_video_streams (media_info)) gtk_widget_set_sensitive (video, FALSE); else { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_VIDEO_INFO); if (submenu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (video), submenu); + else + gtk_widget_set_sensitive (video, FALSE); } - if (!gst_player_get_audio_streams (media_info)) + if (media_info && !gst_player_get_audio_streams (media_info)) gtk_widget_set_sensitive (audio, FALSE); else { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_AUDIO_INFO); if (submenu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (audio), submenu); + else + gtk_widget_set_sensitive (audio, FALSE); } - if (!gst_player_get_subtitle_streams (media_info)) + if (media_info && !gst_player_get_subtitle_streams (media_info)) gtk_widget_set_sensitive (sub, FALSE); else { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_SUBTITLE_INFO); if (submenu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub), submenu); + else + gtk_widget_set_sensitive (sub, FALSE); } + gtk_widget_set_sensitive (next, g_list_next + (play->current_uri) ? TRUE : FALSE); + gtk_widget_set_sensitive (prev, g_list_previous + (play->current_uri) ? TRUE : FALSE); + gtk_widget_set_sensitive (info, media_info ? TRUE : FALSE); + + g_signal_connect (G_OBJECT (open), "activate", + G_CALLBACK (open_file_clicked_cb), play); + g_signal_connect (G_OBJECT (next), "activate", + G_CALLBACK (skip_next_clicked_cb), play); + g_signal_connect (G_OBJECT (prev), "activate", + G_CALLBACK (skip_prev_clicked_cb), play); g_signal_connect (G_OBJECT (info), "activate", G_CALLBACK (media_info_clicked_cb), play); + g_signal_connect (G_OBJECT (quit), "activate", + G_CALLBACK (player_quit_clicked_cb), play); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), open); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), next); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), prev); gtk_menu_shell_append (GTK_MENU_SHELL (menu), video); gtk_menu_shell_append (GTK_MENU_SHELL (menu), audio); gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub); gtk_menu_shell_append (GTK_MENU_SHELL (menu), info); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit); gtk_widget_show_all (menu); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, (event != NULL) ? event->button : 0, gdk_event_get_time ((GdkEvent *) event)); - g_object_unref (media_info); + if (media_info) + g_object_unref (media_info); } static void @@ -1272,27 +1368,9 @@ main (gint argc, gchar ** argv) // FIXME: Add support for playlists and stuff /* Parse the list of the file names we have to play. */ if (!file_names) { - GtkWidget *chooser; - int res; - - chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, - GTK_FILE_CHOOSER_ACTION_OPEN, - "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); - g_object_set (chooser, "local-only", FALSE, "select-multiple", TRUE, NULL); - - res = gtk_dialog_run (GTK_DIALOG (chooser)); - if (res == GTK_RESPONSE_ACCEPT) { - GSList *l; - - l = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); - while (l) { - play.uris = g_list_append (play.uris, l->data); - l = g_slist_delete_link (l, l); - } - } else { + play.uris = open_file_dialog (&play); + if (!play.uris) return 0; - } - gtk_widget_destroy (chooser); } else { guint i; -- cgit v1.2.3 From 4e899336b301b62a4581349db106bb17785c53f6 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 11 May 2015 10:31:08 +0800 Subject: playback/player: README.md formatting. --- playback/player/android/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/playback/player/android/README.md b/playback/player/android/README.md index cf331f7..2f8318f 100644 --- a/playback/player/android/README.md +++ b/playback/player/android/README.md @@ -9,10 +9,16 @@ Prerequisites 3. If you have a different special directory for pkg-config or other tools (e.g. on OSX when using Homebrew), then also set this path using the `ndk.extraPath` variable in **local.properties** 4. Download the GStreamer android ports http://gstreamer.freedesktop.org/data/pkg/android/ and set `gstreamer.$ABI.dir` properties in **local.properties**: +Sample local.properties: + + sdk.dir=/path/to/android-sdk/ + ndk.dir=/path/to/android-ndk/ + ndk.extraPath=/usr/local/bin gstreamer.arm.dir=/path/to/gstreamer-1.0-android-arm-release-1.4.5/ gstreamer.armv7.dir=/path/to/gstreamer-1.0-android-armv7-release-1.4.5/ gstreamer.x86.dir=/path/to/gstreamer-1.0-android-x86-release-1.4.5/ + Compiling the sample -------------------- @@ -47,4 +53,4 @@ If you don't want to build all architectures, please modify the file `app/src/ma Finally, within the `app/src/main/` directory, invoke: - ndk-build \ No newline at end of file + ndk-build -- cgit v1.2.3 From 21eb4b1ac765565469a1946983da3471deca4c92 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 11 May 2015 09:23:27 +0200 Subject: playback/player: android: Unref player in native_free() This makes sure it is actually shut down and does not emit any signals anymore later, and also prevents a memory leak. --- playback/player/android/app/src/main/jni/player.c | 1 + 1 file changed, 1 insertion(+) diff --git a/playback/player/android/app/src/main/jni/player.c b/playback/player/android/app/src/main/jni/player.c index 951f2c6..882c230 100644 --- a/playback/player/android/app/src/main/jni/player.c +++ b/playback/player/android/app/src/main/jni/player.c @@ -224,6 +224,7 @@ native_free (JNIEnv * env, jobject thiz) if (!player) return; + g_object_unref (player->player); (*env)->DeleteGlobalRef (env, player->java_player); g_free (player); SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); -- cgit v1.2.3 From 75404ed8e3fde50d13a4a4155fb2b898c1a03a55 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Mon, 11 May 2015 08:07:48 -0500 Subject: playback/player: gtk-play: move duplicate code into one function --- playback/player/gtk/gtk-play.c | 83 ++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 56 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 35ce102..2c0ad77 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -158,25 +158,33 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) } static void -skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) +play_current_uri (GtkPlay * play, GList * uri) { - GList *prev; - gchar *cur_uri; - - prev = g_list_previous (play->current_uri); - g_return_if_fail (prev != NULL); - + /* reset the button/widget state to default */ if (play->image_pixbuf) g_object_unref (play->image_pixbuf); play->image_pixbuf = NULL; - gtk_widget_set_sensitive (play->next_button, TRUE); gtk_widget_set_sensitive (play->media_info_button, FALSE); gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); - gst_player_set_uri (play->player, prev->data); - play->current_uri = prev; + gtk_widget_set_sensitive (play->prev_button, g_list_previous (uri) != NULL); + gtk_widget_set_sensitive (play->next_button, g_list_next (uri) != NULL); + + /* play uri */ + gst_player_set_uri (play->player, uri->data); + play->current_uri = uri; gst_player_play (play->player); - set_title (play, prev->data); - gtk_widget_set_sensitive (play->prev_button, g_list_previous (prev) != NULL); + set_title (play, uri->data); +} + +static void +skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) +{ + GList *prev; + + prev = g_list_previous (play->current_uri); + g_return_if_fail (prev != NULL); + + play_current_uri (play, prev); } static GList * @@ -216,44 +224,23 @@ open_file_clicked_cb (GtkWidget * unused, GtkPlay *play) uris = open_file_dialog (play); if (uris) { + /* free existing playlist */ g_list_free_full (play->uris, g_free); + play->uris = uris; - current = g_list_first (play->uris); - - if (play->image_pixbuf) - g_object_unref (play->image_pixbuf); - play->image_pixbuf = NULL; - gtk_widget_set_sensitive (play->prev_button, FALSE); - gtk_widget_set_sensitive (play->media_info_button, FALSE); - gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); - gst_player_set_uri (play->player, current->data); - play->current_uri = current; - gst_player_play (play->player); - set_title (play, current->data); - gtk_widget_set_sensitive (play->next_button, g_list_next (current) != NULL); + play_current_uri (play, g_list_first (play->uris)); } } static void skip_next_clicked_cb (GtkButton * button, GtkPlay * play) { - GList *next, *l; - gchar *cur_uri; + GList *next; next = g_list_next (play->current_uri); g_return_if_fail (next != NULL); - if (play->image_pixbuf) - g_object_unref (play->image_pixbuf); - play->image_pixbuf = NULL; - gtk_widget_set_sensitive (play->prev_button, TRUE); - gtk_widget_set_sensitive (play->media_info_button, FALSE); - gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); - gst_player_set_uri (play->player, next->data); - play->current_uri = next; - gst_player_play (play->player); - set_title (play, next->data); - gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); + play_current_uri (play, next); } static const gchar * @@ -1171,20 +1158,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) next = g_list_first (play->uris); if (next) { - if (!gtk_widget_is_sensitive (play->prev_button)) - gtk_widget_set_sensitive (play->prev_button, TRUE); - gtk_widget_set_sensitive (play->next_button, g_list_next (next) != NULL); - if (play->image_pixbuf) - g_object_unref (play->image_pixbuf); - play->image_pixbuf = NULL; - - gtk_widget_set_sensitive (play->media_info_button, FALSE); - gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); - - gst_player_set_uri (play->player, next->data); - play->current_uri = next; - gst_player_play (play->player); - set_title (play, next->data); + play_current_uri (play, next); } else { GtkWidget *image; @@ -1391,12 +1365,9 @@ main (gint argc, gchar ** argv) g_object_set (play.player, "dispatch-to-main-context", TRUE, NULL); - gst_player_set_uri (play.player, g_list_first (play.uris)->data); - create_ui (&play); - if (list_length > 1) - gtk_widget_set_sensitive (play.next_button, TRUE); + play_current_uri (&play, g_list_first (play.uris)); g_signal_connect (play.player, "position-updated", G_CALLBACK (position_updated_cb), &play); -- cgit v1.2.3 From ddd72139591616e6cc00290c07dfa01c110e723b Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 13 May 2015 22:30:48 +0300 Subject: playback/player: ios: Cast the seek slider value from float to integer after scaling https://github.com/sdroege/gst-player/issues/33 --- playback/player/ios/GstPlay/VideoViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index 5c752f2..dcf06b2 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -114,7 +114,7 @@ if (!dragging_slider) return; // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved. if (is_local_media) - gst_player_seek (player, ((long)time_slider.value) * 1000000); + gst_player_seek (player, time_slider.value * 1000000); [self updateTimeWidget]; } -- cgit v1.2.3 From 571cdae9dadd534e11161a83bb6920e6081d5869 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 19 May 2015 10:34:49 -0500 Subject: playback/player: gtk-play: add external subtitle selection menu --- playback/player/gtk/gtk-play.c | 65 ++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 2c0ad77..5667b15 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -158,7 +158,7 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) } static void -play_current_uri (GtkPlay * play, GList * uri) +play_current_uri (GtkPlay * play, GList * uri, const gchar *ext_suburi) { /* reset the button/widget state to default */ if (play->image_pixbuf) @@ -169,8 +169,11 @@ play_current_uri (GtkPlay * play, GList * uri) gtk_widget_set_sensitive (play->prev_button, g_list_previous (uri) != NULL); gtk_widget_set_sensitive (play->next_button, g_list_next (uri) != NULL); - /* play uri */ - gst_player_set_uri (play->player, uri->data); + /* set uri or suburi */ + if (ext_suburi) + gst_player_set_subtitle_uri (play->player, ext_suburi); + else + gst_player_set_uri (play->player, uri->data); play->current_uri = uri; gst_player_play (play->player); set_title (play, uri->data); @@ -184,11 +187,11 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) prev = g_list_previous (play->current_uri); g_return_if_fail (prev != NULL); - play_current_uri (play, prev); + play_current_uri (play, prev, NULL); } static GList * -open_file_dialog (GtkPlay *play) +open_file_dialog (GtkPlay *play, gboolean multi) { int res; GList *uris = NULL; @@ -199,7 +202,7 @@ open_file_dialog (GtkPlay *play) chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); - g_object_set (chooser, "local-only", FALSE, "select-multiple", TRUE, NULL); + g_object_set (chooser, "local-only", FALSE, "select-multiple", multi, NULL); gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (parent)); res = gtk_dialog_run (GTK_DIALOG (chooser)); @@ -222,13 +225,13 @@ open_file_clicked_cb (GtkWidget * unused, GtkPlay *play) { GList * uris, *current; - uris = open_file_dialog (play); + uris = open_file_dialog (play, TRUE); if (uris) { /* free existing playlist */ g_list_free_full (play->uris, g_free); play->uris = uris; - play_current_uri (play, g_list_first (play->uris)); + play_current_uri (play, g_list_first (play->uris), NULL); } } @@ -240,7 +243,7 @@ skip_next_clicked_cb (GtkButton * button, GtkPlay * play) next = g_list_next (play->current_uri); g_return_if_fail (next != NULL); - play_current_uri (play, next); + play_current_uri (play, next, NULL); } static const gchar * @@ -686,6 +689,18 @@ get_menu_label (GstPlayerStreamInfo * stream, GType type) return NULL; } +static void +new_subtitle_clicked_cb (GtkWidget * unused, GtkPlay *play) +{ + GList * uri; + + uri = open_file_dialog (play, FALSE); + if (uri) { + play_current_uri (play, play->current_uri, uri->data); + g_list_free_full (uri, g_free); + } +} + static void disable_track (GtkPlay * play, GType type) { @@ -743,6 +758,7 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) { GtkWidget *menu; GtkWidget *item; + GtkWidget *sep; GList *list, *l; gint current_index; GSList *group = NULL; @@ -761,6 +777,16 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) menu = gtk_menu_new (); + if (type == GST_TYPE_PLAYER_SUBTITLE_INFO) { + GtkWidget *ext_subtitle; + ext_subtitle = gtk_menu_item_new_with_label ("New File"); + sep = gtk_separator_menu_item_new (); + g_signal_connect (G_OBJECT (ext_subtitle), "activate", + G_CALLBACK (new_subtitle_clicked_cb), play); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), ext_subtitle); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); + } + for (l = list; l != NULL; l = l->next) { gint index; gchar *buffer; @@ -779,6 +805,8 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) G_CALLBACK (track_changed_cb), play); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); } + + sep = gtk_separator_menu_item_new (); item = gtk_radio_menu_item_new_with_label (group, "Disable"); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); g_object_set_data (G_OBJECT (item), "index", GINT_TO_POINTER (-1)); @@ -787,7 +815,9 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (track_changed_cb), play); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + return menu; } @@ -846,15 +876,12 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_widget_set_sensitive (audio, FALSE); } - if (media_info && !gst_player_get_subtitle_streams (media_info)) - gtk_widget_set_sensitive (sub, FALSE); - else { + if (media_info) { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_SUBTITLE_INFO); - if (submenu) - gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub), submenu); - else - gtk_widget_set_sensitive (sub, FALSE); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub), submenu); + } else { + gtk_widget_set_sensitive (sub, FALSE); } gtk_widget_set_sensitive (next, g_list_next @@ -1158,7 +1185,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) next = g_list_first (play->uris); if (next) { - play_current_uri (play, next); + play_current_uri (play, next, NULL); } else { GtkWidget *image; @@ -1342,7 +1369,7 @@ main (gint argc, gchar ** argv) // FIXME: Add support for playlists and stuff /* Parse the list of the file names we have to play. */ if (!file_names) { - play.uris = open_file_dialog (&play); + play.uris = open_file_dialog (&play, TRUE); if (!play.uris) return 0; } else { @@ -1367,7 +1394,7 @@ main (gint argc, gchar ** argv) create_ui (&play); - play_current_uri (&play, g_list_first (play.uris)); + play_current_uri (&play, g_list_first (play.uris), NULL); g_signal_connect (play.player, "position-updated", G_CALLBACK (position_updated_cb), &play); -- cgit v1.2.3 From b69cbd6b70a2ee2c8151d3af3f01c936930d61ad Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Tue, 19 May 2015 10:38:06 -0500 Subject: playback/player: gtk-player: add visualization selection menu item. --- playback/player/gtk/gtk-play.c | 120 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 5667b15..b91072e 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -753,6 +753,85 @@ track_changed_cb (GtkWidget * widget, GtkPlay * play) change_track (play, index, type); } +static void +visualization_changed_cb (GtkWidget * widget, GtkPlay * play) +{ + gchar *name; + + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) { + + /* video_area is window-id is shared with playbin hence + * video_area widget will be used by visualization elements to + * render the visuals. If visualization is enabled then hide + * image widget and show video widget and similiarly when visualization + * is disabled then hide video widget and show imag widget. + */ + name = g_object_get_data (G_OBJECT (widget), "name"); + if (g_strcmp0 (name, "disable") == 0) { + gst_player_set_visualization_enabled (play->player, FALSE); + gtk_widget_hide (play->video_area); + gtk_widget_show (play->image_area); + } + else { + const gchar *vis_name; + + gst_player_set_visualization (play->player, name); + /* if visualization is not enabled then enable it */ + if (!(vis_name = gst_player_get_current_visualization (play->player))) { + gst_player_set_visualization_enabled (play->player, TRUE); + } + gtk_widget_hide (play->image_area); + gtk_widget_show (play->video_area); + } + } +} + +static GtkWidget * +create_visualization_menu (GtkPlay * play) +{ + gint i; + GtkWidget *menu; + GtkWidget *item; + GtkWidget *sep; + const GList *list; + GSList *group = NULL; + const gchar *cur_vis; + gchar **vis_names; + + menu = gtk_menu_new (); + cur_vis = gst_player_get_current_visualization (play->player); + vis_names = gst_player_get_visualization_elements_name (); + + for (i = 0; vis_names[i] != NULL; i++) { + gchar *label = (gchar *) vis_names[i]; + + item = gtk_radio_menu_item_new_with_label (group, label); + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); + if (g_strcmp0 (label, cur_vis) == 0) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + g_object_set_data (G_OBJECT (item), "name", label); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + g_signal_connect (G_OBJECT (item), "toggled", + G_CALLBACK (visualization_changed_cb), play); + } + + sep = gtk_separator_menu_item_new (); + item = gtk_radio_menu_item_new_with_label (group, "Disable"); + group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); + g_object_set_data (G_OBJECT (item), "name", "disable"); + if (cur_vis == NULL) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + g_signal_connect (G_OBJECT (item), "toggled", + G_CALLBACK (visualization_changed_cb), play); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + if (vis_names) + g_free (vis_names); + + return menu; +} + static GtkWidget * create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) { @@ -842,6 +921,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) GtkWidget *open; GtkWidget *image; GtkWidget *submenu; + GtkWidget *vis; GstPlayerMediaInfo *media_info; menu = gtk_menu_new (); @@ -853,6 +933,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) next = gtk_menu_item_new_with_label ("Next"); prev = gtk_menu_item_new_with_label ("Prev"); quit = gtk_menu_item_new_with_label ("Quit"); + vis = gtk_menu_item_new_with_label ("Visualization"); media_info = gst_player_get_media_info (play->player); @@ -876,7 +957,17 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_widget_set_sensitive (audio, FALSE); } - if (media_info) { + /* enable visualization menu for audio stream */ + if (media_info && + gst_player_get_audio_streams (media_info) && + !gst_player_get_video_streams (media_info)) { + submenu = create_visualization_menu (play); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (vis), submenu); + } else { + gtk_widget_set_sensitive (vis, FALSE); + } + + if (media_info && gst_player_get_video_streams (media_info)) { submenu = create_tracks_menu (play, media_info, GST_TYPE_PLAYER_SUBTITLE_INFO); gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub), submenu); @@ -906,6 +997,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_menu_shell_append (GTK_MENU_SHELL (menu), prev); gtk_menu_shell_append (GTK_MENU_SHELL (menu), video); gtk_menu_shell_append (GTK_MENU_SHELL (menu), audio); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), vis); gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub); gtk_menu_shell_append (GTK_MENU_SHELL (menu), info); gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit); @@ -1315,6 +1407,7 @@ media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, { if (!gtk_widget_is_sensitive (play->media_info_button)) { const gchar *title; + const gchar *vis; title = gst_player_media_info_get_title (media_info); if (title) @@ -1331,6 +1424,16 @@ media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, } else { display_cover_art (play, media_info); } + + /* if we have audio only stream and visualization is enabled + * then show video widget. + */ + vis = gst_player_get_current_visualization (play->player); + if (!has_active_stream (play, GST_TYPE_PLAYER_VIDEO_INFO) && + has_active_stream (play, GST_TYPE_PLAYER_AUDIO_INFO) && vis) { + gtk_widget_show (play->video_area); + gtk_widget_hide (play->image_area); + } } } @@ -1340,12 +1443,15 @@ main (gint argc, gchar ** argv) GtkPlay play; gchar **file_names = NULL; GOptionContext *ctx; + gboolean vis = FALSE; GOptionEntry options[] = { {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, "Files to play"}, {"loop", 'l', 0, G_OPTION_ARG_NONE, &play.loop, "Repeat all"}, {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, &play.fullscreen, "Show the player in fullscreen"}, + {"visual", 'v', 0, G_OPTION_ARG_NONE, &vis, + "Show visualization when there is no video stream"}, {NULL} }; guint list_length = 0; @@ -1394,6 +1500,18 @@ main (gint argc, gchar ** argv) create_ui (&play); + /* if visualization is enabled then use the first element */ + if (vis) { + gchar **vis_names; + vis_names = gst_player_get_visualization_elements_name (); + + if (vis_names) { + gst_player_set_visualization (play.player, vis_names[0]); + gst_player_set_visualization_enabled (play.player, TRUE); + g_free (vis_names); + } + } + play_current_uri (&play, g_list_first (play.uris), NULL); g_signal_connect (play.player, "position-updated", -- cgit v1.2.3 From 999365f0d206fe2c23a8e873b74f14efe419f726 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 30 May 2015 10:48:34 +0200 Subject: playback/player: Fix indention --- playback/player/gtk/gtk-play.c | 83 +++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index b91072e..ddfd3c1 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -158,7 +158,7 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) } static void -play_current_uri (GtkPlay * play, GList * uri, const gchar *ext_suburi) +play_current_uri (GtkPlay * play, GList * uri, const gchar * ext_suburi) { /* reset the button/widget state to default */ if (play->image_pixbuf) @@ -191,14 +191,14 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) } static GList * -open_file_dialog (GtkPlay *play, gboolean multi) +open_file_dialog (GtkPlay * play, gboolean multi) { int res; GList *uris = NULL; GtkWidget *chooser; GtkWidget *parent; - parent = gtk_window_new(GTK_WINDOW_TOPLEVEL); + parent = gtk_window_new (GTK_WINDOW_TOPLEVEL); chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); @@ -221,9 +221,9 @@ open_file_dialog (GtkPlay *play, gboolean multi) } static void -open_file_clicked_cb (GtkWidget * unused, GtkPlay *play) +open_file_clicked_cb (GtkWidget * unused, GtkPlay * play) { - GList * uris, *current; + GList *uris, *current; uris = open_file_dialog (play, TRUE); if (uris) { @@ -573,8 +573,9 @@ toolbar_hide_func (GtkPlay * play) gtk_widget_hide (play->toolbar); /* hide the mouse pointer */ - cursor = gdk_cursor_new_for_display ( - gtk_widget_get_display (play->window), GDK_BLANK_CURSOR); + cursor = + gdk_cursor_new_for_display (gtk_widget_get_display (play->window), + GDK_BLANK_CURSOR); gdk_window_set_cursor (gtk_widget_get_window (play->window), cursor); g_object_unref (cursor); @@ -588,9 +589,8 @@ fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) GtkWidget *image; if (gtk_toggle_button_get_active (widget)) { - image = gtk_image_new_from_icon_name ("view-restore", - GTK_ICON_SIZE_BUTTON); - gtk_window_fullscreen (GTK_WINDOW(play->window)); + image = gtk_image_new_from_icon_name ("view-restore", GTK_ICON_SIZE_BUTTON); + gtk_window_fullscreen (GTK_WINDOW (play->window)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); /* start timer to hide toolbar */ @@ -598,8 +598,7 @@ fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) g_source_remove (play->toolbar_hide_timeout); play->toolbar_hide_timeout = g_timeout_add_seconds (5, (GSourceFunc) toolbar_hide_func, play); - } - else { + } else { /* if toolbar hide timer is running then kill it */ if (play->toolbar_hide_timeout) { g_source_remove (play->toolbar_hide_timeout); @@ -608,7 +607,7 @@ fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) image = gtk_image_new_from_icon_name ("view-fullscreen", GTK_ICON_SIZE_BUTTON); - gtk_window_unfullscreen (GTK_WINDOW(play->window)); + gtk_window_unfullscreen (GTK_WINDOW (play->window)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); } } @@ -690,9 +689,9 @@ get_menu_label (GstPlayerStreamInfo * stream, GType type) } static void -new_subtitle_clicked_cb (GtkWidget * unused, GtkPlay *play) +new_subtitle_clicked_cb (GtkWidget * unused, GtkPlay * play) { - GList * uri; + GList *uri; uri = open_file_dialog (play, FALSE); if (uri) { @@ -706,9 +705,8 @@ disable_track (GtkPlay * play, GType type) { if (type == GST_TYPE_PLAYER_VIDEO_INFO) { gst_player_set_video_track_enabled (play->player, FALSE); - display_cover_art (play, NULL); /* display cover art */ - } - else if (type == GST_TYPE_PLAYER_AUDIO_INFO) + display_cover_art (play, NULL); /* display cover art */ + } else if (type == GST_TYPE_PLAYER_AUDIO_INFO) gst_player_set_audio_track_enabled (play->player, FALSE); else gst_player_set_subtitle_track_enabled (play->player, FALSE); @@ -771,8 +769,7 @@ visualization_changed_cb (GtkWidget * widget, GtkPlay * play) gst_player_set_visualization_enabled (play->player, FALSE); gtk_widget_hide (play->video_area); gtk_widget_show (play->image_area); - } - else { + } else { const gchar *vis_name; gst_player_set_visualization (play->player, name); @@ -964,7 +961,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) submenu = create_visualization_menu (play); gtk_menu_item_set_submenu (GTK_MENU_ITEM (vis), submenu); } else { - gtk_widget_set_sensitive (vis, FALSE); + gtk_widget_set_sensitive (vis, FALSE); } if (media_info && gst_player_get_video_streams (media_info)) { @@ -1020,10 +1017,10 @@ mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (play->fullscreen_button))) gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (play->fullscreen_button), FALSE); + (GTK_TOGGLE_BUTTON (play->fullscreen_button), FALSE); else gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); + (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); } else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) { /* popup menu on right button click */ gtk_player_popup_menu_create (play, event); @@ -1046,11 +1043,11 @@ image_area_draw_cb (GtkWidget * widget, cairo_t * cr, GtkPlay * play) /* if image is bigger than widget then scale down otherwise center it. */ if (width <= pix_width) - scalex = (gdouble)width / (gdouble)pix_width; + scalex = (gdouble) width / (gdouble) pix_width; else x = (width - pix_width) / 2; if (height <= pix_height) - scaley = (gdouble)height / (gdouble)pix_height; + scaley = (gdouble) height / (gdouble) pix_height; else y = (height - pix_height) / 2; @@ -1060,9 +1057,9 @@ image_area_draw_cb (GtkWidget * widget, cairo_t * cr, GtkPlay * play) cairo_fill (cr); if (scalex > 0.0 && scaley > 0.0) - cairo_scale (cr, scalex, scaley); + cairo_scale (cr, scalex, scaley); - gdk_cairo_set_source_pixbuf(cr, play->image_pixbuf, x, y); + gdk_cairo_set_source_pixbuf (cr, play->image_pixbuf, x, y); cairo_paint (cr); } else { /* fill background with black */ @@ -1123,8 +1120,7 @@ create_ui (GtkPlay * play) | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK - | GDK_ENTER_NOTIFY_MASK); + | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK); play->image_area = gtk_drawing_area_new (); g_signal_connect (play->image_area, "button-press-event", @@ -1136,11 +1132,10 @@ create_ui (GtkPlay * play) g_signal_connect (play->image_area, "scroll-event", G_CALLBACK (gtk_show_toolbar_cb), play); gtk_widget_set_events (play->image_area, GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK - | GDK_ENTER_NOTIFY_MASK); + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK); /* Unified play/pause button */ play->play_pause_button = @@ -1176,7 +1171,7 @@ create_ui (GtkPlay * play) /* Playlist repeat button */ play->repeat_button = gtk_toggle_button_new (); image = gtk_image_new_from_icon_name ("media-playlist-repeat", - GTK_ICON_SIZE_BUTTON); + GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (play->repeat_button), image); if (play->loop) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->repeat_button), @@ -1212,8 +1207,7 @@ create_ui (GtkPlay * play) gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->repeat_button, - FALSE, FALSE, 2); + gtk_box_pack_start (GTK_BOX (controls), play->repeat_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); gtk_box_pack_start (GTK_BOX (controls), play->media_info_button, @@ -1236,7 +1230,7 @@ create_ui (GtkPlay * play) gtk_widget_show_all (play->window); play->default_cursor = gdk_window_get_cursor - (gtk_widget_get_window (play->toolbar)); + (gtk_widget_get_window (play->toolbar)); } static void @@ -1273,7 +1267,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) next = g_list_next (play->current_uri); if (!next && gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON(play->repeat_button))) + (GTK_TOGGLE_BUTTON (play->repeat_button))) next = g_list_first (play->uris); if (next) { @@ -1292,7 +1286,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) } static gboolean -_has_active_stream (GtkPlay * play, void * (*func) (GstPlayer * player)) +_has_active_stream (GtkPlay * play, void *(*func) (GstPlayer * player)) { void *obj; @@ -1344,8 +1338,7 @@ gst_sample_to_pixbuf (GtkPlay * play, GstSample * sample) pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); if (pixbuf) { g_object_ref (pixbuf); - } - else { + } else { g_print ("failed to convert gst buffer to pixbuf %s \n", err->message); g_error_free (err); } @@ -1381,7 +1374,7 @@ display_cover_art (GtkPlay * play, GstPlayerMediaInfo * media_info) play->image_pixbuf = gst_sample_to_pixbuf (play, sample); cleanup: - gtk_widget_queue_draw (play->image_area); /* send expose event to widget */ + gtk_widget_queue_draw (play->image_area); /* send expose event to widget */ if (temp_media_info) g_object_unref (temp_media_info); @@ -1449,9 +1442,9 @@ main (gint argc, gchar ** argv) "Files to play"}, {"loop", 'l', 0, G_OPTION_ARG_NONE, &play.loop, "Repeat all"}, {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, &play.fullscreen, - "Show the player in fullscreen"}, + "Show the player in fullscreen"}, {"visual", 'v', 0, G_OPTION_ARG_NONE, &vis, - "Show visualization when there is no video stream"}, + "Show visualization when there is no video stream"}, {NULL} }; guint list_length = 0; -- cgit v1.2.3 From 5aa6c468a02bd7f61a87acedba43f61e183b1e04 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Sat, 30 May 2015 11:35:25 +0200 Subject: playback/player: player: Change visualization API a bit to be more user friendly and fix some leaks and other bugs --- playback/player/gtk/gtk-play.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index ddfd3c1..fff5aec 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -790,27 +790,30 @@ create_visualization_menu (GtkPlay * play) GtkWidget *menu; GtkWidget *item; GtkWidget *sep; - const GList *list; GSList *group = NULL; const gchar *cur_vis; - gchar **vis_names; + GstPlayerVisualization **viss, **p; menu = gtk_menu_new (); cur_vis = gst_player_get_current_visualization (play->player); - vis_names = gst_player_get_visualization_elements_name (); + viss = gst_player_visualizations_get (); - for (i = 0; vis_names[i] != NULL; i++) { - gchar *label = (gchar *) vis_names[i]; + p = viss; + while (*p) { + gchar *label = g_strdup ((*p)->name); item = gtk_radio_menu_item_new_with_label (group, label); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); if (g_strcmp0 (label, cur_vis) == 0) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); - g_object_set_data (G_OBJECT (item), "name", label); + g_object_set_data_full (G_OBJECT (item), "name", label, + (GDestroyNotify) g_free); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (visualization_changed_cb), play); + p++; } + gst_player_visualizations_free (viss); sep = gtk_separator_menu_item_new (); item = gtk_radio_menu_item_new_with_label (group, "Disable"); @@ -823,9 +826,6 @@ create_visualization_menu (GtkPlay * play) gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - if (vis_names) - g_free (vis_names); - return menu; } @@ -1495,14 +1495,15 @@ main (gint argc, gchar ** argv) /* if visualization is enabled then use the first element */ if (vis) { - gchar **vis_names; - vis_names = gst_player_get_visualization_elements_name (); + GstPlayerVisualization **viss; + viss = gst_player_visualizations_get (); - if (vis_names) { - gst_player_set_visualization (play.player, vis_names[0]); + if (viss && *viss) { + gst_player_set_visualization (play.player, (*viss)->name); gst_player_set_visualization_enabled (play.player, TRUE); - g_free (vis_names); } + if (viss) + gst_player_visualizations_free (viss); } play_current_uri (&play, g_list_first (play.uris), NULL); -- cgit v1.2.3 From 76fb77bfe83471d0f3350aa63f7668231f1cf93e Mon Sep 17 00:00:00 2001 From: danny song Date: Thu, 4 Jun 2015 02:49:55 +0900 Subject: playback/player: gtk-play: move play_current_uri after the signal handler registration --- playback/player/gtk/gtk-play.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index fff5aec..86c426b 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1506,8 +1506,6 @@ main (gint argc, gchar ** argv) gst_player_visualizations_free (viss); } - play_current_uri (&play, g_list_first (play.uris), NULL); - g_signal_connect (play.player, "position-updated", G_CALLBACK (position_updated_cb), &play); g_signal_connect (play.player, "duration-changed", @@ -1521,6 +1519,8 @@ main (gint argc, gchar ** argv) gst_player_play (play.player); play.current_uri = g_list_first (play.uris); + play_current_uri (&play, g_list_first (play.uris), NULL); + gtk_main (); play_clear (&play); -- cgit v1.2.3 From 07a074be042d69ad6310f6c8fe4ba1e1453f2fda Mon Sep 17 00:00:00 2001 From: danny song Date: Thu, 4 Jun 2015 01:45:51 +0900 Subject: playback/player: gtk-play: remove duplicate code --- playback/player/gtk/gtk-play.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 86c426b..ae288f3 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1514,11 +1514,6 @@ main (gint argc, gchar ** argv) g_signal_connect (play.player, "media-info-updated", G_CALLBACK (media_info_updated_cb), &play); - /* We have file(s) that need playing. */ - set_title (&play, g_list_first (play.uris)->data); - gst_player_play (play.player); - play.current_uri = g_list_first (play.uris); - play_current_uri (&play, g_list_first (play.uris), NULL); gtk_main (); -- cgit v1.2.3 From ddc42da7fe183bd4beecb98b6f6a17d00efc850a Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Tue, 9 Jun 2015 17:37:50 +0200 Subject: playback/player: gtk-play: destroy dialog's parent window --- playback/player/gtk/gtk-play.c | 1 + 1 file changed, 1 insertion(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index ae288f3..fb90063 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -217,6 +217,7 @@ open_file_dialog (GtkPlay * play, gboolean multi) } gtk_widget_destroy (chooser); + gtk_widget_destroy (parent); return uris; } -- cgit v1.2.3 From 91379afe55bbc18f8f7c6ef08feda02f9aec75fb Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Tue, 2 Jun 2015 13:03:06 +0200 Subject: playback/player: gtk-play: remove unused variables --- playback/player/gtk/gtk-play.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index fb90063..1103d1f 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -224,7 +224,7 @@ open_file_dialog (GtkPlay * play, gboolean multi) static void open_file_clicked_cb (GtkWidget * unused, GtkPlay * play) { - GList *uris, *current; + GList *uris; uris = open_file_dialog (play, TRUE); if (uris) { @@ -787,7 +787,6 @@ visualization_changed_cb (GtkWidget * widget, GtkPlay * play) static GtkWidget * create_visualization_menu (GtkPlay * play) { - gint i; GtkWidget *menu; GtkWidget *item; GtkWidget *sep; @@ -917,7 +916,6 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) GtkWidget *next; GtkWidget *prev; GtkWidget *open; - GtkWidget *image; GtkWidget *submenu; GtkWidget *vis; GstPlayerMediaInfo *media_info; @@ -1077,8 +1075,6 @@ gtk_show_toolbar_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (play->fullscreen_button))) { - GdkCursor *cursor; - /* if timer is running then kill it */ if (play->toolbar_hide_timeout) { g_source_remove (play->toolbar_hide_timeout); @@ -1264,7 +1260,6 @@ eos_cb (GstPlayer * unused, GtkPlay * play) { if (play->playing) { GList *next = NULL; - gchar *uri; next = g_list_next (play->current_uri); if (!next && gtk_toggle_button_get_active @@ -1450,7 +1445,6 @@ main (gint argc, gchar ** argv) }; guint list_length = 0; GError *err = NULL; - GList *l; memset (&play, 0, sizeof (play)); -- cgit v1.2.3 From b647f6858a514225300760f98a5224880bc4cc52 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jun 2015 13:09:25 +0200 Subject: playback/player: gtk: Only go to PLAYING with the next file if we were in PLAYING state before Otherwise setting a subtitle URI in PAUSED will automatically go to PLAYING. --- playback/player/gtk/gtk-play.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 1103d1f..cc7b742 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -175,7 +175,10 @@ play_current_uri (GtkPlay * play, GList * uri, const gchar * ext_suburi) else gst_player_set_uri (play->player, uri->data); play->current_uri = uri; - gst_player_play (play->player); + if (play->playing) + gst_player_play (play->player); + else + gst_player_pause (play->player); set_title (play, uri->data); } @@ -1509,6 +1512,7 @@ main (gint argc, gchar ** argv) g_signal_connect (play.player, "media-info-updated", G_CALLBACK (media_info_updated_cb), &play); + play.playing = TRUE; play_current_uri (&play, g_list_first (play.uris), NULL); gtk_main (); -- cgit v1.2.3 From 80eefca0d123cb610f9595bdf1cfd5051fbe9386 Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Tue, 9 Jun 2015 17:38:15 +0200 Subject: playback/player: gtk-play: color balance dialog --- playback/player/gtk/gtk-play.c | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index cc7b742..bd6b7f5 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -193,6 +193,100 @@ skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) play_current_uri (play, prev, NULL); } +static gboolean +color_balance_channel_change_value_cb (GtkRange * range, GtkScrollType scroll, + gdouble value, GtkPlay * play) +{ + GstPlayerColorBalanceType type; + + type = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (range), "type")); + + value = CLAMP (value, 0.0, 1.0); + gst_player_set_color_balance (play->player, type, value); + + return FALSE; +} + +static gboolean +color_balance_channel_button_press_cb (GtkWidget * widget, + GdkEventButton * event, GtkPlay * play) +{ + GstPlayerColorBalanceType type; + + if (event->type != GDK_2BUTTON_PRESS) + return FALSE; + + type = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "type")); + gtk_range_set_value (GTK_RANGE (widget), 0.5); + gst_player_set_color_balance (play->player, type, 0.5); + + return FALSE; +} + +static void +color_balance_dialog (GtkPlay * play) +{ + GtkWidget *parent; + GtkWidget *dialog; + GtkWidget *content; + GtkWidget *box; + GtkWidget *ctlbox; + GtkWidget *label; + GtkWidget *scale; + gdouble value; + guint i; + + parent = gtk_window_new (GTK_WINDOW_TOPLEVEL); + dialog = gtk_dialog_new_with_buttons ("Color Balance", GTK_WINDOW (parent), + GTK_DIALOG_MODAL, "_Close", GTK_RESPONSE_CLOSE, NULL); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent)); + + content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); + gtk_box_set_homogeneous (GTK_BOX (box), TRUE); + gtk_box_pack_start (GTK_BOX (content), box, TRUE, TRUE, 5); + + for (i = GST_PLAYER_COLOR_BALANCE_BRIGHTNESS; + i <= GST_PLAYER_COLOR_BALANCE_HUE; i++) { + ctlbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + label = gtk_label_new (gst_player_color_balance_type_get_name (i)); + scale = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL, 0, 1, 0.5); + gtk_widget_set_size_request (scale, 0, 200); + gtk_box_pack_start (GTK_BOX (ctlbox), label, FALSE, TRUE, 2); + gtk_box_pack_end (GTK_BOX (ctlbox), scale, TRUE, TRUE, 2); + + gtk_box_pack_end (GTK_BOX (box), ctlbox, TRUE, TRUE, 2); + + value = gst_player_get_color_balance (play->player, i); + gtk_range_set_value (GTK_RANGE (scale), value); + g_object_set_data (G_OBJECT (scale), "type", GUINT_TO_POINTER (i)); + + g_signal_connect (scale, "change-value", + G_CALLBACK (color_balance_channel_change_value_cb), play); + g_signal_connect (scale, "button-press-event", + G_CALLBACK (color_balance_channel_button_press_cb), play); + } + + gtk_widget_show_all (dialog); + + gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + gtk_widget_destroy (parent); +} + +static void +color_balance_clicked_cb (GtkWidget * unused, GtkPlay * play) +{ + if (gst_player_has_color_balance (play->player)) { + color_balance_dialog (play); + return; + } + + g_warning ("No color balance channels available."); + return; +} + static GList * open_file_dialog (GtkPlay * play, gboolean multi) { @@ -921,6 +1015,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) GtkWidget *open; GtkWidget *submenu; GtkWidget *vis; + GtkWidget *cb; GstPlayerMediaInfo *media_info; menu = gtk_menu_new (); @@ -933,6 +1028,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) prev = gtk_menu_item_new_with_label ("Prev"); quit = gtk_menu_item_new_with_label ("Quit"); vis = gtk_menu_item_new_with_label ("Visualization"); + cb = gtk_menu_item_new_with_label ("Color Balance"); media_info = gst_player_get_media_info (play->player); @@ -979,9 +1075,13 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_widget_set_sensitive (prev, g_list_previous (play->current_uri) ? TRUE : FALSE); gtk_widget_set_sensitive (info, media_info ? TRUE : FALSE); + gtk_widget_set_sensitive (cb, gst_player_has_color_balance (play->player) ? + TRUE : FALSE); g_signal_connect (G_OBJECT (open), "activate", G_CALLBACK (open_file_clicked_cb), play); + g_signal_connect (G_OBJECT (cb), "activate", + G_CALLBACK (color_balance_clicked_cb), play); g_signal_connect (G_OBJECT (next), "activate", G_CALLBACK (skip_next_clicked_cb), play); g_signal_connect (G_OBJECT (prev), "activate", @@ -999,6 +1099,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_menu_shell_append (GTK_MENU_SHELL (menu), vis); gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub); gtk_menu_shell_append (GTK_MENU_SHELL (menu), info); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), cb); gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit); gtk_widget_show_all (menu); -- cgit v1.2.3 From 2a2c10ac2562ec8ab30c2c5d48972c05b1eb69c6 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Thu, 4 Jun 2015 06:51:14 -0500 Subject: playback/player: gtk-play: use volume-changed signal from player to update the volume slider. --- playback/player/gtk/gtk-play.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index bd6b7f5..895ed99 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -1530,6 +1531,25 @@ media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, } } +static void +player_volume_changed_cb (GstPlayer * player, GtkPlay * play) +{ + gdouble new_val, cur_val; + + cur_val = gtk_scale_button_get_value + (GTK_SCALE_BUTTON (play->volume_button)); + new_val = gst_player_get_volume (play->player); + + if (fabs (cur_val - new_val) > 0.001) { + g_signal_handlers_block_by_func (play->volume_button, + volume_changed_cb, play); + gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), + new_val); + g_signal_handlers_unblock_by_func (play->volume_button, + volume_changed_cb, play); + } +} + int main (gint argc, gchar ** argv) { @@ -1612,6 +1632,8 @@ main (gint argc, gchar ** argv) g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); g_signal_connect (play.player, "media-info-updated", G_CALLBACK (media_info_updated_cb), &play); + g_signal_connect (play.player, "volume-changed", + G_CALLBACK (player_volume_changed_cb), &play); play.playing = TRUE; play_current_uri (&play, g_list_first (play.uris), NULL); -- cgit v1.2.3 From 78142bf4eac690859f8457819d6f69f4301b90a0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jun 2015 15:11:23 +0200 Subject: playback/player: gtk: Use gtkglsink if available --- playback/player/gtk/Makefile.am | 4 ++-- playback/player/gtk/gtk-play.c | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/playback/player/gtk/Makefile.am b/playback/player/gtk/Makefile.am index 03068e6..df03555 100644 --- a/playback/player/gtk/Makefile.am +++ b/playback/player/gtk/Makefile.am @@ -3,8 +3,8 @@ bin_PROGRAMS = gtk-play gtk_play_SOURCES = gtk-play.c LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ - $(GSTREAMER_LIBS) $(GTK_LIBS) $(GLIB_LIBS) $(LIBM) + $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) -AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GLIB_CFLAGS) +AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) noinst_HEADERS = diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 895ed99..d39658f 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1203,15 +1203,28 @@ create_ui (GtkPlay * play) { GtkWidget *image; GtkWidget *controls, *main_hbox, *main_vbox; + GstElement *playbin, *video_sink, *gl_sink; play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (play->window), "delete-event", G_CALLBACK (delete_event_cb), play); set_title (play, APP_NAME); - play->video_area = gtk_drawing_area_new (); - g_signal_connect (play->video_area, "realize", - G_CALLBACK (video_area_realize_cb), play); + gl_sink = gst_element_factory_make ("gtkglsink", NULL); + if (gl_sink) { + g_object_get (gl_sink, "widget", &play->video_area, NULL); + + video_sink = gst_element_factory_make ("glsinkbin", NULL); + g_object_set (video_sink, "sink", gl_sink, NULL); + + playbin = gst_player_get_pipeline (play->player); + g_object_set (playbin, "video-sink", video_sink, NULL); + gst_object_unref (playbin); + } else { + play->video_area = gtk_drawing_area_new (); + g_signal_connect (play->video_area, "realize", + G_CALLBACK (video_area_realize_cb), play); + } g_signal_connect (play->video_area, "button-press-event", G_CALLBACK (mouse_button_pressed_cb), play); g_signal_connect (play->video_area, "motion-notify-event", @@ -1536,8 +1549,7 @@ player_volume_changed_cb (GstPlayer * player, GtkPlay * play) { gdouble new_val, cur_val; - cur_val = gtk_scale_button_get_value - (GTK_SCALE_BUTTON (play->volume_button)); + cur_val = gtk_scale_button_get_value (GTK_SCALE_BUTTON (play->volume_button)); new_val = gst_player_get_volume (play->player); if (fabs (cur_val - new_val) > 0.001) { @@ -1570,6 +1582,10 @@ main (gint argc, gchar ** argv) guint list_length = 0; GError *err = NULL; +#if defined (GDK_WINDOWING_X11) + XInitThreads (); +#endif + memset (&play, 0, sizeof (play)); g_set_prgname (APP_NAME); -- cgit v1.2.3 From 362b5ce2a5e5d0e981c651246dd14395023512e0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jun 2015 16:25:49 +0200 Subject: playback/player: gtk: Remove redundant code --- playback/player/gtk/gtk-play.c | 1 - 1 file changed, 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index d39658f..8ae4fc3 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1651,7 +1651,6 @@ main (gint argc, gchar ** argv) g_signal_connect (play.player, "volume-changed", G_CALLBACK (player_volume_changed_cb), &play); - play.playing = TRUE; play_current_uri (&play, g_list_first (play.uris), NULL); gtk_main (); -- cgit v1.2.3 From b5e35ad70bd171c9fd4748d8c3fcba7f60ccb4e3 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jun 2015 18:42:38 +0200 Subject: playback/player: gtk: Port to GtkApplication And also clean up some other things. https://github.com/sdroege/gst-player/issues/56 --- playback/player/gtk/gtk-play.c | 386 +++++++++++++++++++++++++++++------------ 1 file changed, 277 insertions(+), 109 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 8ae4fc3..df0f5b9 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -42,15 +42,22 @@ #define APP_NAME "gtk-play" +typedef GtkApplication GtkPlayApp; +typedef GtkApplicationClass GtkPlayAppClass; + +G_DEFINE_TYPE (GtkPlayApp, gtk_play_app, GTK_TYPE_APPLICATION); + typedef struct { + GtkApplicationWindow parent; + GstPlayer *player; gchar *uri; GList *uris; GList *current_uri; - GtkWidget *window; + GtkWidget *play_pause_button; GtkWidget *prev_button, *next_button; GtkWidget *seekbar; @@ -67,9 +74,27 @@ typedef struct gboolean playing; gboolean loop; gboolean fullscreen; + gboolean visual; gint toolbar_hide_timeout; } GtkPlay; +typedef GtkApplicationWindowClass GtkPlayClass; + +G_DEFINE_TYPE (GtkPlay, gtk_play, GTK_TYPE_APPLICATION_WINDOW); + +enum +{ + PROP_0, + PROP_LOOP, + PROP_FULLSCREEN, + PROP_VISUAL, + PROP_URIS, + + LAST_PROP +}; + +static GParamSpec *gtk_play_properties[LAST_PROP] = { NULL, }; + enum { COL_TEXT = 0, @@ -104,9 +129,9 @@ static void set_title (GtkPlay * play, const gchar * title) { if (title == NULL) { - gtk_window_set_title (GTK_WINDOW (play->window), APP_NAME); + gtk_window_set_title (GTK_WINDOW (play), APP_NAME); } else { - gtk_window_set_title (GTK_WINDOW (play->window), title); + gtk_window_set_title (GTK_WINDOW (play), title); } } @@ -114,7 +139,6 @@ static void delete_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) { gst_player_stop (play->player); - gtk_main_quit (); } static void @@ -227,7 +251,6 @@ color_balance_channel_button_press_cb (GtkWidget * widget, static void color_balance_dialog (GtkPlay * play) { - GtkWidget *parent; GtkWidget *dialog; GtkWidget *content; GtkWidget *box; @@ -237,10 +260,9 @@ color_balance_dialog (GtkPlay * play) gdouble value; guint i; - parent = gtk_window_new (GTK_WINDOW_TOPLEVEL); - dialog = gtk_dialog_new_with_buttons ("Color Balance", GTK_WINDOW (parent), - GTK_DIALOG_MODAL, "_Close", GTK_RESPONSE_CLOSE, NULL); - gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent)); + dialog = gtk_dialog_new_with_buttons ("Color Balance", GTK_WINDOW (play), + GTK_DIALOG_DESTROY_WITH_PARENT, "_Close", GTK_RESPONSE_CLOSE, NULL); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (play)); content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); @@ -273,7 +295,6 @@ color_balance_dialog (GtkPlay * play) gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); - gtk_widget_destroy (parent); } static void @@ -296,7 +317,14 @@ open_file_dialog (GtkPlay * play, gboolean multi) GtkWidget *chooser; GtkWidget *parent; - parent = gtk_window_new (GTK_WINDOW_TOPLEVEL); + if (play) { + parent = GTK_WIDGET (play); + } else { + parent = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_application_add_window (GTK_APPLICATION (g_application_get_default ()), + GTK_WINDOW (parent)); + } + chooser = gtk_file_chooser_dialog_new ("Select files to play", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); @@ -315,7 +343,9 @@ open_file_dialog (GtkPlay * play, gboolean multi) } gtk_widget_destroy (chooser); - gtk_widget_destroy (parent); + if (!play) + gtk_widget_destroy (parent); + return uris; } @@ -603,6 +633,7 @@ create_media_info_window (GtkPlay * play, GstPlayerMediaInfo * info) gtk_window_set_default_size (GTK_WINDOW (window), 550, 450); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER); gtk_container_set_border_width (GTK_CONTAINER (window), 10); + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (play)); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); gtk_container_add (GTK_CONTAINER (window), vbox); @@ -673,9 +704,10 @@ toolbar_hide_func (GtkPlay * play) /* hide the mouse pointer */ cursor = - gdk_cursor_new_for_display (gtk_widget_get_display (play->window), + gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (play)), GDK_BLANK_CURSOR); - gdk_window_set_cursor (gtk_widget_get_window (play->window), cursor); + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (play->video_area)), + cursor); g_object_unref (cursor); play->toolbar_hide_timeout = 0; @@ -689,7 +721,7 @@ fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) if (gtk_toggle_button_get_active (widget)) { image = gtk_image_new_from_icon_name ("view-restore", GTK_ICON_SIZE_BUTTON); - gtk_window_fullscreen (GTK_WINDOW (play->window)); + gtk_window_fullscreen (GTK_WINDOW (play)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); /* start timer to hide toolbar */ @@ -706,7 +738,7 @@ fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) image = gtk_image_new_from_icon_name ("view-fullscreen", GTK_ICON_SIZE_BUTTON); - gtk_window_unfullscreen (GTK_WINDOW (play->window)); + gtk_window_unfullscreen (GTK_WINDOW (play)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); } } @@ -998,8 +1030,7 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) static void player_quit_clicked_cb (GtkButton * button, GtkPlay * play) { - gst_player_stop (play->player); - gtk_main_quit (); + gtk_widget_destroy (GTK_WIDGET (play)); } static void @@ -1187,8 +1218,8 @@ gtk_show_toolbar_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) } /* show mouse pointer */ - gdk_window_set_cursor (gtk_widget_get_window (play->window), - play->default_cursor); + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET + (play->video_area)), play->default_cursor); gtk_widget_show (play->toolbar); play->toolbar_hide_timeout = g_timeout_add_seconds (5, @@ -1205,10 +1236,13 @@ create_ui (GtkPlay * play) GtkWidget *controls, *main_hbox, *main_vbox; GstElement *playbin, *video_sink, *gl_sink; - play->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - g_signal_connect (G_OBJECT (play->window), "delete-event", + gtk_window_set_default_size (GTK_WINDOW (play), 640, 480); + + g_signal_connect (G_OBJECT (play), "delete-event", G_CALLBACK (delete_event_cb), play); set_title (play, APP_NAME); + gtk_application_add_window (GTK_APPLICATION (g_application_get_default ()), + GTK_WINDOW (play)); gl_sink = gst_element_factory_make ("gtkglsink", NULL); if (gl_sink) { @@ -1337,23 +1371,11 @@ create_ui (GtkPlay * play) main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (main_vbox), controls, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (play->window), main_vbox); + gtk_container_add (GTK_CONTAINER (play), main_vbox); - gtk_widget_realize (play->video_area); + if (!gl_sink) + gtk_widget_realize (play->video_area); gtk_widget_hide (play->video_area); - - gtk_widget_show_all (play->window); - - play->default_cursor = gdk_window_get_cursor - (gtk_widget_get_window (play->toolbar)); -} - -static void -play_clear (GtkPlay * play) -{ - g_free (play->uri); - g_list_free_full (play->uris, g_free); - g_object_unref (play->player); } static void @@ -1562,100 +1584,246 @@ player_volume_changed_cb (GstPlayer * player, GtkPlay * play) } } -int -main (gint argc, gchar ** argv) +static void +gtk_play_set_property (GObject * object, guint prop_id, const GValue * value, + GParamSpec * pspec) { - GtkPlay play; - gchar **file_names = NULL; - GOptionContext *ctx; - gboolean vis = FALSE; - GOptionEntry options[] = { - {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &file_names, - "Files to play"}, - {"loop", 'l', 0, G_OPTION_ARG_NONE, &play.loop, "Repeat all"}, - {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, &play.fullscreen, - "Show the player in fullscreen"}, - {"visual", 'v', 0, G_OPTION_ARG_NONE, &vis, - "Show visualization when there is no video stream"}, - {NULL} - }; - guint list_length = 0; - GError *err = NULL; + GtkPlay *self = (GtkPlay *) object; + + switch (prop_id) { + case PROP_LOOP: + self->loop = g_value_get_boolean (value); + break; + case PROP_FULLSCREEN: + self->fullscreen = g_value_get_boolean (value); + break; + case PROP_VISUAL: + self->visual = g_value_get_boolean (value); + break; + case PROP_URIS: + self->uris = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} -#if defined (GDK_WINDOWING_X11) - XInitThreads (); -#endif +static void +show_cb (GtkWidget * widget, gpointer user_data) +{ + GtkPlay *self = (GtkPlay *) widget; - memset (&play, 0, sizeof (play)); + self->default_cursor = gdk_window_get_cursor + (gtk_widget_get_window (GTK_WIDGET (self))); - g_set_prgname (APP_NAME); + play_current_uri (self, g_list_first (self->uris), NULL); +} - ctx = g_option_context_new ("FILE|URI"); - g_option_context_add_main_entries (ctx, options, NULL); - g_option_context_add_group (ctx, gtk_get_option_group (TRUE)); - g_option_context_add_group (ctx, gst_init_get_option_group ()); - if (!g_option_context_parse (ctx, &argc, &argv, &err)) { - g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); - return 1; - } - g_option_context_free (ctx); - - // FIXME: Add support for playlists and stuff - /* Parse the list of the file names we have to play. */ - if (!file_names) { - play.uris = open_file_dialog (&play, TRUE); - if (!play.uris) - return 0; - } else { - guint i; - - list_length = g_strv_length (file_names); - for (i = 0; i < list_length; i++) { - play.uris = - g_list_append (play.uris, - gst_uri_is_valid (file_names[i]) ? - g_strdup (file_names[i]) : gst_filename_to_uri (file_names[i], NULL)); - } +static GObject * +gtk_play_constructor (GType type, guint n_construct_params, + GObjectConstructParam * construct_params) +{ + GtkPlay *self; + gchar **p; - g_strfreev (file_names); - file_names = NULL; - } + self = + (GtkPlay *) G_OBJECT_CLASS (gtk_play_parent_class)->constructor (type, + n_construct_params, construct_params); - play.player = gst_player_new (); - play.playing = TRUE; + self->player = gst_player_new (); + self->playing = TRUE; - g_object_set (play.player, "dispatch-to-main-context", TRUE, NULL); + g_object_set (self->player, "dispatch-to-main-context", TRUE, NULL); - create_ui (&play); + create_ui (self); /* if visualization is enabled then use the first element */ - if (vis) { + if (self->visual) { GstPlayerVisualization **viss; viss = gst_player_visualizations_get (); if (viss && *viss) { - gst_player_set_visualization (play.player, (*viss)->name); - gst_player_set_visualization_enabled (play.player, TRUE); + gst_player_set_visualization (self->player, (*viss)->name); + gst_player_set_visualization_enabled (self->player, TRUE); } if (viss) gst_player_visualizations_free (viss); } - g_signal_connect (play.player, "position-updated", - G_CALLBACK (position_updated_cb), &play); - g_signal_connect (play.player, "duration-changed", - G_CALLBACK (duration_changed_cb), &play); - g_signal_connect (play.player, "end-of-stream", G_CALLBACK (eos_cb), &play); - g_signal_connect (play.player, "media-info-updated", - G_CALLBACK (media_info_updated_cb), &play); - g_signal_connect (play.player, "volume-changed", - G_CALLBACK (player_volume_changed_cb), &play); + g_signal_connect (self->player, "position-updated", + G_CALLBACK (position_updated_cb), self); + g_signal_connect (self->player, "duration-changed", + G_CALLBACK (duration_changed_cb), self); + g_signal_connect (self->player, "end-of-stream", G_CALLBACK (eos_cb), self); + g_signal_connect (self->player, "media-info-updated", + G_CALLBACK (media_info_updated_cb), self); + g_signal_connect (self->player, "volume-changed", + G_CALLBACK (player_volume_changed_cb), self); + + g_signal_connect (G_OBJECT (self), "show", G_CALLBACK (show_cb), NULL); + + return G_OBJECT (self); +} + +static void +gtk_play_dispose (GObject * object) +{ + GtkPlay *self = (GtkPlay *) object; + + if (self->uri) + g_free (self->uri); + self->uri = NULL; + + if (self->uris) + g_list_free_full (self->uris, g_free); + self->uris = NULL; + if (self->player) { + gst_player_stop (self->player); + g_object_unref (self->player); + } + self->player = NULL; + + G_OBJECT_CLASS (gtk_play_parent_class)->dispose (object); +} + +static void +gtk_play_init (GtkPlay * self) +{ +} + +static void +gtk_play_class_init (GtkPlayClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = gtk_play_constructor; + object_class->dispose = gtk_play_dispose; + object_class->set_property = gtk_play_set_property; + + gtk_play_properties[PROP_LOOP] = + g_param_spec_boolean ("loop", "Loop", "Loop the playlist", + FALSE, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + gtk_play_properties[PROP_FULLSCREEN] = + g_param_spec_boolean ("fullscreen", "Fullscreen", "Fullscreen mode", + FALSE, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + gtk_play_properties[PROP_VISUAL] = + g_param_spec_boolean ("visual", "Visual", "Use Visualizations", FALSE, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + gtk_play_properties[PROP_URIS] = + g_param_spec_pointer ("uris", "URIs", "URIs to play", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, LAST_PROP, + gtk_play_properties); +} + +static gint +gtk_play_app_command_line (GApplication * application, + GApplicationCommandLine * command_line) +{ + GtkPlayApp *self = (GtkPlayApp *) application; + GVariantDict *options; + GtkPlay *play; + GList *uris = NULL; + gboolean loop = FALSE, visual = FALSE, fullscreen = FALSE; + gchar **uris_array = NULL; + + options = g_application_command_line_get_options_dict (command_line); + + g_variant_dict_lookup (options, "loop", "b", &loop); + g_variant_dict_lookup (options, "visual", "b", &visual); + g_variant_dict_lookup (options, "fullscreen", "b", &fullscreen); + g_variant_dict_lookup (options, G_OPTION_REMAINING, "^a&ay", &uris_array); + + if (uris_array) { + gchar **p; + + p = uris_array; + while (*p) { + uris = + g_list_prepend (uris, + gst_uri_is_valid (*p) ? + g_strdup (*p) : gst_filename_to_uri (*p, NULL)); + p++; + } + uris = g_list_reverse (uris); + } else { + uris = open_file_dialog (NULL, TRUE); + } + + if (!uris) + return -1; + + play = + g_object_new (gtk_play_get_type (), "loop", loop, "fullscreen", + fullscreen, "visual", visual, "uris", uris, NULL); + gtk_widget_show_all (GTK_WIDGET (play)); + + return + G_APPLICATION_CLASS (gtk_play_app_parent_class)->command_line + (application, command_line); +} + +static void +gtk_play_app_init (GtkPlayApp * self) +{ +} + +static void +gtk_play_app_class_init (GtkPlayAppClass * klass) +{ + GApplicationClass *application_class = G_APPLICATION_CLASS (klass); + + application_class->command_line = gtk_play_app_command_line; +} - play_current_uri (&play, g_list_first (play.uris), NULL); +GtkPlayApp * +gtk_play_app_new (void) +{ + GtkPlayApp *self; + GOptionEntry options[] = { + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, + "Files to play"}, + {"loop", 'l', 0, G_OPTION_ARG_NONE, NULL, "Repeat all"}, + {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, NULL, + "Show the player in fullscreen"}, + {"visual", 'v', 0, G_OPTION_ARG_NONE, NULL, + "Show visualization when there is no video stream"}, + {NULL} + }; - gtk_main (); + g_set_prgname (APP_NAME); + g_set_application_name (APP_NAME); + + self = g_object_new (gtk_play_app_get_type (), + "application-id", "org.freedesktop.gstreamer.GTKPlay", + "flags", G_APPLICATION_HANDLES_COMMAND_LINE, + "register-session", TRUE, NULL); + + g_application_set_default (G_APPLICATION (self)); + g_application_add_main_option_entries (G_APPLICATION (self), options); + g_application_add_option_group (G_APPLICATION (self), + gst_init_get_option_group ()); + + return self; +} + +int +main (gint argc, gchar ** argv) +{ + GtkPlayApp *app; + gint status; + +#if defined (GDK_WINDOWING_X11) + XInitThreads (); +#endif - play_clear (&play); + app = gtk_play_app_new (); + status = g_application_run (G_APPLICATION (app), argc, argv);; + g_object_unref (app); - return 0; + return status; } -- cgit v1.2.3 From 40e21cea24b56e068b4a23ef17b5f5491c064b47 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jun 2015 18:52:12 +0200 Subject: playback/player: gtk: Inhibit the screen saver when playing something --- playback/player/gtk/gtk-play.c | 44 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index df0f5b9..8204362 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -57,6 +57,7 @@ typedef struct GList *uris; GList *current_uri; + guint inhibit_cookie; GtkWidget *play_pause_button; GtkWidget *prev_button, *next_button; @@ -172,7 +173,19 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); play->playing = FALSE; + + if (play->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()), + play->inhibit_cookie); + play->inhibit_cookie = 0; } else { + if (play->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()), + play->inhibit_cookie); + play->inhibit_cookie = + gtk_application_inhibit (GTK_APPLICATION (g_application_get_default ()), + GTK_WINDOW (play), GTK_APPLICATION_INHIBIT_IDLE, "Playing media"); + gst_player_play (play->player); image = gtk_image_new_from_icon_name ("media-playback-pause", @@ -200,10 +213,21 @@ play_current_uri (GtkPlay * play, GList * uri, const gchar * ext_suburi) else gst_player_set_uri (play->player, uri->data); play->current_uri = uri; - if (play->playing) + if (play->playing) { + if (play->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()), + play->inhibit_cookie); + play->inhibit_cookie = + gtk_application_inhibit (GTK_APPLICATION (g_application_get_default ()), + GTK_WINDOW (play), GTK_APPLICATION_INHIBIT_IDLE, "Playing media"); gst_player_play (play->player); - else + } else { gst_player_pause (play->player); + if (play->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()), + play->inhibit_cookie); + play->inhibit_cookie = 0; + } set_title (play, uri->data); } @@ -1417,6 +1441,10 @@ eos_cb (GstPlayer * unused, GtkPlay * play) GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); play->playing = FALSE; + if (play->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default + ()), play->inhibit_cookie); + play->inhibit_cookie = 0; } } } @@ -1634,6 +1662,13 @@ gtk_play_constructor (GType type, guint n_construct_params, self->player = gst_player_new (); self->playing = TRUE; + if (self->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()), + self->inhibit_cookie); + self->inhibit_cookie = + gtk_application_inhibit (GTK_APPLICATION (g_application_get_default ()), + GTK_WINDOW (self), GTK_APPLICATION_INHIBIT_IDLE, "Playing media"); + g_object_set (self->player, "dispatch-to-main-context", TRUE, NULL); create_ui (self); @@ -1671,6 +1706,11 @@ gtk_play_dispose (GObject * object) { GtkPlay *self = (GtkPlay *) object; + if (self->inhibit_cookie) + gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()), + self->inhibit_cookie); + self->inhibit_cookie = 0; + if (self->uri) g_free (self->uri); self->uri = NULL; -- cgit v1.2.3 From ba1ea118232956abdb9f494c074ccc9310e6e97d Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Thu, 11 Jun 2015 19:49:59 +0200 Subject: playback/player: gtk-play: remove unused variables --- playback/player/gtk/gtk-play.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 8204362..66b23c5 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1653,7 +1653,6 @@ gtk_play_constructor (GType type, guint n_construct_params, GObjectConstructParam * construct_params) { GtkPlay *self; - gchar **p; self = (GtkPlay *) G_OBJECT_CLASS (gtk_play_parent_class)->constructor (type, @@ -1764,7 +1763,6 @@ static gint gtk_play_app_command_line (GApplication * application, GApplicationCommandLine * command_line) { - GtkPlayApp *self = (GtkPlayApp *) application; GVariantDict *options; GtkPlay *play; GList *uris = NULL; -- cgit v1.2.3 From 3afafa30c60657fc217e10c8bb7f85fd7ca092d3 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 15 Jun 2015 20:55:29 +0200 Subject: playback/player: gtk: Also use gtksink if available --- playback/player/gtk/gtk-play.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 66b23c5..a16f639 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1258,7 +1258,7 @@ create_ui (GtkPlay * play) { GtkWidget *image; GtkWidget *controls, *main_hbox, *main_vbox; - GstElement *playbin, *video_sink, *gl_sink; + GstElement *playbin, *gtk_sink; gtk_window_set_default_size (GTK_WINDOW (play), 640, 480); @@ -1268,16 +1268,23 @@ create_ui (GtkPlay * play) gtk_application_add_window (GTK_APPLICATION (g_application_get_default ()), GTK_WINDOW (play)); - gl_sink = gst_element_factory_make ("gtkglsink", NULL); - if (gl_sink) { - g_object_get (gl_sink, "widget", &play->video_area, NULL); + if ((gtk_sink = gst_element_factory_make ("gtkglsink", NULL))) { + GstElement *video_sink; + + g_object_get (gtk_sink, "widget", &play->video_area, NULL); video_sink = gst_element_factory_make ("glsinkbin", NULL); - g_object_set (video_sink, "sink", gl_sink, NULL); + g_object_set (video_sink, "sink", gtk_sink, NULL); playbin = gst_player_get_pipeline (play->player); g_object_set (playbin, "video-sink", video_sink, NULL); gst_object_unref (playbin); + } else if ((gtk_sink = gst_element_factory_make ("gtksink", NULL))) { + g_object_get (gtk_sink, "widget", &play->video_area, NULL); + + playbin = gst_player_get_pipeline (play->player); + g_object_set (playbin, "video-sink", gtk_sink, NULL); + gst_object_unref (playbin); } else { play->video_area = gtk_drawing_area_new (); g_signal_connect (play->video_area, "realize", @@ -1397,7 +1404,7 @@ create_ui (GtkPlay * play) gtk_box_pack_start (GTK_BOX (main_vbox), controls, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (play), main_vbox); - if (!gl_sink) + if (!gtk_sink) gtk_widget_realize (play->video_area); gtk_widget_hide (play->video_area); } -- cgit v1.2.3 From efd3c03ab289bab43408f11357d863ba113effc7 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Mon, 15 Jun 2015 10:10:14 -0500 Subject: playback/player: gtk-play: add playback rate control menu item --- playback/player/gtk/gtk-play.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index a16f639..96bb25d 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1051,6 +1051,46 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) return menu; } +static void +player_set_rate_cb (GtkSpinButton * button, GtkPlay * play) +{ + gst_player_set_rate (play->player, gtk_spin_button_get_value (button)); +} + +static void +player_speed_clicked_cb (GtkButton * button, GtkPlay * play) +{ + GtkWidget *box; + GtkWidget *label; + GtkWidget *dialog; + GtkWidget *content; + GtkWidget *rate_spinbutton; + + dialog = gtk_dialog_new (); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (play)); + gtk_window_set_title (GTK_WINDOW (dialog), "Playback speed control"); + + content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); + gtk_box_pack_start (GTK_BOX (content), box, TRUE, TRUE, 0); + + label = gtk_label_new ("Playback rate"); + rate_spinbutton = gtk_spin_button_new_with_range (-64, 64, 0.1); + gtk_spin_button_set_digits (GTK_SPIN_BUTTON (rate_spinbutton), 2); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (rate_spinbutton), + gst_player_get_rate (play->player)); + + gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (box), rate_spinbutton, TRUE, TRUE, 2); + g_signal_connect (rate_spinbutton, "value-changed", + G_CALLBACK (player_set_rate_cb), play); + + gtk_widget_show_all (dialog); + gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_destroy (dialog); +} + static void player_quit_clicked_cb (GtkButton * button, GtkPlay * play) { @@ -1072,6 +1112,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) GtkWidget *submenu; GtkWidget *vis; GtkWidget *cb; + GtkWidget *speed; GstPlayerMediaInfo *media_info; menu = gtk_menu_new (); @@ -1085,6 +1126,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) quit = gtk_menu_item_new_with_label ("Quit"); vis = gtk_menu_item_new_with_label ("Visualization"); cb = gtk_menu_item_new_with_label ("Color Balance"); + speed = gtk_menu_item_new_with_label ("Playback Speed"); media_info = gst_player_get_media_info (play->player); @@ -1144,6 +1186,8 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) G_CALLBACK (skip_prev_clicked_cb), play); g_signal_connect (G_OBJECT (info), "activate", G_CALLBACK (media_info_clicked_cb), play); + g_signal_connect (G_OBJECT (speed), "activate", + G_CALLBACK (player_speed_clicked_cb), play); g_signal_connect (G_OBJECT (quit), "activate", G_CALLBACK (player_quit_clicked_cb), play); @@ -1156,6 +1200,7 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub); gtk_menu_shell_append (GTK_MENU_SHELL (menu), info); gtk_menu_shell_append (GTK_MENU_SHELL (menu), cb); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), speed); gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit); gtk_widget_show_all (menu); -- cgit v1.2.3 From cce3ab6381bf291d1fde96aede8ad4a42ac38c39 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 16 Jun 2015 09:54:25 +0200 Subject: playback/player: gtk-play: Add close button to the playback speed dialog --- playback/player/gtk/gtk-play.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 96bb25d..2a8cfa5 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1066,9 +1066,10 @@ player_speed_clicked_cb (GtkButton * button, GtkPlay * play) GtkWidget *content; GtkWidget *rate_spinbutton; - dialog = gtk_dialog_new (); + dialog = + gtk_dialog_new_with_buttons ("Playback speed control", GTK_WINDOW (play), + GTK_DIALOG_DESTROY_WITH_PARENT, "_Close", GTK_RESPONSE_CLOSE, NULL); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (play)); - gtk_window_set_title (GTK_WINDOW (dialog), "Playback speed control"); content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); -- cgit v1.2.3 From b59a893da7c2e431e4d676b940adcd2bc7018e8a Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Fri, 26 Jun 2015 20:42:31 -0500 Subject: playback/player: gtk-play: add support to build UI through gtkbuilder - build toolbar ui from glade generated xml files - build media info dialog from glade generated xml files - add support to apply css style on widget - multiple cleanups --- playback/player/gtk/Makefile.am | 34 +- playback/player/gtk/gtk-play.c | 868 +++++++++------------ playback/player/gtk/resources/gresources.xml | 11 + playback/player/gtk/resources/media_info_dialog.ui | 108 +++ playback/player/gtk/resources/toolbar.css | 26 + playback/player/gtk/resources/toolbar.ui | 341 ++++++++ 6 files changed, 874 insertions(+), 514 deletions(-) create mode 100644 playback/player/gtk/resources/gresources.xml create mode 100644 playback/player/gtk/resources/media_info_dialog.ui create mode 100644 playback/player/gtk/resources/toolbar.css create mode 100644 playback/player/gtk/resources/toolbar.ui diff --git a/playback/player/gtk/Makefile.am b/playback/player/gtk/Makefile.am index df03555..f7e6d0f 100644 --- a/playback/player/gtk/Makefile.am +++ b/playback/player/gtk/Makefile.am @@ -1,10 +1,36 @@ bin_PROGRAMS = gtk-play -gtk_play_SOURCES = gtk-play.c +gtk-play-resources.c: resources/gresources.xml \ + resources/media_info_dialog.ui \ + resources/toolbar.css \ + resources/toolbar.ui + $(AM_V_GEN) \ + glib-compile-resources \ + --sourcedir=$(srcdir)/resources \ + --target=$@ \ + --generate-source \ + --c-name as \ + $(srcdir)/resources/gresources.xml + +gtk-play-resources.h: resources/gresources.xml \ + resources/media_info_dialog.ui \ + resources/toolbar.css \ + resources/toolbar.ui + $(AM_V_GEN) \ + glib-compile-resources \ + --sourcedir=$(srcdir)/resources \ + --target=$@ \ + --generate-header \ + --c-name as \ + $(srcdir)/resources/gresources.xml + +BUILT_SOURCES: gtk-play-resources.c gtk-play-resources.h + +gtk_play_SOURCES = gtk-play.c gtk-play-resources.c LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ - $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) + $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) $(GMODULE_LIBS) -AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) +AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) -noinst_HEADERS = +noinst_HEADERS = gtk-play-resources.h diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 2a8cfa5..32973af 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -42,6 +42,12 @@ #define APP_NAME "gtk-play" +#define TOOLBAR_GET_OBJECT(x) \ + (GtkWidget *)gtk_builder_get_object (play->toolbar_ui, #x) + +#define TOOLBAR_GET_LABEL(x) \ + (GtkLabel *) gtk_builder_get_object (play->toolbar_ui, #x) + typedef GtkApplication GtkPlayApp; typedef GtkApplicationClass GtkPlayAppClass; @@ -63,20 +69,22 @@ typedef struct GtkWidget *prev_button, *next_button; GtkWidget *seekbar; GtkWidget *video_area; - GtkWidget *image_area; GtkWidget *volume_button; - GtkWidget *media_info_button; - GtkWidget *repeat_button; GtkWidget *fullscreen_button; GtkWidget *toolbar; + GtkWidget *toolbar_overlay; + GtkWidget *media_info_dialog; + GtkLabel *title_label; + GtkLabel *elapshed_label; + GtkLabel *remain_label; + GtkLabel *rate_label; GdkCursor *default_cursor; - gulong seekbar_value_changed_signal_id; - GdkPixbuf *image_pixbuf; gboolean playing; gboolean loop; gboolean fullscreen; - gboolean visual; gint toolbar_hide_timeout; + + GtkBuilder *toolbar_ui; } GtkPlay; typedef GtkApplicationWindowClass GtkPlayClass; @@ -88,7 +96,6 @@ enum PROP_0, PROP_LOOP, PROP_FULLSCREEN, - PROP_VISUAL, PROP_URIS, LAST_PROP @@ -124,8 +131,6 @@ enum SUBTITLE_INFO_END, }; -static void display_cover_art (GtkPlay * play, GstPlayerMediaInfo * media_info); - static void set_title (GtkPlay * play, const gchar * title) { @@ -136,6 +141,25 @@ set_title (GtkPlay * play, const gchar * title) } } +static GtkBuilder * +load_from_builder (const gchar * filename, gboolean register_sig_handler, + GtkPlay * play) +{ + GtkBuilder *builder; + + builder = gtk_builder_new_from_resource (filename); + if (builder == NULL) { + g_print ("ERROR: failed to load %s \n", filename); + return NULL; + } + + if (register_sig_handler) + gtk_builder_connect_signals (builder, play); + + return builder; +} + + static void delete_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) { @@ -162,15 +186,47 @@ video_area_realize_cb (GtkWidget * widget, GtkPlay * play) } static void -play_pause_clicked_cb (GtkButton * button, GtkPlay * play) +gtk_play_set_rate (GtkPlay * play, gdouble step) +{ + gdouble val; + + val = gst_player_get_rate (play->player); + val += step; + if (val == 0.0) + val = step; + gst_player_set_rate (play->player, val); + + if (val == 1.0) + gtk_label_set_label (play->rate_label, NULL); + else { + gchar *data; + + data = g_strdup_printf ("%.2fx", val); + gtk_label_set_label (play->rate_label, data); + g_free (data); + } +} + +G_MODULE_EXPORT void +rewind_button_clicked_cb (GtkButton * button, GtkPlay * play) +{ + gtk_play_set_rate (play, -0.5); +} + +G_MODULE_EXPORT void +forward_button_clicked_cb (GtkButton * button, GtkPlay * play) +{ + gtk_play_set_rate (play, 0.5); +} + +G_MODULE_EXPORT void +play_pause_button_clicked_cb (GtkButton * button, GtkPlay * play) { GtkWidget *image; if (play->playing) { gst_player_pause (play->player); - image = - gtk_image_new_from_icon_name ("media-playback-start", - GTK_ICON_SIZE_BUTTON); + image = TOOLBAR_GET_OBJECT (play_image); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); play->playing = FALSE; @@ -187,9 +243,7 @@ play_pause_clicked_cb (GtkButton * button, GtkPlay * play) GTK_WINDOW (play), GTK_APPLICATION_INHIBIT_IDLE, "Playing media"); gst_player_play (play->player); - image = - gtk_image_new_from_icon_name ("media-playback-pause", - GTK_ICON_SIZE_BUTTON); + image = TOOLBAR_GET_OBJECT (pause_image); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); play->playing = TRUE; } @@ -199,13 +253,10 @@ static void play_current_uri (GtkPlay * play, GList * uri, const gchar * ext_suburi) { /* reset the button/widget state to default */ - if (play->image_pixbuf) - g_object_unref (play->image_pixbuf); - play->image_pixbuf = NULL; - gtk_widget_set_sensitive (play->media_info_button, FALSE); gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); gtk_widget_set_sensitive (play->prev_button, g_list_previous (uri) != NULL); gtk_widget_set_sensitive (play->next_button, g_list_next (uri) != NULL); + gtk_label_set_label (play->rate_label, NULL); /* set uri or suburi */ if (ext_suburi) @@ -231,8 +282,8 @@ play_current_uri (GtkPlay * play, GList * uri, const gchar * ext_suburi) set_title (play, uri->data); } -static void -skip_prev_clicked_cb (GtkButton * button, GtkPlay * play) +G_MODULE_EXPORT void +prev_button_clicked_cb (GtkButton * button, GtkPlay * play) { GList *prev; @@ -388,8 +439,8 @@ open_file_clicked_cb (GtkWidget * unused, GtkPlay * play) } } -static void -skip_next_clicked_cb (GtkButton * button, GtkPlay * play) +G_MODULE_EXPORT void +next_button_clicked_cb (GtkButton * button, GtkPlay * play) { GList *next; @@ -519,51 +570,14 @@ stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) } } -static gboolean -is_current_stream (GtkPlay * play, GstPlayerStreamInfo * stream) -{ - gboolean ret = FALSE; - GstPlayerStreamInfo *s; - GstPlayerVideoInfo *video = gst_player_get_current_video_track (play->player); - GstPlayerAudioInfo *audio = gst_player_get_current_audio_track (play->player); - GstPlayerSubtitleInfo *sub = - gst_player_get_current_subtitle_track (play->player); - - if (GST_IS_PLAYER_VIDEO_INFO (stream)) - s = (GstPlayerStreamInfo *) video; - else if (GST_IS_PLAYER_AUDIO_INFO (stream)) - s = (GstPlayerStreamInfo *) audio; - else - s = (GstPlayerStreamInfo *) sub; - - if (s) - if (gst_player_stream_info_get_index (stream) == - gst_player_stream_info_get_index (s)) - ret = TRUE; - - if (audio) - g_object_unref (audio); - - if (video) - g_object_unref (video); - - if (sub) - g_object_unref (sub); - - return ret; -} - -static GtkTreeModel * -create_and_fill_model (GtkPlay * play, GstPlayerMediaInfo * info) +static void +fill_tree_model (GtkTreeStore * tree, GtkPlay * play, GstPlayerMediaInfo * info) { GList *l; guint count; - GtkTreeStore *tree; GtkTreeIter child, parent; count = 0; - tree = gtk_tree_store_new (COL_NUM, G_TYPE_STRING); - for (l = gst_player_media_info_get_stream_list (info); l != NULL; l = l->next) { gchar *buffer; gint i, start, end; @@ -581,8 +595,7 @@ create_and_fill_model (GtkPlay * play, GstPlayerMediaInfo * info) end = SUBTITLE_INFO_END; } - buffer = g_strdup_printf ("Stream %u %s", count++, - is_current_stream (play, stream) ? "(current)" : ""); + buffer = g_strdup_printf ("Stream %u", count++); gtk_tree_store_append (tree, &parent, NULL); gtk_tree_store_set (tree, &parent, COL_TEXT, buffer, -1); g_free (buffer); @@ -602,131 +615,74 @@ create_and_fill_model (GtkPlay * play, GstPlayerMediaInfo * info) } } } +} - return GTK_TREE_MODEL (tree); +G_MODULE_EXPORT void +media_info_dialog_button_clicked_cb (GtkButton * button, GtkPlay * play) +{ + gtk_widget_destroy (GTK_WIDGET (play->media_info_dialog)); + play->media_info_dialog = NULL; } -static GtkWidget * -create_view_and_model (GtkPlay * play, GstPlayerMediaInfo * info) +static void +media_info_dialog (GtkPlay * play, GstPlayerMediaInfo * media_info) { + GtkBuilder *dialog_ui; GtkWidget *view; + GtkTreeStore *tree; GtkTreeModel *model; GtkTreeViewColumn *col; GtkCellRenderer *renderer; - view = gtk_tree_view_new (); - col = gtk_tree_view_column_new (); - gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE); + dialog_ui = load_from_builder ("/ui/media_info_dialog.ui", TRUE, play); + if (!dialog_ui) + return; + + play->media_info_dialog = + (GtkWidget *) gtk_builder_get_object (dialog_ui, "media_info_dialog"); + gtk_window_set_transient_for (GTK_WINDOW (play->media_info_dialog), + GTK_WINDOW (play)); + + view = (GtkWidget *) gtk_builder_get_object (dialog_ui, "view"); + col = (GtkTreeViewColumn *) gtk_builder_get_object (dialog_ui, "col"); + /* TODO: use glade cell renderer (not working for me) */ renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (col, renderer, TRUE); gtk_tree_view_column_add_attribute (col, renderer, "text", COL_TEXT); - model = create_and_fill_model (play, info); - gtk_tree_view_set_model (GTK_TREE_VIEW (view), model); - g_object_unref (model); - - return view; -} + tree = (GtkTreeStore *) gtk_builder_get_object (dialog_ui, "tree"); + fill_tree_model (tree, play, media_info); -static void -delete_media_info_window (GtkWidget * button, GtkWindow * window) -{ - gtk_window_close (window); -} - -static void -create_media_info_window (GtkPlay * play, GstPlayerMediaInfo * info) -{ - GtkWidget *sw; - GtkWidget *vbox; - GtkWidget *label; - GtkWidget *view; - GtkWidget *hbox; - GtkWidget *uri; - GtkWidget *loc; - GtkTextIter iter; - GtkWidget *window; - GtkTextBuffer *buffer; - GtkWidget *hbox_close; - GtkWidget *button_close; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (window), "Media information"); - gtk_window_set_default_size (GTK_WINDOW (window), 550, 450); - gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER); - gtk_container_set_border_width (GTK_CONTAINER (window), 10); - gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (play)); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8); - gtk_container_add (GTK_CONTAINER (window), vbox); - - label = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL (label), - "Information about all the streams contains in your media. \n" - "Current selected streams are marked as (current)."); - gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 2); - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), - GTK_SHADOW_ETCHED_IN); - gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); - - view = create_view_and_model (play, info); - gtk_container_add (GTK_CONTAINER (sw), view); g_signal_connect (view, "realize", G_CALLBACK (gtk_tree_view_expand_all), NULL); + + gtk_widget_set_size_request (play->media_info_dialog, 550, 450); - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); - - loc = gtk_label_new ("Location : "); - gtk_box_pack_start (GTK_BOX (hbox), loc, FALSE, FALSE, 2); - - buffer = gtk_text_buffer_new (NULL); - gtk_text_buffer_get_start_iter (buffer, &iter); - gtk_text_buffer_insert (buffer, &iter, - gst_player_media_info_get_uri (info), -1); - uri = gtk_text_view_new_with_buffer (buffer); - gtk_box_pack_start (GTK_BOX (hbox), uri, FALSE, FALSE, 2); - gtk_text_view_set_editable (GTK_TEXT_VIEW (uri), FALSE); - g_object_unref (buffer); - - hbox_close = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); - gtk_box_pack_start (GTK_BOX (vbox), hbox_close, FALSE, FALSE, 2); - button_close = gtk_button_new_with_label (" Close "); - g_signal_connect (button_close, "clicked", - G_CALLBACK (delete_media_info_window), window); - gtk_box_pack_end (GTK_BOX (hbox_close), button_close, FALSE, FALSE, 3); - - gtk_widget_show_all (window); + gtk_widget_show_all (play->media_info_dialog); + gtk_dialog_run (GTK_DIALOG (play->media_info_dialog)); } static void media_info_clicked_cb (GtkButton * button, GtkPlay * play) { - GstPlayerMediaInfo *info; + GstPlayerMediaInfo *media_info; - info = gst_player_get_media_info (play->player); - if (!info) + media_info = gst_player_get_media_info (play->player); + if (!media_info) return; - create_media_info_window (play, info); - - g_object_unref (info); + media_info_dialog (play, media_info); + g_object_unref (media_info); } static gboolean -toolbar_hide_func (GtkPlay * play) +toolbar_hide_cb (GtkPlay * play) { GdkCursor *cursor; - /* TODO: add some animation while hiding the toolbar. */ + /* hide mouse pointer and toolbar */ gtk_widget_hide (play->toolbar); - - /* hide the mouse pointer */ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (play)), GDK_BLANK_CURSOR); @@ -739,43 +695,59 @@ toolbar_hide_func (GtkPlay * play) } static void -fullscreen_toggle_cb (GtkToggleButton * widget, GtkPlay * play) +toolbar_show (GtkPlay * play) +{ + /* if timer is running then kill it */ + if (play->toolbar_hide_timeout) { + g_source_remove (play->toolbar_hide_timeout); + play->toolbar_hide_timeout = 0; + } + + /* show toolbar and mouse pointer */ + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET + (play->video_area)), play->default_cursor); + gtk_widget_show (play->toolbar); +} + +static void +start_toolbar_hide_timer (GtkPlay * play) +{ + /* hide toolbar only if its playing */ + if (!play->playing) + return; + + /* start timer to hide toolbar */ + if (play->toolbar_hide_timeout) + g_source_remove (play->toolbar_hide_timeout); + play->toolbar_hide_timeout = g_timeout_add_seconds (5, + (GSourceFunc) toolbar_hide_cb, play); +} + +G_MODULE_EXPORT void +fullscreen_button_toggled_cb (GtkToggleButton * widget, GtkPlay * play) { GtkWidget *image; if (gtk_toggle_button_get_active (widget)) { - image = gtk_image_new_from_icon_name ("view-restore", GTK_ICON_SIZE_BUTTON); + image = TOOLBAR_GET_OBJECT (restore_image); gtk_window_fullscreen (GTK_WINDOW (play)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); - - /* start timer to hide toolbar */ - if (play->toolbar_hide_timeout) - g_source_remove (play->toolbar_hide_timeout); - play->toolbar_hide_timeout = g_timeout_add_seconds (5, - (GSourceFunc) toolbar_hide_func, play); } else { - /* if toolbar hide timer is running then kill it */ - if (play->toolbar_hide_timeout) { - g_source_remove (play->toolbar_hide_timeout); - play->toolbar_hide_timeout = 0; - } - - image = gtk_image_new_from_icon_name ("view-fullscreen", - GTK_ICON_SIZE_BUTTON); + image = TOOLBAR_GET_OBJECT (fullscreen_image); gtk_window_unfullscreen (GTK_WINDOW (play)); gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); } } -static void +G_MODULE_EXPORT void seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) { gdouble value = gtk_range_get_value (GTK_RANGE (play->seekbar)); gst_player_seek (play->player, gst_util_uint64_scale (value, GST_SECOND, 1)); } -void -volume_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) +G_MODULE_EXPORT void +volume_button_value_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) { gst_player_set_volume (play->player, value); } @@ -860,7 +832,6 @@ disable_track (GtkPlay * play, GType type) { if (type == GST_TYPE_PLAYER_VIDEO_INFO) { gst_player_set_video_track_enabled (play->player, FALSE); - display_cover_art (play, NULL); /* display cover art */ } else if (type == GST_TYPE_PLAYER_AUDIO_INFO) gst_player_set_audio_track_enabled (play->player, FALSE); else @@ -873,11 +844,6 @@ change_track (GtkPlay * play, gint index, GType type) if (type == GST_TYPE_PLAYER_VIDEO_INFO) { gst_player_set_video_track (play->player, index); gst_player_set_video_track_enabled (play->player, TRUE); - /* if video area widget is not visible then make it visible */ - if (!gtk_widget_is_visible (play->video_area)) { - gtk_widget_hide (play->image_area); - gtk_widget_show (play->video_area); - } } else if (type == GST_TYPE_PLAYER_AUDIO_INFO) { gst_player_set_audio_track (play->player, index); gst_player_set_audio_track_enabled (play->player, TRUE); @@ -912,18 +878,9 @@ visualization_changed_cb (GtkWidget * widget, GtkPlay * play) gchar *name; if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) { - - /* video_area is window-id is shared with playbin hence - * video_area widget will be used by visualization elements to - * render the visuals. If visualization is enabled then hide - * image widget and show video widget and similiarly when visualization - * is disabled then hide video widget and show imag widget. - */ name = g_object_get_data (G_OBJECT (widget), "name"); if (g_strcmp0 (name, "disable") == 0) { gst_player_set_visualization_enabled (play->player, FALSE); - gtk_widget_hide (play->video_area); - gtk_widget_show (play->image_area); } else { const gchar *vis_name; @@ -932,8 +889,6 @@ visualization_changed_cb (GtkWidget * widget, GtkPlay * play) if (!(vis_name = gst_player_get_current_visualization (play->player))) { gst_player_set_visualization_enabled (play->player, TRUE); } - gtk_widget_hide (play->image_area); - gtk_widget_show (play->video_area); } } } @@ -1057,41 +1012,6 @@ player_set_rate_cb (GtkSpinButton * button, GtkPlay * play) gst_player_set_rate (play->player, gtk_spin_button_get_value (button)); } -static void -player_speed_clicked_cb (GtkButton * button, GtkPlay * play) -{ - GtkWidget *box; - GtkWidget *label; - GtkWidget *dialog; - GtkWidget *content; - GtkWidget *rate_spinbutton; - - dialog = - gtk_dialog_new_with_buttons ("Playback speed control", GTK_WINDOW (play), - GTK_DIALOG_DESTROY_WITH_PARENT, "_Close", GTK_RESPONSE_CLOSE, NULL); - gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (play)); - - content = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); - box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); - gtk_box_pack_start (GTK_BOX (content), box, TRUE, TRUE, 0); - - label = gtk_label_new ("Playback rate"); - rate_spinbutton = gtk_spin_button_new_with_range (-64, 64, 0.1); - gtk_spin_button_set_digits (GTK_SPIN_BUTTON (rate_spinbutton), 2); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (rate_spinbutton), - gst_player_get_rate (play->player)); - - gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (box), rate_spinbutton, TRUE, TRUE, 2); - g_signal_connect (rate_spinbutton, "value-changed", - G_CALLBACK (player_set_rate_cb), play); - - gtk_widget_show_all (dialog); - gtk_dialog_run (GTK_DIALOG (dialog)); - - gtk_widget_destroy (dialog); -} - static void player_quit_clicked_cb (GtkButton * button, GtkPlay * play) { @@ -1113,7 +1033,6 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) GtkWidget *submenu; GtkWidget *vis; GtkWidget *cb; - GtkWidget *speed; GstPlayerMediaInfo *media_info; menu = gtk_menu_new (); @@ -1127,7 +1046,6 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) quit = gtk_menu_item_new_with_label ("Quit"); vis = gtk_menu_item_new_with_label ("Visualization"); cb = gtk_menu_item_new_with_label ("Color Balance"); - speed = gtk_menu_item_new_with_label ("Playback Speed"); media_info = gst_player_get_media_info (play->player); @@ -1182,13 +1100,11 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) g_signal_connect (G_OBJECT (cb), "activate", G_CALLBACK (color_balance_clicked_cb), play); g_signal_connect (G_OBJECT (next), "activate", - G_CALLBACK (skip_next_clicked_cb), play); + G_CALLBACK (next_button_clicked_cb), play); g_signal_connect (G_OBJECT (prev), "activate", - G_CALLBACK (skip_prev_clicked_cb), play); + G_CALLBACK (prev_button_clicked_cb), play); g_signal_connect (G_OBJECT (info), "activate", G_CALLBACK (media_info_clicked_cb), play); - g_signal_connect (G_OBJECT (speed), "activate", - G_CALLBACK (player_speed_clicked_cb), play); g_signal_connect (G_OBJECT (quit), "activate", G_CALLBACK (player_quit_clicked_cb), play); @@ -1201,7 +1117,6 @@ gtk_player_popup_menu_create (GtkPlay * play, GdkEventButton * event) gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub); gtk_menu_shell_append (GTK_MENU_SHELL (menu), info); gtk_menu_shell_append (GTK_MENU_SHELL (menu), cb); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), speed); gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit); gtk_widget_show_all (menu); @@ -1233,68 +1148,108 @@ mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, } static gboolean -image_area_draw_cb (GtkWidget * widget, cairo_t * cr, GtkPlay * play) -{ - if (play->image_pixbuf) { - gint width, height; - gint pix_width, pix_height; - gint x = 0, y = 0; - gdouble scalex = 0.0, scaley = 0.0; - - width = gtk_widget_get_allocated_width (widget); - height = gtk_widget_get_allocated_height (widget); - pix_width = gdk_pixbuf_get_width (play->image_pixbuf); - pix_height = gdk_pixbuf_get_height (play->image_pixbuf); - - /* if image is bigger than widget then scale down otherwise center it. */ - if (width <= pix_width) - scalex = (gdouble) width / (gdouble) pix_width; - else - x = (width - pix_width) / 2; - if (height <= pix_height) - scaley = (gdouble) height / (gdouble) pix_height; - else - y = (height - pix_height) / 2; +video_area_leave_notify_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +{ + start_toolbar_hide_timer (play); - /* fill background with black */ - cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); + return TRUE; +} - if (scalex > 0.0 && scaley > 0.0) - cairo_scale (cr, scalex, scaley); +static gboolean +video_area_toolbar_show_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +{ + toolbar_show (play); - gdk_cairo_set_source_pixbuf (cr, play->image_pixbuf, x, y); - cairo_paint (cr); - } else { - /* fill background with black */ - cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); - cairo_paint (cr); - } + start_toolbar_hide_timer (play); - return FALSE; + return TRUE; } static gboolean -gtk_show_toolbar_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +overlay_leave_notify_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) { - if (gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON (play->fullscreen_button))) { + start_toolbar_hide_timer (play); - /* if timer is running then kill it */ - if (play->toolbar_hide_timeout) { - g_source_remove (play->toolbar_hide_timeout); - play->toolbar_hide_timeout = 0; - } + return TRUE; +} + +static gboolean +overlay_enter_notify_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +{ + toolbar_show (play); + + return TRUE; +} + +static void +apply_css (GtkWidget *widget, GtkStyleProvider *provider) +{ + gtk_style_context_add_provider (gtk_widget_get_style_context (widget), + provider, G_MAXUINT); + if (GTK_IS_CONTAINER (widget)) { + gtk_container_forall (GTK_CONTAINER (widget), + (GtkCallback) apply_css, provider); + } +} + +static void +gtk_widget_apply_css (GtkWidget * widget, const gchar * filename) +{ + GBytes *bytes; + gsize data_size; + const guint8 *data; + GError *err = NULL; + GtkStyleProvider *provider; - /* show mouse pointer */ - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET - (play->video_area)), play->default_cursor); + if (widget == NULL) + return; - gtk_widget_show (play->toolbar); - play->toolbar_hide_timeout = g_timeout_add_seconds (5, - (GSourceFunc) toolbar_hide_func, play); + provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ()); + bytes = g_resources_lookup_data (filename, 0, &err); + if (err) { + g_print ("ERROR: failed to apply css %s '%s' \n", filename, err->message); + return; } + data = g_bytes_get_data (bytes, &data_size); + gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (provider), + (gchar *)data, data_size, NULL); + g_bytes_unref (bytes); + + apply_css (widget, provider); +} + +static gboolean +get_child_position (GtkOverlay * overlay, GtkWidget * widget, + GtkAllocation * alloc, GtkPlay * play) +{ + GtkRequisition req; + GtkWidget *child; + GtkAllocation main_alloc; + gint x, y; + GtkWidget * relative = play->video_area; + + child = gtk_bin_get_child (GTK_BIN (overlay)); + gtk_widget_translate_coordinates (relative, child, 0, 0, &x, &y); + main_alloc.x = x; + main_alloc.y = y; + main_alloc.width = gtk_widget_get_allocated_width (relative); + main_alloc.height = gtk_widget_get_allocated_height (relative); + + gtk_widget_get_preferred_size (widget, NULL, &req); + + alloc->x = (main_alloc.width - req.width) / 2; + if (alloc->x < 0) + alloc->x = 0; + alloc->width = MIN (main_alloc.width, req.width); + if (gtk_widget_get_halign (widget) == GTK_ALIGN_END) + alloc->x += main_alloc.width - req.width; + + alloc->y = main_alloc.height - req.height - 20; + if (alloc->y < 0) + alloc->y = 0; + alloc->height = MIN (main_alloc.height, req.height); + if (gtk_widget_get_valign (widget) == GTK_ALIGN_END) + alloc->y += main_alloc.height - req.height; return TRUE; } @@ -1303,7 +1258,7 @@ static void create_ui (GtkPlay * play) { GtkWidget *image; - GtkWidget *controls, *main_hbox, *main_vbox; + GtkWidget *main_hbox, *main_vbox; GstElement *playbin, *gtk_sink; gtk_window_set_default_size (GTK_WINDOW (play), 640, 480); @@ -1336,140 +1291,123 @@ create_ui (GtkPlay * play) g_signal_connect (play->video_area, "realize", G_CALLBACK (video_area_realize_cb), play); } - g_signal_connect (play->video_area, "button-press-event", - G_CALLBACK (mouse_button_pressed_cb), play); - g_signal_connect (play->video_area, "motion-notify-event", - G_CALLBACK (gtk_show_toolbar_cb), play); - g_signal_connect (play->video_area, "scroll-event", - G_CALLBACK (gtk_show_toolbar_cb), play); gtk_widget_set_events (play->video_area, GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK); - - play->image_area = gtk_drawing_area_new (); - g_signal_connect (play->image_area, "button-press-event", + g_signal_connect (play->video_area, "motion-notify-event", + G_CALLBACK (video_area_toolbar_show_cb), play); + g_signal_connect (play->video_area, "scroll-event", + G_CALLBACK (video_area_toolbar_show_cb), play); + g_signal_connect (play->video_area, "button-press-event", G_CALLBACK (mouse_button_pressed_cb), play); - g_signal_connect (play->image_area, "draw", - G_CALLBACK (image_area_draw_cb), play); - g_signal_connect (play->image_area, "motion-notify-event", - G_CALLBACK (gtk_show_toolbar_cb), play); - g_signal_connect (play->image_area, "scroll-event", - G_CALLBACK (gtk_show_toolbar_cb), play); - gtk_widget_set_events (play->image_area, GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK); + g_signal_connect (play->video_area, "leave-notify-event", + G_CALLBACK (video_area_leave_notify_cb), play); - /* Unified play/pause button */ - play->play_pause_button = - gtk_button_new_from_icon_name ("media-playback-pause", - GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->play_pause_button), "clicked", - G_CALLBACK (play_pause_clicked_cb), play); + /* load toolbar UI */ + play->toolbar_ui = load_from_builder ("/ui/toolbar.ui", TRUE, play); + if (!play->toolbar_ui) + return; - play->seekbar = - gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 100, 1); - gtk_scale_set_draw_value (GTK_SCALE (play->seekbar), 0); - gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); - play->seekbar_value_changed_signal_id = - g_signal_connect (G_OBJECT (play->seekbar), "value-changed", - G_CALLBACK (seekbar_value_changed_cb), play); - - /* Skip backward button */ - play->prev_button = - gtk_button_new_from_icon_name ("media-skip-backward", - GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->prev_button), "clicked", - G_CALLBACK (skip_prev_clicked_cb), play); - gtk_widget_set_sensitive (play->prev_button, FALSE); - - /* Skip forward button */ - play->next_button = - gtk_button_new_from_icon_name ("media-skip-forward", - GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->next_button), "clicked", - G_CALLBACK (skip_next_clicked_cb), play); - gtk_widget_set_sensitive (play->next_button, FALSE); - - /* Playlist repeat button */ - play->repeat_button = gtk_toggle_button_new (); - image = gtk_image_new_from_icon_name ("media-playlist-repeat", - GTK_ICON_SIZE_BUTTON); - gtk_button_set_image (GTK_BUTTON (play->repeat_button), image); - if (play->loop) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->repeat_button), - TRUE); - - /* Volume control button */ - play->volume_button = gtk_volume_button_new (); - gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), - gst_player_get_volume (play->player)); - g_signal_connect (G_OBJECT (play->volume_button), "value-changed", - G_CALLBACK (volume_changed_cb), play); - - /* media information button */ - play->media_info_button = gtk_button_new_from_icon_name ("dialog-information", - GTK_ICON_SIZE_BUTTON); - g_signal_connect (G_OBJECT (play->media_info_button), "clicked", - G_CALLBACK (media_info_clicked_cb), play); - gtk_widget_set_sensitive (play->media_info_button, FALSE); - - /* Full screen button */ - play->fullscreen_button = gtk_toggle_button_new (); - image = gtk_image_new_from_icon_name ("view-fullscreen", - GTK_ICON_SIZE_BUTTON); - gtk_button_set_image (GTK_BUTTON (play->fullscreen_button), image); - g_signal_connect (G_OBJECT (play->fullscreen_button), "toggled", - G_CALLBACK (fullscreen_toggle_cb), play); - if (play->fullscreen) - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->fullscreen_button), - TRUE); - - play->toolbar = controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_start (GTK_BOX (controls), play->prev_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->play_pause_button, FALSE, - FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->next_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->repeat_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->seekbar, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->volume_button, FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->media_info_button, - FALSE, FALSE, 2); - gtk_box_pack_start (GTK_BOX (controls), play->fullscreen_button, - FALSE, FALSE, 2); + play->toolbar = TOOLBAR_GET_OBJECT (toolbar); + play->play_pause_button = TOOLBAR_GET_OBJECT (play_pause_button); + play->seekbar = TOOLBAR_GET_OBJECT (seekbar); + play->next_button = TOOLBAR_GET_OBJECT (next_button); + play->prev_button = TOOLBAR_GET_OBJECT (prev_button); + play->fullscreen_button = TOOLBAR_GET_OBJECT (fullscreen_button); + play->volume_button = TOOLBAR_GET_OBJECT (volume_button); + play->elapshed_label = TOOLBAR_GET_LABEL (elapshed_time); + play->remain_label = TOOLBAR_GET_LABEL (remain_time); + play->rate_label = TOOLBAR_GET_LABEL (rate_label); + play->title_label = TOOLBAR_GET_LABEL (title_label); main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (main_hbox), play->video_area, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (main_hbox), play->image_area, TRUE, TRUE, 0); - main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (main_vbox), controls, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (play), main_vbox); + /* set minimum window size */ + gtk_widget_set_size_request (main_hbox, 320, 240); + + /* set the toolbar size */ + gtk_widget_set_size_request (play->toolbar, 500, 50); + + play->toolbar_overlay = gtk_overlay_new (); + gtk_overlay_add_overlay (GTK_OVERLAY (play->toolbar_overlay), play->toolbar); + gtk_container_add (GTK_CONTAINER (play->toolbar_overlay), main_hbox); + gtk_container_add (GTK_CONTAINER (play), play->toolbar_overlay); + gtk_widget_set_events (play->toolbar_overlay, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK); + + g_signal_connect (play->toolbar_overlay, "get-child-position", + G_CALLBACK (get_child_position), play); + g_signal_connect (play->toolbar_overlay, "leave-notify-event", + G_CALLBACK (overlay_leave_notify_event_cb), play); + g_signal_connect (play->toolbar_overlay, "enter-notify-event", + G_CALLBACK (overlay_enter_notify_event_cb), play); + + /* apply css on widgets */ + gtk_widget_apply_css (play->toolbar, "/css/toolbar.css"); if (!gtk_sink) gtk_widget_realize (play->video_area); gtk_widget_hide (play->video_area); + + /* start toolbar autohide timer */ + start_toolbar_hide_timer (play); + + /* check if we need to enable fullscreen */ + if (play->fullscreen) + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); + + /* enable visualization (by default laybin uses goom) */ + /* if visualization is enabled then use the first element */ + gst_player_set_visualization_enabled (play->player, TRUE); } static void duration_changed_cb (GstPlayer * unused, GstClockTime duration, GtkPlay * play) { - gtk_range_set_range (GTK_RANGE (play->seekbar), 0, + gtk_range_set_range (GTK_RANGE (play->seekbar), 0.0, (gdouble) duration / GST_SECOND); } +static void +update_position_label (GtkLabel * label, guint64 seconds) +{ + gchar *data; + gint hrs, mins; + + hrs = seconds / 3600; + seconds -= hrs * 3600; + mins = seconds / 60; + seconds -= mins * 60; + + if (hrs) + data = g_strdup_printf ("%02d:%02d", hrs, mins); + else + data = g_strdup_printf ("%02d:%02ld", mins, seconds); + + gtk_label_set_label (label, data); + g_free (data); +} + static void position_updated_cb (GstPlayer * unused, GstClockTime position, GtkPlay * play) { - g_signal_handler_block (play->seekbar, play->seekbar_value_changed_signal_id); + g_signal_handlers_block_by_func (play->seekbar, + seekbar_value_changed_cb, play); gtk_range_set_value (GTK_RANGE (play->seekbar), (gdouble) position / GST_SECOND); - g_signal_handler_unblock (play->seekbar, - play->seekbar_value_changed_signal_id); + update_position_label (play->elapshed_label, position / GST_SECOND); + update_position_label (play->remain_label, + GST_CLOCK_DIFF (position, gst_player_get_duration (play->player)) / + GST_SECOND); + g_signal_handlers_unblock_by_func (play->seekbar, + seekbar_value_changed_cb, play); } static void @@ -1479,8 +1417,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) GList *next = NULL; next = g_list_next (play->current_uri); - if (!next && gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON (play->repeat_button))) + if (!next && play->loop) next = g_list_first (play->uris); if (next) { @@ -1489,9 +1426,7 @@ eos_cb (GstPlayer * unused, GtkPlay * play) GtkWidget *image; gst_player_pause (play->player); - image = - gtk_image_new_from_icon_name ("media-playback-start", - GTK_ICON_SIZE_BUTTON); + image = TOOLBAR_GET_OBJECT (play_image); gtk_button_set_image (GTK_BUTTON (play->play_pause_button), image); play->playing = FALSE; if (play->inhibit_cookie) @@ -1502,31 +1437,23 @@ eos_cb (GstPlayer * unused, GtkPlay * play) } } -static gboolean -_has_active_stream (GtkPlay * play, void *(*func) (GstPlayer * player)) -{ - void *obj; - - obj = func (play->player); - if (obj) { - g_object_unref (obj); - return TRUE; - } - - return FALSE; -} - static GdkPixbuf * -gst_sample_to_pixbuf (GtkPlay * play, GstSample * sample) +gtk_play_get_cover_image (GstPlayerMediaInfo * media_info) { - GdkPixbufLoader *loader; - GdkPixbuf *pixbuf = NULL; - GError *err = NULL; + GstSample *sample; GstMapInfo info; GstBuffer *buffer; + GError *err = NULL; + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf = NULL; const GstStructure *caps_struct; GstTagImageType type = GST_TAG_IMAGE_TYPE_UNDEFINED; + /* get image sample buffer from media */ + sample = gst_player_media_info_get_image_sample (media_info); + if (!sample) + return NULL; + buffer = gst_sample_get_buffer (sample); caps_struct = gst_sample_get_info (sample); @@ -1566,84 +1493,27 @@ gst_sample_to_pixbuf (GtkPlay * play, GstSample * sample) return pixbuf; } - -static void -display_cover_art (GtkPlay * play, GstPlayerMediaInfo * media_info) -{ - GstSample *sample; - GstPlayerMediaInfo *temp_media_info = NULL; - - /* hide the video widget and show image widget */ - gtk_widget_hide (play->video_area); - gtk_widget_show (play->image_area); - - /* if media information is not passed then get it from player */ - if (!media_info) - temp_media_info = media_info = gst_player_get_media_info (play->player); - - sample = gst_player_media_info_get_image_sample (media_info); - if (!sample) - goto cleanup; - - if (play->image_pixbuf) - g_object_unref (play->image_pixbuf); - - play->image_pixbuf = gst_sample_to_pixbuf (play, sample); - -cleanup: - gtk_widget_queue_draw (play->image_area); /* send expose event to widget */ - - if (temp_media_info) - g_object_unref (temp_media_info); -} - -static gboolean -has_active_stream (GtkPlay * play, GType type) -{ - if (type == GST_TYPE_PLAYER_VIDEO_INFO) - return _has_active_stream (play, - (void *) gst_player_get_current_video_track); - else if (type == GST_TYPE_PLAYER_AUDIO_INFO) - return _has_active_stream (play, - (void *) gst_player_get_current_audio_track); - else - return _has_active_stream (play, - (void *) gst_player_get_current_subtitle_track); -} - static void media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, GtkPlay * play) { - if (!gtk_widget_is_sensitive (play->media_info_button)) { - const gchar *title; - const gchar *vis; + const gchar *title; + GdkPixbuf *pixbuf; - title = gst_player_media_info_get_title (media_info); - if (title) - set_title (play, title); + title = gst_player_media_info_get_title (media_info); + if (!title) + title = g_path_get_basename (gst_player_media_info_get_uri (media_info)); - gtk_widget_set_sensitive (play->media_info_button, TRUE); + pixbuf = gtk_play_get_cover_image (media_info); - /* if we have active video stream then hide image widget - * and show video widget otherwise show the cover art. - */ - if (has_active_stream (play, GST_TYPE_PLAYER_VIDEO_INFO)) { - gtk_widget_hide (play->image_area); - gtk_widget_show (play->video_area); - } else { - display_cover_art (play, media_info); - } + if (title) { + gtk_label_set_label (play->title_label, title); + set_title (play, title); + } - /* if we have audio only stream and visualization is enabled - * then show video widget. - */ - vis = gst_player_get_current_visualization (play->player); - if (!has_active_stream (play, GST_TYPE_PLAYER_VIDEO_INFO) && - has_active_stream (play, GST_TYPE_PLAYER_AUDIO_INFO) && vis) { - gtk_widget_show (play->video_area); - gtk_widget_hide (play->image_area); - } + if (pixbuf) { + gtk_window_set_icon (GTK_WINDOW (play), pixbuf); + g_object_unref (pixbuf); } } @@ -1657,11 +1527,11 @@ player_volume_changed_cb (GstPlayer * player, GtkPlay * play) if (fabs (cur_val - new_val) > 0.001) { g_signal_handlers_block_by_func (play->volume_button, - volume_changed_cb, play); + volume_button_value_changed_cb, play); gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), new_val); g_signal_handlers_unblock_by_func (play->volume_button, - volume_changed_cb, play); + volume_button_value_changed_cb, play); } } @@ -1678,9 +1548,6 @@ gtk_play_set_property (GObject * object, guint prop_id, const GValue * value, case PROP_FULLSCREEN: self->fullscreen = g_value_get_boolean (value); break; - case PROP_VISUAL: - self->visual = g_value_get_boolean (value); - break; case PROP_URIS: self->uris = g_value_get_pointer (value); break; @@ -1725,19 +1592,6 @@ gtk_play_constructor (GType type, guint n_construct_params, create_ui (self); - /* if visualization is enabled then use the first element */ - if (self->visual) { - GstPlayerVisualization **viss; - viss = gst_player_visualizations_get (); - - if (viss && *viss) { - gst_player_set_visualization (self->player, (*viss)->name); - gst_player_set_visualization_enabled (self->player, TRUE); - } - if (viss) - gst_player_visualizations_free (viss); - } - g_signal_connect (self->player, "position-updated", G_CALLBACK (position_updated_cb), self); g_signal_connect (self->player, "duration-changed", @@ -1801,9 +1655,6 @@ gtk_play_class_init (GtkPlayClass * klass) g_param_spec_boolean ("fullscreen", "Fullscreen", "Fullscreen mode", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - gtk_play_properties[PROP_VISUAL] = - g_param_spec_boolean ("visual", "Visual", "Use Visualizations", FALSE, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); gtk_play_properties[PROP_URIS] = g_param_spec_pointer ("uris", "URIs", "URIs to play", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); @@ -1819,13 +1670,12 @@ gtk_play_app_command_line (GApplication * application, GVariantDict *options; GtkPlay *play; GList *uris = NULL; - gboolean loop = FALSE, visual = FALSE, fullscreen = FALSE; + gboolean loop = FALSE, fullscreen = FALSE; gchar **uris_array = NULL; options = g_application_command_line_get_options_dict (command_line); g_variant_dict_lookup (options, "loop", "b", &loop); - g_variant_dict_lookup (options, "visual", "b", &visual); g_variant_dict_lookup (options, "fullscreen", "b", &fullscreen); g_variant_dict_lookup (options, G_OPTION_REMAINING, "^a&ay", &uris_array); @@ -1850,7 +1700,7 @@ gtk_play_app_command_line (GApplication * application, play = g_object_new (gtk_play_get_type (), "loop", loop, "fullscreen", - fullscreen, "visual", visual, "uris", uris, NULL); + fullscreen, "uris", uris, NULL); gtk_widget_show_all (GTK_WIDGET (play)); return @@ -1881,8 +1731,6 @@ gtk_play_app_new (void) {"loop", 'l', 0, G_OPTION_ARG_NONE, NULL, "Repeat all"}, {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, NULL, "Show the player in fullscreen"}, - {"visual", 'v', 0, G_OPTION_ARG_NONE, NULL, - "Show visualization when there is no video stream"}, {NULL} }; diff --git a/playback/player/gtk/resources/gresources.xml b/playback/player/gtk/resources/gresources.xml new file mode 100644 index 0000000..90b3c43 --- /dev/null +++ b/playback/player/gtk/resources/gresources.xml @@ -0,0 +1,11 @@ + + + + toolbar.ui + media_info_dialog.ui + + + toolbar.css + + + diff --git a/playback/player/gtk/resources/media_info_dialog.ui b/playback/player/gtk/resources/media_info_dialog.ui new file mode 100644 index 0000000..fe25cf1 --- /dev/null +++ b/playback/player/gtk/resources/media_info_dialog.ui @@ -0,0 +1,108 @@ + + + + + + + + + + + + media_info_dialog + False + center-on-parent + dialog + + + False + vertical + 2 + + + False + end + + + Close + media_info_dialog_button + True + True + True + + + + True + True + 0 + + + + + False + False + 0 + + + + + True + False + vertical + + + True + False + 5 + Information about all the streams contains in your media. + + + False + True + 0 + + + + + True + True + 5 + in + + + True + True + tree + False + + + + + + autosize + col + + + + + + + + + + True + True + 1 + + + + + True + True + 1 + + + + + + diff --git a/playback/player/gtk/resources/toolbar.css b/playback/player/gtk/resources/toolbar.css new file mode 100644 index 0000000..b967454 --- /dev/null +++ b/playback/player/gtk/resources/toolbar.css @@ -0,0 +1,26 @@ +* { + background-color: rgba(43,56,54,0.0); + padding: 0px; +} + +GtkLabel { + font-size: 10px; + color: #ffffff; +} + +#toolbar { + border-radius: 25px; + border: 3px solid #212B2A; + background: rgba(43,56,54,0.6); +} + +GtkButton:hover { + border-radius: 45px; + background: rgba(43,56,54,1.0); + border: 1px solid #212B2A; +} + +#title_label { + font-size: 12px; +} + diff --git a/playback/player/gtk/resources/toolbar.ui b/playback/player/gtk/resources/toolbar.ui new file mode 100644 index 0000000..c185795 --- /dev/null +++ b/playback/player/gtk/resources/toolbar.ui @@ -0,0 +1,341 @@ + + + + + + + True + False + 30 + gtk-media-forward + 0 + + + True + False + 25 + view-fullscreen + 0 + + + True + False + 30 + gtk-media-next + 0 + + + True + False + 35 + media-playback-pause + 0 + + + True + False + 0 + 0 + 35 + gtk-media-play + 0 + + + True + False + 30 + gtk-media-previous + + + restore_image + True + False + 25 + view-restore + 0 + + + True + False + 30 + gtk-media-rewind + + + toolbar + True + False + 5 + vertical + + + True + False + 20 + 20 + 9 + + + elapshed_time + True + False + center + 00:00 + + + False + True + 0 + + + + + seekbar + True + True + center + 1 + False + + + + True + True + 1 + + + + + remain_time + True + False + center + 00:00 + + + False + True + 2 + + + + + volume_button + True + True + True + center + none + False + vertical + audio-volume-muted +audio-volume-high +audio-volume-low +audio-volume-medium + + + + + + True + True + none + + + + + - + True + True + none + + + + + False + True + 3 + + + + + fullscreen_button + True + True + True + fullscreen_image + none + 0 + 0 + + + + False + True + 4 + + + + + False + True + -1 + + + + + title_label + True + False + 5 + center + True + + + False + True + 0 + + + + + True + False + center + 20 + 20 + 10 + + + True + False + center + center + 5 + + + prev_button + True + True + True + center + prev_image + none + 0 + 0 + + + + False + True + 0 + + + + + rewind_button + True + True + True + center + center + rewind_image + none + 0 + 0 + + + + False + True + 1 + + + + + play_pause_button + True + True + True + center + pause_image + none + 0 + 0 + + + + False + True + 2 + + + + + forward_button + True + True + True + center + forward_image + none + 0 + 0 + + + + False + True + 3 + + + + + next_button + True + True + True + center + next_image + none + 0 + 0 + + + + False + True + 4 + + + + + True + True + 0 + + + + + rate_label + 40 + False + center + 0 + 0 + right + + + False + True + end + 1 + + + + + False + True + 2 + + + + -- cgit v1.2.3 From 0a38d3699699a6277f85743ea15edbe2bf093de0 Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Wed, 15 Jul 2015 19:18:11 +0200 Subject: playback/player: gtk-play: remove unused variables --- playback/player/gtk/gtk-play.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 32973af..ad42da7 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -630,7 +630,6 @@ media_info_dialog (GtkPlay * play, GstPlayerMediaInfo * media_info) GtkBuilder *dialog_ui; GtkWidget *view; GtkTreeStore *tree; - GtkTreeModel *model; GtkTreeViewColumn *col; GtkCellRenderer *renderer; @@ -1257,8 +1256,7 @@ get_child_position (GtkOverlay * overlay, GtkWidget * widget, static void create_ui (GtkPlay * play) { - GtkWidget *image; - GtkWidget *main_hbox, *main_vbox; + GtkWidget *main_hbox; GstElement *playbin, *gtk_sink; gtk_window_set_default_size (GTK_WINDOW (play), 640, 480); -- cgit v1.2.3 From 64a73ff36b3679eb02f63961c99d105e0f103ed9 Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Wed, 15 Jul 2015 19:52:39 +0200 Subject: playback/player: gtk-play: remove unused callback --- playback/player/gtk/gtk-play.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index ad42da7..4c7e369 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1005,12 +1005,6 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) return menu; } -static void -player_set_rate_cb (GtkSpinButton * button, GtkPlay * play) -{ - gst_player_set_rate (play->player, gtk_spin_button_get_value (button)); -} - static void player_quit_clicked_cb (GtkButton * button, GtkPlay * play) { -- cgit v1.2.3 From a8bb7e0199d7fced6b73220f9719bc7e60eb6202 Mon Sep 17 00:00:00 2001 From: Víctor Manuel Jáquez Leal Date: Wed, 8 Jul 2015 20:56:47 +0200 Subject: playback/player: gtk-play: handle keys Add a mplayer alike key-binding. --- playback/player/gtk/gtk-play.c | 147 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 4c7e369..1d0491d 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -207,6 +207,147 @@ gtk_play_set_rate (GtkPlay * play, gdouble step) } } +static inline void +seekbar_add_delta (GtkPlay *play, gint delta_sec) +{ + gdouble value = gtk_range_get_value (GTK_RANGE (play->seekbar)); + gtk_range_set_value (GTK_RANGE (play->seekbar), value + delta_sec); +} + +/* this mapping follow the mplayer key-bindings */ +static gboolean +key_press_event_cb (GtkWidget * widget, GdkEventKey * event, gpointer data) +{ + GtkPlay *play = (GtkPlay *) widget; + + if (event->state != 0 && + ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_MOD1_MASK) || + (event->state & GDK_MOD3_MASK) || (event->state & GDK_MOD4_MASK))) + return FALSE; + + if (event->type != GDK_KEY_PRESS) + return FALSE; + + switch (event->keyval) { + case GDK_KEY_KP_Right: + case GDK_KEY_Right: { + /* seek forward 10 seconds */ + seekbar_add_delta (play, 10); + break; + } + case GDK_KEY_KP_Left: + case GDK_KEY_Left: { + /* seek backward 10 seconds */ + seekbar_add_delta (play, -10); + break; + } + case GDK_KEY_KP_Up: + case GDK_KEY_Up: { + /* seek forward 1 minute */ + seekbar_add_delta (play, 60); + break; + } + case GDK_KEY_KP_Down: + case GDK_KEY_Down: { + /* seek backward 1 minute */ + seekbar_add_delta (play, -60); + break; + } + case GDK_KEY_KP_Page_Up: + case GDK_KEY_Page_Up: { + /* Seek forward 10 minutes */ + seekbar_add_delta (play, 600); + break; + } + case GDK_KEY_KP_Page_Down: + case GDK_KEY_Page_Down: { + /* Seek backward 10 minutes */ + seekbar_add_delta (play, -600); + break; + } + case GDK_KEY_bracketleft: { + /* Decrease current playback speed by 10% */ + gtk_play_set_rate (play, -0.1); + break; + } + case GDK_KEY_bracketright: { + /* Increase current playback speed by 10% */ + gtk_play_set_rate (play, 0.1); + break; + break; + } + case GDK_KEY_braceleft: { + /* Decrease current playback speed by 10% */ + gtk_play_set_rate (play, -1.0); + break; + } + case GDK_KEY_braceright: { + /* Increase current playback speed by 10% */ + gtk_play_set_rate (play, 1.0); + break; + } + case GDK_KEY_BackSpace: { + /* Reset playback speed to normal */ + gdouble val = gst_player_get_rate (play->player); + gtk_play_set_rate (play, 1.0 - val); + break; + } + case GDK_KEY_less: { + /* Go backward in the playlist */ + if (g_list_previous (play->current_uri)) + gtk_button_clicked (GTK_BUTTON (play->prev_button)); + break; + } + case GDK_KEY_Return: + case GDK_KEY_greater: { + /* Go forward in the playlist */ + if (g_list_next (play->current_uri)) + gtk_button_clicked (GTK_BUTTON (play->next_button)); + break; + } + case GDK_KEY_KP_9: + case GDK_KEY_9: { + /* Increase volume */ + gdouble volume = gst_player_get_volume (play->player); + gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), + volume * 1.10); + break; + } + case GDK_KEY_KP_0: + case GDK_KEY_0: { + /* Decrease volume */ + gdouble volume = gst_player_get_volume (play->player); + gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), + volume * 0.9); + break; + } + case GDK_KEY_m: { + /* Mute sound */ + gboolean mute = gst_player_get_mute (play->player); + gst_player_set_mute (play->player, !mute); + break; + } + case GDK_KEY_f: { + /* Toggle fullscreen */ + GtkToggleButton *fs = GTK_TOGGLE_BUTTON (play->fullscreen_button); + gboolean active = !gtk_toggle_button_get_active (fs); + gtk_toggle_button_set_active (fs, active); + break; + } + case GDK_KEY_p: + case GDK_KEY_space: + /* toggle pause/play */ + gtk_button_clicked (GTK_BUTTON (play->play_pause_button)); + break; + case GDK_KEY_q: + case GDK_KEY_Escape: + default: + break; + } + + return FALSE; +} + G_MODULE_EXPORT void rewind_button_clicked_cb (GtkButton * button, GtkPlay * play) { @@ -1257,6 +1398,12 @@ create_ui (GtkPlay * play) g_signal_connect (G_OBJECT (play), "delete-event", G_CALLBACK (delete_event_cb), play); + + gtk_widget_set_events (GTK_WIDGET (play), + GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK); + g_signal_connect (G_OBJECT (play), "key-press-event", + G_CALLBACK (key_press_event_cb), NULL); + set_title (play, APP_NAME); gtk_application_add_window (GTK_APPLICATION (g_application_get_default ()), GTK_WINDOW (play)); -- cgit v1.2.3 From a18cefb73c2bd2e63d0ba004f8703d1bf811907b Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Wed, 29 Jul 2015 22:52:28 -0500 Subject: playback/player: gtk-play: fix elapsed and remain time label If elapsed or remain time is greater than 60 mins then add hours in label text. --- playback/player/gtk/gtk-play.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 1d0491d..e327606 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1526,7 +1526,7 @@ update_position_label (GtkLabel * label, guint64 seconds) seconds -= mins * 60; if (hrs) - data = g_strdup_printf ("%02d:%02d", hrs, mins); + data = g_strdup_printf ("%d:%02d:%02ld", hrs, mins, seconds); else data = g_strdup_printf ("%02d:%02ld", mins, seconds); -- cgit v1.2.3 From 7a874938a0a62d41dc91063489df8a521dddebbe Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Thu, 30 Jul 2015 07:35:04 -0500 Subject: playback/player: gtk-play: if title is NULL then use uri basename in toolbar label If stream title is not available in the stream then use file basename in toolbar title label and full uri in window title bar. --- playback/player/gtk/gtk-play.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index e327606..ed778a3 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1638,18 +1638,24 @@ media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, { const gchar *title; GdkPixbuf *pixbuf; + gchar *basename = NULL; + gchar *filename = NULL; title = gst_player_media_info_get_title (media_info); - if (!title) - title = g_path_get_basename (gst_player_media_info_get_uri (media_info)); - pixbuf = gtk_play_get_cover_image (media_info); - - if (title) { - gtk_label_set_label (play->title_label, title); - set_title (play, title); + if (!title) { + filename = g_filename_from_uri( + gst_player_media_info_get_uri (media_info), NULL, NULL); + basename = g_path_get_basename (filename); } + gtk_label_set_label (play->title_label, title ? title : basename); + set_title (play, title ? title : filename); + g_free(basename); + g_free(filename); + + pixbuf = gtk_play_get_cover_image (media_info); + if (pixbuf) { gtk_window_set_icon (GTK_WINDOW (play), pixbuf); g_object_unref (pixbuf); -- cgit v1.2.3 From f68bac6318085b051221bc1db1084ab8fce06d3a Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 30 Jul 2015 15:54:26 +0300 Subject: playback/player: gtk-play: Fix indention --- playback/player/gtk/gtk-play.c | 85 +++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index ed778a3..b1ad7ac 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -74,10 +74,10 @@ typedef struct GtkWidget *toolbar; GtkWidget *toolbar_overlay; GtkWidget *media_info_dialog; - GtkLabel *title_label; - GtkLabel *elapshed_label; - GtkLabel *remain_label; - GtkLabel *rate_label; + GtkLabel *title_label; + GtkLabel *elapshed_label; + GtkLabel *remain_label; + GtkLabel *rate_label; GdkCursor *default_cursor; gboolean playing; gboolean loop; @@ -208,7 +208,7 @@ gtk_play_set_rate (GtkPlay * play, gdouble step) } static inline void -seekbar_add_delta (GtkPlay *play, gint delta_sec) +seekbar_add_delta (GtkPlay * play, gint delta_sec) { gdouble value = gtk_range_get_value (GTK_RANGE (play->seekbar)); gtk_range_set_value (GTK_RANGE (play->seekbar), value + delta_sec); @@ -222,7 +222,7 @@ key_press_event_cb (GtkWidget * widget, GdkEventKey * event, gpointer data) if (event->state != 0 && ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_MOD1_MASK) || - (event->state & GDK_MOD3_MASK) || (event->state & GDK_MOD4_MASK))) + (event->state & GDK_MOD3_MASK) || (event->state & GDK_MOD4_MASK))) return FALSE; if (event->type != GDK_KEY_PRESS) @@ -230,83 +230,83 @@ key_press_event_cb (GtkWidget * widget, GdkEventKey * event, gpointer data) switch (event->keyval) { case GDK_KEY_KP_Right: - case GDK_KEY_Right: { + case GDK_KEY_Right:{ /* seek forward 10 seconds */ seekbar_add_delta (play, 10); break; } case GDK_KEY_KP_Left: - case GDK_KEY_Left: { + case GDK_KEY_Left:{ /* seek backward 10 seconds */ seekbar_add_delta (play, -10); break; } case GDK_KEY_KP_Up: - case GDK_KEY_Up: { + case GDK_KEY_Up:{ /* seek forward 1 minute */ seekbar_add_delta (play, 60); break; } case GDK_KEY_KP_Down: - case GDK_KEY_Down: { + case GDK_KEY_Down:{ /* seek backward 1 minute */ seekbar_add_delta (play, -60); break; } case GDK_KEY_KP_Page_Up: - case GDK_KEY_Page_Up: { + case GDK_KEY_Page_Up:{ /* Seek forward 10 minutes */ seekbar_add_delta (play, 600); break; } case GDK_KEY_KP_Page_Down: - case GDK_KEY_Page_Down: { + case GDK_KEY_Page_Down:{ /* Seek backward 10 minutes */ seekbar_add_delta (play, -600); break; } - case GDK_KEY_bracketleft: { + case GDK_KEY_bracketleft:{ /* Decrease current playback speed by 10% */ gtk_play_set_rate (play, -0.1); break; } - case GDK_KEY_bracketright: { + case GDK_KEY_bracketright:{ /* Increase current playback speed by 10% */ gtk_play_set_rate (play, 0.1); break; break; } - case GDK_KEY_braceleft: { + case GDK_KEY_braceleft:{ /* Decrease current playback speed by 10% */ gtk_play_set_rate (play, -1.0); break; } - case GDK_KEY_braceright: { + case GDK_KEY_braceright:{ /* Increase current playback speed by 10% */ gtk_play_set_rate (play, 1.0); break; } - case GDK_KEY_BackSpace: { + case GDK_KEY_BackSpace:{ /* Reset playback speed to normal */ gdouble val = gst_player_get_rate (play->player); gtk_play_set_rate (play, 1.0 - val); break; } - case GDK_KEY_less: { + case GDK_KEY_less:{ /* Go backward in the playlist */ if (g_list_previous (play->current_uri)) gtk_button_clicked (GTK_BUTTON (play->prev_button)); break; } case GDK_KEY_Return: - case GDK_KEY_greater: { + case GDK_KEY_greater:{ /* Go forward in the playlist */ if (g_list_next (play->current_uri)) gtk_button_clicked (GTK_BUTTON (play->next_button)); break; } case GDK_KEY_KP_9: - case GDK_KEY_9: { + case GDK_KEY_9:{ /* Increase volume */ gdouble volume = gst_player_get_volume (play->player); gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), @@ -314,20 +314,20 @@ key_press_event_cb (GtkWidget * widget, GdkEventKey * event, gpointer data) break; } case GDK_KEY_KP_0: - case GDK_KEY_0: { + case GDK_KEY_0:{ /* Decrease volume */ gdouble volume = gst_player_get_volume (play->player); gtk_scale_button_set_value (GTK_SCALE_BUTTON (play->volume_button), volume * 0.9); break; } - case GDK_KEY_m: { + case GDK_KEY_m:{ /* Mute sound */ gboolean mute = gst_player_get_mute (play->player); gst_player_set_mute (play->player, !mute); break; } - case GDK_KEY_f: { + case GDK_KEY_f:{ /* Toggle fullscreen */ GtkToggleButton *fs = GTK_TOGGLE_BUTTON (play->fullscreen_button); gboolean active = !gtk_toggle_button_get_active (fs); @@ -779,7 +779,7 @@ media_info_dialog (GtkPlay * play, GstPlayerMediaInfo * media_info) return; play->media_info_dialog = - (GtkWidget *) gtk_builder_get_object (dialog_ui, "media_info_dialog"); + (GtkWidget *) gtk_builder_get_object (dialog_ui, "media_info_dialog"); gtk_window_set_transient_for (GTK_WINDOW (play->media_info_dialog), GTK_WINDOW (play)); @@ -796,7 +796,7 @@ media_info_dialog (GtkPlay * play, GstPlayerMediaInfo * media_info) g_signal_connect (view, "realize", G_CALLBACK (gtk_tree_view_expand_all), NULL); - + gtk_widget_set_size_request (play->media_info_dialog, 550, 450); gtk_widget_show_all (play->media_info_dialog); @@ -887,7 +887,8 @@ seekbar_value_changed_cb (GtkRange * range, GtkPlay * play) } G_MODULE_EXPORT void -volume_button_value_changed_cb (GtkScaleButton * button, gdouble value, GtkPlay * play) +volume_button_value_changed_cb (GtkScaleButton * button, gdouble value, + GtkPlay * play) { gst_player_set_volume (play->player, value); } @@ -1282,7 +1283,8 @@ mouse_button_pressed_cb (GtkWidget * unused, GdkEventButton * event, } static gboolean -video_area_leave_notify_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +video_area_leave_notify_cb (GtkWidget * widget, GdkEvent * event, + GtkPlay * play) { start_toolbar_hide_timer (play); @@ -1290,7 +1292,8 @@ video_area_leave_notify_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play } static gboolean -video_area_toolbar_show_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +video_area_toolbar_show_cb (GtkWidget * widget, GdkEvent * event, + GtkPlay * play) { toolbar_show (play); @@ -1300,7 +1303,8 @@ video_area_toolbar_show_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play } static gboolean -overlay_leave_notify_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +overlay_leave_notify_event_cb (GtkWidget * widget, GdkEvent * event, + GtkPlay * play) { start_toolbar_hide_timer (play); @@ -1308,7 +1312,8 @@ overlay_leave_notify_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * p } static gboolean -overlay_enter_notify_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) +overlay_enter_notify_event_cb (GtkWidget * widget, GdkEvent * event, + GtkPlay * play) { toolbar_show (play); @@ -1316,7 +1321,7 @@ overlay_enter_notify_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * p } static void -apply_css (GtkWidget *widget, GtkStyleProvider *provider) +apply_css (GtkWidget * widget, GtkStyleProvider * provider) { gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT); @@ -1329,7 +1334,7 @@ apply_css (GtkWidget *widget, GtkStyleProvider *provider) static void gtk_widget_apply_css (GtkWidget * widget, const gchar * filename) { - GBytes *bytes; + GBytes *bytes; gsize data_size; const guint8 *data; GError *err = NULL; @@ -1346,7 +1351,7 @@ gtk_widget_apply_css (GtkWidget * widget, const gchar * filename) } data = g_bytes_get_data (bytes, &data_size); gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (provider), - (gchar *)data, data_size, NULL); + (gchar *) data, data_size, NULL); g_bytes_unref (bytes); apply_css (widget, provider); @@ -1360,7 +1365,7 @@ get_child_position (GtkOverlay * overlay, GtkWidget * widget, GtkWidget *child; GtkAllocation main_alloc; gint x, y; - GtkWidget * relative = play->video_area; + GtkWidget *relative = play->video_area; child = gtk_bin_get_child (GTK_BIN (overlay)); gtk_widget_translate_coordinates (relative, child, 0, 0, &x, &y); @@ -1500,7 +1505,7 @@ create_ui (GtkPlay * play) /* check if we need to enable fullscreen */ if (play->fullscreen) gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); + (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); /* enable visualization (by default laybin uses goom) */ /* if visualization is enabled then use the first element */ @@ -1632,6 +1637,7 @@ gtk_play_get_cover_image (GstPlayerMediaInfo * media_info) return pixbuf; } + static void media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, GtkPlay * play) @@ -1644,15 +1650,16 @@ media_info_updated_cb (GstPlayer * player, GstPlayerMediaInfo * media_info, title = gst_player_media_info_get_title (media_info); if (!title) { - filename = g_filename_from_uri( - gst_player_media_info_get_uri (media_info), NULL, NULL); + filename = + g_filename_from_uri (gst_player_media_info_get_uri (media_info), NULL, + NULL); basename = g_path_get_basename (filename); } gtk_label_set_label (play->title_label, title ? title : basename); set_title (play, title ? title : filename); - g_free(basename); - g_free(filename); + g_free (basename); + g_free (filename); pixbuf = gtk_play_get_cover_image (media_info); -- cgit v1.2.3 From 6ed6b5892925c2b1b7aca5068964b8f8607b206e Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 12 Aug 2015 16:00:15 +0200 Subject: playback/player: player: Abstract the signal emission dispatching to a new interface This allows to implement signal dispatching to other event loop systems than GLib without having direct GLib support in the base GstPlayer class. A implementation for the GLib main context is provided and used in the applications and tests. --- playback/player/gst-play/gst-play.c | 10 +++++----- playback/player/gtk/gtk-play.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index f22e3f2..368b814 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -351,9 +351,10 @@ play_new (gchar ** uris, gdouble initial_volume) play->num_uris = g_strv_length (uris); play->cur_idx = -1; - play->player = gst_player_new (); + play->player = + gst_player_new_full (gst_player_g_main_context_signal_dispatcher_new + (NULL)); - g_object_set (play->player, "dispatch-to-main-context", TRUE, NULL); g_signal_connect (play->player, "position-updated", G_CALLBACK (position_updated_cb), play); g_signal_connect (play->player, "state-changed", @@ -447,9 +448,8 @@ play_next (GstPlay * play) if (play->repeat) { g_print ("Looping playlist \n"); play->cur_idx = -1; - } - else - return FALSE; + } else + return FALSE; } play_uri (play, play->uris[++play->cur_idx]); diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index b1ad7ac..c601f32 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1730,7 +1730,9 @@ gtk_play_constructor (GType type, guint n_construct_params, (GtkPlay *) G_OBJECT_CLASS (gtk_play_parent_class)->constructor (type, n_construct_params, construct_params); - self->player = gst_player_new (); + self->player = + gst_player_new_full (gst_player_g_main_context_signal_dispatcher_new + (NULL)); self->playing = TRUE; if (self->inhibit_cookie) @@ -1740,8 +1742,6 @@ gtk_play_constructor (GType type, guint n_construct_params, gtk_application_inhibit (GTK_APPLICATION (g_application_get_default ()), GTK_WINDOW (self), GTK_APPLICATION_INHIBIT_IDLE, "Playing media"); - g_object_set (self->player, "dispatch-to-main-context", TRUE, NULL); - create_ui (self); g_signal_connect (self->player, "position-updated", -- cgit v1.2.3 From a8f8d1b03250d22da22ec0ffa7b14fbe096e794f Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 14 Aug 2015 17:13:39 +0200 Subject: playback/player: player: Refactor video rendering API There's a GstPlayerVideoRenderer interface now, which defines how video rendering happens in GstPlayer. Included is an implementation for the GstVideoOverlay interface, and inside the GTK example application one for gtksink/gtkglsink. --- playback/player/gst-play/gst-play.c | 2 +- playback/player/gtk/Makefile.am | 4 +- playback/player/gtk/gtk-play.c | 44 ++++---- playback/player/gtk/gtk-video-renderer.c | 178 +++++++++++++++++++++++++++++++ playback/player/gtk/gtk-video-renderer.h | 49 +++++++++ 5 files changed, 249 insertions(+), 28 deletions(-) create mode 100644 playback/player/gtk/gtk-video-renderer.c create mode 100644 playback/player/gtk/gtk-video-renderer.h diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 368b814..8417669 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -352,7 +352,7 @@ play_new (gchar ** uris, gdouble initial_volume) play->cur_idx = -1; play->player = - gst_player_new_full (gst_player_g_main_context_signal_dispatcher_new + gst_player_new_full (NULL, gst_player_g_main_context_signal_dispatcher_new (NULL)); g_signal_connect (play->player, "position-updated", diff --git a/playback/player/gtk/Makefile.am b/playback/player/gtk/Makefile.am index f7e6d0f..8e2331a 100644 --- a/playback/player/gtk/Makefile.am +++ b/playback/player/gtk/Makefile.am @@ -26,11 +26,11 @@ gtk-play-resources.h: resources/gresources.xml \ BUILT_SOURCES: gtk-play-resources.c gtk-play-resources.h -gtk_play_SOURCES = gtk-play.c gtk-play-resources.c +gtk_play_SOURCES = gtk-play.c gtk-play-resources.c gtk-video-renderer.c LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) $(GMODULE_LIBS) AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) -noinst_HEADERS = gtk-play-resources.h +noinst_HEADERS = gtk-play-resources.h gtk-video-renderer.h diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index c601f32..906a672 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -39,6 +39,7 @@ #include #include +#include "gtk-video-renderer.h" #define APP_NAME "gtk-play" @@ -58,6 +59,7 @@ typedef struct GtkApplicationWindow parent; GstPlayer *player; + GstPlayerVideoRenderer *renderer; gchar *uri; GList *uris; @@ -182,7 +184,8 @@ video_area_realize_cb (GtkWidget * widget, GtkPlay * play) #elif defined (GDK_WINDOWING_X11) window_handle = GDK_WINDOW_XID (window); #endif - g_object_set (play->player, "window-handle", (gpointer) window_handle, NULL); + g_object_set (play->renderer, "window-handle", (gpointer) window_handle, + NULL); } static void @@ -1413,24 +1416,14 @@ create_ui (GtkPlay * play) gtk_application_add_window (GTK_APPLICATION (g_application_get_default ()), GTK_WINDOW (play)); - if ((gtk_sink = gst_element_factory_make ("gtkglsink", NULL))) { - GstElement *video_sink; - - g_object_get (gtk_sink, "widget", &play->video_area, NULL); - - video_sink = gst_element_factory_make ("glsinkbin", NULL); - g_object_set (video_sink, "sink", gtk_sink, NULL); - - playbin = gst_player_get_pipeline (play->player); - g_object_set (playbin, "video-sink", video_sink, NULL); - gst_object_unref (playbin); - } else if ((gtk_sink = gst_element_factory_make ("gtksink", NULL))) { - g_object_get (gtk_sink, "widget", &play->video_area, NULL); - - playbin = gst_player_get_pipeline (play->player); - g_object_set (playbin, "video-sink", gtk_sink, NULL); - gst_object_unref (playbin); + play->renderer = gst_player_gtk_video_renderer_new (); + if (play->renderer) { + play->video_area = + gst_player_gtk_video_renderer_get_widget (GST_PLAYER_GTK_VIDEO_RENDERER + (play->renderer)); } else { + play->renderer = gst_player_video_overlay_video_renderer_new (NULL); + play->video_area = gtk_drawing_area_new (); g_signal_connect (play->video_area, "realize", G_CALLBACK (video_area_realize_cb), play); @@ -1506,10 +1499,6 @@ create_ui (GtkPlay * play) if (play->fullscreen) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (play->fullscreen_button), TRUE); - - /* enable visualization (by default laybin uses goom) */ - /* if visualization is enabled then use the first element */ - gst_player_set_visualization_enabled (play->player, TRUE); } static void @@ -1730,9 +1719,6 @@ gtk_play_constructor (GType type, guint n_construct_params, (GtkPlay *) G_OBJECT_CLASS (gtk_play_parent_class)->constructor (type, n_construct_params, construct_params); - self->player = - gst_player_new_full (gst_player_g_main_context_signal_dispatcher_new - (NULL)); self->playing = TRUE; if (self->inhibit_cookie) @@ -1744,6 +1730,10 @@ gtk_play_constructor (GType type, guint n_construct_params, create_ui (self); + self->player = + gst_player_new_full (self->renderer, + gst_player_g_main_context_signal_dispatcher_new (NULL)); + g_signal_connect (self->player, "position-updated", G_CALLBACK (position_updated_cb), self); g_signal_connect (self->player, "duration-changed", @@ -1754,6 +1744,10 @@ gtk_play_constructor (GType type, guint n_construct_params, g_signal_connect (self->player, "volume-changed", G_CALLBACK (player_volume_changed_cb), self); + /* enable visualization (by default playbin uses goom) */ + /* if visualization is enabled then use the first element */ + gst_player_set_visualization_enabled (self->player, TRUE); + g_signal_connect (G_OBJECT (self), "show", G_CALLBACK (show_cb), NULL); return G_OBJECT (self); diff --git a/playback/player/gtk/gtk-video-renderer.c b/playback/player/gtk/gtk-video-renderer.c new file mode 100644 index 0000000..6ff568e --- /dev/null +++ b/playback/player/gtk/gtk-video-renderer.c @@ -0,0 +1,178 @@ +/* GStreamer + * + * Copyright (C) 2015 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gtk-video-renderer.h" + +struct _GstPlayerGtkVideoRenderer +{ + GObject parent; + + GstElement *sink; + GtkWidget *widget; +}; + +struct _GstPlayerGtkVideoRendererClass +{ + GObjectClass parent_class; +}; + +static void + gst_player_gtk_video_renderer_interface_init + (GstPlayerVideoRendererInterface * iface); + +enum +{ + GTK_VIDEO_RENDERER_PROP_0, + GTK_VIDEO_RENDERER_PROP_WIDGET, + GTK_VIDEO_RENDERER_PROP_LAST +}; + +G_DEFINE_TYPE_WITH_CODE (GstPlayerGtkVideoRenderer, + gst_player_gtk_video_renderer, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_VIDEO_RENDERER, + gst_player_gtk_video_renderer_interface_init)); + +static GParamSpec + * gtk_video_renderer_param_specs[GTK_VIDEO_RENDERER_PROP_LAST] = { NULL, }; + +static void +gst_player_gtk_video_renderer_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (object); + + switch (prop_id) { + case GTK_VIDEO_RENDERER_PROP_WIDGET: + g_value_set_object (value, self->widget); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_player_gtk_video_renderer_finalize (GObject * object) +{ + GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (object); + + if (self->sink) + gst_object_unref (self->sink); + if (self->widget) + g_object_unref (self->widget); + + G_OBJECT_CLASS + (gst_player_gtk_video_renderer_parent_class)->finalize (object); +} + +static void + gst_player_gtk_video_renderer_class_init + (GstPlayerGtkVideoRendererClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_player_gtk_video_renderer_get_property; + gobject_class->finalize = gst_player_gtk_video_renderer_finalize; + + gtk_video_renderer_param_specs + [GTK_VIDEO_RENDERER_PROP_WIDGET] = + g_param_spec_object ("widget", "Widget", + "Widget to render the video into", GTK_TYPE_WIDGET, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, + GTK_VIDEO_RENDERER_PROP_LAST, gtk_video_renderer_param_specs); +} + +static void +gst_player_gtk_video_renderer_init (GstPlayerGtkVideoRenderer * self) +{ + GstElement *gtk_sink = gst_element_factory_make ("gtkglsink", NULL); + + if (gtk_sink) { + GstElement *sink = sink = gst_element_factory_make ("glsinkbin", NULL); + g_object_set (sink, "sink", gtk_sink, NULL); + + self->sink = sink; + } else { + gtk_sink = gst_element_factory_make ("gtksink", NULL); + + self->sink = gtk_sink; + } + + g_assert (self->sink != NULL); + + g_object_get (gtk_sink, "widget", &self->widget, NULL); +} + +static GstElement *gst_player_gtk_video_renderer_create_video_sink + (GstPlayerVideoRenderer * iface, GstPlayer * player) +{ + GstElement *gtk; + GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (iface); + + return gst_object_ref (self->sink); +} + +static void + gst_player_gtk_video_renderer_interface_init + (GstPlayerVideoRendererInterface * iface) +{ + iface->create_video_sink = gst_player_gtk_video_renderer_create_video_sink; +} + +/** + * gst_player_gtk_video_renderer_new: + * + * Returns: (transfer full): + */ +GstPlayerVideoRenderer * +gst_player_gtk_video_renderer_new (void) +{ + GstElementFactory *factory; + + factory = gst_element_factory_find ("gtkglsink"); + if (!factory) + factory = gst_element_factory_find ("gtksink"); + if (!factory) + return NULL; + + gst_object_unref (factory); + + return g_object_new (GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, NULL); +} + +/** + * gst_player_gtk_video_renderer_get_widget: + * @self: #GstPlayerVideoRenderer instance + * + * Returns: (transfer full): The GtkWidget + */ +GtkWidget *gst_player_gtk_video_renderer_get_widget + (GstPlayerGtkVideoRenderer * self) +{ + GtkWidget *widget; + + g_return_if_fail (GST_IS_PLAYER_GTK_VIDEO_RENDERER (self)); + + g_object_get (self, "widget", &widget, NULL); + + return widget; +} diff --git a/playback/player/gtk/gtk-video-renderer.h b/playback/player/gtk/gtk-video-renderer.h new file mode 100644 index 0000000..482b609 --- /dev/null +++ b/playback/player/gtk/gtk-video-renderer.h @@ -0,0 +1,49 @@ +/* GStreamer + * + * Copyright (C) 2015 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GTK_VIDEO_RENDERER_H__ +#define __GTK_VIDEO_RENDERER_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstPlayerGtkVideoRenderer + GstPlayerGtkVideoRenderer; +typedef struct _GstPlayerGtkVideoRendererClass + GstPlayerGtkVideoRendererClass; + +#define GST_TYPE_PLAYER_GTK_VIDEO_RENDERER (gst_player_gtk_video_renderer_get_type ()) +#define GST_IS_PLAYER_GTK_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER)) +#define GST_IS_PLAYER_GTK_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER)) +#define GST_PLAYER_GTK_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, GstPlayerGtkVideoRendererClass)) +#define GST_PLAYER_GTK_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, GstPlayerGtkVideoRenderer)) +#define GST_PLAYER_GTK_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_GTK_VIDEO_RENDERER, GstPlayerGtkVideoRendererClass)) +#define GST_PLAYER_GTK_VIDEO_RENDERER_CAST(obj) ((GstPlayerGtkVideoRenderer*)(obj)) + +GType gst_player_gtk_video_renderer_get_type (void); + +GstPlayerVideoRenderer * gst_player_gtk_video_renderer_new (void); +GtkWidget * gst_player_gtk_video_renderer_get_widget (GstPlayerGtkVideoRenderer * self); + +G_END_DECLS + +#endif /* __GTK_VIDEO_RENDERER_H__ */ -- cgit v1.2.3 From 2da236d871b467067176fe1b9e3c2eedef9e6e70 Mon Sep 17 00:00:00 2001 From: trungdoan Date: Tue, 18 Aug 2015 16:34:19 +0700 Subject: playback/player: iOS: Fix build issue Fix build issue on iOS by adding additional files in lib/gst/player to the iOS project. --- playback/player/ios/GstPlay.xcodeproj/project.pbxproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj index ee94d2d..9a3e45c 100644 --- a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj +++ b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ AD2B8861198D65780070367B /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B885E198D65780070367B /* LibraryViewController.m */; }; AD2B8862198D65780070367B /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B8860198D65780070367B /* VideoViewController.m */; }; AD2B886C198D69ED0070367B /* gstplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = AD2B886A198D69ED0070367B /* gstplayer.c */; }; + E95DEC9B1B8332F100CC3512 /* gstplayer-media-info.c in Sources */ = {isa = PBXBuildFile; fileRef = E95DEC981B8332F100CC3512 /* gstplayer-media-info.c */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -54,6 +55,10 @@ AD2B8860198D65780070367B /* VideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; }; AD2B886A198D69ED0070367B /* gstplayer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gstplayer.c; sourceTree = ""; }; AD2B886B198D69ED0070367B /* gstplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gstplayer.h; sourceTree = ""; }; + E95DEC971B8332F100CC3512 /* gstplayer-media-info-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gstplayer-media-info-private.h"; sourceTree = ""; }; + E95DEC981B8332F100CC3512 /* gstplayer-media-info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "gstplayer-media-info.c"; sourceTree = ""; }; + E95DEC991B8332F100CC3512 /* gstplayer-media-info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gstplayer-media-info.h"; sourceTree = ""; }; + E95DEC9A1B8332F100CC3512 /* player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = player.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -147,6 +152,10 @@ AD2B8869198D69ED0070367B /* player */ = { isa = PBXGroup; children = ( + E95DEC971B8332F100CC3512 /* gstplayer-media-info-private.h */, + E95DEC981B8332F100CC3512 /* gstplayer-media-info.c */, + E95DEC991B8332F100CC3512 /* gstplayer-media-info.h */, + E95DEC9A1B8332F100CC3512 /* player.h */, AD2B886A198D69ED0070367B /* gstplayer.c */, AD2B886B198D69ED0070367B /* gstplayer.h */, ); @@ -220,6 +229,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E95DEC9B1B8332F100CC3512 /* gstplayer-media-info.c in Sources */, AD2B8861198D65780070367B /* LibraryViewController.m in Sources */, AD2B8831198D631B0070367B /* AppDelegate.m in Sources */, AD2B8862198D65780070367B /* VideoViewController.m in Sources */, -- cgit v1.2.3 From 80e4c1abff1847378a99fb295a4585aa597de921 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 18 Aug 2015 13:17:57 +0300 Subject: playback/player: ios: Fix video rendering after GstPlayerVideoRenderer refactoring --- playback/player/ios/GstPlay/VideoViewController.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index dcf06b2..0516764 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -63,8 +63,7 @@ media_width = 320; media_height = 240; - player = gst_player_new(); - g_object_set (player, "window-handle", video_view, NULL); + player = gst_player_new_full (gst_player_video_overlay_video_renderer_new (video_view), NULL); g_object_set (player, "uri", [uri UTF8String], NULL); gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE); -- cgit v1.2.3 From c58123346442f503dee0ca61d5542e138ea7c80a Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 18 Aug 2015 13:20:15 +0300 Subject: playback/player: android: Fix video rendering after GstPlayerVideoRenderer refactoring --- playback/player/android/app/src/main/jni/player.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/playback/player/android/app/src/main/jni/player.c b/playback/player/android/app/src/main/jni/player.c index 882c230..133d970 100644 --- a/playback/player/android/app/src/main/jni/player.c +++ b/playback/player/android/app/src/main/jni/player.c @@ -37,6 +37,7 @@ typedef struct _Player { jobject java_player; GstPlayer *player; + GstPlayerVideoRenderer *renderer; ANativeWindow *native_window; } Player; @@ -197,7 +198,8 @@ native_new (JNIEnv * env, jobject thiz) { Player *player = g_new0 (Player, 1); - player->player = gst_player_new (); + player->renderer = gst_player_video_overlay_video_renderer_new (NULL); + player->player = gst_player_new_full (player->renderer, NULL); SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); player->java_player = (*env)->NewGlobalRef (env, thiz); @@ -402,8 +404,9 @@ native_set_surface (JNIEnv * env, jobject thiz, jobject surface) } player->native_window = new_native_window; - g_object_set (player->player, "window-handle", (gpointer) new_native_window, - NULL); + gst_player_video_overlay_video_renderer_set_window_handle + (GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (player->renderer), + (gpointer) new_native_window); } static void -- cgit v1.2.3 From e2581982a6629066c53985ad7f42b45a044de640 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 20 Aug 2015 10:50:30 +0300 Subject: playback/player: gst-play: Fix leak of GError and GOptionContext on parsing errors --- playback/player/gst-play/gst-play.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 8417669..e00a7fc 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -674,6 +674,8 @@ main (int argc, char **argv) g_option_context_add_group (ctx, gst_init_get_option_group ()); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_print ("Error initializing: %s\n", GST_STR_NULL (err->message)); + g_clear_error (&err); + g_option_context_free (ctx); return 1; } g_option_context_free (ctx); -- cgit v1.2.3 From 50099a3aa19c1bb26455e1d9b4d9c7e879990ea2 Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Wed, 26 Aug 2015 18:57:13 +0900 Subject: playback/player: gst-play: Check if the stream list is empty in print_all_stream_info before using it --- playback/player/gst-play/gst-play.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index e00a7fc..6fa304e 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -195,9 +195,12 @@ static void print_all_stream_info (GstPlayerMediaInfo * media_info) { guint count = 0; - GList *l, *list; + GList *list, *l; list = gst_player_media_info_get_stream_list (media_info); + if (!list) + return; + g_print ("URI : %s\n", gst_player_media_info_get_uri (media_info)); g_print ("Duration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (gst_player_media_info_get_duration (media_info))); -- cgit v1.2.3 From 371f4ec378fd418bec95bc2d165508cd2490aa78 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 27 Aug 2015 10:53:43 +0300 Subject: playback/player: gst-play: Remove useless variable initializations They are set to something in the next line anyway. --- playback/player/gst-play/gst-play.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 6fa304e..ed7e1dd 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -236,7 +236,7 @@ print_all_stream_info (GstPlayerMediaInfo * media_info) static void print_all_video_stream (GstPlayerMediaInfo * media_info) { - GList *list = NULL, *l; + GList *list, *l; list = gst_player_get_video_streams (media_info); if (!list) @@ -255,7 +255,7 @@ print_all_video_stream (GstPlayerMediaInfo * media_info) static void print_all_subtitle_stream (GstPlayerMediaInfo * media_info) { - GList *list = NULL, *l; + GList *list, *l; list = gst_player_get_subtitle_streams (media_info); if (!list) @@ -274,7 +274,7 @@ print_all_subtitle_stream (GstPlayerMediaInfo * media_info) static void print_all_audio_stream (GstPlayerMediaInfo * media_info) { - GList *list = NULL, *l; + GList *list, *l; list = gst_player_get_audio_streams (media_info); if (!list) -- cgit v1.2.3 From 6e9e9228bd422d5656be7c2a22cdaba1863621ba Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Wed, 2 Sep 2015 00:53:46 +0800 Subject: playback/player: gtk-play: Remove unused variable --- playback/player/gtk/gtk-video-renderer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/playback/player/gtk/gtk-video-renderer.c b/playback/player/gtk/gtk-video-renderer.c index 6ff568e..01921b0 100644 --- a/playback/player/gtk/gtk-video-renderer.c +++ b/playback/player/gtk/gtk-video-renderer.c @@ -125,7 +125,6 @@ gst_player_gtk_video_renderer_init (GstPlayerGtkVideoRenderer * self) static GstElement *gst_player_gtk_video_renderer_create_video_sink (GstPlayerVideoRenderer * iface, GstPlayer * player) { - GstElement *gtk; GstPlayerGtkVideoRenderer *self = GST_PLAYER_GTK_VIDEO_RENDERER (iface); return gst_object_ref (self->sink); -- cgit v1.2.3 From 0caa80c26fbaf3569043600905b1fdfbbf8b956d Mon Sep 17 00:00:00 2001 From: Justin Kim Date: Thu, 3 Sep 2015 18:29:04 +0900 Subject: playback/player: ios: remove implicit conversion of UIView to c pointer --- playback/player/ios/GstPlay/VideoViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index 0516764..eda419c 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -63,7 +63,7 @@ media_width = 320; media_height = 240; - player = gst_player_new_full (gst_player_video_overlay_video_renderer_new (video_view), NULL); + player = gst_player_new_full (gst_player_video_overlay_video_renderer_new ((__bridge gpointer)(video_view)), NULL); g_object_set (player, "uri", [uri UTF8String], NULL); gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE); -- cgit v1.2.3 From b5c10865aa719333ce8c5b698ef9ceee3aeb68e0 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 4 Sep 2015 18:11:25 +0300 Subject: playback/player: gtk-play: Add compiler warning flags to the build and fix the warnings --- playback/player/gtk/Makefile.am | 2 +- playback/player/gtk/gtk-play.c | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/playback/player/gtk/Makefile.am b/playback/player/gtk/Makefile.am index 8e2331a..97ce95d 100644 --- a/playback/player/gtk/Makefile.am +++ b/playback/player/gtk/Makefile.am @@ -31,6 +31,6 @@ gtk_play_SOURCES = gtk-play.c gtk-play-resources.c gtk-video-renderer.c LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) $(GMODULE_LIBS) -AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) +AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) $(WARNING_CFLAGS) noinst_HEADERS = gtk-play-resources.h gtk-video-renderer.h diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 906a672..aa45229 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -52,6 +52,7 @@ typedef GtkApplication GtkPlayApp; typedef GtkApplicationClass GtkPlayAppClass; +GType gtk_play_app_get_type (void); G_DEFINE_TYPE (GtkPlayApp, gtk_play_app, GTK_TYPE_APPLICATION); typedef struct @@ -91,8 +92,20 @@ typedef struct typedef GtkApplicationWindowClass GtkPlayClass; +GType gtk_play_get_type (void); G_DEFINE_TYPE (GtkPlay, gtk_play, GTK_TYPE_APPLICATION_WINDOW); +void rewind_button_clicked_cb (GtkButton * button, GtkPlay * play); +void forward_button_clicked_cb (GtkButton * button, GtkPlay * play); +void play_pause_button_clicked_cb (GtkButton * button, GtkPlay * play); +void prev_button_clicked_cb (GtkButton * button, GtkPlay * play); +void next_button_clicked_cb (GtkButton * button, GtkPlay * play); +void media_info_dialog_button_clicked_cb (GtkButton * button, GtkPlay * play); +void fullscreen_button_toggled_cb (GtkToggleButton * widget, GtkPlay * play); +void seekbar_value_changed_cb (GtkRange * range, GtkPlay * play); +void volume_button_value_changed_cb (GtkScaleButton * button, gdouble value, + GtkPlay * play); + enum { PROP_0, @@ -1071,7 +1084,7 @@ create_visualization_menu (GtkPlay * play) sep = gtk_separator_menu_item_new (); item = gtk_radio_menu_item_new_with_label (group, "Disable"); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); - g_object_set_data (G_OBJECT (item), "name", "disable"); + g_object_set_data (G_OBJECT (item), "name", (gpointer) "disable"); if (cur_vis == NULL) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); g_signal_connect (G_OBJECT (item), "toggled", @@ -1400,7 +1413,6 @@ static void create_ui (GtkPlay * play) { GtkWidget *main_hbox; - GstElement *playbin, *gtk_sink; gtk_window_set_default_size (GTK_WINDOW (play), 640, 480); @@ -1488,8 +1500,7 @@ create_ui (GtkPlay * play) /* apply css on widgets */ gtk_widget_apply_css (play->toolbar, "/css/toolbar.css"); - if (!gtk_sink) - gtk_widget_realize (play->video_area); + gtk_widget_realize (play->video_area); gtk_widget_hide (play->video_area); /* start toolbar autohide timer */ @@ -1867,7 +1878,7 @@ gtk_play_app_class_init (GtkPlayAppClass * klass) application_class->command_line = gtk_play_app_command_line; } -GtkPlayApp * +static GtkPlayApp * gtk_play_app_new (void) { GtkPlayApp *self; -- cgit v1.2.3 From c454b2914e23fff31813a7d3163731d6c51d024b Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Tue, 15 Sep 2015 21:54:38 +0900 Subject: playback/player: gst-play: Check if the stream list is empty in print_all_stream_info Add a check condition if the stream list is empty before using it. --- playback/player/gst-play/gst-play.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index ed7e1dd..d0924bd 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -197,10 +197,6 @@ print_all_stream_info (GstPlayerMediaInfo * media_info) guint count = 0; GList *list, *l; - list = gst_player_media_info_get_stream_list (media_info); - if (!list) - return; - g_print ("URI : %s\n", gst_player_media_info_get_uri (media_info)); g_print ("Duration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (gst_player_media_info_get_duration (media_info))); @@ -210,6 +206,12 @@ print_all_stream_info (GstPlayerMediaInfo * media_info) print_one_tag, NULL); else g_print (" (nil) \n"); + + list = gst_player_media_info_get_stream_list (media_info); + if (!list) + return; + + g_print ("All Stream information\n"); for (l = list; l != NULL; l = l->next) { GstTagList *tags = NULL; GstPlayerStreamInfo *stream = (GstPlayerStreamInfo *) l->data; -- cgit v1.2.3 From 4dcc43b93562bb7ee7409060d9da972ddd1c598d Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Tue, 15 Sep 2015 22:00:03 +0900 Subject: playback/player: gtk-play: Modify switch statement in stream_info_get_string In stream_info_get_string function, buffer variable is used all switch case repeatedly. Also, return used in switch statement. So, I have modified that cases. --- playback/player/gtk/gtk-play.c | 44 ++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index aa45229..062fdd2 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -623,108 +623,98 @@ audio_channels_string (gint num) static gchar * stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) { + gchar *buffer = NULL; + switch (type) { case AUDIO_INFO_RATE: { - gchar *buffer; GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; buffer = g_strdup_printf ("%s%d", label ? "Sample rate : " : "", gst_player_audio_info_get_sample_rate (audio)); - return buffer; + break; } case AUDIO_INFO_LANGUAGE: { - gchar *buffer; GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; - if (!gst_player_audio_info_get_language (audio)) - return NULL; - buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", - gst_player_audio_info_get_language (audio)); - return buffer; + const gchar* lang = gst_player_audio_info_get_language (audio); + if (lang) + buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", lang); + break; } case AUDIO_INFO_CHANNELS: { - gchar *buffer; GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; buffer = g_strdup_printf ("%s%s", label ? "Channels : " : "", audio_channels_string (gst_player_audio_info_get_channels (audio))); - return buffer; + break; } case SUBTITLE_INFO_CODEC: case VIDEO_INFO_CODEC: case AUDIO_INFO_CODEC: { - gchar *buffer; buffer = g_strdup_printf ("%s%s", label ? "Codec : " : "", gst_player_stream_info_get_codec (stream)); - return buffer; + break; } case AUDIO_INFO_MAX_BITRATE: { - gchar *buffer = NULL; GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; gint bitrate = gst_player_audio_info_get_max_bitrate (audio); if (bitrate > 0) buffer = g_strdup_printf ("%s%d", label ? "Max bitrate : " : "", bitrate); - return buffer; + break; } case VIDEO_INFO_MAX_BITRATE: { - gchar *buffer = NULL; GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gint bitrate = gst_player_video_info_get_max_bitrate (video); if (bitrate > 0) buffer = g_strdup_printf ("%s%d", label ? "Max bitrate : " : "", bitrate); - return buffer; + break; } case VIDEO_INFO_PAR: { guint par_d, par_n; - gchar *buffer; GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gst_player_video_info_get_pixel_aspect_ratio (video, &par_n, &par_d); buffer = g_strdup_printf ("%s%u:%u", label ? "pixel-aspect-ratio : " : "", par_n, par_d); - return buffer; + break; } case VIDEO_INFO_FPS: { gint fps_d, fps_n; - gchar *buffer; GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; gst_player_video_info_get_framerate (video, &fps_n, &fps_d); buffer = g_strdup_printf ("%s%.2f", label ? "Framerate : " : "", (gdouble) fps_n / fps_d); - return buffer; + break; } case VIDEO_INFO_RESOLUTION: { - gchar *buffer; GstPlayerVideoInfo *video = (GstPlayerVideoInfo *) stream; buffer = g_strdup_printf ("%s%dx%d", label ? "Resolution : " : "", gst_player_video_info_get_width (video), gst_player_video_info_get_height (video)); - return buffer; + break; } case SUBTITLE_INFO_LANGUAGE: { - gchar *buffer; GstPlayerSubtitleInfo *sub = (GstPlayerSubtitleInfo *) stream; buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", gst_player_subtitle_info_get_language (sub)); - return buffer; + break; } default: - { - return NULL; - } + break; } + return buffer; } static void -- cgit v1.2.3 From 5903c7cd5ef7de077d084fa3c525371b6a0f776d Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Thu, 17 Sep 2015 22:24:44 +0900 Subject: playback/player: gtk-play: change to use valid macro function --- playback/player/gtk/gtk-video-renderer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-video-renderer.c b/playback/player/gtk/gtk-video-renderer.c index 01921b0..b784f4a 100644 --- a/playback/player/gtk/gtk-video-renderer.c +++ b/playback/player/gtk/gtk-video-renderer.c @@ -169,7 +169,7 @@ GtkWidget *gst_player_gtk_video_renderer_get_widget { GtkWidget *widget; - g_return_if_fail (GST_IS_PLAYER_GTK_VIDEO_RENDERER (self)); + g_return_val_if_fail (GST_IS_PLAYER_GTK_VIDEO_RENDERER (self), NULL); g_object_get (self, "widget", &widget, NULL); -- cgit v1.2.3 From 15d62dcfe6da2a3a845a122410a248ab5fea3a5c Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 21 Sep 2015 14:20:24 +0200 Subject: playback/player: gtk-play: Run gst-indent --- playback/player/gtk/gtk-play.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 062fdd2..6815b3d 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -636,7 +636,7 @@ stream_info_get_string (GstPlayerStreamInfo * stream, gint type, gboolean label) case AUDIO_INFO_LANGUAGE: { GstPlayerAudioInfo *audio = (GstPlayerAudioInfo *) stream; - const gchar* lang = gst_player_audio_info_get_language (audio); + const gchar *lang = gst_player_audio_info_get_language (audio); if (lang) buffer = g_strdup_printf ("%s%s", label ? "Language : " : "", lang); break; -- cgit v1.2.3 From 09864feff459b28b2660995fce6f059dd63d5917 Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Sun, 4 Oct 2015 17:09:44 +0900 Subject: playback/player: gst-play: trivial cleanup --- playback/player/gst-play/gst-play.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index d0924bd..95b9d4f 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -548,15 +548,13 @@ restore_terminal (void) static void toggle_paused (GstPlay * play) { - if (play->desired_state == GST_STATE_PLAYING) + if (play->desired_state == GST_STATE_PLAYING) { play->desired_state = GST_STATE_PAUSED; - else + gst_player_pause (play->player); + } else { play->desired_state = GST_STATE_PLAYING; - - if (play->desired_state == GST_STATE_PLAYING) gst_player_play (play->player); - else - gst_player_pause (play->player); + } } static void @@ -568,20 +566,15 @@ relative_seek (GstPlay * play, gdouble percent) g_object_get (play->player, "position", &pos, "duration", &dur, NULL); - if (dur <= 0) - goto seek_failed; + if (dur <= 0) { + g_print ("\nCould not seek.\n"); + return; + } pos = pos + dur * percent; if (pos < 0) pos = 0; gst_player_seek (play->player, pos); - - return; - -seek_failed: - { - g_print ("\nCould not seek.\n"); - } } static void -- cgit v1.2.3 From 82b2c5361804a7599593f9cd24e4202d5b3c63ff Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Fri, 12 Jun 2015 01:47:56 +0800 Subject: playback/player: Add Qt bindings and player --- playback/player/qt/deployment.pri | 27 ++ playback/player/qt/fontawesome-webfont.ttf | Bin 0 -> 122092 bytes playback/player/qt/fontawesome-webfont.ttf.txt | 10 + playback/player/qt/fontawesome.js | 214 ++++++++++++ playback/player/qt/main.cpp | 52 +++ playback/player/qt/main.qml | 461 +++++++++++++++++++++++++ playback/player/qt/play.pro | 53 +++ playback/player/qt/player.cpp | 41 +++ playback/player/qt/player.h | 44 +++ playback/player/qt/qgstplayer.cpp | 435 +++++++++++++++++++++++ playback/player/qt/qgstplayer.h | 162 +++++++++ playback/player/qt/qml.qrc | 9 + playback/player/qt/quickrenderer.cpp | 56 +++ playback/player/qt/quickrenderer.h | 42 +++ 14 files changed, 1606 insertions(+) create mode 100644 playback/player/qt/deployment.pri create mode 100644 playback/player/qt/fontawesome-webfont.ttf create mode 100644 playback/player/qt/fontawesome-webfont.ttf.txt create mode 100644 playback/player/qt/fontawesome.js create mode 100644 playback/player/qt/main.cpp create mode 100644 playback/player/qt/main.qml create mode 100644 playback/player/qt/play.pro create mode 100644 playback/player/qt/player.cpp create mode 100644 playback/player/qt/player.h create mode 100644 playback/player/qt/qgstplayer.cpp create mode 100644 playback/player/qt/qgstplayer.h create mode 100644 playback/player/qt/qml.qrc create mode 100644 playback/player/qt/quickrenderer.cpp create mode 100644 playback/player/qt/quickrenderer.h diff --git a/playback/player/qt/deployment.pri b/playback/player/qt/deployment.pri new file mode 100644 index 0000000..5441b63 --- /dev/null +++ b/playback/player/qt/deployment.pri @@ -0,0 +1,27 @@ +android-no-sdk { + target.path = /data/user/qt + export(target.path) + INSTALLS += target +} else:android { + x86 { + target.path = /libs/x86 + } else: armeabi-v7a { + target.path = /libs/armeabi-v7a + } else { + target.path = /libs/armeabi + } + export(target.path) + INSTALLS += target +} else:unix { + isEmpty(target.path) { + qnx { + target.path = /tmp/$${TARGET}/bin + } else { + target.path = /opt/$${TARGET}/bin + } + export(target.path) + } + INSTALLS += target +} + +export(INSTALLS) diff --git a/playback/player/qt/fontawesome-webfont.ttf b/playback/player/qt/fontawesome-webfont.ttf new file mode 100644 index 0000000..ed9372f Binary files /dev/null and b/playback/player/qt/fontawesome-webfont.ttf differ diff --git a/playback/player/qt/fontawesome-webfont.ttf.txt b/playback/player/qt/fontawesome-webfont.ttf.txt new file mode 100644 index 0000000..946b3cb --- /dev/null +++ b/playback/player/qt/fontawesome-webfont.ttf.txt @@ -0,0 +1,10 @@ + +Font Awesome + +URL: http://fontawesome.io + +Font License + +License: SIL OFL 1.1 +URL: http://scripts.sil.org/OFL + diff --git a/playback/player/qt/fontawesome.js b/playback/player/qt/fontawesome.js new file mode 100644 index 0000000..8d135e1 --- /dev/null +++ b/playback/player/qt/fontawesome.js @@ -0,0 +1,214 @@ +var Icon = { + Glass : "\uf000", + Music : "\uf001", + Search : "\uf002", + Envelope : "\uf003", + Heart : "\uf004", + Star : "\uf005", + StarEmpty : "\uf006", + User : "\uf007", + Film : "\uf008", + ThLarge : "\uf009", + Th : "\uf00a", + ThList : "\uf00b", + Ok : "\uf00c", + Remove : "\uf00d", + ZoomIn : "\uf00e", + ZoomOut : "\uf010", + Off : "\uf011", + Signal : "\uf012", + Cog : "\uf013", + Trash : "\uf014", + Home : "\uf015", + File : "\uf016", + Time : "\uf017", + Road : "\uf018", + DownloadAlt : "\uf019", + Download : "\uf01a", + Upload : "\uf01b", + Inbox : "\uf01c", + PlayCircle : "\uf01d", + Repeat : "\uf01e", + Refresh : "\uf021", + ListAlt : "\uf022", + Lock : "\uf023", + Flag : "\uf024", + Headphones : "\uf025", + VolumeOff : "\uf026", + VolumeDown : "\uf027", + VolumeUp : "\uf028", + Qrcode : "\uf029", + Barcode : "\uf02a", + Tag : "\uf02b", + Tags : "\uf02c", + Book : "\uf02d", + Bookmark : "\uf02e", + Print : "\uf02f", + Camera : "\uf030", + Font : "\uf031", + Bold : "\uf032", + Italic : "\uf033", + TextHeight : "\uf034", + TextWidth : "\uf035", + AlignLeft : "\uf036", + AlignCenter : "\uf037", + AlignRight : "\uf038", + AlignJustify : "\uf039", + List : "\uf03a", + IndentLeft : "\uf03b", + IndentRight : "\uf03c", + FacetimeVideo : "\uf03d", + Picture : "\uf03e", + Pencil : "\uf040", + MapMarker : "\uf041", + Adjust : "\uf042", + Tint : "\uf043", + Edit : "\uf044", + Share : "\uf045", + Check : "\uf046", + Move : "\uf047", + StepBackward : "\uf048", + StepForward : "\uf049", + Backward : "\uf04a", + Play : "\uf04b", + Pause : "\uf04c", + Stop : "\uf04d", + Forward : "\uf04e", + FastForward : "\uf050", + StepForward : "\uf051", + Eject : "\uf052", + ChevronLeft : "\uf053", + ChevronRight : "\uf054", + PlusSign : "\uf055", + MinusSign : "\uf056", + RemoveSign : "\uf057", + OkSign : "\uf058", + QuestionSign : "\uf059", + InfoSign : "\uf05a", + Screenshot : "\uf05b", + RemoveCircle : "\uf05c", + OkCircle : "\uf05d", + BanCircle : "\uf05e", + ArrowLeft : "\uf060", + ArrowRight : "\uf061", + ArrowUp : "\uf062", + ArrowDown : "\uf063", + ShareAlt : "\uf064", + ResizeFull : "\uf065", + ResizeSmall : "\uf066", + Plus : "\uf067", + Minus : "\uf068", + Asterish : "\uf069", + ExclamationSign : "\uf06a", + Gift : "\uf06b", + Leave : "\uf06c", + Fire : "\uf06d", + EyeOpen : "\uf06e", + EyeClose : "\uf070", + WarningSign : "\uf071", + Plane : "\uf072", + Calendar : "\uf073", + Random : "\uf074", + Comment : "\uf075", + Magnet : "\uf076", + ChevronUp : "\uf077", + ChevronDown : "\uf078", + Retweet : "\uf079", + ShoppingCart : "\uf07a", + FolderClose : "\uf07b", + FolderOpen : "\uf07c", + ResizeVertical : "\uf07d", + ResizeHorizontal : "\uf07e", + BarChart : "\uf080", + TwitterSign : "\uf081", + FacebookSign : "\uf082", + CameraRetro : "\uf083", + Key : "\uf084", + Cogs : "\uf085", + Comments : "\uf086", + ThumbsUp : "\uf087", + ThumbsDown : "\uf088", + StarHalf : "\uf089", + HeartEmpty : "\uf08a", + Signout : "\uf08b", + LinkedinSign : "\uf08c", + Pushpin : "\uf08d", + ExternalLink : "\uf08e", + Signin : "\uf090", + Trophy : "\uf091", + GithubSign : "\uf092", + UploadAlt : "\uf093", + Lemon : "\uf094", + Phone : "\uf095", + CheckEmpty : "\uf096", + BookmarkEmpty : "\uf097", + PhoneSign : "\uf098", + Twitter : "\uf099", + Facebook : "\uf09a", + Github : "\uf09b", + Unlock : "\uf09c", + CreditCard : "\uf09d", + Rss : "\uf09e", + Hdd : "\uf0a0", + Bullhorn : "\uf0a1", + Bell : "\uf0a2", + Certificate : "\uf0a3", + HandRight : "\uf0a4", + HandLeft : "\uf0a5", + HandUp : "\uf0a6", + HandDown : "\uf0a7", + CircleArrowLeft : "\uf0a8", + CircleArrowRight : "\uf0a9", + CircleArrowUp : "\uf0aa", + CircleArrowDown : "\uf0ab", + Globe : "\uf0ac", + Wrench : "\uf0ad", + Tasks : "\uf0ae", + Filter : "\uf0b0", + Briefcase : "\uf0b1", + Fullscreen : "\uf0b2", + Group : "\uf0c0", + Link : "\uf0c1", + Cloud : "\uf0c2", + Beaker : "\uf0c3", + Cut : "\uf0c4", + Copy : "\uf0c5", + PaperClip : "\uf0c6", + Save : "\uf0c7", + SignBlank : "\uf0c8", + Reorder : "\uf0c9", + ListUl : "\uf0ca", + ListOl : "\uf0cb", + Strikethrough : "\uf0cc", + Underline : "\uf0cd", + Table : "\uf0ce", + Magic : "\uf0d0", + Truck : "\uf0d1", + Pinterest : "\uf0d2", + PinterestSign : "\uf0d3", + GooglePlusSign : "\uf0d4", + GooglePlus : "\uf0d5", + Money : "\uf0d6", + CaretDown : "\uf0d7", + CaretUp : "\uf0d8", + CaretLeft : "\uf0d9", + CaretRight : "\uf0da", + Columns : "\uf0db", + Sort : "\uf0dc", + SortDown : "\uf0dd", + SortUp : "\uf0de", + EnvelopeAlt : "\uf0e0", + Linkedin : "\uf0e1", + Undo : "\uf0e2", + Legal : "\uf0e3", + Dashboard : "\uf0e4", + CommentAlt : "\uf0e5", + CommentsAlt : "\uf0e6", + Bolt : "\uf0e7", + Sitemap : "\uf0e8", + Unbrella : "\uf0e9", + Paste : "\uf0ea", + ClosedCaptions : "\uf20a", + UserMd : "\uf200", +}; + diff --git a/playback/player/qt/main.cpp b/playback/player/qt/main.cpp new file mode 100644 index 0000000..5634732 --- /dev/null +++ b/playback/player/qt/main.cpp @@ -0,0 +1,52 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "player.h" + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType("Player", 1, 0, "Player"); + + /* the plugin must be loaded before loading the qml file to register the + * GstGLVideoItem qml item + * FIXME Add a QQmlExtensionPlugin into qmlglsink to register GstGLVideoItem + * with the QML engine, then remove this */ + gst_init(NULL,NULL); + GstElement *sink = gst_element_factory_make ("qmlglsink", NULL); + gst_object_unref(sink); + + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + QObject *rootObject = engine.rootObjects().first(); + + Player *player = rootObject->findChild("player"); + QQuickItem *videoItem = rootObject->findChild("videoItem"); + player->setVideoOutput(videoItem); + + + return app.exec(); +} diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml new file mode 100644 index 0000000..c7fe424 --- /dev/null +++ b/playback/player/qt/main.qml @@ -0,0 +1,461 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.1 +import Player 1.0 +import org.freedesktop.gstreamer.GLVideoItem 1.0 + +import "fontawesome.js" as FontAwesome + +ApplicationWindow { + id: window + visible: true + width: 640 + height: 480 + x: 30 + y: 30 + color: "black" +// title : player.mediaInfo.title + + Player { + id: player + objectName: "player" + volume: 0.5 + onStateChanged: { + if (state === Player.STOPPED) { + playbutton.text = FontAwesome.Icon.Play + } + } + onResolutionChanged: { + if (player.videoAvailable) { + window.width = resolution.width + window.height = resolution.height + } + } + } + + GstGLVideoItem { + id: video + objectName: "videoItem" + anchors.centerIn: parent + width: 640 + height: 480 + } + + FileDialog { + id: fileDialog + //nameFilters: [TODO globs from mime types] + onAccepted: player.source = fileUrl + } + + Action { + id: fileOpenAction + text: "Open" + onTriggered: fileDialog.open() + } + + menuBar: MenuBar { + Menu { + title: "&File" + MenuItem { action: fileOpenAction } + MenuItem { text: "Quit"; onTriggered: Qt.quit() } + } + } + + Item { + anchors.fill: parent + FontLoader { + source: "fonts/fontawesome-webfont.ttf" + } + + Rectangle { + id : playbar + color: Qt.rgba(1, 1, 1, 0.7) + border.width: 1 + border.color: "white" + anchors.bottom: parent.bottom + anchors.bottomMargin: 15 + anchors.horizontalCenter: parent.horizontalCenter + width : grid.width + 20 + height: 40//childrenRect.height + 20 + radius: 5 + + MouseArea { + id: mousearea + anchors.fill: parent + hoverEnabled: true + onEntered: { + parent.opacity = 1.0 + hidetimer.start() + } + } + + Timer { + id: hidetimer + interval: 10000 + onTriggered: { + parent.opacity = 0.0 + stop() + } + } + + Grid { + id: grid + anchors.horizontalCenter: parent.horizontalCenter +// anchors.top: parent.top +// anchors.topMargin: 5 + + spacing: 7 + rows: 1 + verticalItemAlignment: Qt.AlignVCenter + + Text { + id : openmedia + font.pointSize: 17 + font.family: "FontAwesome" + text: FontAwesome.Icon.FolderOpen + + MouseArea { + anchors.fill: parent + onPressed: fileDialog.open() + } + } + + Item { + width: 17 + height: 17 + + Text { + anchors.centerIn: parent + font.pointSize: 17 + font.family: "FontAwesome" + text: FontAwesome.Icon.StepBackward + } + } + + Item { + width: 25 + height: 25 + + Text { + anchors.centerIn: parent + id : playbutton + font.pointSize: 25 + font.family: "FontAwesome" + //font.weight: Font.Light + text: FontAwesome.Icon.PlayCircle + } + + MouseArea { + id: playArea + anchors.fill: parent + onPressed: { + if (player.state !== Player.PLAYING) { + player.play() + playbutton.text = FontAwesome.Icon.Pause + playbutton.font.pointSize = 17 + } else { + player.pause() + playbutton.text = FontAwesome.Icon.PlayCircle + playbutton.font.pointSize = 25 + } + } + } + } + + Item { + width: 17 + height: 17 + + Text { + anchors.centerIn: parent + font.pointSize: 17 + font.family: "FontAwesome" + text: FontAwesome.Icon.StepForward + } + } + + Item { + width: 40 + height: 17 + Text { + id: timelabel + anchors.centerIn: parent + font.pointSize: 13 + color: "black" + text: { + var current = new Date(Math.floor(slider.value / 1e6)); + current.getMinutes() + ":" + ('0'+current.getSeconds()).slice(-2) + } + } + } + + Item { + width: 200 + height: 38 + Text { + anchors.centerIn: parent + text: player.mediaInfo.title + font.pointSize: 15 + } + } + + + + Item { + width: 40 + height: 17 + Text { + id: durationlabel + anchors.centerIn: parent + font.pointSize: 13 + color: "black" + text: { + var duration = new Date(Math.floor(player.duration / 1e6)); + duration.getMinutes() + ":" + ('0'+duration.getSeconds()).slice(-2) + } + } + } + + Item { + width: 17 + height: 17 + + + Text { + id : volume + anchors.centerIn: parent + font.pointSize: 17 + font.family: "FontAwesome" + text: { + if (volumeslider.value > volumeslider.maximumValue / 2) { + FontAwesome.Icon.VolumeUp + } else if (volumeslider.value === 0) { + FontAwesome.Icon.VolumeOff + } else { + FontAwesome.Icon.VolumeDown + } + } + } + + Rectangle { + id : volumebar + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.top + //anchors.bottomMargin:3 + color: "lightgray" + width: 17 + height: 66 + visible: false + radius: 5 + + Slider { + id: volumeslider + value: player.volume + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.001 + anchors.centerIn: parent + orientation: Qt.Vertical + onPressedChanged: player.volume = value + + style: SliderStyle { + groove: Item { + implicitWidth: 47 + implicitHeight: 3 + anchors.centerIn: parent + + Rectangle { + antialiasing: true + height: parent.height + width: parent.width + color: "gray" + opacity: 0.8 + radius: 5 + + Rectangle { + antialiasing: true + height: parent.height + width: parent.width * control.value / control.maximumValue + color: "red" + radius: 5 + } + } + } + handle: Rectangle { + anchors.centerIn: parent + color: control.pressed ? "white" : "lightgray" + border.color: "gray" + border.width: 1 + implicitWidth: 11 + implicitHeight: 11 + radius: 90 + } + } + } + } + + MouseArea { + anchors.fill: parent + onPressed: { + volumebar.visible = !volumebar.visible + } + } + + MouseArea { + anchors.fill: volumebar + hoverEnabled: true + propagateComposedEvents: true + + onClicked: mouse.accepted = false; + onPressed: mouse.accepted = false; + onReleased: mouse.accepted = false; + onDoubleClicked: mouse.accepted = false; + onPositionChanged: mouse.accepted = false; + onPressAndHold: mouse.accepted = false; + + onExited: { + volumebar.visible = false + } + } + + } + + Text { + id: sub + font.pointSize: 17 + font.family: "FontAwesome" + text: FontAwesome.Icon.ClosedCaptions + } + + Text { + id : fullscreen + font.pointSize: 17 + font.family: "FontAwesome" + text: FontAwesome.Icon.ResizeFull + + MouseArea { + anchors.fill: parent + onClicked: { + if (window.visibility === Window.FullScreen) { + window.showNormal() + fullscreen.text = FontAwesome.Icon.ResizeFull + } else { + window.showFullScreen() + fullscreen.text = FontAwesome.Icon.ResizeSmall + } + } + } + } + } + + Item { + width: playbar.width + height: 5 + anchors.bottom: playbar.bottom + + Slider { + id: slider + maximumValue: player.duration + value: player.position + onPressedChanged: player.seek(value) + enabled: player.mediaInfo.isSeekable + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + + MouseArea { + id: sliderMouseArea + anchors.fill: parent + hoverEnabled: true + propagateComposedEvents: true + + onClicked: mouse.accepted = false; + onPressed: mouse.accepted = false; + onReleased: mouse.accepted = false; + onDoubleClicked: mouse.accepted = false; + onPositionChanged: mouse.accepted = false; + onPressAndHold: mouse.accepted = false; + } + + Rectangle { + id: hoveredcliptime + width: 40 + height: 17 + color: "lightgray" + anchors.verticalCenter: parent.verticalCenter + visible: sliderMouseArea.containsMouse + x: sliderMouseArea.mouseX + + Text { + font.pointSize: 13 + color: "black" + anchors.centerIn: parent + text: { + var value = (sliderMouseArea.mouseX - slider.x) * player.duration / (slider.width - slider.x) + var date = new Date(Math.floor(value / 1e6)); + date.getMinutes() + ":" + ('0' + date.getSeconds()).slice(-2) + } + } + } + + style: SliderStyle { + groove: Item { + implicitWidth: playbar.width + implicitHeight: 5 + + Rectangle { + height: parent.height + width: parent.width + anchors.verticalCenter: parent.verticalCenter + color: "gray" + opacity: 0.8 + + Rectangle { + antialiasing: true + color: "red" + height: parent.height + width: parent.width * control.value / control.maximumValue + } + + Rectangle { + antialiasing: true + color: "yellow" + height: parent.height + width: parent.width * player.buffering / 100 + } + } + } + handle: Rectangle { + anchors.centerIn: parent + color: control.pressed ? "white" : "lightgray" + implicitWidth: 4 + implicitHeight: 5 + } + } + } + } + + } + } +} diff --git a/playback/player/qt/play.pro b/playback/player/qt/play.pro new file mode 100644 index 0000000..c8b2954 --- /dev/null +++ b/playback/player/qt/play.pro @@ -0,0 +1,53 @@ +TEMPLATE = app + +QT += qml quick widgets + +CONFIG += c++11 + +DEFINES += GST_USE_UNSTABLE_API + +INCLUDEPATH += ../lib + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Default rules for deployment. +include(deployment.pri) + +# not tested (yet) +unix:!macx { +QT_CONFIG -= no-pkg-config +CONFIG += link_pkgconfig +PKGCONFIG = \ + gstreamer-1.0 \ + gstreamer-audio-1.0 \ + gstreamer-tag-1.0 \ + gstreamer-pbutils-1.0 \ + gstreamer-video-1.0 \ + gstreamer-gl-1.0 +} + +macx { + QMAKE_MAC_SDK = macosx10.9 + INCLUDEPATH += /Library/Frameworks/GStreamer.framework/Headers + + LIBS += \ + -framework AppKit \ + -F/Library/Frameworks -framework GStreamer +} + +HEADERS += \ + qgstplayer.h \ + player.h \ + quickrenderer.h + +SOURCES += main.cpp \ + qgstplayer.cpp \ + ../lib/gst/player/gstplayer.c \ + ../lib/gst/player/gstplayer-media-info.c \ + player.cpp \ + quickrenderer.cpp + +DISTFILES += diff --git a/playback/player/qt/player.cpp b/playback/player/qt/player.cpp new file mode 100644 index 0000000..ec4b78c --- /dev/null +++ b/playback/player/qt/player.cpp @@ -0,0 +1,41 @@ + +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "player.h" +#include "quickrenderer.h" + +Player::Player(QObject *parent) + : Player(parent, new QuickRenderer) +{ + +} + +Player::Player(QObject *parent, QuickRenderer *renderer) + : QGstPlayer(parent, renderer) + , renderer_(renderer) +{ + renderer_->setParent(this); +} + +void Player::setVideoOutput(QQuickItem *output) +{ + renderer_->setVideoItem(output); +} diff --git a/playback/player/qt/player.h b/playback/player/qt/player.h new file mode 100644 index 0000000..88586f4 --- /dev/null +++ b/playback/player/qt/player.h @@ -0,0 +1,44 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include +#include "qgstplayer.h" + +class QuickRenderer; + +class Player : public QGstPlayer +{ + Q_OBJECT +public: + Player(QObject *parent = 0); + void setVideoOutput(QQuickItem *output); + +private: + Player(QObject *parent, QuickRenderer *renderer); + QuickRenderer *renderer_; +}; + +Q_DECLARE_METATYPE(Player*) + +#endif // PLAYER_H diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp new file mode 100644 index 0000000..c2fb3fb --- /dev/null +++ b/playback/player/qt/qgstplayer.cpp @@ -0,0 +1,435 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "qgstplayer.h" +#include +#include + +#include + +class QGstPlayerRegisterMetaTypes +{ +public: + QGstPlayerRegisterMetaTypes() + { + qRegisterMetaType("State"); + } + +} _register; + +QGstPlayer::MediaInfo::MediaInfo(GstPlayerMediaInfo *media_info) + : mediaInfo_(media_info) +{ + +} + +QString QGstPlayer::MediaInfo::title() const +{ + QString title = QString::fromLocal8Bit + (gst_player_media_info_get_title(mediaInfo_)); + + // if media has no title, return the file name + if (title.isEmpty()) { + QUrl url(gst_player_media_info_get_uri(mediaInfo_)); + title = url.fileName(); + } + + return title; +} + +bool QGstPlayer::MediaInfo::isSeekable() const +{ + return gst_player_media_info_is_seekable(mediaInfo_); +} + +bool QGstPlayer::isVideoAvailable() const +{ + GstPlayerVideoInfo *video_info; + + video_info = gst_player_get_current_video_track (player_); + if (video_info) { + g_object_unref (video_info); + return true; + } + + return false; +} + +QQmlPropertyMap *QGstPlayer::mediaInfo() const +{ + return mediaInfoMap_; +} + +QGstPlayer::QGstPlayer(QObject *parent, QGstPlayer::VideoRenderer *renderer) + : QObject(parent) + , player_() + , state_(STOPPED) + , videoDimensions_(QSize()) + , mediaInfoMap_() + , videoAvailable_(false) +{ + + player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, 0); + + g_object_connect(player_, + "swapped-signal::state-changed", G_CALLBACK (QGstPlayer::onStateChanged), this, + "swapped-signal::position-updated", G_CALLBACK (QGstPlayer::onPositionUpdated), this, + "swapped-signal::duration-changed", G_CALLBACK (QGstPlayer::onDurationChanged), this, + "swapped-signal::buffering", G_CALLBACK (QGstPlayer::onBufferingChanged), this, + "swapped-signal::video-dimensions-changed", G_CALLBACK (QGstPlayer::onVideoDimensionsChanged), this, + "swapped-signal::volume-changed", G_CALLBACK (QGstPlayer::onVolumeChanged), this, + "swapped-signal::mute-changed", G_CALLBACK (QGstPlayer::onMuteChanged), this, + "swapped-signal::media-info-updated", G_CALLBACK (QGstPlayer::onMediaInfoUpdated), this, NULL); + + mediaInfoMap_ = new QQmlPropertyMap(this); +} + +void +QGstPlayer::onStateChanged(QGstPlayer * player, GstPlayerState state) +{ + player->state_ = static_cast(state); + + emit player->stateChanged(player->state_); +} + +void +QGstPlayer::onPositionUpdated(QGstPlayer * player, GstClockTime position) +{ + emit player->positionChanged(position); +} + +void +QGstPlayer::onDurationChanged(QGstPlayer * player, GstClockTime duration) +{ + emit player->durationChanged(duration); +} + +void +QGstPlayer::onBufferingChanged(QGstPlayer * player, int percent) +{ + emit player->bufferingChanged(percent); +} + +void +QGstPlayer::onVideoDimensionsChanged(QGstPlayer * player, int w, int h) +{ + QSize res(w,h); + + player->setResolution(res); + + emit player->resolutionChanged(res); +} + +void +QGstPlayer::onVolumeChanged(QGstPlayer *player) +{ + qreal new_val; + + new_val = gst_player_get_volume (player->player_); + + emit player->volumeChanged(new_val); +} + +void +QGstPlayer::onMuteChanged(QGstPlayer *player) +{ + bool new_val; + + new_val = gst_player_get_mute (player->player_); + + emit player->mutedChanged(new_val); +} + +void +QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_info) +{ + MediaInfo mediaInfo(media_info); + + player->mediaInfoMap_->insert(QLatin1String("title"), + QVariant(mediaInfo.title())); + player->mediaInfoMap_->insert(QLatin1String("isSeekable"), + QVariant(mediaInfo.isSeekable())); + + bool val = player->isVideoAvailable(); + + if (player->videoAvailable_ != val) { + player->videoAvailable_ = val; + emit player->videoAvailableChanged(val); + } + + emit player->mediaInfoChanged(); +} + +QUrl QGstPlayer::source() const +{ + Q_ASSERT(player_ != 0); + QString url = QString::fromLocal8Bit(gst_player_get_uri(player_)); + + return QUrl(url); +} + +qint64 QGstPlayer::duration() const +{ + Q_ASSERT(player_ != 0); + + return gst_player_get_duration(player_); +} + +qint64 QGstPlayer::position() const +{ + Q_ASSERT(player_ != 0); + + return gst_player_get_position(player_); +} + +qreal QGstPlayer::volume() const +{ + Q_ASSERT(player_ != 0); + + return gst_player_get_volume(player_); +} + +bool QGstPlayer::isMuted() const +{ + Q_ASSERT(player_ != 0); + + return gst_player_get_mute(player_); +} + +int QGstPlayer::buffering() const +{ + return 0; +} + +QSize QGstPlayer::resolution() const +{ + return videoDimensions_; +} + +void QGstPlayer::setResolution(QSize size) +{ + videoDimensions_ = size; +} + +QGstPlayer::State QGstPlayer::state() const +{ + return state_; +} + +GstElement *QGstPlayer::pipeline() const +{ + Q_ASSERT(player_ != 0); + + return gst_player_get_pipeline(player_); +} + +void QGstPlayer::play() +{ + Q_ASSERT(player_ != 0); + + gst_player_play(player_); +} + +void QGstPlayer::pause() +{ + Q_ASSERT(player_ != 0); + + gst_player_pause(player_); +} + +void QGstPlayer::stop() +{ + Q_ASSERT(player_ != 0); + + gst_player_stop(player_); +} + +void QGstPlayer::seek(qint64 position) +{ + Q_ASSERT(player_ != 0); + + gst_player_seek(player_, position); +} + +void QGstPlayer::setSource(QUrl const& url) +{ + Q_ASSERT(player_ != 0); + QByteArray uri = url.toString().toLocal8Bit(); + + gst_player_set_uri(player_, uri.data()); + + emit sourceChanged(url); +} + +void QGstPlayer::setVolume(qreal val) +{ + Q_ASSERT(player_ != 0); + + gst_player_set_volume(player_, val); +} + +void QGstPlayer::setMuted(bool val) +{ + Q_ASSERT(player_ != 0); + + gst_player_set_mute(player_, val); +} + +void QGstPlayer::setPosition(qint64 pos) +{ + Q_ASSERT(player_ != 0); + + gst_player_seek(player_, pos); +} + +GstPlayerVideoRenderer *QGstPlayer::VideoRenderer::renderer() +{ + return renderer_; +} + +QGstPlayer::VideoRenderer::VideoRenderer() +{ + renderer_ = static_cast + (g_object_new (GST_TYPE_PLAYER_QT_VIDEO_RENDERER, "renderer", this, NULL)); +} + +QGstPlayer::VideoRenderer::~VideoRenderer() +{ + if (renderer_) gst_object_unref(renderer_); +} + +struct _GstPlayerQtVideoRenderer +{ + GObject parent; + + gpointer renderer; +}; + +struct _GstPlayerQtVideoRendererClass +{ + GObjectClass parent_class; +}; + +static void +gst_player_qt_video_renderer_interface_init + (GstPlayerVideoRendererInterface * iface); + +G_DEFINE_TYPE_WITH_CODE (GstPlayerQtVideoRenderer, + gst_player_qt_video_renderer, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_VIDEO_RENDERER, + gst_player_qt_video_renderer_interface_init)) + +enum +{ + QT_VIDEO_RENDERER_PROP_0, + QT_VIDEO_RENDERER_PROP_RENDERER, + QT_VIDEO_RENDERER_PROP_LAST +}; + +static GParamSpec * qt_video_renderer_param_specs + [QT_VIDEO_RENDERER_PROP_LAST] = { NULL, }; + +static void +gst_player_qt_video_renderer_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object); + + switch (prop_id) { + case QT_VIDEO_RENDERER_PROP_RENDERER: + qDebug() << "setting renderer"; + self->renderer = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_player_qt_video_renderer_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object); + + switch (prop_id) { + case QT_VIDEO_RENDERER_PROP_RENDERER: + g_value_set_pointer (value, self->renderer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_player_qt_video_renderer_finalize (GObject * object) +{ + GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object); + + G_OBJECT_CLASS + (gst_player_qt_video_renderer_parent_class)->finalize(object); +} + +static void +gst_player_qt_video_renderer_class_init + (GstPlayerQtVideoRendererClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = + gst_player_qt_video_renderer_set_property; + gobject_class->get_property = + gst_player_qt_video_renderer_get_property; + gobject_class->finalize = gst_player_qt_video_renderer_finalize; + + qt_video_renderer_param_specs + [QT_VIDEO_RENDERER_PROP_RENDERER] = + g_param_spec_pointer ("renderer", "Qt Renderer", "", + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (gobject_class, + QT_VIDEO_RENDERER_PROP_LAST, + qt_video_renderer_param_specs); +} + +static void +gst_player_qt_video_renderer_init (GstPlayerQtVideoRenderer * self) +{ + +} + +static GstElement * +gst_player_qt_video_renderer_create_video_sink + (GstPlayerVideoRenderer * iface, GstPlayer *player) +{ + GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (iface); + + g_assert(self->renderer != NULL); + + return static_cast(self->renderer)->createVideoSink(); +} + +static void +gst_player_qt_video_renderer_interface_init + (GstPlayerVideoRendererInterface * iface) +{ + iface->create_video_sink = gst_player_qt_video_renderer_create_video_sink; +} diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h new file mode 100644 index 0000000..aeb45a5 --- /dev/null +++ b/playback/player/qt/qgstplayer.h @@ -0,0 +1,162 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef QGSTPLAYER_H +#define QGSTPLAYER_H + +#include +#include +#include +//#include +#include +#include + +class QGstPlayer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(qint64 position READ position NOTIFY positionChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int buffering READ buffering NOTIFY bufferingChanged) + Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged) + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged) + Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) + + Q_ENUMS(State) + +public: + + class VideoRenderer; + + explicit QGstPlayer(QObject *parent = 0, VideoRenderer *renderer = 0); + + typedef GstPlayerError Error; + enum State { + STOPPED = GST_PLAYER_STATE_STOPPED, + BUFFERING = GST_PLAYER_STATE_BUFFERING, + PAUSED = GST_PLAYER_STATE_PAUSED, + PLAYING = GST_PLAYER_STATE_PLAYING + }; + + class VideoRenderer + { + public: + GstPlayerVideoRenderer *renderer(); + virtual GstElement *createVideoSink() = 0; + protected: + VideoRenderer(); + virtual ~VideoRenderer(); + private: + GstPlayerVideoRenderer *renderer_; + }; + + // TODO add remaining bits + class MediaInfo + { + public: + MediaInfo(GstPlayerMediaInfo *media_info); + QString title() const; + bool isSeekable() const; + private: + GstPlayerMediaInfo *mediaInfo_; + }; + + QUrl source() const; + qint64 duration() const; + qint64 position() const; + qreal volume() const; + bool isMuted() const; + int buffering() const; + State state() const; + GstElement *pipeline() const; + QSize resolution() const; + void setResolution(QSize size); + bool isVideoAvailable() const; + QQmlPropertyMap *mediaInfo() const; + + +signals: + void stateChanged(State new_state); + void bufferingChanged(int percent); + void enfOfStream(); + void positionChanged(qint64 new_position); + void durationChanged(qint64 duration); + void resolutionChanged(QSize resolution); + void volumeChanged(qreal volume); + void mutedChanged(bool muted); + void mediaInfoChanged(); + void sourceChanged(QUrl new_url); + void videoAvailableChanged(bool videoAvailable); + +public slots: + void play(); + void pause(); + void stop(); + void seek(qint64 position); + void setSource(QUrl const& url); + void setVolume(qreal val); + void setMuted(bool val); + void setPosition(qint64 pos); + +private: + Q_DISABLE_COPY(QGstPlayer) + static void onStateChanged(QGstPlayer *, GstPlayerState state); + static void onPositionUpdated(QGstPlayer *, GstClockTime position); + static void onDurationChanged(QGstPlayer *, GstClockTime duration); + static void onBufferingChanged(QGstPlayer *, int percent); + static void onVideoDimensionsChanged(QGstPlayer *, int w, int h); + static void onVolumeChanged(QGstPlayer *); + static void onMuteChanged(QGstPlayer *); + static void onMediaInfoUpdated(QGstPlayer *, GstPlayerMediaInfo *media_info); + + GstPlayer *player_; + State state_; + QSize videoDimensions_; + QQmlPropertyMap *mediaInfoMap_; + bool videoAvailable_; +}; + +G_BEGIN_DECLS + +typedef struct _GstPlayerQtVideoRenderer + GstPlayerQtVideoRenderer; + +typedef struct _GstPlayerQtVideoRendererClass + GstPlayerQtVideoRendererClass; + +#define GST_TYPE_PLAYER_QT_VIDEO_RENDERER (gst_player_qt_video_renderer_get_type ()) +#define GST_IS_PLAYER_QT_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER)) +#define GST_IS_PLAYER_QT_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_QT_VIDEO_RENDERER)) +#define GST_PLAYER_QT_VIDEO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRendererClass)) +#define GST_PLAYER_QT_VIDEO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRenderer)) +#define GST_PLAYER_QT_VIDEO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_QT_VIDEO_RENDERER, GstPlayerQtVideoRendererClass)) +#define GST_PLAYER_QT_VIDEO_RENDERER_CAST(obj) ((GstPlayerQtVideoRenderer*)(obj)) + +GType gst_player_qt_video_renderer_get_type (void); + +G_END_DECLS + +Q_DECLARE_METATYPE(QGstPlayer*) +Q_DECLARE_METATYPE(QGstPlayer::State) + +#endif // QGSTPLAYER_H diff --git a/playback/player/qt/qml.qrc b/playback/player/qt/qml.qrc new file mode 100644 index 0000000..1052217 --- /dev/null +++ b/playback/player/qt/qml.qrc @@ -0,0 +1,9 @@ + + + main.qml + fontawesome.js + + + fontawesome-webfont.ttf + + diff --git a/playback/player/qt/quickrenderer.cpp b/playback/player/qt/quickrenderer.cpp new file mode 100644 index 0000000..5dd6853 --- /dev/null +++ b/playback/player/qt/quickrenderer.cpp @@ -0,0 +1,56 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "quickrenderer.h" + +QuickRenderer::QuickRenderer(QObject *parent) + : QObject(parent) + , QGstPlayer::VideoRenderer() + , sink() +{ + +} + +QuickRenderer::~QuickRenderer() +{ + if (sink) gst_object_unref(sink); +} + +GstElement *QuickRenderer::createVideoSink() +{ + GstElement *qmlglsink = gst_element_factory_make("qmlglsink", NULL); + + GstElement *glsinkbin = gst_element_factory_make ("glsinkbin", NULL); + + Q_ASSERT(qmlglsink && glsinkbin); + + g_object_set (glsinkbin, "sink", qmlglsink, NULL); + + sink = static_cast(gst_object_ref_sink(qmlglsink)); + + return glsinkbin; +} + +void QuickRenderer::setVideoItem(QQuickItem *item) +{ + Q_ASSERT(item); + + g_object_set(sink, "widget", item, NULL); +} diff --git a/playback/player/qt/quickrenderer.h b/playback/player/qt/quickrenderer.h new file mode 100644 index 0000000..99519fb --- /dev/null +++ b/playback/player/qt/quickrenderer.h @@ -0,0 +1,42 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef QUICKPLAYER_H +#define QUICKPLAYER_H + +#include +#include +#include "qgstplayer.h" + +class QuickRenderer : public QObject, public QGstPlayer::VideoRenderer +{ + Q_OBJECT +public: + QuickRenderer(QObject *parent = 0); + ~QuickRenderer(); + + GstElement *createVideoSink(); + void setVideoItem(QQuickItem *item); + +private: + GstElement *sink; +}; + +#endif // QUICKPLAYER_H -- cgit v1.2.3 From 2ea1c9aee74a6ce994279cb81e443675150959c8 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Tue, 6 Oct 2015 23:19:03 +0800 Subject: playback/player: qt: emit player signals from Qt event loop --- playback/player/qt/qgstplayer.cpp | 144 +++++++++++++++++++++++++++++++++++++- playback/player/qt/qgstplayer.h | 27 +++++-- 2 files changed, 164 insertions(+), 7 deletions(-) diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index c2fb3fb..c2c0ee0 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -21,8 +21,9 @@ #include "qgstplayer.h" #include #include - #include +#include +#include class QGstPlayerRegisterMetaTypes { @@ -86,7 +87,8 @@ QGstPlayer::QGstPlayer(QObject *parent, QGstPlayer::VideoRenderer *renderer) , videoAvailable_(false) { - player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, 0); + player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, + gst_player_qt_signal_dispatcher_new(this)); g_object_connect(player_, "swapped-signal::state-changed", G_CALLBACK (QGstPlayer::onStateChanged), this, @@ -354,7 +356,6 @@ gst_player_qt_video_renderer_set_property (GObject * object, switch (prop_id) { case QT_VIDEO_RENDERER_PROP_RENDERER: - qDebug() << "setting renderer"; self->renderer = g_value_get_pointer (value); break; default: @@ -433,3 +434,140 @@ gst_player_qt_video_renderer_interface_init { iface->create_video_sink = gst_player_qt_video_renderer_create_video_sink; } + +struct _GstPlayerQtSignalDispatcher +{ + GObject parent; + + gpointer player; +}; + +struct _GstPlayerQtSignalDispatcherClass +{ + GObjectClass parent_class; +}; + +static void +gst_player_qt_signal_dispatcher_interface_init + (GstPlayerSignalDispatcherInterface * iface); + +enum +{ + QT_SIGNAL_DISPATCHER_PROP_0, + QT_SIGNAL_DISPATCHER_PROP_PLAYER, + QT_SIGNAL_DISPATCHER_PROP_LAST +}; + +G_DEFINE_TYPE_WITH_CODE (GstPlayerQtSignalDispatcher, + gst_player_qt_signal_dispatcher, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_SIGNAL_DISPATCHER, + gst_player_qt_signal_dispatcher_interface_init)); + +static GParamSpec +* qt_signal_dispatcher_param_specs +[QT_SIGNAL_DISPATCHER_PROP_LAST] = { NULL, }; + +static void +gst_player_qt_signal_dispatcher_finalize (GObject * object) +{ + GstPlayerQtSignalDispatcher *self = + GST_PLAYER_QT_SIGNAL_DISPATCHER (object); + + G_OBJECT_CLASS + (gst_player_qt_signal_dispatcher_parent_class)->finalize + (object); +} + +static void +gst_player_qt_signal_dispatcher_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstPlayerQtSignalDispatcher *self = + GST_PLAYER_QT_SIGNAL_DISPATCHER (object); + + switch (prop_id) { + case QT_SIGNAL_DISPATCHER_PROP_PLAYER: + self->player = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_player_qt_signal_dispatcher_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstPlayerQtSignalDispatcher *self = + GST_PLAYER_QT_SIGNAL_DISPATCHER (object); + + switch (prop_id) { + case QT_SIGNAL_DISPATCHER_PROP_PLAYER: + g_value_set_pointer (value, self->player); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void + gst_player_qt_signal_dispatcher_class_init + (GstPlayerQtSignalDispatcherClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = + gst_player_qt_signal_dispatcher_finalize; + gobject_class->set_property = + gst_player_qt_signal_dispatcher_set_property; + gobject_class->get_property = + gst_player_qt_signal_dispatcher_get_property; + + qt_signal_dispatcher_param_specs + [QT_SIGNAL_DISPATCHER_PROP_PLAYER] = + g_param_spec_pointer ("player", "QGstPlayer instance", "", + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (gobject_class, + QT_SIGNAL_DISPATCHER_PROP_LAST, + qt_signal_dispatcher_param_specs); +} + +static void +gst_player_qt_signal_dispatcher_init + (GstPlayerQtSignalDispatcher * self) +{ + +} + +static void +gst_player_qt_signal_dispatcher_dispatch (GstPlayerSignalDispatcher + * iface, GstPlayer * player, void (*emitter) (gpointer data), gpointer data, + GDestroyNotify destroy) +{ + GstPlayerQtSignalDispatcher *self = GST_PLAYER_QT_SIGNAL_DISPATCHER (iface); + QObject dispatch; + QObject *receiver = static_cast(self->player); + + QObject::connect(&dispatch, &QObject::destroyed, receiver, [=]() { + emitter(data); + if (destroy) destroy(data); + }, Qt::QueuedConnection); +} + +static void +gst_player_qt_signal_dispatcher_interface_init +(GstPlayerSignalDispatcherInterface * iface) +{ + iface->dispatch = gst_player_qt_signal_dispatcher_dispatch; +} + +GstPlayerSignalDispatcher * +gst_player_qt_signal_dispatcher_new (gpointer player) +{ + return static_cast + (g_object_new (GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, + "player", player, NULL)); +} diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index aeb45a5..c0c39d0 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -136,7 +136,10 @@ private: bool videoAvailable_; }; -G_BEGIN_DECLS +Q_DECLARE_METATYPE(QGstPlayer*) +Q_DECLARE_METATYPE(QGstPlayer::State) + +extern "C" { typedef struct _GstPlayerQtVideoRenderer GstPlayerQtVideoRenderer; @@ -154,9 +157,25 @@ typedef struct _GstPlayerQtVideoRendererClass GType gst_player_qt_video_renderer_get_type (void); -G_END_DECLS +typedef struct _GstPlayerQtSignalDispatcher + GstPlayerQtSignalDispatcher; -Q_DECLARE_METATYPE(QGstPlayer*) -Q_DECLARE_METATYPE(QGstPlayer::State) +typedef struct _GstPlayerQtSignalDispatcherClass + GstPlayerQtSignalDispatcherClass; + +#define GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER (gst_player_qt_signal_dispatcher_get_type ()) +#define GST_IS_PLAYER_QT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER)) +#define GST_IS_PLAYER_QT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER)) +#define GST_PLAYER_QT_SIGNAL_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, GstPlayerQtSignalDispatcherClass)) +#define GST_PLAYER_QT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, GstPlayerQtSignalDispatcher)) +#define GST_PLAYER_QT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PLAYER_QT_SIGNAL_DISPATCHER, GstPlayerQtSignalDispatcherClass)) +#define GST_PLAYER_QT_SIGNAL_DISPATCHER_CAST(obj) ((GstPlayerQtSignalDispatcher*)(obj)) + +GType gst_player_qt_video_renderer_get_type (void); + +GstPlayerSignalDispatcher * +gst_player_qt_signal_dispatcher_new (gpointer player); + +} #endif // QGSTPLAYER_H -- cgit v1.2.3 From c8d7277d70378affb9096544f3b3edaa87fcf2c3 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Thu, 22 Oct 2015 23:05:35 +0800 Subject: playback/player: qt: add stream selection support --- playback/player/qt/main.qml | 294 ++++++++++++++++++++++++++++-- playback/player/qt/player.cpp | 2 +- playback/player/qt/player.h | 2 +- playback/player/qt/qgstplayer.cpp | 375 +++++++++++++++++++++++++++++++------- playback/player/qt/qgstplayer.h | 193 +++++++++++++++----- 5 files changed, 738 insertions(+), 128 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index c7fe424..9825026 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -44,7 +44,7 @@ ApplicationWindow { volume: 0.5 onStateChanged: { if (state === Player.STOPPED) { - playbutton.text = FontAwesome.Icon.Play + playbutton.state = "play" } } onResolutionChanged: { @@ -116,16 +116,236 @@ ApplicationWindow { interval: 10000 onTriggered: { parent.opacity = 0.0 + settings.visible = false stop() } } + Rectangle { + id: settings + width: 150; height: settingsView.contentHeight + color: Qt.rgba(1, 1, 1, 0.7) + anchors.right: parent.right + anchors.bottom: parent.top + anchors.bottomMargin: 3 + border.width: 1 + border.color: "white" + radius: 5 + visible: false + + ListModel { + id: settingsModel + ListElement { + name: "Video" + } + ListElement { + name: "Audio" + } + ListElement { + name: "Subtitle" + } + } + + Component { + id: settingsDelegate + Item { + width: 150; height: 20 + Text { + text: model.name + font.pointSize: 13 + anchors.centerIn: parent + } + + Text { + font.pointSize: 13 + font.family: "FontAwesome" + text: FontAwesome.Icon.ChevronRight + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.verticalCenter: parent.verticalCenter + } + + MouseArea { + anchors.fill: parent + onClicked: { + switch(name) { + case 'Video': + videos.visible = true + break + case 'Audio': + audios.visible = true + break + case 'Subtitle' : + subtitles.visible = true + break + } + settings.visible = false + } + } + } + } + + ListView { + id: settingsView + anchors.fill: parent + model: settingsModel + delegate: settingsDelegate + } + } + + Rectangle { + id: videos + width: 150; height: videoView.contentHeight + color: Qt.rgba(1, 1, 1, 0.7) + anchors.right: parent.right + anchors.bottom: parent.top + anchors.bottomMargin: 3 + border.width: 1 + border.color: "white" + radius: 5 + + property bool selected: ListView.isCurrentItem + visible: false + + Component { + id: videoDelegate + Item { + width: 150; height: 20 + Text { + text: model.modelData.resolution.width + 'x' + model.modelData.resolution.height + font.pointSize: 13 + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: { + parent.ListView.view.currentIndex = index + player.currentVideo = model.modelData + } + } + } + } + + ListView { + id : videoView + anchors.fill: parent + model: player.mediaInfo.videoStreams + delegate: videoDelegate + highlight: Rectangle { + color: "white" + radius: 5 + border.width: 1 + border.color: "white" + } + focus: true + clip: true + } + } + + Rectangle { + id: audios + width: 150; height: audioView.contentHeight + color: Qt.rgba(1, 1, 1, 0.7) + anchors.right: parent.right + anchors.bottom: parent.top + anchors.bottomMargin: 3 + border.width: 1 + border.color: "white" + radius: 5 + + property bool selected: ListView.isCurrentItem + visible: false + + Component { + id: audioDelegate + Item { + width: 150; height: 20 + Text { + text: model.modelData.channels + 'channels' + font.pointSize: 13 + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: { + parent.ListView.view.currentIndex = index + player.currentAudio = model.modelData + } + } + } + } + + ListView { + id : audioView + anchors.fill: parent + model: player.mediaInfo.audioStreams + delegate: audioDelegate + highlight: Rectangle { + color: "white" + radius: 5 + border.width: 1 + border.color: "white" + } + focus: true + clip: true + } + } + + Rectangle { + id: subtitles + width: 150; height: subtitleView.contentHeight + color: Qt.rgba(1, 1, 1, 0.7) + anchors.right: parent.right + anchors.bottom: parent.top + anchors.bottomMargin: 3 + border.width: 1 + border.color: "white" + radius: 5 + + property bool selected: ListView.isCurrentItem + visible: false + + Component { + id: subtitleDelegate + Item { + width: 150; height: 20 + Text { + text: model.modelData.language + font.pointSize: 13 + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: { + parent.ListView.view.currentIndex = index + player.currentSubtitle = model.modelData + } + } + } + } + + ListView { + id : subtitleView + anchors.fill: parent + model: player.mediaInfo.subtitleStreams + delegate: subtitleDelegate + highlight: Rectangle { + color: "white" + radius: 5 + border.width: 1 + border.color: "white" + } + focus: true + clip: true + } + } + Grid { id: grid anchors.horizontalCenter: parent.horizontalCenter -// anchors.top: parent.top -// anchors.topMargin: 5 - spacing: 7 rows: 1 verticalItemAlignment: Qt.AlignVCenter @@ -161,10 +381,27 @@ ApplicationWindow { Text { anchors.centerIn: parent id : playbutton - font.pointSize: 25 font.family: "FontAwesome" - //font.weight: Font.Light - text: FontAwesome.Icon.PlayCircle + state: "play" + + states: [ + State { + name: "play" + PropertyChanges { + target: playbutton + text: FontAwesome.Icon.PlayCircle + font.pointSize: 25 + } + }, + State { + name: "pause" + PropertyChanges { + target: playbutton + text: FontAwesome.Icon.Pause + font.pointSize: 17 + } + } + ] } MouseArea { @@ -173,12 +410,10 @@ ApplicationWindow { onPressed: { if (player.state !== Player.PLAYING) { player.play() - playbutton.text = FontAwesome.Icon.Pause - playbutton.font.pointSize = 17 + playbutton.state = "pause" } else { player.pause() - playbutton.text = FontAwesome.Icon.PlayCircle - playbutton.font.pointSize = 25 + playbutton.state = "play" } } } @@ -221,8 +456,6 @@ ApplicationWindow { } } - - Item { width: 40 height: 17 @@ -238,11 +471,25 @@ ApplicationWindow { } } + Text { + id: sub + font.pointSize: 17 + font.family: "FontAwesome" + text: FontAwesome.Icon.ClosedCaptions + color: player.subtitleEnabled ? "red" : "black" + + MouseArea { + anchors.fill: parent + onClicked: { + player.subtitleEnabled = !player.subtitleEnabled + } + } + } + Item { width: 17 height: 17 - Text { id : volume anchors.centerIn: parent @@ -343,10 +590,22 @@ ApplicationWindow { } Text { - id: sub + id: cog font.pointSize: 17 font.family: "FontAwesome" - text: FontAwesome.Icon.ClosedCaptions + text: FontAwesome.Icon.Cog + + MouseArea { + anchors.fill: parent + onClicked: { + settings.visible = !settings.visible + videos.visible = false + audios.visible = false + subtitles.visible = false + + + } + } } Text { @@ -380,7 +639,7 @@ ApplicationWindow { maximumValue: player.duration value: player.position onPressedChanged: player.seek(value) - enabled: player.mediaInfo.isSeekable + enabled: player.mediaInfo.seekable anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter @@ -455,7 +714,6 @@ ApplicationWindow { } } } - } } } diff --git a/playback/player/qt/player.cpp b/playback/player/qt/player.cpp index ec4b78c..3e2cade 100644 --- a/playback/player/qt/player.cpp +++ b/playback/player/qt/player.cpp @@ -29,7 +29,7 @@ Player::Player(QObject *parent) } Player::Player(QObject *parent, QuickRenderer *renderer) - : QGstPlayer(parent, renderer) + : QGstPlayer::Player(parent, renderer) , renderer_(renderer) { renderer_->setParent(this); diff --git a/playback/player/qt/player.h b/playback/player/qt/player.h index 88586f4..34a0002 100644 --- a/playback/player/qt/player.h +++ b/playback/player/qt/player.h @@ -27,7 +27,7 @@ class QuickRenderer; -class Player : public QGstPlayer +class Player : public QGstPlayer::Player { Q_OBJECT public: diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index c2c0ee0..e6fc476 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -24,43 +24,200 @@ #include #include #include +#include -class QGstPlayerRegisterMetaTypes +namespace QGstPlayer { + +class RegisterMetaTypes { public: - QGstPlayerRegisterMetaTypes() + RegisterMetaTypes() { - qRegisterMetaType("State"); + qRegisterMetaType("State"); } } _register; -QGstPlayer::MediaInfo::MediaInfo(GstPlayerMediaInfo *media_info) - : mediaInfo_(media_info) +MediaInfo::MediaInfo(Player *player) + : QObject(player) + , uri_() + , title_() + , isSeekable_(false) { } -QString QGstPlayer::MediaInfo::title() const +QString MediaInfo::uri() const { - QString title = QString::fromLocal8Bit - (gst_player_media_info_get_title(mediaInfo_)); + return uri_; +} + +QString MediaInfo::title() const +{ + return title_; +} + +bool MediaInfo::isSeekable() const +{ + return isSeekable_; +} + +const QList &MediaInfo::videoStreams() const +{ + return videoStreams_; +} + +const QList &MediaInfo::audioStreams() const +{ + return audioStreams_; +} + +const QList &MediaInfo::subtitleStreams() const +{ + return subtitleStreams_; +} + +void MediaInfo::update(GstPlayerMediaInfo *info) +{ + Q_ASSERT(info != 0); + + // FIXME since media-info signal gets emitted + // several times, we just update info iff the + // media uri has changed. + if (uri_ == gst_player_media_info_get_uri(info)) { + return; + } + + uri_ = QString(gst_player_media_info_get_uri(info)); + + title_ = QString::fromLocal8Bit(gst_player_media_info_get_title(info)); // if media has no title, return the file name - if (title.isEmpty()) { - QUrl url(gst_player_media_info_get_uri(mediaInfo_)); - title = url.fileName(); + if (title_.isEmpty()) { + QUrl url(gst_player_media_info_get_uri(info)); + title_ = url.fileName(); + } + + emit titleChanged(); + + if (isSeekable_ != gst_player_media_info_is_seekable(info)) { + isSeekable_ = !isSeekable_; + emit seekableChanged(); + } + + if (!subtitleStreams_.isEmpty()) { + qDeleteAll(subtitleStreams_); + subtitleStreams_.clear(); + } + + if (!videoStreams_.isEmpty()) { + qDeleteAll(videoStreams_); + videoStreams_.clear(); + } + + if (!audioStreams_.isEmpty()) { + qDeleteAll(audioStreams_); + audioStreams_.clear(); } - return title; + GList *list = gst_player_get_subtitle_streams(info); + + g_list_foreach (list, [](gpointer data, gpointer user_data) { + GstPlayerSubtitleInfo *info = static_cast(data); + QList *subs = static_cast*>(user_data); + + subs->append(new SubtitleInfo(info)); + }, &subtitleStreams_); + + list = gst_player_get_video_streams(info); + + g_list_foreach (list, [](gpointer data, gpointer user_data) { + GstPlayerVideoInfo *info = static_cast(data); + QList *videos = static_cast*>(user_data); + + videos->append(new VideoInfo(info)); + }, &videoStreams_); + + list = gst_player_get_audio_streams(info); + + g_list_foreach (list, [](gpointer data, gpointer user_data) { + GstPlayerAudioInfo *info = static_cast(data); + QList *audios = static_cast*>(user_data); + + audios->append(new AudioInfo(info)); + }, &audioStreams_); +} + +VideoInfo::VideoInfo(GstPlayerVideoInfo *info) + : StreamInfo(reinterpret_cast(info)) + , video_(info) + , resolution_(gst_player_video_info_get_width(info), gst_player_video_info_get_height(info)) +{ + +} + +QSize VideoInfo::resolution() const +{ + return resolution_; +} + +AudioInfo::AudioInfo(GstPlayerAudioInfo *info) + : StreamInfo(reinterpret_cast(info)) + , audio_(info) + , language_(gst_player_audio_info_get_language(info)) + , channels_(gst_player_audio_info_get_channels(info)) + , bitRate_(gst_player_audio_info_get_bitrate(info)) + , sampleRate_(gst_player_audio_info_get_sample_rate(info)) +{ + +} + +const QString &AudioInfo::language() const +{ + return language_; +} + +int AudioInfo::channels() const +{ + return channels_; +} + +int AudioInfo::bitRate() const +{ + return bitRate_; +} + +int AudioInfo::sampleRate() const +{ + return sampleRate_; +} + +SubtitleInfo::SubtitleInfo(GstPlayerSubtitleInfo *info) + : StreamInfo(reinterpret_cast(info)) + , subtitle_(info) + , language_(gst_player_subtitle_info_get_language(info)) +{ + +} + +const QString &SubtitleInfo::language() const +{ + return language_; } -bool QGstPlayer::MediaInfo::isSeekable() const +int StreamInfo::index() const { - return gst_player_media_info_is_seekable(mediaInfo_); + return index_; +} + +StreamInfo::StreamInfo(GstPlayerStreamInfo *info) + : stream_(info) + , index_(gst_player_stream_info_get_index(info)) +{ + } -bool QGstPlayer::isVideoAvailable() const +bool Player::isVideoAvailable() const { GstPlayerVideoInfo *video_info; @@ -73,74 +230,163 @@ bool QGstPlayer::isVideoAvailable() const return false; } -QQmlPropertyMap *QGstPlayer::mediaInfo() const +MediaInfo *Player::mediaInfo() const { - return mediaInfoMap_; + return mediaInfo_; } -QGstPlayer::QGstPlayer(QObject *parent, QGstPlayer::VideoRenderer *renderer) +QVariant Player::currentVideo() const +{ + Q_ASSERT(player_ != 0); + + GstPlayerVideoInfo *track = gst_player_get_current_video_track(player_); + + if (!track) + return QVariant(); + + return QVariant::fromValue(new VideoInfo(track)); +} + +QVariant Player::currentAudio() const +{ + Q_ASSERT(player_ != 0); + + GstPlayerAudioInfo *track = gst_player_get_current_audio_track(player_); + + if (!track) + return QVariant(); + + return QVariant::fromValue(new AudioInfo(track)); +} + +QVariant Player::currentSubtitle() const +{ + Q_ASSERT(player_ != 0); + + GstPlayerSubtitleInfo *track = gst_player_get_current_subtitle_track(player_); + + if (!track) + return QVariant(); + + return QVariant::fromValue(new SubtitleInfo(track)); +} + +void Player::setCurrentVideo(QVariant track) +{ + Q_ASSERT(player_ != 0); + + VideoInfo* info = track.value(); + Q_ASSERT(info); + + gst_player_set_video_track(player_, info->index()); +} + +void Player::setCurrentAudio(QVariant track) +{ + Q_ASSERT(player_ != 0); + + AudioInfo* info = track.value(); + Q_ASSERT(info); + + gst_player_set_audio_track(player_, info->index()); + +} + +void Player::setCurrentSubtitle(QVariant track) +{ + Q_ASSERT(player_ != 0); + + SubtitleInfo* info = track.value(); + Q_ASSERT(info); + + gst_player_set_subtitle_track(player_, info->index()); +} + +bool Player::isSubtitleEnabled() const +{ + return subtitleEnabled_; +} + +void Player::setSubtitleEnabled(bool enabled) +{ + Q_ASSERT(player_ != 0); + + subtitleEnabled_ = enabled; + + gst_player_set_subtitle_track_enabled(player_, enabled); + + emit subtitleEnabledChanged(enabled); +} + +Player::Player(QObject *parent, VideoRenderer *renderer) : QObject(parent) , player_() , state_(STOPPED) , videoDimensions_(QSize()) - , mediaInfoMap_() + , mediaInfo_() , videoAvailable_(false) + , subtitleEnabled_(false) { player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, gst_player_qt_signal_dispatcher_new(this)); g_object_connect(player_, - "swapped-signal::state-changed", G_CALLBACK (QGstPlayer::onStateChanged), this, - "swapped-signal::position-updated", G_CALLBACK (QGstPlayer::onPositionUpdated), this, - "swapped-signal::duration-changed", G_CALLBACK (QGstPlayer::onDurationChanged), this, - "swapped-signal::buffering", G_CALLBACK (QGstPlayer::onBufferingChanged), this, - "swapped-signal::video-dimensions-changed", G_CALLBACK (QGstPlayer::onVideoDimensionsChanged), this, - "swapped-signal::volume-changed", G_CALLBACK (QGstPlayer::onVolumeChanged), this, - "swapped-signal::mute-changed", G_CALLBACK (QGstPlayer::onMuteChanged), this, - "swapped-signal::media-info-updated", G_CALLBACK (QGstPlayer::onMediaInfoUpdated), this, NULL); + "swapped-signal::state-changed", G_CALLBACK (Player::onStateChanged), this, + "swapped-signal::position-updated", G_CALLBACK (Player::onPositionUpdated), this, + "swapped-signal::duration-changed", G_CALLBACK (Player::onDurationChanged), this, + "swapped-signal::buffering", G_CALLBACK (Player::onBufferingChanged), this, + "swapped-signal::video-dimensions-changed", G_CALLBACK (Player::onVideoDimensionsChanged), this, + "swapped-signal::volume-changed", G_CALLBACK (Player::onVolumeChanged), this, + "swapped-signal::mute-changed", G_CALLBACK (Player::onMuteChanged), this, + "swapped-signal::media-info-updated", G_CALLBACK (Player::onMediaInfoUpdated), this, NULL); - mediaInfoMap_ = new QQmlPropertyMap(this); + mediaInfo_ = new MediaInfo(this); + gst_player_set_subtitle_track_enabled(player_, false); } void -QGstPlayer::onStateChanged(QGstPlayer * player, GstPlayerState state) +Player::onStateChanged(Player * player, GstPlayerState state) { - player->state_ = static_cast(state); + player->state_ = static_cast(state); emit player->stateChanged(player->state_); } void -QGstPlayer::onPositionUpdated(QGstPlayer * player, GstClockTime position) +Player::onPositionUpdated(Player * player, GstClockTime position) { emit player->positionChanged(position); } void -QGstPlayer::onDurationChanged(QGstPlayer * player, GstClockTime duration) +Player::onDurationChanged(Player * player, GstClockTime duration) { emit player->durationChanged(duration); } void -QGstPlayer::onBufferingChanged(QGstPlayer * player, int percent) +Player::onBufferingChanged(Player * player, int percent) { emit player->bufferingChanged(percent); } void -QGstPlayer::onVideoDimensionsChanged(QGstPlayer * player, int w, int h) +Player::onVideoDimensionsChanged(Player * player, int w, int h) { QSize res(w,h); + if (res == player->videoDimensions_) + return; + player->videoDimensions_ = res; + player->setResolution(res); emit player->resolutionChanged(res); } void -QGstPlayer::onVolumeChanged(QGstPlayer *player) +Player::onVolumeChanged(Player *player) { qreal new_val; @@ -150,7 +396,7 @@ QGstPlayer::onVolumeChanged(QGstPlayer *player) } void -QGstPlayer::onMuteChanged(QGstPlayer *player) +Player::onMuteChanged(Player *player) { bool new_val; @@ -160,15 +406,8 @@ QGstPlayer::onMuteChanged(QGstPlayer *player) } void -QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_info) +Player::onMediaInfoUpdated(Player *player, GstPlayerMediaInfo *media_info) { - MediaInfo mediaInfo(media_info); - - player->mediaInfoMap_->insert(QLatin1String("title"), - QVariant(mediaInfo.title())); - player->mediaInfoMap_->insert(QLatin1String("isSeekable"), - QVariant(mediaInfo.isSeekable())); - bool val = player->isVideoAvailable(); if (player->videoAvailable_ != val) { @@ -176,10 +415,12 @@ QGstPlayer::onMediaInfoUpdated(QGstPlayer *player, GstPlayerMediaInfo *media_inf emit player->videoAvailableChanged(val); } + player->mediaInfo()->update(media_info); + emit player->mediaInfoChanged(); } -QUrl QGstPlayer::source() const +QUrl Player::source() const { Q_ASSERT(player_ != 0); QString url = QString::fromLocal8Bit(gst_player_get_uri(player_)); @@ -187,90 +428,90 @@ QUrl QGstPlayer::source() const return QUrl(url); } -qint64 QGstPlayer::duration() const +qint64 Player::duration() const { Q_ASSERT(player_ != 0); return gst_player_get_duration(player_); } -qint64 QGstPlayer::position() const +qint64 Player::position() const { Q_ASSERT(player_ != 0); return gst_player_get_position(player_); } -qreal QGstPlayer::volume() const +qreal Player::volume() const { Q_ASSERT(player_ != 0); return gst_player_get_volume(player_); } -bool QGstPlayer::isMuted() const +bool Player::isMuted() const { Q_ASSERT(player_ != 0); return gst_player_get_mute(player_); } -int QGstPlayer::buffering() const +int Player::buffering() const { return 0; } -QSize QGstPlayer::resolution() const +QSize Player::resolution() const { return videoDimensions_; } -void QGstPlayer::setResolution(QSize size) +void Player::setResolution(QSize size) { videoDimensions_ = size; } -QGstPlayer::State QGstPlayer::state() const +Player::State Player::state() const { return state_; } -GstElement *QGstPlayer::pipeline() const +GstElement *Player::pipeline() const { Q_ASSERT(player_ != 0); return gst_player_get_pipeline(player_); } -void QGstPlayer::play() +void Player::play() { Q_ASSERT(player_ != 0); gst_player_play(player_); } -void QGstPlayer::pause() +void Player::pause() { Q_ASSERT(player_ != 0); gst_player_pause(player_); } -void QGstPlayer::stop() +void Player::stop() { Q_ASSERT(player_ != 0); gst_player_stop(player_); } -void QGstPlayer::seek(qint64 position) +void Player::seek(qint64 position) { Q_ASSERT(player_ != 0); gst_player_seek(player_, position); } -void QGstPlayer::setSource(QUrl const& url) +void Player::setSource(QUrl const& url) { Q_ASSERT(player_ != 0); QByteArray uri = url.toString().toLocal8Bit(); @@ -280,43 +521,45 @@ void QGstPlayer::setSource(QUrl const& url) emit sourceChanged(url); } -void QGstPlayer::setVolume(qreal val) +void Player::setVolume(qreal val) { Q_ASSERT(player_ != 0); gst_player_set_volume(player_, val); } -void QGstPlayer::setMuted(bool val) +void Player::setMuted(bool val) { Q_ASSERT(player_ != 0); gst_player_set_mute(player_, val); } -void QGstPlayer::setPosition(qint64 pos) +void Player::setPosition(qint64 pos) { Q_ASSERT(player_ != 0); gst_player_seek(player_, pos); } -GstPlayerVideoRenderer *QGstPlayer::VideoRenderer::renderer() +GstPlayerVideoRenderer *VideoRenderer::renderer() { return renderer_; } -QGstPlayer::VideoRenderer::VideoRenderer() +VideoRenderer::VideoRenderer() { renderer_ = static_cast (g_object_new (GST_TYPE_PLAYER_QT_VIDEO_RENDERER, "renderer", this, NULL)); } -QGstPlayer::VideoRenderer::~VideoRenderer() +VideoRenderer::~VideoRenderer() { if (renderer_) gst_object_unref(renderer_); } +} + struct _GstPlayerQtVideoRenderer { GObject parent; @@ -527,7 +770,7 @@ static void qt_signal_dispatcher_param_specs [QT_SIGNAL_DISPATCHER_PROP_PLAYER] = - g_param_spec_pointer ("player", "QGstPlayer instance", "", + g_param_spec_pointer ("player", "Player instance", "", static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_properties (gobject_class, diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index c0c39d0..1f4dc6f 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -28,7 +28,16 @@ #include #include -class QGstPlayer : public QObject +namespace QGstPlayer { + +class VideoRenderer; +class MediaInfo; +class StreamInfo; +class VideInfo; +class AudioInfo; +class SubtitleInfo; + +class Player : public QObject { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -41,14 +50,16 @@ class QGstPlayer : public QObject Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QObject *mediaInfo READ mediaInfo NOTIFY mediaInfoChanged) Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) + Q_PROPERTY(QVariant currentVideo READ currentVideo WRITE setCurrentVideo) + Q_PROPERTY(QVariant currentAudio READ currentAudio WRITE setCurrentAudio) + Q_PROPERTY(QVariant currentSubtitle READ currentSubtitle WRITE setCurrentSubtitle) + Q_PROPERTY(bool subtitleEnabled READ isSubtitleEnabled WRITE setSubtitleEnabled + NOTIFY subtitleEnabledChanged) Q_ENUMS(State) public: - - class VideoRenderer; - - explicit QGstPlayer(QObject *parent = 0, VideoRenderer *renderer = 0); + explicit Player(QObject *parent = 0, VideoRenderer *renderer = 0); typedef GstPlayerError Error; enum State { @@ -58,29 +69,6 @@ public: PLAYING = GST_PLAYER_STATE_PLAYING }; - class VideoRenderer - { - public: - GstPlayerVideoRenderer *renderer(); - virtual GstElement *createVideoSink() = 0; - protected: - VideoRenderer(); - virtual ~VideoRenderer(); - private: - GstPlayerVideoRenderer *renderer_; - }; - - // TODO add remaining bits - class MediaInfo - { - public: - MediaInfo(GstPlayerMediaInfo *media_info); - QString title() const; - bool isSeekable() const; - private: - GstPlayerMediaInfo *mediaInfo_; - }; - QUrl source() const; qint64 duration() const; qint64 position() const; @@ -92,8 +80,11 @@ public: QSize resolution() const; void setResolution(QSize size); bool isVideoAvailable() const; - QQmlPropertyMap *mediaInfo() const; - + MediaInfo *mediaInfo() const; + QVariant currentVideo() const; + QVariant currentAudio() const; + QVariant currentSubtitle() const; + bool isSubtitleEnabled() const; signals: void stateChanged(State new_state); @@ -107,6 +98,7 @@ signals: void mediaInfoChanged(); void sourceChanged(QUrl new_url); void videoAvailableChanged(bool videoAvailable); + void subtitleEnabledChanged(bool enabled); public slots: void play(); @@ -117,27 +109,144 @@ public slots: void setVolume(qreal val); void setMuted(bool val); void setPosition(qint64 pos); + void setCurrentVideo(QVariant track); + void setCurrentAudio(QVariant track); + void setCurrentSubtitle(QVariant track); + void setSubtitleEnabled(bool enabled); private: - Q_DISABLE_COPY(QGstPlayer) - static void onStateChanged(QGstPlayer *, GstPlayerState state); - static void onPositionUpdated(QGstPlayer *, GstClockTime position); - static void onDurationChanged(QGstPlayer *, GstClockTime duration); - static void onBufferingChanged(QGstPlayer *, int percent); - static void onVideoDimensionsChanged(QGstPlayer *, int w, int h); - static void onVolumeChanged(QGstPlayer *); - static void onMuteChanged(QGstPlayer *); - static void onMediaInfoUpdated(QGstPlayer *, GstPlayerMediaInfo *media_info); + Q_DISABLE_COPY(Player) + static void onStateChanged(Player *, GstPlayerState state); + static void onPositionUpdated(Player *, GstClockTime position); + static void onDurationChanged(Player *, GstClockTime duration); + static void onBufferingChanged(Player *, int percent); + static void onVideoDimensionsChanged(Player *, int w, int h); + static void onVolumeChanged(Player *); + static void onMuteChanged(Player *); + static void onMediaInfoUpdated(Player *, GstPlayerMediaInfo *media_info); GstPlayer *player_; State state_; QSize videoDimensions_; - QQmlPropertyMap *mediaInfoMap_; + MediaInfo *mediaInfo_; bool videoAvailable_; + bool subtitleEnabled_; +}; + +class VideoRenderer +{ +public: + GstPlayerVideoRenderer *renderer(); + virtual GstElement *createVideoSink() = 0; +protected: + VideoRenderer(); + virtual ~VideoRenderer(); +private: + GstPlayerVideoRenderer *renderer_; +}; + +class MediaInfo : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString uri READ uri NOTIFY uriChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(QString title READ title NOTIFY titleChanged) + Q_PROPERTY(QList videoStreams READ videoStreams CONSTANT) + Q_PROPERTY(QList audioStreams READ audioStreams CONSTANT) + Q_PROPERTY(QList subtitleStreams READ subtitleStreams CONSTANT) + +public: + explicit MediaInfo(Player *player = 0); + QString uri() const; + QString title() const; + bool isSeekable() const; + const QList &videoStreams() const; + const QList &audioStreams() const; + const QList &subtitleStreams() const; + +signals: + void uriChanged(); + void seekableChanged(); + void titleChanged(); + +public Q_SLOTS: + void update(GstPlayerMediaInfo *info); +private: + QString uri_; + QString title_; + bool isSeekable_; + QList videoStreams_; + QList audioStreams_; + QList subtitleStreams_; +}; + +class StreamInfo : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index CONSTANT) +public: + int index() const; + +protected: + StreamInfo(GstPlayerStreamInfo* info); +private: + GstPlayerStreamInfo *stream_; + int index_; +}; + +class VideoInfo : public StreamInfo +{ + Q_OBJECT + Q_PROPERTY(QSize resolution READ resolution CONSTANT) +public: + VideoInfo(GstPlayerVideoInfo *info); + QSize resolution() const; + +private: + GstPlayerVideoInfo *video_; + QSize resolution_; +}; + +class AudioInfo : public StreamInfo +{ + Q_OBJECT + Q_PROPERTY(QString language READ language CONSTANT) + Q_PROPERTY(int channels READ channels CONSTANT) + Q_PROPERTY(int bitRate READ bitRate CONSTANT) + Q_PROPERTY(int sampleRate READ sampleRate CONSTANT) + +public: + AudioInfo(GstPlayerAudioInfo *info); + QString const& language() const; + int channels() const; + int bitRate() const; + int sampleRate() const; + +private: + GstPlayerAudioInfo *audio_; + QString language_; + int channels_; + int bitRate_; + int sampleRate_; +}; + +class SubtitleInfo : public StreamInfo +{ + Q_OBJECT + Q_PROPERTY(QString language READ language CONSTANT) +public: + SubtitleInfo(GstPlayerSubtitleInfo *info); + QString const& language() const; + +private: + GstPlayerSubtitleInfo *subtitle_; + QString language_; }; -Q_DECLARE_METATYPE(QGstPlayer*) -Q_DECLARE_METATYPE(QGstPlayer::State) +} + +Q_DECLARE_METATYPE(QGstPlayer::Player*) +Q_DECLARE_METATYPE(QGstPlayer::Player::State) extern "C" { -- cgit v1.2.3 From 13156a713d8fc9d9ce6b0742d188e0d258ee9217 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 23 Oct 2015 21:54:05 +0300 Subject: playback/player: qt: Fix -Wunused-variable compiler warnings --- playback/player/qt/qgstplayer.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index e6fc476..1dadfa8 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -626,8 +626,6 @@ gst_player_qt_video_renderer_get_property (GObject * object, static void gst_player_qt_video_renderer_finalize (GObject * object) { - GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (object); - G_OBJECT_CLASS (gst_player_qt_video_renderer_parent_class)->finalize(object); } @@ -655,14 +653,14 @@ gst_player_qt_video_renderer_class_init } static void -gst_player_qt_video_renderer_init (GstPlayerQtVideoRenderer * self) +gst_player_qt_video_renderer_init (G_GNUC_UNUSED GstPlayerQtVideoRenderer * self) { } static GstElement * gst_player_qt_video_renderer_create_video_sink - (GstPlayerVideoRenderer * iface, GstPlayer *player) + (GstPlayerVideoRenderer * iface, G_GNUC_UNUSED GstPlayer *player) { GstPlayerQtVideoRenderer *self = GST_PLAYER_QT_VIDEO_RENDERER (iface); @@ -713,9 +711,6 @@ static GParamSpec static void gst_player_qt_signal_dispatcher_finalize (GObject * object) { - GstPlayerQtSignalDispatcher *self = - GST_PLAYER_QT_SIGNAL_DISPATCHER (object); - G_OBJECT_CLASS (gst_player_qt_signal_dispatcher_parent_class)->finalize (object); @@ -780,14 +775,14 @@ static void static void gst_player_qt_signal_dispatcher_init - (GstPlayerQtSignalDispatcher * self) + (G_GNUC_UNUSED GstPlayerQtSignalDispatcher * self) { } static void gst_player_qt_signal_dispatcher_dispatch (GstPlayerSignalDispatcher - * iface, GstPlayer * player, void (*emitter) (gpointer data), gpointer data, + * iface, G_GNUC_UNUSED GstPlayer * player, void (*emitter) (gpointer data), gpointer data, GDestroyNotify destroy) { GstPlayerQtSignalDispatcher *self = GST_PLAYER_QT_SIGNAL_DISPATCHER (iface); -- cgit v1.2.3 From 3542cae13868648fb4a0202eb66a72d1b6d9c716 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sat, 24 Oct 2015 13:28:10 +0800 Subject: playback/player: qt: add position update interval property --- playback/player/qt/main.qml | 1 + playback/player/qt/qgstplayer.cpp | 16 +++++++++++++++- playback/player/qt/qgstplayer.h | 9 +++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index 9825026..85014c3 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -42,6 +42,7 @@ ApplicationWindow { id: player objectName: "player" volume: 0.5 + positionUpdateInterval: 100 onStateChanged: { if (state === Player.STOPPED) { playbutton.state = "play" diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index 1dadfa8..ab140f3 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -307,6 +307,13 @@ bool Player::isSubtitleEnabled() const return subtitleEnabled_; } +quint32 Player::positionUpdateInterval() const +{ + Q_ASSERT(player_ != 0); + + return gst_player_get_position_update_interval(player_); +} + void Player::setSubtitleEnabled(bool enabled) { Q_ASSERT(player_ != 0); @@ -318,6 +325,13 @@ void Player::setSubtitleEnabled(bool enabled) emit subtitleEnabledChanged(enabled); } +void Player::setPositionUpdateInterval(quint32 interval) +{ + Q_ASSERT(player_ != 0); + + gst_player_set_position_update_interval(player_, interval); +} + Player::Player(QObject *parent, VideoRenderer *renderer) : QObject(parent) , player_() @@ -356,7 +370,7 @@ Player::onStateChanged(Player * player, GstPlayerState state) void Player::onPositionUpdated(Player * player, GstClockTime position) { - emit player->positionChanged(position); + emit player->positionUpdated(position); } void diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index 1f4dc6f..f5d4ab8 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -42,7 +42,9 @@ class Player : public QObject Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) - Q_PROPERTY(qint64 position READ position NOTIFY positionChanged) + Q_PROPERTY(qint64 position READ position NOTIFY positionUpdated) + Q_PROPERTY(quint32 positionUpdateInterval READ positionUpdateInterval + WRITE setPositionUpdateInterval) Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) Q_PROPERTY(int buffering READ buffering NOTIFY bufferingChanged) @@ -85,12 +87,14 @@ public: QVariant currentAudio() const; QVariant currentSubtitle() const; bool isSubtitleEnabled() const; + quint32 positionUpdateInterval() const; + signals: void stateChanged(State new_state); void bufferingChanged(int percent); void enfOfStream(); - void positionChanged(qint64 new_position); + void positionUpdated(qint64 new_position); void durationChanged(qint64 duration); void resolutionChanged(QSize resolution); void volumeChanged(qreal volume); @@ -113,6 +117,7 @@ public slots: void setCurrentAudio(QVariant track); void setCurrentSubtitle(QVariant track); void setSubtitleEnabled(bool enabled); + void setPositionUpdateInterval(quint32 interval); private: Q_DISABLE_COPY(Player) -- cgit v1.2.3 From 512051bdd64d92a185894d7214db5c680eb3f775 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sat, 24 Oct 2015 21:47:38 +0800 Subject: playback/player: qt: elide long titles Fixes #121 --- playback/player/qt/main.qml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index 85014c3..b3eb188 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -76,14 +76,6 @@ ApplicationWindow { onTriggered: fileDialog.open() } - menuBar: MenuBar { - Menu { - title: "&File" - MenuItem { action: fileOpenAction } - MenuItem { text: "Quit"; onTriggered: Qt.quit() } - } - } - Item { anchors.fill: parent FontLoader { @@ -452,8 +444,10 @@ ApplicationWindow { height: 38 Text { anchors.centerIn: parent + width: parent.width text: player.mediaInfo.title font.pointSize: 15 + elide: Text.ElideRight } } -- cgit v1.2.3 From d623c45b7608b216bd8b822cd866de5569173e22 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sat, 24 Oct 2015 21:55:37 +0800 Subject: playback/player: qt: bind video item size to window Fixes #119 --- playback/player/qt/main.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index b3eb188..c75a7b3 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -60,8 +60,8 @@ ApplicationWindow { id: video objectName: "videoItem" anchors.centerIn: parent - width: 640 - height: 480 + width: parent.width + height: parent.height } FileDialog { -- cgit v1.2.3 From dbc1f82678261c192a7ef16bee52a5fc9dafad51 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sun, 25 Oct 2015 01:18:01 +0800 Subject: playback/player: qt: hide playbar properly Fixes #120 --- playback/player/qt/main.qml | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index c75a7b3..d06b0d4 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -64,6 +64,25 @@ ApplicationWindow { height: parent.height } + MouseArea { + anchors.fill: parent + hoverEnabled: true + onPositionChanged: { + playbar.opacity = 1.0 + hidetimer.start() + } + } + + Timer { + id: hidetimer + interval: 5000 + onTriggered: { + playbar.opacity = 0.0 + settings.visible = false + stop() + } + } + FileDialog { id: fileDialog //nameFilters: [TODO globs from mime types] @@ -94,26 +113,6 @@ ApplicationWindow { height: 40//childrenRect.height + 20 radius: 5 - MouseArea { - id: mousearea - anchors.fill: parent - hoverEnabled: true - onEntered: { - parent.opacity = 1.0 - hidetimer.start() - } - } - - Timer { - id: hidetimer - interval: 10000 - onTriggered: { - parent.opacity = 0.0 - settings.visible = false - stop() - } - } - Rectangle { id: settings width: 150; height: settingsView.contentHeight -- cgit v1.2.3 From 5dbeabcb760b1c168ffb27cfc386e4fc7ba6da0b Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Tue, 27 Oct 2015 17:32:27 +0800 Subject: playback/player: qt: consistent use of pixel sizes See #124. We should switch everything to be device independent at some point, but this at least gives us a consistent UI for the time being. --- playback/player/qt/main.qml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index d06b0d4..9b4d59d 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -144,12 +144,12 @@ ApplicationWindow { width: 150; height: 20 Text { text: model.name - font.pointSize: 13 + font.pixelSize: 13 anchors.centerIn: parent } Text { - font.pointSize: 13 + font.pixelSize: 13 font.family: "FontAwesome" text: FontAwesome.Icon.ChevronRight anchors.right: parent.right @@ -205,7 +205,7 @@ ApplicationWindow { width: 150; height: 20 Text { text: model.modelData.resolution.width + 'x' + model.modelData.resolution.height - font.pointSize: 13 + font.pixelSize: 13 anchors.centerIn: parent } @@ -255,7 +255,7 @@ ApplicationWindow { width: 150; height: 20 Text { text: model.modelData.channels + 'channels' - font.pointSize: 13 + font.pixelSize: 13 anchors.centerIn: parent } @@ -305,7 +305,7 @@ ApplicationWindow { width: 150; height: 20 Text { text: model.modelData.language - font.pointSize: 13 + font.pixelSize: 13 anchors.centerIn: parent } @@ -344,7 +344,7 @@ ApplicationWindow { Text { id : openmedia - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: FontAwesome.Icon.FolderOpen @@ -360,7 +360,7 @@ ApplicationWindow { Text { anchors.centerIn: parent - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: FontAwesome.Icon.StepBackward } @@ -382,7 +382,7 @@ ApplicationWindow { PropertyChanges { target: playbutton text: FontAwesome.Icon.PlayCircle - font.pointSize: 25 + font.pixelSize: 25 } }, State { @@ -390,7 +390,7 @@ ApplicationWindow { PropertyChanges { target: playbutton text: FontAwesome.Icon.Pause - font.pointSize: 17 + font.pixelSize: 17 } } ] @@ -417,7 +417,7 @@ ApplicationWindow { Text { anchors.centerIn: parent - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: FontAwesome.Icon.StepForward } @@ -429,7 +429,7 @@ ApplicationWindow { Text { id: timelabel anchors.centerIn: parent - font.pointSize: 13 + font.pixelSize: 13 color: "black" text: { var current = new Date(Math.floor(slider.value / 1e6)); @@ -445,7 +445,7 @@ ApplicationWindow { anchors.centerIn: parent width: parent.width text: player.mediaInfo.title - font.pointSize: 15 + font.pixelSize: 15 elide: Text.ElideRight } } @@ -456,7 +456,7 @@ ApplicationWindow { Text { id: durationlabel anchors.centerIn: parent - font.pointSize: 13 + font.pixelSize: 13 color: "black" text: { var duration = new Date(Math.floor(player.duration / 1e6)); @@ -467,7 +467,7 @@ ApplicationWindow { Text { id: sub - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: FontAwesome.Icon.ClosedCaptions color: player.subtitleEnabled ? "red" : "black" @@ -487,7 +487,7 @@ ApplicationWindow { Text { id : volume anchors.centerIn: parent - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: { if (volumeslider.value > volumeslider.maximumValue / 2) { @@ -585,7 +585,7 @@ ApplicationWindow { Text { id: cog - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: FontAwesome.Icon.Cog @@ -604,7 +604,7 @@ ApplicationWindow { Text { id : fullscreen - font.pointSize: 17 + font.pixelSize: 17 font.family: "FontAwesome" text: FontAwesome.Icon.ResizeFull @@ -661,7 +661,7 @@ ApplicationWindow { x: sliderMouseArea.mouseX Text { - font.pointSize: 13 + font.pixelSize: 13 color: "black" anchors.centerIn: parent text: { -- cgit v1.2.3 From d0bc1108365b7c85298dde848e7442e4a6ad5bbc Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Wed, 28 Oct 2015 00:43:03 +0800 Subject: playback/player: qt: add a destructor and release resources Fixes #129 --- playback/player/qt/qgstplayer.cpp | 9 +++++++++ playback/player/qt/qgstplayer.h | 1 + 2 files changed, 10 insertions(+) diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index ab140f3..3aae93d 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -359,6 +359,15 @@ Player::Player(QObject *parent, VideoRenderer *renderer) gst_player_set_subtitle_track_enabled(player_, false); } +Player::~Player() +{ + if (player_) { + g_signal_handlers_disconnect_by_data(player_, this); + gst_player_stop(player_); + g_object_unref(player_); + } +} + void Player::onStateChanged(Player * player, GstPlayerState state) { diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index f5d4ab8..c060bc9 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -62,6 +62,7 @@ class Player : public QObject public: explicit Player(QObject *parent = 0, VideoRenderer *renderer = 0); + virtual ~Player(); typedef GstPlayerError Error; enum State { -- cgit v1.2.3 From afd72fe79efc720395ff9b80782c0f003f238214 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 27 Oct 2015 19:01:58 +0200 Subject: playback/player: qt: Return a new reference to the renderer from VideoRenderer::renderer() gst_player_new_full() takes ownership of it, and that's where it is usually used. Without this we would create assertions on application shutdown. Fixes #129 --- playback/player/qt/qgstplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index 3aae93d..4fcc975 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -567,7 +567,7 @@ void Player::setPosition(qint64 pos) GstPlayerVideoRenderer *VideoRenderer::renderer() { - return renderer_; + return static_cast (gst_object_ref (renderer_)); } VideoRenderer::VideoRenderer() -- cgit v1.2.3 From a8f242d48c9771fb86e5909f18b1de51ade45e28 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sat, 31 Oct 2015 11:09:27 +0800 Subject: playback/player: qt: do not hide playbar if it contains cursor --- playback/player/qt/main.qml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index 9b4d59d..8e56328 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -77,8 +77,10 @@ ApplicationWindow { id: hidetimer interval: 5000 onTriggered: { - playbar.opacity = 0.0 - settings.visible = false + if (!playbarMouseArea.containsMouse) { + playbar.opacity = 0.0 + settings.visible = false + } stop() } } @@ -101,6 +103,8 @@ ApplicationWindow { source: "fonts/fontawesome-webfont.ttf" } + + Rectangle { id : playbar color: Qt.rgba(1, 1, 1, 0.7) @@ -112,6 +116,13 @@ ApplicationWindow { width : grid.width + 20 height: 40//childrenRect.height + 20 radius: 5 + focus: true + + MouseArea { + id: playbarMouseArea + anchors.fill: parent + hoverEnabled: true + } Rectangle { id: settings -- cgit v1.2.3 From 736ba935187d8973f93fbb8fe06bc43f7e96eff5 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sun, 1 Nov 2015 11:24:31 +0800 Subject: playback/player: qt: seek while dragging seek bar removed time label on top the seek bar, should be placed elsewhere --- playback/player/qt/main.qml | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index 8e56328..322bd01 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -644,9 +644,14 @@ ApplicationWindow { maximumValue: player.duration value: player.position onPressedChanged: player.seek(value) + onValueChanged: { + if (pressed) + player.seek(value) + } enabled: player.mediaInfo.seekable anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter + updateValueWhileDragging: true MouseArea { id: sliderMouseArea @@ -662,27 +667,6 @@ ApplicationWindow { onPressAndHold: mouse.accepted = false; } - Rectangle { - id: hoveredcliptime - width: 40 - height: 17 - color: "lightgray" - anchors.verticalCenter: parent.verticalCenter - visible: sliderMouseArea.containsMouse - x: sliderMouseArea.mouseX - - Text { - font.pixelSize: 13 - color: "black" - anchors.centerIn: parent - text: { - var value = (sliderMouseArea.mouseX - slider.x) * player.duration / (slider.width - slider.x) - var date = new Date(Math.floor(value / 1e6)); - date.getMinutes() + ":" + ('0' + date.getSeconds()).slice(-2) - } - } - } - style: SliderStyle { groove: Item { implicitWidth: playbar.width -- cgit v1.2.3 From 16a9b70155d25c7e32b22e816c04369009ce07ff Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sun, 1 Nov 2015 16:27:13 +0800 Subject: playback/player: qt: add autoPlay property When set to true will play current media set immediately, and if set to false will show first frame (i.e. go to pause state) --- playback/player/qt/qgstplayer.cpp | 17 +++++++++++++++++ playback/player/qt/qgstplayer.h | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index 4fcc975..8117b74 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -340,6 +340,7 @@ Player::Player(QObject *parent, VideoRenderer *renderer) , mediaInfo_() , videoAvailable_(false) , subtitleEnabled_(false) + , autoPlay_(false) { player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, @@ -443,9 +444,25 @@ Player::onMediaInfoUpdated(Player *player, GstPlayerMediaInfo *media_info) emit player->mediaInfoChanged(); } + +bool Player::autoPlay() const +{ + return autoPlay_; +} + +void Player::setAutoPlay(bool auto_play) +{ + autoPlay_ = auto_play; + + if (autoPlay_) { + connect(this, SIGNAL(endOfStream()), SLOT(next())); + } +} + QUrl Player::source() const { Q_ASSERT(player_ != 0); + QString url = QString::fromLocal8Bit(gst_player_get_uri(player_)); return QUrl(url); diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index c060bc9..afbefd4 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -57,6 +57,7 @@ class Player : public QObject Q_PROPERTY(QVariant currentSubtitle READ currentSubtitle WRITE setCurrentSubtitle) Q_PROPERTY(bool subtitleEnabled READ isSubtitleEnabled WRITE setSubtitleEnabled NOTIFY subtitleEnabledChanged) + Q_PROPERTY(bool autoPlay READ autoPlay WRITE setAutoPlay) Q_ENUMS(State) @@ -89,12 +90,11 @@ public: QVariant currentSubtitle() const; bool isSubtitleEnabled() const; quint32 positionUpdateInterval() const; - + bool autoPlay() const; signals: void stateChanged(State new_state); void bufferingChanged(int percent); - void enfOfStream(); void positionUpdated(qint64 new_position); void durationChanged(qint64 duration); void resolutionChanged(QSize resolution); @@ -119,6 +119,7 @@ public slots: void setCurrentSubtitle(QVariant track); void setSubtitleEnabled(bool enabled); void setPositionUpdateInterval(quint32 interval); + void setAutoPlay(bool auto_play); private: Q_DISABLE_COPY(Player) @@ -137,6 +138,7 @@ private: MediaInfo *mediaInfo_; bool videoAvailable_; bool subtitleEnabled_; + bool autoPlay_; }; class VideoRenderer -- cgit v1.2.3 From 1cebdf926c8f9a06f31fc7dc8a6f5cee9d4bc392 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sun, 1 Nov 2015 16:30:43 +0800 Subject: playback/player: qt: add simple playlist support and wire buttons --- playback/player/qt/main.qml | 12 +++++++ playback/player/qt/qgstplayer.cpp | 68 +++++++++++++++++++++++++++++++++++++-- playback/player/qt/qgstplayer.h | 14 +++++++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index 322bd01..15a8292 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -43,6 +43,8 @@ ApplicationWindow { objectName: "player" volume: 0.5 positionUpdateInterval: 100 + autoPlay: false + onStateChanged: { if (state === Player.STOPPED) { playbutton.state = "play" @@ -375,6 +377,11 @@ ApplicationWindow { font.family: "FontAwesome" text: FontAwesome.Icon.StepBackward } + + MouseArea { + anchors.fill: parent + onPressed: player.previous() + } } Item { @@ -432,6 +439,11 @@ ApplicationWindow { font.family: "FontAwesome" text: FontAwesome.Icon.StepForward } + + MouseArea { + anchors.fill: parent + onPressed: player.next() + } } Item { diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index 8117b74..8c350d5 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -354,7 +354,8 @@ Player::Player(QObject *parent, VideoRenderer *renderer) "swapped-signal::video-dimensions-changed", G_CALLBACK (Player::onVideoDimensionsChanged), this, "swapped-signal::volume-changed", G_CALLBACK (Player::onVolumeChanged), this, "swapped-signal::mute-changed", G_CALLBACK (Player::onMuteChanged), this, - "swapped-signal::media-info-updated", G_CALLBACK (Player::onMediaInfoUpdated), this, NULL); + "swapped-signal::media-info-updated", G_CALLBACK (Player::onMediaInfoUpdated), this, + "swapped-signal::end-of-stream", G_CALLBACK (Player::onEndOfStreamReached), this, NULL); mediaInfo_ = new MediaInfo(this); gst_player_set_subtitle_track_enabled(player_, false); @@ -444,6 +445,63 @@ Player::onMediaInfoUpdated(Player *player, GstPlayerMediaInfo *media_info) emit player->mediaInfoChanged(); } +void Player::onEndOfStreamReached(Player *player) +{ + Q_ASSERT(player != 0); + + emit player->endOfStream(); +} + +void Player::setUri(QUrl url) +{ + Q_ASSERT(player_ != 0); + QByteArray uri = url.toString().toLocal8Bit(); + + gst_player_set_uri(player_, uri.data()); + + autoPlay_ ? play() : pause(); + + emit sourceChanged(url); +} + +QList Player::playlist() const +{ + return playlist_; +} + +void Player::setPlaylist(const QList &playlist) +{ + if (!playlist_.isEmpty()) { + playlist_.erase(playlist_.begin(), playlist_.end()); + } + + playlist_ = playlist; + + iter_ = playlist_.begin(); + setUri(*iter_); +} + +void Player::next() +{ + if (playlist_.isEmpty()) + return; + + if (iter_ == playlist_.end()) + return; + + setUri(*++iter_); +} + +void Player::previous() +{ + if (playlist_.isEmpty()) + return; + + if (iter_ == playlist_.begin()) + return; + + setUri(*--iter_); +} bool Player::autoPlay() const { @@ -554,9 +612,13 @@ void Player::seek(qint64 position) void Player::setSource(QUrl const& url) { Q_ASSERT(player_ != 0); - QByteArray uri = url.toString().toLocal8Bit(); - gst_player_set_uri(player_, uri.data()); + // discard playlist + if (!playlist_.isEmpty()) { + playlist_.erase(playlist_.begin(), playlist_.end()); + } + + setUri(url); emit sourceChanged(url); } diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index afbefd4..c41f66c 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -25,7 +25,8 @@ #include #include //#include -#include +#include +#include #include namespace QGstPlayer { @@ -58,6 +59,7 @@ class Player : public QObject Q_PROPERTY(bool subtitleEnabled READ isSubtitleEnabled WRITE setSubtitleEnabled NOTIFY subtitleEnabledChanged) Q_PROPERTY(bool autoPlay READ autoPlay WRITE setAutoPlay) + Q_PROPERTY(QList playlist READ playlist WRITE setPlaylist) Q_ENUMS(State) @@ -91,10 +93,12 @@ public: bool isSubtitleEnabled() const; quint32 positionUpdateInterval() const; bool autoPlay() const; + QList playlist() const; signals: void stateChanged(State new_state); void bufferingChanged(int percent); + void endOfStream(); void positionUpdated(qint64 new_position); void durationChanged(qint64 duration); void resolutionChanged(QSize resolution); @@ -119,6 +123,9 @@ public slots: void setCurrentSubtitle(QVariant track); void setSubtitleEnabled(bool enabled); void setPositionUpdateInterval(quint32 interval); + void setPlaylist(const QList &playlist); + void next(); + void previous(); void setAutoPlay(bool auto_play); private: @@ -131,6 +138,9 @@ private: static void onVolumeChanged(Player *); static void onMuteChanged(Player *); static void onMediaInfoUpdated(Player *, GstPlayerMediaInfo *media_info); + static void onEndOfStreamReached(Player *); + + void setUri(QUrl url); GstPlayer *player_; State state_; @@ -139,6 +149,8 @@ private: bool videoAvailable_; bool subtitleEnabled_; bool autoPlay_; + QList playlist_; + QList::iterator iter_; }; class VideoRenderer -- cgit v1.2.3 From 8853575547c58e379e1fff17858147fc19039c5f Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Sun, 1 Nov 2015 16:32:55 +0800 Subject: playback/player: qt: accept a list of uris or files as command line parameters --- playback/player/qt/main.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/playback/player/qt/main.cpp b/playback/player/qt/main.cpp index 5634732..999ddcb 100644 --- a/playback/player/qt/main.cpp +++ b/playback/player/qt/main.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include +#include #include "player.h" @@ -27,6 +30,20 @@ int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); + QCommandLineParser parser; + parser.setApplicationDescription("GstPlayer"); + parser.addHelpOption(); + parser.addPositionalArgument("urls", + QCoreApplication::translate("main", "URLs to play, optionally."), "[urls...]"); + parser.process(app); + + QList media_files; + + const QStringList args = parser.positionalArguments(); + foreach (const QString file, args) { + media_files << QUrl::fromUserInput(file); + } + qmlRegisterType("Player", 1, 0, "Player"); /* the plugin must be loaded before loading the qml file to register the @@ -44,9 +61,12 @@ int main(int argc, char *argv[]) QObject *rootObject = engine.rootObjects().first(); Player *player = rootObject->findChild("player"); + QQuickItem *videoItem = rootObject->findChild("videoItem"); player->setVideoOutput(videoItem); + if (!media_files.isEmpty()) + player->setPlaylist(media_files); return app.exec(); } -- cgit v1.2.3 From e4ae2c3c7bfe14e58e2b73f0c20743dd7ba4bbc2 Mon Sep 17 00:00:00 2001 From: Alexandre Moreno Date: Mon, 2 Nov 2015 01:48:08 +0800 Subject: playback/player: qt: add new qml item to render media info sample when video is not available it will try to display the sample image returned by media info object. --- playback/player/qt/imagesample.cpp | 61 ++++++++++++++++++++++++++++++++++++++ playback/player/qt/imagesample.h | 46 ++++++++++++++++++++++++++++ playback/player/qt/main.cpp | 2 ++ playback/player/qt/main.qml | 12 ++++++++ playback/player/qt/play.pro | 6 ++-- playback/player/qt/qgstplayer.cpp | 54 +++++++++++++++++++++++++++++++++ playback/player/qt/qgstplayer.h | 6 ++++ 7 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 playback/player/qt/imagesample.cpp create mode 100644 playback/player/qt/imagesample.h diff --git a/playback/player/qt/imagesample.cpp b/playback/player/qt/imagesample.cpp new file mode 100644 index 0000000..94c07d4 --- /dev/null +++ b/playback/player/qt/imagesample.cpp @@ -0,0 +1,61 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include "imagesample.h" + +ImageSample::ImageSample() + : QQuickPaintedItem() + , sample_() +{ + +} + +ImageSample::~ImageSample() +{ + +} + +void ImageSample::paint(QPainter *painter) +{ + if (sample_.size().isEmpty()) + return; + + float aspect_ratio = sample_.width() / sample_.height(); + int w = height() * aspect_ratio; + int x = (width() - w) / 2; + + painter->setViewport(x, 0, w, height()); + painter->drawImage(QRectF(0, 0, width(), height()), sample_); +} + +const QImage &ImageSample::sample() const +{ + return sample_; +} + +void ImageSample::setSample(const QImage &sample) +{ + sample_ = sample; + update(); +} + + + diff --git a/playback/player/qt/imagesample.h b/playback/player/qt/imagesample.h new file mode 100644 index 0000000..917bb24 --- /dev/null +++ b/playback/player/qt/imagesample.h @@ -0,0 +1,46 @@ +/* GStreamer + * + * Copyright (C) 2015 Alexandre Moreno + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef IMAGESAMPLE_H +#define IMAGESAMPLE_H + +#include +#include +#include +#include +#include "player.h" + +class ImageSample : public QQuickPaintedItem +{ + Q_OBJECT + Q_PROPERTY(QImage sample READ sample WRITE setSample) +public: + ImageSample(); + ~ImageSample(); + void paint(QPainter *painter); + + const QImage &sample() const; + void setSample(const QImage &sample); + +private: + QImage sample_; +}; + +#endif // IMAGESAMPLE_H diff --git a/playback/player/qt/main.cpp b/playback/player/qt/main.cpp index 999ddcb..4ef6b64 100644 --- a/playback/player/qt/main.cpp +++ b/playback/player/qt/main.cpp @@ -25,6 +25,7 @@ #include #include "player.h" +#include "imagesample.h" int main(int argc, char *argv[]) { @@ -45,6 +46,7 @@ int main(int argc, char *argv[]) } qmlRegisterType("Player", 1, 0, "Player"); + qmlRegisterType("ImageSample", 1, 0, "ImageSample"); /* the plugin must be loaded before loading the qml file to register the * GstGLVideoItem qml item diff --git a/playback/player/qt/main.qml b/playback/player/qt/main.qml index 15a8292..ce1cf8f 100644 --- a/playback/player/qt/main.qml +++ b/playback/player/qt/main.qml @@ -25,6 +25,7 @@ import QtQuick.Dialogs 1.2 import QtQuick.Window 2.1 import Player 1.0 import org.freedesktop.gstreamer.GLVideoItem 1.0 +import ImageSample 1.0 import "fontawesome.js" as FontAwesome @@ -50,6 +51,7 @@ ApplicationWindow { playbutton.state = "play" } } + onResolutionChanged: { if (player.videoAvailable) { window.width = resolution.width @@ -64,6 +66,16 @@ ApplicationWindow { anchors.centerIn: parent width: parent.width height: parent.height + visible: player.videoAvailable + } + + ImageSample { + id: sample + anchors.centerIn: parent + sample: player.mediaInfo.sample + width: parent.width + height: parent.height + visible: !player.videoAvailable } MouseArea { diff --git a/playback/player/qt/play.pro b/playback/player/qt/play.pro index c8b2954..d16440c 100644 --- a/playback/player/qt/play.pro +++ b/playback/player/qt/play.pro @@ -41,13 +41,15 @@ macx { HEADERS += \ qgstplayer.h \ player.h \ - quickrenderer.h + quickrenderer.h \ + imagesample.h SOURCES += main.cpp \ qgstplayer.cpp \ ../lib/gst/player/gstplayer.c \ ../lib/gst/player/gstplayer-media-info.c \ player.cpp \ - quickrenderer.cpp + quickrenderer.cpp \ + imagesample.cpp DISTFILES += diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index 8c350d5..b15347f 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -25,6 +25,10 @@ #include #include #include +#include + +#include +#include namespace QGstPlayer { @@ -43,6 +47,10 @@ MediaInfo::MediaInfo(Player *player) , uri_() , title_() , isSeekable_(false) + , videoStreams_() + , audioStreams_() + , subtitleStreams_() + , sample_() { } @@ -77,6 +85,11 @@ const QList &MediaInfo::subtitleStreams() const return subtitleStreams_; } +const QImage &MediaInfo::sample() +{ + return sample_; +} + void MediaInfo::update(GstPlayerMediaInfo *info) { Q_ASSERT(info != 0); @@ -146,6 +159,47 @@ void MediaInfo::update(GstPlayerMediaInfo *info) audios->append(new AudioInfo(info)); }, &audioStreams_); + + GstSample *sample; + GstMapInfo map_info; + GstBuffer *buffer; + const GstStructure *caps_struct; + GstTagImageType type = GST_TAG_IMAGE_TYPE_UNDEFINED; + + /* get image sample buffer from media */ + sample = gst_player_media_info_get_image_sample (info); + if (!sample) + return; + + buffer = gst_sample_get_buffer (sample); + caps_struct = gst_sample_get_info (sample); + + /* if sample is retrieved from preview-image tag then caps struct + * will not be defined. */ + if (caps_struct) + gst_structure_get_enum (caps_struct, "image-type", + GST_TYPE_TAG_IMAGE_TYPE, reinterpret_cast(&type)); + + /* FIXME: Should we check more type ?? */ + if ((type != GST_TAG_IMAGE_TYPE_FRONT_COVER) && + (type != GST_TAG_IMAGE_TYPE_UNDEFINED) && + (type != GST_TAG_IMAGE_TYPE_NONE)) { + g_print ("unsupport type ... %d \n", type); + return; + } + + if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) { + g_print ("failed to map gst buffer \n"); + return; + } + + sample_ = QImage::fromData(map_info.data, map_info.size); + if (sample_.isNull()) + qWarning() << "failed to load media info sample image"; + + emit sampleChanged(); + + gst_buffer_unmap (buffer, &map_info); } VideoInfo::VideoInfo(GstPlayerVideoInfo *info) diff --git a/playback/player/qt/qgstplayer.h b/playback/player/qt/qgstplayer.h index c41f66c..8ff87d1 100644 --- a/playback/player/qt/qgstplayer.h +++ b/playback/player/qt/qgstplayer.h @@ -27,6 +27,7 @@ //#include #include #include +#include #include namespace QGstPlayer { @@ -174,6 +175,7 @@ class MediaInfo : public QObject Q_PROPERTY(QList videoStreams READ videoStreams CONSTANT) Q_PROPERTY(QList audioStreams READ audioStreams CONSTANT) Q_PROPERTY(QList subtitleStreams READ subtitleStreams CONSTANT) + Q_PROPERTY(QImage sample READ sample NOTIFY sampleChanged) public: explicit MediaInfo(Player *player = 0); @@ -183,11 +185,13 @@ public: const QList &videoStreams() const; const QList &audioStreams() const; const QList &subtitleStreams() const; + const QImage &sample(); signals: void uriChanged(); void seekableChanged(); void titleChanged(); + void sampleChanged(); public Q_SLOTS: void update(GstPlayerMediaInfo *info); @@ -198,6 +202,7 @@ private: QList videoStreams_; QList audioStreams_; QList subtitleStreams_; + QImage sample_; }; class StreamInfo : public QObject @@ -267,6 +272,7 @@ private: Q_DECLARE_METATYPE(QGstPlayer::Player*) Q_DECLARE_METATYPE(QGstPlayer::Player::State) +Q_DECLARE_METATYPE(QGstPlayer::MediaInfo*) extern "C" { -- cgit v1.2.3 From 6cc6793d1f44805a3c10b25c2539c09ee58acf4b Mon Sep 17 00:00:00 2001 From: Justin Kim Date: Wed, 4 Nov 2015 19:59:23 +0900 Subject: playback/player: gtk-play: change print format of guint64 guint64 type usually corresponds with 'G_GUINT64_FORMAT'. --- playback/player/gtk/gtk-play.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 6815b3d..0e6ac76 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1521,9 +1521,9 @@ update_position_label (GtkLabel * label, guint64 seconds) seconds -= mins * 60; if (hrs) - data = g_strdup_printf ("%d:%02d:%02ld", hrs, mins, seconds); + data = g_strdup_printf ("%d:%02d:%02" G_GUINT64_FORMAT, hrs, mins, seconds); else - data = g_strdup_printf ("%02d:%02ld", mins, seconds); + data = g_strdup_printf ("%02d:%02" G_GUINT64_FORMAT, mins, seconds); gtk_label_set_label (label, data); g_free (data); -- cgit v1.2.3 From 9ffdefc14f2f3877fe4eb2b51595fc618b40ff70 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 6 Nov 2015 11:03:56 +0100 Subject: playback/player: Revert "README.md formatting." This reverts commit 499f68c42371081204b6285227073a7eb165c652. The gradle based build system has various problems currently. --- playback/player/android/README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/playback/player/android/README.md b/playback/player/android/README.md index 2f8318f..cf331f7 100644 --- a/playback/player/android/README.md +++ b/playback/player/android/README.md @@ -9,16 +9,10 @@ Prerequisites 3. If you have a different special directory for pkg-config or other tools (e.g. on OSX when using Homebrew), then also set this path using the `ndk.extraPath` variable in **local.properties** 4. Download the GStreamer android ports http://gstreamer.freedesktop.org/data/pkg/android/ and set `gstreamer.$ABI.dir` properties in **local.properties**: -Sample local.properties: - - sdk.dir=/path/to/android-sdk/ - ndk.dir=/path/to/android-ndk/ - ndk.extraPath=/usr/local/bin gstreamer.arm.dir=/path/to/gstreamer-1.0-android-arm-release-1.4.5/ gstreamer.armv7.dir=/path/to/gstreamer-1.0-android-armv7-release-1.4.5/ gstreamer.x86.dir=/path/to/gstreamer-1.0-android-x86-release-1.4.5/ - Compiling the sample -------------------- @@ -53,4 +47,4 @@ If you don't want to build all architectures, please modify the file `app/src/ma Finally, within the `app/src/main/` directory, invoke: - ndk-build + ndk-build \ No newline at end of file -- cgit v1.2.3 From 9d8f476174408789fb42f03300425678decb8e5b Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 6 Nov 2015 11:04:14 +0100 Subject: playback/player: Revert "android: Fix Windows build of the app" This reverts commit 5d8c1868beec85ac02bcc6e0bfd0ad9dbb99a3b8. The gradle based build system has various problems currently. --- playback/player/android/app/build.gradle | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/playback/player/android/app/build.gradle b/playback/player/android/app/build.gradle index 18e68bd..6039b5b 100644 --- a/playback/player/android/app/build.gradle +++ b/playback/player/android/app/build.gradle @@ -1,5 +1,3 @@ -import org.apache.tools.ant.taskdefs.condition.Os - apply plugin: 'com.android.application' android { @@ -59,12 +57,7 @@ android { environment PATH: "${System.getenv("PATH")}${File.pathSeparator}${ndkExtraPath}" } - // Enable V=1 for debugging messages. - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine "${ndkDir}/ndk-build.cmd", '-C', file('src/main/jni').absolutePath //, 'V=1' - } else { - commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' - } + commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' // Enable V=1 for debugging messages. } } -- cgit v1.2.3 From 1d5a020a034276e270e4b54dbd2e6e4020b0abe7 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 6 Nov 2015 11:04:17 +0100 Subject: playback/player: Revert "android: Use gradle & ndk-build combo to generate the Android App" This reverts commit a95ee9c61c371ec2b8d4ff59cace26451b11225a. The gradle based build system has various problems currently. --- playback/player/android/AndroidManifest.xml | 79 ++++ playback/player/android/Makefile.am | 32 +- playback/player/android/README.md | 50 --- playback/player/android/app/app.iml | 97 ---- playback/player/android/app/build.gradle | 68 --- .../android/app/src/main/AndroidManifest.xml | 97 ---- .../java/org/freedesktop/gstreamer/Player.java | 241 ---------- .../gstreamer/play/GStreamerSurfaceView.java | 105 ----- .../java/org/freedesktop/gstreamer/play/Play.java | 196 -------- .../freedesktop/gstreamer/play/VideoSelector.java | 151 ------- .../player/android/app/src/main/jni/Android.mk | 32 -- .../player/android/app/src/main/jni/Application.mk | 2 - playback/player/android/app/src/main/jni/player.c | 496 --------------------- .../app/src/main/res/layout/activity_player.xml | 70 --- .../main/res/layout/activity_video_selector.xml | 15 - .../app/src/main/res/menu/menu_video_selector.xml | 17 - .../app/src/main/res/values-w820dp/dimens.xml | 6 - .../android/app/src/main/res/values/dimens.xml | 5 - .../android/app/src/main/res/values/strings.xml | 9 - .../android/app/src/main/res/values/styles.xml | 7 - playback/player/android/build.gradle | 15 - playback/player/android/build.xml | 92 ++++ .../android/gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - playback/player/android/gradlew | 164 ------- playback/player/android/gradlew.bat | 90 ---- playback/player/android/jni/Android.mk | 25 ++ playback/player/android/jni/player.c | 496 +++++++++++++++++++++ playback/player/android/res/layout/main.xml | 62 +++ playback/player/android/res/values/strings.xml | 6 + playback/player/android/settings.gradle | 1 - .../src/org/freedesktop/gstreamer/Player.java | 241 ++++++++++ .../gstreamer/player/GStreamerSurfaceView.java | 105 +++++ .../src/org/freedesktop/gstreamer/player/Play.java | 196 ++++++++ 34 files changed, 1311 insertions(+), 1963 deletions(-) create mode 100644 playback/player/android/AndroidManifest.xml delete mode 100644 playback/player/android/README.md delete mode 100644 playback/player/android/app/app.iml delete mode 100644 playback/player/android/app/build.gradle delete mode 100644 playback/player/android/app/src/main/AndroidManifest.xml delete mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java delete mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java delete mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java delete mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java delete mode 100644 playback/player/android/app/src/main/jni/Android.mk delete mode 100644 playback/player/android/app/src/main/jni/Application.mk delete mode 100644 playback/player/android/app/src/main/jni/player.c delete mode 100644 playback/player/android/app/src/main/res/layout/activity_player.xml delete mode 100644 playback/player/android/app/src/main/res/layout/activity_video_selector.xml delete mode 100644 playback/player/android/app/src/main/res/menu/menu_video_selector.xml delete mode 100644 playback/player/android/app/src/main/res/values-w820dp/dimens.xml delete mode 100644 playback/player/android/app/src/main/res/values/dimens.xml delete mode 100644 playback/player/android/app/src/main/res/values/strings.xml delete mode 100644 playback/player/android/app/src/main/res/values/styles.xml delete mode 100644 playback/player/android/build.gradle create mode 100644 playback/player/android/build.xml delete mode 100644 playback/player/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 playback/player/android/gradle/wrapper/gradle-wrapper.properties delete mode 100755 playback/player/android/gradlew delete mode 100644 playback/player/android/gradlew.bat create mode 100644 playback/player/android/jni/Android.mk create mode 100644 playback/player/android/jni/player.c create mode 100644 playback/player/android/res/layout/main.xml create mode 100644 playback/player/android/res/values/strings.xml delete mode 100644 playback/player/android/settings.gradle create mode 100644 playback/player/android/src/org/freedesktop/gstreamer/Player.java create mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java create mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/Play.java diff --git a/playback/player/android/AndroidManifest.xml b/playback/player/android/AndroidManifest.xml new file mode 100644 index 0000000..8b156d4 --- /dev/null +++ b/playback/player/android/AndroidManifest.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/Makefile.am b/playback/player/android/Makefile.am index e9e4c74..2664abb 100644 --- a/playback/player/android/Makefile.am +++ b/playback/player/android/Makefile.am @@ -1,24 +1,10 @@ EXTRA_DIST = \ - build.gradle \ - gradlew \ - gradlew.bat \ - README.md \ - settings.gradle \ - app/build.gradle \ - app/src/main/AndroidManifest.xml \ - app/src/main/java/org/freedesktop/gstreamer/Player.java \ - app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ - app/src/main/java/org/freedesktop/gstreamer/player/Play.java \ - app/src/main/java/org/freedesktop/gstreamer/player/VideoSelector.java \ - app/src/main/jni/Android.mk \ - app/src/main/jni/Application.mk \ - app/src/main/jni/player.c \ - app/src/main/res/layout/activity_player.xml \ - app/src/main/res/layout/activity_video_selector.xml \ - app/src/main/res/menu/menu_video_selector.xml \ - app/src/main/res/values/dimens.xml \ - app/src/main/res/values/strings.xml \ - app/src/main/res/values/styles.xml \ - app/src/main/res/values-w820dp/styles.xml \ - gradle/wrapper/gradle-wrapper.jar \ - gradle/wrapper/gradle-wrapper.properties \ No newline at end of file + AndroidManifest.xml \ + jni/Android.mk \ + jni/player.c \ + res/layout/main.xml \ + res/values/strings.xml \ + src/org/freedesktop/gstreamer/Player.java \ + src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ + src/org/freedesktop/gstreamer/player/Play.java + diff --git a/playback/player/android/README.md b/playback/player/android/README.md deleted file mode 100644 index cf331f7..0000000 --- a/playback/player/android/README.md +++ /dev/null @@ -1,50 +0,0 @@ -GST Player Android port -======================= - -Prerequisites -------------- - -1. Install Android SDK from https://developer.android.com/sdk/ & set `sdk.dir` in **local.properties** to the installation path -2. Install Android NDK from https://developer.android.com/tools/sdk/ndk/index.html & set `ndk.dir` in **local.properties** to the installation path -3. If you have a different special directory for pkg-config or other tools (e.g. on OSX when using Homebrew), then also set this path using the `ndk.extraPath` variable in **local.properties** -4. Download the GStreamer android ports http://gstreamer.freedesktop.org/data/pkg/android/ and set `gstreamer.$ABI.dir` properties in **local.properties**: - - gstreamer.arm.dir=/path/to/gstreamer-1.0-android-arm-release-1.4.5/ - gstreamer.armv7.dir=/path/to/gstreamer-1.0-android-armv7-release-1.4.5/ - gstreamer.x86.dir=/path/to/gstreamer-1.0-android-x86-release-1.4.5/ - -Compiling the sample --------------------- - -Use - - ./gradlew installDebug - -to compile and install a debug version onto all connected devices. - -Please note this component is using the new Android build system based on Gradle. More information about this is available on http://tools.android.com/tech-docs/new-build-system. - -Android Studio --------------- - -Android Studio builds will work out of the box. Simply open `build.gradle` in this folder to import the project. - -Manual NDK build ----------------- - -It is still possible to build just the NDK portion. This will speed up the process a bit as you don't need to start gradle first and compile the complete App. -First, make sure to set `NDK_PROJECT_PATH` to this projects main source path. Additionally the SDK & NDK tools are available in `$PATH`. - - export NDK_PROJECT_PATH=$PWD/app/src/main - -Second, set the following environment variables to the GStreamer installation folders: - - export GSTREAMER_ROOT_ARM=/path/to/gstreamer-1.0-android-arm-release-1.4.5/ - export GSTREAMER_ROOT_ARMV7=/path/to/tmp/gstreamer-1.0-android-armv7-release-1.4.5/ - export GSTREAMER_ROOT_X86=/path/to/gstreamer-1.0-android-x86-release-1.4.5/ - -If you don't want to build all architectures, please modify the file `app/src/main/jni/Application.mk` - -Finally, within the `app/src/main/` directory, invoke: - - ndk-build \ No newline at end of file diff --git a/playback/player/android/app/app.iml b/playback/player/android/app/app.iml deleted file mode 100644 index 86e3b56..0000000 --- a/playback/player/android/app/app.iml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/playback/player/android/app/build.gradle b/playback/player/android/app/build.gradle deleted file mode 100644 index 6039b5b..0000000 --- a/playback/player/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" - - defaultConfig { - applicationId "org.freedesktop.gstreamer.play" - minSdkVersion 9 - targetSdkVersion 22 - - ndk { - moduleName "gstplayer" - } - } - - sourceSets { - main { - // GStreamer will generate these files. - java { - srcDir 'src/main/jni/src' - } - assets { - srcDir 'src/main/jni/assets' - } - - //Tell Gradle where to put the compiled shared library - jniLibs.srcDir 'src/main/libs' - - //disable automatic ndk-build call - jni.srcDirs = []; - } - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } - } - - // Thank you http://stackoverflow.com/q/28878689/375209 - tasks.withType(JavaCompile) { - compileTask -> compileTask.dependsOn ndkBuild - } - - task ndkBuild(type: Exec) { - Properties properties = new Properties() - properties.load(project.rootProject.file('local.properties').newDataInputStream()) - def ndkDir = properties.getProperty('ndk.dir') - environment GSTREAMER_ROOT_ARM: properties.getProperty('gstreamer.arm.dir') - environment GSTREAMER_ROOT_ARMV7: properties.getProperty('gstreamer.armv7.dir') - environment GSTREAMER_ROOT_X86: properties.getProperty('gstreamer.x86.dir') - - def ndkExtraPath = properties.getProperty('ndk.extraPath') - if (! "".equalsIgnoreCase(ndkExtraPath)) { - environment PATH: "${System.getenv("PATH")}${File.pathSeparator}${ndkExtraPath}" - } - - commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' // Enable V=1 for debugging messages. - } -} - -dependencies { - compile 'com.android.support:appcompat-v7:22.1.1' - compile "com.android.support:recyclerview-v7:22.1.1" - compile "com.android.support:support-annotations:22.1.1" -} diff --git a/playback/player/android/app/src/main/AndroidManifest.xml b/playback/player/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 6de668c..0000000 --- a/playback/player/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java deleted file mode 100644 index e2bef8c..0000000 --- a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java +++ /dev/null @@ -1,241 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014-2015 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer; - -import java.io.Closeable; -import android.view.Surface; -import android.content.Context; -import org.freedesktop.gstreamer.GStreamer; - -public class Player implements Closeable { - private static native void nativeClassInit(); - public static void init(Context context) throws Exception { - System.loadLibrary("gstreamer_android"); - GStreamer.init(context); - - System.loadLibrary("gstplayer"); - nativeClassInit(); - } - - private long native_player; - private native void nativeNew(); - public Player() { - nativeNew(); - } - - private native void nativeFree(); - @Override - public void close() { - nativeFree(); - } - - private native void nativePlay(); - public void play() { - nativePlay(); - } - - private native void nativePause(); - public void pause() { - nativePause(); - } - - private native void nativeStop(); - public void stop() { - nativeStop(); - } - - private native void nativeSeek(long position); - public void seek(long position) { - nativeSeek(position); - } - - private native String nativeGetUri(); - public String getUri() { - return nativeGetUri(); - } - - private native void nativeSetUri(String uri); - public void setUri(String uri) { - nativeSetUri(uri); - } - - private native long nativeGetPosition(); - public long getPosition() { - return nativeGetPosition(); - } - - private native long nativeGetDuration(); - public long getDuration() { - return nativeGetDuration(); - } - - private native double nativeGetVolume(); - public double getVolume() { - return nativeGetVolume(); - } - - private native void nativeSetVolume(double volume); - public void setVolume(double volume) { - nativeSetVolume(volume); - } - - private native boolean nativeGetMute(); - public boolean getMute() { - return nativeGetMute(); - } - - private native void nativeSetMute(boolean mute); - public void setMute(boolean mute) { - nativeSetMute(mute); - } - - private Surface surface; - private native void nativeSetSurface(Surface surface); - public void setSurface(Surface surface) { - this.surface = surface; - nativeSetSurface(surface); - } - - public Surface getSurface() { - return surface; - } - - public static interface PositionUpdatedListener { - abstract void positionUpdated(Player player, long position); - } - - private PositionUpdatedListener positionUpdatedListener; - public void setPositionUpdatedListener(PositionUpdatedListener listener) { - positionUpdatedListener = listener; - } - - private void onPositionUpdated(long position) { - if (positionUpdatedListener != null) { - positionUpdatedListener.positionUpdated(this, position); - } - } - - public static interface DurationChangedListener { - abstract void durationChanged(Player player, long duration); - } - - private DurationChangedListener durationChangedListener; - public void setDurationChangedListener(DurationChangedListener listener) { - durationChangedListener = listener; - } - - private void onDurationChanged(long duration) { - if (durationChangedListener != null) { - durationChangedListener.durationChanged(this, duration); - } - } - - private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; - public enum State { - STOPPED, - BUFFERING, - PAUSED, - PLAYING - } - - public static interface StateChangedListener { - abstract void stateChanged(Player player, State state); - } - - private StateChangedListener stateChangedListener; - public void setStateChangedListener(StateChangedListener listener) { - stateChangedListener = listener; - } - - private void onStateChanged(int stateIdx) { - if (stateChangedListener != null) { - State state = stateMap[stateIdx]; - stateChangedListener.stateChanged(this, state); - } - } - - public static interface BufferingListener { - abstract void buffering(Player player, int percent); - } - - private BufferingListener bufferingListener; - public void setBufferingListener(BufferingListener listener) { - bufferingListener = listener; - } - - private void onBuffering(int percent) { - if (bufferingListener != null) { - bufferingListener.buffering(this, percent); - } - } - - public static interface EndOfStreamListener { - abstract void endOfStream(Player player); - } - - private EndOfStreamListener endOfStreamListener; - public void setEndOfStreamListener(EndOfStreamListener listener) { - endOfStreamListener = listener; - } - - private void onEndOfStream() { - if (endOfStreamListener != null) { - endOfStreamListener.endOfStream(this); - } - } - - // Keep these in sync with gstplayer.h - private static final Error[] errorMap = {Error.FAILED}; - public enum Error { - FAILED - } - - public static interface ErrorListener { - abstract void error(Player player, Error error, String errorMessage); - } - - private ErrorListener errorListener; - public void setErrorListener(ErrorListener listener) { - errorListener = listener; - } - - private void onError(int errorCode, String errorMessage) { - if (errorListener != null) { - Error error = errorMap[errorCode]; - errorListener.error(this, error, errorMessage); - } - } - - public static interface VideoDimensionsChangedListener { - abstract void videoDimensionsChanged(Player player, int width, int height); - } - - private VideoDimensionsChangedListener videoDimensionsChangedListener; - public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { - videoDimensionsChangedListener = listener; - } - - private void onVideoDimensionsChanged(int width, int height) { - if (videoDimensionsChangedListener != null) { - videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); - } - } -} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java deleted file mode 100644 index f2dd8a9..0000000 --- a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/GStreamerSurfaceView.java +++ /dev/null @@ -1,105 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.SurfaceView; -import android.view.View; - -// A simple SurfaceView whose width and height can be set from the outside -public class GStreamerSurfaceView extends SurfaceView { - public int media_width = 320; - public int media_height = 240; - - // Mandatory constructors, they do not do much - public GStreamerSurfaceView(Context context, AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - } - - public GStreamerSurfaceView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public GStreamerSurfaceView (Context context) { - super(context); - } - - // Called by the layout manager to find out our size and give us some rules. - // We will try to maximize our size, and preserve the media's aspect ratio if - // we are given the freedom to do so. - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = 0, height = 0; - int wmode = View.MeasureSpec.getMode(widthMeasureSpec); - int hmode = View.MeasureSpec.getMode(heightMeasureSpec); - int wsize = View.MeasureSpec.getSize(widthMeasureSpec); - int hsize = View.MeasureSpec.getSize(heightMeasureSpec); - - Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); - // Obey width rules - switch (wmode) { - case View.MeasureSpec.AT_MOST: - if (hmode == View.MeasureSpec.EXACTLY) { - width = Math.min(hsize * media_width / media_height, wsize); - break; - } - case View.MeasureSpec.EXACTLY: - width = wsize; - break; - case View.MeasureSpec.UNSPECIFIED: - width = media_width; - } - - // Obey height rules - switch (hmode) { - case View.MeasureSpec.AT_MOST: - if (wmode == View.MeasureSpec.EXACTLY) { - height = Math.min(wsize * media_height / media_width, hsize); - break; - } - case View.MeasureSpec.EXACTLY: - height = hsize; - break; - case View.MeasureSpec.UNSPECIFIED: - height = media_height; - } - - // Finally, calculate best size when both axis are free - if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { - int correct_height = width * media_height / media_width; - int correct_width = height * media_width / media_height; - - if (correct_height < height) - height = correct_height; - else - width = correct_width; - } - - // Obey minimum size - width = Math.max (getSuggestedMinimumWidth(), width); - height = Math.max (getSuggestedMinimumHeight(), height); - setMeasuredDimension(width, height); - } - -} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java deleted file mode 100644 index 9be9d78..0000000 --- a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/Play.java +++ /dev/null @@ -1,196 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.PowerManager; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; -import android.widget.Toast; - -import org.freedesktop.gstreamer.Player; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -public class Play extends AppCompatActivity implements SurfaceHolder.Callback, OnSeekBarChangeListener { - private PowerManager.WakeLock wake_lock; - private Player player; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - try { - Player.init(this); - } catch (Exception e) { - Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); - finish(); - return; - } - - setContentView(R.layout.activity_player); - - player = new Player(); - - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); - wake_lock.setReferenceCounted(false); - - ImageButton play = (ImageButton) this.findViewById(R.id.button_play); - play.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - player.play(); - wake_lock.acquire(); - } - }); - - ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); - pause.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - player.pause(); - wake_lock.release(); - } - }); - - final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); - sb.setOnSeekBarChangeListener(this); - - player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { - public void positionUpdated(Player player, final long position) { - runOnUiThread(new Runnable() { - public void run() { - sb.setProgress((int) (position / 1000000)); - updateTimeWidget(); - } - }); - } - }); - - player.setDurationChangedListener(new Player.DurationChangedListener() { - public void durationChanged(Player player, final long duration) { - runOnUiThread(new Runnable() { - public void run() { - sb.setMax((int) (duration / 1000000)); - updateTimeWidget(); - } - }); - } - }); - - final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); - - player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { - public void videoDimensionsChanged(Player player, final int width, final int height) { - runOnUiThread(new Runnable() { - public void run() { - Log.i("GStreamer", "Media size changed to " + width + "x" + height); - if (width > 0 && height > 0) { - gsv.media_width = width; - gsv.media_height = height; - runOnUiThread(new Runnable() { - public void run() { - gsv.requestLayout(); - } - }); - } else { - Log.i("GStreamer", "Ignoring media size."); - } - } - }); - } - }); - - SurfaceHolder sh = gsv.getHolder(); - sh.addCallback(this); - - String mediaUri = null; - Intent intent = getIntent(); - android.net.Uri uri = intent.getData(); - Log.i("GStreamer", "Received URI: " + uri); - if (uri.getScheme().equals("content")) { - android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); - cursor.moveToFirst(); - mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); - cursor.close(); - } else { - mediaUri = uri.toString(); - } - player.setUri(mediaUri); - - updateTimeWidget(); - } - - protected void onDestroy() { - player.close(); - super.onDestroy(); - } - - private void updateTimeWidget() { - final TextView tv = (TextView) this.findViewById(R.id.textview_time); - final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); - final int pos = sb.getProgress(); - final int max = sb.getMax(); - - SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - final String message = df.format(new Date(pos)) + " / " + df.format(new Date(max)); - tv.setText(message); - } - - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.d("GStreamer", "Surface changed to format " + format + " width " + width + " height " + height); - player.setSurface(holder.getSurface()); - } - - public void surfaceCreated(SurfaceHolder holder) { - Log.d("GStreamer", "Surface created: " + holder.getSurface()); - } - - public void surfaceDestroyed(SurfaceHolder holder) { - Log.d("GStreamer", "Surface destroyed"); - player.setSurface(null); - } - - public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { - if (!fromUser) return; - - updateTimeWidget(); - } - - public void onStartTrackingTouch(SeekBar sb) { - } - - public void onStopTrackingTouch(SeekBar sb) { - Log.d("GStreamer", "Seek to " + sb.getProgress()); - player.seek(((long) sb.getProgress()) * 1000000); - } -} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java deleted file mode 100644 index 38739f7..0000000 --- a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/play/VideoSelector.java +++ /dev/null @@ -1,151 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2015 Sebastian Roth - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.provider.MediaStore; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.SimpleCursorAdapter; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; - - -public class VideoSelector extends AppCompatActivity implements LoaderManager.LoaderCallbacks { - - VideoAdapter adapter; - boolean sortByName = false; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_video_selector); - - ListView videoList = (ListView) findViewById(R.id.videoList); - adapter = new VideoAdapter(this); - videoList.setAdapter(adapter); - videoList.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, final int position, final long id) { - final String videoPath = adapter.getVideoPath(position); - if (!TextUtils.isEmpty(videoPath)) { - Intent intent = new Intent(VideoSelector.this, Play.class); - intent.setData(Uri.parse("file://" + videoPath)); - startActivity(intent); - } - } - }); - - getSupportLoaderManager().initLoader(1, null, this); - - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_video_selector, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_about) { - return true; - } - - //noinspection SimplifiableIfStatement - if (id == R.id.action_sort) { - sortByName = !sortByName; - getSupportLoaderManager().restartLoader(1, null, this); - return true; - } - - - return super.onOptionsItemSelected(item); - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - if (sortByName) { - return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null, - "UPPER(" + MediaStore.Video.Media.DATA + ")"); - } else { - return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null, - "UPPER(" + MediaStore.Video.Media.DISPLAY_NAME + ")"); - } - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - adapter.swapCursor(data); - } - - @Override - public void onLoaderReset(Loader loader) { - - } - - - class VideoAdapter extends SimpleCursorAdapter { - public VideoAdapter(Context context) { - super(context, android.R.layout.simple_list_item_2, null, - new String[]{MediaStore.Video.Media.DISPLAY_NAME, MediaStore.Video.Media.DATA}, - new int[]{android.R.id.text1, android.R.id.text2}, 0); - } - - @Override - public long getItemId(int position) { - final Cursor cursor = getCursor(); - if (cursor.getCount() == 0 || position >= cursor.getCount()) { - return 0; - } - cursor.moveToPosition(position); - - return cursor.getLong(0); - } - - public String getVideoPath(int position) { - final Cursor cursor = getCursor(); - if (cursor.getCount() == 0) { - return ""; - } - cursor.moveToPosition(position); - - return cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA)); - } - } -} diff --git a/playback/player/android/app/src/main/jni/Android.mk b/playback/player/android/app/src/main/jni/Android.mk deleted file mode 100644 index 7afe062..0000000 --- a/playback/player/android/app/src/main/jni/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -GST_PATH := $(LOCAL_PATH)/../../../../../ - -LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := player.c \ - $(GST_PATH)/lib/gst/player/gstplayer.c \ - $(GST_PATH)/lib/gst/player/gstplayer-media-info.c -LOCAL_C_INCLUDES := $(GST_PATH)/lib -LOCAL_SHARED_LIBRARIES := gstreamer_android -LOCAL_LDLIBS := -llog -landroid -include $(BUILD_SHARED_LIBRARY) - -ifeq ($(TARGET_ARCH_ABI),armeabi) - GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM) -else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7) -else ifeq ($(TARGET_ARCH_ABI),x86) - GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86) -else - $(error Target arch ABI $(TARGET_ARCH_ABI) not supported) -endif - -GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ - -include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk -GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) -GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 - -include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/app/src/main/jni/Application.mk b/playback/player/android/app/src/main/jni/Application.mk deleted file mode 100644 index f665244..0000000 --- a/playback/player/android/app/src/main/jni/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -APP_ABI := armeabi armeabi-v7a x86 -APP_PLATFORM := android-9 \ No newline at end of file diff --git a/playback/player/android/app/src/main/jni/player.c b/playback/player/android/app/src/main/jni/player.c deleted file mode 100644 index 133d970..0000000 --- a/playback/player/android/app/src/main/jni/player.c +++ /dev/null @@ -1,496 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "gst/player/player.h" - -GST_DEBUG_CATEGORY_STATIC (debug_category); -#define GST_CAT_DEFAULT debug_category - -#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) -#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) - -typedef struct _Player -{ - jobject java_player; - GstPlayer *player; - GstPlayerVideoRenderer *renderer; - ANativeWindow *native_window; -} Player; - -static pthread_key_t current_jni_env; -static JavaVM *java_vm; -static jfieldID native_player_field_id; -static jmethodID on_position_updated_method_id; -static jmethodID on_duration_changed_method_id; -static jmethodID on_state_changed_method_id; -static jmethodID on_buffering_method_id; -static jmethodID on_end_of_stream_method_id; -static jmethodID on_error_method_id; -static jmethodID on_video_dimensions_changed_method_id; - -/* Register this thread with the VM */ -static JNIEnv * -attach_current_thread (void) -{ - JNIEnv *env; - JavaVMAttachArgs args; - - GST_DEBUG ("Attaching thread %p", g_thread_self ()); - args.version = JNI_VERSION_1_4; - args.name = NULL; - args.group = NULL; - - if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { - GST_ERROR ("Failed to attach current thread"); - return NULL; - } - - return env; -} - -/* Unregister this thread from the VM */ -static void -detach_current_thread (void *env) -{ - GST_DEBUG ("Detaching thread %p", g_thread_self ()); - (*java_vm)->DetachCurrentThread (java_vm); -} - -/* Retrieve the JNI environment for this thread */ -static JNIEnv * -get_jni_env (void) -{ - JNIEnv *env; - - if ((env = pthread_getspecific (current_jni_env)) == NULL) { - env = attach_current_thread (); - pthread_setspecific (current_jni_env, env); - } - - return env; -} - -/* - * Java Bindings - */ -static void -on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_position_updated_method_id, position); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_duration_changed_method_id, duration); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_state_changed_method_id, state); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_buffering (GstPlayer * unused, gint percent, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_buffering_method_id, percent); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_end_of_stream (GstPlayer * unused, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_error (GstPlayer * unused, GError * err, Player * player) -{ - JNIEnv *env = get_jni_env (); - jstring error_msg; - - error_msg = (*env)->NewStringUTF (env, err->message); - - (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, - err->code, error_msg); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - - (*env)->DeleteLocalRef (env, error_msg); -} - -static void -on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, - Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_video_dimensions_changed_method_id, width, height); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -native_new (JNIEnv * env, jobject thiz) -{ - Player *player = g_new0 (Player, 1); - - player->renderer = gst_player_video_overlay_video_renderer_new (NULL); - player->player = gst_player_new_full (player->renderer, NULL); - SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); - player->java_player = (*env)->NewGlobalRef (env, thiz); - - g_signal_connect (player->player, "position-updated", - G_CALLBACK (on_position_updated), player); - g_signal_connect (player->player, "duration-changed", - G_CALLBACK (on_duration_changed), player); - g_signal_connect (player->player, "state-changed", - G_CALLBACK (on_state_changed), player); - g_signal_connect (player->player, "buffering", - G_CALLBACK (on_buffering), player); - g_signal_connect (player->player, "end-of-stream", - G_CALLBACK (on_end_of_stream), player); - g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); - g_signal_connect (player->player, "video-dimensions-changed", - G_CALLBACK (on_video_dimensions_changed), player); -} - -static void -native_free (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_unref (player->player); - (*env)->DeleteGlobalRef (env, player->java_player); - g_free (player); - SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); -} - -static void -native_play (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_play (player->player); -} - -static void -native_pause (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_pause (player->player); -} - -static void -native_stop (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_stop (player->player); -} - -static void -native_seek (JNIEnv * env, jobject thiz, jlong position) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_seek (player->player, position); -} - -static void -native_set_uri (JNIEnv * env, jobject thiz, jobject uri) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - const gchar *uri_str; - - if (!player) - return; - - uri_str = (*env)->GetStringUTFChars (env, uri, NULL); - g_object_set (player->player, "uri", uri_str, NULL); - (*env)->ReleaseStringUTFChars (env, uri, uri_str); -} - -static jobject -native_get_uri (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jobject uri; - gchar *uri_str; - - if (!player) - return NULL; - - g_object_get (player->player, "uri", &uri_str, NULL); - - uri = (*env)->NewStringUTF (env, uri_str); - g_free (uri_str); - - return uri; -} - -static jlong -native_get_position (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jdouble position; - - if (!player) - return -1; - - g_object_get (player->player, "position", &position, NULL); - - return position; -} - -static jlong -native_get_duration (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jlong duration; - - if (!player) - return -1; - - g_object_get (player->player, "duration", &duration, NULL); - - return duration; -} - -static jdouble -native_get_volume (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jdouble volume; - - if (!player) - return 1.0; - - g_object_get (player->player, "volume", &volume, NULL); - - return volume; -} - -static void -native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_set (player->player, "volume", volume, NULL); -} - -static jboolean -native_get_mute (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jboolean mute; - - if (!player) - return FALSE; - - g_object_get (player->player, "mute", &mute, NULL); - - return mute; -} - -static void -native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_set (player->player, "mute", mute, NULL); -} - -static void -native_set_surface (JNIEnv * env, jobject thiz, jobject surface) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - ANativeWindow *new_native_window; - - if (!player) - return; - - new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; - GST_DEBUG ("Received surface %p (native window %p)", surface, - new_native_window); - - if (player->native_window) { - ANativeWindow_release (player->native_window); - } - - player->native_window = new_native_window; - gst_player_video_overlay_video_renderer_set_window_handle - (GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (player->renderer), - (gpointer) new_native_window); -} - -static void -native_class_init (JNIEnv * env, jclass klass) -{ - native_player_field_id = - (*env)->GetFieldID (env, klass, "native_player", "J"); - on_position_updated_method_id = - (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); - on_duration_changed_method_id = - (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); - on_state_changed_method_id = - (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); - on_buffering_method_id = - (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); - on_end_of_stream_method_id = - (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); - on_error_method_id = - (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); - on_video_dimensions_changed_method_id = - (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); - - if (!native_player_field_id || - !on_position_updated_method_id || !on_duration_changed_method_id || - !on_state_changed_method_id || !on_buffering_method_id || - !on_end_of_stream_method_id || - !on_error_method_id || !on_video_dimensions_changed_method_id) { - static const gchar *message = - "The calling class does not implement all necessary interface methods"; - jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); - (*env)->ThrowNew (env, exception_class, message); - } - - gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); -} - -/* List of implemented native methods */ -static JNINativeMethod native_methods[] = { - {"nativeClassInit", "()V", (void *) native_class_init}, - {"nativeNew", "()V", (void *) native_new}, - {"nativePlay", "()V", (void *) native_play}, - {"nativePause", "()V", (void *) native_pause}, - {"nativeSeek", "(J)V", (void *) native_seek}, - {"nativeFree", "()V", (void *) native_free}, - {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, - {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, - {"nativeGetPosition", "()J", (void *) native_get_position}, - {"nativeGetDuration", "()J", (void *) native_get_duration}, - {"nativeGetVolume", "()D", (void *) native_get_volume}, - {"nativeSetVolume", "(D)V", (void *) native_set_volume}, - {"nativeGetMute", "()Z", (void *) native_get_mute}, - {"nativeSetMute", "(Z)V", (void *) native_set_mute}, - {"nativeSetSurface", "(Landroid/view/Surface;)V", - (void *) native_set_surface} -}; - -/* Library initializer */ -jint -JNI_OnLoad (JavaVM * vm, void *reserved) -{ - JNIEnv *env = NULL; - - java_vm = vm; - - if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not retrieve JNIEnv"); - return 0; - } - jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); - if (!klass) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not retrieve class org.freedesktop.gstreamer.Player"); - return 0; - } - if ((*env)->RegisterNatives (env, klass, native_methods, - G_N_ELEMENTS (native_methods))) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not register native methods for org.freedesktop.gstreamer.Player"); - return 0; - } - - pthread_key_create (¤t_jni_env, detach_current_thread); - - return JNI_VERSION_1_4; -} diff --git a/playback/player/android/app/src/main/res/layout/activity_player.xml b/playback/player/android/app/src/main/res/layout/activity_player.xml deleted file mode 100644 index cd4a933..0000000 --- a/playback/player/android/app/src/main/res/layout/activity_player.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/app/src/main/res/layout/activity_video_selector.xml b/playback/player/android/app/src/main/res/layout/activity_video_selector.xml deleted file mode 100644 index 229ae17..0000000 --- a/playback/player/android/app/src/main/res/layout/activity_video_selector.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - diff --git a/playback/player/android/app/src/main/res/menu/menu_video_selector.xml b/playback/player/android/app/src/main/res/menu/menu_video_selector.xml deleted file mode 100644 index 93f4437..0000000 --- a/playback/player/android/app/src/main/res/menu/menu_video_selector.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - diff --git a/playback/player/android/app/src/main/res/values-w820dp/dimens.xml b/playback/player/android/app/src/main/res/values-w820dp/dimens.xml deleted file mode 100644 index 63fc816..0000000 --- a/playback/player/android/app/src/main/res/values-w820dp/dimens.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - 64dp - diff --git a/playback/player/android/app/src/main/res/values/dimens.xml b/playback/player/android/app/src/main/res/values/dimens.xml deleted file mode 100644 index 47c8224..0000000 --- a/playback/player/android/app/src/main/res/values/dimens.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 16dp - 16dp - diff --git a/playback/player/android/app/src/main/res/values/strings.xml b/playback/player/android/app/src/main/res/values/strings.xml deleted file mode 100644 index d3af9a3..0000000 --- a/playback/player/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - GStreamer Play - Play - Pause - - About - Sort - diff --git a/playback/player/android/app/src/main/res/values/styles.xml b/playback/player/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 540f2fe..0000000 --- a/playback/player/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/playback/player/android/build.gradle b/playback/player/android/build.gradle deleted file mode 100644 index 01de6ef..0000000 --- a/playback/player/android/build.gradle +++ /dev/null @@ -1,15 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.2.2' - } -} - -allprojects { - repositories { - jcenter() - } -} diff --git a/playback/player/android/build.xml b/playback/player/android/build.xml new file mode 100644 index 0000000..4ef18c8 --- /dev/null +++ b/playback/player/android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.jar b/playback/player/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 8c0fb64..0000000 Binary files a/playback/player/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.properties b/playback/player/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 0c71e76..0000000 --- a/playback/player/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Wed Apr 10 15:27:10 PDT 2013 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/playback/player/android/gradlew b/playback/player/android/gradlew deleted file mode 100755 index 91a7e26..0000000 --- a/playback/player/android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/playback/player/android/gradlew.bat b/playback/player/android/gradlew.bat deleted file mode 100644 index 8a0b282..0000000 --- a/playback/player/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk new file mode 100644 index 0000000..fe4d50a --- /dev/null +++ b/playback/player/android/jni/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := gstplayer +LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c ../../lib/gst/player/gstplayer-media-info.c +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../lib +LOCAL_SHARED_LIBRARIES := gstreamer_android +LOCAL_LDLIBS := -llog -landroid +include $(BUILD_SHARED_LIBRARY) + +ifndef GSTREAMER_ROOT +ifndef GSTREAMER_ROOT_ANDROID +$(error GSTREAMER_ROOT_ANDROID is not defined!) +endif +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID) +endif + +GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ + +include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk +GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) +GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 + +include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c new file mode 100644 index 0000000..fc55247 --- /dev/null +++ b/playback/player/android/jni/player.c @@ -0,0 +1,496 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "gst/player/gstplayer.h" + +GST_DEBUG_CATEGORY_STATIC (debug_category); +#define GST_CAT_DEFAULT debug_category + +#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) +#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) + +typedef struct _Player +{ + jobject java_player; + GstPlayer *player; + GstPlayerVideoRenderer *renderer; + ANativeWindow *native_window; +} Player; + +static pthread_key_t current_jni_env; +static JavaVM *java_vm; +static jfieldID native_player_field_id; +static jmethodID on_position_updated_method_id; +static jmethodID on_duration_changed_method_id; +static jmethodID on_state_changed_method_id; +static jmethodID on_buffering_method_id; +static jmethodID on_end_of_stream_method_id; +static jmethodID on_error_method_id; +static jmethodID on_video_dimensions_changed_method_id; + +/* Register this thread with the VM */ +static JNIEnv * +attach_current_thread (void) +{ + JNIEnv *env; + JavaVMAttachArgs args; + + GST_DEBUG ("Attaching thread %p", g_thread_self ()); + args.version = JNI_VERSION_1_4; + args.name = NULL; + args.group = NULL; + + if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { + GST_ERROR ("Failed to attach current thread"); + return NULL; + } + + return env; +} + +/* Unregister this thread from the VM */ +static void +detach_current_thread (void *env) +{ + GST_DEBUG ("Detaching thread %p", g_thread_self ()); + (*java_vm)->DetachCurrentThread (java_vm); +} + +/* Retrieve the JNI environment for this thread */ +static JNIEnv * +get_jni_env (void) +{ + JNIEnv *env; + + if ((env = pthread_getspecific (current_jni_env)) == NULL) { + env = attach_current_thread (); + pthread_setspecific (current_jni_env, env); + } + + return env; +} + +/* + * Java Bindings + */ +static void +on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_position_updated_method_id, position); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_duration_changed_method_id, duration); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_state_changed_method_id, state); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_buffering (GstPlayer * unused, gint percent, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_buffering_method_id, percent); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_end_of_stream (GstPlayer * unused, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_error (GstPlayer * unused, GError * err, Player * player) +{ + JNIEnv *env = get_jni_env (); + jstring error_msg; + + error_msg = (*env)->NewStringUTF (env, err->message); + + (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, + err->code, error_msg); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + + (*env)->DeleteLocalRef (env, error_msg); +} + +static void +on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, + Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_video_dimensions_changed_method_id, width, height); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +native_new (JNIEnv * env, jobject thiz) +{ + Player *player = g_new0 (Player, 1); + + player->renderer = gst_player_video_overlay_video_renderer_new (NULL); + player->player = gst_player_new_full (player->renderer, NULL); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); + player->java_player = (*env)->NewGlobalRef (env, thiz); + + g_signal_connect (player->player, "position-updated", + G_CALLBACK (on_position_updated), player); + g_signal_connect (player->player, "duration-changed", + G_CALLBACK (on_duration_changed), player); + g_signal_connect (player->player, "state-changed", + G_CALLBACK (on_state_changed), player); + g_signal_connect (player->player, "buffering", + G_CALLBACK (on_buffering), player); + g_signal_connect (player->player, "end-of-stream", + G_CALLBACK (on_end_of_stream), player); + g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); + g_signal_connect (player->player, "video-dimensions-changed", + G_CALLBACK (on_video_dimensions_changed), player); +} + +static void +native_free (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_unref (player->player); + (*env)->DeleteGlobalRef (env, player->java_player); + g_free (player); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); +} + +static void +native_play (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_play (player->player); +} + +static void +native_pause (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_pause (player->player); +} + +static void +native_stop (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_stop (player->player); +} + +static void +native_seek (JNIEnv * env, jobject thiz, jlong position) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_seek (player->player, position); +} + +static void +native_set_uri (JNIEnv * env, jobject thiz, jobject uri) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + const gchar *uri_str; + + if (!player) + return; + + uri_str = (*env)->GetStringUTFChars (env, uri, NULL); + g_object_set (player->player, "uri", uri_str, NULL); + (*env)->ReleaseStringUTFChars (env, uri, uri_str); +} + +static jobject +native_get_uri (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jobject uri; + gchar *uri_str; + + if (!player) + return NULL; + + g_object_get (player->player, "uri", &uri_str, NULL); + + uri = (*env)->NewStringUTF (env, uri_str); + g_free (uri_str); + + return uri; +} + +static jlong +native_get_position (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble position; + + if (!player) + return -1; + + g_object_get (player->player, "position", &position, NULL); + + return position; +} + +static jlong +native_get_duration (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jlong duration; + + if (!player) + return -1; + + g_object_get (player->player, "duration", &duration, NULL); + + return duration; +} + +static jdouble +native_get_volume (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble volume; + + if (!player) + return 1.0; + + g_object_get (player->player, "volume", &volume, NULL); + + return volume; +} + +static void +native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "volume", volume, NULL); +} + +static jboolean +native_get_mute (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jboolean mute; + + if (!player) + return FALSE; + + g_object_get (player->player, "mute", &mute, NULL); + + return mute; +} + +static void +native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "mute", mute, NULL); +} + +static void +native_set_surface (JNIEnv * env, jobject thiz, jobject surface) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + ANativeWindow *new_native_window; + + if (!player) + return; + + new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; + GST_DEBUG ("Received surface %p (native window %p)", surface, + new_native_window); + + if (player->native_window) { + ANativeWindow_release (player->native_window); + } + + player->native_window = new_native_window; + gst_player_video_overlay_video_renderer_set_window_handle + (GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (player->renderer), + (gpointer) new_native_window); +} + +static void +native_class_init (JNIEnv * env, jclass klass) +{ + native_player_field_id = + (*env)->GetFieldID (env, klass, "native_player", "J"); + on_position_updated_method_id = + (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); + on_duration_changed_method_id = + (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); + on_state_changed_method_id = + (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); + on_buffering_method_id = + (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); + on_end_of_stream_method_id = + (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); + on_error_method_id = + (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); + on_video_dimensions_changed_method_id = + (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); + + if (!native_player_field_id || + !on_position_updated_method_id || !on_duration_changed_method_id || + !on_state_changed_method_id || !on_buffering_method_id || + !on_end_of_stream_method_id || + !on_error_method_id || !on_video_dimensions_changed_method_id) { + static const gchar *message = + "The calling class does not implement all necessary interface methods"; + jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); + (*env)->ThrowNew (env, exception_class, message); + } + + gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); +} + +/* List of implemented native methods */ +static JNINativeMethod native_methods[] = { + {"nativeClassInit", "()V", (void *) native_class_init}, + {"nativeNew", "()V", (void *) native_new}, + {"nativePlay", "()V", (void *) native_play}, + {"nativePause", "()V", (void *) native_pause}, + {"nativeSeek", "(J)V", (void *) native_seek}, + {"nativeFree", "()V", (void *) native_free}, + {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, + {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, + {"nativeGetPosition", "()J", (void *) native_get_position}, + {"nativeGetDuration", "()J", (void *) native_get_duration}, + {"nativeGetVolume", "()D", (void *) native_get_volume}, + {"nativeSetVolume", "(D)V", (void *) native_set_volume}, + {"nativeGetMute", "()Z", (void *) native_get_mute}, + {"nativeSetMute", "(Z)V", (void *) native_set_mute}, + {"nativeSetSurface", "(Landroid/view/Surface;)V", + (void *) native_set_surface} +}; + +/* Library initializer */ +jint +JNI_OnLoad (JavaVM * vm, void *reserved) +{ + JNIEnv *env = NULL; + + java_vm = vm; + + if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve JNIEnv"); + return 0; + } + jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); + if (!klass) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve class org.freedesktop.gstreamer.Player"); + return 0; + } + if ((*env)->RegisterNatives (env, klass, native_methods, + G_N_ELEMENTS (native_methods))) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not register native methods for org.freedesktop.gstreamer.Player"); + return 0; + } + + pthread_key_create (¤t_jni_env, detach_current_thread); + + return JNI_VERSION_1_4; +} diff --git a/playback/player/android/res/layout/main.xml b/playback/player/android/res/layout/main.xml new file mode 100644 index 0000000..b745d80 --- /dev/null +++ b/playback/player/android/res/layout/main.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/res/values/strings.xml b/playback/player/android/res/values/strings.xml new file mode 100644 index 0000000..9587e3c --- /dev/null +++ b/playback/player/android/res/values/strings.xml @@ -0,0 +1,6 @@ + + + GStreamer Play + Play + Pause + diff --git a/playback/player/android/settings.gradle b/playback/player/android/settings.gradle deleted file mode 100644 index e7b4def..0000000 --- a/playback/player/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java new file mode 100644 index 0000000..e2bef8c --- /dev/null +++ b/playback/player/android/src/org/freedesktop/gstreamer/Player.java @@ -0,0 +1,241 @@ +/* GStreamer + * + * Copyright (C) 2014-2015 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer; + +import java.io.Closeable; +import android.view.Surface; +import android.content.Context; +import org.freedesktop.gstreamer.GStreamer; + +public class Player implements Closeable { + private static native void nativeClassInit(); + public static void init(Context context) throws Exception { + System.loadLibrary("gstreamer_android"); + GStreamer.init(context); + + System.loadLibrary("gstplayer"); + nativeClassInit(); + } + + private long native_player; + private native void nativeNew(); + public Player() { + nativeNew(); + } + + private native void nativeFree(); + @Override + public void close() { + nativeFree(); + } + + private native void nativePlay(); + public void play() { + nativePlay(); + } + + private native void nativePause(); + public void pause() { + nativePause(); + } + + private native void nativeStop(); + public void stop() { + nativeStop(); + } + + private native void nativeSeek(long position); + public void seek(long position) { + nativeSeek(position); + } + + private native String nativeGetUri(); + public String getUri() { + return nativeGetUri(); + } + + private native void nativeSetUri(String uri); + public void setUri(String uri) { + nativeSetUri(uri); + } + + private native long nativeGetPosition(); + public long getPosition() { + return nativeGetPosition(); + } + + private native long nativeGetDuration(); + public long getDuration() { + return nativeGetDuration(); + } + + private native double nativeGetVolume(); + public double getVolume() { + return nativeGetVolume(); + } + + private native void nativeSetVolume(double volume); + public void setVolume(double volume) { + nativeSetVolume(volume); + } + + private native boolean nativeGetMute(); + public boolean getMute() { + return nativeGetMute(); + } + + private native void nativeSetMute(boolean mute); + public void setMute(boolean mute) { + nativeSetMute(mute); + } + + private Surface surface; + private native void nativeSetSurface(Surface surface); + public void setSurface(Surface surface) { + this.surface = surface; + nativeSetSurface(surface); + } + + public Surface getSurface() { + return surface; + } + + public static interface PositionUpdatedListener { + abstract void positionUpdated(Player player, long position); + } + + private PositionUpdatedListener positionUpdatedListener; + public void setPositionUpdatedListener(PositionUpdatedListener listener) { + positionUpdatedListener = listener; + } + + private void onPositionUpdated(long position) { + if (positionUpdatedListener != null) { + positionUpdatedListener.positionUpdated(this, position); + } + } + + public static interface DurationChangedListener { + abstract void durationChanged(Player player, long duration); + } + + private DurationChangedListener durationChangedListener; + public void setDurationChangedListener(DurationChangedListener listener) { + durationChangedListener = listener; + } + + private void onDurationChanged(long duration) { + if (durationChangedListener != null) { + durationChangedListener.durationChanged(this, duration); + } + } + + private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; + public enum State { + STOPPED, + BUFFERING, + PAUSED, + PLAYING + } + + public static interface StateChangedListener { + abstract void stateChanged(Player player, State state); + } + + private StateChangedListener stateChangedListener; + public void setStateChangedListener(StateChangedListener listener) { + stateChangedListener = listener; + } + + private void onStateChanged(int stateIdx) { + if (stateChangedListener != null) { + State state = stateMap[stateIdx]; + stateChangedListener.stateChanged(this, state); + } + } + + public static interface BufferingListener { + abstract void buffering(Player player, int percent); + } + + private BufferingListener bufferingListener; + public void setBufferingListener(BufferingListener listener) { + bufferingListener = listener; + } + + private void onBuffering(int percent) { + if (bufferingListener != null) { + bufferingListener.buffering(this, percent); + } + } + + public static interface EndOfStreamListener { + abstract void endOfStream(Player player); + } + + private EndOfStreamListener endOfStreamListener; + public void setEndOfStreamListener(EndOfStreamListener listener) { + endOfStreamListener = listener; + } + + private void onEndOfStream() { + if (endOfStreamListener != null) { + endOfStreamListener.endOfStream(this); + } + } + + // Keep these in sync with gstplayer.h + private static final Error[] errorMap = {Error.FAILED}; + public enum Error { + FAILED + } + + public static interface ErrorListener { + abstract void error(Player player, Error error, String errorMessage); + } + + private ErrorListener errorListener; + public void setErrorListener(ErrorListener listener) { + errorListener = listener; + } + + private void onError(int errorCode, String errorMessage) { + if (errorListener != null) { + Error error = errorMap[errorCode]; + errorListener.error(this, error, errorMessage); + } + } + + public static interface VideoDimensionsChangedListener { + abstract void videoDimensionsChanged(Player player, int width, int height); + } + + private VideoDimensionsChangedListener videoDimensionsChangedListener; + public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { + videoDimensionsChangedListener = listener; + } + + private void onVideoDimensionsChanged(int width, int height) { + if (videoDimensionsChangedListener != null) { + videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); + } + } +} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java new file mode 100644 index 0000000..f2dd8a9 --- /dev/null +++ b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java @@ -0,0 +1,105 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceView; +import android.view.View; + +// A simple SurfaceView whose width and height can be set from the outside +public class GStreamerSurfaceView extends SurfaceView { + public int media_width = 320; + public int media_height = 240; + + // Mandatory constructors, they do not do much + public GStreamerSurfaceView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public GStreamerSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public GStreamerSurfaceView (Context context) { + super(context); + } + + // Called by the layout manager to find out our size and give us some rules. + // We will try to maximize our size, and preserve the media's aspect ratio if + // we are given the freedom to do so. + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = 0, height = 0; + int wmode = View.MeasureSpec.getMode(widthMeasureSpec); + int hmode = View.MeasureSpec.getMode(heightMeasureSpec); + int wsize = View.MeasureSpec.getSize(widthMeasureSpec); + int hsize = View.MeasureSpec.getSize(heightMeasureSpec); + + Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); + // Obey width rules + switch (wmode) { + case View.MeasureSpec.AT_MOST: + if (hmode == View.MeasureSpec.EXACTLY) { + width = Math.min(hsize * media_width / media_height, wsize); + break; + } + case View.MeasureSpec.EXACTLY: + width = wsize; + break; + case View.MeasureSpec.UNSPECIFIED: + width = media_width; + } + + // Obey height rules + switch (hmode) { + case View.MeasureSpec.AT_MOST: + if (wmode == View.MeasureSpec.EXACTLY) { + height = Math.min(wsize * media_height / media_width, hsize); + break; + } + case View.MeasureSpec.EXACTLY: + height = hsize; + break; + case View.MeasureSpec.UNSPECIFIED: + height = media_height; + } + + // Finally, calculate best size when both axis are free + if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { + int correct_height = width * media_height / media_width; + int correct_width = height * media_width / media_height; + + if (correct_height < height) + height = correct_height; + else + width = correct_width; + } + + // Obey minimum size + width = Math.max (getSuggestedMinimumWidth(), width); + height = Math.max (getSuggestedMinimumHeight(), height); + setMeasuredDimension(width, height); + } + +} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java b/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java new file mode 100644 index 0000000..2874f05 --- /dev/null +++ b/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java @@ -0,0 +1,196 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.PowerManager; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; +import android.widget.Toast; + +import org.freedesktop.gstreamer.Player; + +public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener { + private PowerManager.WakeLock wake_lock; + private Player player; + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + try { + Player.init(this); + } catch (Exception e) { + Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); + finish(); + return; + } + + setContentView(R.layout.main); + + player = new Player(); + + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); + wake_lock.setReferenceCounted(false); + + ImageButton play = (ImageButton) this.findViewById(R.id.button_play); + play.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.play(); + wake_lock.acquire(); + } + }); + + ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); + pause.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.pause(); + wake_lock.release(); + } + }); + + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + sb.setOnSeekBarChangeListener(this); + + player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { + public void positionUpdated(Player player, final long position) { + runOnUiThread (new Runnable() { + public void run() { + sb.setProgress((int) (position / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + player.setDurationChangedListener(new Player.DurationChangedListener() { + public void durationChanged(Player player, final long duration) { + runOnUiThread (new Runnable() { + public void run() { + sb.setMax((int) (duration / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); + player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { + public void videoDimensionsChanged(Player player, final int width, final int height) { + runOnUiThread (new Runnable() { + public void run() { + Log.i ("GStreamer", "Media size changed to " + width + "x" + height); + gsv.media_width = width; + gsv.media_height = height; + runOnUiThread(new Runnable() { + public void run() { + gsv.requestLayout(); + } + }); + } + }); + } + }); + + SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video); + SurfaceHolder sh = sv.getHolder(); + sh.addCallback(this); + + String mediaUri = null; + Intent intent = getIntent(); + android.net.Uri uri = intent.getData(); + Log.i ("GStreamer", "Received URI: " + uri); + if (uri.getScheme().equals("content")) { + android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); + cursor.close(); + } else { + mediaUri = uri.toString(); + } + player.setUri(mediaUri); + + updateTimeWidget(); + } + + protected void onDestroy() { + player.close(); + super.onDestroy(); + } + + private void updateTimeWidget () { + final TextView tv = (TextView) this.findViewById(R.id.textview_time); + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + final int pos = sb.getProgress(); + final int max = sb.getMax(); + + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max)); + tv.setText(message); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + Log.d("GStreamer", "Surface changed to format " + format + " width " + + width + " height " + height); + player.setSurface(holder.getSurface()); + } + + public void surfaceCreated(SurfaceHolder holder) { + Log.d("GStreamer", "Surface created: " + holder.getSurface()); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d("GStreamer", "Surface destroyed"); + player.setSurface(null); + } + + public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { + if (!fromUser) return; + + updateTimeWidget(); + } + + public void onStartTrackingTouch(SeekBar sb) { + } + + public void onStopTrackingTouch(SeekBar sb) { + Log.d("GStreamer", "Seek to " + sb.getProgress()); + player.seek(((long) sb.getProgress()) * 1000000); + } +} -- cgit v1.2.3 From de7130efc268a77beeba567012c85a119531d0ac Mon Sep 17 00:00:00 2001 From: caseten Date: Sat, 7 Nov 2015 13:09:47 -0700 Subject: playback/player: android: Fix typo for restricted codecs plugin --- playback/player/android/jni/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index fe4d50a..9d2ff4c 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -19,7 +19,7 @@ endif GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk -GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) +GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk -- cgit v1.2.3 -- cgit v1.2.3 From 171c7235929ff0fb88d10e345d34260ad333a4c4 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 9 Nov 2015 21:35:57 +0100 Subject: playback/player: gtk: Remove double assignment of a variable --- playback/player/gtk/gtk-video-renderer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-video-renderer.c b/playback/player/gtk/gtk-video-renderer.c index b784f4a..b34f927 100644 --- a/playback/player/gtk/gtk-video-renderer.c +++ b/playback/player/gtk/gtk-video-renderer.c @@ -107,7 +107,7 @@ gst_player_gtk_video_renderer_init (GstPlayerGtkVideoRenderer * self) GstElement *gtk_sink = gst_element_factory_make ("gtkglsink", NULL); if (gtk_sink) { - GstElement *sink = sink = gst_element_factory_make ("glsinkbin", NULL); + GstElement *sink = gst_element_factory_make ("glsinkbin", NULL); g_object_set (sink, "sink", gtk_sink, NULL); self->sink = sink; -- cgit v1.2.3 From 00cad0da116ee809eeb8cdfaad19c03ae5e231cd Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 13 Nov 2015 10:36:24 +0100 Subject: playback/player: android: Add more URI schemes, mimetypes and file extensions Based on the AndroidManifest.xml of VLC for Android. --- playback/player/android/AndroidManifest.xml | 331 +++++++++++++++++++++++++--- 1 file changed, 300 insertions(+), 31 deletions(-) diff --git a/playback/player/android/AndroidManifest.xml b/playback/player/android/AndroidManifest.xml index 8b156d4..41d5652 100644 --- a/playback/player/android/AndroidManifest.xml +++ b/playback/player/android/AndroidManifest.xml @@ -11,12 +11,7 @@ - - - + @@ -26,9 +21,27 @@ + + + + + + + + + + + + + + + + + + - @@ -37,43 +50,299 @@ - + + + + + + + + + + - + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From eaed96145e604b4e543255f76e5903605aa9448d Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Fri, 13 Nov 2015 10:36:52 +0100 Subject: playback/player: android: Don't do custom surface width/height calculations if we have no media width/height --- .../src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java index f2dd8a9..075f035 100644 --- a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java +++ b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java @@ -50,6 +50,11 @@ public class GStreamerSurfaceView extends SurfaceView { // we are given the freedom to do so. @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (media_width == 0 || media_height == 0) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + return; + } + int width = 0, height = 0; int wmode = View.MeasureSpec.getMode(widthMeasureSpec); int hmode = View.MeasureSpec.getMode(heightMeasureSpec); -- cgit v1.2.3 From af371bf38e47442290f11c816ba34c6cbf7160d3 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Wed, 9 Dec 2015 09:48:38 +0200 Subject: playback/player: android: Allow building for multiple Android ABIs --- playback/player/android/jni/Android.mk | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 9d2ff4c..4766fb4 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -9,6 +9,20 @@ LOCAL_SHARED_LIBRARIES := gstreamer_android LOCAL_LDLIBS := -llog -landroid include $(BUILD_SHARED_LIBRARY) +ifeq ($(TARGET_ARCH_ABI),armeabi) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM) +else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7) +else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM64) +else ifeq ($(TARGET_ARCH_ABI),x86) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86) +else ifeq ($(TARGET_ARCH_ABI),x86_64) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86_64) +else +$(error Target arch ABI not supported) +endif + ifndef GSTREAMER_ROOT ifndef GSTREAMER_ROOT_ANDROID $(error GSTREAMER_ROOT_ANDROID is not defined!) -- cgit v1.2.3 From 8ccf31fcf963b9933f1b71fad6a7c3a11c89d182 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 22 Dec 2015 12:08:53 +0100 Subject: playback/player: android: Fix compilation --- playback/player/android/jni/Android.mk | 11 ++++++++++- playback/player/android/jni/player.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 4766fb4..77af905 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -3,7 +3,16 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c ../../lib/gst/player/gstplayer-media-info.c +LOCAL_SRC_FILES := \ + player.c \ + ../../lib/gst/player/gstplayer.c \ + ../../lib/gst/player/gstplayer-signal-dispatcher.c \ + ../../lib/gst/player/gstplayer-video-renderer.c \ + ../../lib/gst/player/gstplayer-media-info.c \ + ../../lib/gst/player/gstplayer-g-main-context-signal-dispatcher.c \ + ../../lib/gst/player/gstplayer-video-overlay-video-renderer.c \ + ../../lib/gst/player/gstplayer-visualization.c + LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../lib LOCAL_SHARED_LIBRARIES := gstreamer_android LOCAL_LDLIBS := -llog -landroid diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index fc55247..133d970 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -25,7 +25,7 @@ #include #include -#include "gst/player/gstplayer.h" +#include "gst/player/player.h" GST_DEBUG_CATEGORY_STATIC (debug_category); #define GST_CAT_DEFAULT debug_category -- cgit v1.2.3 From addb63586bad7a36d82caa9b30bd10445dd61264 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 4 Jan 2016 09:59:40 +0200 Subject: playback/player: player: Remove gst_player_new() and make gst_player_new_full() the normal constructor In very few cases the simple version was actually needed and having the parameters hidden by a _full() version caused application that actually needed it to not use it. --- playback/player/android/jni/player.c | 2 +- playback/player/gst-play/gst-play.c | 2 +- playback/player/gtk/gtk-play.c | 2 +- playback/player/ios/GstPlay/VideoViewController.m | 2 +- playback/player/qt/qgstplayer.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index 133d970..ee53708 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -199,7 +199,7 @@ native_new (JNIEnv * env, jobject thiz) Player *player = g_new0 (Player, 1); player->renderer = gst_player_video_overlay_video_renderer_new (NULL); - player->player = gst_player_new_full (player->renderer, NULL); + player->player = gst_player_new (player->renderer, NULL); SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); player->java_player = (*env)->NewGlobalRef (env, thiz); diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 95b9d4f..46f6d62 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -357,7 +357,7 @@ play_new (gchar ** uris, gdouble initial_volume) play->cur_idx = -1; play->player = - gst_player_new_full (NULL, gst_player_g_main_context_signal_dispatcher_new + gst_player_new (NULL, gst_player_g_main_context_signal_dispatcher_new (NULL)); g_signal_connect (play->player, "position-updated", diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 0e6ac76..51d0bf0 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1732,7 +1732,7 @@ gtk_play_constructor (GType type, guint n_construct_params, create_ui (self); self->player = - gst_player_new_full (self->renderer, + gst_player_new (self->renderer, gst_player_g_main_context_signal_dispatcher_new (NULL)); g_signal_connect (self->player, "position-updated", diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index eda419c..19c3799 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -63,7 +63,7 @@ media_width = 320; media_height = 240; - player = gst_player_new_full (gst_player_video_overlay_video_renderer_new ((__bridge gpointer)(video_view)), NULL); + player = gst_player_new (gst_player_video_overlay_video_renderer_new ((__bridge gpointer)(video_view)), NULL); g_object_set (player, "uri", [uri UTF8String], NULL); gst_debug_set_threshold_for_name("gst-player", GST_LEVEL_TRACE); diff --git a/playback/player/qt/qgstplayer.cpp b/playback/player/qt/qgstplayer.cpp index b15347f..77112ef 100644 --- a/playback/player/qt/qgstplayer.cpp +++ b/playback/player/qt/qgstplayer.cpp @@ -397,7 +397,7 @@ Player::Player(QObject *parent, VideoRenderer *renderer) , autoPlay_(false) { - player_ = gst_player_new_full(renderer ? renderer->renderer() : 0, + player_ = gst_player_new(renderer ? renderer->renderer() : 0, gst_player_qt_signal_dispatcher_new(this)); g_object_connect(player_, -- cgit v1.2.3 From f509043c1d18bf7b25ddec60543670346b4282f3 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 4 Jan 2016 10:11:20 +0200 Subject: playback/player: player: Build against GstPlayer version from gst-plugins-bad everywhere The old version with everything included and buildable against GStreamer 1.6 can still be found in the gst-player-0.1 branch and will be continued to be updated for a while. --- playback/player/android/jni/Android.mk | 15 ++-------- playback/player/android/jni/player.c | 2 +- playback/player/gst-play/Makefile.am | 5 ++-- playback/player/gtk/Makefile.am | 5 ++-- playback/player/gtk/gtk-play.c | 1 - .../player/ios/GstPlay.xcodeproj/project.pbxproj | 33 ---------------------- playback/player/ios/GstPlay/VideoViewController.m | 2 +- playback/player/qt/play.pro | 11 ++------ 8 files changed, 11 insertions(+), 63 deletions(-) diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk index 77af905..65e2044 100644 --- a/playback/player/android/jni/Android.mk +++ b/playback/player/android/jni/Android.mk @@ -3,17 +3,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := \ - player.c \ - ../../lib/gst/player/gstplayer.c \ - ../../lib/gst/player/gstplayer-signal-dispatcher.c \ - ../../lib/gst/player/gstplayer-video-renderer.c \ - ../../lib/gst/player/gstplayer-media-info.c \ - ../../lib/gst/player/gstplayer-g-main-context-signal-dispatcher.c \ - ../../lib/gst/player/gstplayer-video-overlay-video-renderer.c \ - ../../lib/gst/player/gstplayer-visualization.c - -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../lib +LOCAL_SRC_FILES := player.c + LOCAL_SHARED_LIBRARIES := gstreamer_android LOCAL_LDLIBS := -llog -landroid include $(BUILD_SHARED_LIBRARY) @@ -43,6 +34,6 @@ GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) -GSTREAMER_EXTRA_DEPS := gstreamer-video-1.0 glib-2.0 +GSTREAMER_EXTRA_DEPS := gstreamer-player-1.0 gstreamer-video-1.0 glib-2.0 include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index ee53708..ed72e86 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -25,7 +25,7 @@ #include #include -#include "gst/player/player.h" +#include GST_DEBUG_CATEGORY_STATIC (debug_category); #define GST_CAT_DEFAULT debug_category diff --git a/playback/player/gst-play/Makefile.am b/playback/player/gst-play/Makefile.am index 534e0df..184e8c1 100644 --- a/playback/player/gst-play/Makefile.am +++ b/playback/player/gst-play/Makefile.am @@ -2,9 +2,8 @@ bin_PROGRAMS = gst-play gst_play_SOURCES = gst-play.c gst-play-kb.c gst-play-kb.h -LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ - $(GSTREAMER_LIBS) $(GLIB_LIBS) $(LIBM) +LDADD = $(GSTREAMER_LIBS) $(GLIB_LIBS) $(LIBM) -AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GLIB_CFLAGS) $(WARNING_CFLAGS) +AM_CFLAGS = $(GSTREAMER_CFLAGS) $(GLIB_CFLAGS) $(WARNING_CFLAGS) noinst_HEADERS = gst-play-kb.h diff --git a/playback/player/gtk/Makefile.am b/playback/player/gtk/Makefile.am index 97ce95d..45623e5 100644 --- a/playback/player/gtk/Makefile.am +++ b/playback/player/gtk/Makefile.am @@ -28,9 +28,8 @@ BUILT_SOURCES: gtk-play-resources.c gtk-play-resources.h gtk_play_SOURCES = gtk-play.c gtk-play-resources.c gtk-video-renderer.c -LDADD = $(top_builddir)/lib/gst/player/.libs/libgstplayer-@GST_PLAYER_API_VERSION@.la \ - $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) $(GMODULE_LIBS) +LDADD = $(GSTREAMER_LIBS) $(GTK_LIBS) $(GTK_X11_LIBS) $(GLIB_LIBS) $(LIBM) $(GMODULE_LIBS) -AM_CFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) $(WARNING_CFLAGS) +AM_CFLAGS = $(GSTREAMER_CFLAGS) $(GTK_CFLAGS) $(GTK_X11_CFLAGS) $(GLIB_CFLAGS) $(GMODULE_CFLAGS) $(WARNING_CFLAGS) noinst_HEADERS = gtk-play-resources.h gtk-video-renderer.h diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 51d0bf0..c91693b 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj index 9a3e45c..6d9ff1f 100644 --- a/playback/player/ios/GstPlay.xcodeproj/project.pbxproj +++ b/playback/player/ios/GstPlay.xcodeproj/project.pbxproj @@ -23,8 +23,6 @@ AD2B885C198D65470070367B /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD2B885A198D65470070367B /* MainStoryboard_iPad.storyboard */; }; AD2B8861198D65780070367B /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B885E198D65780070367B /* LibraryViewController.m */; }; AD2B8862198D65780070367B /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2B8860198D65780070367B /* VideoViewController.m */; }; - AD2B886C198D69ED0070367B /* gstplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = AD2B886A198D69ED0070367B /* gstplayer.c */; }; - E95DEC9B1B8332F100CC3512 /* gstplayer-media-info.c in Sources */ = {isa = PBXBuildFile; fileRef = E95DEC981B8332F100CC3512 /* gstplayer-media-info.c */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -53,12 +51,6 @@ AD2B885E198D65780070367B /* LibraryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LibraryViewController.m; sourceTree = ""; }; AD2B885F198D65780070367B /* VideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoViewController.h; sourceTree = ""; }; AD2B8860198D65780070367B /* VideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; }; - AD2B886A198D69ED0070367B /* gstplayer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gstplayer.c; sourceTree = ""; }; - AD2B886B198D69ED0070367B /* gstplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gstplayer.h; sourceTree = ""; }; - E95DEC971B8332F100CC3512 /* gstplayer-media-info-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gstplayer-media-info-private.h"; sourceTree = ""; }; - E95DEC981B8332F100CC3512 /* gstplayer-media-info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "gstplayer-media-info.c"; sourceTree = ""; }; - E95DEC991B8332F100CC3512 /* gstplayer-media-info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gstplayer-media-info.h"; sourceTree = ""; }; - E95DEC9A1B8332F100CC3512 /* player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = player.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -79,7 +71,6 @@ AD2B8812198D631B0070367B = { isa = PBXGroup; children = ( - AD2B8868198D69ED0070367B /* gst */, AD2B8826198D631B0070367B /* GstPlay */, AD2B881D198D631B0070367B /* Frameworks */, AD2B881C198D631B0070367B /* Products */, @@ -140,28 +131,6 @@ name = "Supporting Files"; sourceTree = ""; }; - AD2B8868198D69ED0070367B /* gst */ = { - isa = PBXGroup; - children = ( - AD2B8869198D69ED0070367B /* player */, - ); - name = gst; - path = ../lib/gst; - sourceTree = ""; - }; - AD2B8869198D69ED0070367B /* player */ = { - isa = PBXGroup; - children = ( - E95DEC971B8332F100CC3512 /* gstplayer-media-info-private.h */, - E95DEC981B8332F100CC3512 /* gstplayer-media-info.c */, - E95DEC991B8332F100CC3512 /* gstplayer-media-info.h */, - E95DEC9A1B8332F100CC3512 /* player.h */, - AD2B886A198D69ED0070367B /* gstplayer.c */, - AD2B886B198D69ED0070367B /* gstplayer.h */, - ); - path = player; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -229,14 +198,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E95DEC9B1B8332F100CC3512 /* gstplayer-media-info.c in Sources */, AD2B8861198D65780070367B /* LibraryViewController.m in Sources */, AD2B8831198D631B0070367B /* AppDelegate.m in Sources */, AD2B8862198D65780070367B /* VideoViewController.m in Sources */, AD2B8858198D637A0070367B /* EaglUIVIew.m in Sources */, AD2B882D198D631B0070367B /* main.m in Sources */, AD2B8837198D631B0070367B /* gst_ios_init.m in Sources */, - AD2B886C198D69ED0070367B /* gstplayer.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/playback/player/ios/GstPlay/VideoViewController.m b/playback/player/ios/GstPlay/VideoViewController.m index 19c3799..079fcde 100644 --- a/playback/player/ios/GstPlay/VideoViewController.m +++ b/playback/player/ios/GstPlay/VideoViewController.m @@ -1,5 +1,5 @@ #import "VideoViewController.h" -#import +#import #import @interface VideoViewController () { diff --git a/playback/player/qt/play.pro b/playback/player/qt/play.pro index d16440c..87a1490 100644 --- a/playback/player/qt/play.pro +++ b/playback/player/qt/play.pro @@ -6,8 +6,6 @@ CONFIG += c++11 DEFINES += GST_USE_UNSTABLE_API -INCLUDEPATH += ../lib - RESOURCES += qml.qrc # Additional import path used to resolve QML modules in Qt Creator's code model @@ -22,11 +20,8 @@ QT_CONFIG -= no-pkg-config CONFIG += link_pkgconfig PKGCONFIG = \ gstreamer-1.0 \ - gstreamer-audio-1.0 \ - gstreamer-tag-1.0 \ - gstreamer-pbutils-1.0 \ - gstreamer-video-1.0 \ - gstreamer-gl-1.0 + gstreamer-player-1.0 \ + gstreamer-tag-1.0 } macx { @@ -46,8 +41,6 @@ HEADERS += \ SOURCES += main.cpp \ qgstplayer.cpp \ - ../lib/gst/player/gstplayer.c \ - ../lib/gst/player/gstplayer-media-info.c \ player.cpp \ quickrenderer.cpp \ imagesample.cpp -- cgit v1.2.3 From 048de744414101463d632ac8488a9dcf63dee33e Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 7 Jan 2016 00:22:26 +0200 Subject: playback/player: android: Register native_stop() with JNI https://github.com/sdroege/gst-player/issues/143 --- playback/player/android/jni/player.c | 1 + 1 file changed, 1 insertion(+) diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c index ed72e86..58d177e 100644 --- a/playback/player/android/jni/player.c +++ b/playback/player/android/jni/player.c @@ -450,6 +450,7 @@ static JNINativeMethod native_methods[] = { {"nativeNew", "()V", (void *) native_new}, {"nativePlay", "()V", (void *) native_play}, {"nativePause", "()V", (void *) native_pause}, + {"nativeStop", "()V", (void *) native_stop}, {"nativeSeek", "(J)V", (void *) native_seek}, {"nativeFree", "()V", (void *) native_free}, {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, -- cgit v1.2.3 From e8906735ae3dc669e25bf62459f9c7206ed06abe Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 5 Feb 2016 08:45:44 +0530 Subject: playback/player: android: Move to gradle based build --- playback/player/android/AndroidManifest.xml | 348 --------------- playback/player/android/Makefile.am | 23 +- playback/player/android/app/build.gradle | 73 +++ playback/player/android/app/proguard-rules.pro | 17 + .../android/app/src/main/AndroidManifest.xml | 344 ++++++++++++++ .../java/org/freedesktop/gstreamer/Player.java | 241 ++++++++++ .../gstreamer/player/GStreamerSurfaceView.java | 110 +++++ .../org/freedesktop/gstreamer/player/Play.java | 196 ++++++++ .../player/android/app/src/main/jni/Android.mk | 39 ++ .../player/android/app/src/main/jni/Application.mk | 1 + playback/player/android/app/src/main/jni/player.c | 497 +++++++++++++++++++++ .../android/app/src/main/res/layout/main.xml | 62 +++ .../android/app/src/main/res/values/strings.xml | 6 + playback/player/android/build.gradle | 23 + playback/player/android/build.xml | 92 ---- playback/player/android/gradle.properties | 18 + playback/player/android/jni/Android.mk | 39 -- playback/player/android/jni/player.c | 497 --------------------- playback/player/android/res/layout/main.xml | 62 --- playback/player/android/res/values/strings.xml | 6 - playback/player/android/settings.gradle | 1 + .../src/org/freedesktop/gstreamer/Player.java | 241 ---------- .../gstreamer/player/GStreamerSurfaceView.java | 110 ----- .../src/org/freedesktop/gstreamer/player/Play.java | 196 -------- 24 files changed, 1642 insertions(+), 1600 deletions(-) delete mode 100644 playback/player/android/AndroidManifest.xml create mode 100644 playback/player/android/app/build.gradle create mode 100644 playback/player/android/app/proguard-rules.pro create mode 100644 playback/player/android/app/src/main/AndroidManifest.xml create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java create mode 100644 playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/Play.java create mode 100644 playback/player/android/app/src/main/jni/Android.mk create mode 100644 playback/player/android/app/src/main/jni/Application.mk create mode 100644 playback/player/android/app/src/main/jni/player.c create mode 100644 playback/player/android/app/src/main/res/layout/main.xml create mode 100644 playback/player/android/app/src/main/res/values/strings.xml create mode 100644 playback/player/android/build.gradle delete mode 100644 playback/player/android/build.xml create mode 100644 playback/player/android/gradle.properties delete mode 100644 playback/player/android/jni/Android.mk delete mode 100644 playback/player/android/jni/player.c delete mode 100644 playback/player/android/res/layout/main.xml delete mode 100644 playback/player/android/res/values/strings.xml create mode 100644 playback/player/android/settings.gradle delete mode 100644 playback/player/android/src/org/freedesktop/gstreamer/Player.java delete mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java delete mode 100644 playback/player/android/src/org/freedesktop/gstreamer/player/Play.java diff --git a/playback/player/android/AndroidManifest.xml b/playback/player/android/AndroidManifest.xml deleted file mode 100644 index 41d5652..0000000 --- a/playback/player/android/AndroidManifest.xml +++ /dev/null @@ -1,348 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/Makefile.am b/playback/player/android/Makefile.am index 2664abb..27d8ada 100644 --- a/playback/player/android/Makefile.am +++ b/playback/player/android/Makefile.am @@ -1,10 +1,15 @@ EXTRA_DIST = \ - AndroidManifest.xml \ - jni/Android.mk \ - jni/player.c \ - res/layout/main.xml \ - res/values/strings.xml \ - src/org/freedesktop/gstreamer/Player.java \ - src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ - src/org/freedesktop/gstreamer/player/Play.java - + build.gradle \ + gradle.properties \ + settings.gradle \ + app/build.gradle \ + app/proguard-rules.pro \ + app/src/main/AndroidManifest.xml \ + app/src/main/java/org/freedesktop/gstreamer/Player.java \ + app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \ + app/src/main/java/org/freedesktop/gstreamer/player/Play.java \ + app/src/main/jni/Android.mk \ + app/src/main/jni/Application.mk \ + app/src/main/jni/player.c \ + app/src/main/res/layout/main.xml \ + app/src/main/res/values/strings.xml diff --git a/playback/player/android/app/build.gradle b/playback/player/android/app/build.gradle new file mode 100644 index 0000000..e908022 --- /dev/null +++ b/playback/player/android/app/build.gradle @@ -0,0 +1,73 @@ +apply plugin: 'com.android.application' + + +def getNdkCommandLine(ndkRoot, target) { + def gstRoot + + if (project.hasProperty('gstAndroidRoot')) + gstRoot = project.gstAndroidRoot + else + gstRoot = System.properties['user.home'] + '/cerbero/dist/android_arm' + + if (ndkRoot == null) + throw new GradleException('NDK not configured') + + return ["$ndkRoot/ndk-build", + 'NDK_PROJECT_PATH=build', + 'APP_BUILD_SCRIPT=src/main/jni/Android.mk', + 'NDK_APPLICATION_MK=src/main/jni/Application.mk', + 'GSTREAMER_JAVA_SRC_DIR=src/main/java', + "GSTREAMER_ROOT_ANDROID=$gstRoot", + target] +} + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + + sourceSets { + main { + // Avoid using the built in JNI generation plugin + jni.srcDirs = [] + jniLibs.srcDirs = ['build/libs'] + } + } + + defaultConfig { + applicationId "org.freedesktop.gstreamer.play" + minSdkVersion 15 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + // Before compiling our app, prepare NDK code + tasks.withType(JavaCompile) { + compileTask -> compileTask.dependsOn ndkBuild + } + + // Need to call clean on NDK ourselves too + clean.dependsOn 'ndkClean' + + // Build native code using mk files like on Eclipse + task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') { + commandLine getNdkCommandLine(android.ndkDirectory, 'all') + } + + task ndkClean(type: Exec, description: 'Clean JNI code built via NDK') { + commandLine getNdkCommandLine(android.ndkDirectory, 'clean') + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.1.1' +} diff --git a/playback/player/android/app/proguard-rules.pro b/playback/player/android/app/proguard-rules.pro new file mode 100644 index 0000000..d5d45de --- /dev/null +++ b/playback/player/android/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /home/arun/code/android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/playback/player/android/app/src/main/AndroidManifest.xml b/playback/player/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9823f22 --- /dev/null +++ b/playback/player/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java new file mode 100644 index 0000000..e2bef8c --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/Player.java @@ -0,0 +1,241 @@ +/* GStreamer + * + * Copyright (C) 2014-2015 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer; + +import java.io.Closeable; +import android.view.Surface; +import android.content.Context; +import org.freedesktop.gstreamer.GStreamer; + +public class Player implements Closeable { + private static native void nativeClassInit(); + public static void init(Context context) throws Exception { + System.loadLibrary("gstreamer_android"); + GStreamer.init(context); + + System.loadLibrary("gstplayer"); + nativeClassInit(); + } + + private long native_player; + private native void nativeNew(); + public Player() { + nativeNew(); + } + + private native void nativeFree(); + @Override + public void close() { + nativeFree(); + } + + private native void nativePlay(); + public void play() { + nativePlay(); + } + + private native void nativePause(); + public void pause() { + nativePause(); + } + + private native void nativeStop(); + public void stop() { + nativeStop(); + } + + private native void nativeSeek(long position); + public void seek(long position) { + nativeSeek(position); + } + + private native String nativeGetUri(); + public String getUri() { + return nativeGetUri(); + } + + private native void nativeSetUri(String uri); + public void setUri(String uri) { + nativeSetUri(uri); + } + + private native long nativeGetPosition(); + public long getPosition() { + return nativeGetPosition(); + } + + private native long nativeGetDuration(); + public long getDuration() { + return nativeGetDuration(); + } + + private native double nativeGetVolume(); + public double getVolume() { + return nativeGetVolume(); + } + + private native void nativeSetVolume(double volume); + public void setVolume(double volume) { + nativeSetVolume(volume); + } + + private native boolean nativeGetMute(); + public boolean getMute() { + return nativeGetMute(); + } + + private native void nativeSetMute(boolean mute); + public void setMute(boolean mute) { + nativeSetMute(mute); + } + + private Surface surface; + private native void nativeSetSurface(Surface surface); + public void setSurface(Surface surface) { + this.surface = surface; + nativeSetSurface(surface); + } + + public Surface getSurface() { + return surface; + } + + public static interface PositionUpdatedListener { + abstract void positionUpdated(Player player, long position); + } + + private PositionUpdatedListener positionUpdatedListener; + public void setPositionUpdatedListener(PositionUpdatedListener listener) { + positionUpdatedListener = listener; + } + + private void onPositionUpdated(long position) { + if (positionUpdatedListener != null) { + positionUpdatedListener.positionUpdated(this, position); + } + } + + public static interface DurationChangedListener { + abstract void durationChanged(Player player, long duration); + } + + private DurationChangedListener durationChangedListener; + public void setDurationChangedListener(DurationChangedListener listener) { + durationChangedListener = listener; + } + + private void onDurationChanged(long duration) { + if (durationChangedListener != null) { + durationChangedListener.durationChanged(this, duration); + } + } + + private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; + public enum State { + STOPPED, + BUFFERING, + PAUSED, + PLAYING + } + + public static interface StateChangedListener { + abstract void stateChanged(Player player, State state); + } + + private StateChangedListener stateChangedListener; + public void setStateChangedListener(StateChangedListener listener) { + stateChangedListener = listener; + } + + private void onStateChanged(int stateIdx) { + if (stateChangedListener != null) { + State state = stateMap[stateIdx]; + stateChangedListener.stateChanged(this, state); + } + } + + public static interface BufferingListener { + abstract void buffering(Player player, int percent); + } + + private BufferingListener bufferingListener; + public void setBufferingListener(BufferingListener listener) { + bufferingListener = listener; + } + + private void onBuffering(int percent) { + if (bufferingListener != null) { + bufferingListener.buffering(this, percent); + } + } + + public static interface EndOfStreamListener { + abstract void endOfStream(Player player); + } + + private EndOfStreamListener endOfStreamListener; + public void setEndOfStreamListener(EndOfStreamListener listener) { + endOfStreamListener = listener; + } + + private void onEndOfStream() { + if (endOfStreamListener != null) { + endOfStreamListener.endOfStream(this); + } + } + + // Keep these in sync with gstplayer.h + private static final Error[] errorMap = {Error.FAILED}; + public enum Error { + FAILED + } + + public static interface ErrorListener { + abstract void error(Player player, Error error, String errorMessage); + } + + private ErrorListener errorListener; + public void setErrorListener(ErrorListener listener) { + errorListener = listener; + } + + private void onError(int errorCode, String errorMessage) { + if (errorListener != null) { + Error error = errorMap[errorCode]; + errorListener.error(this, error, errorMessage); + } + } + + public static interface VideoDimensionsChangedListener { + abstract void videoDimensionsChanged(Player player, int width, int height); + } + + private VideoDimensionsChangedListener videoDimensionsChangedListener; + public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { + videoDimensionsChangedListener = listener; + } + + private void onVideoDimensionsChanged(int width, int height) { + if (videoDimensionsChangedListener != null) { + videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); + } + } +} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java new file mode 100644 index 0000000..075f035 --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java @@ -0,0 +1,110 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.SurfaceView; +import android.view.View; + +// A simple SurfaceView whose width and height can be set from the outside +public class GStreamerSurfaceView extends SurfaceView { + public int media_width = 320; + public int media_height = 240; + + // Mandatory constructors, they do not do much + public GStreamerSurfaceView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public GStreamerSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public GStreamerSurfaceView (Context context) { + super(context); + } + + // Called by the layout manager to find out our size and give us some rules. + // We will try to maximize our size, and preserve the media's aspect ratio if + // we are given the freedom to do so. + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (media_width == 0 || media_height == 0) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + return; + } + + int width = 0, height = 0; + int wmode = View.MeasureSpec.getMode(widthMeasureSpec); + int hmode = View.MeasureSpec.getMode(heightMeasureSpec); + int wsize = View.MeasureSpec.getSize(widthMeasureSpec); + int hsize = View.MeasureSpec.getSize(heightMeasureSpec); + + Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); + // Obey width rules + switch (wmode) { + case View.MeasureSpec.AT_MOST: + if (hmode == View.MeasureSpec.EXACTLY) { + width = Math.min(hsize * media_width / media_height, wsize); + break; + } + case View.MeasureSpec.EXACTLY: + width = wsize; + break; + case View.MeasureSpec.UNSPECIFIED: + width = media_width; + } + + // Obey height rules + switch (hmode) { + case View.MeasureSpec.AT_MOST: + if (wmode == View.MeasureSpec.EXACTLY) { + height = Math.min(wsize * media_height / media_width, hsize); + break; + } + case View.MeasureSpec.EXACTLY: + height = hsize; + break; + case View.MeasureSpec.UNSPECIFIED: + height = media_height; + } + + // Finally, calculate best size when both axis are free + if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { + int correct_height = width * media_height / media_width; + int correct_width = height * media_width / media_height; + + if (correct_height < height) + height = correct_height; + else + width = correct_width; + } + + // Obey minimum size + width = Math.max (getSuggestedMinimumWidth(), width); + height = Math.max (getSuggestedMinimumHeight(), height); + setMeasuredDimension(width, height); + } + +} diff --git a/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/Play.java b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/Play.java new file mode 100644 index 0000000..2874f05 --- /dev/null +++ b/playback/player/android/app/src/main/java/org/freedesktop/gstreamer/player/Play.java @@ -0,0 +1,196 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.freedesktop.gstreamer.play; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.PowerManager; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; +import android.widget.Toast; + +import org.freedesktop.gstreamer.Player; + +public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener { + private PowerManager.WakeLock wake_lock; + private Player player; + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + try { + Player.init(this); + } catch (Exception e) { + Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); + finish(); + return; + } + + setContentView(R.layout.main); + + player = new Player(); + + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); + wake_lock.setReferenceCounted(false); + + ImageButton play = (ImageButton) this.findViewById(R.id.button_play); + play.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.play(); + wake_lock.acquire(); + } + }); + + ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); + pause.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + player.pause(); + wake_lock.release(); + } + }); + + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + sb.setOnSeekBarChangeListener(this); + + player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { + public void positionUpdated(Player player, final long position) { + runOnUiThread (new Runnable() { + public void run() { + sb.setProgress((int) (position / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + player.setDurationChangedListener(new Player.DurationChangedListener() { + public void durationChanged(Player player, final long duration) { + runOnUiThread (new Runnable() { + public void run() { + sb.setMax((int) (duration / 1000000)); + updateTimeWidget(); + } + }); + } + }); + + final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); + player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { + public void videoDimensionsChanged(Player player, final int width, final int height) { + runOnUiThread (new Runnable() { + public void run() { + Log.i ("GStreamer", "Media size changed to " + width + "x" + height); + gsv.media_width = width; + gsv.media_height = height; + runOnUiThread(new Runnable() { + public void run() { + gsv.requestLayout(); + } + }); + } + }); + } + }); + + SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video); + SurfaceHolder sh = sv.getHolder(); + sh.addCallback(this); + + String mediaUri = null; + Intent intent = getIntent(); + android.net.Uri uri = intent.getData(); + Log.i ("GStreamer", "Received URI: " + uri); + if (uri.getScheme().equals("content")) { + android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); + cursor.close(); + } else { + mediaUri = uri.toString(); + } + player.setUri(mediaUri); + + updateTimeWidget(); + } + + protected void onDestroy() { + player.close(); + super.onDestroy(); + } + + private void updateTimeWidget () { + final TextView tv = (TextView) this.findViewById(R.id.textview_time); + final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); + final int pos = sb.getProgress(); + final int max = sb.getMax(); + + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max)); + tv.setText(message); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + Log.d("GStreamer", "Surface changed to format " + format + " width " + + width + " height " + height); + player.setSurface(holder.getSurface()); + } + + public void surfaceCreated(SurfaceHolder holder) { + Log.d("GStreamer", "Surface created: " + holder.getSurface()); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d("GStreamer", "Surface destroyed"); + player.setSurface(null); + } + + public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { + if (!fromUser) return; + + updateTimeWidget(); + } + + public void onStartTrackingTouch(SeekBar sb) { + } + + public void onStopTrackingTouch(SeekBar sb) { + Log.d("GStreamer", "Seek to " + sb.getProgress()); + player.seek(((long) sb.getProgress()) * 1000000); + } +} diff --git a/playback/player/android/app/src/main/jni/Android.mk b/playback/player/android/app/src/main/jni/Android.mk new file mode 100644 index 0000000..65e2044 --- /dev/null +++ b/playback/player/android/app/src/main/jni/Android.mk @@ -0,0 +1,39 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := gstplayer +LOCAL_SRC_FILES := player.c + +LOCAL_SHARED_LIBRARIES := gstreamer_android +LOCAL_LDLIBS := -llog -landroid +include $(BUILD_SHARED_LIBRARY) + +ifeq ($(TARGET_ARCH_ABI),armeabi) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM) +else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7) +else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM64) +else ifeq ($(TARGET_ARCH_ABI),x86) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86) +else ifeq ($(TARGET_ARCH_ABI),x86_64) +GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86_64) +else +$(error Target arch ABI not supported) +endif + +ifndef GSTREAMER_ROOT +ifndef GSTREAMER_ROOT_ANDROID +$(error GSTREAMER_ROOT_ANDROID is not defined!) +endif +GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID) +endif + +GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ + +include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk +GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) +GSTREAMER_EXTRA_DEPS := gstreamer-player-1.0 gstreamer-video-1.0 glib-2.0 + +include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/app/src/main/jni/Application.mk b/playback/player/android/app/src/main/jni/Application.mk new file mode 100644 index 0000000..87c0990 --- /dev/null +++ b/playback/player/android/app/src/main/jni/Application.mk @@ -0,0 +1 @@ +APP_PLATFORM = 15 diff --git a/playback/player/android/app/src/main/jni/player.c b/playback/player/android/app/src/main/jni/player.c new file mode 100644 index 0000000..58d177e --- /dev/null +++ b/playback/player/android/app/src/main/jni/player.c @@ -0,0 +1,497 @@ +/* GStreamer + * + * Copyright (C) 2014 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +GST_DEBUG_CATEGORY_STATIC (debug_category); +#define GST_CAT_DEFAULT debug_category + +#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) +#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) + +typedef struct _Player +{ + jobject java_player; + GstPlayer *player; + GstPlayerVideoRenderer *renderer; + ANativeWindow *native_window; +} Player; + +static pthread_key_t current_jni_env; +static JavaVM *java_vm; +static jfieldID native_player_field_id; +static jmethodID on_position_updated_method_id; +static jmethodID on_duration_changed_method_id; +static jmethodID on_state_changed_method_id; +static jmethodID on_buffering_method_id; +static jmethodID on_end_of_stream_method_id; +static jmethodID on_error_method_id; +static jmethodID on_video_dimensions_changed_method_id; + +/* Register this thread with the VM */ +static JNIEnv * +attach_current_thread (void) +{ + JNIEnv *env; + JavaVMAttachArgs args; + + GST_DEBUG ("Attaching thread %p", g_thread_self ()); + args.version = JNI_VERSION_1_4; + args.name = NULL; + args.group = NULL; + + if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { + GST_ERROR ("Failed to attach current thread"); + return NULL; + } + + return env; +} + +/* Unregister this thread from the VM */ +static void +detach_current_thread (void *env) +{ + GST_DEBUG ("Detaching thread %p", g_thread_self ()); + (*java_vm)->DetachCurrentThread (java_vm); +} + +/* Retrieve the JNI environment for this thread */ +static JNIEnv * +get_jni_env (void) +{ + JNIEnv *env; + + if ((env = pthread_getspecific (current_jni_env)) == NULL) { + env = attach_current_thread (); + pthread_setspecific (current_jni_env, env); + } + + return env; +} + +/* + * Java Bindings + */ +static void +on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_position_updated_method_id, position); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_duration_changed_method_id, duration); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_state_changed_method_id, state); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_buffering (GstPlayer * unused, gint percent, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_buffering_method_id, percent); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_end_of_stream (GstPlayer * unused, Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +on_error (GstPlayer * unused, GError * err, Player * player) +{ + JNIEnv *env = get_jni_env (); + jstring error_msg; + + error_msg = (*env)->NewStringUTF (env, err->message); + + (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, + err->code, error_msg); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + + (*env)->DeleteLocalRef (env, error_msg); +} + +static void +on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, + Player * player) +{ + JNIEnv *env = get_jni_env (); + + (*env)->CallVoidMethod (env, player->java_player, + on_video_dimensions_changed_method_id, width, height); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } +} + +static void +native_new (JNIEnv * env, jobject thiz) +{ + Player *player = g_new0 (Player, 1); + + player->renderer = gst_player_video_overlay_video_renderer_new (NULL); + player->player = gst_player_new (player->renderer, NULL); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); + player->java_player = (*env)->NewGlobalRef (env, thiz); + + g_signal_connect (player->player, "position-updated", + G_CALLBACK (on_position_updated), player); + g_signal_connect (player->player, "duration-changed", + G_CALLBACK (on_duration_changed), player); + g_signal_connect (player->player, "state-changed", + G_CALLBACK (on_state_changed), player); + g_signal_connect (player->player, "buffering", + G_CALLBACK (on_buffering), player); + g_signal_connect (player->player, "end-of-stream", + G_CALLBACK (on_end_of_stream), player); + g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); + g_signal_connect (player->player, "video-dimensions-changed", + G_CALLBACK (on_video_dimensions_changed), player); +} + +static void +native_free (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_unref (player->player); + (*env)->DeleteGlobalRef (env, player->java_player); + g_free (player); + SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); +} + +static void +native_play (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_play (player->player); +} + +static void +native_pause (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_pause (player->player); +} + +static void +native_stop (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_stop (player->player); +} + +static void +native_seek (JNIEnv * env, jobject thiz, jlong position) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + gst_player_seek (player->player, position); +} + +static void +native_set_uri (JNIEnv * env, jobject thiz, jobject uri) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + const gchar *uri_str; + + if (!player) + return; + + uri_str = (*env)->GetStringUTFChars (env, uri, NULL); + g_object_set (player->player, "uri", uri_str, NULL); + (*env)->ReleaseStringUTFChars (env, uri, uri_str); +} + +static jobject +native_get_uri (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jobject uri; + gchar *uri_str; + + if (!player) + return NULL; + + g_object_get (player->player, "uri", &uri_str, NULL); + + uri = (*env)->NewStringUTF (env, uri_str); + g_free (uri_str); + + return uri; +} + +static jlong +native_get_position (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble position; + + if (!player) + return -1; + + g_object_get (player->player, "position", &position, NULL); + + return position; +} + +static jlong +native_get_duration (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jlong duration; + + if (!player) + return -1; + + g_object_get (player->player, "duration", &duration, NULL); + + return duration; +} + +static jdouble +native_get_volume (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jdouble volume; + + if (!player) + return 1.0; + + g_object_get (player->player, "volume", &volume, NULL); + + return volume; +} + +static void +native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "volume", volume, NULL); +} + +static jboolean +native_get_mute (JNIEnv * env, jobject thiz) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + jboolean mute; + + if (!player) + return FALSE; + + g_object_get (player->player, "mute", &mute, NULL); + + return mute; +} + +static void +native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + + if (!player) + return; + + g_object_set (player->player, "mute", mute, NULL); +} + +static void +native_set_surface (JNIEnv * env, jobject thiz, jobject surface) +{ + Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); + ANativeWindow *new_native_window; + + if (!player) + return; + + new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; + GST_DEBUG ("Received surface %p (native window %p)", surface, + new_native_window); + + if (player->native_window) { + ANativeWindow_release (player->native_window); + } + + player->native_window = new_native_window; + gst_player_video_overlay_video_renderer_set_window_handle + (GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (player->renderer), + (gpointer) new_native_window); +} + +static void +native_class_init (JNIEnv * env, jclass klass) +{ + native_player_field_id = + (*env)->GetFieldID (env, klass, "native_player", "J"); + on_position_updated_method_id = + (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); + on_duration_changed_method_id = + (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); + on_state_changed_method_id = + (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); + on_buffering_method_id = + (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); + on_end_of_stream_method_id = + (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); + on_error_method_id = + (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); + on_video_dimensions_changed_method_id = + (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); + + if (!native_player_field_id || + !on_position_updated_method_id || !on_duration_changed_method_id || + !on_state_changed_method_id || !on_buffering_method_id || + !on_end_of_stream_method_id || + !on_error_method_id || !on_video_dimensions_changed_method_id) { + static const gchar *message = + "The calling class does not implement all necessary interface methods"; + jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); + (*env)->ThrowNew (env, exception_class, message); + } + + gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); +} + +/* List of implemented native methods */ +static JNINativeMethod native_methods[] = { + {"nativeClassInit", "()V", (void *) native_class_init}, + {"nativeNew", "()V", (void *) native_new}, + {"nativePlay", "()V", (void *) native_play}, + {"nativePause", "()V", (void *) native_pause}, + {"nativeStop", "()V", (void *) native_stop}, + {"nativeSeek", "(J)V", (void *) native_seek}, + {"nativeFree", "()V", (void *) native_free}, + {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, + {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, + {"nativeGetPosition", "()J", (void *) native_get_position}, + {"nativeGetDuration", "()J", (void *) native_get_duration}, + {"nativeGetVolume", "()D", (void *) native_get_volume}, + {"nativeSetVolume", "(D)V", (void *) native_set_volume}, + {"nativeGetMute", "()Z", (void *) native_get_mute}, + {"nativeSetMute", "(Z)V", (void *) native_set_mute}, + {"nativeSetSurface", "(Landroid/view/Surface;)V", + (void *) native_set_surface} +}; + +/* Library initializer */ +jint +JNI_OnLoad (JavaVM * vm, void *reserved) +{ + JNIEnv *env = NULL; + + java_vm = vm; + + if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve JNIEnv"); + return 0; + } + jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); + if (!klass) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not retrieve class org.freedesktop.gstreamer.Player"); + return 0; + } + if ((*env)->RegisterNatives (env, klass, native_methods, + G_N_ELEMENTS (native_methods))) { + __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", + "Could not register native methods for org.freedesktop.gstreamer.Player"); + return 0; + } + + pthread_key_create (¤t_jni_env, detach_current_thread); + + return JNI_VERSION_1_4; +} diff --git a/playback/player/android/app/src/main/res/layout/main.xml b/playback/player/android/app/src/main/res/layout/main.xml new file mode 100644 index 0000000..b745d80 --- /dev/null +++ b/playback/player/android/app/src/main/res/layout/main.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/playback/player/android/app/src/main/res/values/strings.xml b/playback/player/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..9587e3c --- /dev/null +++ b/playback/player/android/app/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + GStreamer Play + Play + Pause + diff --git a/playback/player/android/build.gradle b/playback/player/android/build.gradle new file mode 100644 index 0000000..e0b366a --- /dev/null +++ b/playback/player/android/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.5.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/playback/player/android/build.xml b/playback/player/android/build.xml deleted file mode 100644 index 4ef18c8..0000000 --- a/playback/player/android/build.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/gradle.properties b/playback/player/android/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/playback/player/android/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/playback/player/android/jni/Android.mk b/playback/player/android/jni/Android.mk deleted file mode 100644 index 65e2044..0000000 --- a/playback/player/android/jni/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := gstplayer -LOCAL_SRC_FILES := player.c - -LOCAL_SHARED_LIBRARIES := gstreamer_android -LOCAL_LDLIBS := -llog -landroid -include $(BUILD_SHARED_LIBRARY) - -ifeq ($(TARGET_ARCH_ABI),armeabi) -GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM) -else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7) -else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) -GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM64) -else ifeq ($(TARGET_ARCH_ABI),x86) -GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86) -else ifeq ($(TARGET_ARCH_ABI),x86_64) -GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86_64) -else -$(error Target arch ABI not supported) -endif - -ifndef GSTREAMER_ROOT -ifndef GSTREAMER_ROOT_ANDROID -$(error GSTREAMER_ROOT_ANDROID is not defined!) -endif -GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID) -endif - -GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/ - -include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk -GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_CODECS_RESTRICTED) $(GSTREAMER_CODECS_GPL) $(GSTREAMER_PLUGINS_ENCODING) $(GSTREAMER_PLUGINS_VIS) $(GSTREAMER_PLUGINS_EFFECTS) $(GSTREAMER_PLUGINS_NET_RESTRICTED) -GSTREAMER_EXTRA_DEPS := gstreamer-player-1.0 gstreamer-video-1.0 glib-2.0 - -include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk diff --git a/playback/player/android/jni/player.c b/playback/player/android/jni/player.c deleted file mode 100644 index 58d177e..0000000 --- a/playback/player/android/jni/player.c +++ /dev/null @@ -1,497 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include - -GST_DEBUG_CATEGORY_STATIC (debug_category); -#define GST_CAT_DEFAULT debug_category - -#define GET_CUSTOM_DATA(env, thiz, fieldID) (Player *)(gintptr)(*env)->GetLongField (env, thiz, fieldID) -#define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(gintptr)data) - -typedef struct _Player -{ - jobject java_player; - GstPlayer *player; - GstPlayerVideoRenderer *renderer; - ANativeWindow *native_window; -} Player; - -static pthread_key_t current_jni_env; -static JavaVM *java_vm; -static jfieldID native_player_field_id; -static jmethodID on_position_updated_method_id; -static jmethodID on_duration_changed_method_id; -static jmethodID on_state_changed_method_id; -static jmethodID on_buffering_method_id; -static jmethodID on_end_of_stream_method_id; -static jmethodID on_error_method_id; -static jmethodID on_video_dimensions_changed_method_id; - -/* Register this thread with the VM */ -static JNIEnv * -attach_current_thread (void) -{ - JNIEnv *env; - JavaVMAttachArgs args; - - GST_DEBUG ("Attaching thread %p", g_thread_self ()); - args.version = JNI_VERSION_1_4; - args.name = NULL; - args.group = NULL; - - if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { - GST_ERROR ("Failed to attach current thread"); - return NULL; - } - - return env; -} - -/* Unregister this thread from the VM */ -static void -detach_current_thread (void *env) -{ - GST_DEBUG ("Detaching thread %p", g_thread_self ()); - (*java_vm)->DetachCurrentThread (java_vm); -} - -/* Retrieve the JNI environment for this thread */ -static JNIEnv * -get_jni_env (void) -{ - JNIEnv *env; - - if ((env = pthread_getspecific (current_jni_env)) == NULL) { - env = attach_current_thread (); - pthread_setspecific (current_jni_env, env); - } - - return env; -} - -/* - * Java Bindings - */ -static void -on_position_updated (GstPlayer * unused, GstClockTime position, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_position_updated_method_id, position); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_duration_changed (GstPlayer * unused, GstClockTime duration, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_duration_changed_method_id, duration); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_state_changed (GstPlayer * unused, GstPlayerState state, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_state_changed_method_id, state); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_buffering (GstPlayer * unused, gint percent, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_buffering_method_id, percent); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_end_of_stream (GstPlayer * unused, Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, on_end_of_stream_method_id); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -on_error (GstPlayer * unused, GError * err, Player * player) -{ - JNIEnv *env = get_jni_env (); - jstring error_msg; - - error_msg = (*env)->NewStringUTF (env, err->message); - - (*env)->CallVoidMethod (env, player->java_player, on_error_method_id, - err->code, error_msg); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - - (*env)->DeleteLocalRef (env, error_msg); -} - -static void -on_video_dimensions_changed (GstPlayer * unused, gint width, gint height, - Player * player) -{ - JNIEnv *env = get_jni_env (); - - (*env)->CallVoidMethod (env, player->java_player, - on_video_dimensions_changed_method_id, width, height); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } -} - -static void -native_new (JNIEnv * env, jobject thiz) -{ - Player *player = g_new0 (Player, 1); - - player->renderer = gst_player_video_overlay_video_renderer_new (NULL); - player->player = gst_player_new (player->renderer, NULL); - SET_CUSTOM_DATA (env, thiz, native_player_field_id, player); - player->java_player = (*env)->NewGlobalRef (env, thiz); - - g_signal_connect (player->player, "position-updated", - G_CALLBACK (on_position_updated), player); - g_signal_connect (player->player, "duration-changed", - G_CALLBACK (on_duration_changed), player); - g_signal_connect (player->player, "state-changed", - G_CALLBACK (on_state_changed), player); - g_signal_connect (player->player, "buffering", - G_CALLBACK (on_buffering), player); - g_signal_connect (player->player, "end-of-stream", - G_CALLBACK (on_end_of_stream), player); - g_signal_connect (player->player, "error", G_CALLBACK (on_error), player); - g_signal_connect (player->player, "video-dimensions-changed", - G_CALLBACK (on_video_dimensions_changed), player); -} - -static void -native_free (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_unref (player->player); - (*env)->DeleteGlobalRef (env, player->java_player); - g_free (player); - SET_CUSTOM_DATA (env, thiz, native_player_field_id, NULL); -} - -static void -native_play (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_play (player->player); -} - -static void -native_pause (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_pause (player->player); -} - -static void -native_stop (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_stop (player->player); -} - -static void -native_seek (JNIEnv * env, jobject thiz, jlong position) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - gst_player_seek (player->player, position); -} - -static void -native_set_uri (JNIEnv * env, jobject thiz, jobject uri) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - const gchar *uri_str; - - if (!player) - return; - - uri_str = (*env)->GetStringUTFChars (env, uri, NULL); - g_object_set (player->player, "uri", uri_str, NULL); - (*env)->ReleaseStringUTFChars (env, uri, uri_str); -} - -static jobject -native_get_uri (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jobject uri; - gchar *uri_str; - - if (!player) - return NULL; - - g_object_get (player->player, "uri", &uri_str, NULL); - - uri = (*env)->NewStringUTF (env, uri_str); - g_free (uri_str); - - return uri; -} - -static jlong -native_get_position (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jdouble position; - - if (!player) - return -1; - - g_object_get (player->player, "position", &position, NULL); - - return position; -} - -static jlong -native_get_duration (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jlong duration; - - if (!player) - return -1; - - g_object_get (player->player, "duration", &duration, NULL); - - return duration; -} - -static jdouble -native_get_volume (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jdouble volume; - - if (!player) - return 1.0; - - g_object_get (player->player, "volume", &volume, NULL); - - return volume; -} - -static void -native_set_volume (JNIEnv * env, jobject thiz, jdouble volume) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_set (player->player, "volume", volume, NULL); -} - -static jboolean -native_get_mute (JNIEnv * env, jobject thiz) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - jboolean mute; - - if (!player) - return FALSE; - - g_object_get (player->player, "mute", &mute, NULL); - - return mute; -} - -static void -native_set_mute (JNIEnv * env, jobject thiz, jboolean mute) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - - if (!player) - return; - - g_object_set (player->player, "mute", mute, NULL); -} - -static void -native_set_surface (JNIEnv * env, jobject thiz, jobject surface) -{ - Player *player = GET_CUSTOM_DATA (env, thiz, native_player_field_id); - ANativeWindow *new_native_window; - - if (!player) - return; - - new_native_window = surface ? ANativeWindow_fromSurface (env, surface) : NULL; - GST_DEBUG ("Received surface %p (native window %p)", surface, - new_native_window); - - if (player->native_window) { - ANativeWindow_release (player->native_window); - } - - player->native_window = new_native_window; - gst_player_video_overlay_video_renderer_set_window_handle - (GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (player->renderer), - (gpointer) new_native_window); -} - -static void -native_class_init (JNIEnv * env, jclass klass) -{ - native_player_field_id = - (*env)->GetFieldID (env, klass, "native_player", "J"); - on_position_updated_method_id = - (*env)->GetMethodID (env, klass, "onPositionUpdated", "(J)V"); - on_duration_changed_method_id = - (*env)->GetMethodID (env, klass, "onDurationChanged", "(J)V"); - on_state_changed_method_id = - (*env)->GetMethodID (env, klass, "onStateChanged", "(I)V"); - on_buffering_method_id = - (*env)->GetMethodID (env, klass, "onBuffering", "(I)V"); - on_end_of_stream_method_id = - (*env)->GetMethodID (env, klass, "onEndOfStream", "()V"); - on_error_method_id = - (*env)->GetMethodID (env, klass, "onError", "(ILjava/lang/String;)V"); - on_video_dimensions_changed_method_id = - (*env)->GetMethodID (env, klass, "onVideoDimensionsChanged", "(II)V"); - - if (!native_player_field_id || - !on_position_updated_method_id || !on_duration_changed_method_id || - !on_state_changed_method_id || !on_buffering_method_id || - !on_end_of_stream_method_id || - !on_error_method_id || !on_video_dimensions_changed_method_id) { - static const gchar *message = - "The calling class does not implement all necessary interface methods"; - jclass exception_class = (*env)->FindClass (env, "java/lang/Exception"); - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", "%s", message); - (*env)->ThrowNew (env, exception_class, message); - } - - gst_debug_set_threshold_for_name ("gst-player", GST_LEVEL_TRACE); -} - -/* List of implemented native methods */ -static JNINativeMethod native_methods[] = { - {"nativeClassInit", "()V", (void *) native_class_init}, - {"nativeNew", "()V", (void *) native_new}, - {"nativePlay", "()V", (void *) native_play}, - {"nativePause", "()V", (void *) native_pause}, - {"nativeStop", "()V", (void *) native_stop}, - {"nativeSeek", "(J)V", (void *) native_seek}, - {"nativeFree", "()V", (void *) native_free}, - {"nativeGetUri", "()Ljava/lang/String;", (void *) native_get_uri}, - {"nativeSetUri", "(Ljava/lang/String;)V", (void *) native_set_uri}, - {"nativeGetPosition", "()J", (void *) native_get_position}, - {"nativeGetDuration", "()J", (void *) native_get_duration}, - {"nativeGetVolume", "()D", (void *) native_get_volume}, - {"nativeSetVolume", "(D)V", (void *) native_set_volume}, - {"nativeGetMute", "()Z", (void *) native_get_mute}, - {"nativeSetMute", "(Z)V", (void *) native_set_mute}, - {"nativeSetSurface", "(Landroid/view/Surface;)V", - (void *) native_set_surface} -}; - -/* Library initializer */ -jint -JNI_OnLoad (JavaVM * vm, void *reserved) -{ - JNIEnv *env = NULL; - - java_vm = vm; - - if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not retrieve JNIEnv"); - return 0; - } - jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/Player"); - if (!klass) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not retrieve class org.freedesktop.gstreamer.Player"); - return 0; - } - if ((*env)->RegisterNatives (env, klass, native_methods, - G_N_ELEMENTS (native_methods))) { - __android_log_print (ANDROID_LOG_ERROR, "GstPlayer", - "Could not register native methods for org.freedesktop.gstreamer.Player"); - return 0; - } - - pthread_key_create (¤t_jni_env, detach_current_thread); - - return JNI_VERSION_1_4; -} diff --git a/playback/player/android/res/layout/main.xml b/playback/player/android/res/layout/main.xml deleted file mode 100644 index b745d80..0000000 --- a/playback/player/android/res/layout/main.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/playback/player/android/res/values/strings.xml b/playback/player/android/res/values/strings.xml deleted file mode 100644 index 9587e3c..0000000 --- a/playback/player/android/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - GStreamer Play - Play - Pause - diff --git a/playback/player/android/settings.gradle b/playback/player/android/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/playback/player/android/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/playback/player/android/src/org/freedesktop/gstreamer/Player.java b/playback/player/android/src/org/freedesktop/gstreamer/Player.java deleted file mode 100644 index e2bef8c..0000000 --- a/playback/player/android/src/org/freedesktop/gstreamer/Player.java +++ /dev/null @@ -1,241 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014-2015 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer; - -import java.io.Closeable; -import android.view.Surface; -import android.content.Context; -import org.freedesktop.gstreamer.GStreamer; - -public class Player implements Closeable { - private static native void nativeClassInit(); - public static void init(Context context) throws Exception { - System.loadLibrary("gstreamer_android"); - GStreamer.init(context); - - System.loadLibrary("gstplayer"); - nativeClassInit(); - } - - private long native_player; - private native void nativeNew(); - public Player() { - nativeNew(); - } - - private native void nativeFree(); - @Override - public void close() { - nativeFree(); - } - - private native void nativePlay(); - public void play() { - nativePlay(); - } - - private native void nativePause(); - public void pause() { - nativePause(); - } - - private native void nativeStop(); - public void stop() { - nativeStop(); - } - - private native void nativeSeek(long position); - public void seek(long position) { - nativeSeek(position); - } - - private native String nativeGetUri(); - public String getUri() { - return nativeGetUri(); - } - - private native void nativeSetUri(String uri); - public void setUri(String uri) { - nativeSetUri(uri); - } - - private native long nativeGetPosition(); - public long getPosition() { - return nativeGetPosition(); - } - - private native long nativeGetDuration(); - public long getDuration() { - return nativeGetDuration(); - } - - private native double nativeGetVolume(); - public double getVolume() { - return nativeGetVolume(); - } - - private native void nativeSetVolume(double volume); - public void setVolume(double volume) { - nativeSetVolume(volume); - } - - private native boolean nativeGetMute(); - public boolean getMute() { - return nativeGetMute(); - } - - private native void nativeSetMute(boolean mute); - public void setMute(boolean mute) { - nativeSetMute(mute); - } - - private Surface surface; - private native void nativeSetSurface(Surface surface); - public void setSurface(Surface surface) { - this.surface = surface; - nativeSetSurface(surface); - } - - public Surface getSurface() { - return surface; - } - - public static interface PositionUpdatedListener { - abstract void positionUpdated(Player player, long position); - } - - private PositionUpdatedListener positionUpdatedListener; - public void setPositionUpdatedListener(PositionUpdatedListener listener) { - positionUpdatedListener = listener; - } - - private void onPositionUpdated(long position) { - if (positionUpdatedListener != null) { - positionUpdatedListener.positionUpdated(this, position); - } - } - - public static interface DurationChangedListener { - abstract void durationChanged(Player player, long duration); - } - - private DurationChangedListener durationChangedListener; - public void setDurationChangedListener(DurationChangedListener listener) { - durationChangedListener = listener; - } - - private void onDurationChanged(long duration) { - if (durationChangedListener != null) { - durationChangedListener.durationChanged(this, duration); - } - } - - private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING}; - public enum State { - STOPPED, - BUFFERING, - PAUSED, - PLAYING - } - - public static interface StateChangedListener { - abstract void stateChanged(Player player, State state); - } - - private StateChangedListener stateChangedListener; - public void setStateChangedListener(StateChangedListener listener) { - stateChangedListener = listener; - } - - private void onStateChanged(int stateIdx) { - if (stateChangedListener != null) { - State state = stateMap[stateIdx]; - stateChangedListener.stateChanged(this, state); - } - } - - public static interface BufferingListener { - abstract void buffering(Player player, int percent); - } - - private BufferingListener bufferingListener; - public void setBufferingListener(BufferingListener listener) { - bufferingListener = listener; - } - - private void onBuffering(int percent) { - if (bufferingListener != null) { - bufferingListener.buffering(this, percent); - } - } - - public static interface EndOfStreamListener { - abstract void endOfStream(Player player); - } - - private EndOfStreamListener endOfStreamListener; - public void setEndOfStreamListener(EndOfStreamListener listener) { - endOfStreamListener = listener; - } - - private void onEndOfStream() { - if (endOfStreamListener != null) { - endOfStreamListener.endOfStream(this); - } - } - - // Keep these in sync with gstplayer.h - private static final Error[] errorMap = {Error.FAILED}; - public enum Error { - FAILED - } - - public static interface ErrorListener { - abstract void error(Player player, Error error, String errorMessage); - } - - private ErrorListener errorListener; - public void setErrorListener(ErrorListener listener) { - errorListener = listener; - } - - private void onError(int errorCode, String errorMessage) { - if (errorListener != null) { - Error error = errorMap[errorCode]; - errorListener.error(this, error, errorMessage); - } - } - - public static interface VideoDimensionsChangedListener { - abstract void videoDimensionsChanged(Player player, int width, int height); - } - - private VideoDimensionsChangedListener videoDimensionsChangedListener; - public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) { - videoDimensionsChangedListener = listener; - } - - private void onVideoDimensionsChanged(int width, int height) { - if (videoDimensionsChangedListener != null) { - videoDimensionsChangedListener.videoDimensionsChanged(this, width, height); - } - } -} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java b/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java deleted file mode 100644 index 075f035..0000000 --- a/playback/player/android/src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java +++ /dev/null @@ -1,110 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.SurfaceView; -import android.view.View; - -// A simple SurfaceView whose width and height can be set from the outside -public class GStreamerSurfaceView extends SurfaceView { - public int media_width = 320; - public int media_height = 240; - - // Mandatory constructors, they do not do much - public GStreamerSurfaceView(Context context, AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - } - - public GStreamerSurfaceView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public GStreamerSurfaceView (Context context) { - super(context); - } - - // Called by the layout manager to find out our size and give us some rules. - // We will try to maximize our size, and preserve the media's aspect ratio if - // we are given the freedom to do so. - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (media_width == 0 || media_height == 0) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - return; - } - - int width = 0, height = 0; - int wmode = View.MeasureSpec.getMode(widthMeasureSpec); - int hmode = View.MeasureSpec.getMode(heightMeasureSpec); - int wsize = View.MeasureSpec.getSize(widthMeasureSpec); - int hsize = View.MeasureSpec.getSize(heightMeasureSpec); - - Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height); - // Obey width rules - switch (wmode) { - case View.MeasureSpec.AT_MOST: - if (hmode == View.MeasureSpec.EXACTLY) { - width = Math.min(hsize * media_width / media_height, wsize); - break; - } - case View.MeasureSpec.EXACTLY: - width = wsize; - break; - case View.MeasureSpec.UNSPECIFIED: - width = media_width; - } - - // Obey height rules - switch (hmode) { - case View.MeasureSpec.AT_MOST: - if (wmode == View.MeasureSpec.EXACTLY) { - height = Math.min(wsize * media_height / media_width, hsize); - break; - } - case View.MeasureSpec.EXACTLY: - height = hsize; - break; - case View.MeasureSpec.UNSPECIFIED: - height = media_height; - } - - // Finally, calculate best size when both axis are free - if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) { - int correct_height = width * media_height / media_width; - int correct_width = height * media_width / media_height; - - if (correct_height < height) - height = correct_height; - else - width = correct_width; - } - - // Obey minimum size - width = Math.max (getSuggestedMinimumWidth(), width); - height = Math.max (getSuggestedMinimumHeight(), height); - setMeasuredDimension(width, height); - } - -} diff --git a/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java b/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java deleted file mode 100644 index 2874f05..0000000 --- a/playback/player/android/src/org/freedesktop/gstreamer/player/Play.java +++ /dev/null @@ -1,196 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 Sebastian Dröge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -package org.freedesktop.gstreamer.play; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.PowerManager; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageButton; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; -import android.widget.Toast; - -import org.freedesktop.gstreamer.Player; - -public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener { - private PowerManager.WakeLock wake_lock; - private Player player; - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - try { - Player.init(this); - } catch (Exception e) { - Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); - finish(); - return; - } - - setContentView(R.layout.main); - - player = new Player(); - - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play"); - wake_lock.setReferenceCounted(false); - - ImageButton play = (ImageButton) this.findViewById(R.id.button_play); - play.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - player.play(); - wake_lock.acquire(); - } - }); - - ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause); - pause.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - player.pause(); - wake_lock.release(); - } - }); - - final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); - sb.setOnSeekBarChangeListener(this); - - player.setPositionUpdatedListener(new Player.PositionUpdatedListener() { - public void positionUpdated(Player player, final long position) { - runOnUiThread (new Runnable() { - public void run() { - sb.setProgress((int) (position / 1000000)); - updateTimeWidget(); - } - }); - } - }); - - player.setDurationChangedListener(new Player.DurationChangedListener() { - public void durationChanged(Player player, final long duration) { - runOnUiThread (new Runnable() { - public void run() { - sb.setMax((int) (duration / 1000000)); - updateTimeWidget(); - } - }); - } - }); - - final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video); - player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() { - public void videoDimensionsChanged(Player player, final int width, final int height) { - runOnUiThread (new Runnable() { - public void run() { - Log.i ("GStreamer", "Media size changed to " + width + "x" + height); - gsv.media_width = width; - gsv.media_height = height; - runOnUiThread(new Runnable() { - public void run() { - gsv.requestLayout(); - } - }); - } - }); - } - }); - - SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video); - SurfaceHolder sh = sv.getHolder(); - sh.addCallback(this); - - String mediaUri = null; - Intent intent = getIntent(); - android.net.Uri uri = intent.getData(); - Log.i ("GStreamer", "Received URI: " + uri); - if (uri.getScheme().equals("content")) { - android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null); - cursor.moveToFirst(); - mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA)); - cursor.close(); - } else { - mediaUri = uri.toString(); - } - player.setUri(mediaUri); - - updateTimeWidget(); - } - - protected void onDestroy() { - player.close(); - super.onDestroy(); - } - - private void updateTimeWidget () { - final TextView tv = (TextView) this.findViewById(R.id.textview_time); - final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar); - final int pos = sb.getProgress(); - final int max = sb.getMax(); - - SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max)); - tv.setText(message); - } - - public void surfaceChanged(SurfaceHolder holder, int format, int width, - int height) { - Log.d("GStreamer", "Surface changed to format " + format + " width " - + width + " height " + height); - player.setSurface(holder.getSurface()); - } - - public void surfaceCreated(SurfaceHolder holder) { - Log.d("GStreamer", "Surface created: " + holder.getSurface()); - } - - public void surfaceDestroyed(SurfaceHolder holder) { - Log.d("GStreamer", "Surface destroyed"); - player.setSurface(null); - } - - public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { - if (!fromUser) return; - - updateTimeWidget(); - } - - public void onStartTrackingTouch(SeekBar sb) { - } - - public void onStopTrackingTouch(SeekBar sb) { - Log.d("GStreamer", "Seek to " + sb.getProgress()); - player.seek(((long) sb.getProgress()) * 1000000); - } -} -- cgit v1.2.3 From b46d26b81f7f2be95bad2738b652ca7a3b513d53 Mon Sep 17 00:00:00 2001 From: Mariusz Wasak Date: Wed, 16 Mar 2016 15:45:17 +0100 Subject: playback/player: gtk: Change True to glib TRUE to make gtk player project compile https://github.com/sdroege/gst-player/pull/149 --- playback/player/gtk/gtk-play.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index c91693b..6bc8fd8 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1060,7 +1060,7 @@ create_visualization_menu (GtkPlay * play) item = gtk_radio_menu_item_new_with_label (group, label); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); if (g_strcmp0 (label, cur_vis) == 0) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); g_object_set_data_full (G_OBJECT (item), "name", label, (GDestroyNotify) g_free); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); @@ -1075,7 +1075,7 @@ create_visualization_menu (GtkPlay * play) group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); g_object_set_data (G_OBJECT (item), "name", (gpointer) "disable"); if (cur_vis == NULL) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (visualization_changed_cb), play); gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); @@ -1130,7 +1130,7 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) g_object_set_data (G_OBJECT (item), "index", GINT_TO_POINTER (index)); g_object_set_data (G_OBJECT (item), "type", GSIZE_TO_POINTER (type)); if (current_index == index) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); g_free (buffer); g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (track_changed_cb), play); @@ -1143,7 +1143,7 @@ create_tracks_menu (GtkPlay * play, GstPlayerMediaInfo * media_info, GType type) g_object_set_data (G_OBJECT (item), "index", GINT_TO_POINTER (-1)); g_object_set_data (G_OBJECT (item), "type", GSIZE_TO_POINTER (type)); if (current_index == -1) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), True); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (track_changed_cb), play); gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); -- cgit v1.2.3 From edc47343838416f23cf0c0fa3aa8007d2b42ffcb Mon Sep 17 00:00:00 2001 From: Mariusz Wasak Date: Tue, 22 Mar 2016 15:45:36 +0100 Subject: playback/player: Changing icons names to make it visible on gtk player Fixes https://github.com/sdroege/gst-player/pull/150 --- playback/player/gtk/resources/toolbar.ui | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/playback/player/gtk/resources/toolbar.ui b/playback/player/gtk/resources/toolbar.ui index c185795..f71e2f2 100644 --- a/playback/player/gtk/resources/toolbar.ui +++ b/playback/player/gtk/resources/toolbar.ui @@ -7,7 +7,7 @@ True False 30 - gtk-media-forward + media-seek-forward 0 @@ -21,7 +21,7 @@ True False 30 - gtk-media-next + media-skip-forward 0 @@ -37,14 +37,14 @@ 0 0 35 - gtk-media-play + media-playback-start 0 True False 30 - gtk-media-previous + media-skip-backward restore_image @@ -58,7 +58,7 @@ True False 30 - gtk-media-rewind + media-seek-backward toolbar -- cgit v1.2.3 From 9c64ebb048a9407bd4bbc9ee87e1ad037dcc7307 Mon Sep 17 00:00:00 2001 From: Emmanuel Imbernon Date: Mon, 28 Mar 2016 17:09:59 +0200 Subject: playback/player: ios: Sync gst_ios_init.[mh] with latest version Fixes https://github.com/sdroege/gst-player/pull/154 --- playback/player/ios/GstPlay/gst_ios_init.h | 2 +- playback/player/ios/GstPlay/gst_ios_init.m | 104 +++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 20 deletions(-) diff --git a/playback/player/ios/GstPlay/gst_ios_init.h b/playback/player/ios/GstPlay/gst_ios_init.h index a880bf6..870515b 100644 --- a/playback/player/ios/GstPlay/gst_ios_init.h +++ b/playback/player/ios/GstPlay/gst_ios_init.h @@ -15,6 +15,7 @@ G_PASTE(g_io_module_, G_PASTE(name, _load_static)) () * You can also enable individual plugins. See gst_ios_init.c to see their names */ +//#define GST_IOS_PLUGINS_GES #define GST_IOS_PLUGINS_CORE //#define GST_IOS_PLUGINS_CAPTURE #define GST_IOS_PLUGINS_CODECS_RESTRICTED @@ -27,7 +28,6 @@ G_PASTE(g_io_module_, G_PASTE(name, _load_static)) () #define GST_IOS_PLUGINS_EFFECTS #define GST_IOS_PLUGINS_CODECS #define GST_IOS_PLUGINS_NET -//#define GST_IOS_PLUGINS_EDITING #define GST_IOS_GIO_MODULE_GNUTLS diff --git a/playback/player/ios/GstPlay/gst_ios_init.m b/playback/player/ios/GstPlay/gst_ios_init.m index 403f9f9..214b2e8 100644 --- a/playback/player/ios/GstPlay/gst_ios_init.m +++ b/playback/player/ios/GstPlay/gst_ios_init.m @@ -1,5 +1,8 @@ #include "gst_ios_init.h" +#if defined(GST_IOS_PLUGIN_NLE) || defined(GST_IOS_PLUGINS_GES) +GST_PLUGIN_STATIC_DECLARE(nle); +#endif #if defined(GST_IOS_PLUGIN_COREELEMENTS) || defined(GST_IOS_PLUGINS_CORE) GST_PLUGIN_STATIC_DECLARE(coreelements); #endif @@ -111,6 +114,12 @@ GST_PLUGIN_STATIC_DECLARE(realmedia); #if defined(GST_IOS_PLUGIN_X264) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) GST_PLUGIN_STATIC_DECLARE(x264); #endif +#if defined(GST_IOS_PLUGIN_LAME) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(lame); +#endif +#if defined(GST_IOS_PLUGIN_MPG123) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) +GST_PLUGIN_STATIC_DECLARE(mpg123); +#endif #if defined(GST_IOS_PLUGIN_LIBAV) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) GST_PLUGIN_STATIC_DECLARE(libav); #endif @@ -255,15 +264,15 @@ GST_PLUGIN_STATIC_DECLARE(gaudieffects); #if defined(GST_IOS_PLUGIN_GEOMETRICTRANSFORM) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_DECLARE(geometrictransform); #endif +#if defined(GST_IOS_PLUGIN_INTER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(inter); +#endif #if defined(GST_IOS_PLUGIN_INTERLACE) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_DECLARE(interlace); #endif #if defined(GST_IOS_PLUGIN_IVTC) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_DECLARE(ivtc); #endif -#if defined(GST_IOS_PLUGIN_LIVEADDER) || defined(GST_IOS_PLUGINS_EFFECTS) -GST_PLUGIN_STATIC_DECLARE(liveadder); -#endif #if defined(GST_IOS_PLUGIN_RAWPARSE) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_DECLARE(rawparse); #endif @@ -279,9 +288,18 @@ GST_PLUGIN_STATIC_DECLARE(smooth); #if defined(GST_IOS_PLUGIN_SPEED) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_DECLARE(speed); #endif +#if defined(GST_IOS_PLUGIN_SOUNDTOUCH) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(soundtouch); +#endif #if defined(GST_IOS_PLUGIN_VIDEOFILTERSBAD) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_DECLARE(videofiltersbad); #endif +#if defined(GST_IOS_PLUGIN_AUDIOMIXER) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(audiomixer); +#endif +#if defined(GST_IOS_PLUGIN_COMPOSITOR) || defined(GST_IOS_PLUGINS_EFFECTS) +GST_PLUGIN_STATIC_DECLARE(compositor); +#endif #if defined(GST_IOS_PLUGIN_SUBPARSE) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(subparse); #endif @@ -294,6 +312,9 @@ GST_PLUGIN_STATIC_DECLARE(theora); #if defined(GST_IOS_PLUGIN_VORBIS) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(vorbis); #endif +#if defined(GST_IOS_PLUGIN_OPUS) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(opus); +#endif #if defined(GST_IOS_PLUGIN_IVORBISDEC) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(ivorbisdec); #endif @@ -384,8 +405,8 @@ GST_PLUGIN_STATIC_DECLARE(dvbsuboverlay); #if defined(GST_IOS_PLUGIN_DVDSPU) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(dvdspu); #endif -#if defined(GST_IOS_PLUGIN_FRAGMENTED) || defined(GST_IOS_PLUGINS_CODECS) -GST_PLUGIN_STATIC_DECLARE(fragmented); +#if defined(GST_IOS_PLUGIN_HLS) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(hls); #endif #if defined(GST_IOS_PLUGIN_ID3TAG) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(id3tag); @@ -399,8 +420,11 @@ GST_PLUGIN_STATIC_DECLARE(midi); #if defined(GST_IOS_PLUGIN_MXF) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(mxf); #endif -#if defined(GST_IOS_PLUGIN_OPUS) || defined(GST_IOS_PLUGINS_CODECS) -GST_PLUGIN_STATIC_DECLARE(opus); +#if defined(GST_IOS_PLUGIN_OPENH264) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(openh264); +#endif +#if defined(GST_IOS_PLUGIN_OPUSPARSE) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(opusparse); #endif #if defined(GST_IOS_PLUGIN_PCAPPARSE) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(pcapparse); @@ -438,6 +462,12 @@ GST_PLUGIN_STATIC_DECLARE(gdp); #if defined(GST_IOS_PLUGIN_RSVG) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_DECLARE(rsvg); #endif +#if defined(GST_IOS_PLUGIN_OPENJPEG) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(openjpeg); +#endif +#if defined(GST_IOS_PLUGIN_SPANDSP) || defined(GST_IOS_PLUGINS_CODECS) +GST_PLUGIN_STATIC_DECLARE(spandsp); +#endif #if defined(GST_IOS_PLUGIN_TCP) || defined(GST_IOS_PLUGINS_NET) GST_PLUGIN_STATIC_DECLARE(tcp); #endif @@ -462,8 +492,11 @@ GST_PLUGIN_STATIC_DECLARE(dataurisrc); #if defined(GST_IOS_PLUGIN_SDP) || defined(GST_IOS_PLUGINS_NET) GST_PLUGIN_STATIC_DECLARE(sdp); #endif -#if defined(GST_IOS_PLUGIN_GNONLIN) || defined(GST_IOS_PLUGINS_EDITING) -GST_PLUGIN_STATIC_DECLARE(gnonlin); +#if defined(GST_IOS_PLUGIN_SRTP) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(srtp); +#endif +#if defined(GST_IOS_PLUGIN_RTSPCLIENTSINK) || defined(GST_IOS_PLUGINS_NET) +GST_PLUGIN_STATIC_DECLARE(rtspclientsink); #endif #if defined(GST_IOS_GIO_MODULE_GNUTLS) @@ -506,7 +539,10 @@ gst_ios_init (void) gst_init (NULL, NULL); - #if defined(GST_IOS_PLUGIN_COREELEMENTS) || defined(GST_IOS_PLUGINS_CORE) + #if defined(GST_IOS_PLUGIN_NLE) || defined(GST_IOS_PLUGINS_GES) + GST_PLUGIN_STATIC_REGISTER(nle); +#endif +#if defined(GST_IOS_PLUGIN_COREELEMENTS) || defined(GST_IOS_PLUGINS_CORE) GST_PLUGIN_STATIC_REGISTER(coreelements); #endif #if defined(GST_IOS_PLUGIN_ADDER) || defined(GST_IOS_PLUGINS_CORE) @@ -617,6 +653,12 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_X264) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) GST_PLUGIN_STATIC_REGISTER(x264); #endif +#if defined(GST_IOS_PLUGIN_LAME) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(lame); +#endif +#if defined(GST_IOS_PLUGIN_MPG123) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) + GST_PLUGIN_STATIC_REGISTER(mpg123); +#endif #if defined(GST_IOS_PLUGIN_LIBAV) || defined(GST_IOS_PLUGINS_CODECS_RESTRICTED) GST_PLUGIN_STATIC_REGISTER(libav); #endif @@ -761,15 +803,15 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_GEOMETRICTRANSFORM) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_REGISTER(geometrictransform); #endif +#if defined(GST_IOS_PLUGIN_INTER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(inter); +#endif #if defined(GST_IOS_PLUGIN_INTERLACE) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_REGISTER(interlace); #endif #if defined(GST_IOS_PLUGIN_IVTC) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_REGISTER(ivtc); #endif -#if defined(GST_IOS_PLUGIN_LIVEADDER) || defined(GST_IOS_PLUGINS_EFFECTS) - GST_PLUGIN_STATIC_REGISTER(liveadder); -#endif #if defined(GST_IOS_PLUGIN_RAWPARSE) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_REGISTER(rawparse); #endif @@ -785,9 +827,18 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_SPEED) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_REGISTER(speed); #endif +#if defined(GST_IOS_PLUGIN_SOUNDTOUCH) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(soundtouch); +#endif #if defined(GST_IOS_PLUGIN_VIDEOFILTERSBAD) || defined(GST_IOS_PLUGINS_EFFECTS) GST_PLUGIN_STATIC_REGISTER(videofiltersbad); #endif +#if defined(GST_IOS_PLUGIN_AUDIOMIXER) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(audiomixer); +#endif +#if defined(GST_IOS_PLUGIN_COMPOSITOR) || defined(GST_IOS_PLUGINS_EFFECTS) + GST_PLUGIN_STATIC_REGISTER(compositor); +#endif #if defined(GST_IOS_PLUGIN_SUBPARSE) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(subparse); #endif @@ -800,6 +851,9 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_VORBIS) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(vorbis); #endif +#if defined(GST_IOS_PLUGIN_OPUS) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(opus); +#endif #if defined(GST_IOS_PLUGIN_IVORBISDEC) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(ivorbisdec); #endif @@ -890,8 +944,8 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_DVDSPU) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(dvdspu); #endif -#if defined(GST_IOS_PLUGIN_FRAGMENTED) || defined(GST_IOS_PLUGINS_CODECS) - GST_PLUGIN_STATIC_REGISTER(fragmented); +#if defined(GST_IOS_PLUGIN_HLS) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(hls); #endif #if defined(GST_IOS_PLUGIN_ID3TAG) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(id3tag); @@ -905,8 +959,11 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_MXF) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(mxf); #endif -#if defined(GST_IOS_PLUGIN_OPUS) || defined(GST_IOS_PLUGINS_CODECS) - GST_PLUGIN_STATIC_REGISTER(opus); +#if defined(GST_IOS_PLUGIN_OPENH264) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(openh264); +#endif +#if defined(GST_IOS_PLUGIN_OPUSPARSE) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(opusparse); #endif #if defined(GST_IOS_PLUGIN_PCAPPARSE) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(pcapparse); @@ -944,6 +1001,12 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_RSVG) || defined(GST_IOS_PLUGINS_CODECS) GST_PLUGIN_STATIC_REGISTER(rsvg); #endif +#if defined(GST_IOS_PLUGIN_OPENJPEG) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(openjpeg); +#endif +#if defined(GST_IOS_PLUGIN_SPANDSP) || defined(GST_IOS_PLUGINS_CODECS) + GST_PLUGIN_STATIC_REGISTER(spandsp); +#endif #if defined(GST_IOS_PLUGIN_TCP) || defined(GST_IOS_PLUGINS_NET) GST_PLUGIN_STATIC_REGISTER(tcp); #endif @@ -968,8 +1031,11 @@ gst_ios_init (void) #if defined(GST_IOS_PLUGIN_SDP) || defined(GST_IOS_PLUGINS_NET) GST_PLUGIN_STATIC_REGISTER(sdp); #endif -#if defined(GST_IOS_PLUGIN_GNONLIN) || defined(GST_IOS_PLUGINS_EDITING) - GST_PLUGIN_STATIC_REGISTER(gnonlin); +#if defined(GST_IOS_PLUGIN_SRTP) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(srtp); +#endif +#if defined(GST_IOS_PLUGIN_RTSPCLIENTSINK) || defined(GST_IOS_PLUGINS_NET) + GST_PLUGIN_STATIC_REGISTER(rtspclientsink); #endif #if defined(GST_IOS_GIO_MODULE_GNUTLS) -- cgit v1.2.3 From 2435b0e37c754f0ad4d122acf83de2d2084110af Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 10 May 2016 22:01:54 +0300 Subject: playback/player: android: Update build tools version and ship gradle wrapper script --- playback/player/android/app/build.gradle | 4 +- .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53637 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + playback/player/android/gradlew | 160 +++++++++++++++++++++ playback/player/android/gradlew.bat | 90 ++++++++++++ 5 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 playback/player/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 playback/player/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 playback/player/android/gradlew create mode 100644 playback/player/android/gradlew.bat diff --git a/playback/player/android/app/build.gradle b/playback/player/android/app/build.gradle index e908022..50b135e 100644 --- a/playback/player/android/app/build.gradle +++ b/playback/player/android/app/build.gradle @@ -23,7 +23,7 @@ def getNdkCommandLine(ndkRoot, target) { android { compileSdkVersion 23 - buildToolsVersion "23.0.2" + buildToolsVersion "23.0.3" sourceSets { main { @@ -36,7 +36,7 @@ android { defaultConfig { applicationId "org.freedesktop.gstreamer.play" minSdkVersion 15 - targetSdkVersion 22 + targetSdkVersion 15 versionCode 1 versionName "1.0" } diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.jar b/playback/player/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..05ef575 Binary files /dev/null and b/playback/player/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.properties b/playback/player/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..428c55e --- /dev/null +++ b/playback/player/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue May 10 21:58:01 EEST 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-bin.zip diff --git a/playback/player/android/gradlew b/playback/player/android/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/playback/player/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/playback/player/android/gradlew.bat b/playback/player/android/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/playback/player/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega -- cgit v1.2.3 From 10dd3a21776d88394c06d9725993a4673d467756 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 20 Jul 2016 11:43:51 +0200 Subject: playback/player: Call gst_deinit() in all applications at the end of main() Needed to be able to track leaks using valgrind or the leaks tracer. --- playback/player/gst-play/gst-play.c | 1 + playback/player/gtk/gtk-play.c | 1 + playback/player/qt/main.cpp | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/playback/player/gst-play/gst-play.c b/playback/player/gst-play/gst-play.c index 46f6d62..bd21bd2 100644 --- a/playback/player/gst-play/gst-play.c +++ b/playback/player/gst-play/gst-play.c @@ -768,5 +768,6 @@ main (int argc, char **argv) play_free (play); g_print ("\n"); + gst_deinit (); return 0; } diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 6bc8fd8..7f9e588 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1910,5 +1910,6 @@ main (gint argc, gchar ** argv) status = g_application_run (G_APPLICATION (app), argc, argv);; g_object_unref (app); + gst_deinit (); return status; } diff --git a/playback/player/qt/main.cpp b/playback/player/qt/main.cpp index 4ef6b64..9a8adf6 100644 --- a/playback/player/qt/main.cpp +++ b/playback/player/qt/main.cpp @@ -30,6 +30,7 @@ int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); + int result; QCommandLineParser parser; parser.setApplicationDescription("GstPlayer"); @@ -70,5 +71,8 @@ int main(int argc, char *argv[]) if (!media_files.isEmpty()) player->setPlaylist(media_files); - return app.exec(); + result = app.exec(); + + gst_deinit (); + return result; } -- cgit v1.2.3 From 5b8ba60c46f66cb31313c516af17aed374c95465 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 20 Jul 2016 12:38:51 +0200 Subject: playback/player: gtk: fix gtkglsink leak The ref returned by gst_element_factory_make() was leaked. --- playback/player/gtk/gtk-video-renderer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-video-renderer.c b/playback/player/gtk/gtk-video-renderer.c index b34f927..c62af1c 100644 --- a/playback/player/gtk/gtk-video-renderer.c +++ b/playback/player/gtk/gtk-video-renderer.c @@ -114,12 +114,13 @@ gst_player_gtk_video_renderer_init (GstPlayerGtkVideoRenderer * self) } else { gtk_sink = gst_element_factory_make ("gtksink", NULL); - self->sink = gtk_sink; + self->sink = gst_object_ref (gtk_sink); } g_assert (self->sink != NULL); g_object_get (gtk_sink, "widget", &self->widget, NULL); + gst_object_unref (gtk_sink); } static GstElement *gst_player_gtk_video_renderer_create_video_sink -- cgit v1.2.3 From f8d4796a57bb28a2089791cb7b5c7d10427bfc63 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 20 Jul 2016 16:20:40 +0200 Subject: playback/player: gtk: fix widget leak The ref returned by gst_player_gtk_video_renderer_get_widget() was never released. --- playback/player/gtk/gtk-play.c | 1 + 1 file changed, 1 insertion(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 7f9e588..a520bef 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1775,6 +1775,7 @@ gtk_play_dispose (GObject * object) g_object_unref (self->player); } self->player = NULL; + g_clear_object (&self->video_area); G_OBJECT_CLASS (gtk_play_parent_class)->dispose (object); } -- cgit v1.2.3 From e82333ab704419307fa1a3703f492e4f04b51571 Mon Sep 17 00:00:00 2001 From: "Maxin B. John" Date: Fri, 5 Aug 2016 17:52:18 +0300 Subject: playback/player: gtk-play: provide similar behaviour for quit and close In x86 targets, gtk-play just pause rather than quitting the application when we click the close button (delete-event). Change the callback function to get similar behaviour when we click on "Quit" menu option. --- playback/player/gtk/gtk-play.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index a520bef..16afc6b 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -177,7 +177,7 @@ load_from_builder (const gchar * filename, gboolean register_sig_handler, static void delete_event_cb (GtkWidget * widget, GdkEvent * event, GtkPlay * play) { - gst_player_stop (play->player); + gtk_widget_destroy (GTK_WIDGET (play)); } static void -- cgit v1.2.3 From 89c74b3dd86000581d15270dddbee1f6a2cade39 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 18 Aug 2016 15:48:57 +0300 Subject: playback/player: gtk: Use GQueue instead of g_list_append() or the prepend-reverse trick --- playback/player/gtk/gtk-play.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 16afc6b..8aa6975 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -544,7 +544,7 @@ static GList * open_file_dialog (GtkPlay * play, gboolean multi) { int res; - GList *uris = NULL; + GQueue uris = G_QUEUE_INIT; GtkWidget *chooser; GtkWidget *parent; @@ -568,7 +568,7 @@ open_file_dialog (GtkPlay * play, gboolean multi) l = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser)); while (l) { - uris = g_list_append (uris, l->data); + g_queue_push_tail (&uris, l->data); l = g_slist_delete_link (l, l); } } @@ -577,7 +577,7 @@ open_file_dialog (GtkPlay * play, gboolean multi) if (!play) gtk_widget_destroy (parent); - return uris; + return uris.head; } static void @@ -1828,16 +1828,15 @@ gtk_play_app_command_line (GApplication * application, if (uris_array) { gchar **p; + GQueue uris_builder = G_QUEUE_INIT; p = uris_array; while (*p) { - uris = - g_list_prepend (uris, - gst_uri_is_valid (*p) ? + g_queue_push_tail (&uris_builder, gst_uri_is_valid (*p) ? g_strdup (*p) : gst_filename_to_uri (*p, NULL)); p++; } - uris = g_list_reverse (uris); + uris = uris_builder.head; } else { uris = open_file_dialog (NULL, TRUE); } -- cgit v1.2.3 From 1d760d92ed6076003112f0653a27e26f11912c1d Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Mon, 22 Aug 2016 16:19:59 +0300 Subject: playback/player: gtk: Block value-change signal handler while updating the range of the seekbar too I.e. when updating the duration. Changing the range might also change the value, which would then trigger a seek. --- playback/player/gtk/gtk-play.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 8aa6975..6dac913 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -1504,8 +1504,12 @@ create_ui (GtkPlay * play) static void duration_changed_cb (GstPlayer * unused, GstClockTime duration, GtkPlay * play) { + g_signal_handlers_block_by_func (play->seekbar, + seekbar_value_changed_cb, play); gtk_range_set_range (GTK_RANGE (play->seekbar), 0.0, (gdouble) duration / GST_SECOND); + g_signal_handlers_unblock_by_func (play->seekbar, + seekbar_value_changed_cb, play); } static void -- cgit v1.2.3 From 5743b39d4e5a11e2fdc2402b14d3032ebbc15fc0 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Wed, 27 Jul 2016 21:10:31 +0530 Subject: playback/player: android: Update build tools and gradle New build tools needed for Instant Run, and Android Studio wants us to update that and the gradle version. --- playback/player/android/build.gradle | 2 +- playback/player/android/gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/playback/player/android/build.gradle b/playback/player/android/build.gradle index e0b366a..77ce66e 100644 --- a/playback/player/android/build.gradle +++ b/playback/player/android/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.android.tools.build:gradle:2.1.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/playback/player/android/gradle/wrapper/gradle-wrapper.properties b/playback/player/android/gradle/wrapper/gradle-wrapper.properties index 428c55e..fc500fd 100644 --- a/playback/player/android/gradle/wrapper/gradle-wrapper.properties +++ b/playback/player/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue May 10 21:58:01 EEST 2016 +#Tue Aug 23 11:07:06 IST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip -- cgit v1.2.3 From d30c65f9f8e4df372794a6007cfd1bea9f16c776 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 23 Aug 2016 19:02:53 +0300 Subject: playback/player: Block value-changed signal when playing an URI to prevent spurious seeks --- playback/player/gtk/gtk-play.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 6dac913..3ff03cd 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -409,7 +409,11 @@ static void play_current_uri (GtkPlay * play, GList * uri, const gchar * ext_suburi) { /* reset the button/widget state to default */ + g_signal_handlers_block_by_func (play->seekbar, + seekbar_value_changed_cb, play); gtk_range_set_range (GTK_RANGE (play->seekbar), 0, 0); + g_signal_handlers_unblock_by_func (play->seekbar, + seekbar_value_changed_cb, play); gtk_widget_set_sensitive (play->prev_button, g_list_previous (uri) != NULL); gtk_widget_set_sensitive (play->next_button, g_list_next (uri) != NULL); gtk_label_set_label (play->rate_label, NULL); -- cgit v1.2.3 From f6cf0dd99701be7f3632c3e7c99c65eb404df018 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 23 Aug 2016 23:48:26 +0300 Subject: playback/player: gtk: Remove unused variable --- playback/player/gtk/gtk-play.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/playback/player/gtk/gtk-play.c b/playback/player/gtk/gtk-play.c index 3ff03cd..8ae0fea 100644 --- a/playback/player/gtk/gtk-play.c +++ b/playback/player/gtk/gtk-play.c @@ -60,7 +60,6 @@ typedef struct GstPlayer *player; GstPlayerVideoRenderer *renderer; - gchar *uri; GList *uris; GList *current_uri; @@ -1771,10 +1770,6 @@ gtk_play_dispose (GObject * object) self->inhibit_cookie); self->inhibit_cookie = 0; - if (self->uri) - g_free (self->uri); - self->uri = NULL; - if (self->uris) g_list_free_full (self->uris, g_free); self->uris = NULL; -- cgit v1.2.3