Seperate decode and picture_copy if no pix_fmt is specified
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstmaruinterface.c
index 953a5bd..c9bc312 100644 (file)
 
 #include "gstmaru.h"
 #include "gstmaruinterface.h"
+#include "gstmaruutils.h"
 #include "gstmarumem.h"
 #include "gstmarudevice.h"
 
 extern int device_fd;
 extern gpointer device_mem;
 
-struct mem_info {
-    gpointer start;
-    uint32_t offset;
-    uint32_t size;
-};
-
 typedef struct _CodecHeader {
   int32_t   api_index;
   uint32_t  mem_offset;
 } CodecHeader;
 
-#define CODEC_META_DATA_SIZE    256
-#define GET_OFFSET(buffer)      ((uint32_t)buffer - (uint32_t)device_mem)
-#define SMALLDATA               0
+typedef struct _CodecBufferId {
+  uint32_t  buffer_index;
+  uint32_t  buffer_size;
+} CodecBufferId;
 
-static int
-_codec_header (int32_t api_index, uint32_t mem_offset, uint8_t *device_buf)
-{
-  CodecHeader header = { 0 };
-
-  CODEC_LOG (DEBUG, "enter, %s\n", __func__);
+typedef struct _CodecIOParams {
+  int32_t   api_index;
+  int32_t   ctx_index;
+  uint32_t  mem_offset;
 
-  header.api_index = api_index;
-  header.mem_offset = mem_offset;
+  CodecBufferId buffer_id;
+} CodecIOParams;
 
-  memcpy(device_buf, &header, sizeof(header));
 
-  CODEC_LOG (DEBUG, "leave, %s\n", __func__);
+#define CODEC_META_DATA_SIZE    256
+#define GET_OFFSET(buffer)      ((uint32_t)buffer - (uint32_t)device_mem)
+#define SMALLDATA               0
 
-  return sizeof(header);
-}
+#define OFFSET_PICTURE_BUFFER   0x100
 
-static void
-_codec_write_to_qemu (int32_t ctx_index, int32_t api_index,
-                          uint32_t mem_offset, int fd)
+static int
+_codec_invoke_qemu(int32_t ctx_index, int32_t api_index,
+                          uint32_t mem_offset, int fd, CodecBufferId *buffer_id)
 {
-  CodecIOParams ioparam;
+  CodecIOParams ioparam = { 0, };
+  int ret = -1;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  memset(&ioparam, 0, sizeof(ioparam));
   ioparam.api_index = api_index;
   ioparam.ctx_index = ctx_index;
   ioparam.mem_offset = mem_offset;
-  if (write (fd, &ioparam, 1) < 0) {
-    CODEC_LOG (ERR, "failed to write input data\n");
+
+  if (CHECK_VERSION(3)) {
+    if (buffer_id) {
+      ioparam.buffer_id.buffer_index = buffer_id->buffer_index;
+      ioparam.buffer_id.buffer_size = buffer_id->buffer_size;
+    }
+
+    ret = ioctl(fd, CODEC_CMD_INVOKE_API_AND_RELEASE_BUFFER, &ioparam);
+
+    if (buffer_id) {
+      buffer_id->buffer_index = ioparam.buffer_id.buffer_index;
+      buffer_id->buffer_size = ioparam.buffer_id.buffer_size;
+    }
+  } else {
+    if (ioctl(fd, CODEC_CMD_INVOKE_API_AND_RELEASE_BUFFER, &ioparam) < 0) {
+      return -1;
+    }
+    if (buffer_id) {
+      ret = ioctl(fd, CODEC_CMD_PUT_DATA_INTO_BUFFER, buffer_id);
+    }
   }
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+
+  return ret;
 }
 
 static int
-secure_device_mem (int fd, guint buf_size, gpointer* buffer)
+secure_device_mem (int fd, guint ctx_id, guint buf_size, gpointer* buffer)
 {
   int ret = 0;
-  uint32_t opaque = 0;
-  struct mem_info info = {0, };
+  CodecBufferId opaque;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
-  opaque = buf_size;
+  opaque.buffer_index = ctx_id;
+  opaque.buffer_size = buf_size;
 
   ret = ioctl (fd, CODEC_CMD_SECURE_BUFFER, &opaque);
-  *buffer = (gpointer)((uint32_t)device_mem + opaque);
-  CODEC_LOG (DEBUG, "buffer: 0x%x\n", (int)buffer);
+  /* ioctl: CODEC_CMD_SECURE_BUFFER
+   *  - sets device memory offset into opaque.buffer_size
+   */
+  *buffer = (gpointer)((uint32_t)device_mem + opaque.buffer_size);
+  GST_DEBUG ("device_mem %p, offset_size 0x%x", device_mem, opaque.buffer_size);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 
@@ -114,14 +131,10 @@ release_device_mem (int fd, gpointer start)
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  CODEC_LOG (DEBUG, "release device_mem start: %p, offset: 0x%x\n", start, offset);
-  if (fd == -1) {
-    // FIXME: We use device_fd now...
-    fd = device_fd;
-  }
+  GST_DEBUG ("release device_mem start: %p, offset: 0x%x", start, offset);
   ret = ioctl (fd, CODEC_CMD_RELEASE_BUFFER, &offset);
   if (ret < 0) {
-    CODEC_LOG (ERR, "failed to release buffer\n");
+    GST_ERROR ("failed to release buffer\n");
   }
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
@@ -132,7 +145,17 @@ codec_buffer_free (gpointer start)
 {
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  release_device_mem (-1, start);
+  release_device_mem (device_fd, start);
+
+  CODEC_LOG (DEBUG, "leave: %s\n", __func__);
+}
+
+static void
+codec_buffer_free2 (gpointer start)
+{
+  CODEC_LOG (DEBUG, "enter: %s\n", __func__);
+
+  release_device_mem (device_fd, start - OFFSET_PICTURE_BUFFER);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 }
@@ -141,48 +164,71 @@ GstFlowReturn
 codec_buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
                   GstCaps *caps, GstBuffer **buf)
 {
-  struct mem_info info;
-  uint32_t opaque;
-  int ret = 0;
+  bool is_last_buffer = 0;
+  int mem_offset;
+  CodecBufferId opaque;
   GstMaruDec *marudec;
+  CodecContext *ctx;
+  CodecDevice *dev;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  opaque = size;
-
   *buf = gst_buffer_new ();
 
   marudec = (GstMaruDec *)gst_pad_get_element_private(pad);
+  ctx = marudec->context;
+  dev = marudec->dev;
 
-  _codec_write_to_qemu (marudec->context->index, CODEC_PICTURE_COPY,
-                        0, marudec->dev->fd);
+  if (marudec->is_using_new_decode_api) {
+    is_last_buffer = marudec->is_last_buffer;
+    mem_offset = marudec->mem_offset;
+  } else {
+    ctx = marudec->context;
 
-  ret = ioctl (marudec->dev->fd, CODEC_CMD_PUT_DATA_INTO_BUFFER, &opaque);
+    opaque.buffer_index = ctx->index;
+    opaque.buffer_size = size;
 
-  if (ret < 0) {
-    CODEC_LOG (DEBUG, "failed to get available buffer\n");
-  } else if (ret == 1) {
+    GST_DEBUG ("buffer_and_copy. ctx_id: %d", ctx->index);
+
+    int ret = _codec_invoke_qemu(ctx->index, CODEC_PICTURE_COPY, 0, dev->fd, &opaque);
+    if (ret < 0) {
+      GST_DEBUG ("failed to get available buffer");
+      return GST_FLOW_ERROR;
+    }
+    is_last_buffer = ret;
+    mem_offset = opaque.buffer_size;
+  }
+
+  gpointer *buffer = NULL;
+  if (is_last_buffer) {
     // FIXME: we must aligned buffer offset.
-    info.start = g_malloc (size);
-    info.offset = 0;
+    buffer = g_malloc (size);
 
     GST_BUFFER_FREE_FUNC (*buf) = g_free;
 
-    memcpy (info.start, (uint32_t)device_mem + opaque, size);
-    release_device_mem(marudec->dev->fd, (uint32_t)device_mem + opaque);
+    if (marudec->is_using_new_decode_api) {
+      memcpy (buffer, device_mem + mem_offset + OFFSET_PICTURE_BUFFER, size);
+    } else {
+      memcpy (buffer, device_mem + mem_offset, size);
+    }
+    release_device_mem(dev->fd, device_mem + mem_offset);
 
-    CODEC_LOG (DEBUG, "we secured last buffer, so we will use heap buffer\n");
+    GST_DEBUG ("secured last buffer!! Use heap buffer");
   } else {
     // address of "device_mem" and "opaque" is aleady aligned.
-    info.start = (gpointer)((uint32_t)device_mem + opaque);
-    info.offset = opaque;
+    if (marudec->is_using_new_decode_api) {
+      buffer = (gpointer)(device_mem + mem_offset + OFFSET_PICTURE_BUFFER);
+      GST_BUFFER_FREE_FUNC (*buf) = codec_buffer_free2;
+    } else {
+      buffer = (gpointer)(device_mem + mem_offset);
+      GST_BUFFER_FREE_FUNC (*buf) = codec_buffer_free;
+    }
 
-    GST_BUFFER_FREE_FUNC (*buf) = codec_buffer_free;
 
-    CODEC_LOG (DEBUG, "device memory start: 0x%p, offset 0x%x\n", info.start, info.offset);
+    GST_DEBUG ("device memory start: 0x%p, offset 0x%x", (intptr_t)buffer, mem_offset);
   }
 
-  GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = info.start;
+  GST_BUFFER_DATA (*buf) = GST_BUFFER_MALLOCDATA (*buf) = (void *)buffer;
   GST_BUFFER_SIZE (*buf) = size;
   GST_BUFFER_OFFSET (*buf) = offset;
 
@@ -198,34 +244,48 @@ codec_buffer_alloc_and_copy (GstPad *pad, guint64 offset, guint size,
 int
 codec_init (CodecContext *ctx, CodecElement *codec, CodecDevice *dev)
 {
-  int ret = 0, opened = 0, size = 8;
-  uint32_t meta_offset = 0;
+  int opened = 0;
+  gpointer buffer = NULL;
+  CodecBufferId opaque;
+  int ret;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  ret = ioctl(dev->fd, CODEC_CMD_GET_CONTEXT_INDEX, &ctx->index);
-  if (ret < 0) {
-    GST_ERROR ("failed to get context index\n");
+  if (ioctl(dev->fd, CODEC_CMD_GET_CONTEXT_INDEX, &ctx->index) < 0) {
+    GST_ERROR ("failed to get a context index");
     return -1;
   }
-  CODEC_LOG (DEBUG, "get context index: %d\n", ctx->index);
+  GST_DEBUG ("get context index: %d", ctx->index);
 
-  meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
-  CODEC_LOG (DEBUG,
-    "init. ctx: %d meta_offset = 0x%x\n", ctx->index, meta_offset);
+  /* buffer size is 0. It means that this function is required to
+   * use small size.
+  */
+  if (secure_device_mem(dev->fd, ctx->index, 0, &buffer) < 0) {
+    GST_ERROR ("failed to get a memory block");
+    return -1;
+  }
+
+  codec_init_data_to (ctx, codec, buffer);
 
-  _codec_init_meta_to (ctx, codec, device_mem + meta_offset + size);
+  opaque.buffer_index = ctx->index;
+  opaque.buffer_size = SMALLDATA;
 
-  _codec_write_to_qemu (ctx->index, CODEC_INIT, 0, dev->fd);
+  ret = _codec_invoke_qemu (ctx->index, CODEC_INIT, GET_OFFSET(buffer), dev->fd, &opaque);
 
-  CODEC_LOG (DEBUG,
-    "init. ctx: %d meta_offset = 0x%x, size: %d\n", ctx->index, meta_offset, size);
+  if (ret < 0) {
+    return -1;
+  }
 
   opened =
-    _codec_init_meta_from (ctx, codec->media_type, device_mem + meta_offset + size);
-  ctx->codec = codec;
+    codec_init_data_from (ctx, codec->media_type, device_mem + opaque.buffer_size);
 
-  CODEC_LOG (DEBUG, "opened: %d\n", opened);
+  if (opened < 0) {
+    GST_ERROR ("failed to open Context for %s", codec->name);
+  } else {
+    ctx->codec = codec;
+  }
+
+  release_device_mem(dev->fd, device_mem + opaque.buffer_size);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 
@@ -237,8 +297,8 @@ codec_deinit (CodecContext *ctx, CodecDevice *dev)
 {
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  CODEC_LOG (INFO, "close. context index: %d\n", ctx->index);
-  _codec_write_to_qemu (ctx->index, CODEC_DEINIT, 0, dev->fd);
+  GST_INFO ("close context %d", ctx->index);
+  _codec_invoke_qemu (ctx->index, CODEC_DEINIT, 0, dev->fd, NULL);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 }
@@ -248,41 +308,74 @@ codec_flush_buffers (CodecContext *ctx, CodecDevice *dev)
 {
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  CODEC_LOG (DEBUG, "flush buffers. context index: %d\n", ctx->index);
-  _codec_write_to_qemu (ctx->index, CODEC_FLUSH_BUFFERS, 0, dev->fd);
+  GST_DEBUG ("flush buffers of context: %d", ctx->index);
+  _codec_invoke_qemu (ctx->index, CODEC_FLUSH_BUFFERS, 0, dev->fd, NULL);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 }
 
 int
-codec_decode_video (CodecContext *ctx, uint8_t *in_buf, int in_size,
-                    gint idx, gint64 in_offset, GstBuffer **out_buf,
-                    int *got_picture_ptr, CodecDevice *dev)
+codec_decode_video (GstMaruDec *marudec, uint8_t *in_buf, int in_size,
+                    gint idx, gint64 in_offset, GstBuffer **out_buf, int *have_data)
 {
-  int len = 0, ret = 0, size = 8;
+  CodecContext *ctx = marudec->context;
+  CodecDevice *dev = marudec->dev;
+  int len = 0, ret = 0;
   gpointer buffer = NULL;
-  uint32_t meta_offset = 0;
+  CodecBufferId opaque = { 0, };
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
-  CODEC_LOG (DEBUG, "decode_video. ctx_id: %d meta_offset = 0x%x\n", ctx->index, meta_offset);
-  _codec_decode_video_meta_to (in_size, idx, in_offset, device_mem + meta_offset + size);
+  ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
+  if (ret < 0) {
+    GST_ERROR ("failed to get available memory to write inbuf");
+    return -1;
+  }
+
+  codec_decode_video_data_to (in_size, idx, in_offset, in_buf, buffer);
+
+  opaque.buffer_index = ctx->index;
+
+  marudec->is_using_new_decode_api = (can_use_new_decode_api() && (ctx->video.pix_fmt != -1));
+
+  if (marudec->is_using_new_decode_api) {
+    int picture_size = gst_maru_avpicture_size (ctx->video.pix_fmt,
+        ctx->video.width, ctx->video.height);
+    if (picture_size < 0) {
+      GST_ERROR ("Check about it"); // FIXME
+      opaque.buffer_size = SMALLDATA;
+    } else {
+      opaque.buffer_size = picture_size;
+    }
+    ret = _codec_invoke_qemu(ctx->index, CODEC_DECODE_VIDEO2, GET_OFFSET(buffer), dev->fd, &opaque);
+  } else {
+    opaque.buffer_size = SMALLDATA;
+    ret = _codec_invoke_qemu(ctx->index, CODEC_DECODE_VIDEO, GET_OFFSET(buffer), dev->fd, &opaque);
+  }
 
-  ret = secure_device_mem(dev->fd, in_size, &buffer);
   if (ret < 0) {
-    CODEC_LOG (ERR,
-      "decode_video. failed to get available memory to write inbuf\n");
+    // FIXME:
     return -1;
   }
+  len = codec_decode_video_data_from (have_data, &ctx->video, device_mem + opaque.buffer_size);
+
+  GST_DEBUG_OBJECT (marudec, "after decode: len %d, have_data %d",
+        len, *have_data);
+  if (len < 0 || *have_data <= 0) {
+    GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
+        ret, *out_buf, len);
 
-  _codec_decode_video_inbuf (in_buf, in_size, buffer);
-  dev->mem_info.offset = GET_OFFSET(buffer);
-  _codec_write_to_qemu (ctx->index, CODEC_DECODE_VIDEO, GET_OFFSET(buffer), dev->fd);
+    release_device_mem(dev->fd, device_mem + opaque.buffer_size);
+
+    return len;
+  }
 
-  // after decoding video, no need to get outbuf.
-  len =
-    _codec_decode_video_meta_from (&ctx->video, got_picture_ptr, device_mem + meta_offset + size);
+  if (marudec->is_using_new_decode_api) {
+    marudec->is_last_buffer = ret;
+    marudec->mem_offset = opaque.buffer_size;
+  } else {
+    release_device_mem(dev->fd, device_mem + opaque.buffer_size);
+  }
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 
@@ -294,43 +387,39 @@ codec_decode_audio (CodecContext *ctx, int16_t *samples,
                     int *have_data, uint8_t *in_buf,
                     int in_size, CodecDevice *dev)
 {
-  int len = 0, ret = 0, size = 8;
+  int len = 0, ret = 0;
   gpointer buffer = NULL;
-  uint32_t meta_offset = 0, opaque = 0;
+  CodecBufferId opaque;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
-  CODEC_LOG (DEBUG, "decode_audio. ctx_id: %d meta_offset = 0x%x\n", ctx->index, meta_offset);
-  _codec_decode_audio_meta_to (in_size, device_mem + meta_offset + size);
-
-  ret = secure_device_mem(dev->fd, in_size, &buffer);
+  ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
   if (ret < 0) {
-    CODEC_LOG (ERR,
-      "decode_audio. failed to get available memory to write inbuf\n");
+    GST_ERROR ("failed to get available memory to write inbuf");
     return -1;
   }
 
-  _codec_decode_audio_inbuf (in_buf, in_size, buffer);
-  dev->mem_info.offset = GET_OFFSET(buffer);
-  _codec_write_to_qemu (ctx->index, CODEC_DECODE_AUDIO, GET_OFFSET(buffer), dev->fd);
+  GST_DEBUG ("decode_audio 1. in_buffer size %d", in_size);
+  codec_decode_audio_data_to (in_size, in_buf, buffer);
+
+  opaque.buffer_index = ctx->index;
+  opaque.buffer_size = SMALLDATA;
+
+  ret = _codec_invoke_qemu(ctx->index, CODEC_DECODE_AUDIO, GET_OFFSET(buffer), dev->fd, &opaque);
 
-  opaque = SMALLDATA; // FIXME: how can we know output data size ?
-  ret = ioctl (dev->fd, CODEC_CMD_PUT_DATA_INTO_BUFFER, &opaque);
   if (ret < 0) {
     return -1;
   }
-  CODEC_LOG (DEBUG, "after decode_audio. ctx_id: %d, buffer = 0x%x\n", ctx->index, (int)device_mem + opaque);
 
-  len =
-    _codec_decode_audio_meta_from (&ctx->audio, have_data, device_mem + meta_offset + size);
-  if (len > 0) {
-    _codec_decode_audio_outbuf (*have_data, samples, device_mem + opaque);
-  } else {
-    CODEC_LOG (DEBUG, "decode_audio failure. ctx_id: %d\n", ctx->index);
-  }
+  GST_DEBUG ("decode_audio 2. ctx_id: %d, buffer = 0x%x",
+    ctx->index, device_mem + opaque.buffer_size);
+
+  len = codec_decode_audio_data_from (have_data, samples,
+    &ctx->audio, device_mem + opaque.buffer_size);
 
-  release_device_mem(dev->fd, device_mem + opaque);
+  GST_DEBUG ("decode_audio 3. ctx_id: %d len: %d", ctx->index, len);
+
+  release_device_mem(dev->fd, device_mem + opaque.buffer_size);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 
@@ -340,44 +429,39 @@ codec_decode_audio (CodecContext *ctx, int16_t *samples,
 int
 codec_encode_video (CodecContext *ctx, uint8_t *out_buf,
                     int out_size, uint8_t *in_buf,
-                    int in_size, int64_t in_timestamp, CodecDevice *dev)
+                    int in_size, int64_t in_timestamp,
+                    int *coded_frame, int *is_keyframe,
+                    CodecDevice *dev)
 {
-  int len = 0, ret = 0, size = 8;
+  int len = 0, ret = 0;
   gpointer buffer = NULL;
-  uint32_t meta_offset = 0, opaque = 0;
+  CodecBufferId opaque;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
-  CODEC_LOG (DEBUG, "encode_video. meta_offset = 0x%x\n", meta_offset);
-  _codec_encode_video_meta_to (in_size, in_timestamp, device_mem + meta_offset + size);
-
-  ret = secure_device_mem(dev->fd, in_size, &buffer);
+  ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
   if (ret < 0) {
-    CODEC_LOG (ERR, "failed to small size of buffer.\n");
+    GST_ERROR ("failed to small size of buffer");
     return -1;
   }
 
-  _codec_encode_video_inbuf (in_buf, in_size, buffer);
-  dev->mem_info.offset = GET_OFFSET(buffer);
-  _codec_write_to_qemu (ctx->index, CODEC_ENCODE_VIDEO, GET_OFFSET(buffer), dev->fd);
+  codec_encode_video_data_to (in_size, in_timestamp, in_buf, buffer);
+
+  opaque.buffer_index = ctx->index;
+  opaque.buffer_size = SMALLDATA;
+
+  // FIXME: how can we know output data size ?
+  ret = _codec_invoke_qemu(ctx->index, CODEC_ENCODE_VIDEO, GET_OFFSET(buffer), dev->fd, &opaque);
 
-  opaque = SMALLDATA; // FIXME: how can we know output data size ?
-  ret = ioctl (dev->fd, CODEC_CMD_PUT_DATA_INTO_BUFFER, &opaque);
   if (ret < 0) {
     return -1;
   }
-  CODEC_LOG (DEBUG, "read, encode_video. mem_offset = 0x%x\n", opaque);
 
-  memcpy (&len, device_mem + meta_offset + size, sizeof(len));
+  GST_DEBUG ("encode_video. mem_offset = 0x%x", opaque.buffer_size);
 
-  CODEC_LOG (DEBUG, "encode_video. outbuf size: %d\n", len);
-  if (len > 0) {
-    memcpy (out_buf, device_mem + opaque, len);
-    dev->mem_info.offset = opaque;
-  }
+  len = codec_encode_video_data_from (out_buf, coded_frame, is_keyframe, device_mem + opaque.buffer_size);
 
-  release_device_mem(dev->fd, device_mem + opaque);
+  release_device_mem(dev->fd, device_mem + opaque.buffer_size);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 
@@ -387,42 +471,38 @@ codec_encode_video (CodecContext *ctx, uint8_t *out_buf,
 int
 codec_encode_audio (CodecContext *ctx, uint8_t *out_buf,
                     int max_size, uint8_t *in_buf,
-                    int in_size, CodecDevice *dev)
+                    int in_size, int64_t timestamp,
+                    CodecDevice *dev)
 {
-  int len = 0, ret = 0, size = 8;
+  int ret = 0;
   gpointer buffer = NULL;
-  uint32_t meta_offset = 0, opaque = 0;
+  CodecBufferId opaque;
 
   CODEC_LOG (DEBUG, "enter: %s\n", __func__);
 
-  meta_offset = (ctx->index - 1) * CODEC_META_DATA_SIZE;
-  CODEC_LOG (DEBUG, "encode_audio. meta mem_offset = 0x%x\n", meta_offset);
-  size = _codec_header (CODEC_ENCODE_AUDIO, opaque,
-                            device_mem + meta_offset);
-  _codec_encode_audio_meta_to (max_size, in_size, device_mem + meta_offset + size);
-
-  ret = secure_device_mem(dev->fd, in_size, &buffer);
+  ret = secure_device_mem(dev->fd, ctx->index, in_size, &buffer);
   if (ret < 0) {
     return -1;
   }
 
-  _codec_encode_audio_inbuf (in_buf, in_size, buffer);
-  dev->mem_info.offset = GET_OFFSET(buffer);
-  _codec_write_to_qemu (ctx->index, CODEC_ENCODE_AUDIO, GET_OFFSET(buffer), dev->fd);
+  codec_encode_audio_data_to (in_size, max_size, in_buf, timestamp, buffer);
+
+  opaque.buffer_index = ctx->index;
+  opaque.buffer_size = SMALLDATA;
+
+  ret = _codec_invoke_qemu(ctx->index, CODEC_ENCODE_AUDIO, GET_OFFSET(buffer), dev->fd, &opaque);
 
-  opaque = SMALLDATA; // FIXME: how can we know output data size ?
-  ret = ioctl (dev->fd, CODEC_CMD_PUT_DATA_INTO_BUFFER, &opaque);
   if (ret < 0) {
     return -1;
   }
 
-  CODEC_LOG (DEBUG, "read, encode_video. mem_offset = 0x%x\n", opaque);
+  GST_DEBUG ("encode_audio. mem_offset = 0x%x", opaque.buffer_size);
 
-  len = _codec_encode_audio_outbuf (out_buf, device_mem + opaque);
+  ret = codec_encode_audio_data_from (out_buf, device_mem + opaque.buffer_size);
 
-  release_device_mem(dev->fd, device_mem + opaque);
+  release_device_mem(dev->fd, device_mem + opaque.buffer_size);
 
   CODEC_LOG (DEBUG, "leave: %s\n", __func__);
 
-  return len;
+  return ret;
 }