--- /dev/null
+/*
+ * This file is part of QMAFW
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights
+ * reserved.
+ *
+ * Contact: Visa Smolander <visa.smolander@nokia.com>
+ *
+ * This software, including documentation, is protected by copyright controlled
+ * by Nokia Corporation. All rights are reserved. Copying, including
+ * reproducing, storing, adapting or translating, any or all of this material
+ * requires the prior written consent of Nokia Corporation. This material also
+ * contains confidential information which may not be disclosed to others
+ * without the prior written consent of Nokia.
+ *
+ */
+
+#include "mafw-gst-renderer-seeker.h"
+
+#include <gst/gst.h>
+
+#define CLOSE_LIMIT 2
+#define MOVE_FORWARD 10
+
+typedef struct {
+ gint64 required_pos;
+ gint64 starting_pos;
+ gint64 current_pos;
+} seek_request;
+
+struct _MafwGstRendererSeeker {
+ GstElement *pipeline;
+ seek_request last_request;
+};
+
+gint64 _get_current_pos(GstElement* pipeline)
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 time = 0;
+
+ if(pipeline &&
+ gst_element_query_position(pipeline, &format, &time))
+ {
+ return (time + (GST_SECOND/2)) / GST_SECOND;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+gint64 _get_duration(GstElement *pipeline)
+{
+ gint64 value = -1;
+ GstFormat format = GST_FORMAT_TIME;
+
+ gboolean success = gst_element_query_duration(pipeline, &format, &value);
+ if( success )
+ {
+ return (value + (GST_SECOND/2)) / GST_SECOND;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+gboolean _try_seek_required_pos(MafwGstRendererSeeker *seeker)
+{
+ gboolean ret;
+ gint64 spos;
+ GstSeekFlags flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT;
+
+
+ spos = (seeker->last_request.required_pos) * GST_SECOND;
+ g_debug("seek target: %lld", spos);
+
+ ret = gst_element_seek(seeker->pipeline,
+ 1.0,
+ GST_FORMAT_TIME,
+ flags,
+ GST_SEEK_TYPE_SET,
+ spos,
+ GST_SEEK_TYPE_NONE,
+ GST_CLOCK_TIME_NONE);
+
+ return ret;
+}
+
+gboolean _is_position_close_enough(gint64 pos, gint64 required_pos)
+{
+ return ABS((pos - required_pos)) < CLOSE_LIMIT;
+}
+
+gboolean _has_position_changed_enough(gint64 pos, gint64 required_pos)
+{
+ return !_is_position_close_enough(pos, required_pos);
+}
+
+MafwGstRendererSeeker* mafw_gst_renderer_seeker_new()
+{
+ return g_new0(MafwGstRendererSeeker, 1);
+}
+
+void mafw_gst_renderer_seeker_free(MafwGstRendererSeeker *seeker)
+{
+ g_free(seeker);
+}
+
+void mafw_gst_renderer_seeker_set_pipeline(MafwGstRendererSeeker *seeker, GstElement *pipeline)
+{
+ seeker->pipeline = pipeline;
+ mafw_gst_renderer_seeker_cancel(seeker);
+}
+
+gboolean mafw_gst_renderer_seeker_seek_to(MafwGstRendererSeeker *seeker, gint64 seek_pos)
+{
+ if( seeker == NULL )
+ {
+ g_critical("Seeker is NULL!");
+ return FALSE;
+ }
+
+ seek_request *request = &(seeker->last_request);
+ request->required_pos = seek_pos;
+ request->starting_pos = _get_current_pos(seeker->pipeline);
+ request->current_pos = request->starting_pos;
+
+ return _try_seek_required_pos(seeker);
+
+}
+
+void mafw_gst_renderer_seeker_cancel(MafwGstRendererSeeker *seeker)
+{
+ seek_request *request = &(seeker->last_request);
+ request->current_pos = -1;
+ request->required_pos = -1;
+ request->starting_pos = -1;
+}
+
+gint64 mafw_gst_renderer_seeker_process(MafwGstRendererSeeker *seeker)
+{
+ if( seeker == NULL )
+ {
+ g_critical("Seeker is NULL!");
+ return -1;
+ }
+
+ seek_request *request = &(seeker->last_request);
+
+ if(request->required_pos < 0)
+ {
+ g_debug("[Seeker] No valid request set! Doing nothing,");
+ return request->required_pos;
+ }
+
+ request->current_pos = _get_current_pos(seeker->pipeline);
+ if( request->current_pos < 0 )
+ {
+ mafw_gst_renderer_seeker_cancel(seeker);
+ g_warning("[Seeker] Could not get position! Cannot refine seek!");
+ return seeker->last_request.current_pos;
+ }
+
+ gboolean forward_seek = ( request->required_pos >= request->starting_pos );
+
+ if( _is_position_close_enough(request->current_pos, request->required_pos)
+ ||
+ ((_has_position_changed_enough(request->current_pos, request->starting_pos)
+ && forward_seek
+ && request->current_pos > request->starting_pos)) )
+ {
+ g_debug("Got good enough seek result: Current pos: %lld, Required pos: %lld", request->current_pos, request->required_pos);
+ mafw_gst_renderer_seeker_cancel(seeker);
+ }
+ else
+ {
+ if( forward_seek )
+ {
+ request->required_pos += MOVE_FORWARD;
+ gint64 duration = _get_duration(seeker->pipeline);
+ if( request->required_pos > duration )
+ {
+ g_debug("[Seeker] Cancelling increased seek target beyond media length!");
+ mafw_gst_renderer_seeker_cancel(seeker);
+ }
+ }
+ else
+ {
+ g_debug("Backward seek done, cannot do better...");
+ mafw_gst_renderer_seeker_cancel(seeker);
+ }
+ }
+
+ if( request->required_pos >= 0 )
+ {
+ _try_seek_required_pos(seeker);
+ }
+
+ return request->required_pos;
+}