Added qmafw-gst-subtitles-renderer-0.0.55 for Meego Harmattan 1.2
[mafwsubrenderer] / qmafw-gst-subtitles-renderer / src / mafw-gst-renderer-seeker.c
diff --git a/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-seeker.c b/qmafw-gst-subtitles-renderer/src/mafw-gst-renderer-seeker.c
new file mode 100644 (file)
index 0000000..07d7fc6
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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;
+}