Source tree moved to mafw-gst-subtitles-renderer directory.
[mafwsubrenderer] / libmafw-gst-renderer / mafw-gst-renderer-worker.c
diff --git a/libmafw-gst-renderer/mafw-gst-renderer-worker.c b/libmafw-gst-renderer/mafw-gst-renderer-worker.c
deleted file mode 100644 (file)
index 2404608..0000000
+++ /dev/null
@@ -1,2464 +0,0 @@
-/*
- * This file is a part of MAFW
- *
- * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
- *
- * Contact: Visa Smolander <visa.smolander@nokia.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; version 2.1 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 <string.h>
-#include <glib.h>
-#include <X11/Xlib.h>
-#include <gst/interfaces/xoverlay.h>
-#include <gst/pbutils/missing-plugins.h>
-#include <gst/base/gstbasesink.h>
-#include <libmafw/mafw.h>
-
-#ifdef HAVE_GDKPIXBUF
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <glib/gstdio.h>
-#include <unistd.h>
-#include "gstscreenshot.h"
-#endif
-
-#include <totem-pl-parser.h>
-#include "mafw-gst-renderer.h"
-#include "mafw-gst-renderer-worker.h"
-#include "mafw-gst-renderer-utils.h"
-#include "blanking.h"
-#include "keypad.h"
-
-#undef  G_LOG_DOMAIN
-#define G_LOG_DOMAIN "mafw-gst-renderer-worker"
-
-#define MAFW_GST_RENDERER_WORKER_SECONDS_READY 60
-#define MAFW_GST_RENDERER_WORKER_SECONDS_DURATION_AND_SEEKABILITY 4
-
-#define MAFW_GST_MISSING_TYPE_DECODER "decoder"
-#define MAFW_GST_MISSING_TYPE_ENCODER "encoder"
-
-#define MAFW_GST_BUFFER_TIME  600000L
-#define MAFW_GST_LATENCY_TIME (MAFW_GST_BUFFER_TIME / 2)
-
-#define NSECONDS_TO_SECONDS(ns) ((ns)%1000000000 < 500000000?\
-                                 GST_TIME_AS_SECONDS((ns)):\
-                                 GST_TIME_AS_SECONDS((ns))+1)
-
-#define _current_metadata_add(worker, key, type, value)        \
-               do { \
-                       if (!worker->current_metadata) \
-                               worker->current_metadata = mafw_metadata_new(); \
-                       /* At first remove old value */ \
-                       g_hash_table_remove(worker->current_metadata, key); \
-                       mafw_metadata_add_something(worker->current_metadata, \
-                                       key, type, 1, value); \
-               } while (0)
-
-/* Private variables. */
-/* Global reference to worker instance, needed for Xerror handler */
-static MafwGstRendererWorker *Global_worker = NULL;
-
-/* Forward declarations. */
-static void _do_play(MafwGstRendererWorker *worker);
-static void _do_seek(MafwGstRendererWorker *worker, GstSeekType seek_type,
-                    gint position, GError **error);
-static void _play_pl_next(MafwGstRendererWorker *worker);
-
-static void _emit_metadatas(MafwGstRendererWorker *worker);
-
-/* Playlist parsing */
-static void _on_pl_entry_parsed(TotemPlParser *parser, gchar *uri,
-                               gpointer metadata, GSList **plitems)
-{
-       if (uri != NULL) {
-               *plitems = g_slist_append(*plitems, g_strdup(uri));
-       }
-}
-static GSList *_parse_playlist(const gchar *uri)
-{
-       static TotemPlParser *pl_parser = NULL;
-       GSList *plitems = NULL;
-       gulong handler_id;
-
-       /* Initialize the playlist parser */
-       if (!pl_parser)
-       {
-               pl_parser = totem_pl_parser_new ();
-               g_object_set(pl_parser, "recurse", TRUE, "disable-unsafe",
-                    TRUE, NULL);
-       }
-       handler_id = g_signal_connect(G_OBJECT(pl_parser), "entry-parsed",
-                        G_CALLBACK(_on_pl_entry_parsed), &plitems);
-       /* Parsing */
-       if (totem_pl_parser_parse(pl_parser, uri, FALSE) !=
-           TOTEM_PL_PARSER_RESULT_SUCCESS) {
-               /* An error happens while parsing */
-               
-       }
-       g_signal_handler_disconnect(pl_parser, handler_id);
-       return plitems;
-}
-               
-/*
- * Sends @error to MafwGstRenderer.  Only call this from the glib main thread, or
- * face the consequences.  @err is free'd.
- */
-static void _send_error(MafwGstRendererWorker *worker, GError *err)
-{
-       worker->is_error = TRUE;
-        if (worker->notify_error_handler)
-                worker->notify_error_handler(worker, worker->owner, err);
-       g_error_free(err);
-}
-
-/*
- * Posts an @error on the gst bus.  _async_bus_handler will then pick it up and
- * forward to MafwGstRenderer.  @err is free'd.
- */
-static void _post_error(MafwGstRendererWorker *worker, GError *err)
-{
-       gst_bus_post(worker->bus,
-                    gst_message_new_error(GST_OBJECT(worker->pipeline),
-                                          err, NULL));
-       g_error_free(err);
-}
-
-#ifdef HAVE_GDKPIXBUF
-typedef struct {
-       MafwGstRendererWorker *worker;
-       gchar *metadata_key;
-       GdkPixbuf *pixbuf;
-} SaveGraphicData;
-
-static gchar *_init_tmp_file(void)
-{
-       gint fd;
-       gchar *path = NULL;
-
-       fd = g_file_open_tmp("mafw-gst-renderer-XXXXXX.jpeg", &path, NULL);
-       close(fd);
-
-       return path;
-}
-
-static void _init_tmp_files_pool(MafwGstRendererWorker *worker)
-{
-       guint8 i;
-
-       worker->tmp_files_pool_index = 0;
-
-       for (i = 0; i < MAFW_GST_RENDERER_MAX_TMP_FILES; i++) {
-               worker->tmp_files_pool[i] = NULL;
-       }
-}
-
-static void _destroy_tmp_files_pool(MafwGstRendererWorker *worker)
-{
-       guint8 i;
-
-       for (i = 0; (i < MAFW_GST_RENDERER_MAX_TMP_FILES) &&
-                    (worker->tmp_files_pool[i] != NULL); i++) {
-               g_unlink(worker->tmp_files_pool[i]);
-               g_free(worker->tmp_files_pool[i]);
-       }
-}
-
-static const gchar *_get_tmp_file_from_pool(
-                        MafwGstRendererWorker *worker)
-{
-       gchar *path = worker->tmp_files_pool[worker->tmp_files_pool_index];
-
-       if (path == NULL) {
-               path = _init_tmp_file();
-               worker->tmp_files_pool[worker->tmp_files_pool_index] = path;
-       }
-
-       if (++(worker->tmp_files_pool_index) >=
-           MAFW_GST_RENDERER_MAX_TMP_FILES) {
-               worker->tmp_files_pool_index = 0;
-       }
-
-       return path;
-}
-
-static void _destroy_pixbuf (guchar *pixbuf, gpointer data)
-{
-       gst_buffer_unref(GST_BUFFER(data));
-}
-
-static void _emit_gst_buffer_as_graphic_file_cb(GstBuffer *new_buffer,
-                                               gpointer user_data)
-{
-       SaveGraphicData *sgd = user_data;
-       GdkPixbuf *pixbuf = NULL;
-
-       if (new_buffer != NULL) {
-               gint width, height;
-               GstStructure *structure;
-
-               structure =
-                       gst_caps_get_structure(GST_BUFFER_CAPS(new_buffer), 0);
-
-               gst_structure_get_int(structure, "width", &width);
-               gst_structure_get_int(structure, "height", &height);
-
-               pixbuf = gdk_pixbuf_new_from_data(
-                       GST_BUFFER_DATA(new_buffer), GDK_COLORSPACE_RGB,
-                       FALSE, 8, width, height,
-                       GST_ROUND_UP_4(3 * width), _destroy_pixbuf,
-                       new_buffer);
-
-               if (sgd->pixbuf != NULL) {
-                       g_object_unref(sgd->pixbuf);
-                       sgd->pixbuf = NULL;
-               }
-       } else {
-               pixbuf = sgd->pixbuf;
-       }
-
-       if (pixbuf != NULL) {
-               gboolean save_ok;
-               GError *error = NULL;
-               const gchar *filename;
-
-               filename = _get_tmp_file_from_pool(sgd->worker);
-
-               save_ok = gdk_pixbuf_save (pixbuf, filename, "jpeg", &error,
-                                          NULL);
-
-               g_object_unref (pixbuf);
-
-               if (save_ok) {
-                       /* Add the info to the current metadata. */
-                       _current_metadata_add(sgd->worker, sgd->metadata_key,
-                                             G_TYPE_STRING,
-                                             (gchar*)filename);
-
-                       /* Emit the metadata. */
-                       mafw_renderer_emit_metadata_string(sgd->worker->owner,
-                                                          sgd->metadata_key,
-                                                          (gchar *) filename);
-               } else {
-                       if (error != NULL) {
-                               g_warning ("%s\n", error->message);
-                               g_error_free (error);
-                       } else {
-                               g_critical("Unknown error when saving pixbuf "
-                                          "with GStreamer data");
-                       }
-               }
-       } else {
-               g_warning("Could not create pixbuf from GstBuffer");
-       }
-
-       g_free(sgd->metadata_key);
-       g_free(sgd);
-}
-
-static void _pixbuf_size_prepared_cb (GdkPixbufLoader *loader, 
-                                     gint width, gint height,
-                                     gpointer user_data)
-{
-       /* Be sure the image size is reasonable */
-       if (width > 512 || height > 512) {
-               g_debug ("pixbuf: image is too big: %dx%d", width, height);
-               gdouble ar;
-               ar = (gdouble) width / height;
-               if (width > height) {
-                       width = 512;
-                       height = width / ar;
-               } else {
-                       height = 512;
-                       width = height * ar;
-               }
-               g_debug ("pixbuf: scaled image to %dx%d", width, height);
-               gdk_pixbuf_loader_set_size (loader, width, height);
-       }
-}
-
-static void _emit_gst_buffer_as_graphic_file(MafwGstRendererWorker *worker,
-                                            GstBuffer *buffer,
-                                            const gchar *metadata_key)
-{
-       GdkPixbufLoader *loader;
-       GstStructure *structure;
-       const gchar *mime = NULL;
-       GError *error = NULL;
-
-       g_return_if_fail((buffer != NULL) && GST_IS_BUFFER(buffer));
-
-       structure = gst_caps_get_structure(GST_BUFFER_CAPS(buffer), 0);
-       mime = gst_structure_get_name(structure);
-
-       if (g_str_has_prefix(mime, "video/x-raw")) {
-               gint framerate_d, framerate_n;
-               GstCaps *to_caps;
-               SaveGraphicData *sgd;
-
-               gst_structure_get_fraction (structure, "framerate",
-                                           &framerate_n, &framerate_d);
-
-               to_caps = gst_caps_new_simple ("video/x-raw-rgb",
-                                              "bpp", G_TYPE_INT, 24,
-                                              "depth", G_TYPE_INT, 24,
-                                              "framerate", GST_TYPE_FRACTION,
-                                              framerate_n, framerate_d,
-                                              "pixel-aspect-ratio",
-                                              GST_TYPE_FRACTION, 1, 1,
-                                              "endianness",
-                                              G_TYPE_INT, G_BIG_ENDIAN,
-                                              "red_mask", G_TYPE_INT,
-                                              0xff0000,
-                                              "green_mask",
-                                              G_TYPE_INT, 0x00ff00,
-                                              "blue_mask",
-                                              G_TYPE_INT, 0x0000ff,
-                                              NULL);
-
-               sgd = g_new0(SaveGraphicData, 1);
-               sgd->worker = worker;
-               sgd->metadata_key = g_strdup(metadata_key);
-
-               g_debug("pixbuf: using bvw to convert image format");
-               bvw_frame_conv_convert (buffer, to_caps,
-                                       _emit_gst_buffer_as_graphic_file_cb,
-                                       sgd);
-       } else {
-               GdkPixbuf *pixbuf = NULL;
-               loader = gdk_pixbuf_loader_new_with_mime_type(mime, &error);
-               g_signal_connect (G_OBJECT (loader), "size-prepared", 
-                                (GCallback)_pixbuf_size_prepared_cb, NULL);
-
-               if (loader == NULL) {
-                       g_warning ("%s\n", error->message);
-                       g_error_free (error);
-               } else {
-                       if (!gdk_pixbuf_loader_write (loader,
-                                                     GST_BUFFER_DATA(buffer),
-                                                     GST_BUFFER_SIZE(buffer),
-                                                     &error)) {
-                               g_warning ("%s\n", error->message);
-                               g_error_free (error);
-
-                               gdk_pixbuf_loader_close (loader, NULL);
-                       } else {
-                               pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-
-                               if (!gdk_pixbuf_loader_close (loader, &error)) {
-                                       g_warning ("%s\n", error->message);
-                                       g_error_free (error);
-
-                                       g_object_unref(pixbuf);
-                               } else {
-                                       SaveGraphicData *sgd;
-
-                                       sgd = g_new0(SaveGraphicData, 1);
-
-                                       sgd->worker = worker;
-                                       sgd->metadata_key =
-                                               g_strdup(metadata_key);
-                                       sgd->pixbuf = pixbuf;
-
-                                       _emit_gst_buffer_as_graphic_file_cb(
-                                               NULL, sgd);
-                               }
-                       }
-                       g_object_unref(loader);
-               }
-       }
-}
-#endif
-
-static gboolean _go_to_gst_ready(gpointer user_data)
-{
-       MafwGstRendererWorker *worker = user_data;
-
-       g_return_val_if_fail(worker->state == GST_STATE_PAUSED ||
-                            worker->prerolling, FALSE);
-
-       worker->seek_position =
-               mafw_gst_renderer_worker_get_position(worker);
-
-       g_debug("going to GST_STATE_READY");
-       gst_element_set_state(worker->pipeline, GST_STATE_READY);
-       worker->in_ready = TRUE;
-        worker->ready_timeout = 0;
-
-       return FALSE;
-}
-
-static void _add_ready_timeout(MafwGstRendererWorker *worker)
-{
-       if (worker->media.seekable) {
-               if (!worker->ready_timeout)
-               {
-                       g_debug("Adding timeout to go to GST_STATE_READY");
-                       worker->ready_timeout =
-                               g_timeout_add_seconds(
-                                       MAFW_GST_RENDERER_WORKER_SECONDS_READY,
-                                       _go_to_gst_ready,
-                                       worker);
-               }
-       } else {
-               g_debug("Not adding timeout to go to GST_STATE_READY as media "
-                       "is not seekable");
-               worker->ready_timeout = 0;
-       }
-}
-
-static void _remove_ready_timeout(MafwGstRendererWorker *worker)
-{
-       if (worker->ready_timeout != 0) {
-               g_debug("removing timeout for READY");
-               g_source_remove(worker->ready_timeout);
-               worker->ready_timeout = 0;
-       }
-       worker->in_ready = FALSE;
-}
-
-static gboolean _emit_video_info(MafwGstRendererWorker *worker)
-{
-       mafw_renderer_emit_metadata_int(worker->owner,
-                                   MAFW_METADATA_KEY_RES_X,
-                                   worker->media.video_width);
-       mafw_renderer_emit_metadata_int(worker->owner,
-                                   MAFW_METADATA_KEY_RES_Y,
-                                   worker->media.video_height);
-       mafw_renderer_emit_metadata_double(worker->owner,
-                                      MAFW_METADATA_KEY_VIDEO_FRAMERATE,
-                                      worker->media.fps);
-       return FALSE;
-}
-
-/*
- * Checks if the video details are supported.  It also extracts other useful
- * information (such as PAR and framerate) from the caps, if available.  NOTE:
- * this will be called from a different thread than glib's mainloop (when
- * invoked via _stream_info_cb);  don't call MafwGstRenderer directly.
- *
- * Returns: TRUE if video details are acceptable.
- */
-static gboolean _handle_video_info(MafwGstRendererWorker *worker,
-                                  const GstStructure *structure)
-{
-       gint width, height;
-       gdouble fps;
-
-       width = height = 0;
-       gst_structure_get_int(structure, "width", &width);
-       gst_structure_get_int(structure, "height", &height);
-       g_debug("video size: %d x %d", width, height);
-       if (gst_structure_has_field(structure, "pixel-aspect-ratio"))
-       {
-               gst_structure_get_fraction(structure, "pixel-aspect-ratio",
-                                          &worker->media.par_n,
-                                          &worker->media.par_d);
-               g_debug("video PAR: %d:%d", worker->media.par_n,
-                       worker->media.par_d);
-               width = width * worker->media.par_n / worker->media.par_d;
-       }
-
-       fps = 1.0;
-       if (gst_structure_has_field(structure, "framerate"))
-       {
-               gint fps_n, fps_d;
-
-               gst_structure_get_fraction(structure, "framerate",
-                                          &fps_n, &fps_d);
-               if (fps_d > 0)
-                       fps = (gdouble)fps_n / (gdouble)fps_d;
-               g_debug("video fps: %f", fps);
-       }
-
-       worker->media.video_width = width;
-       worker->media.video_height = height;
-       worker->media.fps = fps;
-
-       /* Add the info to the current metadata. */
-       gint p_width, p_height, p_fps;
-
-       p_width = width;
-       p_height = height;
-       p_fps = fps;
-
-       _current_metadata_add(worker, MAFW_METADATA_KEY_RES_X, G_TYPE_INT,
-                             p_width);
-       _current_metadata_add(worker, MAFW_METADATA_KEY_RES_Y, G_TYPE_INT,
-                             p_height);
-       _current_metadata_add(worker, MAFW_METADATA_KEY_VIDEO_FRAMERATE,
-                             G_TYPE_DOUBLE,
-                             p_fps);
-
-       /* Emit the metadata.*/
-       g_idle_add((GSourceFunc)_emit_video_info, worker);
-
-       return TRUE;
-}
-
-static void _parse_stream_info_item(MafwGstRendererWorker *worker, GObject *obj)
-{
-       GParamSpec *pspec;
-       GEnumValue *val;
-       gint type;
-
-       g_object_get(obj, "type", &type, NULL);
-       pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), "type");
-       val = g_enum_get_value(G_PARAM_SPEC_ENUM(pspec)->enum_class, type);
-       if (!val)
-               return;
-       if (!g_ascii_strcasecmp(val->value_nick, "video") ||
-           !g_ascii_strcasecmp(val->value_name, "video"))
-       {
-               GstCaps *vcaps;
-               GstObject *object;
-
-               object = NULL;
-               g_object_get(obj, "object", &object, NULL);
-               vcaps = NULL;
-               if (object) {
-                       vcaps = gst_pad_get_caps(GST_PAD_CAST(object));
-               } else {
-                       g_object_get(obj, "caps", &vcaps, NULL);
-                       gst_caps_ref(vcaps);
-               }
-               if (vcaps) {
-                       if (gst_caps_is_fixed(vcaps))
-                       {
-                               _handle_video_info(
-                                       worker,
-                                       gst_caps_get_structure(vcaps, 0));
-                       }
-                       gst_caps_unref(vcaps);
-               }
-       }
-}
-
-/* It always returns FALSE, because it is used as an idle callback as well. */
-static gboolean _parse_stream_info(MafwGstRendererWorker *worker)
-{
-       GList *stream_info, *s;
-
-       stream_info = NULL;
-       if (g_object_class_find_property(G_OBJECT_GET_CLASS(worker->pipeline),
-                                        "stream-info"))
-       {
-               g_object_get(worker->pipeline,
-                            "stream-info", &stream_info, NULL);
-       }
-       for (s = stream_info; s; s = g_list_next(s))
-               _parse_stream_info_item(worker, G_OBJECT(s->data));
-       return FALSE;
-}
-
-static void mafw_gst_renderer_worker_apply_xid(MafwGstRendererWorker *worker)
-{
-       /* Set sink to render on the provided XID if we have do have
-          a XID a valid video sink and we are rendeing video content */
-       if (worker->xid && 
-           worker->vsink && 
-           worker->media.has_visual_content)
-       {
-               g_debug ("Setting overlay, window id: %x", 
-                        (gint) worker->xid);
-               gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(worker->vsink), 
-                                            worker->xid);
-               /* Ask the gst to redraw the frame if we are paused */
-               /* TODO: in MTG this works only in non-fs -> fs way. */
-               if (worker->state == GST_STATE_PAUSED)
-               {
-                       gst_x_overlay_expose(GST_X_OVERLAY(worker->vsink));
-               }
-       } else {
-               g_debug("Not setting overlay for window id: %x", 
-                       (gint) worker->xid);
-       }
-}
-
-/*
- * GstBus synchronous message handler.  NOTE that this handler is NOT invoked
- * from the glib thread, so be careful what you do here.
- */
-static GstBusSyncReply _sync_bus_handler(GstBus *bus, GstMessage *msg,
-                                        MafwGstRendererWorker *worker)
-{
-       if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ELEMENT &&
-           gst_structure_has_name(msg->structure, "prepare-xwindow-id"))
-       {
-               g_debug("got prepare-xwindow-id");
-               worker->media.has_visual_content = TRUE;
-               /* The user has to preset the XID, we don't create windows by
-                * ourselves. */
-               if (!worker->xid) {
-                       /* We must post an error message to the bus that will
-                        * be picked up by _async_bus_handler.  Calling the
-                        * notification function directly from here (different
-                        * thread) is not healthy. */
-                       g_warning("No video window set!");
-                       _post_error(worker,
-                                   g_error_new_literal(
-                                           MAFW_RENDERER_ERROR,
-                                           MAFW_RENDERER_ERROR_PLAYBACK,
-                                           "No video window XID set"));
-                       gst_message_unref (msg);
-                       return GST_BUS_DROP;
-               } else {
-                       g_debug ("Video window to use is: %x", 
-                                (gint) worker->xid);
-               }
-
-               /* Instruct vsink to use the client-provided window */
-               mafw_gst_renderer_worker_apply_xid(worker);
-
-               /* Handle colorkey and autopaint */
-               mafw_gst_renderer_worker_set_autopaint(
-                       worker,
-                       worker->autopaint);
-               if (worker->colorkey == -1)
-                       g_object_get(worker->vsink,
-                               "colorkey", &worker->colorkey, NULL);
-               else
-                       mafw_gst_renderer_worker_set_colorkey(
-                       worker,
-                       worker->colorkey);
-               /* Defer the signal emission to the thread running the
-                * mainloop. */
-               if (worker->colorkey != -1) {
-                       gst_bus_post(worker->bus,
-                                    gst_message_new_application(
-                                            GST_OBJECT(worker->vsink),
-                                            gst_structure_empty_new("ckey")));
-               }
-               gst_message_unref (msg);
-               return GST_BUS_DROP;
-       }
-       /* do not unref message when returning PASS */
-       return GST_BUS_PASS;
-}
-
-static void _free_taglist_item(GstMessage *msg, gpointer data)
-{
-       gst_message_unref(msg);
-}
-
-static void _free_taglist(MafwGstRendererWorker *worker)
-{
-       if (worker->tag_list != NULL)
-       {
-               g_ptr_array_foreach(worker->tag_list, (GFunc)_free_taglist_item,
-                                   NULL);
-               g_ptr_array_free(worker->tag_list, TRUE);
-               worker->tag_list = NULL;
-       }
-}
-
-static gboolean _seconds_duration_equal(gint64 duration1, gint64 duration2)
-{
-       gint64 duration1_seconds, duration2_seconds;
-
-       duration1_seconds = NSECONDS_TO_SECONDS(duration1);
-       duration2_seconds = NSECONDS_TO_SECONDS(duration2);
-
-       return duration1_seconds == duration2_seconds;
-}
-
-static void _check_duration(MafwGstRendererWorker *worker, gint64 value)
-{
-       MafwGstRenderer *renderer = worker->owner;
-       gboolean right_query = TRUE;
-
-       if (value == -1) {
-               GstFormat format = GST_FORMAT_TIME;
-               right_query =
-                       gst_element_query_duration(worker->pipeline, &format,
-                                                  &value);
-       }
-
-       if (right_query && value > 0) {
-               gint duration_seconds = NSECONDS_TO_SECONDS(value);
-
-               if (!_seconds_duration_equal(worker->media.length_nanos,
-                                            value)) {                  
-                       /* Add the duration to the current metadata. */
-                       _current_metadata_add(worker, MAFW_METADATA_KEY_DURATION,
-                                               G_TYPE_INT64,
-                                               (gint64)duration_seconds);
-                       /* Emit the duration. */
-                       mafw_renderer_emit_metadata_int64(
-                               worker->owner, MAFW_METADATA_KEY_DURATION,
-                               (gint64)duration_seconds);
-               }
-
-               /* We compare this duration we just got with the
-                * source one and update it in the source if needed */
-               if (duration_seconds > 0 &&
-                       duration_seconds != renderer->media->duration) {
-                       mafw_gst_renderer_update_source_duration(
-                               renderer,
-                               duration_seconds);
-               }
-       }
-
-       worker->media.length_nanos = value;
-       g_debug("media duration: %lld", worker->media.length_nanos);
-}
-
-static void _check_seekability(MafwGstRendererWorker *worker)
-{
-       MafwGstRenderer *renderer = worker->owner;
-       SeekabilityType seekable = SEEKABILITY_NO_SEEKABLE;
-
-       if (worker->media.length_nanos != -1)
-       {
-               g_debug("source seekability %d", renderer->media->seekability);
-
-               if (renderer->media->seekability != SEEKABILITY_NO_SEEKABLE) {
-                       g_debug("Quering GStreamer for seekability");
-                       GstQuery *seek_query;
-                       GstFormat format = GST_FORMAT_TIME;
-                       /* Query the seekability of the stream */
-                       seek_query = gst_query_new_seeking(format);
-                       if (gst_element_query(worker->pipeline, seek_query)) {
-                               gboolean renderer_seekable = FALSE;
-                               gst_query_parse_seeking(seek_query, NULL,
-                                                       &renderer_seekable,
-                                                       NULL, NULL);
-                               g_debug("GStreamer seekability %d",
-                                       renderer_seekable);
-                               seekable = renderer_seekable ?
-                                       SEEKABILITY_SEEKABLE :
-                                       SEEKABILITY_NO_SEEKABLE;
-                       }
-                       gst_query_unref(seek_query);
-               }
-       }
-
-       if (worker->media.seekable != seekable) {
-               gboolean is_seekable = (seekable == SEEKABILITY_SEEKABLE);
-
-               /* Add the seekability to the current metadata. */
-               _current_metadata_add(worker, MAFW_METADATA_KEY_IS_SEEKABLE,
-                       G_TYPE_BOOLEAN, is_seekable);
-
-               /* Emit. */
-               mafw_renderer_emit_metadata_boolean(
-                       worker->owner, MAFW_METADATA_KEY_IS_SEEKABLE,
-                       is_seekable);
-       }
-
-       g_debug("media seekable: %d", seekable);
-       worker->media.seekable = seekable;
-}
-
-static gboolean _query_duration_and_seekability_timeout(gpointer data)
-{
-       MafwGstRendererWorker *worker = data;
-
-       _check_duration(worker, -1);
-       _check_seekability(worker);
-
-       worker->duration_seek_timeout = 0;
-
-       return FALSE;
-}
-
-/*
- * Called when the pipeline transitions into PAUSED state.  It extracts more
- * information from Gst.
- */
-static void _finalize_startup(MafwGstRendererWorker *worker)
-{
-       /* Check video caps */
-       if (worker->media.has_visual_content) {
-               GstPad *pad = GST_BASE_SINK_PAD(worker->vsink);
-               GstCaps *caps = GST_PAD_CAPS(pad);
-               if (caps && gst_caps_is_fixed(caps)) {
-                       GstStructure *structure;
-                       structure = gst_caps_get_structure(caps, 0);
-                       if (!_handle_video_info(worker, structure))
-                               return;
-               }
-       }
-
-       /* Something might have gone wrong at this point already. */
-       if (worker->is_error) {
-               g_debug("Error occured during preroll");
-               return;
-       }
-
-       /* Streaminfo might reveal the media to be unsupported.  Therefore we
-        * need to check the error again. */
-       _parse_stream_info(worker);
-       if (worker->is_error) {
-               g_debug("Error occured. Leaving");
-               return;
-       }
-
-       /* Check duration and seekability */
-       if (worker->duration_seek_timeout != 0) {
-               g_source_remove(worker->duration_seek_timeout);
-               worker->duration_seek_timeout = 0;
-       }
-       _check_duration(worker, -1);
-       _check_seekability(worker);
-}
-
-static void _add_duration_seek_query_timeout(MafwGstRendererWorker *worker)
-{
-       if (worker->duration_seek_timeout != 0) {
-               g_source_remove(worker->duration_seek_timeout);
-       }
-       worker->duration_seek_timeout = g_timeout_add_seconds(
-               MAFW_GST_RENDERER_WORKER_SECONDS_DURATION_AND_SEEKABILITY,
-               _query_duration_and_seekability_timeout,
-               worker);
-}
-
-static void _do_pause_postprocessing(MafwGstRendererWorker *worker)
-{
-       if (worker->notify_pause_handler) {
-               worker->notify_pause_handler(worker, worker->owner);
-       }
-
-#ifdef HAVE_GDKPIXBUF
-       if (worker->media.has_visual_content &&
-           worker->current_frame_on_pause) {
-               GstBuffer *buffer = NULL;
-
-               g_object_get(worker->pipeline, "frame", &buffer, NULL);
-
-               if (buffer != NULL) {
-                       _emit_gst_buffer_as_graphic_file(
-                               worker, buffer,
-                               MAFW_METADATA_KEY_PAUSED_THUMBNAIL_URI);
-               }
-       }
-#endif
-
-       _add_ready_timeout(worker);
-}
-
-static void _report_playing_state(MafwGstRendererWorker * worker)
-{
-       if (worker->report_statechanges) {
-               switch (worker->mode) {
-               case WORKER_MODE_SINGLE_PLAY:
-                       /* Notify play if we are playing in
-                        * single mode */
-                       if (worker->notify_play_handler)
-                               worker->notify_play_handler(
-                                       worker,
-                                       worker->owner);
-                       break;
-               case WORKER_MODE_PLAYLIST:
-               case WORKER_MODE_REDUNDANT:
-                       /* Only notify play when the "playlist"
-                          playback starts, don't notify play for each
-                          individual element of the playlist. */
-                       if (worker->pl.notify_play_pending) {
-                               if (worker->notify_play_handler)
-                                       worker->notify_play_handler(
-                                               worker,
-                                               worker->owner);
-                               worker->pl.notify_play_pending = FALSE;
-                       }
-                       break;
-               default: break;
-               }
-       }
-}
-
-static void _handle_state_changed(GstMessage *msg, MafwGstRendererWorker *worker)
-{
-       GstState newstate, oldstate;
-       GstStateChange statetrans;
-       MafwGstRenderer *renderer = (MafwGstRenderer*)worker->owner;
-
-       gst_message_parse_state_changed(msg, &oldstate, &newstate, NULL);
-       statetrans = GST_STATE_TRANSITION(oldstate, newstate);
-       g_debug ("State changed: %d: %d -> %d", worker->state, oldstate, newstate);
-
-       /* If the state is the same we do nothing, otherwise, we keep
-        * it */
-       if (worker->state == newstate) {
-               return;
-       } else {
-               worker->state = newstate;
-       }
-
-        if (statetrans == GST_STATE_CHANGE_READY_TO_PAUSED &&
-            worker->in_ready) {
-                /* Woken up from READY, resume stream position and playback */
-                g_debug("State changed to pause after ready");
-                if (worker->seek_position > 0) {
-                        _check_seekability(worker);
-                        if (worker->media.seekable) {
-                                g_debug("performing a seek");
-                                _do_seek(worker, GST_SEEK_TYPE_SET,
-                                         worker->seek_position, NULL);
-                        } else {
-                                g_critical("media is not seekable (and should)");
-                        }
-                }
-
-                /* If playing a stream wait for buffering to finish before
-                   starting to play */
-                if (!worker->is_stream || worker->is_live) {
-                        _do_play(worker);
-                }
-                return;
-        }
-
-       /* While buffering, we have to wait in PAUSED 
-          until we reach 100% before doing anything */
-       if (worker->buffering) {
-               if (statetrans == GST_STATE_CHANGE_PAUSED_TO_PLAYING) {
-                       /* Mmm... probably the client issued a seek on the
-                        * stream and then a play/resume command right away,
-                        * so the stream got into PLAYING state while
-                        * buffering. When the next buffering signal arrives,
-                        * the stream will be PAUSED silently and resumed when
-                        * buffering is done (silently too), so let's signal
-                        * the state change to PLAYING here. */
-                       _report_playing_state(worker);                  
-               }
-               return;
-       }
-
-       switch (statetrans) {
-       case GST_STATE_CHANGE_READY_TO_PAUSED:
-               if (worker->prerolling && worker->report_statechanges) {
-                       /* PAUSED after pipeline has been
-                        * constructed. We check caps, seek and
-                        * duration and if staying in pause is needed,
-                        * we perform operations for pausing, such as
-                        * current frame on pause and signalling state
-                        * change and adding the timeout to go to ready */
-                       g_debug ("Prerolling done, finalizaing startup");
-                       _finalize_startup(worker);
-                       _do_play(worker);
-                       renderer->play_failed_count = 0;
-
-                       if (worker->stay_paused) {
-                               _do_pause_postprocessing(worker);
-                       }
-                       worker->prerolling = FALSE;
-               }
-               break;
-       case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
-               /* When pausing we do the stuff, like signalling
-                * state, current frame on pause and timeout to go to
-                * ready */
-               if (worker->report_statechanges) {
-                       _do_pause_postprocessing(worker);
-               }
-               break;
-       case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
-               /* if seek was called, at this point it is really ended */
-               worker->seek_position = -1;
-                worker->eos = FALSE;
-
-               /* Signal state change if needed */
-               _report_playing_state(worker);
-
-               /* Prevent blanking if we are playing video */
-                if (worker->media.has_visual_content) {
-                        blanking_prohibit();
-                }
-               keypadlocking_prohibit();
-               /* Remove the ready timeout if we are playing [again] */
-               _remove_ready_timeout(worker);
-                /* If mode is redundant we are trying to play one of several
-                 * candidates, so when we get a successful playback, we notify
-                 * the real URI that we are playing */
-                if (worker->mode == WORKER_MODE_REDUNDANT) {
-                        mafw_renderer_emit_metadata_string(
-                                worker->owner,
-                                MAFW_METADATA_KEY_URI,
-                                worker->media.location);
-                }
-
-               /* Emit metadata. We wait until we reach the playing
-                  state because this speeds up playback start time */
-               _emit_metadatas(worker);
-               /* Query duration and seekability. Useful for vbr
-                * clips or streams. */
-               _add_duration_seek_query_timeout(worker);
-               break;
-       case GST_STATE_CHANGE_PAUSED_TO_READY:
-               /* If we went to READY, we free the taglist and
-                * deassign the timout it */
-               if (worker->in_ready) {
-                       g_debug("changed to GST_STATE_READY");
-                       _free_taglist(worker);
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static void _handle_duration(MafwGstRendererWorker *worker, GstMessage *msg)
-{
-       GstFormat fmt;
-       gint64 duration;
-
-       gst_message_parse_duration(msg, &fmt, &duration);
-
-       if (worker->duration_seek_timeout != 0) {
-               g_source_remove(worker->duration_seek_timeout);
-               worker->duration_seek_timeout = 0;
-       }
-
-       _check_duration(worker,
-                       duration != GST_CLOCK_TIME_NONE ? duration : -1);
-       _check_seekability(worker);
-}
-
-#ifdef HAVE_GDKPIXBUF
-static void _emit_renderer_art(MafwGstRendererWorker *worker,
-                              const GstTagList *list)
-{
-       GstBuffer *buffer = NULL;
-       const GValue *value = NULL;
-
-       g_return_if_fail(gst_tag_list_get_tag_size(list, GST_TAG_IMAGE) > 0);
-
-       value = gst_tag_list_get_value_index(list, GST_TAG_IMAGE, 0);
-
-       g_return_if_fail((value != NULL) && G_VALUE_HOLDS(value, GST_TYPE_BUFFER));
-
-       buffer = g_value_peek_pointer(value);
-
-       g_return_if_fail((buffer != NULL) && GST_IS_BUFFER(buffer));
-
-       _emit_gst_buffer_as_graphic_file(worker, buffer,
-                                        MAFW_METADATA_KEY_RENDERER_ART_URI);
-}
-#endif
-
-static GHashTable* _build_tagmap(void)
-{
-       GHashTable *hash_table = NULL;
-
-       hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-                                          g_free);
-
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_TITLE),
-                           g_strdup(MAFW_METADATA_KEY_TITLE));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_ARTIST),
-                           g_strdup(MAFW_METADATA_KEY_ARTIST));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_AUDIO_CODEC),
-                           g_strdup(MAFW_METADATA_KEY_AUDIO_CODEC));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_VIDEO_CODEC),
-                           g_strdup(MAFW_METADATA_KEY_VIDEO_CODEC));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_BITRATE),
-                           g_strdup(MAFW_METADATA_KEY_BITRATE));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_LANGUAGE_CODE),
-                           g_strdup(MAFW_METADATA_KEY_ENCODING));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_ALBUM),
-                           g_strdup(MAFW_METADATA_KEY_ALBUM));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_GENRE),
-                           g_strdup(MAFW_METADATA_KEY_GENRE));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_TRACK_NUMBER),
-                           g_strdup(MAFW_METADATA_KEY_TRACK));
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_ORGANIZATION),
-                           g_strdup(MAFW_METADATA_KEY_ORGANIZATION));
-#ifdef HAVE_GDKPIXBUF
-       g_hash_table_insert(hash_table, g_strdup(GST_TAG_IMAGE),
-                           g_strdup(MAFW_METADATA_KEY_RENDERER_ART_URI));
-#endif
-
-       return hash_table;
-}
-
-/*
- * Emits metadata-changed signals for gst tags.
- */
-static void _emit_tag(const GstTagList *list, const gchar *tag,
-                     MafwGstRendererWorker *worker)
-{
-       /* Mapping between Gst <-> MAFW metadata tags
-        * NOTE: This assumes that GTypes matches between GST and MAFW. */
-       static GHashTable *tagmap = NULL;
-       gint i, count;
-       const gchar *mafwtag;
-       GType type;
-       GValueArray *values;
-
-       if (tagmap == NULL) {
-               tagmap = _build_tagmap();
-       }
-
-       g_debug("tag: '%s' (type: %s)", tag,
-               g_type_name(gst_tag_get_type(tag)));
-       /* Is there a mapping for this tag? */
-       mafwtag = g_hash_table_lookup(tagmap, tag);
-       if (!mafwtag)
-               return;
-
-#ifdef HAVE_GDKPIXBUF
-       if (strcmp (mafwtag, MAFW_METADATA_KEY_RENDERER_ART_URI) == 0) {
-               _emit_renderer_art(worker, list);
-               return;
-       }
-#endif
-
-       /* Build a value array of this tag.  We need to make sure that strings
-        * are UTF-8.  GstTagList API says that the value is always UTF8, but it
-        * looks like the ID3 demuxer still might sometimes produce non-UTF-8
-        * strings. */
-       count = gst_tag_list_get_tag_size(list, tag);
-       type = gst_tag_get_type(tag);
-       values = g_value_array_new(count);
-       for (i = 0; i < count; ++i) {
-               GValue *v = (GValue *)
-                       gst_tag_list_get_value_index(list, tag, i);
-               if (type == G_TYPE_STRING) {
-                       gchar *orig, *utf8;
-
-                       gst_tag_list_get_string_index(list, tag, i, &orig);
-                       if (convert_utf8(orig, &utf8)) {
-                               GValue utf8gval = {0};
-
-                               g_value_init(&utf8gval, G_TYPE_STRING);
-                               g_value_take_string(&utf8gval, utf8);
-                               _current_metadata_add(worker, mafwtag, G_TYPE_STRING,
-                                                       utf8);
-                               g_value_array_append(values, &utf8gval);
-                               g_value_unset(&utf8gval);
-                       }
-                       g_free(orig);
-               } else if (type == G_TYPE_UINT) {
-                       GValue intgval = {0};
-                       gint intval;
-
-                       g_value_init(&intgval, G_TYPE_INT);
-                       g_value_transform(v, &intgval);
-                       intval = g_value_get_int(&intgval);
-                       _current_metadata_add(worker, mafwtag, G_TYPE_INT,
-                                               intval);
-                       g_value_array_append(values, &intgval);
-                       g_value_unset(&intgval);
-               } else {
-                       _current_metadata_add(worker, mafwtag, G_TYPE_VALUE,
-                                               v);
-                       g_value_array_append(values, v);
-               }
-       }
-
-       /* Emit the metadata. */
-       g_signal_emit_by_name(worker->owner, "metadata-changed", mafwtag,
-                             values);
-
-       g_value_array_free(values);
-}
-
-/**
- * Collect tag-messages, parse it later, when playing is ongoing
- */
-static void _handle_tag(MafwGstRendererWorker *worker, GstMessage *msg)
-{
-       /* Do not emit metadata until we get to PLAYING state to speed up
-          playback start */
-       if (worker->tag_list == NULL)
-               worker->tag_list = g_ptr_array_new();
-       g_ptr_array_add(worker->tag_list, gst_message_ref(msg));
-
-       /* Some tags come in playing state, so in this case we have
-          to emit them right away (example: radio stations) */
-       if (worker->state == GST_STATE_PLAYING) {
-               _emit_metadatas(worker);
-       }
-}
-
-/**
- * Parses the list of tag-messages
- */
-static void _parse_tagmsg(GstMessage *msg, MafwGstRendererWorker *worker)
-{
-       GstTagList *new_tags;
-
-       gst_message_parse_tag(msg, &new_tags);
-       gst_tag_list_foreach(new_tags, (gpointer)_emit_tag, worker);
-       gst_tag_list_free(new_tags);
-       gst_message_unref(msg);
-}
-
-/**
- * Parses the collected tag messages, and emits the metadatas
- */
-static void _emit_metadatas(MafwGstRendererWorker *worker)
-{
-       if (worker->tag_list != NULL)
-       {
-               g_ptr_array_foreach(worker->tag_list, (GFunc)_parse_tagmsg,
-                                   worker);
-               g_ptr_array_free(worker->tag_list, TRUE);
-               worker->tag_list = NULL;
-       }
-}
-
-static void _reset_volume_and_mute_to_pipeline(MafwGstRendererWorker *worker)
-{
-#ifdef MAFW_GST_RENDERER_DISABLE_PULSE_VOLUME
-       g_debug("resetting volume and mute to pipeline");
-
-       if (worker->pipeline != NULL) {
-               g_object_set(
-                       G_OBJECT(worker->pipeline), "volume",
-                       mafw_gst_renderer_worker_volume_get(worker->wvolume),
-                       "mute",
-                       mafw_gst_renderer_worker_volume_is_muted(worker->wvolume),
-                       NULL);
-       }
-#endif
-}
-
-static void _handle_buffering(MafwGstRendererWorker *worker, GstMessage *msg)
-{
-       gint percent;
-       MafwGstRenderer *renderer = (MafwGstRenderer*)worker->owner;
-
-       gst_message_parse_buffering(msg, &percent);
-       g_debug("buffering: %d", percent);
-
-        /* No state management needed for live pipelines */
-        if (!worker->is_live) {
-               worker->buffering = TRUE;
-               if (percent < 100 && worker->state == GST_STATE_PLAYING) {
-                       g_debug("setting pipeline to PAUSED not to wolf the "
-                               "buffer down");
-                       worker->report_statechanges = FALSE;
-                       /* We can't call _pause() here, since it sets
-                        * the "report_statechanges" to TRUE.  We don't
-                        * want that, application doesn't need to know
-                        * that internally the state changed to
-                        * PAUSED. */
-                       if (gst_element_set_state(worker->pipeline,
-                                             GST_STATE_PAUSED) ==
-                                       GST_STATE_CHANGE_ASYNC)
-                       {
-                               /* XXX this blocks at most 2 seconds. */
-                               gst_element_get_state(worker->pipeline, NULL,
-                                             NULL,
-                                             2 * GST_SECOND);
-                       }
-               }
-
-                if (percent >= 100) {
-                        /* On buffering we go to PAUSED, so here we move back to
-                           PLAYING */
-                        worker->buffering = FALSE;
-                        if (worker->state == GST_STATE_PAUSED) {
-                                /* If buffering more than once, do this only the
-                                   first time we are done with buffering */
-                                if (worker->prerolling) {
-                                       g_debug("buffering concluded during "
-                                               "prerolling");
-                                       _finalize_startup(worker);
-                                       _do_play(worker);
-                                       renderer->play_failed_count = 0;
-                                       /* Send the paused notification */
-                                       if (worker->stay_paused &&
-                                           worker->notify_pause_handler) {
-                                               worker->notify_pause_handler(
-                                                       worker,
-                                                       worker->owner);
-                                       }
-                                       worker->prerolling = FALSE;
-                                } else if (worker->in_ready) {
-                                       /* If we had been woken up from READY
-                                          and we have finish our buffering,
-                                          check if we have to play or stay
-                                          paused and if we have to play,
-                                          signal the state change. */
-                                        g_debug("buffering concluded, "
-                                                "continuing playing");
-                                        _do_play(worker);
-                                } else if (!worker->stay_paused) {
-                                       /* This means, that we were playing but
-                                          ran out of buffer, so we silently
-                                          paused waited for buffering to
-                                          finish and now we continue silently
-                                          (silently meaning we do not expose
-                                          state changes) */
-                                       g_debug("buffering concluded, setting "
-                                               "pipeline to PLAYING again");
-                                       _reset_volume_and_mute_to_pipeline(
-                                               worker);
-                                       if (gst_element_set_state(
-                                               worker->pipeline,
-                                               GST_STATE_PLAYING) ==
-                                                       GST_STATE_CHANGE_ASYNC)
-                                       {
-                                               /* XXX this blocks at most 2 seconds. */
-                                               gst_element_get_state(
-                                                       worker->pipeline, NULL, NULL,
-                                                       2 * GST_SECOND);
-                                       }
-                               }
-                        } else if (worker->state == GST_STATE_PLAYING) {
-                               g_debug("buffering concluded, signalling "
-                                       "state change");
-                               /* In this case we got a PLAY command while 
-                                  buffering, likely because it was issued
-                                  before we got the first buffering signal.
-                                  The UI should not do this, but if it does,
-                                  we have to signal that we have executed
-                                  the state change, since in 
-                                  _handle_state_changed we do not do anything 
-                                  if we are buffering  */
-
-                               /* Set the pipeline to playing. This is an async
-                                  handler, it could be, that the reported state
-                                  is not the real-current state */
-                               if (gst_element_set_state(
-                                               worker->pipeline,
-                                               GST_STATE_PLAYING) ==
-                                                       GST_STATE_CHANGE_ASYNC)
-                               {
-                                       /* XXX this blocks at most 2 seconds. */
-                                       gst_element_get_state(
-                                               worker->pipeline, NULL, NULL,
-                                               2 * GST_SECOND);
-                               }
-                               if (worker->report_statechanges &&
-                                   worker->notify_play_handler) {
-                                       worker->notify_play_handler(
-                                                               worker,
-                                                       worker->owner);
-                               }
-                                _add_duration_seek_query_timeout(worker);
-                        }
-                }
-        }
-
-       /* Send buffer percentage */
-        if (worker->notify_buffer_status_handler)
-                worker->notify_buffer_status_handler(worker, worker->owner,
-                                                    percent);
-}
-
-static void _handle_element_msg(MafwGstRendererWorker *worker, GstMessage *msg)
-{
-       /* Only HelixBin sends "resolution" messages. */
-       if (gst_structure_has_name(msg->structure, "resolution") &&
-           _handle_video_info(worker, msg->structure))
-       {
-               worker->media.has_visual_content = TRUE;
-       }
-}
-
-static void _reset_pl_info(MafwGstRendererWorker *worker)
-{
-       if (worker->pl.items) {
-               g_slist_foreach(worker->pl.items, (GFunc) g_free, NULL);
-               g_slist_free(worker->pl.items);
-               worker->pl.items = NULL;
-       }
-
-       worker->pl.current = 0;
-       worker->pl.notify_play_pending = TRUE;
-}
-
-static GError * _get_specific_missing_plugin_error(GstMessage *msg)
-{
-       const GstStructure *gst_struct;
-       const gchar *type;
-
-       GError *error;
-       gchar *desc;
-
-       desc = gst_missing_plugin_message_get_description(msg);
-
-       gst_struct = gst_message_get_structure(msg);
-       type = gst_structure_get_string(gst_struct, "type");
-
-       if ((type) && ((strcmp(type, MAFW_GST_MISSING_TYPE_DECODER) == 0) ||
-                      (strcmp(type, MAFW_GST_MISSING_TYPE_ENCODER) == 0))) {
-
-               /* Missing codec error. */
-               const GValue *val;
-               const GstCaps *caps;
-               GstStructure *caps_struct;
-               const gchar *mime;
-
-               val = gst_structure_get_value(gst_struct, "detail");
-               caps = gst_value_get_caps(val);
-               caps_struct = gst_caps_get_structure(caps, 0);
-               mime = gst_structure_get_name(caps_struct);
-
-               if (g_strrstr(mime, "video")) {
-                       error = g_error_new_literal(
-                               MAFW_RENDERER_ERROR,
-                               MAFW_RENDERER_ERROR_VIDEO_CODEC_NOT_FOUND,
-                               desc);
-               } else if (g_strrstr(mime, "audio")) {
-                       error = g_error_new_literal(
-                               MAFW_RENDERER_ERROR,
-                               MAFW_RENDERER_ERROR_AUDIO_CODEC_NOT_FOUND,
-                               desc);
-               } else {
-                       error = g_error_new_literal(
-                               MAFW_RENDERER_ERROR,
-                               MAFW_RENDERER_ERROR_CODEC_NOT_FOUND,
-                               desc);
-               }
-       } else {
-               /* Unsupported type error. */
-               error = g_error_new(
-                       MAFW_RENDERER_ERROR,
-                       MAFW_RENDERER_ERROR_UNSUPPORTED_TYPE,
-                       "missing plugin: %s", desc);
-       }
-
-       g_free(desc);
-
-       return error;
-}
-
-/*
- * Asynchronous message handler.  It gets removed from if it returns FALSE.
- */
-static gboolean _async_bus_handler(GstBus *bus, GstMessage *msg,
-                                  MafwGstRendererWorker *worker)
-{
-       /* No need to handle message if error has already occured. */
-       if (worker->is_error)
-               return TRUE;
-
-       /* Handle missing-plugin (element) messages separately, relaying more
-        * details. */
-       if (gst_is_missing_plugin_message(msg)) {
-               GError *err = _get_specific_missing_plugin_error(msg);
-               /* FIXME?: for some reason, calling the error handler directly
-                * (_send_error) causes problems.  On the other hand, turning
-                * the error into a new GstMessage and letting the next
-                * iteration handle it seems to work. */
-               _post_error(worker, err);
-               return TRUE;
-       }
-
-       switch (GST_MESSAGE_TYPE(msg)) {
-       case GST_MESSAGE_ERROR:
-               if (!worker->is_error) {
-                       gchar *debug;
-                       GError *err;
-
-                       debug = NULL;
-                       gst_message_parse_error(msg, &err, &debug);
-                       g_debug("gst error: domain = %d, code = %d, "
-                               "message = '%s', debug = '%s'",
-                               err->domain, err->code, err->message, debug);
-                       if (debug)
-                               g_free(debug);
-
-                       /* If we are in playlist/radio mode, we silently
-                          ignore the error and continue with the next
-                          item until we end the playlist. If no
-                          playable elements we raise the error and
-                          after finishing we go to normal mode */
-
-                       if (worker->mode == WORKER_MODE_PLAYLIST ||
-                            worker->mode == WORKER_MODE_REDUNDANT) {
-                               if (worker->pl.current <
-                                   (g_slist_length(worker->pl.items) - 1)) {
-                                       /* If the error is "no space left"
-                                          notify, otherwise try to play the
-                                          next item */
-                                       if (err->code ==
-                                           GST_RESOURCE_ERROR_NO_SPACE_LEFT) {
-                                               _send_error(worker, err);
-
-                                       } else {
-                                               _play_pl_next(worker);
-                                       }
-                               } else {
-                                        /* Playlist EOS. We cannot try another
-                                         * URI, so we have to go back to normal
-                                         * mode and signal the error (done
-                                         * below) */
-                                       worker->mode = WORKER_MODE_SINGLE_PLAY;
-                                       _reset_pl_info(worker);
-                               }
-                       }
-
-                       if (worker->mode == WORKER_MODE_SINGLE_PLAY) {
-                               if (err->domain == GST_STREAM_ERROR &&
-                                       err->code == GST_STREAM_ERROR_WRONG_TYPE)
-                               {/* Maybe it is a playlist? */
-                                       GSList *plitems = _parse_playlist(worker->media.location);
-                                       
-                                       if (plitems)
-                                       {/* Yes, it is a plitem */
-                                               g_error_free(err);
-                                               mafw_gst_renderer_worker_play(worker, NULL, plitems);
-                                               break;
-                                       }
-                                       
-                                       
-                               }
-                               _send_error(worker, err);
-                       }
-               }
-               break;
-       case GST_MESSAGE_EOS:
-               if (!worker->is_error) {
-                       worker->eos = TRUE;
-
-                       if (worker->mode == WORKER_MODE_PLAYLIST) {
-                               if (worker->pl.current <
-                                   (g_slist_length(worker->pl.items) - 1)) {
-                                       /* If the playlist EOS is not reached
-                                          continue playing */
-                                       _play_pl_next(worker);
-                               } else {
-                                       /* Playlist EOS, go back to normal
-                                          mode */
-                                       worker->mode = WORKER_MODE_SINGLE_PLAY;
-                                       _reset_pl_info(worker);
-                               }
-                       }
-
-                       if (worker->mode == WORKER_MODE_SINGLE_PLAY ||
-                            worker->mode == WORKER_MODE_REDUNDANT) {
-                               if (worker->notify_eos_handler)
-                                       worker->notify_eos_handler(
-                                               worker,
-                                               worker->owner);
-
-                               /* We can remove the message handlers now, we
-                                  are not interested in bus messages
-                                  anymore. */
-                               if (worker->bus) {
-                                       gst_bus_set_sync_handler(worker->bus,
-                                                                 NULL,
-                                                                NULL);
-                               }
-                               if (worker->async_bus_id) {
-                                       g_source_remove(worker->async_bus_id);
-                                       worker->async_bus_id = 0;
-                               }
-
-                                if (worker->mode == WORKER_MODE_REDUNDANT) {
-                                        /* Go to normal mode */
-                                        worker->mode = WORKER_MODE_SINGLE_PLAY;
-                                        _reset_pl_info(worker);
-                                }
-                       }
-               }
-               break;
-       case GST_MESSAGE_TAG:
-               _handle_tag(worker, msg);
-               break;
-       case GST_MESSAGE_BUFFERING:
-               _handle_buffering(worker, msg);
-               break;
-       case GST_MESSAGE_DURATION:
-               _handle_duration(worker, msg);
-               break;
-       case GST_MESSAGE_ELEMENT:
-               _handle_element_msg(worker, msg);
-               break;
-       case GST_MESSAGE_STATE_CHANGED:
-               if ((GstElement *)GST_MESSAGE_SRC(msg) == worker->pipeline)
-                       _handle_state_changed(msg, worker);
-               break;
-       case GST_MESSAGE_APPLICATION:
-               if (gst_structure_has_name(gst_message_get_structure(msg),
-                                          "ckey"))
-               {
-                       GValue v = {0};
-                       g_value_init(&v, G_TYPE_INT);
-                       g_value_set_int(&v, worker->colorkey);
-                       mafw_extension_emit_property_changed(
-                               MAFW_EXTENSION(worker->owner),
-                               MAFW_PROPERTY_RENDERER_COLORKEY,
-                               &v);
-               }
-       default: break;
-       }
-       return TRUE;
-}
-
-/* NOTE this function will possibly be called from a different thread than the
- * glib main thread. */
-static void _stream_info_cb(GstObject *pipeline, GParamSpec *unused,
-                           MafwGstRendererWorker *worker)
-{
-       g_debug("stream-info changed");
-       _parse_stream_info(worker);
-}
-
-static void _volume_cb(MafwGstRendererWorkerVolume *wvolume, gdouble volume,
-                      gpointer data)
-{
-       MafwGstRendererWorker *worker = data;
-       GValue value = {0, };
-
-       _reset_volume_and_mute_to_pipeline(worker);
-
-       g_value_init(&value, G_TYPE_UINT);
-       g_value_set_uint(&value, (guint) (volume * 100.0));
-       mafw_extension_emit_property_changed(MAFW_EXTENSION(worker->owner),
-                                            MAFW_PROPERTY_RENDERER_VOLUME,
-                                            &value);
-}
-
-#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
-
-static void _mute_cb(MafwGstRendererWorkerVolume *wvolume, gboolean mute,
-                    gpointer data)
-{
-       MafwGstRendererWorker *worker = data;
-       GValue value = {0, };
-
-       _reset_volume_and_mute_to_pipeline(worker);
-
-       g_value_init(&value, G_TYPE_BOOLEAN);
-       g_value_set_boolean(&value, mute);
-       mafw_extension_emit_property_changed(MAFW_EXTENSION(worker->owner),
-                                            MAFW_PROPERTY_RENDERER_MUTE,
-                                            &value);
-}
-
-#endif
-
-/* TODO: I think it's not enought to act on error, we need to handle
- * DestroyNotify on the given window ourselves, because for example helixbin
- * does it and silently stops the decoder thread.  But it doesn't notify
- * us... */
-static int xerror(Display *dpy, XErrorEvent *xev)
-{
-       MafwGstRendererWorker *worker;
-
-       if (Global_worker == NULL) {
-               return -1;
-       } else {
-               worker = Global_worker;
-       }
-
-       /* Swallow BadWindow and stop pipeline when the error is about the
-        * currently set xid. */
-       if (worker->xid &&
-           xev->resourceid == worker->xid &&
-           xev->error_code == BadWindow)
-       {
-               g_warning("BadWindow received for current xid (%x).",
-                       (gint)xev->resourceid);
-               worker->xid = 0;
-               /* We must post a message to the bus, because this function is
-                * invoked from a different thread (xvimagerenderer's queue). */
-               _post_error(worker, g_error_new_literal(
-                                   MAFW_RENDERER_ERROR,
-                                   MAFW_RENDERER_ERROR_PLAYBACK,
-                                   "Video window gone"));
-       }
-       return 0;
-}
-
-/*
- * Resets the media information.
- */
-static void _reset_media_info(MafwGstRendererWorker *worker)
-{
-       if (worker->media.location) {
-               g_free(worker->media.location);
-               worker->media.location = NULL;
-       }
-       worker->media.length_nanos = -1;
-       worker->media.has_visual_content = FALSE;
-       worker->media.seekable = SEEKABILITY_UNKNOWN;
-       worker->media.video_width = 0;
-       worker->media.video_height = 0;
-       worker->media.fps = 0.0;
-}
-
-static void _set_volume_and_mute(MafwGstRendererWorker *worker, gdouble vol,
-                                gboolean mute)
-{
-       g_return_if_fail(worker->wvolume != NULL);
-
-       mafw_gst_renderer_worker_volume_set(worker->wvolume, vol, mute);
-}
-
-static void _set_volume(MafwGstRendererWorker *worker, gdouble new_vol)
-{
-       g_return_if_fail(worker->wvolume != NULL);
-
-       _set_volume_and_mute(
-               worker, new_vol,
-               mafw_gst_renderer_worker_volume_is_muted(worker->wvolume));
-}
-
-static void _set_mute(MafwGstRendererWorker *worker, gboolean mute)
-{
-       g_return_if_fail(worker->wvolume != NULL);
-
-       _set_volume_and_mute(
-               worker, mafw_gst_renderer_worker_volume_get(worker->wvolume),
-               mute);
-}
-
-/*
- * Start to play the media
- */
-static void _start_play(MafwGstRendererWorker *worker)
-{
-       MafwGstRenderer *renderer = (MafwGstRenderer*) worker->owner;
-       GstStateChangeReturn state_change_info;
-       char *autoload_sub = NULL;
-
-       g_assert(worker->pipeline);
-       g_object_set(G_OBJECT(worker->pipeline),
-                    "uri", worker->media.location, NULL);
-
-       if (worker->subtitles.enabled) {
-               autoload_sub = uri_get_subtitle_uri(worker->media.location);
-               if (autoload_sub) {
-                       g_debug("SUBURI: %s", autoload_sub);
-                       g_object_set(G_OBJECT(worker->pipeline),
-                                    "suburi", autoload_sub,
-                                    "subtitle-font-desc", worker->subtitles.font,
-                                    "subtitle-encoding", worker->subtitles.encoding,
-                                    NULL);
-
-                       gst_element_set_state(worker->pipeline, GST_STATE_READY);
-                       g_free(autoload_sub);
-               }
-       } else {
-               g_object_set(G_OBJECT(worker->pipeline), "suburi", NULL, NULL);
-       }
-
-       g_debug("URI: %s", worker->media.location);
-       g_debug("setting pipeline to PAUSED");
-
-       worker->report_statechanges = TRUE;
-       state_change_info = gst_element_set_state(worker->pipeline, 
-                                                 GST_STATE_PAUSED);
-       if (state_change_info == GST_STATE_CHANGE_NO_PREROLL) {
-               /* FIXME:  for live sources we may have to handle
-                  buffering and prerolling differently */
-               g_debug ("Source is live!");
-               worker->is_live = TRUE;
-       }
-        worker->prerolling = TRUE;
-
-       worker->is_stream = uri_is_stream(worker->media.location);
-
-        if (renderer->update_playcount_id > 0) {
-                g_source_remove(renderer->update_playcount_id);
-                renderer->update_playcount_id = 0;
-        }
-
-}
-
-/*
- * Constructs gst pipeline
- *
- * FIXME: Could the same pipeline be used for playing all media instead of
- *  constantly deleting and reconstructing it again?
- */
-static void _construct_pipeline(MafwGstRendererWorker *worker)
-{
-       g_debug("constructing pipeline");
-       g_assert(worker != NULL);
-
-       /* Return if we have already one */
-       if (worker->pipeline)
-               return;
-
-       _free_taglist(worker);
-
-       g_debug("Creating a new instance of playbin2");
-       worker->pipeline = gst_element_factory_make("playbin2",
-                                                   "playbin");
-       if (worker->pipeline == NULL)
-       {
-               /* Let's try with playbin */
-               g_warning ("playbin2 failed, falling back to playbin");
-               worker->pipeline = gst_element_factory_make("playbin",
-                                                           "playbin");
-
-               if (worker->pipeline) {
-                       /* Use nwqueue only for non-rtsp and non-mms(h)
-                          streams. */
-                       gboolean use_nw;
-                       use_nw = worker->media.location && 
-                               !g_str_has_prefix(worker->media.location, 
-                                                 "rtsp://") &&
-                               !g_str_has_prefix(worker->media.location, 
-                                                 "mms://") &&
-                               !g_str_has_prefix(worker->media.location, 
-                                                 "mmsh://");
-                       
-                       g_debug("playbin using network queue: %d", use_nw);
-
-                       /* These need a modified version of playbin. */
-                       g_object_set(G_OBJECT(worker->pipeline),
-                                    "nw-queue", use_nw,
-                                    "no-video-transform", TRUE,
-                                    NULL);
-               }
-       }
-
-       if (!worker->pipeline) {
-               g_critical("failed to create playback pipeline");
-               g_signal_emit_by_name(MAFW_EXTENSION (worker->owner), 
-                                     "error",
-                                     MAFW_RENDERER_ERROR,
-                                     MAFW_RENDERER_ERROR_UNABLE_TO_PERFORM,
-                                     "Could not create pipeline");
-               g_assert_not_reached();
-       }
-
-
-       worker->bus = gst_pipeline_get_bus(GST_PIPELINE(worker->pipeline));
-       gst_bus_set_sync_handler(worker->bus,
-                                (GstBusSyncHandler)_sync_bus_handler, worker);
-       worker->async_bus_id = gst_bus_add_watch_full(worker->bus,G_PRIORITY_HIGH,
-                                                (GstBusFunc)_async_bus_handler,
-                                                worker, NULL);
-
-       /* Listen for changes in stream-info object to find out whether the
-        * media contains video and throw error if application has not provided
-        * video window. */
-       g_signal_connect(worker->pipeline, "notify::stream-info",
-                        G_CALLBACK(_stream_info_cb), worker);
-
-#ifndef MAFW_GST_RENDERER_DISABLE_PULSE_VOLUME
-       
-
-       /* Set audio and video sinks ourselves. We create and configure
-          them only once. */
-       if (!worker->asink) {
-               worker->asink = gst_element_factory_make("pulsesink", NULL);
-               if (!worker->asink) {
-                       g_critical("Failed to create pipeline audio sink");
-                       g_signal_emit_by_name(MAFW_EXTENSION (worker->owner), 
-                                             "error",
-                                             MAFW_RENDERER_ERROR,
-                                             MAFW_RENDERER_ERROR_UNABLE_TO_PERFORM,
-                                             "Could not create audio sink");
-                       g_assert_not_reached();
-               }
-               gst_object_ref(worker->asink);
-               g_object_set(worker->asink,
-                               "buffer-time", (gint64) MAFW_GST_BUFFER_TIME,
-                               "latency-time", (gint64) MAFW_GST_LATENCY_TIME,
-                               NULL);
-       }
-       g_object_set(worker->pipeline, "audio-sink", worker->asink, NULL);
-#endif
-
-       if (!worker->vsink) {
-               worker->vsink = gst_element_factory_make("xvimagesink", NULL);
-               if (!worker->vsink) {
-                       g_critical("Failed to create pipeline video sink");
-                       g_signal_emit_by_name(MAFW_EXTENSION (worker->owner), 
-                                             "error",
-                                             MAFW_RENDERER_ERROR,
-                                             MAFW_RENDERER_ERROR_UNABLE_TO_PERFORM,
-                                             "Could not create video sink");
-                       g_assert_not_reached();
-               }
-               gst_object_ref(worker->vsink);
-               g_object_set(G_OBJECT(worker->vsink),
-                               "handle-events", TRUE,
-                               "force-aspect-ratio", TRUE,
-                               NULL);
-       }
-       g_object_set(worker->pipeline,
-                       "video-sink", worker->vsink,
-                       "flags", 103,
-                       NULL);
-
-       if (!worker->tsink) {
-               worker->tsink = gst_element_factory_make("textoverlay", NULL);
-               if (!worker->tsink) {
-                       g_critical("Failed to create pipeline text sink");
-                       g_signal_emit_by_name(MAFW_EXTENSION (worker->owner), 
-                                             "error",
-                                             MAFW_RENDERER_ERROR,
-                                             MAFW_RENDERER_ERROR_UNABLE_TO_PERFORM,
-                                             "Could not create text sink");
-                       g_assert_not_reached();
-               }
-               gst_object_ref(worker->tsink);
-       }
-       g_object_set(worker->pipeline, "text-sink", worker->tsink, NULL);
-}
-
-/*
- * @seek_type: GstSeekType
- * @position: Time in seconds where to seek
- */
-static void _do_seek(MafwGstRendererWorker *worker, GstSeekType seek_type,
-                    gint position, GError **error)
-{
-       gboolean ret;
-       gint64 spos;
-
-       g_assert(worker != NULL);
-
-       if (worker->eos || !worker->media.seekable)
-               goto err;
-
-       /* According to the docs, relative seeking is not so easy:
-       GST_SEEK_TYPE_CUR - change relative to currently configured segment.
-       This can't be used to seek relative to the current playback position -
-       do a position query, calculate the desired position and then do an
-       absolute position seek instead if that's what you want to do. */
-       if (seek_type == GST_SEEK_TYPE_CUR)
-       {
-               gint curpos = mafw_gst_renderer_worker_get_position(worker);
-               position = curpos + position;
-               seek_type = GST_SEEK_TYPE_SET;
-       }
-
-       if (position < 0) {
-               position = 0;
-       }
-
-       worker->seek_position = position;
-       worker->report_statechanges = FALSE;
-       spos = (gint64)position * GST_SECOND;
-       g_debug("seek: type = %d, offset = %lld", seek_type, spos);
-
-        /* If the pipeline has been set to READY by us, then wake it up by
-          setting it to PAUSED (when we get the READY->PAUSED transition
-          we will execute the seek). This way when we seek we disable the
-          READY state (logical, since the player is not idle anymore)
-          allowing the sink to render the destination frame in case of
-          video playback */
-        if (worker->in_ready && worker->state == GST_STATE_READY) {
-                gst_element_set_state(worker->pipeline, GST_STATE_PAUSED);
-        } else {
-                ret = gst_element_seek(worker->pipeline, 1.0, GST_FORMAT_TIME,
-                                       GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_KEY_UNIT,
-                                       seek_type, spos,
-                                       GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
-                if (!ret) {
-                        /* Seeking is async, so seek_position should not be
-                           invalidated here */
-                        goto err;
-                }
-       }
-        return;
-
-err:    g_set_error(error,
-                   MAFW_RENDERER_ERROR,
-                   MAFW_RENDERER_ERROR_CANNOT_SET_POSITION,
-                   "Seeking to %d failed", position);
-}
-
-/* @vol should be between [0 .. 100], higher values (up to 1000) are allowed,
- * but probably cause distortion. */
-void mafw_gst_renderer_worker_set_volume(
-       MafwGstRendererWorker *worker, guint volume)
-{
-        _set_volume(worker, CLAMP((gdouble)volume / 100.0, 0.0, 1.0));
-}
-
-guint mafw_gst_renderer_worker_get_volume(
-       MafwGstRendererWorker *worker)
-{
-        return (guint)
-               (mafw_gst_renderer_worker_volume_get(worker->wvolume) * 100);
-}
-
-void mafw_gst_renderer_worker_set_mute(MafwGstRendererWorker *worker,
-                                     gboolean mute)
-{
-        _set_mute(worker, mute);
-}
-
-gboolean mafw_gst_renderer_worker_get_mute(MafwGstRendererWorker *worker)
-{
-       return mafw_gst_renderer_worker_volume_is_muted(worker->wvolume);
-}
-
-#ifdef HAVE_GDKPIXBUF
-void mafw_gst_renderer_worker_set_current_frame_on_pause(MafwGstRendererWorker *worker,
-                                                               gboolean current_frame_on_pause)
-{
-        worker->current_frame_on_pause = current_frame_on_pause;
-}
-
-gboolean mafw_gst_renderer_worker_get_current_frame_on_pause(MafwGstRendererWorker *worker)
-{
-       return worker->current_frame_on_pause;
-}
-#endif
-
-void mafw_gst_renderer_worker_set_position(MafwGstRendererWorker *worker,
-                                         GstSeekType seek_type,
-                                         gint position, GError **error)
-{
-        /* If player is paused and we have a timeout for going to ready
-        * restart it. This is logical, since the user is seeking and
-        * thus, the player is not idle anymore. Also this prevents that
-        * when seeking streams we enter buffering and in the middle of
-        * the buffering process we set the pipeline to ready (which stops
-        * the buffering before it reaches 100%, making the client think
-        * buffering is still going on).
-        */
-        if (worker->ready_timeout) {
-                _remove_ready_timeout(worker);
-                _add_ready_timeout(worker);
-        }
-
-        _do_seek(worker, seek_type, position, error);
-        if (worker->notify_seek_handler)
-                worker->notify_seek_handler(worker, worker->owner);
-}
-
-/*
- * Gets current position, rounded down into precision of one second.  If a seek
- * is pending, returns the position we are going to seek.  Returns -1 on
- * failure.
- */
-gint mafw_gst_renderer_worker_get_position(MafwGstRendererWorker *worker)
-{
-       GstFormat format;
-       gint64 time = 0;
-       g_assert(worker != NULL);
-
-       /* If seek is ongoing, return the position where we are seeking. */
-       if (worker->seek_position != -1)
-       {
-               return worker->seek_position;
-       }
-       /* Otherwise query position from pipeline. */
-       format = GST_FORMAT_TIME;
-       if (worker->pipeline &&
-            gst_element_query_position(worker->pipeline, &format, &time))
-       {
-               return (gint)(NSECONDS_TO_SECONDS(time));
-       }
-       return -1;
-}
-
-GHashTable *mafw_gst_renderer_worker_get_current_metadata(
-       MafwGstRendererWorker *worker)
-{
-       return worker->current_metadata;
-}
-
-void mafw_gst_renderer_worker_set_xid(MafwGstRendererWorker *worker, XID xid)
-{
-       /* Check for errors on the target window */
-       XSetErrorHandler(xerror);
-
-       /* Store the target window id */
-       g_debug("Setting xid: %x", (guint)xid);
-       worker->xid = xid;
-
-       /* Check if we should use it right away */
-       mafw_gst_renderer_worker_apply_xid(worker);
-}
-
-XID mafw_gst_renderer_worker_get_xid(MafwGstRendererWorker *worker)
-{
-       return worker->xid;
-}
-
-gboolean mafw_gst_renderer_worker_get_autopaint(
-       MafwGstRendererWorker *worker)
-{
-       return worker->autopaint;
-}
-void mafw_gst_renderer_worker_set_autopaint(
-       MafwGstRendererWorker *worker, gboolean autopaint)
-{
-       worker->autopaint = autopaint;
-       if (worker->vsink)
-               g_object_set(worker->vsink, "autopaint-colorkey",
-                            worker->autopaint, NULL);
-}
-
-gint mafw_gst_renderer_worker_get_colorkey(
-       MafwGstRendererWorker *worker)
-{
-       return worker->colorkey;
-}
-
-void mafw_gst_renderer_worker_set_colorkey(
-       MafwGstRendererWorker *worker, gint colorkey)
-{
-       worker->colorkey = colorkey;
-       if (worker->vsink)
-               g_object_set(worker->vsink, "colorkey",
-                            worker->colorkey, NULL);
-}
-
-gboolean mafw_gst_renderer_worker_get_seekable(MafwGstRendererWorker *worker)
-{
-       return worker->media.seekable;
-}
-
-static void _play_pl_next(MafwGstRendererWorker *worker) {
-       gchar *next;
-
-       g_assert(worker != NULL);
-       g_return_if_fail(worker->pl.items != NULL);
-
-       next = (gchar *) g_slist_nth_data(worker->pl.items,
-                                         ++worker->pl.current);
-       mafw_gst_renderer_worker_stop(worker);
-       _reset_media_info(worker);
-
-       worker->media.location = g_strdup(next);
-       _construct_pipeline(worker);
-       _start_play(worker);
-}
-
-static void _do_play(MafwGstRendererWorker *worker)
-{
-       g_assert(worker != NULL);
-
-       if (worker->pipeline == NULL) {
-               g_debug("play without a pipeline!");
-               return;
-       }
-       worker->report_statechanges = TRUE;
-
-       /* If we have to stay paused, we do and add the ready
-        * timeout. Otherwise, we move the pipeline */
-       if (!worker->stay_paused) {
-               /* If pipeline is READY, we move it to PAUSED,
-                * otherwise, to PLAYING */
-               if (worker->state == GST_STATE_READY) {
-                       gst_element_set_state(worker->pipeline,
-                                             GST_STATE_PAUSED);
-                       g_debug("setting pipeline to PAUSED");
-               } else {
-                       _reset_volume_and_mute_to_pipeline(worker);
-                       gst_element_set_state(worker->pipeline,
-                                             GST_STATE_PLAYING);
-                       g_debug("setting pipeline to PLAYING");
-               }
-       }
-       else {
-               g_debug("staying in PAUSED state");
-               _add_ready_timeout(worker);
-       }
-}
-
-void mafw_gst_renderer_worker_play(MafwGstRendererWorker *worker,
-                                 const gchar *uri, GSList *plitems)
-{
-       g_assert(uri || plitems);
-
-       mafw_gst_renderer_worker_stop(worker);
-       _reset_media_info(worker);
-       _reset_pl_info(worker);
-       /* Check if the item to play is a single item or a playlist. */
-       if (plitems || uri_is_playlist(uri)){
-               gchar *item;
-               /* In case of a playlist we parse it and start playing the first
-                  item of the playlist. */
-               if (plitems)
-               {
-                       worker->pl.items = plitems;
-               }
-               else
-               {
-                       worker->pl.items = _parse_playlist(uri);
-               }
-               if (!worker->pl.items)
-               {
-                       _send_error(worker,
-                           g_error_new(MAFW_RENDERER_ERROR,
-                                       MAFW_RENDERER_ERROR_PLAYLIST_PARSING,
-                                       "Playlist parsing failed: %s",
-                                       uri));
-                       return;
-               }
-
-               /* Set the playback mode */
-               worker->mode = WORKER_MODE_PLAYLIST;
-               worker->pl.notify_play_pending = TRUE;
-
-               /* Set the item to be played */
-               worker->pl.current = 0;
-               item = (gchar *) g_slist_nth_data(worker->pl.items, 0);
-               worker->media.location = g_strdup(item);
-       } else {
-               /* Single item. Set the playback mode according to that */
-               worker->mode = WORKER_MODE_SINGLE_PLAY;
-
-               /* Set the item to be played */
-               worker->media.location = g_strdup(uri);
-       }
-       _construct_pipeline(worker);
-       _start_play(worker);
-}
-
-void mafw_gst_renderer_worker_play_alternatives(MafwGstRendererWorker *worker,
-                                                gchar **uris)
-{
-        gint i;
-        gchar *item;
-
-        g_assert(uris && uris[0]);
-
-        mafw_gst_renderer_worker_stop(worker);
-        _reset_media_info(worker);
-        _reset_pl_info(worker);
-
-        /* Add the uris to playlist */
-        i = 0;
-        while (uris[i]) {
-                worker->pl.items =
-                        g_slist_append(worker->pl.items, g_strdup(uris[i]));
-                i++;
-        }
-
-        /* Set the playback mode */
-        worker->mode = WORKER_MODE_REDUNDANT;
-        worker->pl.notify_play_pending = TRUE;
-
-        /* Set the item to be played */
-        worker->pl.current = 0;
-        item = (gchar *) g_slist_nth_data(worker->pl.items, 0);
-        worker->media.location = g_strdup(item);
-
-        /* Start playing */
-        _construct_pipeline(worker);
-        _start_play(worker);
-}
-
-/*
- * Currently, stop destroys the Gst pipeline and resets the worker into
- * default startup configuration.
- */
-void mafw_gst_renderer_worker_stop(MafwGstRendererWorker *worker)
-{
-       g_debug("worker stop");
-       g_assert(worker != NULL);
-
-       /* If location is NULL, this is a pre-created pipeline */
-       if (worker->async_bus_id && worker->pipeline && !worker->media.location)
-               return;
-
-       if (worker->pipeline) {
-               g_debug("destroying pipeline");
-               if (worker->async_bus_id) {
-                       g_source_remove(worker->async_bus_id);
-                       worker->async_bus_id = 0;
-               }
-               gst_bus_set_sync_handler(worker->bus, NULL, NULL);
-               gst_element_set_state(worker->pipeline, GST_STATE_NULL);
-               if (worker->bus) {
-                       gst_object_unref(GST_OBJECT_CAST(worker->bus));
-                       worker->bus = NULL;
-               }
-               gst_object_unref(GST_OBJECT(worker->pipeline));
-               worker->pipeline = NULL;
-       }
-
-       /* Reset worker */
-       worker->report_statechanges = TRUE;
-       worker->state = GST_STATE_NULL;
-       worker->prerolling = FALSE;
-       worker->is_live = FALSE;
-       worker->buffering = FALSE;
-       worker->is_stream = FALSE;
-       worker->is_error = FALSE;
-       worker->eos = FALSE;
-       worker->seek_position = -1;
-       _remove_ready_timeout(worker);
-       _free_taglist(worker);
-       if (worker->current_metadata) {
-               g_hash_table_destroy(worker->current_metadata);
-               worker->current_metadata = NULL;
-       }
-
-       if (worker->duration_seek_timeout != 0) {
-               g_source_remove(worker->duration_seek_timeout);
-               worker->duration_seek_timeout = 0;
-       }
-
-       /* Reset media iformation */
-       _reset_media_info(worker);
-
-       /* We are not playing, so we can let the screen blank */
-       blanking_allow();
-       keypadlocking_allow();
-
-       /* And now get a fresh pipeline ready */
-       _construct_pipeline(worker);
-}
-
-void mafw_gst_renderer_worker_pause(MafwGstRendererWorker *worker)
-{
-       g_assert(worker != NULL);
-
-       if (worker->buffering && worker->state == GST_STATE_PAUSED &&
-           !worker->prerolling) {
-               /* If we are buffering and get a pause, we have to
-                * signal state change and stay_paused */
-               g_debug("Pausing while buffering, signalling state change");
-               worker->stay_paused = TRUE;
-               if (worker->notify_pause_handler) {
-                       worker->notify_pause_handler(
-                               worker,
-                               worker->owner);
-               }
-       } else {
-               worker->report_statechanges = TRUE;
-
-               if (gst_element_set_state(worker->pipeline, GST_STATE_PAUSED) ==
-                   GST_STATE_CHANGE_ASYNC)
-               {
-                       /* XXX this blocks at most 2 seconds. */
-                       gst_element_get_state(worker->pipeline, NULL, NULL,
-                                     2 * GST_SECOND);
-               }
-               blanking_allow();
-               keypadlocking_allow();
-       }
-}
-
-void mafw_gst_renderer_worker_resume(MafwGstRendererWorker *worker)
-{
-       if (worker->mode == WORKER_MODE_PLAYLIST ||
-            worker->mode == WORKER_MODE_REDUNDANT) {
-               /* We must notify play if the "playlist" playback
-                  is resumed */
-               worker->pl.notify_play_pending = TRUE;
-       }
-       if (worker->buffering && worker->state == GST_STATE_PAUSED &&
-           !worker->prerolling) {
-               /* If we are buffering we cannot resume, but we know
-                * that the pipeline will be moved to PLAYING as
-                * stay_paused is FALSE, so we just activate the state
-                * change report, this way as soon as buffering is finished
-                * the pipeline will be set to PLAYING and the state
-                * change will be reported */
-               worker->report_statechanges = TRUE;
-               g_debug("Resumed while buffering, activating pipeline state "
-                       "changes");
-               /* Notice though that we can receive the Resume before
-                  we get any buffering information. In that case
-                  we go with the "else" branch and set the pipeline to
-                  to PLAYING. However, it is possible that in this case
-                  we get the fist buffering signal before the
-                  PAUSED -> PLAYING state change. In that case, since we
-                  ignore state changes while buffering we never signal
-                  the state change to PLAYING. We can only fix this by
-                  checking, when we receive a PAUSED -> PLAYING transition
-                  if we are buffering, and in that case signal the state
-                  change (if we get that transition while buffering
-                  is on, it can only mean that the client resumed playback
-                  while buffering, and we must notify the state change) */
-       } else {
-               _do_play(worker);
-       }
-}
-
-static void _volume_init_cb(MafwGstRendererWorkerVolume *wvolume,
-                           gpointer data)
-{
-       MafwGstRendererWorker *worker = data;
-       gdouble volume;
-       gboolean mute;
-
-       worker->wvolume = wvolume;
-
-       g_debug("volume manager initialized");
-
-       volume = mafw_gst_renderer_worker_volume_get(wvolume);
-       mute = mafw_gst_renderer_worker_volume_is_muted(wvolume);
-       _volume_cb(wvolume, volume, worker);
-#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
-       _mute_cb(wvolume, mute, worker);
-#endif
-}
-
-MafwGstRendererWorker *mafw_gst_renderer_worker_new(gpointer owner)
-{
-        MafwGstRendererWorker *worker;
-       GMainContext *main_context;
-
-       worker = g_new0(MafwGstRendererWorker, 1);
-       worker->mode = WORKER_MODE_SINGLE_PLAY;
-       worker->pl.items = NULL;
-       worker->pl.current = 0;
-       worker->pl.notify_play_pending = TRUE;
-       worker->owner = owner;
-       worker->report_statechanges = TRUE;
-       worker->state = GST_STATE_NULL;
-       worker->seek_position = -1;
-       worker->ready_timeout = 0;
-       worker->in_ready = FALSE;
-       worker->xid = 0;
-       worker->autopaint = TRUE;
-       worker->colorkey = -1;
-       worker->vsink = NULL;
-       worker->asink = NULL;
-       worker->tsink = NULL;
-       worker->tag_list = NULL;
-       worker->current_metadata = NULL;
-       worker->subtitles.enabled = FALSE;
-       worker->subtitles.font = NULL;
-       worker->subtitles.encoding = NULL;
-
-#ifdef HAVE_GDKPIXBUF
-       worker->current_frame_on_pause = FALSE;
-       _init_tmp_files_pool(worker);
-#endif
-       worker->notify_seek_handler = NULL;
-       worker->notify_pause_handler = NULL;
-       worker->notify_play_handler = NULL;
-       worker->notify_buffer_status_handler = NULL;
-       worker->notify_eos_handler = NULL;
-       worker->notify_error_handler = NULL;
-       Global_worker = worker;
-       main_context = g_main_context_default();
-       worker->wvolume = NULL;
-       mafw_gst_renderer_worker_volume_init(main_context,
-                                            _volume_init_cb, worker,
-                                            _volume_cb, worker,
-#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
-                                            _mute_cb,
-#else
-                                            NULL,
-#endif
-                                            worker);
-       blanking_init();
-       _construct_pipeline(worker);
-
-       return worker;
-}
-
-void mafw_gst_renderer_worker_exit(MafwGstRendererWorker *worker)
-{
-       blanking_deinit();
-#ifdef HAVE_GDKPIXBUF
-       _destroy_tmp_files_pool(worker);
-#endif
-       mafw_gst_renderer_worker_volume_destroy(worker->wvolume);
-        mafw_gst_renderer_worker_stop(worker);
-}
-/* vi: set noexpandtab ts=8 sw=8 cino=t0,(0: */