Rewrite Dirac encoder plugin based on Schroedinger gstreamer elements.
authorDavid Schleef <ds@schleef.org>
Thu, 6 Mar 2008 03:16:13 +0000 (03:16 +0000)
committerDavid Schleef <ds@schleef.org>
Thu, 6 Mar 2008 03:16:13 +0000 (03:16 +0000)
Original commit message from CVS:
* configure.ac:
* ext/Makefile.am:
* ext/dirac/Makefile.am:
* ext/dirac/gstdirac.cc:
* ext/dirac/gstdiracenc.cc:
Rewrite Dirac encoder plugin based on Schroedinger gstreamer
elements.

ChangeLog
configure.ac
ext/Makefile.am
ext/dirac/Makefile.am
ext/dirac/gstdirac.cc
ext/dirac/gstdiracenc.cc [new file with mode: 0644]

index 0b33c56..70b017a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-03-05  David Schleef  <ds@schleef.org>
+
+       * configure.ac:
+       * ext/Makefile.am:
+       * ext/dirac/Makefile.am:
+       * ext/dirac/gstdirac.cc:
+       * ext/dirac/gstdiracenc.cc:
+         Rewrite Dirac encoder plugin based on Schroedinger gstreamer
+         elements.
+
 2008-03-05  Sebastian Dröge  <slomo@circular-chaos.org>
 
        Patch by: Mark Nauwelaerts <manauw at skynet dot be>
index a7ac689..66e6e1b 100644 (file)
@@ -373,6 +373,15 @@ AG_GST_CHECK_FEATURE(DIRECTFB, [directfb], dfbvideosink , [
   ])
 ])
 
+dnl **** Dirac ****
+translit(dnm, m, l) AM_CONDITIONAL(USE_DIRAC, true)
+AG_GST_CHECK_FEATURE(DIRAC, [dirac], dirac, [
+  PKG_CHECK_MODULES(DIRAC, dirac >= 0.9, HAVE_DIRAC="yes", [
+    HAVE_DIRAC="no"
+    AC_MSG_RESULT(no)
+  ])
+])
+
 dnl *** DTS ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_DTS, true)
 AG_GST_CHECK_FEATURE(DTS, [dts library], dtsdec, [
@@ -1156,6 +1165,7 @@ ext/alsaspdif/Makefile
 ext/bz2/Makefile
 ext/cdaudio/Makefile
 ext/dc1394/Makefile
+ext/dirac/Makefile
 ext/directfb/Makefile
 ext/divx/Makefile
 ext/dts/Makefile
index af82344..5add82c 100644 (file)
@@ -52,11 +52,11 @@ else
 DC1394_DIR=
 endif
 
-if USE_DIRAC
-DIRAC_DIR=dirac
-else
+if USE_DIRAC
+DIRAC_DIR=dirac
+else
 DIRAC_DIR=
-endif
+endif
 
 if USE_DIRECTFB
 DIRECTFB_DIR=directfb
@@ -343,6 +343,7 @@ DIST_SUBDIRS = \
        bz2 \
        cdaudio \
        dc1394 \
+       dirac \
        directfb \
        faac \
        faad \
index 1a73fb5..e2e326b 100644 (file)
@@ -2,11 +2,12 @@ plugin_LTLIBRARIES = libgstdirac.la
 
 libgstdirac_la_SOURCES = \
        gstdirac.cc \
-       gstdiracdec.cc
+       gstdiracenc.cc
 
-libgstdirac_la_CXXFLAGS = $(GST_CFLAGS) $(DIRAC_CFLAGS)
-libgstdirac_la_LIBADD = $(DIRAC_LIBS) -lz $(LIBM)
+libgstdirac_la_CXXFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(DIRAC_CFLAGS)
+libgstdirac_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(DIRAC_LIBS) -lz $(LIBM)
 libgstdirac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
 noinst_HEADERS = \
        gstdiracdec.h
+
index 6f5dda2..807be93 100644 (file)
 
 #include <gst/gst.h>
 
-#include "gstdiracdec.h"
+GType gst_dirac_dec_get_type (void);
+GType gst_dirac_enc_get_type (void);
+
+GST_DEBUG_CATEGORY (dirac_debug);
+#define GST_CAT_DEFAULT dirac_debug
 
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-#if 0
+  GST_DEBUG_CATEGORY_INIT (dirac_debug, "dirac", 0, "Dirac elements");
+
   if (!gst_element_register (plugin, "diracenc", GST_RANK_NONE,
-          gst_diracenc_get_type ())) {
+          gst_dirac_enc_get_type ())) {
     return FALSE;
   }
-#endif
-
-  if (!gst_element_register (plugin, "diracdec", GST_RANK_PRIMARY,
-          GST_TYPE_DIRACDEC)) {
+#if 0
+  if (!gst_element_register (plugin, "diracdec", GST_RANK_MARGINAL,
+          gst_dirac_dec_get_type ())) {
     return FALSE;
   }
+#endif
 
   return TRUE;
 }
@@ -46,4 +51,5 @@ plugin_init (GstPlugin * plugin)
 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
     GST_VERSION_MINOR,
     "dirac",
-    "Dirac plugin", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)
+    "Dirac plugin", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN)
diff --git a/ext/dirac/gstdiracenc.cc b/ext/dirac/gstdiracenc.cc
new file mode 100644 (file)
index 0000000..5cd3da9
--- /dev/null
@@ -0,0 +1,782 @@
+/* Dirac Encoder
+ * Copyright (C) 2006 David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <string.h>
+#include <libdirac_encoder/dirac_encoder.h>
+#include <math.h>
+
+GST_DEBUG_CATEGORY_EXTERN (dirac_debug);
+#define GST_CAT_DEFAULT dirac_debug
+
+#define GST_TYPE_DIRAC_ENC \
+  (gst_dirac_enc_get_type())
+#define GST_DIRAC_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRAC_ENC,GstDiracEnc))
+#define GST_DIRAC_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRAC_ENC,GstDiracEncClass))
+#define GST_IS_DIRAC_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRAC_ENC))
+#define GST_IS_DIRAC_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRAC_ENC))
+
+typedef struct _GstDiracEnc GstDiracEnc;
+typedef struct _GstDiracEncClass GstDiracEncClass;
+
+struct _GstDiracEnc
+{
+  GstElement element;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  /* parameters */
+  int level;
+
+  /* video properties */
+  int width;
+  int height;
+  int fps_n, fps_d;
+  int par_n, par_d;
+  guint64 duration;
+  guint32 fourcc;
+
+  /* segment properties */
+  GstClockTime segment_start;
+  GstClockTime segment_position;
+
+  /* state */
+  gboolean got_offset;
+  guint64 granulepos_offset;
+  guint64 granulepos_low;
+  guint64 granulepos_hi;
+  gboolean started;
+  gint64 timestamp_offset;
+  int picture_number;
+
+  dirac_encoder_context_t enc_ctx;
+  dirac_encoder_t *encoder;
+  dirac_sourceparams_t *src_params;
+  GstBuffer *buffer;
+};
+
+struct _GstDiracEncClass
+{
+  GstElementClass parent_class;
+};
+
+
+enum
+{
+  LAST_SIGNAL
+};
+
+enum
+{
+  ARG_0
+};
+
+static void gst_dirac_enc_finalize (GObject * object);
+static void gst_dirac_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_dirac_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_dirac_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean gst_dirac_enc_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_dirac_enc_chain (GstPad * pad, GstBuffer * buf);
+static GstFlowReturn gst_dirac_enc_process (GstDiracEnc * dirac_enc,
+    gboolean end_sequence);
+static GstStateChangeReturn gst_dirac_enc_change_state (GstElement * element,
+    GstStateChange transition);
+static const GstQueryType *gst_dirac_enc_get_query_types (GstPad * pad);
+static gboolean gst_dirac_enc_src_query (GstPad * pad, GstQuery * query);
+
+static GstStaticPadTemplate gst_dirac_enc_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, AYUV }"))
+    );
+
+static GstStaticPadTemplate gst_dirac_enc_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/x-dirac")
+    );
+
+GST_BOILERPLATE (GstDiracEnc, gst_dirac_enc, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_dirac_enc_base_init (gpointer g_class)
+{
+  static GstElementDetails dirac_enc_details =
+      GST_ELEMENT_DETAILS ("Dirac Encoder",
+      "Codec/Encoder/Video",
+      "Encode raw YUV video into Dirac stream",
+      "David Schleef <ds@schleef.org>");
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_dirac_enc_src_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_dirac_enc_sink_template));
+
+  gst_element_class_set_details (element_class, &dirac_enc_details);
+}
+
+static void
+gst_dirac_enc_class_init (GstDiracEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  //int i;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_dirac_enc_set_property;
+  gobject_class->get_property = gst_dirac_enc_get_property;
+  gobject_class->finalize = gst_dirac_enc_finalize;
+
+#if 0
+  for (i = 0; i < dirac_encoder_get_n_settings (); i++) {
+    const DiracEncoderSetting *setting;
+
+    setting = dirac_encoder_get_setting_info (i);
+
+    switch (setting->type) {
+      case DIRAC_ENCODER_SETTING_TYPE_BOOLEAN:
+        g_object_class_install_property (gobject_class, i + 1,
+            g_param_spec_boolean (setting->name, setting->name, setting->name,
+                setting->default_value, G_PARAM_READWRITE));
+        break;
+      case DIRAC_ENCODER_SETTING_TYPE_INT:
+        g_object_class_install_property (gobject_class, i + 1,
+            g_param_spec_int (setting->name, setting->name, setting->name,
+                setting->min, setting->max, setting->default_value,
+                G_PARAM_READWRITE));
+        break;
+      case DIRAC_ENCODER_SETTING_TYPE_ENUM:
+        g_object_class_install_property (gobject_class, i + 1,
+            g_param_spec_int (setting->name, setting->name, setting->name,
+                setting->min, setting->max, setting->default_value,
+                G_PARAM_READWRITE));
+        break;
+      case DIRAC_ENCODER_SETTING_TYPE_DOUBLE:
+        g_object_class_install_property (gobject_class, i + 1,
+            g_param_spec_double (setting->name, setting->name, setting->name,
+                setting->min, setting->max, setting->default_value,
+                G_PARAM_READWRITE));
+        break;
+      default:
+        break;
+    }
+  }
+#endif
+
+  gstelement_class->change_state = gst_dirac_enc_change_state;
+}
+
+static void
+gst_dirac_enc_init (GstDiracEnc * dirac_enc, GstDiracEncClass * klass)
+{
+  GST_DEBUG ("gst_dirac_enc_init");
+
+  dirac_enc->src_params = &dirac_enc->enc_ctx.src_params;
+
+  dirac_enc->sinkpad =
+      gst_pad_new_from_static_template (&gst_dirac_enc_sink_template, "sink");
+  gst_pad_set_chain_function (dirac_enc->sinkpad, gst_dirac_enc_chain);
+  gst_pad_set_event_function (dirac_enc->sinkpad, gst_dirac_enc_sink_event);
+  gst_pad_set_setcaps_function (dirac_enc->sinkpad, gst_dirac_enc_sink_setcaps);
+  //gst_pad_set_query_function (dirac_enc->sinkpad, gst_dirac_enc_sink_query);
+  gst_element_add_pad (GST_ELEMENT (dirac_enc), dirac_enc->sinkpad);
+
+  dirac_enc->srcpad =
+      gst_pad_new_from_static_template (&gst_dirac_enc_src_template, "src");
+  gst_pad_set_query_type_function (dirac_enc->srcpad,
+      gst_dirac_enc_get_query_types);
+  gst_pad_set_query_function (dirac_enc->srcpad, gst_dirac_enc_src_query);
+  gst_element_add_pad (GST_ELEMENT (dirac_enc), dirac_enc->srcpad);
+}
+
+static gboolean
+gst_dirac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstStructure *structure;
+  GstDiracEnc *dirac_enc = GST_DIRAC_ENC (gst_pad_get_parent (pad));
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_get_fourcc (structure, "format", &dirac_enc->fourcc);
+  gst_structure_get_int (structure, "width", &dirac_enc->width);
+  gst_structure_get_int (structure, "height", &dirac_enc->height);
+  gst_structure_get_fraction (structure, "framerate", &dirac_enc->fps_n,
+      &dirac_enc->fps_d);
+  dirac_enc->par_n = 1;
+  dirac_enc->par_d = 1;
+  gst_structure_get_fraction (structure, "pixel-aspect-ratio",
+      &dirac_enc->par_n, &dirac_enc->par_d);
+
+  dirac_encoder_context_init (&dirac_enc->enc_ctx, VIDEO_FORMAT_CUSTOM);
+
+  switch (dirac_enc->fourcc) {
+    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+    case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+      dirac_enc->enc_ctx.src_params.chroma = format420;
+      break;
+    case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+    case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+      dirac_enc->enc_ctx.src_params.chroma = format422;
+      break;
+    case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
+      dirac_enc->enc_ctx.src_params.chroma = format444;
+      break;
+    default:
+      g_assert_not_reached ();
+  }
+
+  dirac_enc->enc_ctx.src_params.frame_rate.numerator = dirac_enc->fps_n;
+  dirac_enc->enc_ctx.src_params.frame_rate.denominator = dirac_enc->fps_d;
+
+  dirac_enc->enc_ctx.src_params.width = dirac_enc->width;
+  dirac_enc->enc_ctx.src_params.height = dirac_enc->height;
+#if 0
+  /* FIXME */
+  dirac_enc->enc_ctx.src_params.clean_width = dirac_enc->width;
+  dirac_enc->enc_ctx.src_params.clean_height = dirac_enc->height;
+#endif
+
+#if 0
+  /* FIXME */
+  dirac_enc->enc_ctx.src_params.aspect_ratio_numerator = dirac_enc->par_n;
+  dirac_enc->enc_ctx.src_params.aspect_ratio_denominator = dirac_enc->par_d;
+#endif
+
+#if 0
+  /* FIXME */
+  dirac_video_format_set_std_signal_range (dirac_enc->video_format,
+      DIRAC_SIGNAL_RANGE_8BIT_VIDEO);
+  dirac_video_format_set_std_colour_spec (dirac_enc->video_format,
+      DIRAC_COLOUR_SPEC_HDTV);
+#endif
+
+  dirac_enc->enc_ctx.decode_flag = 0;
+  dirac_enc->enc_ctx.instr_flag = 0;
+
+  dirac_enc->duration = gst_util_uint64_scale_int (GST_SECOND,
+      dirac_enc->fps_d, dirac_enc->fps_n);
+
+  gst_object_unref (GST_OBJECT (dirac_enc));
+
+  return TRUE;
+}
+
+static void
+gst_dirac_enc_finalize (GObject * object)
+{
+  GstDiracEnc *dirac_enc;
+
+  g_return_if_fail (GST_IS_DIRAC_ENC (object));
+  dirac_enc = GST_DIRAC_ENC (object);
+
+  if (dirac_enc->encoder) {
+    /* FIXME */
+    //dirac_encoder_free (dirac_enc->encoder);
+    dirac_enc->encoder = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_dirac_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDiracEnc *src;
+
+  g_return_if_fail (GST_IS_DIRAC_ENC (object));
+  src = GST_DIRAC_ENC (object);
+
+  GST_DEBUG ("gst_dirac_enc_set_property");
+
+#if 0
+  if (prop_id >= 1) {
+    const DiracEncoderSetting *setting;
+
+    setting = dirac_encoder_get_setting_info (prop_id - 1);
+    switch (G_VALUE_TYPE (value)) {
+      case G_TYPE_DOUBLE:
+        dirac_encoder_setting_set_double (src->encoder, setting->name,
+            g_value_get_double (value));
+        break;
+      case G_TYPE_INT:
+        dirac_encoder_setting_set_double (src->encoder, setting->name,
+            g_value_get_int (value));
+        break;
+      case G_TYPE_BOOLEAN:
+        dirac_encoder_setting_set_double (src->encoder, setting->name,
+            g_value_get_boolean (value));
+        break;
+    }
+  }
+#endif
+}
+
+static void
+gst_dirac_enc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstDiracEnc *src;
+
+  g_return_if_fail (GST_IS_DIRAC_ENC (object));
+  src = GST_DIRAC_ENC (object);
+
+#if 0
+  if (prop_id >= 1) {
+    const DiracEncoderSetting *setting;
+
+    setting = dirac_encoder_get_setting_info (prop_id - 1);
+    switch (G_VALUE_TYPE (value)) {
+      case G_TYPE_DOUBLE:
+        g_value_set_double (value,
+            dirac_encoder_setting_get_double (src->encoder, setting->name));
+        break;
+      case G_TYPE_INT:
+        g_value_set_int (value,
+            dirac_encoder_setting_get_double (src->encoder, setting->name));
+        break;
+      case G_TYPE_BOOLEAN:
+        g_value_set_boolean (value,
+            dirac_encoder_setting_get_double (src->encoder, setting->name));
+        break;
+    }
+  }
+#endif
+}
+
+static gboolean
+gst_dirac_enc_sink_event (GstPad * pad, GstEvent * event)
+{
+  GstDiracEnc *dirac_enc;
+  gboolean ret;
+
+  dirac_enc = GST_DIRAC_ENC (GST_PAD_PARENT (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      gst_dirac_enc_process (dirac_enc, TRUE);
+      ret = gst_pad_push_event (dirac_enc->srcpad, event);
+      break;
+    case GST_EVENT_NEWSEGMENT:
+    {
+      gboolean update;
+      double rate;
+      double applied_rate;
+      GstFormat format;
+      gint64 start;
+      gint64 stop;
+      gint64 position;
+
+      gst_event_parse_new_segment_full (event, &update, &rate,
+          &applied_rate, &format, &start, &stop, &position);
+
+      GST_DEBUG ("new segment %lld %lld", start, position);
+      dirac_enc->segment_start = start;
+      dirac_enc->segment_position = position;
+
+      ret = gst_pad_push_event (dirac_enc->srcpad, event);
+    }
+      break;
+    default:
+      ret = gst_pad_push_event (dirac_enc->srcpad, event);
+      break;
+  }
+
+  return ret;
+}
+
+#define OGG_DIRAC_GRANULE_SHIFT 30
+#define OGG_DIRAC_GRANULE_LOW_MASK ((1ULL<<OGG_DIRAC_GRANULE_SHIFT)-1)
+
+static gint64
+granulepos_to_frame (gint64 granulepos)
+{
+  if (granulepos == -1)
+    return -1;
+
+  return (granulepos >> OGG_DIRAC_GRANULE_SHIFT) +
+      (granulepos & OGG_DIRAC_GRANULE_LOW_MASK);
+}
+
+static const GstQueryType *
+gst_dirac_enc_get_query_types (GstPad * pad)
+{
+  static const GstQueryType query_types[] = {
+    //GST_QUERY_POSITION,
+    //GST_QUERY_DURATION,
+    GST_QUERY_CONVERT
+        /* FIXME */
+        //0
+  };
+
+  return query_types;
+}
+
+#if 0
+static gboolean
+gst_dirac_enc_sink_convert (GstPad * pad,
+    GstFormat src_format, gint64 src_value,
+    GstFormat * dest_format, gint64 * dest_value)
+{
+  gboolean res = TRUE;
+  GstDiracEnc *enc;
+
+  if (src_format == *dest_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  enc = GST_DIRAC_ENC (gst_pad_get_parent (pad));
+
+  /* FIXME: check if we are in a decoding state */
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:
+      switch (*dest_format) {
+#if 0
+        case GST_FORMAT_DEFAULT:
+          *dest_value = gst_util_uint64_scale_int (src_value, 1,
+              enc->bytes_per_picture);
+          break;
+#endif
+        case GST_FORMAT_TIME:
+          /* seems like a rather silly conversion, implement me if you like */
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          *dest_value = gst_util_uint64_scale (src_value,
+              GST_SECOND * enc->fps_d, enc->fps_n);
+          break;
+#if 0
+        case GST_FORMAT_BYTES:
+          *dest_value = gst_util_uint64_scale_int (src_value,
+              enc->bytes_per_picture, 1);
+          break;
+#endif
+        default:
+          res = FALSE;
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+}
+#endif
+
+static gboolean
+gst_dirac_enc_src_convert (GstPad * pad,
+    GstFormat src_format, gint64 src_value,
+    GstFormat * dest_format, gint64 * dest_value)
+{
+  gboolean res = TRUE;
+  GstDiracEnc *enc;
+
+  if (src_format == *dest_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  enc = GST_DIRAC_ENC (gst_pad_get_parent (pad));
+
+  /* FIXME: check if we are in a encoding state */
+
+  switch (src_format) {
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_TIME:
+          *dest_value = gst_util_uint64_scale (granulepos_to_frame (src_value),
+              enc->fps_d * GST_SECOND, enc->fps_n);
+          break;
+        default:
+          res = FALSE;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_DEFAULT:
+        {
+          *dest_value = gst_util_uint64_scale (src_value,
+              enc->fps_n, enc->fps_d * GST_SECOND);
+          break;
+        }
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+
+  gst_object_unref (enc);
+
+  return res;
+}
+
+static gboolean
+gst_dirac_enc_src_query (GstPad * pad, GstQuery * query)
+{
+  GstDiracEnc *enc;
+  gboolean res;
+
+  enc = GST_DIRAC_ENC (gst_pad_get_parent (pad));
+
+  switch GST_QUERY_TYPE
+    (query) {
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      res = gst_dirac_enc_src_convert (pad, src_fmt, src_val, &dest_fmt,
+          &dest_val);
+      if (!res)
+        goto error;
+      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, query);
+    }
+  gst_object_unref (enc);
+  return res;
+error:
+  GST_DEBUG_OBJECT (enc, "query failed");
+  gst_object_unref (enc);
+  return res;
+}
+
+static gboolean
+gst_pad_is_negotiated (GstPad * pad)
+{
+  GstCaps *caps;
+
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  caps = gst_pad_get_negotiated_caps (pad);
+  if (caps) {
+    gst_caps_unref (caps);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_dirac_enc_chain (GstPad * pad, GstBuffer * buf)
+{
+  GstDiracEnc *dirac_enc;
+  GstFlowReturn ret;
+
+  dirac_enc = GST_DIRAC_ENC (gst_pad_get_parent (pad));
+
+  if (!gst_pad_is_negotiated (pad)) {
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+  if (GST_BUFFER_TIMESTAMP (buf) < dirac_enc->segment_start) {
+    GST_DEBUG ("dropping early buffer");
+    return GST_FLOW_OK;
+  }
+  if (!dirac_enc->got_offset) {
+    dirac_enc->granulepos_offset =
+        gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buf), dirac_enc->fps_n,
+        GST_SECOND * dirac_enc->fps_d);
+
+    GST_DEBUG ("using granulepos offset %lld", dirac_enc->granulepos_offset);
+    dirac_enc->granulepos_hi = 0;
+    dirac_enc->got_offset = TRUE;
+
+    dirac_enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buf);
+    dirac_enc->picture_number = 0;
+  }
+  if (!dirac_enc->started) {
+    dirac_enc->encoder = dirac_encoder_init (&dirac_enc->enc_ctx, FALSE);
+    dirac_enc->started = TRUE;
+  }
+
+  dirac_encoder_load (dirac_enc->encoder, GST_BUFFER_DATA (buf),
+      GST_BUFFER_SIZE (buf));
+
+  ret = gst_dirac_enc_process (dirac_enc, FALSE);
+
+  gst_object_unref (dirac_enc);
+
+  return ret;
+}
+
+#define SCHRO_PARSE_CODE_IS_SEQ_HEADER(x) ((x) == 0x00)
+#define SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(x) ((x) == 0x10)
+#define SCHRO_PARSE_CODE_IS_PICTURE(x) ((x) & 0x8)
+#define SCHRO_PARSE_CODE_NUM_REFS(x) ((x) & 0x3)
+#define SCHRO_PARSE_CODE_IS_INTRA(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) == 0)
+
+static GstFlowReturn
+gst_dirac_enc_process (GstDiracEnc * dirac_enc, gboolean end_sequence)
+{
+  GstBuffer *outbuf;
+  GstFlowReturn ret;
+  int presentation_frame;
+  int parse_code;
+  int state;
+
+  do {
+    outbuf = gst_buffer_new_and_alloc (32 * 1024 * 1024);
+    dirac_enc->encoder->enc_buf.buffer = GST_BUFFER_DATA (outbuf);
+    dirac_enc->encoder->enc_buf.size = GST_BUFFER_SIZE (outbuf);
+
+    if (end_sequence) {
+      /* FIXME this is a hack to make the code simpler. */
+      dirac_encoder_end_sequence (dirac_enc->encoder);
+      state = ENC_STATE_AVAIL;
+    } else {
+      state = dirac_encoder_output (dirac_enc->encoder);
+    }
+
+    switch (state) {
+      case ENC_STATE_BUFFER:
+        break;
+      case ENC_STATE_INVALID:
+        GST_ERROR ("Dirac returned ENC_STATE_INVALID");
+        gst_buffer_unref (outbuf);
+        return GST_FLOW_ERROR;
+      case ENC_STATE_AVAIL:
+        parse_code = ((guint8 *) GST_BUFFER_DATA (outbuf))[4];
+        /* FIXME */
+        presentation_frame = 0;
+
+        if (SCHRO_PARSE_CODE_IS_SEQ_HEADER (parse_code)) {
+          dirac_enc->granulepos_hi = dirac_enc->granulepos_offset +
+              presentation_frame + 1;
+        }
+
+        dirac_enc->granulepos_low = dirac_enc->granulepos_offset +
+            presentation_frame + 1 - dirac_enc->granulepos_hi;
+
+        gst_buffer_set_caps (outbuf,
+            gst_caps_new_simple ("video/x-dirac",
+                "width", G_TYPE_INT, dirac_enc->width,
+                "height", G_TYPE_INT, dirac_enc->height,
+                "framerate", GST_TYPE_FRACTION, dirac_enc->fps_n,
+                dirac_enc->fps_d, NULL));
+
+        GST_BUFFER_SIZE (outbuf) = dirac_enc->encoder->enc_buf.size;
+        if (SCHRO_PARSE_CODE_IS_PICTURE (parse_code)) {
+          GST_BUFFER_OFFSET_END (outbuf) =
+              (dirac_enc->granulepos_hi << OGG_DIRAC_GRANULE_SHIFT) +
+              dirac_enc->granulepos_low;
+          GST_BUFFER_OFFSET (outbuf) = gst_util_uint64_scale (
+              (dirac_enc->granulepos_hi + dirac_enc->granulepos_low),
+              dirac_enc->fps_d * GST_SECOND, dirac_enc->fps_n);
+          GST_BUFFER_DURATION (outbuf) = dirac_enc->duration;
+          GST_BUFFER_TIMESTAMP (outbuf) =
+              dirac_enc->timestamp_offset +
+              gst_util_uint64_scale (dirac_enc->picture_number,
+              dirac_enc->fps_d * GST_SECOND, dirac_enc->fps_n);
+          dirac_enc->picture_number++;
+          if (!SCHRO_PARSE_CODE_IS_INTRA (parse_code)) {
+            GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+          }
+        } else {
+          GST_BUFFER_OFFSET_END (outbuf) = 0;
+          GST_BUFFER_OFFSET (outbuf) = 0;
+          GST_BUFFER_DURATION (outbuf) = -1;
+          //GST_BUFFER_TIMESTAMP (outbuf) = -1;
+          GST_BUFFER_TIMESTAMP (outbuf) =
+              dirac_enc->timestamp_offset +
+              gst_util_uint64_scale (dirac_enc->picture_number,
+              dirac_enc->fps_d * GST_SECOND, dirac_enc->fps_n);
+        }
+
+        GST_INFO
+            ("size %d offset %lld granulepos %llu:%llu timestamp %lld duration %lld",
+            GST_BUFFER_SIZE (outbuf), GST_BUFFER_OFFSET (outbuf),
+            GST_BUFFER_OFFSET_END (outbuf) >> OGG_DIRAC_GRANULE_SHIFT,
+            GST_BUFFER_OFFSET_END (outbuf) & OGG_DIRAC_GRANULE_LOW_MASK,
+            GST_BUFFER_TIMESTAMP (outbuf), GST_BUFFER_DURATION (outbuf));
+
+        ret = gst_pad_push (dirac_enc->srcpad, outbuf);
+
+        if (ret != GST_FLOW_OK) {
+          GST_DEBUG ("pad_push returned %d", ret);
+          return ret;
+        }
+        break;
+      default:
+        GST_ERROR ("Dirac returned state==%d", state);
+        gst_buffer_unref (outbuf);
+        return GST_FLOW_ERROR;
+    }
+    if (end_sequence) {
+      /* FIXME more hackage */
+      return GST_FLOW_OK;
+    }
+  } while (state == ENC_STATE_AVAIL);
+
+  gst_buffer_unref (outbuf);
+  return GST_FLOW_OK;
+}
+
+static GstStateChangeReturn
+gst_dirac_enc_change_state (GstElement * element, GstStateChange transition)
+{
+  GstDiracEnc *dirac_enc;
+  GstStateChangeReturn ret;
+
+  dirac_enc = GST_DIRAC_ENC (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = parent_class->change_state (element, transition);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  return ret;
+}