summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuis de Bethencourt <luis@debethencourt.com>2011-03-29 17:26:38 +0200
committerLuis de Bethencourt <luis@debethencourt.com>2011-03-29 17:26:38 +0200
commitb5f5cf1de62b0a37172db12505373fbdabc3b6d4 (patch)
tree703b03714669069c2f3430db33fcb9f7550ed75b
parenta8adf3a0d65ed56c4d3d925b56f3755277bd8ef3 (diff)
engine: continue playback where file was closed
save position of playback if snappy is closed and the file is longer than 5 minutes, position is >5% || <95% of the stream and ~/.config/snappy/config file exists.
-rw-r--r--src/gst_engine.c204
-rw-r--r--src/gst_engine.h7
-rw-r--r--src/snappy.c6
3 files changed, 188 insertions, 29 deletions
diff --git a/src/gst_engine.c b/src/gst_engine.c
index 815418a..ebc943e 100644
--- a/src/gst_engine.c
+++ b/src/gst_engine.c
@@ -25,10 +25,148 @@
#include "user_interface.h"
#include "gst_engine.h"
+#define SAVE_POSITION_MIN_DURATION 300 * 1000 // don't save >5 minute files
+#define SAVE_POSITION_THRESHOLD 0.05 // percentage threshold
+
+/* -------------------- static functions --------------------- */
+
+gint64
+uri_is_unfinished_playback (GstEngine * engine, gchar * uri)
+{
+ guint hash_key;
+ gint64 position = -1;
+ const gchar *config_dir;
+ gchar *path, *key;
+ GKeyFile *keyfile;
+ GKeyFileFlags flags;
+
+ keyfile = g_key_file_new ();
+ flags = G_KEY_FILE_KEEP_COMMENTS;
+ hash_key = g_str_hash (uri);
+ asprintf (&key, "%d", hash_key);
+
+ // config file path
+ config_dir = g_get_user_config_dir ();
+ asprintf (&path, "%s/snappy/config", config_dir);
+
+ if (g_key_file_load_from_file (keyfile, path, flags, NULL))
+ if (g_key_file_has_group (keyfile, "unfinished"))
+ if (g_key_file_has_key (keyfile, "unfinished", key, NULL))
+ position = g_key_file_get_int64 (keyfile, "unfinished", key, NULL);
+
+ g_key_file_free (keyfile);
+ g_free (path);
+
+ return position;
+}
+
+gboolean
+add_uri_unfinished_playback (GstEngine * engine, gchar * uri, gint64 position)
+{
+ guint hash_key;
+ gint64 duration;
+ const gchar *config_dir;
+ gchar *path, *data, *key;
+ FILE *file;
+ GKeyFile *keyfile;
+ GKeyFileFlags flags;
+
+ duration = engine->media_duration;
+ if (duration < SAVE_POSITION_MIN_DURATION ||
+ (duration - position) < (duration * SAVE_POSITION_THRESHOLD) ||
+ (position < duration * SAVE_POSITION_THRESHOLD)) {
+ // remove in case position is already stored and close
+ remove_uri_unfinished_playback (engine, uri);
+ return FALSE;
+ }
+
+ keyfile = g_key_file_new ();
+ flags = G_KEY_FILE_KEEP_COMMENTS;
+ hash_key = g_str_hash (uri);
+ asprintf (&key, "%d", hash_key);
+
+ // config file path
+ config_dir = g_get_user_config_dir ();
+ asprintf (&path, "%s/snappy/config", config_dir);
+
+ g_key_file_load_from_file (keyfile, path, flags, NULL);
+ // if file doesn't exist it uses the newly created one
+ g_key_file_set_int64 (keyfile, "unfinished", key, position);
+
+ // save gkeyfile to a file
+ data = g_key_file_to_data (keyfile, NULL, NULL);
+ file = fopen (path, "w");
+ fputs (data, file);
+ fclose (file);
+
+ g_free (data);
+ g_free (path);
+
+ return TRUE;
+}
+
+gboolean
+remove_uri_unfinished_playback (GstEngine * engine, gchar * uri)
+{
+ guint hash_key;
+ const gchar *config_dir;
+ gchar *path, *data, *key;
+ FILE *file;
+ GKeyFile *keyfile;
+ GKeyFileFlags flags;
+
+ keyfile = g_key_file_new ();
+ flags = G_KEY_FILE_KEEP_COMMENTS;
+ hash_key = g_str_hash (uri);
+ asprintf (&key, "%d", hash_key);
+
+ // config file path
+ config_dir = g_get_user_config_dir ();
+ asprintf (&path, "%s/snappy/config", config_dir);
+
+ // remove key if gkeyfile exists
+ if (g_key_file_load_from_file (keyfile, path, flags, NULL))
+ g_key_file_remove_key (keyfile, "unfinished", key, NULL);
+
+ // save gkeyfile to a file
+ data = g_key_file_to_data (keyfile, NULL, NULL);
+ file = fopen (path, "w");
+ fputs (data, file);
+ fclose (file);
+
+ g_free (data);
+ g_free (path);
+
+ return TRUE;
+}
/* -------------------- non-static functions --------------------- */
gboolean
+add_uri_unfinished (GstEngine * engine)
+{
+ gint64 position;
+
+ position = query_position (engine);
+ add_uri_unfinished_playback (engine, engine->uri, position);
+
+ return TRUE;
+}
+
+gboolean
+at_the_eos (GstEngine * engine)
+{
+ gboolean ret = TRUE;
+ gint64 position;
+
+ position = query_position (engine);
+ if (position < engine->media_duration)
+ ret = FALSE;
+
+ return ret;
+}
+
+gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
UserInterface *ui = (UserInterface *) data;
@@ -37,6 +175,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_debug ("End-of-stream\n");
+ remove_uri_unfinished_playback (engine, engine->uri);
break;
case GST_MESSAGE_ERROR:
{
@@ -75,6 +214,7 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
heightval = gst_structure_get_value (s, "height");
if (G_VALUE_HOLDS (widthval, G_TYPE_INT)) {
gint width, height;
+ gint64 position;
width = g_value_get_int (widthval);
height = g_value_get_int (heightval);
@@ -82,6 +222,10 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
engine->media_height = height;
update_media_duration (ui->engine);
load_user_interface (ui);
+
+ position = uri_is_unfinished_playback (engine, engine->uri);
+ if (position != -1)
+ seek (engine, position);
}
}
}
@@ -100,7 +244,8 @@ bus_call (GstBus * bus, GstMessage * msg, gpointer data)
return TRUE;
}
-gboolean engine_load (GstEngine * engine, GstElement * sink)
+gboolean
+engine_load (GstEngine * engine, GstElement * sink)
{
engine->player = gst_element_factory_make ("playbin2", "playbin2");
if (engine->player == NULL) {
@@ -115,8 +260,11 @@ gboolean engine_load (GstEngine * engine, GstElement * sink)
return TRUE;
}
-gboolean engine_load_uri (GstEngine * engine, gchar * uri)
+gboolean
+engine_load_uri (GstEngine * engine, gchar * uri)
{
+ gint64 position;
+
engine->uri = uri;
g_object_set (G_OBJECT (engine->player), "uri", uri, NULL);
g_print ("Loading: %s\n", uri);
@@ -124,19 +272,18 @@ gboolean engine_load_uri (GstEngine * engine, gchar * uri)
return TRUE;
}
-gboolean frame_stepping (GstEngine * engine, gboolean foward)
+gboolean
+frame_stepping (GstEngine * engine, gboolean foward)
{
gboolean ok;
gint64 pos;
gdouble rate;
GstFormat fmt;
- if (engine->prev_done)
- {
+ if (engine->prev_done) {
engine->prev_done = FALSE;
- if (foward != engine->direction_foward)
- {
+ if (foward != engine->direction_foward) {
engine->direction_foward = foward;
fmt = GST_FORMAT_TIME;
@@ -144,20 +291,18 @@ gboolean frame_stepping (GstEngine * engine, gboolean foward)
gst_element_get_state (engine->player, NULL, NULL, GST_SECOND);
if (foward)
- rate = 1.0;
+ rate = 1.0;
else
- rate = -1.0;
+ rate = -1.0;
if (rate >= 0.0) {
- ok = gst_element_seek (engine->player, rate, fmt,
- GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
- GST_SEEK_TYPE_SET, pos,
- GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
+ ok = gst_element_seek (engine->player, rate, fmt,
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+ GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE);
} else {
- ok = gst_element_seek (engine->player, rate, fmt,
+ ok = gst_element_seek (engine->player, rate, fmt,
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
- GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0),
- GST_SEEK_TYPE_SET, pos);
+ GST_SEEK_TYPE_SET, G_GINT64_CONSTANT (0), GST_SEEK_TYPE_SET, pos);
}
gst_element_get_state (engine->player, NULL, NULL, GST_SECOND);
}
@@ -170,7 +315,17 @@ gboolean frame_stepping (GstEngine * engine, gboolean foward)
return FALSE;
}
-gint64 query_position (GstEngine *engine)
+GstState
+get_state (GstEngine * engine)
+{
+ GstState state;
+ gst_element_get_state (engine->player, &state, NULL, GST_SECOND);
+
+ return state;
+}
+
+gint64
+query_position (GstEngine * engine)
{
gint64 position;
GstFormat fmt = GST_FORMAT_TIME;
@@ -179,7 +334,8 @@ gint64 query_position (GstEngine *engine)
return position;
}
-gboolean seek (GstEngine * engine, gint64 position)
+gboolean
+seek (GstEngine * engine, gint64 position)
{
GstFormat fmt = GST_FORMAT_TIME;
@@ -188,23 +344,21 @@ gboolean seek (GstEngine * engine, gint64 position)
return TRUE;
}
-gboolean change_state (GstEngine * engine, gchar * state)
+gboolean
+change_state (GstEngine * engine, gchar * state)
{
if (state == "Playing") {
gst_element_set_state (engine->player, GST_STATE_PLAYING);
engine->playing = TRUE;
- }
- else if (state == "Paused") {
+ } else if (state == "Paused") {
gst_element_set_state (engine->player, GST_STATE_PAUSED);
engine->playing = FALSE;
engine->media_duration = -1;
- }
- else if (state == "Ready") {
+ } else if (state == "Ready") {
gst_element_set_state (engine->player, GST_STATE_READY);
engine->playing = FALSE;
engine->media_duration = -1;
- }
- else if (state == "Null") {
+ } else if (state == "Null") {
gst_element_set_state (engine->player, GST_STATE_NULL);
engine->playing = FALSE;
engine->media_duration = -1;
diff --git a/src/gst_engine.h b/src/gst_engine.h
index 4a407f5..22d2791 100644
--- a/src/gst_engine.h
+++ b/src/gst_engine.h
@@ -23,9 +23,7 @@
#ifndef __GST_ENGINE_H__
#define __GST_ENGINE_H__
-G_BEGIN_DECLS
-
-typedef struct _GstEngine GstEngine;
+G_BEGIN_DECLS typedef struct _GstEngine GstEngine;
struct _GstEngine
{
@@ -44,10 +42,13 @@ struct _GstEngine
};
// Declaration of non-static functions
+gboolean add_uri_unfinished (GstEngine * engine);
+gboolean at_the_eos (GstEngine * engine);
gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data);
gboolean engine_load (GstEngine * engine, GstElement * sink);
gboolean engine_load_uri (GstEngine * engine, gchar * uri);
gboolean frame_stepping (GstEngine * engine, gboolean foward);
+GstState get_state (GstEngine * engine);
gint64 query_position (GstEngine * engine);
gboolean seek (GstEngine * engine, gint64 position);
gboolean change_state (GstEngine * engine, gchar * state);
diff --git a/src/snappy.c b/src/snappy.c
index cae2980..a729211 100644
--- a/src/snappy.c
+++ b/src/snappy.c
@@ -113,7 +113,6 @@ main (int argc, char *argv[])
fileuri = clean_uri (file_list[0]);
asprintf (&uri, "file://%s", fileuri);
- g_print ("Loading: %s\n", uri);
engine_load_uri (engine, uri);
interface_load_uri (ui, uri);
@@ -122,6 +121,11 @@ main (int argc, char *argv[])
clutter_main ();
+ g_print ("closing snappy\n");
+
+ // save position if file isn't finished playing
+ add_uri_unfinished (engine);
+
change_state (engine, "Null");
gst_object_unref (engine->player);