openjpeg: Add JPEG2000 encoder element
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 14 Dec 2012 20:08:27 +0000 (20:08 +0000)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Sun, 16 Dec 2012 19:50:34 +0000 (20:50 +0100)
ext/openjpeg/gstopenjpeg.c
ext/openjpeg/gstopenjpegenc.c
ext/openjpeg/gstopenjpegenc.h

index 8e699e0..04a970b 100644 (file)
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  if (!gst_element_register (plugin, "openjpegdec", GST_RANK_MARGINAL,
+  if (!gst_element_register (plugin, "openjpegdec", GST_RANK_PRIMARY,
           GST_TYPE_OPENJPEG_DEC))
     return FALSE;
-#if 0
-  if (!gst_element_register (plugin, "openjpegenc", GST_RANK_MARGINAL,
+  if (!gst_element_register (plugin, "openjpegenc", GST_RANK_PRIMARY,
           GST_TYPE_OPENJPEG_ENC))
     return FALSE;
-#endif
 
   return TRUE;
 }
index e69de29..b17cfbf 100644 (file)
@@ -0,0 +1,626 @@
+/* 
+ * Copyright (C) 2012 Collabora Ltd.
+ *     Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstopenjpegenc.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_openjpeg_enc_debug);
+#define GST_CAT_DEFAULT gst_openjpeg_enc_debug
+
+enum
+{
+  PROP_0,
+};
+
+static void gst_openjpeg_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_openjpeg_enc_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_openjpeg_enc_start (GstVideoEncoder * encoder);
+static gboolean gst_openjpeg_enc_stop (GstVideoEncoder * encoder);
+static gboolean gst_openjpeg_enc_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state);
+static gboolean gst_openjpeg_enc_reset (GstVideoEncoder * encoder,
+    gboolean hard);
+static GstFlowReturn gst_openjpeg_enc_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame);
+static gboolean gst_openjpeg_enc_propose_allocation (GstVideoEncoder * encoder,
+    GstQuery * query);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GRAY16 "GRAY16_LE"
+#define YUV10 "Y444_10LE, I422_10LE, I420_10LE"
+#else
+#define GRAY16 "GRAY16_BE"
+#define YUV10 "Y444_10BE, I422_10BE, I420_10BE"
+#endif
+
+static GstStaticPadTemplate gst_openjpeg_enc_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ ARGB64, ARGB, xRGB, "
+            "AYUV64, " YUV10 ", "
+            "AYUV, Y444, Y42B, I420, Y41B, YUV9, " "GRAY8, " GRAY16 " }"))
+    );
+
+static GstStaticPadTemplate gst_openjpeg_enc_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("image/x-j2c; image/x-jpc; image/jp2")
+    );
+
+#define parent_class gst_openjpeg_enc_parent_class
+G_DEFINE_TYPE (GstOpenJPEGEnc, gst_openjpeg_enc, GST_TYPE_VIDEO_ENCODER);
+
+static void
+gst_openjpeg_enc_class_init (GstOpenJPEGEncClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstVideoEncoderClass *video_encoder_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = (GstElementClass *) klass;
+  video_encoder_class = (GstVideoEncoderClass *) klass;
+
+  gobject_class->set_property = gst_openjpeg_enc_set_property;
+  gobject_class->get_property = gst_openjpeg_enc_get_property;
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_openjpeg_enc_src_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_openjpeg_enc_sink_template));
+
+  gst_element_class_set_static_metadata (element_class,
+      "OpenJPEG JPEG2000 encoder",
+      "Codec/Encoder/Video",
+      "Encode JPEG2000 streams",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_openjpeg_enc_start);
+  video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_openjpeg_enc_stop);
+  video_encoder_class->reset = GST_DEBUG_FUNCPTR (gst_openjpeg_enc_reset);
+  video_encoder_class->set_format =
+      GST_DEBUG_FUNCPTR (gst_openjpeg_enc_set_format);
+  video_encoder_class->handle_frame =
+      GST_DEBUG_FUNCPTR (gst_openjpeg_enc_handle_frame);
+  video_encoder_class->propose_allocation = gst_openjpeg_enc_propose_allocation;
+
+  GST_DEBUG_CATEGORY_INIT (gst_openjpeg_enc_debug, "openjpegenc", 0,
+      "VP8 Encoder");
+}
+
+static void
+gst_openjpeg_enc_init (GstOpenJPEGEnc * self)
+{
+  opj_set_default_encoder_parameters (&self->params);
+
+  /* TODO: Add properties for these */
+  self->params.cp_fixed_quality = 1;
+  self->params.tcp_numlayers = 1;
+}
+
+static void
+gst_openjpeg_enc_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  /* GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_openjpeg_enc_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  /* GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_openjpeg_enc_start (GstVideoEncoder * encoder)
+{
+  GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
+
+  GST_DEBUG_OBJECT (self, "Starting");
+
+  return TRUE;
+}
+
+static gboolean
+gst_openjpeg_enc_stop (GstVideoEncoder * video_encoder)
+{
+  GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (video_encoder);
+
+  GST_DEBUG_OBJECT (self, "Stopping");
+
+  if (self->output_state) {
+    gst_video_codec_state_unref (self->output_state);
+    self->output_state = NULL;
+  }
+
+  if (self->input_state) {
+    gst_video_codec_state_unref (self->input_state);
+    self->input_state = NULL;
+  }
+
+  GST_DEBUG_OBJECT (self, "Stopped");
+
+  return TRUE;
+}
+
+static void
+fill_image_packed16_4 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint x, y, w, h;
+  guint16 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  sindex = 0;
+
+  for (y = 0; y < h; y++) {
+    for (x = 0; x < w; x++, sindex++) {
+      image->comps[3].data[sindex] = data[x * 4 + 0];
+      image->comps[0].data[sindex] = data[x * 4 + 1];
+      image->comps[1].data[sindex] = data[x * 4 + 2];
+      image->comps[2].data[sindex] = data[x * 4 + 3];
+    }
+    data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2;
+  }
+}
+
+static void
+fill_image_packed8_4 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint x, y, w, h;
+  guint8 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  sindex = 0;
+
+  for (y = 0; y < h; y++) {
+    for (x = 0; x < w; x++, sindex++) {
+      image->comps[3].data[sindex] = data[x * 4 + 0];
+      image->comps[0].data[sindex] = data[x * 4 + 1];
+      image->comps[1].data[sindex] = data[x * 4 + 2];
+      image->comps[2].data[sindex] = data[x * 4 + 3];
+    }
+    data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+  }
+}
+
+static void
+fill_image_packed8_3 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint x, y, w, h;
+  guint8 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  sindex = 0;
+
+  for (y = 0; y < h; y++) {
+    for (x = 0; x < w; x++, sindex++) {
+      image->comps[0].data[sindex] = data[x * 4 + 1];
+      image->comps[1].data[sindex] = data[x * 4 + 2];
+      image->comps[2].data[sindex] = data[x * 4 + 3];
+    }
+    data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+  }
+}
+
+static void
+fill_image_planar16_3 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint c, x, y, w, h;
+  guint16 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  for (c = 0; c < 3; c++) {
+    w = GST_VIDEO_FRAME_COMP_WIDTH (frame, c);
+    h = GST_VIDEO_FRAME_COMP_HEIGHT (frame, c);
+    data = (guint16 *) GST_VIDEO_FRAME_COMP_DATA (frame, c);
+
+    sindex = 0;
+    for (y = 0; y < h; y++) {
+      for (x = 0; x < w; x++, sindex++) {
+        image->comps[c].data[sindex] = data[x];
+      }
+      data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, c) / 2;
+    }
+  }
+}
+
+static void
+fill_image_planar8_3 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint c, x, y, w, h;
+  guint8 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  for (c = 0; c < 3; c++) {
+    w = GST_VIDEO_FRAME_COMP_WIDTH (frame, c);
+    h = GST_VIDEO_FRAME_COMP_HEIGHT (frame, c);
+    data = GST_VIDEO_FRAME_COMP_DATA (frame, c);
+
+    sindex = 0;
+    for (y = 0; y < h; y++) {
+      for (x = 0; x < w; x++, sindex++) {
+        image->comps[c].data[sindex] = data[x];
+      }
+      data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, c);
+    }
+  }
+}
+
+static void
+fill_image_planar8_1 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint x, y, w, h;
+  guint8 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  sindex = 0;
+
+  for (y = 0; y < h; y++) {
+    for (x = 0; x < w; x++, sindex++) {
+      image->comps[0].data[sindex] = data[x];
+    }
+    data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+  }
+}
+
+static void
+fill_image_planar16_1 (opj_image_t * image, GstVideoFrame * frame)
+{
+  gint x, y, w, h;
+  guint16 *data;
+  gint sindex;
+
+  w = GST_VIDEO_FRAME_WIDTH (frame);
+  h = GST_VIDEO_FRAME_HEIGHT (frame);
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+
+  sindex = 0;
+
+  for (y = 0; y < h; y++) {
+    for (x = 0; x < w; x++, sindex++) {
+      image->comps[0].data[sindex] = data[x];
+    }
+    data += GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2;
+  }
+}
+
+static gboolean
+gst_openjpeg_enc_set_format (GstVideoEncoder * encoder,
+    GstVideoCodecState * state)
+{
+  GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
+  GstCaps *allowed_caps, *caps;
+  GstStructure *s;
+
+  GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
+
+  if (self->input_state)
+    gst_video_codec_state_unref (self->input_state);
+  self->input_state = gst_video_codec_state_ref (state);
+
+  allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
+  allowed_caps = gst_caps_truncate (allowed_caps);
+  s = gst_caps_get_structure (allowed_caps, 0);
+  if (gst_structure_has_name (s, "image/jp2")) {
+    self->codec_format = CODEC_JP2;
+    self->is_jp2c = FALSE;
+  } else if (gst_structure_has_name (s, "image/x-j2c")) {
+    self->codec_format = CODEC_J2K;
+    self->is_jp2c = TRUE;
+  } else if (gst_structure_has_name (s, "image/x-jpc")) {
+    self->codec_format = CODEC_J2K;
+    self->is_jp2c = FALSE;
+  } else {
+    g_return_val_if_reached (FALSE);
+  }
+
+  switch (state->info.finfo->format) {
+    case GST_VIDEO_FORMAT_ARGB64:
+      self->fill_image = fill_image_packed16_4;
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+      self->fill_image = fill_image_packed8_4;
+      break;
+    case GST_VIDEO_FORMAT_xRGB:
+      self->fill_image = fill_image_packed8_3;
+      break;
+    case GST_VIDEO_FORMAT_AYUV64:
+      self->fill_image = fill_image_packed16_4;
+      break;
+    case GST_VIDEO_FORMAT_Y444_10LE:
+    case GST_VIDEO_FORMAT_Y444_10BE:
+    case GST_VIDEO_FORMAT_I422_10LE:
+    case GST_VIDEO_FORMAT_I422_10BE:
+    case GST_VIDEO_FORMAT_I420_10LE:
+    case GST_VIDEO_FORMAT_I420_10BE:
+      self->fill_image = fill_image_planar16_3;
+      break;
+    case GST_VIDEO_FORMAT_AYUV:
+      self->fill_image = fill_image_packed8_3;
+      break;
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_Y41B:
+    case GST_VIDEO_FORMAT_YUV9:
+      self->fill_image = fill_image_planar8_3;
+      break;
+    case GST_VIDEO_FORMAT_GRAY8:
+      self->fill_image = fill_image_planar8_1;
+      break;
+    case GST_VIDEO_FORMAT_GRAY16_LE:
+    case GST_VIDEO_FORMAT_GRAY16_BE:
+      self->fill_image = fill_image_planar16_1;
+      break;
+    default:
+      g_assert_not_reached ();
+  }
+
+  caps = gst_caps_new_empty_simple (gst_structure_get_name (s));
+  gst_caps_unref (allowed_caps);
+
+  if (self->output_state)
+    gst_video_codec_state_unref (self->output_state);
+  self->output_state =
+      gst_video_encoder_set_output_state (encoder, caps, state);
+
+  gst_video_encoder_negotiate (GST_VIDEO_ENCODER (encoder));
+
+  return TRUE;
+}
+
+static gboolean
+gst_openjpeg_enc_reset (GstVideoEncoder * encoder, gboolean hard)
+{
+  GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
+
+  GST_DEBUG_OBJECT (self, "Resetting");
+
+  if (self->output_state) {
+    gst_video_codec_state_unref (self->output_state);
+    self->output_state = NULL;
+  }
+
+  return TRUE;
+}
+
+static opj_image_t *
+gst_openjpeg_enc_fill_image (GstOpenJPEGEnc * self, GstVideoFrame * frame)
+{
+  gint i, ncomps;
+  opj_image_cmptparm_t *comps;
+  OPJ_COLOR_SPACE colorspace;
+  opj_image_t *image;
+
+  ncomps = GST_VIDEO_FRAME_N_COMPONENTS (frame);
+  comps = g_new0 (opj_image_cmptparm_t, ncomps);
+
+  for (i = 0; i < ncomps; i++) {
+    comps[i].prec = GST_VIDEO_FRAME_COMP_DEPTH (frame, i);
+    comps[i].bpp = GST_VIDEO_FRAME_COMP_DEPTH (frame, i);
+    comps[i].sgnd = 0;
+    comps[i].w = GST_VIDEO_FRAME_COMP_WIDTH (frame, i);
+    comps[i].h = GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
+    comps[i].dx =
+        GST_VIDEO_FRAME_WIDTH (frame) / GST_VIDEO_FRAME_COMP_WIDTH (frame, i);
+    comps[i].dy =
+        GST_VIDEO_FRAME_HEIGHT (frame) / GST_VIDEO_FRAME_COMP_HEIGHT (frame, i);
+  }
+
+  if ((frame->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_YUV))
+    colorspace = CLRSPC_SYCC;
+  else if ((frame->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB))
+    colorspace = CLRSPC_SRGB;
+  else if ((frame->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_GRAY))
+    colorspace = CLRSPC_GRAY;
+  else
+    g_return_val_if_reached (NULL);
+
+  image = opj_image_create (ncomps, comps, colorspace);
+  g_free (comps);
+
+  image->x0 = image->y0 = 0;
+  image->x1 = GST_VIDEO_FRAME_WIDTH (frame);
+  image->y1 = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  self->fill_image (image, frame);
+
+  return image;
+}
+
+static GstFlowReturn
+gst_openjpeg_enc_handle_frame (GstVideoEncoder * encoder,
+    GstVideoCodecFrame * frame)
+{
+  GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder);
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstMapInfo map;
+  opj_cinfo_t *enc;
+  opj_cio_t *io;
+  opj_image_t *image;
+  GstVideoFrame vframe;
+  gint length;
+
+  GST_DEBUG_OBJECT (self, "Handling frame");
+
+  enc = opj_create_compress (self->codec_format);
+  if (!enc)
+    goto initialization_error;
+
+  opj_set_event_mgr ((opj_common_ptr) enc, NULL, NULL);
+
+  if (!gst_video_frame_map (&vframe, &self->input_state->info,
+          frame->input_buffer, GST_MAP_READ))
+    goto map_read_error;
+
+  image = gst_openjpeg_enc_fill_image (self, &vframe);
+  if (!image)
+    goto fill_image_error;
+  gst_video_frame_unmap (&vframe);
+
+  opj_setup_encoder (enc, &self->params, image);
+
+  io = opj_cio_open ((opj_common_ptr) enc, NULL, 0);
+  if (!io)
+    goto open_error;
+
+  if (!opj_encode (enc, io, image, NULL))
+    goto encode_error;
+
+  opj_image_destroy (image);
+
+  length = cio_tell (io);
+
+  ret =
+      gst_video_encoder_allocate_output_frame (encoder, frame,
+      length + (self->is_jp2c ? 8 : 0));
+  if (ret != GST_FLOW_OK)
+    goto allocate_error;
+
+  gst_buffer_fill (frame->output_buffer, self->is_jp2c ? 8 : 0, io->buffer,
+      length);
+  if (self->is_jp2c) {
+    gst_buffer_map (frame->output_buffer, &map, GST_MAP_WRITE);
+    GST_WRITE_UINT32_BE (map.data, length + 8);
+    GST_WRITE_UINT32_BE (map.data + 4, GST_MAKE_FOURCC ('j', 'p', '2', 'c'));
+    gst_buffer_unmap (frame->output_buffer, &map);
+  }
+
+  opj_cio_close (io);
+  opj_destroy_compress (enc);
+
+  ret = gst_video_encoder_finish_frame (encoder, frame);
+
+  return ret;
+
+initialization_error:
+  {
+    gst_video_codec_frame_unref (frame);
+    GST_ELEMENT_ERROR (self, LIBRARY, INIT,
+        ("Failed to initialize OpenJPEG encoder"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+map_read_error:
+  {
+    opj_destroy_compress (enc);
+    gst_video_codec_frame_unref (frame);
+
+    GST_ELEMENT_ERROR (self, CORE, FAILED,
+        ("Failed to map input buffer"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+fill_image_error:
+  {
+    opj_destroy_compress (enc);
+    gst_video_frame_unmap (&vframe);
+    gst_video_codec_frame_unref (frame);
+
+    GST_ELEMENT_ERROR (self, LIBRARY, INIT,
+        ("Failed to fill OpenJPEG image"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+open_error:
+  {
+    opj_image_destroy (image);
+    opj_destroy_compress (enc);
+    gst_video_codec_frame_unref (frame);
+
+    GST_ELEMENT_ERROR (self, LIBRARY, INIT,
+        ("Failed to open OpenJPEG data"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+encode_error:
+  {
+    opj_cio_close (io);
+    opj_image_destroy (image);
+    opj_destroy_compress (enc);
+    gst_video_codec_frame_unref (frame);
+
+    GST_ELEMENT_ERROR (self, STREAM, ENCODE,
+        ("Failed to encode OpenJPEG stream"), (NULL));
+    return GST_FLOW_ERROR;
+  }
+allocate_error:
+  {
+    opj_cio_close (io);
+    opj_destroy_compress (enc);
+    gst_video_codec_frame_unref (frame);
+
+    GST_ELEMENT_ERROR (self, CORE, FAILED,
+        ("Failed to allocate output buffer"), (NULL));
+    return ret;
+  }
+}
+
+static gboolean
+gst_openjpeg_enc_propose_allocation (GstVideoEncoder * encoder,
+    GstQuery * query)
+{
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+
+  return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
+      query);
+}
index e69de29..d1274b0 100644 (file)
@@ -0,0 +1,71 @@
+/* 
+ * Copyright (C) 2012 Collabora Ltd.
+ *     Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __GST_OPENJPEG_ENC_H__
+#define __GST_OPENJPEG_ENC_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <openjpeg.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_OPENJPEG_ENC \
+  (gst_openjpeg_enc_get_type())
+#define GST_OPENJPEG_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPENJPEG_ENC,GstOpenJPEGEnc))
+#define GST_OPENJPEG_ENC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPENJPEG_ENC,GstOpenJPEGEncClass))
+#define GST_IS_OPENJPEG_ENC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPENJPEG_ENC))
+#define GST_IS_OPENJPEG_ENC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPENJPEG_ENC))
+
+typedef struct _GstOpenJPEGEnc GstOpenJPEGEnc;
+typedef struct _GstOpenJPEGEncClass GstOpenJPEGEncClass;
+
+struct _GstOpenJPEGEnc
+{
+  GstVideoEncoder parent;
+
+  /* < private > */
+  GstVideoCodecState *input_state;
+  GstVideoCodecState *output_state;
+
+  OPJ_CODEC_FORMAT codec_format;
+  gboolean is_jp2c;
+
+  void (*fill_image) (opj_image_t * image, GstVideoFrame *frame);
+
+  opj_cparameters_t params;
+};
+
+struct _GstOpenJPEGEncClass
+{
+  GstVideoEncoderClass parent_class;
+};
+
+GType gst_openjpeg_enc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_OPENJPEG_ENC_H__ */