dvbsuboverlay: Handle non_modifying_colour_flag correctly in the RLE handlers
[platform/upstream/gstreamer.git] / gst / dvbsuboverlay / dvb-sub.c
index b0b26cc..21061a3 100644 (file)
@@ -1,7 +1,6 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
-/*
- * libdvbsub - DVB subtitle decoding
+/* dvb-sub.c - DVB subtitle decoding
  * Copyright (C) Mart Raudsepp 2009 <mart.raudsepp@artecdesign.ee>
+ * Copyright (C) 2010 ONELAN Ltd.
  * 
  * Heavily uses code algorithms ported from ffmpeg's libavcodec/dvbsubdec.c,
  * especially the segment parsers. The original license applies to this
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "dvb-sub.h"
 #include <string.h>             /* memset */
 #include <gst/gstutils.h>       /* GST_READ_UINT16_BE */
 #include <gst/base/gstbitreader.h>      /* GstBitReader */
-#include "ffmpeg-colorspace.h" /* YUV_TO_RGB1_CCIR */   /* FIXME: Just give YUV data to gstreamer then? */
 
-/* FIXME: Convert to GST_LOG and clean up */
-void (*g_log_callback) (GLogLevelFlags log_level, const gchar * format,
-    va_list args, gpointer user_data) = NULL;
-gpointer g_log_callback_user_data = NULL;
+#include "dvb-sub.h"
 
-#define DEBUG
-#ifdef DEBUG
-#define dvb_log(log_type, log_level, format...) real_dvb_log(log_type, log_level, ## format)
-typedef enum
-{
-  /* dvb_log types // DVB_LOG environment variable string */
-  DVB_LOG_GENERAL,              /* GENERAL */
-  DVB_LOG_PAGE,                 /* PAGE */
-  DVB_LOG_REGION,               /* REGION */
-  DVB_LOG_CLUT,                 /* CLUT */
-  DVB_LOG_OBJECT,               /* OBJECT */
-  DVB_LOG_PIXEL,                /* PIXEL */
-  DVB_LOG_RUNLEN,               /* RUNLEN */
-  DVB_LOG_DISPLAY,              /* DISPLAY */
-  DVB_LOG_STREAM,               /* STREAM - issues in the encoded stream (TV service provider encoder problem) */
-  DVB_LOG_PACKET,               /* PACKET - messages during raw demuxer data packet handling */
-  DVB_LOG_LAST                  /* sentinel use only */
-} DvbLogTypes;
+GST_DEBUG_CATEGORY_STATIC (dvbsub_debug);
+#define GST_CAT_DEFAULT dvbsub_debug
 
-static void
-real_dvb_log (const gint log_type, GLogLevelFlags log_level,
-    const gchar * format, ...)
-{
-  if (g_log_callback) {
-    va_list va;
-    va_start (va, format);
-    switch (log_type) {
-      default:
-        g_log_callback (log_level, format, va, g_log_callback_user_data);
-        break;
-      case DVB_LOG_PIXEL:
-      case DVB_LOG_RUNLEN:
-        break;
-    }
-    va_end (va);
-  }
-}
-#else
-#define dvb_log(log_type, log_level, format...)
-#endif
+static void dvb_sub_init (void);
 
 /* FIXME: Are we waiting for an acquisition point before trying to do things? */
 /* FIXME: In the end convert some of the guint8/16 (especially stack variables) back to gint for access efficiency */
@@ -94,14 +52,9 @@ real_dvb_log (const gint log_type, GLogLevelFlags log_level,
  * and signalling the API user for new bitmaps to show on screen.
  */
 
-#define MAX_NEG_CROP 1024
-static guint8 ff_cropTbl[256 + 2 * MAX_NEG_CROP] = { 0, };
-
-#define cm (ff_cropTbl + MAX_NEG_CROP)
+#define AYUV(y,u,v,a) (((a) << 24) | ((y) << 16) | ((u) << 8) | (v))
+#define RGBA_TO_AYUV(r,g,b,a) (((a) << 24) | ((rgb_to_y(r,g,b)) << 16) | ((rgb_to_u(r,g,b)) << 8) | (rgb_to_v(r,g,b)))
 
-/* FIXME: This is really ARGB... We might need this configurable for performant
- * FIXME: use in GStreamer as well if that likes RGBA more (Qt prefers ARGB) */
-#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
 
 typedef struct DVBSubCLUT
 {
@@ -174,10 +127,8 @@ typedef struct DVBSubRegion
   struct DVBSubRegion *next;
 } DVBSubRegion;
 
-typedef struct _DvbSubPrivate DvbSubPrivate;
-struct _DvbSubPrivate
+struct _DvbSub
 {
-  int fd;
   DvbSubCallbacks callbacks;
   gpointer user_data;
 
@@ -189,24 +140,53 @@ struct _DvbSubPrivate
   int display_list_size;
   DVBSubRegionDisplay *display_list;
   GString *pes_buffer;
+  DVBSubtitleWindow display_def;
 };
 
-#define DVB_SUB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), DVB_TYPE_SUB, DvbSubPrivate))
-
-G_DEFINE_TYPE (DvbSub, dvb_sub, G_TYPE_OBJECT);
-
 typedef enum
 {
   TOP_FIELD = 0,
   BOTTOM_FIELD = 1
 } DvbSubPixelDataSubBlockFieldType;
 
-/* FIXME: It might make sense to pass DvbSubPrivate for all the get_* functions, instead of public DvbSub */
+static inline gint
+rgb_to_y (gint r, gint g, gint b)
+{
+  gint ret;
+
+  ret = (gint) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16));
+  ret = CLAMP (ret, 0, 255);
+  return ret;
+}
+
+static inline gint
+rgb_to_u (gint r, gint g, gint b)
+{
+  gint ret;
+
+  ret =
+      (gint) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) +
+      128);
+  ret = CLAMP (ret, 0, 255);
+  return ret;
+}
+
+static inline gint
+rgb_to_v (gint r, gint g, gint b)
+{
+  gint ret;
+
+  ret =
+      (gint) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) +
+      128);
+  ret = CLAMP (ret, 0, 255);
+  return ret;
+}
+
 static DVBSubObject *
 get_object (DvbSub * dvb_sub, guint16 object_id)
 {
-  const DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
-  DVBSubObject *ptr = priv->object_list;
+  DVBSubObject *ptr = dvb_sub->object_list;
 
   while (ptr && ptr->id != object_id) {
     ptr = ptr->next;
@@ -218,8 +198,7 @@ get_object (DvbSub * dvb_sub, guint16 object_id)
 static DVBSubCLUT *
 get_clut (DvbSub * dvb_sub, gint clut_id)
 {
-  const DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
-  DVBSubCLUT *ptr = priv->clut_list;
+  DVBSubCLUT *ptr = dvb_sub->clut_list;
 
   while (ptr && ptr->id != clut_id) {
     ptr = ptr->next;
@@ -228,12 +207,10 @@ get_clut (DvbSub * dvb_sub, gint clut_id)
   return ptr;
 }
 
-// FIXME: Just pass private_data pointer directly here and in other get_* helper functions?
 static DVBSubRegion *
 get_region (DvbSub * dvb_sub, guint8 region_id)
 {
-  const DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
-  DVBSubRegion *ptr = priv->region_list;
+  DVBSubRegion *ptr = dvb_sub->region_list;
 
   while (ptr && ptr->id != region_id) {
     ptr = ptr->next;
@@ -245,7 +222,6 @@ get_region (DvbSub * dvb_sub, guint8 region_id)
 static void
 delete_region_display_list (DvbSub * dvb_sub, DVBSubRegion * region)
 {
-  const DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
   DVBSubObject *object, *obj2;
   DVBSubObject **obj2_ptr;
   DVBSubObjectDisplay *display, *obj_disp, **obj_disp_ptr;
@@ -268,7 +244,7 @@ delete_region_display_list (DvbSub * dvb_sub, DVBSubRegion * region)
         *obj_disp_ptr = obj_disp->object_list_next;
 
         if (!object->display_list) {
-          obj2_ptr = (DVBSubObject **) & priv->object_list;     /* FIXME: Evil casting */
+          obj2_ptr = (DVBSubObject **) & dvb_sub->object_list;  /* FIXME: Evil casting */
           obj2 = *obj2_ptr;
 
           while (obj2 != object) {
@@ -293,13 +269,12 @@ delete_region_display_list (DvbSub * dvb_sub, DVBSubRegion * region)
 static void
 delete_state (DvbSub * dvb_sub)
 {
-  DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
   DVBSubRegion *region;
 
-  while (priv->region_list) {
-    region = priv->region_list;
+  while (dvb_sub->region_list) {
+    region = dvb_sub->region_list;
 
-    priv->region_list = region->next;
+    dvb_sub->region_list = region->next;
 
     delete_region_display_list (dvb_sub, region);
     if (region->pbuf)
@@ -308,79 +283,31 @@ delete_state (DvbSub * dvb_sub)
     g_slice_free (DVBSubRegion, region);
   }
 
-  g_slice_free_chain (DVBSubCLUT, priv->clut_list, next);
-  priv->clut_list = NULL;
-
-  /* Should already be null */
-  if (priv->object_list)
-    g_warning ("Memory deallocation error!");
-}
-
-static void
-dvb_sub_init (DvbSub * self)
-{
-  DvbSubPrivate *priv;
-
-  self->private_data = priv = DVB_SUB_GET_PRIVATE (self);
+  g_slice_free_chain (DVBSubCLUT, dvb_sub->clut_list, next);
+  dvb_sub->clut_list = NULL;
 
-  /* TODO: Add initialization code here */
-  /* FIXME: Do we have a reason to initiate the members to zero, or are we guaranteed that anyway? */
-  priv->region_list = NULL;
-  priv->object_list = NULL;
-  priv->page_time_out = 0;      /* FIXME: Maybe 255 instead? */
-  priv->pes_buffer = g_string_new (NULL);
+  /* Should already be NULL */
+  g_warn_if_fail (dvb_sub->object_list == NULL);
 }
 
 static void
-dvb_sub_finalize (GObject * object)
-{
-  DvbSub *self = DVB_SUB (object);
-  DvbSubPrivate *priv = (DvbSubPrivate *) self->private_data;
-  /* TODO: Add deinitalization code here */
-  /* FIXME: Clear up region_list contents */
-  delete_state (self);          /* close_pid should have called this, but lets be sure */
-  g_string_free (priv->pes_buffer, TRUE);
-
-  G_OBJECT_CLASS (dvb_sub_parent_class)->finalize (object);
-}
-
-/* init static data necessary for ffmpeg-colorspace conversion */
-static void
-dsputil_static_init (void)
-{
-  int i;
-
-  for (i = 0; i < 256; i++)
-    ff_cropTbl[i + MAX_NEG_CROP] = i;
-  for (i = 0; i < MAX_NEG_CROP; i++) {
-    ff_cropTbl[i] = 0;
-    ff_cropTbl[i + MAX_NEG_CROP + 256] = 255;
-  }
-}
-
-static void
-dvb_sub_class_init (DvbSubClass * klass)
+dvb_sub_init (void)
 {
   int i, r, g, b, a = 0;
-  GObjectClass *object_class = (GObjectClass *) klass;
 
-  object_class->finalize = dvb_sub_finalize;
-
-  g_type_class_add_private (klass, sizeof (DvbSubPrivate));
-
-  dsputil_static_init ();       /* Initializes ff_cropTbl table, used in YUV_TO_RGB conversion */
+  GST_DEBUG_CATEGORY_INIT (dvbsub_debug, "dvbsub", 0, "dvbsuboverlay parser");
 
   /* Initialize the static default_clut structure, from which other clut
    * structures are initialized from (to start off with default CLUTs
    * as defined in the specification). */
   default_clut.id = -1;
 
-  default_clut.clut4[0] = RGBA (0, 0, 0, 0);
-  default_clut.clut4[1] = RGBA (255, 255, 255, 255);
-  default_clut.clut4[2] = RGBA (0, 0, 0, 255);
-  default_clut.clut4[3] = RGBA (127, 127, 127, 255);
+  default_clut.clut4[0] = RGBA_TO_AYUV (0, 0, 0, 0);
+  default_clut.clut4[1] = RGBA_TO_AYUV (255, 255, 255, 255);
+  default_clut.clut4[2] = RGBA_TO_AYUV (0, 0, 0, 255);
+  default_clut.clut4[3] = RGBA_TO_AYUV (127, 127, 127, 255);
 
-  default_clut.clut16[0] = RGBA (0, 0, 0, 0);
+  default_clut.clut16[0] = RGBA_TO_AYUV (0, 0, 0, 0);
   for (i = 1; i < 16; i++) {
     if (i < 8) {
       r = (i & 1) ? 255 : 0;
@@ -391,10 +318,10 @@ dvb_sub_class_init (DvbSubClass * klass)
       g = (i & 2) ? 127 : 0;
       b = (i & 4) ? 127 : 0;
     }
-    default_clut.clut16[i] = RGBA (r, g, b, 255);
+    default_clut.clut16[i] = RGBA_TO_AYUV (r, g, b, 255);
   }
 
-  default_clut.clut256[0] = RGBA (0, 0, 0, 0);
+  default_clut.clut256[0] = RGBA_TO_AYUV (0, 0, 0, 0);
   for (i = 1; i < 256; i++) {
     if (i < 8) {
       r = (i & 1) ? 255 : 0;
@@ -429,7 +356,7 @@ dvb_sub_class_init (DvbSubClass * klass)
           break;
       }
     }
-    default_clut.clut256[i] = RGBA (r, g, b, a);
+    default_clut.clut256[i] = RGBA_TO_AYUV (r, g, b, a);
   }
 }
 
@@ -437,7 +364,6 @@ static void
 _dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     gint buf_size)
 {                               /* FIXME: Use guint for buf_size here and in many other places? */
-  DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
   DVBSubRegionDisplay *display;
   DVBSubRegionDisplay *tmp_display_list, **tmp_ptr;
 
@@ -445,37 +371,31 @@ _dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
   guint8 region_id;
   guint8 page_state;
 
-#ifdef DEBUG
-  static int counter = 0;
-  static const gchar *page_state_str[] = {
-    "Normal case",
-    "ACQUISITION POINT",
-    "Mode Change",
-    "RESERVED"
-  };
-#endif
-
   if (buf_size < 1)
     return;
 
-  priv->page_time_out = *buf++;
+  dvb_sub->page_time_out = *buf++;
   page_state = ((*buf++) >> 2) & 3;
 
-#ifdef DEBUG
-  ++counter;
-  dvb_log (DVB_LOG_PAGE, G_LOG_LEVEL_DEBUG,
-      "%d: page_id = %u, length = %d, page_time_out = %u seconds, page_state = %s",
-      counter, page_id, buf_size, priv->page_time_out,
-      page_state_str[page_state]);
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    static const gchar *page_state_str[4] = {
+      "Normal case", "ACQUISITION POINT", "Mode Change", "RESERVED"
+    };
+
+    GST_DEBUG ("PAGE: page_id = %u, length = %d, page_time_out = %u secs, "
+        "page_state = %s", page_id, buf_size, dvb_sub->page_time_out,
+        page_state_str[page_state]);
+  }
 #endif
 
   if (page_state == 2) {        /* Mode change */
     delete_state (dvb_sub);
   }
 
-  tmp_display_list = priv->display_list;
-  priv->display_list = NULL;
-  priv->display_list_size = 0;
+  tmp_display_list = dvb_sub->display_list;
+  dvb_sub->display_list = NULL;
+  dvb_sub->display_list_size = 0;
 
   while (buf + 5 < buf_end) {
     region_id = *buf++;
@@ -501,13 +421,12 @@ _dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
 
     *tmp_ptr = display->next;
 
-    display->next = priv->display_list;
-    priv->display_list = display;
-    priv->display_list_size++;
+    display->next = dvb_sub->display_list;
+    dvb_sub->display_list = display;
+    dvb_sub->display_list_size++;
 
-    dvb_log (DVB_LOG_PAGE, G_LOG_LEVEL_DEBUG,
-        "%d: REGION information: ID = %u, address = %ux%u",
-        counter, region_id, display->x_pos, display->y_pos);
+    GST_LOG ("PAGE: REGION information: ID = %u, address = %ux%u", region_id,
+        display->x_pos, display->y_pos);
   }
 
   while (tmp_display_list) {
@@ -523,8 +442,6 @@ static void
 _dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     gint buf_size)
 {
-  DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
-
   const guint8 *buf_end = buf + buf_size;
   guint8 region_id;
   guint16 object_id;
@@ -543,8 +460,8 @@ _dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
   if (!region) {                /* Create a new region */
     region = g_slice_new0 (DVBSubRegion);
     region->id = region_id;
-    region->next = priv->region_list;
-    priv->region_list = region;
+    region->next = dvb_sub->region_list;
+    dvb_sub->region_list = region;
   }
 
   fill = ((*buf++) >> 3) & 1;
@@ -567,7 +484,7 @@ _dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
 
   region->depth = 1 << (((*buf++) >> 2) & 7);
   if (region->depth < 2 || region->depth > 8) {
-    g_warning ("region depth %d is invalid\n", region->depth);
+    GST_WARNING ("region depth %d is invalid", region->depth);
     region->depth = 4;          /* FIXME: Check from spec this is the default? */
   }
 
@@ -584,14 +501,13 @@ _dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
       region->bgcolor = (((*buf++) >> 2) & 3);
   }
 
-  dvb_log (DVB_LOG_REGION, G_LOG_LEVEL_DEBUG,
-      "id = %u, (%ux%u)@%u-bit",
-      region_id, region->width, region->height, region->depth);
+  GST_DEBUG ("REGION: id = %u, (%ux%u)@%u-bit", region_id, region->width,
+      region->height, region->depth);
 
   if (fill) {
     memset (region->pbuf, region->bgcolor, region->buf_size);
-    dvb_log (DVB_LOG_REGION, G_LOG_LEVEL_DEBUG,
-        "Filling region (%u) with bgcolor = %u", region->id, region->bgcolor);
+    GST_DEBUG ("REGION: filling region (%u) with bgcolor = %u", region->id,
+        region->bgcolor);
   }
 
   delete_region_display_list (dvb_sub, region); /* Delete the region display list for current region - FIXME: why? */
@@ -607,8 +523,8 @@ _dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
 
       object->id = object_id;
 
-      object->next = priv->object_list;
-      priv->object_list = object;
+      object->next = dvb_sub->object_list;
+      dvb_sub->object_list = object;
     }
 
     object->type = (*buf) >> 6;
@@ -634,14 +550,14 @@ _dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     object_display->object_list_next = object->display_list;
     object->display_list = object_display;
 
-    dvb_log (DVB_LOG_REGION, G_LOG_LEVEL_DEBUG,
-        "REGION DATA: object_id = %u, region_id = %u, pos = %ux%u, obj_type = %u",
-        object->id, region->id, object_display->x_pos, object_display->y_pos,
-        object->type);
-    if (object->type == 1 || object->type == 2)
-      dvb_log (DVB_LOG_REGION, G_LOG_LEVEL_DEBUG,
-          "REGION DATA: fgcolor = %u, bgcolor = %u\n", object_display->fgcolor,
-          object_display->bgcolor);
+    GST_DEBUG ("REGION DATA: object_id = %u, region_id = %u, pos = %ux%u, "
+        "obj_type = %u", object->id, region->id, object_display->x_pos,
+        object_display->y_pos, object->type);
+
+    if (object->type == 1 || object->type == 2) {
+      GST_DEBUG ("REGION DATA: fgcolor = %u, bgcolor = %u",
+          object_display->fgcolor, object_display->bgcolor);
+    }
   }
 }
 
@@ -649,19 +565,13 @@ static void
 _dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     gint buf_size)
 {
-  DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
-
   const guint8 *buf_end = buf + buf_size;
   guint8 clut_id;
   DVBSubCLUT *clut;
   int entry_id, depth, full_range;
   int y, cr, cb, alpha;
-  int r, g, b, r_add, g_add, b_add;
 
-#ifdef DEBUG_PACKET_CONTENTS
-  g_print ("DVB clut packet:\n");
-  gst_util_dump_mem (buf, buf_size);
-#endif
+  GST_MEMDUMP ("DVB clut packet", buf, buf_size);
 
   clut_id = *buf++;
   buf += 1;
@@ -669,14 +579,14 @@ _dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
   clut = get_clut (dvb_sub, clut_id);
 
   if (!clut) {
-    clut = g_slice_new (DVBSubCLUT);    /* FIXME-MEMORY-LEAK: This seems to leak per valgrind */
+    clut = g_slice_new (DVBSubCLUT);
 
     memcpy (clut, &default_clut, sizeof (DVBSubCLUT));
 
     clut->id = clut_id;
 
-    clut->next = priv->clut_list;
-    priv->clut_list = clut;
+    clut->next = dvb_sub->clut_list;
+    dvb_sub->clut_list = clut;
   }
 
   while (buf + 4 < buf_end) {
@@ -685,7 +595,7 @@ _dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     depth = (*buf) & 0xe0;
 
     if (depth == 0) {
-      g_warning ("Invalid clut depth 0x%x!", *buf);
+      GST_WARNING ("Invalid clut depth 0x%x!", *buf);
       return;
     }
 
@@ -708,18 +618,15 @@ _dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     if (y == 0)
       alpha = 0xff;
 
-    YUV_TO_RGB1_CCIR (cb, cr);
-    YUV_TO_RGB2_CCIR (r, g, b, y);
-
-    dvb_log (DVB_LOG_CLUT, G_LOG_LEVEL_DEBUG,
-        "CLUT DEFINITION: clut %d := (%d,%d,%d,%d)", entry_id, r, g, b, alpha);
+    GST_DEBUG ("CLUT DEFINITION: clut %d := (%d,%d,%d,%d)", entry_id, y, cb, cr,
+        alpha);
 
     if (depth & 0x80)
-      clut->clut4[entry_id] = RGBA (r, g, b, 255 - alpha);
+      clut->clut4[entry_id] = AYUV (y, cb, cr, 255 - alpha);
     if (depth & 0x40)
-      clut->clut16[entry_id] = RGBA (r, g, b, 255 - alpha);
+      clut->clut16[entry_id] = AYUV (y, cb, cr, 255 - alpha);
     if (depth & 0x20)
-      clut->clut256[entry_id] = RGBA (r, g, b, 255 - alpha);
+      clut->clut256[entry_id] = AYUV (y, cb, cr, 255 - alpha);
   }
 }
 
@@ -738,33 +645,34 @@ _dvb_sub_read_2bit_string (guint8 * destbuf, gint dbuf_len,
 
   static gboolean warning_shown = FALSE;
   if (!warning_shown) {
-    g_warning
-        ("Parsing 2bit color DVB sub-picture. This is not tested at all. If you see this message, "
-        "please provide the developers with sample media with these subtitles, if possible.");
+    g_warning ("Parsing 2bit color DVB sub-picture. This is not tested at all. "
+        "If you see this message, please provide the developers with sample "
+        "media with these subtitles, if possible.");
     warning_shown = TRUE;
   }
-  dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-      "(n=2): Inside %s with dbuf_len = %d", __PRETTY_FUNCTION__, dbuf_len);
+
+  GST_TRACE ("dbuf_len = %d", dbuf_len);
 
   while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 0)) {
     guint run_length = 0, clut_index = 0;
-    gst_bit_reader_get_bits_uint32 (&gb, &bits, 2);
+
+    bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
 
     if (bits) {                 /* 2-bit_pixel-code */
       run_length = 1;
       clut_index = bits;
     } else {                    /* 2-bit_zero */
-      gst_bit_reader_get_bits_uint32 (&gb, &bits, 1);
+      bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
       if (bits == 1) {          /* switch_1 == '1' */
-        gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3);
+        run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 3);
         run_length += 3;
-        gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2);
+        clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
       } else {                  /* switch_1 == '0' */
-        gst_bit_reader_get_bits_uint32 (&gb, &bits, 1);
+        bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
         if (bits == 1) {        /* switch_2 == '1' */
           run_length = 1;       /* 1x pseudo-colour '00' */
         } else {                /* switch_2 == '0' */
-          gst_bit_reader_get_bits_uint32 (&gb, &bits, 2);
+          bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
           switch (bits) {       /* switch_3 */
             case 0x0:          /* end of 2-bit/pixel_code_string */
               stop_parsing = TRUE;
@@ -773,14 +681,14 @@ _dvb_sub_read_2bit_string (guint8 * destbuf, gint dbuf_len,
               run_length = 2;
               break;
             case 0x2:          /* the following 6 bits contain run length coded pixel data */
-              gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4);
+              run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
               run_length += 12;
-              gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2);
+              clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
               break;
             case 0x3:          /* the following 10 bits contain run length coded pixel data */
-              gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8);
+              run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
               run_length += 29;
-              gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2);
+              clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
               break;
           }
         }
@@ -804,10 +712,10 @@ _dvb_sub_read_2bit_string (guint8 * destbuf, gint dbuf_len,
 
     /* Now we can simply memset run_length count of destination bytes
      * to clut_index, but only if not non_modifying */
-    dvb_log (DVB_LOG_RUNLEN, G_LOG_LEVEL_DEBUG,
-        "Setting %u pixels to color 0x%x in destination buffer; dbuf_len left is %d pixels",
-        run_length, clut_index, dbuf_len);
-    if (!(non_mod == 1 && bits == 1))
+    GST_TRACE ("RUNLEN: setting %u pixels to color 0x%x in destination buffer, "
+        "dbuf_len left is %d pixels", run_length, clut_index, dbuf_len);
+
+    if (!(non_mod == 1 && clut_index == 1))
       memset (destbuf, clut_index, run_length);
 
     destbuf += run_length;
@@ -818,8 +726,7 @@ _dvb_sub_read_2bit_string (guint8 * destbuf, gint dbuf_len,
   //gst_bit_reader_skip_to_byte (&gb);
   *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3;
 
-  dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-      "Returning from 2bit_string parser with %u pixels read", pixels_read);
+  GST_TRACE ("PIXEL: returning, read %u pixels", pixels_read);
   // FIXME: Shouldn't need this variable if tracking things in the loop better
   return pixels_read;
 }
@@ -836,34 +743,34 @@ _dvb_sub_read_4bit_string (guint8 * destbuf, gint dbuf_len,
   guint32 bits = 0;
   guint32 pixels_read = 0;
 
-  dvb_log (DVB_LOG_RUNLEN, G_LOG_LEVEL_DEBUG,
-      "Entering 4bit_string parser at srcbuf position %p with buf_size = %d; destination buffer size is %d @ %p",
-      *srcbuf, buf_size, dbuf_len, destbuf);
+  GST_TRACE ("RUNLEN: srcbuf position %p, buf_size = %d; destination buffer "
+      "size is %d @ %p", *srcbuf, buf_size, dbuf_len, destbuf);
 
   while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 0)) {
     guint run_length = 0, clut_index = 0;
-    gst_bit_reader_get_bits_uint32 (&gb, &bits, 4);
+
+    bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
 
     if (bits) {
       run_length = 1;
       clut_index = bits;
     } else {
-      gst_bit_reader_get_bits_uint32 (&gb, &bits, 1);
+      bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
       if (bits == 0) {          /* switch_1 == '0' */
-        gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3);
+        run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 3);
         if (!run_length) {
           stop_parsing = TRUE;
         } else {
           run_length += 2;
         }
       } else {                  /* switch_1 == '1' */
-        gst_bit_reader_get_bits_uint32 (&gb, &bits, 1);
+        bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
         if (bits == 0) {        /* switch_2 == '0' */
-          gst_bit_reader_get_bits_uint32 (&gb, &run_length, 2);
+          run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
           run_length += 4;
-          gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4);
+          clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
         } else {                /* switch_2 == '1' */
-          gst_bit_reader_get_bits_uint32 (&gb, &bits, 2);
+          bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2);
           switch (bits) {
             case 0x0:          /* switch_3 == '00' */
               run_length = 1;   /* 1 pixel of pseudo-color 0 */
@@ -872,14 +779,14 @@ _dvb_sub_read_4bit_string (guint8 * destbuf, gint dbuf_len,
               run_length = 2;   /* 2 pixels of pseudo-color 0 */
               break;
             case 0x2:          /* switch_3 == '10' */
-              gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4);
+              run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
               run_length += 9;
-              gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4);
+              clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
               break;
             case 0x3:          /* switch_3 == '11' */
-              gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8);
+              run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
               run_length += 25;
-              gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4);
+              clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4);
               break;
           }
         }
@@ -903,10 +810,10 @@ _dvb_sub_read_4bit_string (guint8 * destbuf, gint dbuf_len,
 
     /* Now we can simply memset run_length count of destination bytes
      * to clut_index, but only if not non_modifying */
-    dvb_log (DVB_LOG_RUNLEN, G_LOG_LEVEL_DEBUG,
-        "Setting %u pixels to color 0x%x in destination buffer; dbuf_len left is %d pixels",
-        run_length, clut_index, dbuf_len);
-    if (!(non_mod == 1 && bits == 1))
+    GST_TRACE ("RUNLEN: setting %u pixels to color 0x%x in destination buffer; "
+        "dbuf_len left is %d pixels", run_length, clut_index, dbuf_len);
+
+    if (!(non_mod == 1 && clut_index == 1))
       memset (destbuf, clut_index, run_length);
 
     destbuf += run_length;
@@ -917,8 +824,8 @@ _dvb_sub_read_4bit_string (guint8 * destbuf, gint dbuf_len,
   //gst_bit_reader_skip_to_byte (&gb);
   *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3;
 
-  dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-      "Returning from 4bit_string parser with %u pixels read", pixels_read);
+  GST_LOG ("Returning with %u pixels read", pixels_read);
+
   // FIXME: Shouldn't need this variable if tracking things in the loop better
   return pixels_read;
 }
@@ -941,8 +848,8 @@ _dvb_sub_read_8bit_string (guint8 * destbuf, gint dbuf_len,
         "please provide the developers with sample media with these subtitles, if possible.");
     warning_shown = TRUE;
   }
-  dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-      "(n=8): Inside %s with dbuf_len = %d", __PRETTY_FUNCTION__, dbuf_len);
+
+  GST_LOG ("dbuf_len = %d", dbuf_len);
 
   /* FFMPEG-FIXME: ffmpeg uses a manual byte walking algorithm, which might be more performant,
    * FFMPEG-FIXME: but it does almost absolutely no buffer length checking, so could walk over
@@ -953,31 +860,28 @@ _dvb_sub_read_8bit_string (guint8 * destbuf, gint dbuf_len,
   /* Rephrased - it's better to work with bytes with default value '0' instead of reading from memory we don't own. */
   while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 0)) {
     guint run_length = 0, clut_index = 0;
-    gst_bit_reader_get_bits_uint32 (&gb, &bits, 8);
+    bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
 
     if (bits) {                 /* 8-bit_pixel-code */
       run_length = 1;
       clut_index = bits;
     } else {                    /* 8-bit_zero */
-      gst_bit_reader_get_bits_uint32 (&gb, &bits, 1);
+      bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1);
       if (bits == 0) {          /* switch_1 == '0' */
         /* run_length_1-127 for pseudo-colour _entry) '0x00' */
-        gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7);
+        run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 7);
         if (run_length == 0) {  /* end_of_string_signal */
           stop_parsing = TRUE;
         }
       } else {                  /* switch_1 == '1' */
         /* run_length_3-127 */
-        gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7);
-        gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 8);
-#ifdef DEBUG
-        /* Emit a debugging message about stream not following specification */
+        run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 7);
+        clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8);
+
         if (run_length < 3) {
-          dvb_log (DVB_LOG_STREAM, G_LOG_LEVEL_WARNING,
-              "8-bit/pixel_code_string::run_length_3-127 value was %u, but the spec requires it must be >=3",
-              run_length);
+          GST_WARNING ("runlength value was %u, but the spec requires it "
+              "must be >=3", run_length);
         }
-#endif
       }
     }
 
@@ -998,18 +902,18 @@ _dvb_sub_read_8bit_string (guint8 * destbuf, gint dbuf_len,
 
     /* Now we can simply memset run_length count of destination bytes
      * to clut_index, but only if not non_modifying */
-    dvb_log (DVB_LOG_RUNLEN, G_LOG_LEVEL_DEBUG,
-        "Setting %u pixels to color 0x%x in destination buffer; dbuf_len left is %d pixels",
-        run_length, clut_index, dbuf_len);
-    if (!(non_mod == 1 && bits == 1))
+    GST_TRACE ("RUNLEN: setting %u pixels to color 0x%x in destination buffer; "
+        "dbuf_len left is %d pixels", run_length, clut_index, dbuf_len);
+
+    if (!(non_mod == 1 && clut_index == 1))
       memset (destbuf, clut_index, run_length);
 
     destbuf += run_length;
     pixels_read += run_length;
   }
 
-  dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-      "Returning from 8bit_string parser with %u pixels read", pixels_read);
+  GST_LOG ("Returning with %u pixels read", pixels_read);
+
   // FIXME: Shouldn't need this variable if tracking things in the loop better
   return pixels_read;
 }
@@ -1033,16 +937,13 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
   };
   guint8 *map_table;
 
-  dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-      "(parse_block): DVB pixel block size %d, %s field:",
-      buf_size, top_bottom ? "bottom" : "top");
+  GST_LOG ("DVB pixel block size %d, %s field:", buf_size,
+      top_bottom ? "bottom" : "top");
 
-#ifdef DEBUG_PACKET_CONTENTS
-  gst_util_dump_mem (buf, buf_size);
-#endif
+  GST_MEMDUMP ("packet", buf, buf_size);
 
   if (region == NULL) {
-    g_print ("Region is NULL, returning\n");
+    GST_LOG ("Region is NULL, returning");
     return;
   }
 
@@ -1055,11 +956,11 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
     y_pos++;
 
   while (buf < buf_end) {
-    dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-        "Iteration start, %u bytes missing from end; buf = %p, buf_end = %p;  "
-        "Region is number %u, with a dimension of %dx%d; We are at position %dx%d",
-        buf_end - buf, buf, buf_end,
+    GST_LOG ("Iteration start, %u bytes missing from end; buf = %p, "
+        "buf_end = %p; Region is number %u, with a dimension of %dx%d; "
+        "We are at position %dx%d", (guint) (buf_end - buf), buf, buf_end,
         region->id, region->width, region->height, x_pos, y_pos);
+
     // FFMPEG-FIXME: ffmpeg doesn't check for equality and so can overflow destination buffer later on with bad input data
     // FFMPEG-FIXME: However that makes it warn on end_of_object_line and map tables as well, so we add the dest_buf_filled tracking
     // FIXME: Removed x_pos checking here, because we don't want to turn dest_buf_filled to TRUE permanently in that case
@@ -1072,9 +973,11 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
     switch (*buf++) {
       case 0x10:
         if (dest_buf_filled) {
-          g_warning ("Invalid object location for data_type 0x%x!\n", *(buf - 1));      /* FIXME: Be more verbose */
-          g_print ("Remaining data after invalid object location:\n");
-          gst_util_dump_mem (buf, buf_end - buf);
+          /* FIXME: Be more verbose */
+          GST_WARNING ("Invalid object location for data_type 0x%x!",
+              *(buf - 1));
+          GST_MEMDUMP ("Remaining data after invalid object location:", buf,
+              (guint) (buf_end - buf));
           return;
         }
 
@@ -1093,14 +996,16 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
         break;
       case 0x11:
         if (dest_buf_filled) {
-          g_warning ("Invalid object location for data_type 0x%x!\n", *(buf - 1));      /* FIXME: Be more verbose */
-          g_print ("Remaining data after invalid object location:\n");
-          gst_util_dump_mem (buf, buf_end - buf);
+          /* FIXME: Be more verbose */
+          GST_WARNING ("Invalid object location for data_type 0x%x!",
+              *(buf - 1));
+          GST_MEMDUMP ("Remaining data after invalid object location:", buf,
+              buf_end - buf);
           return;               // FIXME: Perhaps tell read_nbit_string that dbuf_len is zero and let it walk the bytes regardless? (Same FIXME for 2bit and 8bit)
         }
 
         if (region->depth < 4) {
-          g_warning ("4-bit pixel string in %d-bit region!\n", region->depth);
+          GST_WARNING ("4-bit pixel string in %d-bit region!", region->depth);
           return;
         }
 
@@ -1109,27 +1014,27 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
         else
           map_table = NULL;
 
-        dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-            "READ_nBIT_STRING (4): String data into position %dx%d; buf before is %p\n",
-            x_pos, y_pos, buf);
+        GST_LOG ("READ_4BIT_STRING: String data into position %dx%d; "
+            "buf before is %p", x_pos, y_pos, buf);
         // FFMPEG-FIXME: ffmpeg code passes buf_size instead of buf_end - buf, and could
         // FFMPEG-FIXME: therefore potentially walk over the memory area we own
         x_pos +=
             _dvb_sub_read_4bit_string (pbuf + (y_pos * region->width) + x_pos,
             region->width - x_pos, &buf, buf_end - buf, non_mod, map_table);
-        dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-            "READ_nBIT_STRING (4) finished: buf pointer now %p", buf);
+        GST_DEBUG ("READ_4BIT_STRING finished: buf pointer now %p", buf);
         break;
       case 0x12:
         if (dest_buf_filled) {
-          g_warning ("Invalid object location for data_type 0x%x!\n", *(buf - 1));      /* FIXME: Be more verbose */
-          g_print ("Remaining data after invalid object location:\n");
-          gst_util_dump_mem (buf, buf_end - buf);
+          /* FIXME: Be more verbose */
+          GST_WARNING ("Invalid object location for data_type 0x%x!",
+              *(buf - 1));
+          GST_MEMDUMP ("Remaining data after invalid object location:",
+              buf, (guint) (buf_end - buf));
           return;
         }
 
         if (region->depth < 8) {
-          g_warning ("8-bit pixel string in %d-bit region!\n", region->depth);
+          GST_WARNING ("8-bit pixel string in %d-bit region!", region->depth);
           return;
         }
         // FFMPEG-FIXME: ffmpeg code passes buf_size instead of buf_end - buf, and could
@@ -1140,8 +1045,7 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
         break;
 
       case 0x20:
-        dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-            "(parse_block): handling map2to4 table data");
+        GST_DEBUG ("handling map2to4 table data");
         /* FIXME: I don't see any guards about buffer size here - buf++ happens with the switch, but
          * FIXME: buffer is walked without length checks? Same deal in other map table cases */
         map2to4[0] = (*buf) >> 4;
@@ -1150,27 +1054,23 @@ _dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub,
         map2to4[3] = (*buf++) & 0xf;
         break;
       case 0x21:
-        dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-            "(parse_block): handling map2to8 table data");
+        GST_DEBUG ("handling map2to8 table data");
         for (i = 0; i < 4; i++)
           map2to8[i] = *buf++;
         break;
       case 0x22:
-        dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-            "(parse_block): handling map4to8 table data");
+        GST_DEBUG ("handling map4to8 table data");
         for (i = 0; i < 16; i++)
           map4to8[i] = *buf++;
         break;
-
       case 0xf0:
-        dvb_log (DVB_LOG_PIXEL, G_LOG_LEVEL_DEBUG,
-            "(parse_block): end of object line code encountered");
+        GST_DEBUG ("end of object line code encountered");
         x_pos = display->x_pos;
         y_pos += 2;
         break;
       default:
         /* FIXME: Do we consume word align stuffing byte that could follow top/bottom data? */
-        g_warning ("Unknown/unsupported pixel block 0x%x", *(buf - 1));
+        GST_WARNING ("Unknown/unsupported pixel block 0x%x", *(buf - 1));
     }
   }
 }
@@ -1190,13 +1090,11 @@ _dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
 
   object = get_object (dvb_sub, object_id);
 
-  dvb_log (DVB_LOG_OBJECT, G_LOG_LEVEL_DEBUG,
-      "parse_object_segment: A new object segment has occurred for object_id = %u",
+  GST_DEBUG ("OBJECT: a new object segment has occurred for object_id = %u",
       object_id);
 
   if (!object) {
-    g_warning
-        ("Nothing known about object with ID %u yet inside parse_object_segment, bailing out",
+    GST_WARNING ("Nothing known about object with ID %u yet, bailing out",
         object_id);
     return;
   }
@@ -1215,7 +1113,7 @@ _dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     buf += 2;
 
     if (buf + top_field_len + bottom_field_len > buf_end) {
-      g_warning ("%s: Field data size too large\n", __PRETTY_FUNCTION__);
+      GST_WARNING ("Field data size too large");
       return;
     }
 
@@ -1225,9 +1123,10 @@ _dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
         display = display->object_list_next) {
       block = buf;
 
-      dvb_log (DVB_LOG_OBJECT, G_LOG_LEVEL_DEBUG,
-          "Parsing top and bottom part of object id %d; top_field_len = %u, bottom_field_len = %u",
+      GST_DEBUG ("OBJECT: parsing top and bottom part of object id %d; "
+          "top_field_len = %u, bottom_field_len = %u",
           display->object_id, top_field_len, bottom_field_len);
+
       _dvb_sub_parse_pixel_data_block (dvb_sub, display, block, top_field_len,
           TOP_FIELD, non_modifying_color);
 
@@ -1241,58 +1140,90 @@ _dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf,
     }
 
   } else if (coding_method == 1) {
-    g_warning ("'a string of characters' coding method not supported (yet?)!");
+    GST_FIXME ("'a string of characters' coding method not supported yet!");
   } else {
-    g_warning ("%s: Unknown object coding 0x%x\n", __PRETTY_FUNCTION__,
-        coding_method);
+    GST_WARNING ("Unknown object coding 0x%x", coding_method);
   }
 }
 
 static gint
-_dvb_sub_parse_end_of_display_set (DvbSub * dvb_sub, guint16 page_id,
-    guint8 * buf, gint buf_size, guint64 pts)
+_dvb_sub_parse_display_definition_segment (DvbSub * dvb_sub, guint8 * buf,
+    gint buf_size)
 {
-  DvbSubPrivate *priv = (DvbSubPrivate *) dvb_sub->private_data;
+  int dds_version, info_byte;
 
-  DVBSubtitles *sub = g_slice_new0 (DVBSubtitles);
+  if (buf_size < 5)
+    return -1;
 
-  DVBSubRegion *region;
+  info_byte = *buf++;
+  dds_version = info_byte >> 4;
+
+  if (dvb_sub->display_def.version == dds_version)
+    return 0;                   /* already have this display definition version */
+
+  dvb_sub->display_def.version = dds_version;
+  dvb_sub->display_def.display_width = GST_READ_UINT16_BE (buf) + 1;
+  buf += 2;
+  dvb_sub->display_def.display_height = GST_READ_UINT16_BE (buf) + 1;
+  buf += 2;
+
+  dvb_sub->display_def.window_flag = info_byte & 1 << 3;
+
+  if (buf_size >= 13 && dvb_sub->display_def.window_flag) {
+    dvb_sub->display_def.window_x = GST_READ_UINT16_BE (buf);
+    buf += 2;
+    dvb_sub->display_def.window_y = GST_READ_UINT16_BE (buf);
+    buf += 2;
+    dvb_sub->display_def.window_width =
+        GST_READ_UINT16_BE (buf) - dvb_sub->display_def.window_x + 1;
+    buf += 2;
+    dvb_sub->display_def.window_height =
+        GST_READ_UINT16_BE (buf) - dvb_sub->display_def.window_y + 1;
+    buf += 2;
+  }
+
+  return 0;
+}
+
+static gint
+_dvb_sub_parse_end_of_display_set (DvbSub * dvb_sub, guint16 page_id,
+    guint8 * buf, gint buf_size, guint64 pts)
+{
   DVBSubRegionDisplay *display;
-  DVBSubtitleRect *rect;
+  DVBSubtitles *sub;
   DVBSubCLUT *clut;
   guint32 *clut_table;
   int i;
 
-  static unsigned counter = 0;  /* DEBUG use only */
+  GST_DEBUG ("DISPLAY SET END: page_id = %u, length = %d", page_id, buf_size);
 
-  dvb_log (DVB_LOG_DISPLAY, G_LOG_LEVEL_DEBUG,
-      "END OF DISPLAY SET: page_id = %u, length = %d\n", page_id, buf_size);
+  sub = g_slice_new0 (DVBSubtitles);
 
-  sub->rects = NULL;
 #if 0                           /* FIXME: PTS stuff not figured out yet */
   sub->start_display_time = 0;
   sub->end_display_time = priv->page_time_out * 1000;
   sub->format = 0;              /* 0 = graphics */
 #endif
 
-  sub->num_rects = priv->display_list_size;
-
-  if (sub->num_rects > 0) {
-    // FIXME-MEMORY-LEAK: This structure is not freed up yet
-    sub->rects = g_malloc0 (sizeof (*sub->rects) * sub->num_rects);     /* GSlice? */
-    for (i = 0; i < sub->num_rects; i++)
-      sub->rects[i] = g_malloc0 (sizeof (*sub->rects[i]));      /* GSlice? */
-  }
+  /* N.B. g_new0() will return NULL if num_rects is 0 */
+  sub->num_rects = dvb_sub->display_list_size;
+  sub->rects = g_new0 (DVBSubtitleRect, sub->num_rects);
 
   i = 0;
 
-  for (display = priv->display_list; display; display = display->next) {
+  /* copy subtitle display and window information */
+  sub->display_def = dvb_sub->display_def;
+
+  for (display = dvb_sub->display_list; display; display = display->next) {
+    DVBSubtitleRect *rect;
+    DVBSubRegion *region;
+
     region = get_region (dvb_sub, display->region_id);
-    rect = sub->rects[i];
 
     if (!region)
       continue;
 
+    rect = &sub->rects[i];
     rect->x = display->x_pos;
     rect->y = display->y_pos;
     rect->w = region->width;
@@ -1329,163 +1260,102 @@ _dvb_sub_parse_end_of_display_set (DvbSub * dvb_sub, guint16 page_id,
     rect->pict.palette = g_malloc ((1 << region->depth) * sizeof (guint32));    /* FIXME: Can we use GSlice here? */
     memcpy (rect->pict.palette, clut_table,
         (1 << region->depth) * sizeof (guint32));
-#if 0
-    g_print ("rect->pict.data.palette content:\n");
-    gst_util_dump_mem (rect->pict.palette,
-        (1 << region->depth) * sizeof (guint32));
-#endif
+
+    GST_MEMDUMP ("rect->pict.data.palette content",
+        (guint8 *) rect->pict.palette, (1 << region->depth) * sizeof (guint32));
 
     rect->pict.data = g_malloc (region->buf_size);      /* FIXME: Can we use GSlice here? */
     memcpy (rect->pict.data, region->pbuf, region->buf_size);
 
-    ++counter;
-    dvb_log (DVB_LOG_DISPLAY, G_LOG_LEVEL_DEBUG,
-        "An object rect created: number %u, iteration %u, pos: %d:%d, size: %dx%d",
-        counter, i, rect->x, rect->y, rect->w, rect->h);
-#if 0
-    g_print ("rect->pict.data content:\n");
-    gst_util_dump_mem (rect->pict.data, region->buf_size);
-#endif
+    GST_DEBUG ("DISPLAY: an object rect created: iteration %u, "
+        "pos: %d:%d, size: %dx%d", i, rect->x, rect->y, rect->w, rect->h);
+
+    GST_MEMDUMP ("rect->pict.data content", rect->pict.data, region->buf_size);
 
     ++i;
   }
 
+  sub->pts = pts;
+  sub->page_time_out = dvb_sub->page_time_out;
   sub->num_rects = i;
 
-  if (priv->callbacks.new_data)
-    priv->callbacks.new_data (dvb_sub, pts, sub, priv->page_time_out,
-        priv->user_data);
+  if (dvb_sub->callbacks.new_data) {
+    dvb_sub->callbacks.new_data (dvb_sub, sub, dvb_sub->user_data);
+  } else {
+    /* No-one responsible to clean up memory, so do it ourselves */
+    /* FIXME: Just don't bother with all this palette image creation in the first place then... */
+    dvb_subtitles_free (sub);
+  }
+
+  return 1;                     /* FIXME: The caller of this function is probably supposed to do something with the return value */
+}
+
+void
+dvb_subtitles_free (DVBSubtitles * sub)
+{
+  int i;
+
+  if (sub == NULL)
+    return;
 
   /* Now free up all the temporary memory we allocated */
   for (i = 0; i < sub->num_rects; ++i) {
-    rect = sub->rects[i];
-
-    g_free (rect->pict.palette);
-    g_free (rect->pict.data);
-    g_free (rect);
+    g_free (sub->rects[i].pict.palette);
+    g_free (sub->rects[i].pict.data);
   }
   g_free (sub->rects);
   g_slice_free (DVBSubtitles, sub);
-
-  return 1;                     /* FIXME: The caller of this function is probably supposed to do something with the return value */
 }
 
-/**
- * dvb_sub_new:
- *
- * Creates a new #DvbSub.
- *
- * Return value: a newly created #DvbSub
- */
 DvbSub *
 dvb_sub_new (void)
 {
-  DvbSub *dvbsub = g_object_new (DVB_TYPE_SUB, NULL);
-
-  return dvbsub;
-}
+  static gsize inited = 0;
+  DvbSub *sub;
 
-/**
- * dvb_sub_feed:
- * @dvb_sub: a #DvbSub
- * @data: The data to feed to the parser
- * @len: Length of the data
- *
- * Feeds the DvbSub parser with new PES packet data to parse.
- * The data given must be a full PES packet, which must
- * include a PTS field in the headers.
- * Only one packet is handled in one call, so the available data
- * should be fed continously until all is consumed.
- *
- * Return value: a negative value on errors, -4 if simply not enough data for the PES packet;
- *               Amount of data consumed (length of handled PES packet on success)
- */
-gint
-dvb_sub_feed (DvbSub * dvb_sub, guint8 * data, gint len)
-{
-  guint64 pts = 0;
-  unsigned int pos = 0;
-  guint16 PES_packet_len;
-  guint8 PES_packet_header_len;
-  gboolean is_subtitle_packet = TRUE;
-  gboolean pts_field_present = FALSE;
-  g_warning ("Feeding %d bytes of data to dvbsub!!!!!!!!!!!!\n", len);
-  if (len == 0)
-    return 0;
-
-  if (len <= 8) {
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_WARNING,
-        "Length %d too small for further processing", len);
-    return -1;
-  }
-
-  if (data[0] != 0x00 || data[1] != 0x00 || data[2] != 0x01) {
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_WARNING,
-        "Data fed to dvb_sub_feed is not a PES packet - does not start with a code_prefix of 0x000001");
-    return 1;                   // FIXME: Probably handle it? - we need to skip PES_packet_len from this elementary stream then and move on
-  }
-
-  if (data[3] != 0xBD) {
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_INFO,
-        "Data fed to dvb_sub_feed is not a PES packet of type private_stream_1, but rather '0x%X', so not a subtitle stream",
-        data[3]);
-    is_subtitle_packet = FALSE;
-  }
-
-  PES_packet_len = (data[4] << 8) | data[5];
-  dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-      "PES packet length is %u", PES_packet_len);
-  pos = 6;
-
-  /* FIXME: If the packet is cut, we could be feeding data more than we actually have here, which breaks everything. Probably need to buffer up and handle it,
-   * FIXME: Or push back in front to the file descriptor buffer (but we are using read, not libc buffered fread, so that idea might not be possible )*/
-  if ((len - 5) < PES_packet_len) {
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_WARNING,
-        "!!!!!!!!!!! claimed PES packet length was %d, but we only had %d bytes available, falling back and waiting more !!!!!!!!!",
-        PES_packet_len, len - 5);
-    return -4;
-  }
-  /* FIXME: Validate sizes inbetween here */
-
-  /* If this is a non-subtitle packet, still skip the data, pretending we consumed it (FIXME: Signal up) */
-  if (!is_subtitle_packet) {
-    return pos + PES_packet_len;
-  }
-
-  pos++;
-
-  if (data[pos++] & 0x80) {     /* PTS fields present (possibly also DTS). Technically this must be present per the spec */
-    pts_field_present = TRUE;
+  if (g_once_init_enter (&inited)) {
+    dvb_sub_init ();
+    g_once_init_leave (&inited, TRUE);
   }
 
-  /* pos should be 8 now anyway */
-  pos = 8;
+  sub = g_slice_new0 (DvbSub);
 
-  PES_packet_header_len = data[pos++];
+  /* TODO: Add initialization code here */
+  /* FIXME: Do we have a reason to initiate the members to zero, or are we guaranteed that anyway? */
+  sub->region_list = NULL;
+  sub->object_list = NULL;
+  sub->page_time_out = 0;       /* FIXME: Maybe 255 instead? */
+  sub->pes_buffer = g_string_new (NULL);
+
+  /* display/window information */
+  sub->display_def.version = -1;
+  sub->display_def.window_flag = 0;
+  sub->display_def.display_width = 720;
+  sub->display_def.display_height = 576;
+
+  return sub;
+}
 
-  if (pts_field_present) {
-    /* '001x', PTS[32..30], marker, PTS[29..15], marker, PTS[14..0], marker */
-    pts = ((guint64) (data[pos] & 0x0E)) << 29; /* PTS[32..30], ignore marker at rightmost bit */
-    pts |= ((guint64) (data[pos + 1])) << 22;   /* PTS[29..22], full byte */
-    pts |= ((guint64) (data[pos + 2] & 0xFE)) << 14;    /* PTS[21..15], ignore marker at rightmost bit */
-    pts |= ((guint64) (data[pos + 3])) << 7;    /* PTS[14.. 7], full byte */
-    pts |= ((guint64) (data[pos + 4] & 0xFE)) >> 1;     /* PTS[ 6.. 0], ignore marker at rightmost bit */
+void
+dvb_sub_free (DvbSub * sub)
+{
+  /* TODO: Add deinitalization code here */
+  /* FIXME: Clear up region_list contents */
+  delete_state (sub);
+  while (sub->display_list) {
+    DVBSubRegionDisplay *tmp = sub->display_list->next;
+    g_slice_free (DVBSubRegionDisplay, sub->display_list);
+    sub->display_list = tmp;
   }
-
-  pos += PES_packet_header_len; /* FIXME: Currently including all header values with all but PTS ignored */
-
-  dvb_sub_feed_with_pts (dvb_sub, pts, data + pos, PES_packet_len - PES_packet_header_len - 3); /* 2 bytes between PES_packet_len and PES_packet_header_len fields, minus header_len itself */
-  pos += PES_packet_len - PES_packet_header_len - 3;
-  dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-      "Finished PES packet - consumed %u bytes of %d", pos, len);
-
-  return pos;
+  g_string_free (sub->pes_buffer, TRUE);
+  g_slice_free (DvbSub, sub);
 }
 
 #define DVB_SUB_SEGMENT_PAGE_COMPOSITION 0x10
 #define DVB_SUB_SEGMENT_REGION_COMPOSITION 0x11
 #define DVB_SUB_SEGMENT_CLUT_DEFINITION 0x12
 #define DVB_SUB_SEGMENT_OBJECT_DATA 0x13
+#define DVB_SUB_SEGMENT_DISPLAY_DEFINITION 0x14
 #define DVB_SUB_SEGMENT_END_OF_DISPLAY_SET 0x80
 #define DVB_SUB_SEGMENT_STUFFING 0xFF
 
@@ -1514,93 +1384,91 @@ dvb_sub_feed_with_pts (DvbSub * dvb_sub, guint64 pts, guint8 * data, gint len)
   guint16 segment_len;
   guint16 page_id;
 
-  dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-      "Inside dvb_sub_feed_with_pts with pts=%" G_GUINT64_FORMAT
-      " and length %d", pts, len);
+  GST_DEBUG ("pts=%" G_GUINT64_FORMAT " and length %d", pts, len);
 
   g_return_val_if_fail (data != NULL, -1);
 
   if (len <= 3) {               /* len(0x20 0x00 end_of_PES_data_field_marker) */
-    g_warning ("Data length too short");
+    GST_WARNING ("Data length too short");
     return -1;
   }
 
   if (data[pos++] != 0x20) {
-    g_warning
-        ("Tried to handle a PES packet private data that isn't a subtitle packet (does not start with 0x20)");
+    GST_WARNING ("Tried to handle a PES packet private data that isn't a "
+        "subtitle packet (does not start with 0x20)");
     return -1;
   }
 
   if (data[pos++] != 0x00) {
-    g_warning
-        ("'Subtitle stream in this PES packet' was not 0x00, so this is in theory not a DVB subtitle stream (but some other subtitle standard?); bailing out");
+    GST_WARNING ("'Subtitle stream in this PES packet' was not 0x00, so this "
+        "is in theory not a DVB subtitle stream (but some other subtitle "
+        "standard?); bailing out");
     return -1;
   }
 
   while (data[pos++] == DVB_SUB_SYNC_BYTE) {
     if ((len - pos) < (2 * 2 + 1)) {
-      g_warning
-          ("Data after SYNC BYTE too short, less than needed to even get to segment_length");
+      GST_WARNING ("Data after SYNC BYTE too short, less than needed to "
+          "even get to segment_length");
       return -2;
     }
     segment_type = data[pos++];
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-        "=== Segment type is 0x%x", segment_type);
+    GST_DEBUG ("=== Segment type is 0x%x", segment_type);
     page_id = (data[pos] << 8) | data[pos + 1];
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG, "page_id is 0x%x", page_id);
+    GST_DEBUG ("page_id is 0x%x", page_id);
     pos += 2;
     segment_len = (data[pos] << 8) | data[pos + 1];
-    dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-        "segment_length is %d (0x%x 0x%x)", segment_len, data[pos],
+    GST_DEBUG ("segment_length is %d (0x%x 0x%x)", segment_len, data[pos],
         data[pos + 1]);
     pos += 2;
     if ((len - pos) < segment_len) {
-      g_warning
-          ("segment_length was told to be %u, but we only have %d bytes left",
-          segment_len, len - pos);
+      GST_WARNING ("segment_length was told to be %u, but we only have "
+          "%d bytes left", segment_len, len - pos);
       return -2;
     }
-    // TODO: Parse the segment per type
+    // TODO: Parse the segment per type  (this is probably a leftover TODO that is now done?)
+    /* FIXME: Handle differing PTS values - all segments of a given display set must be with the same PTS,
+     * FIXME: but we let it slip and just take it for granted in end_of_display_set */
     switch (segment_type) {
       case DVB_SUB_SEGMENT_PAGE_COMPOSITION:
-        dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-            "Page composition segment at buffer pos %u\n", pos);
+        GST_DEBUG ("Page composition segment at buffer pos %u", pos);
         _dvb_sub_parse_page_segment (dvb_sub, page_id, data + pos, segment_len);        /* FIXME: Not sure about args */
         break;
       case DVB_SUB_SEGMENT_REGION_COMPOSITION:
-        dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-            "Region composition segment at buffer pos %u\n", pos);
+        GST_DEBUG ("Region composition segment at buffer pos %u", pos);
         _dvb_sub_parse_region_segment (dvb_sub, page_id, data + pos, segment_len);      /* FIXME: Not sure about args */
         break;
       case DVB_SUB_SEGMENT_CLUT_DEFINITION:
-        dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-            "CLUT definition segment at buffer pos %u\n", pos);
+        GST_DEBUG ("CLUT definition segment at buffer pos %u", pos);
         _dvb_sub_parse_clut_segment (dvb_sub, page_id, data + pos, segment_len);        /* FIXME: Not sure about args */
         break;
       case DVB_SUB_SEGMENT_OBJECT_DATA:
-        dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-            "Object data segment at buffer pos %u\n", pos);
+        GST_DEBUG ("Object data segment at buffer pos %u", pos);
         _dvb_sub_parse_object_segment (dvb_sub, page_id, data + pos, segment_len);      /* FIXME: Not sure about args */
         break;
+      case DVB_SUB_SEGMENT_DISPLAY_DEFINITION:
+        GST_DEBUG ("display definition segment at buffer pos %u", pos);
+        _dvb_sub_parse_display_definition_segment (dvb_sub, data + pos,
+            segment_len);
+        break;
       case DVB_SUB_SEGMENT_END_OF_DISPLAY_SET:
-        dvb_log (DVB_LOG_PACKET, G_LOG_LEVEL_DEBUG,
-            "End of display set at buffer pos %u\n", pos);
+        GST_DEBUG ("End of display set at buffer pos %u", pos);
         _dvb_sub_parse_end_of_display_set (dvb_sub, page_id, data + pos, segment_len, pts);     /* FIXME: Not sure about args */
         break;
       default:
-        g_warning ("Unhandled segment type 0x%x", segment_type);
+        GST_FIXME ("Unhandled segment type 0x%x", segment_type);
         break;
     }
 
     pos += segment_len;
 
     if (pos == len) {
-      g_warning ("Data ended without a PES data end marker");
+      GST_WARNING ("Data ended without a PES data end marker");
       return 1;
     }
   }
 
-  g_warning ("Processed %d bytes out of %d\n", pos, len);
+  GST_LOG ("Processed %d bytes out of %d", pos, len);
   return pos;
 }
 
@@ -1616,25 +1484,9 @@ void
 dvb_sub_set_callbacks (DvbSub * dvb_sub, DvbSubCallbacks * callbacks,
     gpointer user_data)
 {
-  DvbSubPrivate *priv;
-
   g_return_if_fail (dvb_sub != NULL);
-  g_return_if_fail (DVB_IS_SUB (dvb_sub));
   g_return_if_fail (callbacks != NULL);
 
-  priv = (DvbSubPrivate *) dvb_sub->private_data;
-
-  priv->callbacks = *callbacks;
-  priv->user_data = user_data;
-}
-
-void
-dvb_sub_set_global_log_cb (void (*log_cb) (GLogLevelFlags log_level,
-        const gchar * format, va_list args, gpointer user_data),
-    gpointer user_data)
-{
-  if (log_cb) {
-    g_log_callback = log_cb;
-    g_log_callback_user_data = user_data;
-  }
+  dvb_sub->callbacks = *callbacks;
+  dvb_sub->user_data = user_data;
 }