brillcodec: clean-up source 75/25575/1
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Sat, 2 Aug 2014 09:21:05 +0000 (18:21 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Thu, 7 Aug 2014 05:45:10 +0000 (14:45 +0900)
brillcodec is separated into two source files.
Using macro to get a proper codec context.

Change-Id: I5dfc4f0707b5cf6d98653b65ab8b121ea48f5121
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
tizen/src/hw/pci/Makefile.objs
tizen/src/hw/pci/maru_brill_codec.c [deleted file]
tizen/src/hw/pci/maru_brill_codec.h [deleted file]
tizen/src/hw/pci/maru_brillcodec.c [new file with mode: 0644]
tizen/src/hw/pci/maru_brillcodec.h [new file with mode: 0644]
tizen/src/hw/pci/maru_brillcodec_device.c [new file with mode: 0644]

index 615bb1d2a0755e4bb874ccde35d38fccd7cdaad7..0c2a166ce2e8243ba843e85b9a5a5e0a08e59bf1 100644 (file)
@@ -1,4 +1,6 @@
-obj-y += maru_brill_codec.o
+obj-y += maru_brillcodec_device.o
+obj-y += maru_brillcodec.o
+
 obj-y += maru_brightness.o
 
 obj-y += maru_camera_common_pci.o
diff --git a/tizen/src/hw/pci/maru_brill_codec.c b/tizen/src/hw/pci/maru_brill_codec.c
deleted file mode 100644 (file)
index d0598b5..0000000
+++ /dev/null
@@ -1,2003 +0,0 @@
-/*
- * Virtual Codec Device
- *
- * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- *  Kitae Kim <kt920.kim@samsung.com>
- *  SeokYeon Hwang <syeon.hwang@samsung.com>
- *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "maru_brill_codec.h"
-#include "debug_ch.h"
-
-/* define debug channel */
-MULTI_DEBUG_CHANNEL(qemu, brillcodec);
-
-// device
-#define CODEC_DEVICE_NAME   "codec-pci"
-#define CODEC_DEVICE_THREAD "codec-workthread"
-#define CODEC_VERSION       2
-
-// device memory
-#define CODEC_META_DATA_SIZE    (256)
-
-#define CODEC_MEM_SIZE          (32 * 1024 * 1024)
-#define CODEC_REG_SIZE          (256)
-
-// libav
-#define GEN_MASK(x) ((1 << (x)) - 1)
-#define ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x))
-#define ROUND_UP_2(x) ROUND_UP_X(x, 1)
-#define ROUND_UP_4(x) ROUND_UP_X(x, 2)
-#define ROUND_UP_8(x) ROUND_UP_X(x, 3)
-#define DIV_ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) >> (x))
-
-#define DEFAULT_VIDEO_GOP_SIZE 15
-
-
-// define a queue to manage ioparam, context data
-typedef struct DeviceMemEntry {
-    void *opaque;
-    uint32_t data_size;
-    uint32_t ctx_id;
-
-    DataHandler *handler;
-
-    QTAILQ_ENTRY(DeviceMemEntry) node;
-} DeviceMemEntry;
-
-typedef struct CodecDataStg {
-    CodecParam *param_buf;
-    DeviceMemEntry *data_buf;
-
-    QTAILQ_ENTRY(CodecDataStg) node;
-} CodecDataStg;
-
-// define two queue to store input and output buffers.
-static QTAILQ_HEAD(codec_wq, DeviceMemEntry) codec_wq =
-   QTAILQ_HEAD_INITIALIZER(codec_wq);
-
-static QTAILQ_HEAD(codec_rq, CodecDataStg) codec_rq =
-   QTAILQ_HEAD_INITIALIZER(codec_rq);
-
-static DeviceMemEntry *entry[CODEC_CONTEXT_MAX];
-
-// pixel info
-typedef struct PixFmtInfo {
-    uint8_t x_chroma_shift;
-    uint8_t y_chroma_shift;
-} PixFmtInfo;
-
-static PixFmtInfo pix_fmt_info[PIX_FMT_NB];
-
-// thread
-#define DEFAULT_WORKER_THREAD_CNT 8
-
-static void *maru_brill_codec_threads(void *opaque);
-
-// static void maru_brill_codec_reset_parser_info(MaruBrillCodecState *s, int32_t ctx_index);
-static int maru_brill_codec_query_list(MaruBrillCodecState *s);
-static void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t value);
-
-// codec functions
-static bool codec_init(MaruBrillCodecState *, int, void *);
-static bool codec_deinit(MaruBrillCodecState *, int, void *);
-static bool codec_decode_video(MaruBrillCodecState *, int, void *);
-static bool codec_encode_video(MaruBrillCodecState *, int, void *);
-static bool codec_decode_audio(MaruBrillCodecState *, int, void *);
-static bool codec_encode_audio(MaruBrillCodecState *, int, void *);
-static bool codec_picture_copy(MaruBrillCodecState *, int, void *);
-static bool codec_flush_buffers(MaruBrillCodecState *, int, void *);
-
-typedef bool (*CodecFuncEntry)(MaruBrillCodecState *, int, void *);
-static CodecFuncEntry codec_func_handler[] = {
-    codec_init,
-    codec_decode_video,
-    codec_encode_video,
-    codec_decode_audio,
-    codec_encode_audio,
-    codec_picture_copy,
-    codec_deinit,
-    codec_flush_buffers,
-};
-
-static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx);
-
-static void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx);
-static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s, CodecParam *ioparam);
-static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
-                                            size_t data_size, int ctx_id,
-                                            DataHandler *handler);
-
-static void *maru_brill_codec_store_inbuf(uint8_t *mem_base, CodecParam *ioparam);
-
-static void maru_brill_codec_reset(DeviceState *s);
-
-static void default_get_data(void *dst, void *src, size_t size) {
-    memcpy(dst, src, size);
-}
-
-static void default_release(void *opaque) {
-    g_free(opaque);
-}
-
-
-static DataHandler default_data_handler = {
-    .get_data = default_get_data,
-    .release = default_release,
-};
-
-
-static void extract(void *dst, void *src, size_t size) {
-    AVFrame *frame = (AVFrame *)src;
-    avpicture_layout((AVPicture *)src, PIX_FMT_YUV420P, frame->width, frame->height, dst, size);
-}
-
-static void release(void *buf) {}
-
-static DataHandler default_video_decode_data_handler = {
-    .get_data = extract,
-    .release = release,
-};
-
-static void maru_brill_codec_get_cpu_cores(MaruBrillCodecState *s)
-{
-    s->worker_thread_cnt = get_number_of_processors();
-    if (s->worker_thread_cnt < DEFAULT_WORKER_THREAD_CNT) {
-        s->worker_thread_cnt = DEFAULT_WORKER_THREAD_CNT;
-    }
-
-    TRACE("number of threads: %d\n", s->worker_thread_cnt);
-}
-
-static void maru_brill_codec_threads_create(MaruBrillCodecState *s)
-{
-    int index;
-    QemuThread *pthread = NULL;
-
-    TRACE("enter: %s\n", __func__);
-
-    pthread = g_malloc(sizeof(QemuThread) * s->worker_thread_cnt);
-    if (!pthread) {
-        ERR("failed to allocate threadpool memory.\n");
-        return;
-    }
-
-    qemu_cond_init(&s->threadpool.cond);
-    qemu_mutex_init(&s->threadpool.mutex);
-
-    s->is_thread_running = true;
-
-    qemu_mutex_lock(&s->context_mutex);
-    s->idle_thread_cnt = 0;
-    qemu_mutex_unlock(&s->context_mutex);
-
-    for (index = 0; index < s->worker_thread_cnt; index++) {
-        qemu_thread_create(&pthread[index], CODEC_DEVICE_THREAD,
-            maru_brill_codec_threads, (void *)s, QEMU_THREAD_JOINABLE);
-    }
-
-    s->threadpool.threads = pthread;
-
-    TRACE("leave: %s\n", __func__);
-}
-
-static void maru_brill_codec_thread_exit(MaruBrillCodecState *s)
-{
-    int index;
-
-    TRACE("enter: %s\n", __func__);
-
-    /* stop to run dedicated threads. */
-    s->is_thread_running = false;
-
-    for (index = 0; index < s->worker_thread_cnt; index++) {
-        qemu_thread_join(&s->threadpool.threads[index]);
-    }
-
-    TRACE("destroy mutex and conditional.\n");
-    qemu_mutex_destroy(&s->threadpool.mutex);
-    qemu_cond_destroy(&s->threadpool.cond);
-
-    if (s->threadpool.threads) {
-        g_free(s->threadpool.threads);
-        s->threadpool.threads = NULL;
-    }
-
-    TRACE("leave: %s\n", __func__);
-}
-
-static void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
-{
-    CodecParam *ioparam = NULL;
-
-    ioparam = g_malloc0(sizeof(CodecParam));
-    if (!ioparam) {
-        ERR("failed to allocate ioparam\n");
-        return;
-    }
-
-    memcpy(ioparam, &s->ioparam, sizeof(CodecParam));
-
-    TRACE("wakeup thread. ctx_id: %u, api_id: %u, mem_offset: 0x%x\n",
-        ioparam->ctx_index, ioparam->api_index, ioparam->mem_offset);
-
-    qemu_mutex_lock(&s->context_mutex);
-
-    if (ioparam->api_index != CODEC_INIT) {
-        if (!s->context[ioparam->ctx_index].opened_context) {
-            INFO("abandon api %d for context %d\n",
-                    ioparam->api_index, ioparam->ctx_index);
-            qemu_mutex_unlock(&s->context_mutex);
-            return;
-        }
-    }
-
-    qemu_mutex_unlock(&s->context_mutex);
-
-    maru_brill_codec_push_readqueue(s, ioparam);
-
-    qemu_mutex_lock(&s->context_mutex);
-    // W/A for threads starvation.
-    while (s->idle_thread_cnt == 0) {
-        qemu_mutex_unlock(&s->context_mutex);
-        TRACE("Worker threads are exhausted\n");
-        usleep(2000); // wait 2ms.
-        qemu_mutex_lock(&s->context_mutex);
-    }
-    qemu_cond_signal(&s->threadpool.cond);
-    qemu_mutex_unlock(&s->context_mutex);
-
-    TRACE("after sending conditional signal\n");
-}
-
-static void *maru_brill_codec_threads(void *opaque)
-{
-    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
-    bool ret = false;
-
-    TRACE("enter: %s\n", __func__);
-
-    while (s->is_thread_running) {
-        int ctx_id = 0, api_id = 0;
-        CodecDataStg *elem = NULL;
-        DeviceMemEntry *indata_buf = NULL;
-
-        qemu_mutex_lock(&s->context_mutex);
-        ++(s->idle_thread_cnt); // protected under mutex.
-        qemu_cond_wait(&s->threadpool.cond, &s->context_mutex);
-        --(s->idle_thread_cnt); // protected under mutex.
-        qemu_mutex_unlock(&s->context_mutex);
-
-        qemu_mutex_lock(&s->ioparam_queue_mutex);
-        elem = QTAILQ_FIRST(&codec_rq);
-        if (elem) {
-            QTAILQ_REMOVE(&codec_rq, elem, node);
-            qemu_mutex_unlock(&s->ioparam_queue_mutex);
-        } else {
-            qemu_mutex_unlock(&s->ioparam_queue_mutex);
-            continue;
-        }
-
-        if (!elem->param_buf) {
-            continue;
-        }
-
-        api_id = elem->param_buf->api_index;
-        ctx_id = elem->param_buf->ctx_index;
-
-        indata_buf = elem->data_buf;
-
-        TRACE("api_id: %d ctx_id: %d\n", api_id, ctx_id);
-
-        qemu_mutex_lock(&s->context_mutex);
-        s->context[ctx_id].occupied_thread = true;
-        qemu_mutex_unlock(&s->context_mutex);
-
-        ret = codec_func_handler[api_id](s, ctx_id, indata_buf);
-        if (!ret) {
-            ERR("fail api %d for context %d\n", api_id, ctx_id);
-            g_free(elem->param_buf);
-            continue;
-        }
-
-        TRACE("release a buffer of CodecParam\n");
-        g_free(elem->param_buf);
-        elem->param_buf = NULL;
-
-        if (elem->data_buf) {
-            if (elem->data_buf->opaque) {
-                TRACE("release inbuf\n");
-                g_free(elem->data_buf->opaque);
-                elem->data_buf->opaque = NULL;
-            }
-
-            TRACE("release a buffer indata_buf\n");
-            g_free(elem->data_buf);
-            elem->data_buf = NULL;
-        }
-
-        TRACE("release an element of CodecDataStg\n");
-        g_free(elem);
-
-        qemu_mutex_lock(&s->context_mutex);
-        if (s->context[ctx_id].requested_close) {
-            INFO("make worker thread to handle deinit\n");
-            // codec_deinit(s, ctx_id, NULL);
-            maru_brill_codec_release_context(s, ctx_id);
-            s->context[ctx_id].requested_close = false;
-        }
-        qemu_mutex_unlock(&s->context_mutex);
-
-        TRACE("switch context to raise interrupt.\n");
-        qemu_bh_schedule(s->codec_bh);
-
-        qemu_mutex_lock(&s->context_mutex);
-        s->context[ctx_id].occupied_thread = false;
-        qemu_mutex_unlock(&s->context_mutex);
-    }
-
-    maru_brill_codec_thread_exit(s);
-
-    TRACE("leave: %s\n", __func__);
-    return NULL;
-}
-
-// queue
-static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s,
-                                            CodecParam *ioparam)
-{
-    CodecDataStg *elem = NULL;
-    DeviceMemEntry *data_buf = NULL;
-
-    elem = g_malloc0(sizeof(CodecDataStg));
-    if (!elem) {
-        ERR("failed to allocate ioparam_queue. %d\n", sizeof(CodecDataStg));
-        return;
-    }
-
-    elem->param_buf = ioparam;
-
-    switch(ioparam->api_index) {
-    case CODEC_INIT ... CODEC_ENCODE_AUDIO:
-        data_buf = maru_brill_codec_store_inbuf((uint8_t *)s->vaddr, ioparam);
-        break;
-    default:
-        TRACE("no buffer from guest\n");
-        break;
-    }
-
-    elem->data_buf = data_buf;
-
-    qemu_mutex_lock(&s->ioparam_queue_mutex);
-    QTAILQ_INSERT_TAIL(&codec_rq, elem, node);
-    qemu_mutex_unlock(&s->ioparam_queue_mutex);
-}
-
-static void *maru_brill_codec_store_inbuf(uint8_t *mem_base,
-                                        CodecParam *ioparam)
-{
-    DeviceMemEntry *elem = NULL;
-    int readbuf_size, size = 0;
-    uint8_t *readbuf = NULL;
-    uint8_t *device_mem = mem_base + ioparam->mem_offset;
-
-    elem = g_malloc0(sizeof(DeviceMemEntry));
-    if (!elem) {
-        ERR("failed to allocate readqueue node. size: %d\n",
-            sizeof(DeviceMemEntry));
-        return NULL;
-    }
-
-    memcpy(&readbuf_size, device_mem, sizeof(readbuf_size));
-    size = sizeof(readbuf_size);
-
-    TRACE("readbuf size: %d\n", readbuf_size);
-    if (readbuf_size <= 0) {
-        TRACE("inbuf size is 0. api_id %d, ctx_id %d, mem_offset %x\n",
-            ioparam->api_index, ioparam->ctx_index, ioparam->mem_offset);
-    } else {
-        readbuf = g_malloc0(readbuf_size);
-        if (!readbuf) {
-            ERR("failed to allocate a read buffer. size: %d\n", readbuf_size);
-        } else {
-            TRACE("copy input buffer from guest. ctx_id: %d, mem_offset: %x\n",
-                ioparam->ctx_index, ioparam->mem_offset);
-            memcpy(readbuf, device_mem + size, readbuf_size);
-        }
-    }
-    // memset(device_mem, 0x00, sizeof(readbuf_size));
-
-    elem->opaque = readbuf;
-    elem->data_size = readbuf_size;
-    elem->ctx_id = ioparam->ctx_index;
-
-    return elem;
-}
-
-static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
-                                            size_t data_size, int ctx_id,
-                                            DataHandler *handler)
-{
-    DeviceMemEntry *elem = NULL;
-    elem = g_malloc0(sizeof(DeviceMemEntry));
-
-    elem->opaque = opaque;
-    elem->data_size = data_size;
-    elem->ctx_id = ctx_id;
-
-    if (handler) {
-        elem->handler = handler;
-    } else {
-        elem->handler = &default_data_handler;
-    }
-
-    qemu_mutex_lock(&s->context_queue_mutex);
-    QTAILQ_INSERT_TAIL(&codec_wq, elem, node);
-    qemu_mutex_unlock(&s->context_queue_mutex);
-}
-
-static void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
-{
-    DeviceMemEntry *elem = NULL;
-    uint32_t mem_offset = 0;
-
-    TRACE("enter: %s\n", __func__);
-
-    if (ctx_idx < 1 || ctx_idx > (CODEC_CONTEXT_MAX - 1)) {
-        ERR("invalid buffer index. %d\n", ctx_idx);
-        return;
-    }
-
-    TRACE("pop_writeqeue. context index: %d\n", ctx_idx);
-    elem = entry[ctx_idx];
-    if (elem) {
-        mem_offset = s->ioparam.mem_offset;
-
-        // check corrupted mem_offset
-        if (mem_offset < CODEC_MEM_SIZE) {
-            elem->handler->get_data(s->vaddr + mem_offset, elem->opaque, elem->data_size);
-            elem->handler->release(elem->opaque);
-        } else {
-            TRACE("mem_offset is corrupted!!\n");
-        }
-
-        TRACE("pop_writequeue. release elem: %p\n", elem);
-        g_free(elem);
-
-        entry[ctx_idx] = NULL;
-    } else {
-        TRACE("there is no buffer to copy data to guest\n");
-    }
-
-    TRACE("leave: %s\n", __func__);
-}
-
-static void serialize_video_data(const struct video_data *video,
-                                AVCodecContext *avctx)
-{
-    if (video->width) {
-        avctx->width = video->width;
-    }
-    if (video->height) {
-        avctx->height = video->height;
-    }
-    if (video->fps_n) {
-        avctx->time_base.num = video->fps_n;
-    }
-    if (video->fps_d) {
-        avctx->time_base.den = video->fps_d;
-    }
-    if (video->pix_fmt > PIX_FMT_NONE) {
-        avctx->pix_fmt = video->pix_fmt;
-    }
-    if (video->par_n) {
-        avctx->sample_aspect_ratio.num = video->par_n;
-    }
-    if (video->par_d) {
-        avctx->sample_aspect_ratio.den = video->par_d;
-    }
-    if (video->bpp) {
-        avctx->bits_per_coded_sample = video->bpp;
-    }
-    if (video->ticks_per_frame) {
-        avctx->ticks_per_frame = video->ticks_per_frame;
-    }
-
-    INFO("codec_init. video, resolution: %dx%d, framerate: %d/%d "
-        "pixel_fmt: %d sample_aspect_ratio: %d/%d bpp %d\n",
-        avctx->width, avctx->height, avctx->time_base.num,
-        avctx->time_base.den, avctx->pix_fmt, avctx->sample_aspect_ratio.num,
-        avctx->sample_aspect_ratio.den, avctx->bits_per_coded_sample);
-}
-
-static void deserialize_video_data (const AVCodecContext *avctx,
-                                    struct video_data *video)
-{
-    memset(video, 0x00, sizeof(struct video_data));
-
-    video->width = avctx->width;
-    video->height = avctx->height;
-    video->fps_n = avctx->time_base.num;
-    video->fps_d = avctx->time_base.den;
-    video->pix_fmt = avctx->pix_fmt;
-    video->par_n = avctx->sample_aspect_ratio.num;
-    video->par_d = avctx->sample_aspect_ratio.den;
-    video->bpp = avctx->bits_per_coded_sample;
-    video->ticks_per_frame = avctx->ticks_per_frame;
-}
-
-static void serialize_audio_data (const struct audio_data *audio,
-                                  AVCodecContext *avctx)
-{
-    if (audio->channels) {
-        avctx->channels = audio->channels;
-    }
-    if (audio->sample_rate) {
-        avctx->sample_rate = audio->sample_rate;
-    }
-    if (audio->block_align) {
-        avctx->block_align = audio->block_align;
-    }
-
-    if (audio->sample_fmt > AV_SAMPLE_FMT_NONE) {
-        avctx->sample_fmt = audio->sample_fmt;
-    }
-
-    INFO("codec_init. audio, channel %d sample_rate %d sample_fmt %d ch_layout %lld\n",
-        avctx->channels, avctx->sample_rate, avctx->sample_fmt, avctx->channel_layout);
-}
-
-#if 0
-static void maru_brill_codec_reset_parser_info(MaruBrillCodecState *s, int32_t ctx_index)
-{
-    s->context[ctx_index].parser_buf = NULL;
-    s->context[ctx_index].parser_use = false;
-}
-#endif
-
-static void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t context_id)
-{
-    DeviceMemEntry *wq_elem = NULL, *wnext = NULL;
-    CodecDataStg *rq_elem = NULL, *rnext = NULL;
-
-    TRACE("enter: %s\n", __func__);
-
-    TRACE("release %d of context\n", context_id);
-
-    qemu_mutex_lock(&s->threadpool.mutex);
-    if (s->context[context_id].opened_context) {
-        // qemu_mutex_unlock(&s->threadpool.mutex);
-        codec_deinit(s, context_id, NULL);
-        // qemu_mutex_lock(&s->threadpool.mutex);
-    }
-    s->context[context_id].occupied_context = false;
-    qemu_mutex_unlock(&s->threadpool.mutex);
-
-    // TODO: check if foreach statment needs lock or not.
-    QTAILQ_FOREACH_SAFE(rq_elem, &codec_rq, node, rnext) {
-        if (rq_elem && rq_elem->data_buf &&
-            (rq_elem->data_buf->ctx_id == context_id)) {
-
-            TRACE("remove unused node from codec_rq. ctx_id: %d\n", context_id);
-            qemu_mutex_lock(&s->context_queue_mutex);
-            QTAILQ_REMOVE(&codec_rq, rq_elem, node);
-            qemu_mutex_unlock(&s->context_queue_mutex);
-            if (rq_elem && rq_elem->data_buf) {
-                TRACE("release rq_buffer: %p\n", rq_elem->data_buf);
-                g_free(rq_elem->data_buf);
-            }
-
-            TRACE("release rq_elem: %p\n", rq_elem);
-            g_free(rq_elem);
-        } else {
-            TRACE("no elem of %d context in the codec_rq.\n", context_id);
-        }
-    }
-
-    QTAILQ_FOREACH_SAFE(wq_elem, &codec_wq, node, wnext) {
-        if (wq_elem && wq_elem->ctx_id == context_id) {
-            TRACE("remove unused node from codec_wq. ctx_id: %d\n", context_id);
-            qemu_mutex_lock(&s->context_queue_mutex);
-            QTAILQ_REMOVE(&codec_wq, wq_elem, node);
-            qemu_mutex_unlock(&s->context_queue_mutex);
-
-            if (wq_elem && wq_elem->opaque) {
-                TRACE("release wq_buffer: %p\n", wq_elem->opaque);
-                g_free(wq_elem->opaque);
-                wq_elem->opaque = NULL;
-            }
-
-            TRACE("release wq_elem: %p\n", wq_elem);
-            g_free(wq_elem);
-        } else {
-            TRACE("no elem of %d context in the codec_wq.\n", context_id);
-        }
-    }
-
-    TRACE("leave: %s\n", __func__);
-}
-
-
-// initialize each pixel format.
-static void maru_brill_codec_pixfmt_info_init(void)
-{
-    /* YUV formats */
-    pix_fmt_info[PIX_FMT_YUV420P].x_chroma_shift = 1;
-    pix_fmt_info[PIX_FMT_YUV420P].y_chroma_shift = 1;
-
-    pix_fmt_info[PIX_FMT_YUV422P].x_chroma_shift = 1;
-    pix_fmt_info[PIX_FMT_YUV422P].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_YUV444P].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_YUV444P].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_YUYV422].x_chroma_shift = 1;
-    pix_fmt_info[PIX_FMT_YUYV422].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_YUV410P].x_chroma_shift = 2;
-    pix_fmt_info[PIX_FMT_YUV410P].y_chroma_shift = 2;
-
-    pix_fmt_info[PIX_FMT_YUV411P].x_chroma_shift = 2;
-    pix_fmt_info[PIX_FMT_YUV411P].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_YUVJ420P].x_chroma_shift = 1;
-    pix_fmt_info[PIX_FMT_YUVJ420P].y_chroma_shift = 1;
-
-    pix_fmt_info[PIX_FMT_YUVJ422P].x_chroma_shift = 1;
-    pix_fmt_info[PIX_FMT_YUVJ422P].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_YUVJ444P].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_YUVJ444P].y_chroma_shift = 0;
-
-    /* RGB formats */
-    pix_fmt_info[PIX_FMT_RGB24].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_RGB24].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_BGR24].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_BGR24].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_RGB32].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_RGB32].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_RGB565].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_RGB565].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_RGB555].x_chroma_shift = 0;
-    pix_fmt_info[PIX_FMT_RGB555].y_chroma_shift = 0;
-
-    pix_fmt_info[PIX_FMT_YUVA420P].x_chroma_shift = 1;
-    pix_fmt_info[PIX_FMT_YUVA420P].y_chroma_shift = 1;
-}
-
-static int maru_brill_codec_query_list (MaruBrillCodecState *s)
-{
-    AVCodec *codec = NULL;
-    uint32_t size = 0, mem_size = 0;
-    uint32_t data_len = 0, length = 0;
-    int32_t codec_type, media_type;
-    int32_t codec_fmts[4], i;
-
-    /* register avcodec */
-    TRACE("register avcodec\n");
-    av_register_all();
-
-    codec = av_codec_next(NULL);
-    if (!codec) {
-        ERR("failed to get codec info.\n");
-        return -1;
-    }
-
-    // a region to store the number of codecs.
-    length = 32 + 64 + 6 * sizeof(int32_t);
-    mem_size = size = sizeof(uint32_t);
-
-    while (codec) {
-        codec_type =
-            codec->decode ? CODEC_TYPE_DECODE : CODEC_TYPE_ENCODE;
-        media_type = codec->type;
-
-        memset(codec_fmts, -1, sizeof(codec_fmts));
-        if (media_type == AVMEDIA_TYPE_VIDEO) {
-            if (codec->pix_fmts) {
-                for (i = 0; codec->pix_fmts[i] != -1 && i < 4; i++) {
-                    codec_fmts[i] = codec->pix_fmts[i];
-                }
-            }
-        } else if (media_type == AVMEDIA_TYPE_AUDIO) {
-            if (codec->sample_fmts) {
-                for (i = 0; codec->sample_fmts[i] != -1; i++) {
-                    codec_fmts[i] = codec->sample_fmts[i];
-                }
-            }
-        } else {
-            ERR("unknown media type: %d\n", media_type);
-        }
-
-        memset(s->vaddr + mem_size, 0x00, length);
-        mem_size += length;
-
-        data_len += length;
-        memcpy(s->vaddr, &data_len, sizeof(data_len));
-
-        memcpy(s->vaddr + size, &codec_type, sizeof(codec_type));
-        size += sizeof(codec_type);
-        memcpy(s->vaddr + size, &media_type, sizeof(media_type));
-        size += sizeof(media_type);
-        memcpy(s->vaddr + size, codec->name, strlen(codec->name));
-        size += 32;
-        memcpy(s->vaddr + size,
-           codec->long_name, strlen(codec->long_name));
-        size += 64;
-        memcpy(s->vaddr + size, codec_fmts, sizeof(codec_fmts));
-        size += sizeof(codec_fmts);
-
-        codec = av_codec_next(codec);
-    }
-
-    return 0;
-}
-
-static int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
-{
-    int index;
-
-    TRACE("enter: %s\n", __func__);
-
-    // requires mutex_lock? its function is protected by critical section.
-    qemu_mutex_lock(&s->threadpool.mutex);
-    for (index = 1; index < CODEC_CONTEXT_MAX; index++) {
-        if (s->context[index].occupied_context == false) {
-            TRACE("get %d of codec context successfully.\n", index);
-            s->context[index].occupied_context = true;
-            break;
-        }
-    }
-    qemu_mutex_unlock(&s->threadpool.mutex);
-
-    if (index == CODEC_CONTEXT_MAX) {
-        ERR("failed to get available codec context. ");
-        ERR("try to run codec again.\n");
-        index = -1;
-    }
-
-    TRACE("leave: %s\n", __func__);
-
-    return index;
-}
-
-
-// allocate avcontext and avframe struct.
-static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, int index)
-{
-    TRACE("enter: %s\n", __func__);
-
-    TRACE("allocate %d of context and frame.\n", index);
-    s->context[index].avctx = avcodec_alloc_context3(NULL);
-    s->context[index].frame = avcodec_alloc_frame();
-    s->context[index].opened_context = false;
-#if 0
-    s->context[index].parser_buf = NULL;
-    s->context[index].parser_use = false;
-#endif
-    TRACE("leave: %s\n", __func__);
-
-    return s->context[index].avctx;
-}
-
-static AVCodec *maru_brill_codec_find_avcodec(uint8_t *mem_buf)
-{
-    AVCodec *codec = NULL;
-    int32_t encode, size = 0;
-    char codec_name[32] = {0, };
-
-    memcpy(&encode, mem_buf, sizeof(encode));
-    size = sizeof(encode);
-    memcpy(codec_name, mem_buf + size, sizeof(codec_name));
-    size += sizeof(codec_name);
-
-    TRACE("type: %d, name: %s\n", encode, codec_name);
-
-    if (encode) {
-        codec = avcodec_find_encoder_by_name (codec_name);
-    } else {
-        codec = avcodec_find_decoder_by_name (codec_name);
-    }
-    INFO("%s!! find %s %s\n", codec ? "success" : "failure",
-        codec_name, encode ? "encoder" : "decoder");
-
-    return codec;
-}
-
-static void read_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
-{
-    struct video_data video = { 0, };
-    struct audio_data audio = { 0, };
-    int bitrate = 0, size = 0;
-
-    memcpy(&video, mem_buf + size, sizeof(video));
-    size = sizeof(video);
-    serialize_video_data(&video, avctx);
-
-    memcpy(&audio, mem_buf + size, sizeof(audio));
-    size += sizeof(audio);
-    serialize_audio_data(&audio, avctx);
-
-    memcpy(&bitrate, mem_buf + size, sizeof(bitrate));
-    size += sizeof(bitrate);
-    if (bitrate) {
-        avctx->bit_rate = bitrate;
-    }
-
-    memcpy(&avctx->codec_tag, mem_buf + size, sizeof(avctx->codec_tag));
-    size += sizeof(avctx->codec_tag);
-    memcpy(&avctx->extradata_size,
-            mem_buf + size, sizeof(avctx->extradata_size));
-    size += sizeof(avctx->extradata_size);
-    INFO("extradata size: %d.\n", avctx->extradata_size);
-
-    if (avctx->extradata_size > 0) {
-        avctx->extradata =
-            av_mallocz(ROUND_UP_X(avctx->extradata_size +
-                        FF_INPUT_BUFFER_PADDING_SIZE, 4));
-        if (avctx->extradata) {
-            memcpy(avctx->extradata, mem_buf + size, avctx->extradata_size);
-        }
-    } else {
-        TRACE("no extra data.\n");
-        avctx->extradata =
-            av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
-    }
-}
-
-// write the result of codec_init
-static int write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
-{
-    int size = 0;
-
-    if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
-        int osize = av_get_bytes_per_sample(avctx->sample_fmt);
-
-        INFO("avcodec_open. sample_fmt %d, bytes_per_sample %d\n", avctx->sample_fmt, osize);
-
-        if ((avctx->codec_id == AV_CODEC_ID_AAC) && avctx->codec->encode2) {
-            osize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
-        }
-        memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
-        size = sizeof(avctx->sample_fmt);
-
-        // frame_size: samples per packet, initialized when calling 'init'
-        memcpy(mem_buf + size, &avctx->frame_size, sizeof(avctx->frame_size));
-        size += sizeof(avctx->frame_size);
-
-        memcpy(mem_buf + size, &osize, sizeof(osize));
-        size += sizeof(osize);
-    }
-
-    return size;
-}
-
-static uint8_t *resample_audio_buffer(AVCodecContext * avctx, AVFrame *samples,
-                                    int *out_size, int out_sample_fmt)
-{
-    AVAudioResampleContext *avr = NULL;
-    uint8_t *resampled_audio = NULL;
-    int buffer_size = 0, out_linesize = 0;
-    int nb_samples = samples->nb_samples;
-    // int out_sample_fmt = avctx->sample_fmt - 5;
-
-    avr = avresample_alloc_context();
-    if (!avr) {
-        ERR("failed to allocate avresample context\n");
-        return NULL;
-    }
-
-    TRACE("resample audio. channel_layout %lld sample_rate %d "
-        "in_sample_fmt %d out_sample_fmt %d\n",
-        avctx->channel_layout, avctx->sample_rate,
-        avctx->sample_fmt, out_sample_fmt);
-
-    av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
-    av_opt_set_int(avr, "in_sample_fmt", avctx->sample_fmt, 0);
-    av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
-    av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
-    av_opt_set_int(avr, "out_sample_fmt", out_sample_fmt, 0);
-    av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
-
-    TRACE("open avresample context\n");
-    if (avresample_open(avr) < 0) {
-        ERR("failed to open avresample context\n");
-        avresample_free(&avr);
-        return NULL;
-    }
-
-    *out_size =
-        av_samples_get_buffer_size(&out_linesize, avctx->channels,
-                                    nb_samples, out_sample_fmt, 0);
-
-    TRACE("resample audio. out_linesize %d nb_samples %d\n", out_linesize, nb_samples);
-
-    if (*out_size < 0) {
-        ERR("failed to get size of sample buffer %d\n", *out_size);
-        avresample_close(avr);
-        avresample_free(&avr);
-        return NULL;
-    }
-
-    resampled_audio = av_mallocz(*out_size);
-    if (!resampled_audio) {
-        ERR("failed to allocate resample buffer\n");
-        avresample_close(avr);
-        avresample_free(&avr);
-        return NULL;
-    }
-
-    buffer_size = avresample_convert(avr, &resampled_audio,
-        out_linesize, nb_samples,
-        samples->data, samples->linesize[0],
-        samples->nb_samples);
-    TRACE("resample_audio out_size %d buffer_size %d\n", *out_size, buffer_size);
-
-    avresample_close(avr);
-    avresample_free(&avr);
-
-    return resampled_audio;
-}
-
-// codec functions
-static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx = NULL;
-    AVCodec *codec = NULL;
-    int size = 0, ret = -1;
-    DeviceMemEntry *elem = NULL;
-    uint8_t *tempbuf = NULL;
-    int tempbuf_size = 0;
-
-    TRACE("enter: %s\n", __func__);
-
-    elem = (DeviceMemEntry *)data_buf;
-
-    // allocate AVCodecContext
-    avctx = maru_brill_codec_alloc_context(s, ctx_id);
-    if (!avctx) {
-        ERR("[%d] failed to allocate context.\n", __LINE__);
-        ret = -1;
-    } else {
-#if 0
-        avcodec_get_context_defaults3(avctx, NULL);
-
-        avctx->rc_strategy = 2;
-        avctx->b_frame_strategy = 0;
-        avctx->coder_type = 0;
-        avctx->context_model = 0;
-        avctx->scenechange_threshold = 0;
-
-        avctx->gop_size = DEFAULT_VIDEO_GOP_SIZE;
-        avctx->lmin = (2 * FF_QP2LAMBDA + 0.5);
-        avctx->lmax = (31 * FF_QP2LAMBDA + 0.5);
-#endif
-
-        codec = maru_brill_codec_find_avcodec(elem->opaque);
-        if (codec) {
-            size = sizeof(int32_t) + 32; // buffer size of codec_name
-            read_codec_init_data(avctx, elem->opaque + size);
-
-            // in case of aac encoder, sample format is float
-            if (!strcmp(codec->name, "aac") && codec->encode2) {
-                TRACE("convert sample format into SAMPLE_FMT_FLTP\n");
-                avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
-
-                avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
-
-                INFO("aac encoder!! channels %d channel_layout %lld\n", avctx->channels, avctx->channel_layout);
-                avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
-            }
-
-            TRACE("audio sample format %d\n", avctx->sample_fmt);
-            TRACE("strict_std_compliance %d\n", avctx->strict_std_compliance);
-
-            ret = avcodec_open2(avctx, codec, NULL);
-            INFO("avcodec_open. ret 0x%x ctx_id %d\n", ret, ctx_id);
-
-            TRACE("channels %d sample_rate %d sample_fmt %d "
-                "channel_layout %lld frame_size %d\n",
-                avctx->channels, avctx->sample_rate, avctx->sample_fmt,
-                avctx->channel_layout, avctx->frame_size);
-
-            tempbuf_size = (sizeof(avctx->sample_fmt) + sizeof(avctx->frame_size)
-                           + sizeof(avctx->extradata_size) + avctx->extradata_size)
-                           + sizeof(int);
-
-            s->context[ctx_id].opened_context = true;
-            s->context[ctx_id].parser_ctx =
-                maru_brill_codec_parser_init(avctx);
-        } else {
-            ERR("failed to find codec. ctx_id: %d\n", ctx_id);
-            ret = -1;
-        }
-    }
-
-    tempbuf_size += sizeof(ret);
-
-    tempbuf = g_malloc(tempbuf_size);
-    if (!tempbuf) {
-        ERR("failed to allocate a buffer\n");
-        tempbuf_size = 0;
-    } else {
-        memcpy(tempbuf, &ret, sizeof(ret));
-        size = sizeof(ret);
-        if (ret < 0) {
-            ERR("failed to open codec contex.\n");
-        } else {
-            size += write_codec_init_data(avctx, tempbuf + size);
-            TRACE("codec_init. copyback!! size %d\n", size);
-            {
-                memcpy(tempbuf + size, &avctx->extradata_size, sizeof(avctx->extradata_size));
-                size += sizeof(avctx->extradata_size);
-
-                INFO("codec_init. extradata_size: %d\n", avctx->extradata_size);
-                if (avctx->extradata) {
-                    memcpy(tempbuf + size, avctx->extradata, avctx->extradata_size);
-                    size += avctx->extradata_size;
-                }
-            }
-        }
-    }
-
-    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
-
-    TRACE("leave: %s\n", __func__);
-
-    return true;
-}
-
-static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx = NULL;
-    AVFrame *frame = NULL;
-    AVCodecParserContext *parserctx = NULL;
-
-    TRACE("enter: %s\n", __func__);
-
-    avctx = s->context[ctx_id].avctx;
-    frame = s->context[ctx_id].frame;
-    parserctx = s->context[ctx_id].parser_ctx;
-    if (!avctx || !frame) {
-        TRACE("%d of AVCodecContext or AVFrame is NULL. "
-            " Those resources have been released before.\n", ctx_id);
-        return false;
-    }
-
-    INFO("close avcontext of %d\n", ctx_id);
-    // qemu_mutex_lock(&s->threadpool.mutex);
-    avcodec_close(avctx);
-    s->context[ctx_id].opened_context = false;
-    // qemu_mutex_unlock(&s->threadpool.mutex);
-
-    if (avctx->extradata) {
-        TRACE("free context extradata\n");
-        av_free(avctx->extradata);
-        s->context[ctx_id].avctx->extradata = NULL;
-    }
-
-    if (frame) {
-        TRACE("free frame\n");
-        // av_free(frame);
-        avcodec_free_frame(&frame);
-        s->context[ctx_id].frame = NULL;
-    }
-
-    if (avctx) {
-        TRACE("free codec context\n");
-        av_free(avctx);
-        s->context[ctx_id].avctx = NULL;
-    }
-
-    if (parserctx) {
-        av_parser_close(parserctx);
-        s->context[ctx_id].parser_ctx = NULL;
-    }
-
-    maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
-
-    TRACE("leave: %s\n", __func__);
-
-    return true;
-}
-
-static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx = NULL;
-    bool ret = true;
-
-    TRACE("enter: %s\n", __func__);
-
-    avctx = s->context[ctx_id].avctx;
-    if (!avctx) {
-        ERR("%d of AVCodecContext is NULL.\n", ctx_id);
-        ret = false;
-    } else if (!avctx->codec) {
-        ERR("%d of AVCodec is NULL.\n", ctx_id);
-        ret = false;
-    } else {
-        TRACE("flush %d context of buffers.\n", ctx_id);
-        avcodec_flush_buffers(avctx);
-    }
-
-    maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
-
-    TRACE("leave: %s\n", __func__);
-
-    return ret;
-}
-
-static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx = NULL;
-    AVFrame *picture = NULL;
-    AVPacket avpkt;
-    int got_picture = 0, len = -1;
-    uint8_t *inbuf = NULL;
-    int inbuf_size = 0, idx, size = 0;
-    int64_t in_offset;
-    DeviceMemEntry *elem = NULL;
-    uint8_t *tempbuf = NULL;
-    int tempbuf_size = 0;
-
-    TRACE("enter: %s\n", __func__);
-
-    elem = (DeviceMemEntry *)data_buf;
-    if (elem && elem->opaque) {
-        memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
-        size += sizeof(inbuf_size);
-        memcpy(&idx, elem->opaque + size, sizeof(idx));
-        size += sizeof(idx);
-        memcpy(&in_offset, elem->opaque + size, sizeof(in_offset));
-        size += sizeof(in_offset);
-        TRACE("decode_video. inbuf_size %d\n", inbuf_size);
-
-        if (inbuf_size > 0) {
-            inbuf = elem->opaque + size;
-        }
-    } else {
-        TRACE("decode_video. no input buffer\n");
-        // FIXME: improve error handling
-        // return false;
-    }
-
-    av_init_packet(&avpkt);
-    avpkt.data = inbuf;
-    avpkt.size = inbuf_size;
-
-    avctx = s->context[ctx_id].avctx;
-    picture = s->context[ctx_id].frame;
-    if (!avctx) {
-        ERR("decode_video. %d of AVCodecContext is NULL.\n", ctx_id);
-    } else if (!avctx->codec) {
-        ERR("decode_video. %d of AVCodec is NULL.\n", ctx_id);
-    } else if (!picture) {
-        ERR("decode_video. %d of AVFrame is NULL.\n", ctx_id);
-    } else {
-        // in case of skipping frames
-        // picture->pict_type = -1;
-
-        TRACE("decode_video. bitrate %d\n", avctx->bit_rate);
-        // avctx->reordered_opaque = idx;
-        // picture->reordered_opaque = idx;
-
-        len =
-            avcodec_decode_video2(avctx, picture, &got_picture, &avpkt);
-        TRACE("decode_video. in_size %d len %d, frame_size %d\n", avpkt.size, len, got_picture);
-    }
-
-    tempbuf_size =
-            sizeof(len) + sizeof(got_picture) + sizeof(struct video_data);
-
-    if (len < 0) {
-        ERR("failed to decode video. ctx_id: %d, len: %d\n", ctx_id, len);
-        got_picture = 0;
-    }
-
-    tempbuf = g_malloc(tempbuf_size);
-    if (!tempbuf) {
-        ERR("failed to allocate decoded audio buffer\n");
-        // FIXME: how to handle this case?
-    } else {
-        struct video_data video;
-
-        memcpy(tempbuf, &len, sizeof(len));
-        size = sizeof(len);
-        memcpy(tempbuf + size, &got_picture, sizeof(got_picture));
-        size += sizeof(got_picture);
-        if (avctx) {
-
-            avctx->pix_fmt = AV_PIX_FMT_YUV420P;
-            //avctx->pix_fmt = AV_PIX_FMT_;
-
-            deserialize_video_data(avctx, &video);
-            memcpy(tempbuf + size, &video, sizeof(struct video_data));
-        }
-    }
-
-    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
-
-    TRACE("leave: %s\n", __func__);
-
-    return true;
-}
-
-
-static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
-{
-    AVCodecContext *avctx = NULL;
-    AVPicture *src = NULL;
-    int pict_size = 0;
-    bool ret = true;
-
-    TRACE("enter: %s\n", __func__);
-
-    TRACE("copy decoded image of %d context.\n", ctx_id);
-
-    avctx = s->context[ctx_id].avctx;
-    src = (AVPicture *)s->context[ctx_id].frame;
-    if (!avctx) {
-        ERR("picture_copy. %d of AVCodecContext is NULL.\n", ctx_id);
-        ret = false;
-    } else if (!avctx->codec) {
-        ERR("picture_copy. %d of AVCodec is NULL.\n", ctx_id);
-        ret = false;
-    } else if (!src) {
-        ERR("picture_copy. %d of AVFrame is NULL.\n", ctx_id);
-        ret = false;
-    } else {
-        TRACE("decoded image. pix_fmt: %d width: %d, height: %d\n",
-                avctx->pix_fmt, avctx->width, avctx->height);
-        pict_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
-
-        if ((pict_size) < 0) {
-            ERR("picture size: %d\n", pict_size);
-            ret = false;
-        } else {
-            TRACE("picture size: %d\n", pict_size);
-            maru_brill_codec_push_writequeue(s, src, pict_size, ctx_id, &default_video_decode_data_handler);
-        }
-    }
-
-    TRACE("leave: %s\n", __func__);
-
-    return ret;
-}
-
-static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx;
-    AVPacket avpkt;
-    AVFrame *audio_out = NULL;
-    uint8_t *inbuf = NULL;
-    int inbuf_size = 0, size = 0;
-    int len = -1, got_frame = 0;
-
-    DeviceMemEntry *elem = NULL;
-    uint8_t *tempbuf = NULL;
-    int tempbuf_size = 0;
-
-    uint8_t *out_buf = NULL;
-    int out_buf_size = 0;
-    int out_sample_fmt = -1;
-
-    TRACE("enter: %s\n", __func__);
-
-    elem = (DeviceMemEntry *)data_buf;
-    if (elem && elem->opaque) {
-        memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
-        size = sizeof(inbuf_size);
-        TRACE("decode_audio. inbuf_size %d\n", inbuf_size);
-
-        if (inbuf_size > 0) {
-            inbuf = elem->opaque + size;
-        }
-    } else {
-        ERR("decode_audio. no input buffer\n");
-        // FIXME: improve error handling
-        // return false;
-    }
-
-    av_init_packet(&avpkt);
-    avpkt.data = inbuf;
-    avpkt.size = inbuf_size;
-
-    avctx = s->context[ctx_id].avctx;
-    // audio_out = s->context[ctx_id].frame;
-    audio_out = avcodec_alloc_frame();
-    if (!avctx) {
-        ERR("decode_audio. %d of AVCodecContext is NULL\n", ctx_id);
-    } else if (!avctx->codec) {
-        ERR("decode_audio. %d of AVCodec is NULL\n", ctx_id);
-    } else if (!audio_out) {
-        ERR("decode_audio. %d of AVFrame is NULL\n", ctx_id);
-    } else {
-        // avcodec_get_frame_defaults(audio_out);
-
-        len = avcodec_decode_audio4(avctx, audio_out, &got_frame, &avpkt);
-        TRACE("decode_audio. len %d, channel_layout %lld, got_frame %d\n",
-            len, avctx->channel_layout, got_frame);
-        if (got_frame) {
-            if (av_sample_fmt_is_planar(avctx->sample_fmt)) {
-                // convert PLANAR to LINEAR format
-                out_sample_fmt = avctx->sample_fmt - 5;
-
-                out_buf = resample_audio_buffer(avctx, audio_out, &out_buf_size, out_sample_fmt);
-            } else {
-                // TODO: not planar format
-                INFO("decode_audio. cannot handle planar audio format\n");
-                len = -1;
-            }
-        }
-    }
-
-    tempbuf_size = (sizeof(len) + sizeof(got_frame));
-    if (len < 0) {
-        ERR("failed to decode audio. ctx_id: %d len: %d got_frame: %d\n",
-            ctx_id, len, got_frame);
-        got_frame = 0;
-    } else {
-        tempbuf_size += (sizeof(out_sample_fmt) + sizeof(avctx->sample_rate)
-                        + sizeof(avctx->channels) +  sizeof(avctx->channel_layout)
-                        + sizeof(out_buf_size) + out_buf_size);
-    }
-
-    tempbuf = g_malloc(tempbuf_size);
-    if (!tempbuf) {
-        ERR("failed to allocate decoded audio buffer\n");
-    } else {
-        memcpy(tempbuf, &len, sizeof(len));
-        size = sizeof(len);
-        memcpy(tempbuf + size, &got_frame, sizeof(got_frame));
-        size += sizeof(got_frame);
-        if (got_frame) {
-            memcpy(tempbuf + size, &out_sample_fmt, sizeof(out_sample_fmt));
-            size += sizeof(out_sample_fmt);
-            memcpy(tempbuf + size, &avctx->sample_rate, sizeof(avctx->sample_rate));
-            size += sizeof(avctx->sample_rate);
-            memcpy(tempbuf + size, &avctx->channels, sizeof(avctx->channels));
-            size += sizeof(avctx->channels);
-            memcpy(tempbuf + size, &avctx->channel_layout, sizeof(avctx->channel_layout));
-            size += sizeof(avctx->channel_layout);
-
-            memcpy(tempbuf + size, &out_buf_size, sizeof(out_buf_size));
-            size += sizeof(out_buf_size);
-            if (out_buf) {
-                TRACE("copy resampled audio buffer\n");
-                memcpy(tempbuf + size, out_buf, out_buf_size);
-            }
-        }
-    }
-
-    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
-
-    if (audio_out) {
-        avcodec_free_frame(&audio_out);
-    }
-
-    if (out_buf) {
-        TRACE("and release decoded_audio buffer\n");
-        av_free(out_buf);
-    }
-
-
-    TRACE("leave: %s\n", __func__);
-    return true;
-}
-
-static bool codec_encode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx = NULL;
-    AVFrame *pict = NULL;
-    AVPacket avpkt;
-    uint8_t *inbuf = NULL, *outbuf = NULL;
-    int inbuf_size = 0, outbuf_size = 0;
-    int got_frame = 0, ret = 0, size = 0;
-    int64_t in_timestamp = 0;
-    int coded_frame = 0, key_frame = 0;
-
-    DeviceMemEntry *elem = NULL;
-    uint8_t *tempbuf = NULL;
-    int tempbuf_size = 0;
-
-    TRACE("enter: %s\n", __func__);
-
-    elem = (DeviceMemEntry *)data_buf;
-    if (elem && elem->opaque) {
-        memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
-        size += sizeof(inbuf_size);
-        memcpy(&in_timestamp, elem->opaque + size, sizeof(in_timestamp));
-        size += sizeof(in_timestamp);
-        TRACE("encode video. inbuf_size %d\n", inbuf_size);
-
-        if (inbuf_size > 0) {
-            inbuf = elem->opaque + size;
-        }
-    } else {
-        TRACE("encode video. no input buffer.\n");
-        // FIXME: improve error handling
-        // return false;
-    }
-
-    // initialize AVPacket
-    av_init_packet(&avpkt);
-    avpkt.data = NULL;
-    avpkt.size = 0;
-
-    avctx = s->context[ctx_id].avctx;
-    pict = s->context[ctx_id].frame;
-    if (!avctx || !pict) {
-        ERR("%d of context or frame is NULL\n", ctx_id);
-    } else if (!avctx->codec) {
-        ERR("%d of AVCodec is NULL.\n", ctx_id);
-    } else {
-        TRACE("pixel format: %d inbuf: %p, picture data: %p\n",
-            avctx->pix_fmt, inbuf, pict->data[0]);
-
-        ret = avpicture_fill((AVPicture *)pict, inbuf, avctx->pix_fmt,
-                            avctx->width, avctx->height);
-        if (ret < 0) {
-            ERR("after avpicture_fill, ret:%d\n", ret);
-        } else {
-            if (avctx->time_base.num == 0) {
-                pict->pts = AV_NOPTS_VALUE;
-            } else {
-                AVRational bq =
-                            {1, (G_USEC_PER_SEC * G_GINT64_CONSTANT(1000))};
-                pict->pts = av_rescale_q(in_timestamp, bq, avctx->time_base);
-            }
-            TRACE("encode video. ticks_per_frame:%d, pts:%lld\n",
-                avctx->ticks_per_frame, pict->pts);
-
-            outbuf_size =
-                (avctx->width * avctx->height * 6) + FF_MIN_BUFFER_SIZE;
-
-            outbuf = g_malloc0(outbuf_size);
-
-            avpkt.data = outbuf;
-            avpkt.size = outbuf_size;
-
-            if (!outbuf) {
-                ERR("failed to allocate a buffer of encoding video.\n");
-            } else {
-                ret = avcodec_encode_video2(avctx, &avpkt, pict, &got_frame);
-
-                TRACE("encode video. ret %d got_picture %d outbuf_size %d\n", ret, got_frame, avpkt.size);
-                if (avctx->coded_frame) {
-                    TRACE("encode video. keyframe %d\n", avctx->coded_frame->key_frame);
-                }
-            }
-        }
-    }
-
-    tempbuf_size = sizeof(ret);
-    if (ret < 0) {
-        ERR("failed to encode video. ctx_id %d ret %d\n", ctx_id, ret);
-    } else {
-        tempbuf_size += avpkt.size + sizeof(coded_frame) + sizeof(key_frame);
-    }
-
-    // write encoded video data
-    tempbuf = g_malloc0(tempbuf_size);
-    if (!tempbuf) {
-        ERR("encode video. failed to allocate encoded out buffer.\n");
-    } else {
-        memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
-        size = sizeof(avpkt.size);
-
-        if ((got_frame) && outbuf) {
-            // inform gstreamer plugin about the status of encoded frames
-            // A flag for output buffer in gstreamer is depending on the status.
-            if (avctx->coded_frame) {
-                coded_frame = 1;
-                // if key_frame is 0, this frame cannot be decoded independently.
-                key_frame = avctx->coded_frame->key_frame;
-            }
-            memcpy(tempbuf + size, &coded_frame, sizeof(coded_frame));
-            size += sizeof(coded_frame);
-            memcpy(tempbuf + size, &key_frame, sizeof(key_frame));
-            size += sizeof(key_frame);
-            memcpy(tempbuf + size, outbuf, avpkt.size);
-        }
-    }
-
-    if (outbuf) {
-        TRACE("release encoded output buffer. %p\n", outbuf);
-        g_free(outbuf);
-    }
-
-    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
-
-    TRACE("leave: %s\n", __func__);
-    return true;
-}
-
-static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
-    AVCodecContext *avctx = NULL;
-    AVPacket avpkt;
-    uint8_t *audio_in = NULL;
-    int32_t audio_in_size = 0;
-    int ret = 0, got_pkt = 0, size = 0;
-
-    DeviceMemEntry *elem = NULL;
-    uint8_t *tempbuf = NULL;
-    int tempbuf_size = 0;
-
-    AVFrame *in_frame = NULL;
-    AVFrame *resampled_frame = NULL;
-    uint8_t *samples = NULL;
-    int64_t in_timestamp = 0;
-
-    TRACE("enter: %s\n", __func__);
-
-    /*
-     *  copy raw audio data from gstreamer encoder plugin
-     *  audio_in_size: size of raw audio data
-     *  audio_in : raw audio data
-     */
-    elem = (DeviceMemEntry *)data_buf;
-    if (elem && elem->opaque) {
-        memcpy(&audio_in_size, elem->opaque, sizeof(audio_in_size));
-        size += sizeof(audio_in_size);
-
-        memcpy(&in_timestamp, elem->opaque + size, sizeof(in_timestamp));
-        size += sizeof(in_timestamp);
-
-        TRACE("encode_audio. audio_in_size %d\n", audio_in_size);
-        if (audio_in_size > 0) {
-            // audio_in = g_malloc0(audio_in_size);
-            // memcpy(audio_in, elem->buf + size, audio_in_size);
-            audio_in = elem->opaque + size;
-        }
-    } else {
-        TRACE("encode_audio. no input buffer\n");
-        // FIXME: improve error handling
-        // return false;
-    }
-
-    avctx = s->context[ctx_id].avctx;
-    if (!avctx) {
-        ERR("[%s] %d of Context is NULL!\n", __func__, ctx_id);
-    } else if (!avctx->codec) {
-        ERR("%d of AVCodec is NULL.\n", ctx_id);
-    } else {
-        int bytes_per_sample = 0;
-        int audio_in_buffer_size = 0;
-        int audio_in_sample_fmt = AV_SAMPLE_FMT_S16;
-
-        in_frame = avcodec_alloc_frame();
-        if (!in_frame) {
-            // FIXME: error handling
-            ERR("encode_audio. failed to allocate in_frame\n");
-            ret = -1;
-        }
-
-        bytes_per_sample = av_get_bytes_per_sample(audio_in_sample_fmt);
-        TRACE("bytes per sample %d, sample format %d\n", bytes_per_sample, audio_in_sample_fmt);
-
-        in_frame->nb_samples = audio_in_size / (bytes_per_sample * avctx->channels);
-        TRACE("in_frame->nb_samples %d\n", in_frame->nb_samples);
-
-        in_frame->format = audio_in_sample_fmt;
-        in_frame->channel_layout = avctx->channel_layout;
-
-        audio_in_buffer_size = av_samples_get_buffer_size(NULL, avctx->channels, avctx->frame_size, audio_in_sample_fmt, 0);
-        TRACE("audio_in_buffer_size: %d, audio_in_size %d\n", audio_in_buffer_size, audio_in_size);
-
-        {
-            samples = av_mallocz(audio_in_buffer_size);
-            memcpy(samples, audio_in, audio_in_size);
-
-            // g_free(audio_in);
-            // audio_in = NULL;
-
-            ret = avcodec_fill_audio_frame(in_frame, avctx->channels, AV_SAMPLE_FMT_S16, (const uint8_t *)samples, audio_in_size, 0);
-            TRACE("fill in_frame. ret: %d frame->ch_layout %lld\n", ret, in_frame->channel_layout);
-        }
-
-        {
-            AVAudioResampleContext *avr = NULL;
-            uint8_t *resampled_audio = NULL;
-            int resampled_buffer_size = 0, resampled_linesize = 0, convert_size;
-            int resampled_nb_samples = 0;
-            int resampled_sample_fmt = AV_SAMPLE_FMT_FLTP;
-
-            avr = avresample_alloc_context();
-
-            av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
-            av_opt_set_int(avr, "in_sample_fmt", audio_in_sample_fmt , 0);
-            av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
-            av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
-            av_opt_set_int(avr, "out_sample_fmt", resampled_sample_fmt, 0);
-            av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
-
-            resampled_nb_samples = in_frame->nb_samples; // av_get_bytes_per_samples(resampled_sample_fmt);
-
-            if (avresample_open(avr) < 0) {
-                ERR("failed to open avresample context\n");
-                avresample_free(&avr);
-            }
-
-            resampled_buffer_size = av_samples_get_buffer_size(&resampled_linesize, avctx->channels, resampled_nb_samples, resampled_sample_fmt, 0);
-            if (resampled_buffer_size < 0) {
-                ERR("failed to get size of sample buffer %d\n", resampled_buffer_size);
-                avresample_close(avr);
-                avresample_free(&avr);
-            }
-
-            TRACE("resampled nb_samples %d linesize %d out_size %d\n", resampled_nb_samples, resampled_linesize, resampled_buffer_size);
-
-            resampled_audio = av_mallocz(resampled_buffer_size);
-            if (!resampled_audio) {
-                ERR("failed to allocate resample buffer\n");
-                avresample_close(avr);
-                avresample_free(&avr);
-            }
-
-            // in_frame->nb_samples = nb_samples;
-            resampled_frame = avcodec_alloc_frame();
-            if (!resampled_frame) {
-                // FIXME: error handling
-                ERR("encode_audio. failed to allocate resampled_frame\n");
-                ret = -1;
-            }
-
-
-            bytes_per_sample = av_get_bytes_per_sample(audio_in_sample_fmt);
-            TRACE("bytes per sample %d, sample format %d\n", bytes_per_sample, audio_in_sample_fmt);
-
-            resampled_frame->nb_samples = in_frame->nb_samples;
-            TRACE("resampled_frame->nb_samples %d\n", resampled_frame->nb_samples);
-
-            resampled_frame->format = resampled_sample_fmt;
-            resampled_frame->channel_layout = avctx->channel_layout;
-
-            ret = avcodec_fill_audio_frame(resampled_frame, avctx->channels, resampled_sample_fmt,
-                    (const uint8_t *)resampled_audio, resampled_buffer_size, 0);
-            TRACE("fill resampled_frame ret: %d frame->ch_layout %lld\n", ret, in_frame->channel_layout);
-
-            convert_size = avresample_convert(avr, resampled_frame->data, resampled_buffer_size, resampled_nb_samples,
-                                        in_frame->data, audio_in_size, in_frame->nb_samples);
-
-            TRACE("resample_audio convert_size %d\n", convert_size);
-
-            avresample_close(avr);
-            avresample_free(&avr);
-        }
-
-        if (ret == 0) {
-            av_init_packet(&avpkt);
-            // packet data will be allocated by encoder
-            avpkt.data = NULL;
-            avpkt.size = 0;
-
-            ret = avcodec_encode_audio2(avctx, &avpkt, (const AVFrame *)resampled_frame, &got_pkt);
-            TRACE("encode audio. ret %d got_pkt %d avpkt.size %d frame_number %d coded_frame %p\n",
-                ret, got_pkt, avpkt.size, avctx->frame_number, avctx->coded_frame);
-        }
-    }
-
-    tempbuf_size = sizeof(ret);
-    if (ret < 0) {
-        ERR("failed to encode audio. ctx_id %d ret %d\n", ctx_id, ret);
-    } else {
-        // tempbuf_size += (max_size); // len;
-        tempbuf_size += (sizeof(avpkt.size) + avpkt.size);
-    }
-    TRACE("encode_audio. writequeue elem buffer size %d\n", tempbuf_size);
-
-    // write encoded audio data
-    tempbuf = g_malloc0(tempbuf_size);
-    if (!tempbuf) {
-        ERR("encode audio. failed to allocate encoded out buffer.\n");
-    } else {
-        memcpy(tempbuf, &ret, sizeof(ret));
-        size = sizeof(ret);
-        if (ret == 0) {
-            memcpy(tempbuf + size, &avpkt.size, sizeof(avpkt.size));
-            size += sizeof(avpkt.size);
-
-            if (got_pkt) {
-                memcpy(tempbuf + size, avpkt.data, avpkt.size);
-                av_free_packet(&avpkt);
-            }
-        }
-    }
-
-    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
-    if (in_frame) {
-        avcodec_free_frame(&in_frame);
-    }
-
-    if (resampled_frame) {
-        avcodec_free_frame(&resampled_frame);
-    }
-
-    TRACE("[%s] leave:\n", __func__);
-
-    return true;
-}
-
-static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx)
-{
-    AVCodecParserContext *parser = NULL;
-
-    if (!avctx) {
-        ERR("context is NULL\n");
-        return NULL;
-    }
-
-    switch (avctx->codec_id) {
-    case CODEC_ID_MPEG4:
-    case CODEC_ID_VC1:
-        TRACE("not using parser.\n");
-        break;
-    case CODEC_ID_H264:
-        if (avctx->extradata_size == 0) {
-            TRACE("H.264 with no extradata, creating parser.\n");
-            parser = av_parser_init (avctx->codec_id);
-        }
-        break;
-    default:
-        parser = av_parser_init (avctx->codec_id);
-        if (parser) {
-            INFO("using parser. %d\n", avctx->codec_id);
-        }
-        break;
-    }
-
-    return parser;
-}
-
-static void maru_brill_codec_bh_callback(void *opaque)
-{
-    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
-
-    TRACE("enter: %s\n", __func__);
-
-    qemu_mutex_lock(&s->context_queue_mutex);
-    if (!QTAILQ_EMPTY(&codec_wq)) {
-        qemu_mutex_unlock(&s->context_queue_mutex);
-
-        TRACE("raise irq\n");
-        pci_set_irq(&s->dev, 1);
-        s->irq_raised = 1;
-    } else {
-        qemu_mutex_unlock(&s->context_queue_mutex);
-        TRACE("codec_wq is empty!!\n");
-    }
-
-    TRACE("leave: %s\n", __func__);
-}
-
-/*
- *  Codec Device APIs
- */
-static uint64_t maru_brill_codec_read(void *opaque,
-                                        hwaddr addr,
-                                        unsigned size)
-{
-    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
-    uint64_t ret = 0;
-
-    switch (addr) {
-    case CODEC_CMD_GET_THREAD_STATE:
-        qemu_mutex_lock(&s->context_queue_mutex);
-        if (s->irq_raised) {
-            ret = CODEC_TASK_END;
-            pci_set_irq(&s->dev, 0);
-            s->irq_raised = 0;
-        }
-        qemu_mutex_unlock(&s->context_queue_mutex);
-
-        TRACE("get thread_state. ret: %d\n", ret);
-        break;
-
-    case CODEC_CMD_GET_CTX_FROM_QUEUE:
-    {
-        DeviceMemEntry *head = NULL;
-
-        qemu_mutex_lock(&s->context_queue_mutex);
-        head = QTAILQ_FIRST(&codec_wq);
-        if (head) {
-            ret = head->ctx_id;
-            QTAILQ_REMOVE(&codec_wq, head, node);
-            entry[ret] = head;
-            TRACE("get a elem from codec_wq. 0x%x\n", head);
-        } else {
-            ret = 0;
-        }
-        qemu_mutex_unlock(&s->context_queue_mutex);
-
-        TRACE("get a head from a writequeue. head: %x\n", ret);
-    }
-        break;
-
-    case CODEC_CMD_GET_VERSION:
-        ret = CODEC_VERSION;
-        TRACE("codec version: %d\n", ret);
-        break;
-
-    case CODEC_CMD_GET_ELEMENT:
-        ret = maru_brill_codec_query_list(s);
-        break;
-
-    case CODEC_CMD_GET_CONTEXT_INDEX:
-        ret = maru_brill_codec_get_context_index(s);
-        TRACE("get context index: %d\n", ret);
-        break;
-
-    default:
-        ERR("no avaiable command for read. %d\n", addr);
-    }
-
-    return ret;
-}
-
-static void maru_brill_codec_write(void *opaque, hwaddr addr,
-                                    uint64_t value, unsigned size)
-{
-    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
-
-    switch (addr) {
-    case CODEC_CMD_API_INDEX:
-        TRACE("set codec_cmd value: %d\n", value);
-        s->ioparam.api_index = value;
-        maru_brill_codec_wakeup_threads(s, value);
-        break;
-
-    case CODEC_CMD_CONTEXT_INDEX:
-        TRACE("set context_index value: %d\n", value);
-        s->ioparam.ctx_index = value;
-        break;
-
-    case CODEC_CMD_DEVICE_MEM_OFFSET:
-        TRACE("set mem_offset value: 0x%x\n", value);
-        s->ioparam.mem_offset = value;
-        break;
-
-    case CODEC_CMD_RELEASE_CONTEXT:
-    {
-        int ctx_index = (int32_t)value;
-
-        if (s->context[ctx_index].occupied_thread) {
-            s->context[ctx_index].requested_close = true;
-            INFO("make running thread to handle deinit\n");
-        } else {
-            maru_brill_codec_release_context(s, ctx_index);
-        }
-    }
-        break;
-
-    case CODEC_CMD_GET_DATA_FROM_QUEUE:
-        maru_brill_codec_pop_writequeue(s, (uint32_t)value);
-        break;
-
-    default:
-        ERR("no available command for write. %d\n", addr);
-    }
-}
-
-static const MemoryRegionOps maru_brill_codec_mmio_ops = {
-    .read = maru_brill_codec_read,
-    .write = maru_brill_codec_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-        .unaligned = false
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int maru_brill_codec_initfn(PCIDevice *dev)
-{
-    MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
-
-    INFO("device initialization.\n");
-    pci_config_set_interrupt_pin(pci_conf, 1);
-
-    memory_region_init_ram(&s->vram, OBJECT(s), "maru_brill_codec.vram", CODEC_MEM_SIZE);
-    s->vaddr = (uint8_t *)memory_region_get_ram_ptr(&s->vram);
-
-    memory_region_init_io(&s->mmio, OBJECT(s), &maru_brill_codec_mmio_ops, s,
-                        "maru_brill_codec.mmio", CODEC_REG_SIZE);
-
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
-    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
-
-    qemu_mutex_init(&s->context_mutex);
-    qemu_mutex_init(&s->context_queue_mutex);
-    qemu_mutex_init(&s->ioparam_queue_mutex);
-
-    maru_brill_codec_get_cpu_cores(s);
-    maru_brill_codec_threads_create(s);
-
-    // register a function to qemu bottom-halves to switch context.
-    s->codec_bh = qemu_bh_new(maru_brill_codec_bh_callback, s);
-
-    return 0;
-}
-
-static void maru_brill_codec_exitfn(PCIDevice *dev)
-{
-    MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
-    INFO("device exit\n");
-
-    qemu_mutex_destroy(&s->context_mutex);
-    qemu_mutex_destroy(&s->context_queue_mutex);
-    qemu_mutex_destroy(&s->ioparam_queue_mutex);
-
-    qemu_bh_delete(s->codec_bh);
-
-    memory_region_destroy(&s->vram);
-    memory_region_destroy(&s->mmio);
-}
-
-static void maru_brill_codec_reset(DeviceState *d)
-{
-    MaruBrillCodecState *s = (MaruBrillCodecState *)d;
-    INFO("device reset\n");
-
-    s->irq_raised = 0;
-
-    memset(&s->context, 0, sizeof(CodecContext) * CODEC_CONTEXT_MAX);
-    memset(&s->ioparam, 0, sizeof(CodecParam));
-
-    maru_brill_codec_pixfmt_info_init();
-}
-
-static void maru_brill_codec_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = maru_brill_codec_initfn;
-    k->exit = maru_brill_codec_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_TIZEN;
-    k->device_id = PCI_DEVICE_ID_VIRTUAL_BRILL_CODEC;
-    k->class_id = PCI_CLASS_OTHERS;
-    dc->reset = maru_brill_codec_reset;
-    dc->desc = "Virtual new codec device for Tizen emulator";
-}
-
-static TypeInfo codec_device_info = {
-    .name          = CODEC_DEVICE_NAME,
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(MaruBrillCodecState),
-    .class_init    = maru_brill_codec_class_init,
-};
-
-static void codec_register_types(void)
-{
-    type_register_static(&codec_device_info);
-}
-
-type_init(codec_register_types)
diff --git a/tizen/src/hw/pci/maru_brill_codec.h b/tizen/src/hw/pci/maru_brill_codec.h
deleted file mode 100644 (file)
index cd5e80d..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Virtual Codec device
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- *  Kitae Kim <kt920.kim@samsung.com>
- *  SeokYeon Hwang <syeon.hwang@samsung.com>
- *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "hw/hw.h"
-#include "sysemu/kvm.h"
-#include "qemu/main-loop.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_ids.h"
-#include "qemu-common.h"
-#include "qemu/thread.h"
-
-#include "util/osutil.h"
-#include "hw/maru_device_ids.h"
-
-#include "libavformat/avformat.h"
-#include "libavresample/avresample.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-
-#define CODEC_CONTEXT_MAX           1024
-
-/*
- *  Codec Device Structures
- */
-typedef struct CodecParam {
-    int32_t     api_index;
-    int32_t     ctx_index;
-    uint32_t    mem_offset;
-} CodecParam;
-
-struct video_data {
-    int32_t width;
-    int32_t height;
-    int32_t fps_n;
-    int32_t fps_d;
-    int32_t par_n;
-    int32_t par_d;
-    int32_t pix_fmt;
-    int32_t bpp;
-    int32_t ticks_per_frame;
-};
-
-struct audio_data {
-    int32_t channels;
-    int32_t sample_rate;
-    int32_t block_align;
-    int32_t depth;
-    int32_t sample_fmt;
-    int32_t frame_size;
-    int32_t bits_per_smp_fmt;
-    int32_t reserved;
-    int64_t channel_layout;
-};
-
-typedef struct CodecContext {
-    AVCodecContext          *avctx;
-    AVFrame                 *frame;
-    AVCodecParserContext    *parser_ctx;
-    uint8_t                 *parser_buf;
-    uint16_t                parser_use;
-    bool                    occupied_context;
-    bool                    occupied_thread;
-    bool                    opened_context;
-    bool                    requested_close;
-} CodecContext;
-
-typedef struct CodecThreadPool {
-    QemuThread          *threads;
-    QemuMutex           mutex;
-    QemuCond            cond;
-} CodecThreadPool;
-
-typedef struct DataHandler {
-    void (*get_data)(void *dst, void *src, size_t size);
-    void (*release)(void *opaque);
-} DataHandler;
-
-typedef struct MaruBrillCodecState {
-    PCIDevice           dev;
-
-    uint8_t             *vaddr;
-    MemoryRegion        vram;
-    MemoryRegion        mmio;
-
-    QEMUBH              *codec_bh;
-    QemuMutex           context_mutex;
-    QemuMutex           context_queue_mutex;
-    QemuMutex           ioparam_queue_mutex;
-
-    CodecThreadPool     threadpool;
-    bool                is_thread_running;
-    uint32_t            worker_thread_cnt;
-    uint32_t            idle_thread_cnt;
-
-    int                 irq_raised;
-
-    CodecContext        context[CODEC_CONTEXT_MAX];
-    CodecParam          ioparam;
-} MaruBrillCodecState;
-
-enum codec_io_cmd {
-    CODEC_CMD_API_INDEX             = 0x28,
-    CODEC_CMD_CONTEXT_INDEX         = 0x2C,
-    CODEC_CMD_DEVICE_MEM_OFFSET     = 0x34,
-    CODEC_CMD_GET_THREAD_STATE      = 0x38,
-    CODEC_CMD_GET_CTX_FROM_QUEUE    = 0x3C,
-    CODEC_CMD_GET_DATA_FROM_QUEUE   = 0x40,
-    CODEC_CMD_RELEASE_CONTEXT       = 0x44,
-    CODEC_CMD_GET_VERSION           = 0x50,
-    CODEC_CMD_GET_ELEMENT           = 0x54,
-    CODEC_CMD_GET_CONTEXT_INDEX     = 0x58,
-};
-
-enum codec_api_type {
-    CODEC_INIT = 0,
-    CODEC_DECODE_VIDEO,
-    CODEC_ENCODE_VIDEO,
-    CODEC_DECODE_AUDIO,
-    CODEC_ENCODE_AUDIO,
-    CODEC_PICTURE_COPY,
-    CODEC_DEINIT,
-    CODEC_FLUSH_BUFFERS,
- };
-
-enum codec_type {
-    CODEC_TYPE_UNKNOWN = -1,
-    CODEC_TYPE_DECODE,
-    CODEC_TYPE_ENCODE,
-};
-
-enum thread_state {
-    CODEC_TASK_START    = 0,
-    CODEC_TASK_END      = 0x1f,
-};
-
-/*
- *  Codec Device Functions
- */
-int maru_brill_codec_pci_device_init(PCIBus *bus);
diff --git a/tizen/src/hw/pci/maru_brillcodec.c b/tizen/src/hw/pci/maru_brillcodec.c
new file mode 100644 (file)
index 0000000..5920019
--- /dev/null
@@ -0,0 +1,1663 @@
+/*
+ * Virtual Codec Device
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  Kitae Kim <kt920.kim@samsung.com>
+ *  SeokYeon Hwang <syeon.hwang@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "maru_brillcodec.h"
+
+#include "libavresample/avresample.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavformat/avformat.h"
+
+#include "debug_ch.h"
+
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, brillcodec);
+
+// device memory
+#define CODEC_META_DATA_SIZE    (256)
+
+// libav
+#define GEN_MASK(x) ((1 << (x)) - 1)
+#define ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x))
+#define ROUND_UP_2(x) ROUND_UP_X(x, 1)
+#define ROUND_UP_4(x) ROUND_UP_X(x, 2)
+#define ROUND_UP_8(x) ROUND_UP_X(x, 3)
+#define DIV_ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) >> (x))
+
+#define DEFAULT_VIDEO_GOP_SIZE 15
+
+enum codec_api_type {
+    CODEC_INIT = 0,
+    CODEC_DECODE_VIDEO,
+    CODEC_ENCODE_VIDEO,
+    CODEC_DECODE_AUDIO,
+    CODEC_ENCODE_AUDIO,
+    CODEC_PICTURE_COPY,
+    CODEC_DEINIT,
+    CODEC_FLUSH_BUFFERS,
+ };
+
+enum codec_type {
+    CODEC_TYPE_UNKNOWN = -1,
+    CODEC_TYPE_DECODE,
+    CODEC_TYPE_ENCODE,
+};
+
+struct video_data {
+    int32_t width;
+    int32_t height;
+    int32_t fps_n;
+    int32_t fps_d;
+    int32_t par_n;
+    int32_t par_d;
+    int32_t pix_fmt;
+    int32_t bpp;
+    int32_t ticks_per_frame;
+};
+
+struct audio_data {
+    int32_t channels;
+    int32_t sample_rate;
+    int32_t block_align;
+    int32_t depth;
+    int32_t sample_fmt;
+    int32_t frame_size;
+    int32_t bits_per_smp_fmt;
+    int32_t reserved;
+    int64_t channel_layout;
+};
+
+DeviceMemEntry *entry[CODEC_CONTEXT_MAX];
+
+// define a queue to manage ioparam, context data
+typedef struct CodecDataStg {
+    CodecParam *param_buf;
+    DeviceMemEntry *data_buf;
+
+    QTAILQ_ENTRY(CodecDataStg) node;
+} CodecDataStg;
+
+// define two queue to store input and output buffers.
+struct codec_wq codec_wq = QTAILQ_HEAD_INITIALIZER(codec_wq);
+static QTAILQ_HEAD(codec_rq, CodecDataStg) codec_rq =
+   QTAILQ_HEAD_INITIALIZER(codec_rq);
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *, int, void *);
+static bool codec_deinit(MaruBrillCodecState *, int, void *);
+static bool codec_decode_video(MaruBrillCodecState *, int, void *);
+static bool codec_encode_video(MaruBrillCodecState *, int, void *);
+static bool codec_decode_audio(MaruBrillCodecState *, int, void *);
+static bool codec_encode_audio(MaruBrillCodecState *, int, void *);
+static bool codec_picture_copy(MaruBrillCodecState *, int, void *);
+static bool codec_flush_buffers(MaruBrillCodecState *, int, void *);
+
+typedef bool (*CodecFuncEntry)(MaruBrillCodecState *, int, void *);
+static CodecFuncEntry codec_func_handler[] = {
+    codec_init,
+    codec_decode_video,
+    codec_encode_video,
+    codec_decode_audio,
+    codec_encode_audio,
+    codec_picture_copy,
+    codec_deinit,
+    codec_flush_buffers,
+};
+
+static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx);
+
+static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s, CodecParam *ioparam);
+static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
+                                            size_t data_size, int ctx_id,
+                                            DataHandler *handler);
+
+static void *maru_brill_codec_store_inbuf(uint8_t *mem_base, CodecParam *ioparam);
+
+// default handler
+static void default_get_data(void *dst, void *src, size_t size) {
+    memcpy(dst, src, size);
+}
+
+static void default_release(void *opaque) {
+    g_free(opaque);
+}
+
+static DataHandler default_data_handler = {
+    .get_data = default_get_data,
+    .release = default_release,
+};
+
+// default video decode data handler
+static void extract(void *dst, void *src, size_t size) {
+    AVFrame *frame = (AVFrame *)src;
+    avpicture_layout((AVPicture *)src, PIX_FMT_YUV420P, frame->width, frame->height, dst, size);
+}
+
+static void release(void *buf) {}
+
+static DataHandler default_video_decode_data_handler = {
+    .get_data = extract,
+    .release = release,
+};
+
+static void maru_brill_codec_thread_exit(MaruBrillCodecState *s)
+{
+    int index;
+
+    TRACE("enter: %s\n", __func__);
+
+    /* stop to run dedicated threads. */
+    s->is_thread_running = false;
+
+    for (index = 0; index < s->worker_thread_cnt; index++) {
+        qemu_thread_join(&s->threadpool.threads[index]);
+    }
+
+    TRACE("destroy mutex and conditional.\n");
+    qemu_mutex_destroy(&s->threadpool.mutex);
+    qemu_cond_destroy(&s->threadpool.cond);
+
+    if (s->threadpool.threads) {
+        g_free(s->threadpool.threads);
+        s->threadpool.threads = NULL;
+    }
+
+    TRACE("leave: %s\n", __func__);
+}
+
+void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
+{
+    CodecParam *ioparam = NULL;
+
+    ioparam = g_malloc0(sizeof(CodecParam));
+    if (!ioparam) {
+        ERR("failed to allocate ioparam\n");
+        return;
+    }
+
+    memcpy(ioparam, &s->ioparam, sizeof(CodecParam));
+
+    TRACE("wakeup thread. ctx_id: %u, api_id: %u, mem_offset: 0x%x\n",
+        ioparam->ctx_index, ioparam->api_index, ioparam->mem_offset);
+
+    qemu_mutex_lock(&s->context_mutex);
+
+    if (ioparam->api_index != CODEC_INIT) {
+        if (!CONTEXT(s, ioparam->ctx_index).opened_context) {
+            INFO("abandon api %d for context %d\n",
+                    ioparam->api_index, ioparam->ctx_index);
+            qemu_mutex_unlock(&s->context_mutex);
+            return;
+        }
+    }
+
+    qemu_mutex_unlock(&s->context_mutex);
+
+    maru_brill_codec_push_readqueue(s, ioparam);
+
+    qemu_mutex_lock(&s->context_mutex);
+    // W/A for threads starvation.
+    while (s->idle_thread_cnt == 0) {
+        qemu_mutex_unlock(&s->context_mutex);
+        TRACE("Worker threads are exhausted\n");
+        usleep(2000); // wait 2ms.
+        qemu_mutex_lock(&s->context_mutex);
+    }
+    qemu_cond_signal(&s->threadpool.cond);
+    qemu_mutex_unlock(&s->context_mutex);
+
+    TRACE("after sending conditional signal\n");
+}
+
+void *maru_brill_codec_threads(void *opaque)
+{
+    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+    bool ret = false;
+
+    TRACE("enter: %s\n", __func__);
+
+    while (s->is_thread_running) {
+        int ctx_id = 0, api_id = 0;
+        CodecDataStg *elem = NULL;
+        DeviceMemEntry *indata_buf = NULL;
+
+        qemu_mutex_lock(&s->context_mutex);
+        ++(s->idle_thread_cnt); // protected under mutex.
+        qemu_cond_wait(&s->threadpool.cond, &s->context_mutex);
+        --(s->idle_thread_cnt); // protected under mutex.
+        qemu_mutex_unlock(&s->context_mutex);
+
+        qemu_mutex_lock(&s->ioparam_queue_mutex);
+        elem = QTAILQ_FIRST(&codec_rq);
+        if (elem) {
+            QTAILQ_REMOVE(&codec_rq, elem, node);
+            qemu_mutex_unlock(&s->ioparam_queue_mutex);
+        } else {
+            qemu_mutex_unlock(&s->ioparam_queue_mutex);
+            continue;
+        }
+
+        if (!elem->param_buf) {
+            continue;
+        }
+
+        api_id = elem->param_buf->api_index;
+        ctx_id = elem->param_buf->ctx_index;
+
+        indata_buf = elem->data_buf;
+
+        TRACE("api_id: %d ctx_id: %d\n", api_id, ctx_id);
+
+        qemu_mutex_lock(&s->context_mutex);
+        CONTEXT(s, ctx_id).occupied_thread = true;
+        qemu_mutex_unlock(&s->context_mutex);
+
+        ret = codec_func_handler[api_id](s, ctx_id, indata_buf);
+        if (!ret) {
+            ERR("fail api %d for context %d\n", api_id, ctx_id);
+            g_free(elem->param_buf);
+            continue;
+        }
+
+        TRACE("release a buffer of CodecParam\n");
+        g_free(elem->param_buf);
+        elem->param_buf = NULL;
+
+        if (elem->data_buf) {
+            if (elem->data_buf->opaque) {
+                TRACE("release inbuf\n");
+                g_free(elem->data_buf->opaque);
+                elem->data_buf->opaque = NULL;
+            }
+
+            TRACE("release a buffer indata_buf\n");
+            g_free(elem->data_buf);
+            elem->data_buf = NULL;
+        }
+
+        TRACE("release an element of CodecDataStg\n");
+        g_free(elem);
+
+        qemu_mutex_lock(&s->context_mutex);
+        if (CONTEXT(s, ctx_id).requested_close) {
+            INFO("make worker thread to handle deinit\n");
+            // codec_deinit(s, ctx_id, NULL);
+            maru_brill_codec_release_context(s, ctx_id);
+            CONTEXT(s, ctx_id).requested_close = false;
+        }
+        qemu_mutex_unlock(&s->context_mutex);
+
+        TRACE("switch context to raise interrupt.\n");
+        qemu_bh_schedule(s->codec_bh);
+
+        qemu_mutex_lock(&s->context_mutex);
+        CONTEXT(s, ctx_id).occupied_thread = false;
+        qemu_mutex_unlock(&s->context_mutex);
+    }
+
+    maru_brill_codec_thread_exit(s);
+
+    TRACE("leave: %s\n", __func__);
+    return NULL;
+}
+
+// queue
+static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s,
+                                            CodecParam *ioparam)
+{
+    CodecDataStg *elem = NULL;
+    DeviceMemEntry *data_buf = NULL;
+
+    elem = g_malloc0(sizeof(CodecDataStg));
+    if (!elem) {
+        ERR("failed to allocate ioparam_queue. %d\n", sizeof(CodecDataStg));
+        return;
+    }
+
+    elem->param_buf = ioparam;
+
+    switch(ioparam->api_index) {
+    case CODEC_INIT ... CODEC_ENCODE_AUDIO:
+        data_buf = maru_brill_codec_store_inbuf((uint8_t *)s->vaddr, ioparam);
+        break;
+    default:
+        TRACE("no buffer from guest\n");
+        break;
+    }
+
+    elem->data_buf = data_buf;
+
+    qemu_mutex_lock(&s->ioparam_queue_mutex);
+    QTAILQ_INSERT_TAIL(&codec_rq, elem, node);
+    qemu_mutex_unlock(&s->ioparam_queue_mutex);
+}
+
+static void *maru_brill_codec_store_inbuf(uint8_t *mem_base,
+                                        CodecParam *ioparam)
+{
+    DeviceMemEntry *elem = NULL;
+    int readbuf_size, size = 0;
+    uint8_t *readbuf = NULL;
+    uint8_t *device_mem = mem_base + ioparam->mem_offset;
+
+    elem = g_malloc0(sizeof(DeviceMemEntry));
+    if (!elem) {
+        ERR("failed to allocate readqueue node. size: %d\n",
+            sizeof(DeviceMemEntry));
+        return NULL;
+    }
+
+    memcpy(&readbuf_size, device_mem, sizeof(readbuf_size));
+    size = sizeof(readbuf_size);
+
+    TRACE("readbuf size: %d\n", readbuf_size);
+    if (readbuf_size <= 0) {
+        TRACE("inbuf size is 0. api_id %d, ctx_id %d, mem_offset %x\n",
+            ioparam->api_index, ioparam->ctx_index, ioparam->mem_offset);
+    } else {
+        readbuf = g_malloc0(readbuf_size);
+        if (!readbuf) {
+            ERR("failed to allocate a read buffer. size: %d\n", readbuf_size);
+        } else {
+            TRACE("copy input buffer from guest. ctx_id: %d, mem_offset: %x\n",
+                ioparam->ctx_index, ioparam->mem_offset);
+            memcpy(readbuf, device_mem + size, readbuf_size);
+        }
+    }
+    // memset(device_mem, 0x00, sizeof(readbuf_size));
+
+    elem->opaque = readbuf;
+    elem->data_size = readbuf_size;
+    elem->ctx_id = ioparam->ctx_index;
+
+    return elem;
+}
+
+static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
+                                            size_t data_size, int ctx_id,
+                                            DataHandler *handler)
+{
+    DeviceMemEntry *elem = NULL;
+    elem = g_malloc0(sizeof(DeviceMemEntry));
+
+    elem->opaque = opaque;
+    elem->data_size = data_size;
+    elem->ctx_id = ctx_id;
+
+    if (handler) {
+        elem->handler = handler;
+    } else {
+        elem->handler = &default_data_handler;
+    }
+
+    qemu_mutex_lock(&s->context_queue_mutex);
+    QTAILQ_INSERT_TAIL(&codec_wq, elem, node);
+    qemu_mutex_unlock(&s->context_queue_mutex);
+}
+
+void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
+{
+    DeviceMemEntry *elem = NULL;
+    uint32_t mem_offset = 0;
+
+    TRACE("enter: %s\n", __func__);
+
+    if (ctx_idx < 1 || ctx_idx > (CODEC_CONTEXT_MAX - 1)) {
+        ERR("invalid buffer index. %d\n", ctx_idx);
+        return;
+    }
+
+    TRACE("pop_writeqeue. context index: %d\n", ctx_idx);
+    elem = entry[ctx_idx];
+    if (elem) {
+        mem_offset = s->ioparam.mem_offset;
+
+        // check corrupted mem_offset
+        if (mem_offset < CODEC_MEM_SIZE) {
+            elem->handler->get_data(s->vaddr + mem_offset, elem->opaque, elem->data_size);
+            elem->handler->release(elem->opaque);
+        } else {
+            TRACE("mem_offset is corrupted!!\n");
+        }
+
+        TRACE("pop_writequeue. release elem: %p\n", elem);
+        g_free(elem);
+
+        entry[ctx_idx] = NULL;
+    } else {
+        TRACE("there is no buffer to copy data to guest\n");
+    }
+
+    TRACE("leave: %s\n", __func__);
+}
+
+static void serialize_video_data(const struct video_data *video,
+                                AVCodecContext *avctx)
+{
+    if (video->width) {
+        avctx->width = video->width;
+    }
+    if (video->height) {
+        avctx->height = video->height;
+    }
+    if (video->fps_n) {
+        avctx->time_base.num = video->fps_n;
+    }
+    if (video->fps_d) {
+        avctx->time_base.den = video->fps_d;
+    }
+    if (video->pix_fmt > PIX_FMT_NONE) {
+        avctx->pix_fmt = video->pix_fmt;
+    }
+    if (video->par_n) {
+        avctx->sample_aspect_ratio.num = video->par_n;
+    }
+    if (video->par_d) {
+        avctx->sample_aspect_ratio.den = video->par_d;
+    }
+    if (video->bpp) {
+        avctx->bits_per_coded_sample = video->bpp;
+    }
+    if (video->ticks_per_frame) {
+        avctx->ticks_per_frame = video->ticks_per_frame;
+    }
+
+    INFO("codec_init. video, resolution: %dx%d, framerate: %d/%d "
+        "pixel_fmt: %d sample_aspect_ratio: %d/%d bpp %d\n",
+        avctx->width, avctx->height, avctx->time_base.num,
+        avctx->time_base.den, avctx->pix_fmt, avctx->sample_aspect_ratio.num,
+        avctx->sample_aspect_ratio.den, avctx->bits_per_coded_sample);
+}
+
+static void deserialize_video_data (const AVCodecContext *avctx,
+                                    struct video_data *video)
+{
+    memset(video, 0x00, sizeof(struct video_data));
+
+    video->width = avctx->width;
+    video->height = avctx->height;
+    video->fps_n = avctx->time_base.num;
+    video->fps_d = avctx->time_base.den;
+    video->pix_fmt = avctx->pix_fmt;
+    video->par_n = avctx->sample_aspect_ratio.num;
+    video->par_d = avctx->sample_aspect_ratio.den;
+    video->bpp = avctx->bits_per_coded_sample;
+    video->ticks_per_frame = avctx->ticks_per_frame;
+}
+
+static void serialize_audio_data (const struct audio_data *audio,
+                                  AVCodecContext *avctx)
+{
+    if (audio->channels) {
+        avctx->channels = audio->channels;
+    }
+    if (audio->sample_rate) {
+        avctx->sample_rate = audio->sample_rate;
+    }
+    if (audio->block_align) {
+        avctx->block_align = audio->block_align;
+    }
+
+    if (audio->sample_fmt > AV_SAMPLE_FMT_NONE) {
+        avctx->sample_fmt = audio->sample_fmt;
+    }
+
+    INFO("codec_init. audio, channel %d sample_rate %d sample_fmt %d ch_layout %lld\n",
+        avctx->channels, avctx->sample_rate, avctx->sample_fmt, avctx->channel_layout);
+}
+
+void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t ctx_id)
+{
+    DeviceMemEntry *wq_elem = NULL, *wnext = NULL;
+    CodecDataStg *rq_elem = NULL, *rnext = NULL;
+
+    TRACE("enter: %s\n", __func__);
+
+    TRACE("release %d of context\n", ctx_id);
+
+    qemu_mutex_lock(&s->threadpool.mutex);
+    if (CONTEXT(s, ctx_id).opened_context) {
+        // qemu_mutex_unlock(&s->threadpool.mutex);
+        codec_deinit(s, ctx_id, NULL);
+        // qemu_mutex_lock(&s->threadpool.mutex);
+    }
+    CONTEXT(s, ctx_id).occupied_context = false;
+    qemu_mutex_unlock(&s->threadpool.mutex);
+
+    // TODO: check if foreach statment needs lock or not.
+    QTAILQ_FOREACH_SAFE(rq_elem, &codec_rq, node, rnext) {
+        if (rq_elem && rq_elem->data_buf &&
+            (rq_elem->data_buf->ctx_id == ctx_id)) {
+
+            TRACE("remove unused node from codec_rq. ctx_id: %d\n", ctx_id);
+            qemu_mutex_lock(&s->context_queue_mutex);
+            QTAILQ_REMOVE(&codec_rq, rq_elem, node);
+            qemu_mutex_unlock(&s->context_queue_mutex);
+            if (rq_elem && rq_elem->data_buf) {
+                TRACE("release rq_buffer: %p\n", rq_elem->data_buf);
+                g_free(rq_elem->data_buf);
+            }
+
+            TRACE("release rq_elem: %p\n", rq_elem);
+            g_free(rq_elem);
+        } else {
+            TRACE("no elem of %d context in the codec_rq.\n", ctx_id);
+        }
+    }
+
+    QTAILQ_FOREACH_SAFE(wq_elem, &codec_wq, node, wnext) {
+        if (wq_elem && wq_elem->ctx_id == ctx_id) {
+            TRACE("remove unused node from codec_wq. ctx_id: %d\n", ctx_id);
+            qemu_mutex_lock(&s->context_queue_mutex);
+            QTAILQ_REMOVE(&codec_wq, wq_elem, node);
+            qemu_mutex_unlock(&s->context_queue_mutex);
+
+            if (wq_elem && wq_elem->opaque) {
+                TRACE("release wq_buffer: %p\n", wq_elem->opaque);
+                g_free(wq_elem->opaque);
+                wq_elem->opaque = NULL;
+            }
+
+            TRACE("release wq_elem: %p\n", wq_elem);
+            g_free(wq_elem);
+        } else {
+            TRACE("no elem of %d context in the codec_wq.\n", ctx_id);
+        }
+    }
+
+    TRACE("leave: %s\n", __func__);
+}
+
+int maru_brill_codec_query_list (MaruBrillCodecState *s)
+{
+    AVCodec *codec = NULL;
+    uint32_t size = 0, mem_size = 0;
+    uint32_t data_len = 0, length = 0;
+    int32_t codec_type, media_type;
+    int32_t codec_fmts[4], i;
+
+    /* register avcodec */
+    TRACE("register avcodec\n");
+    av_register_all();
+
+    codec = av_codec_next(NULL);
+    if (!codec) {
+        ERR("failed to get codec info.\n");
+        return -1;
+    }
+
+    // a region to store the number of codecs.
+    length = 32 + 64 + 6 * sizeof(int32_t);
+    mem_size = size = sizeof(uint32_t);
+
+    while (codec) {
+        codec_type =
+            codec->decode ? CODEC_TYPE_DECODE : CODEC_TYPE_ENCODE;
+        media_type = codec->type;
+
+        memset(codec_fmts, -1, sizeof(codec_fmts));
+        if (media_type == AVMEDIA_TYPE_VIDEO) {
+            if (codec->pix_fmts) {
+                for (i = 0; codec->pix_fmts[i] != -1 && i < 4; i++) {
+                    codec_fmts[i] = codec->pix_fmts[i];
+                }
+            }
+        } else if (media_type == AVMEDIA_TYPE_AUDIO) {
+            if (codec->sample_fmts) {
+                for (i = 0; codec->sample_fmts[i] != -1; i++) {
+                    codec_fmts[i] = codec->sample_fmts[i];
+                }
+            }
+        } else {
+            ERR("unknown media type: %d\n", media_type);
+        }
+
+        memset(s->vaddr + mem_size, 0x00, length);
+        mem_size += length;
+
+        data_len += length;
+        memcpy(s->vaddr, &data_len, sizeof(data_len));
+
+        memcpy(s->vaddr + size, &codec_type, sizeof(codec_type));
+        size += sizeof(codec_type);
+        memcpy(s->vaddr + size, &media_type, sizeof(media_type));
+        size += sizeof(media_type);
+        memcpy(s->vaddr + size, codec->name, strlen(codec->name));
+        size += 32;
+        memcpy(s->vaddr + size,
+           codec->long_name, strlen(codec->long_name));
+        size += 64;
+        memcpy(s->vaddr + size, codec_fmts, sizeof(codec_fmts));
+        size += sizeof(codec_fmts);
+
+        codec = av_codec_next(codec);
+    }
+
+    return 0;
+}
+
+int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
+{
+    int ctx_id;
+
+    TRACE("enter: %s\n", __func__);
+
+    // requires mutex_lock? its function is protected by critical section.
+    qemu_mutex_lock(&s->threadpool.mutex);
+    for (ctx_id = 1; ctx_id < CODEC_CONTEXT_MAX; ctx_id++) {
+        if (CONTEXT(s, ctx_id).occupied_context == false) {
+            TRACE("get %d of codec context successfully.\n", ctx_id);
+            CONTEXT(s, ctx_id).occupied_context = true;
+            break;
+        }
+    }
+    qemu_mutex_unlock(&s->threadpool.mutex);
+
+    if (ctx_id == CODEC_CONTEXT_MAX) {
+        ERR("failed to get available codec context. ");
+        ERR("try to run codec again.\n");
+        ctx_id = -1;
+    }
+
+    TRACE("leave: %s\n", __func__);
+
+    return ctx_id;
+}
+
+
+// allocate avcontext and avframe struct.
+static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, int ctx_id)
+{
+    TRACE("enter: %s\n", __func__);
+
+    TRACE("allocate %d of context and frame.\n", ctx_id);
+    CONTEXT(s, ctx_id).avctx = avcodec_alloc_context3(NULL);
+    CONTEXT(s, ctx_id).frame = avcodec_alloc_frame();
+    CONTEXT(s, ctx_id).opened_context = false;
+
+    TRACE("leave: %s\n", __func__);
+
+    return CONTEXT(s, ctx_id).avctx;
+}
+
+static AVCodec *maru_brill_codec_find_avcodec(uint8_t *mem_buf)
+{
+    AVCodec *codec = NULL;
+    int32_t encode, size = 0;
+    char codec_name[32] = {0, };
+
+    memcpy(&encode, mem_buf, sizeof(encode));
+    size = sizeof(encode);
+    memcpy(codec_name, mem_buf + size, sizeof(codec_name));
+    size += sizeof(codec_name);
+
+    TRACE("type: %d, name: %s\n", encode, codec_name);
+
+    if (encode) {
+        codec = avcodec_find_encoder_by_name (codec_name);
+    } else {
+        codec = avcodec_find_decoder_by_name (codec_name);
+    }
+    INFO("%s!! find %s %s\n", codec ? "success" : "failure",
+        codec_name, encode ? "encoder" : "decoder");
+
+    return codec;
+}
+
+static void read_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+    struct video_data video = { 0, };
+    struct audio_data audio = { 0, };
+    int bitrate = 0, size = 0;
+
+    memcpy(&video, mem_buf + size, sizeof(video));
+    size = sizeof(video);
+    serialize_video_data(&video, avctx);
+
+    memcpy(&audio, mem_buf + size, sizeof(audio));
+    size += sizeof(audio);
+    serialize_audio_data(&audio, avctx);
+
+    memcpy(&bitrate, mem_buf + size, sizeof(bitrate));
+    size += sizeof(bitrate);
+    if (bitrate) {
+        avctx->bit_rate = bitrate;
+    }
+
+    memcpy(&avctx->codec_tag, mem_buf + size, sizeof(avctx->codec_tag));
+    size += sizeof(avctx->codec_tag);
+    memcpy(&avctx->extradata_size,
+            mem_buf + size, sizeof(avctx->extradata_size));
+    size += sizeof(avctx->extradata_size);
+    INFO("extradata size: %d.\n", avctx->extradata_size);
+
+    if (avctx->extradata_size > 0) {
+        avctx->extradata =
+            av_mallocz(ROUND_UP_X(avctx->extradata_size +
+                        FF_INPUT_BUFFER_PADDING_SIZE, 4));
+        if (avctx->extradata) {
+            memcpy(avctx->extradata, mem_buf + size, avctx->extradata_size);
+        }
+    } else {
+        TRACE("no extra data.\n");
+        avctx->extradata =
+            av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
+    }
+}
+
+// write the result of codec_init
+static int write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+    int size = 0;
+
+    if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+        int osize = av_get_bytes_per_sample(avctx->sample_fmt);
+
+        INFO("avcodec_open. sample_fmt %d, bytes_per_sample %d\n", avctx->sample_fmt, osize);
+
+        if ((avctx->codec_id == AV_CODEC_ID_AAC) && avctx->codec->encode2) {
+            osize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
+        }
+        memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
+        size = sizeof(avctx->sample_fmt);
+
+        // frame_size: samples per packet, initialized when calling 'init'
+        memcpy(mem_buf + size, &avctx->frame_size, sizeof(avctx->frame_size));
+        size += sizeof(avctx->frame_size);
+
+        memcpy(mem_buf + size, &osize, sizeof(osize));
+        size += sizeof(osize);
+    }
+
+    return size;
+}
+
+static uint8_t *resample_audio_buffer(AVCodecContext * avctx, AVFrame *samples,
+                                    int *out_size, int out_sample_fmt)
+{
+    AVAudioResampleContext *avr = NULL;
+    uint8_t *resampled_audio = NULL;
+    int buffer_size = 0, out_linesize = 0;
+    int nb_samples = samples->nb_samples;
+    // int out_sample_fmt = avctx->sample_fmt - 5;
+
+    avr = avresample_alloc_context();
+    if (!avr) {
+        ERR("failed to allocate avresample context\n");
+        return NULL;
+    }
+
+    TRACE("resample audio. channel_layout %lld sample_rate %d "
+        "in_sample_fmt %d out_sample_fmt %d\n",
+        avctx->channel_layout, avctx->sample_rate,
+        avctx->sample_fmt, out_sample_fmt);
+
+    av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
+    av_opt_set_int(avr, "in_sample_fmt", avctx->sample_fmt, 0);
+    av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
+    av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
+    av_opt_set_int(avr, "out_sample_fmt", out_sample_fmt, 0);
+    av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
+
+    TRACE("open avresample context\n");
+    if (avresample_open(avr) < 0) {
+        ERR("failed to open avresample context\n");
+        avresample_free(&avr);
+        return NULL;
+    }
+
+    *out_size =
+        av_samples_get_buffer_size(&out_linesize, avctx->channels,
+                                    nb_samples, out_sample_fmt, 0);
+
+    TRACE("resample audio. out_linesize %d nb_samples %d\n", out_linesize, nb_samples);
+
+    if (*out_size < 0) {
+        ERR("failed to get size of sample buffer %d\n", *out_size);
+        avresample_close(avr);
+        avresample_free(&avr);
+        return NULL;
+    }
+
+    resampled_audio = av_mallocz(*out_size);
+    if (!resampled_audio) {
+        ERR("failed to allocate resample buffer\n");
+        avresample_close(avr);
+        avresample_free(&avr);
+        return NULL;
+    }
+
+    buffer_size = avresample_convert(avr, &resampled_audio,
+        out_linesize, nb_samples,
+        samples->data, samples->linesize[0],
+        samples->nb_samples);
+    TRACE("resample_audio out_size %d buffer_size %d\n", *out_size, buffer_size);
+
+    avresample_close(avr);
+    avresample_free(&avr);
+
+    return resampled_audio;
+}
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx = NULL;
+    AVCodec *codec = NULL;
+    int size = 0, ret = -1;
+    DeviceMemEntry *elem = NULL;
+    uint8_t *tempbuf = NULL;
+    int tempbuf_size = 0;
+
+    TRACE("enter: %s\n", __func__);
+
+    elem = (DeviceMemEntry *)data_buf;
+
+    // allocate AVCodecContext
+    avctx = maru_brill_codec_alloc_context(s, ctx_id);
+    if (!avctx) {
+        ERR("[%d] failed to allocate context.\n", __LINE__);
+        ret = -1;
+    } else {
+        codec = maru_brill_codec_find_avcodec(elem->opaque);
+        if (codec) {
+            size = sizeof(int32_t) + 32; // buffer size of codec_name
+            read_codec_init_data(avctx, elem->opaque + size);
+
+            // in case of aac encoder, sample format is float
+            if (!strcmp(codec->name, "aac") && codec->encode2) {
+                TRACE("convert sample format into SAMPLE_FMT_FLTP\n");
+                avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+
+                avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+
+                INFO("aac encoder!! channels %d channel_layout %lld\n", avctx->channels, avctx->channel_layout);
+                avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
+            }
+
+            TRACE("audio sample format %d\n", avctx->sample_fmt);
+            TRACE("strict_std_compliance %d\n", avctx->strict_std_compliance);
+
+            ret = avcodec_open2(avctx, codec, NULL);
+            INFO("avcodec_open. ret 0x%x ctx_id %d\n", ret, ctx_id);
+
+            TRACE("channels %d sample_rate %d sample_fmt %d "
+                "channel_layout %lld frame_size %d\n",
+                avctx->channels, avctx->sample_rate, avctx->sample_fmt,
+                avctx->channel_layout, avctx->frame_size);
+
+            tempbuf_size = (sizeof(avctx->sample_fmt) + sizeof(avctx->frame_size)
+                           + sizeof(avctx->extradata_size) + avctx->extradata_size)
+                           + sizeof(int);
+
+            CONTEXT(s, ctx_id).opened_context = true;
+            CONTEXT(s, ctx_id).parser_ctx =
+                maru_brill_codec_parser_init(avctx);
+        } else {
+            ERR("failed to find codec. ctx_id: %d\n", ctx_id);
+            ret = -1;
+        }
+    }
+
+    tempbuf_size += sizeof(ret);
+
+    tempbuf = g_malloc(tempbuf_size);
+    if (!tempbuf) {
+        ERR("failed to allocate a buffer\n");
+        tempbuf_size = 0;
+    } else {
+        memcpy(tempbuf, &ret, sizeof(ret));
+        size = sizeof(ret);
+        if (ret < 0) {
+            ERR("failed to open codec contex.\n");
+        } else {
+            size += write_codec_init_data(avctx, tempbuf + size);
+            TRACE("codec_init. copyback!! size %d\n", size);
+            {
+                memcpy(tempbuf + size, &avctx->extradata_size, sizeof(avctx->extradata_size));
+                size += sizeof(avctx->extradata_size);
+
+                INFO("codec_init. extradata_size: %d\n", avctx->extradata_size);
+                if (avctx->extradata) {
+                    memcpy(tempbuf + size, avctx->extradata, avctx->extradata_size);
+                    size += avctx->extradata_size;
+                }
+            }
+        }
+    }
+
+    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+    TRACE("leave: %s\n", __func__);
+
+    return true;
+}
+
+static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx = NULL;
+    AVFrame *frame = NULL;
+    AVCodecParserContext *parserctx = NULL;
+
+    TRACE("enter: %s\n", __func__);
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    frame = CONTEXT(s, ctx_id).frame;
+    parserctx = CONTEXT(s, ctx_id).parser_ctx;
+    if (!avctx || !frame) {
+        TRACE("%d of AVCodecContext or AVFrame is NULL. "
+            " Those resources have been released before.\n", ctx_id);
+        return false;
+    }
+
+    INFO("close avcontext of %d\n", ctx_id);
+    // qemu_mutex_lock(&s->threadpool.mutex);
+    avcodec_close(avctx);
+    CONTEXT(s, ctx_id).opened_context = false;
+    // qemu_mutex_unlock(&s->threadpool.mutex);
+
+    if (avctx->extradata) {
+        TRACE("free context extradata\n");
+        av_free(avctx->extradata);
+        CONTEXT(s, ctx_id).avctx->extradata = NULL;
+    }
+
+    if (frame) {
+        TRACE("free frame\n");
+        // av_free(frame);
+        avcodec_free_frame(&frame);
+        CONTEXT(s, ctx_id).frame = NULL;
+    }
+
+    if (avctx) {
+        TRACE("free codec context\n");
+        av_free(avctx);
+        CONTEXT(s, ctx_id).avctx = NULL;
+    }
+
+    if (parserctx) {
+        av_parser_close(parserctx);
+        CONTEXT(s, ctx_id).parser_ctx = NULL;
+    }
+
+    maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+
+    TRACE("leave: %s\n", __func__);
+
+    return true;
+}
+
+static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx = NULL;
+    bool ret = true;
+
+    TRACE("enter: %s\n", __func__);
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    if (!avctx) {
+        ERR("%d of AVCodecContext is NULL.\n", ctx_id);
+        ret = false;
+    } else if (!avctx->codec) {
+        ERR("%d of AVCodec is NULL.\n", ctx_id);
+        ret = false;
+    } else {
+        TRACE("flush %d context of buffers.\n", ctx_id);
+        avcodec_flush_buffers(avctx);
+    }
+
+    maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+
+    TRACE("leave: %s\n", __func__);
+
+    return ret;
+}
+
+static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx = NULL;
+    AVFrame *picture = NULL;
+    AVPacket avpkt;
+    int got_picture = 0, len = -1;
+    uint8_t *inbuf = NULL;
+    int inbuf_size = 0, idx, size = 0;
+    int64_t in_offset;
+    DeviceMemEntry *elem = NULL;
+    uint8_t *tempbuf = NULL;
+    int tempbuf_size = 0;
+
+    TRACE("enter: %s\n", __func__);
+
+    elem = (DeviceMemEntry *)data_buf;
+    if (elem && elem->opaque) {
+        memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
+        size += sizeof(inbuf_size);
+        memcpy(&idx, elem->opaque + size, sizeof(idx));
+        size += sizeof(idx);
+        memcpy(&in_offset, elem->opaque + size, sizeof(in_offset));
+        size += sizeof(in_offset);
+        TRACE("decode_video. inbuf_size %d\n", inbuf_size);
+
+        if (inbuf_size > 0) {
+            inbuf = elem->opaque + size;
+        }
+    } else {
+        TRACE("decode_video. no input buffer\n");
+        // FIXME: improve error handling
+        // return false;
+    }
+
+    av_init_packet(&avpkt);
+    avpkt.data = inbuf;
+    avpkt.size = inbuf_size;
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    picture = CONTEXT(s, ctx_id).frame;
+    if (!avctx) {
+        ERR("decode_video. %d of AVCodecContext is NULL.\n", ctx_id);
+    } else if (!avctx->codec) {
+        ERR("decode_video. %d of AVCodec is NULL.\n", ctx_id);
+    } else if (!picture) {
+        ERR("decode_video. %d of AVFrame is NULL.\n", ctx_id);
+    } else {
+        // in case of skipping frames
+        // picture->pict_type = -1;
+
+        TRACE("decode_video. bitrate %d\n", avctx->bit_rate);
+        // avctx->reordered_opaque = idx;
+        // picture->reordered_opaque = idx;
+
+        len =
+            avcodec_decode_video2(avctx, picture, &got_picture, &avpkt);
+        TRACE("decode_video. in_size %d len %d, frame_size %d\n", avpkt.size, len, got_picture);
+    }
+
+    tempbuf_size =
+            sizeof(len) + sizeof(got_picture) + sizeof(struct video_data);
+
+    if (len < 0) {
+        ERR("failed to decode video. ctx_id: %d, len: %d\n", ctx_id, len);
+        got_picture = 0;
+    }
+
+    tempbuf = g_malloc(tempbuf_size);
+    if (!tempbuf) {
+        ERR("failed to allocate decoded audio buffer\n");
+        // FIXME: how to handle this case?
+    } else {
+        struct video_data video;
+
+        memcpy(tempbuf, &len, sizeof(len));
+        size = sizeof(len);
+        memcpy(tempbuf + size, &got_picture, sizeof(got_picture));
+        size += sizeof(got_picture);
+        if (avctx) {
+
+            avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+            //avctx->pix_fmt = AV_PIX_FMT_;
+
+            deserialize_video_data(avctx, &video);
+            memcpy(tempbuf + size, &video, sizeof(struct video_data));
+        }
+    }
+
+    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+    TRACE("leave: %s\n", __func__);
+
+    return true;
+}
+
+static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
+{
+    AVCodecContext *avctx = NULL;
+    AVPicture *src = NULL;
+    int pict_size = 0;
+    bool ret = true;
+
+    TRACE("enter: %s\n", __func__);
+
+    TRACE("copy decoded image of %d context.\n", ctx_id);
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    src = (AVPicture *)CONTEXT(s, ctx_id).frame;
+    if (!avctx) {
+        ERR("picture_copy. %d of AVCodecContext is NULL.\n", ctx_id);
+        ret = false;
+    } else if (!avctx->codec) {
+        ERR("picture_copy. %d of AVCodec is NULL.\n", ctx_id);
+        ret = false;
+    } else if (!src) {
+        ERR("picture_copy. %d of AVFrame is NULL.\n", ctx_id);
+        ret = false;
+    } else {
+        TRACE("decoded image. pix_fmt: %d width: %d, height: %d\n",
+                avctx->pix_fmt, avctx->width, avctx->height);
+        pict_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
+
+        if ((pict_size) < 0) {
+            ERR("picture size: %d\n", pict_size);
+            ret = false;
+        } else {
+            TRACE("picture size: %d\n", pict_size);
+            maru_brill_codec_push_writequeue(s, src, pict_size, ctx_id, &default_video_decode_data_handler);
+        }
+    }
+
+    TRACE("leave: %s\n", __func__);
+
+    return ret;
+}
+
+static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx;
+    AVPacket avpkt;
+    AVFrame *audio_out = NULL;
+    uint8_t *inbuf = NULL;
+    int inbuf_size = 0, size = 0;
+    int len = -1, got_frame = 0;
+
+    DeviceMemEntry *elem = NULL;
+    uint8_t *tempbuf = NULL;
+    int tempbuf_size = 0;
+
+    uint8_t *out_buf = NULL;
+    int out_buf_size = 0;
+    int out_sample_fmt = -1;
+
+    TRACE("enter: %s\n", __func__);
+
+    elem = (DeviceMemEntry *)data_buf;
+    if (elem && elem->opaque) {
+        memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
+        size = sizeof(inbuf_size);
+        TRACE("decode_audio. inbuf_size %d\n", inbuf_size);
+
+        if (inbuf_size > 0) {
+            inbuf = elem->opaque + size;
+        }
+    } else {
+        ERR("decode_audio. no input buffer\n");
+        // FIXME: improve error handling
+        // return false;
+    }
+
+    av_init_packet(&avpkt);
+    avpkt.data = inbuf;
+    avpkt.size = inbuf_size;
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    // audio_out = CONTEXT(s, ctx_id).frame;
+    audio_out = avcodec_alloc_frame();
+    if (!avctx) {
+        ERR("decode_audio. %d of AVCodecContext is NULL\n", ctx_id);
+    } else if (!avctx->codec) {
+        ERR("decode_audio. %d of AVCodec is NULL\n", ctx_id);
+    } else if (!audio_out) {
+        ERR("decode_audio. %d of AVFrame is NULL\n", ctx_id);
+    } else {
+        // avcodec_get_frame_defaults(audio_out);
+
+        len = avcodec_decode_audio4(avctx, audio_out, &got_frame, &avpkt);
+        TRACE("decode_audio. len %d, channel_layout %lld, got_frame %d\n",
+            len, avctx->channel_layout, got_frame);
+        if (got_frame) {
+            if (av_sample_fmt_is_planar(avctx->sample_fmt)) {
+                // convert PLANAR to LINEAR format
+                out_sample_fmt = avctx->sample_fmt - 5;
+
+                out_buf = resample_audio_buffer(avctx, audio_out, &out_buf_size, out_sample_fmt);
+            } else {
+                // TODO: not planar format
+                INFO("decode_audio. cannot handle planar audio format\n");
+                len = -1;
+            }
+        }
+    }
+
+    tempbuf_size = (sizeof(len) + sizeof(got_frame));
+    if (len < 0) {
+        ERR("failed to decode audio. ctx_id: %d len: %d got_frame: %d\n",
+            ctx_id, len, got_frame);
+        got_frame = 0;
+    } else {
+        tempbuf_size += (sizeof(out_sample_fmt) + sizeof(avctx->sample_rate)
+                        + sizeof(avctx->channels) +  sizeof(avctx->channel_layout)
+                        + sizeof(out_buf_size) + out_buf_size);
+    }
+
+    tempbuf = g_malloc(tempbuf_size);
+    if (!tempbuf) {
+        ERR("failed to allocate decoded audio buffer\n");
+    } else {
+        memcpy(tempbuf, &len, sizeof(len));
+        size = sizeof(len);
+        memcpy(tempbuf + size, &got_frame, sizeof(got_frame));
+        size += sizeof(got_frame);
+        if (got_frame) {
+            memcpy(tempbuf + size, &out_sample_fmt, sizeof(out_sample_fmt));
+            size += sizeof(out_sample_fmt);
+            memcpy(tempbuf + size, &avctx->sample_rate, sizeof(avctx->sample_rate));
+            size += sizeof(avctx->sample_rate);
+            memcpy(tempbuf + size, &avctx->channels, sizeof(avctx->channels));
+            size += sizeof(avctx->channels);
+            memcpy(tempbuf + size, &avctx->channel_layout, sizeof(avctx->channel_layout));
+            size += sizeof(avctx->channel_layout);
+
+            memcpy(tempbuf + size, &out_buf_size, sizeof(out_buf_size));
+            size += sizeof(out_buf_size);
+            if (out_buf) {
+                TRACE("copy resampled audio buffer\n");
+                memcpy(tempbuf + size, out_buf, out_buf_size);
+            }
+        }
+    }
+
+    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+    if (audio_out) {
+        avcodec_free_frame(&audio_out);
+    }
+
+    if (out_buf) {
+        TRACE("and release decoded_audio buffer\n");
+        av_free(out_buf);
+    }
+
+
+    TRACE("leave: %s\n", __func__);
+    return true;
+}
+
+static bool codec_encode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx = NULL;
+    AVFrame *pict = NULL;
+    AVPacket avpkt;
+    uint8_t *inbuf = NULL, *outbuf = NULL;
+    int inbuf_size = 0, outbuf_size = 0;
+    int got_frame = 0, ret = 0, size = 0;
+    int64_t in_timestamp = 0;
+    int coded_frame = 0, key_frame = 0;
+
+    DeviceMemEntry *elem = NULL;
+    uint8_t *tempbuf = NULL;
+    int tempbuf_size = 0;
+
+    TRACE("enter: %s\n", __func__);
+
+    elem = (DeviceMemEntry *)data_buf;
+    if (elem && elem->opaque) {
+        memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
+        size += sizeof(inbuf_size);
+        memcpy(&in_timestamp, elem->opaque + size, sizeof(in_timestamp));
+        size += sizeof(in_timestamp);
+        TRACE("encode video. inbuf_size %d\n", inbuf_size);
+
+        if (inbuf_size > 0) {
+            inbuf = elem->opaque + size;
+        }
+    } else {
+        TRACE("encode video. no input buffer.\n");
+        // FIXME: improve error handling
+        // return false;
+    }
+
+    // initialize AVPacket
+    av_init_packet(&avpkt);
+    avpkt.data = NULL;
+    avpkt.size = 0;
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    pict = CONTEXT(s, ctx_id).frame;
+    if (!avctx || !pict) {
+        ERR("%d of context or frame is NULL\n", ctx_id);
+    } else if (!avctx->codec) {
+        ERR("%d of AVCodec is NULL.\n", ctx_id);
+    } else {
+        TRACE("pixel format: %d inbuf: %p, picture data: %p\n",
+            avctx->pix_fmt, inbuf, pict->data[0]);
+
+        ret = avpicture_fill((AVPicture *)pict, inbuf, avctx->pix_fmt,
+                            avctx->width, avctx->height);
+        if (ret < 0) {
+            ERR("after avpicture_fill, ret:%d\n", ret);
+        } else {
+            if (avctx->time_base.num == 0) {
+                pict->pts = AV_NOPTS_VALUE;
+            } else {
+                AVRational bq =
+                            {1, (G_USEC_PER_SEC * G_GINT64_CONSTANT(1000))};
+                pict->pts = av_rescale_q(in_timestamp, bq, avctx->time_base);
+            }
+            TRACE("encode video. ticks_per_frame:%d, pts:%lld\n",
+                avctx->ticks_per_frame, pict->pts);
+
+            outbuf_size =
+                (avctx->width * avctx->height * 6) + FF_MIN_BUFFER_SIZE;
+
+            outbuf = g_malloc0(outbuf_size);
+
+            avpkt.data = outbuf;
+            avpkt.size = outbuf_size;
+
+            if (!outbuf) {
+                ERR("failed to allocate a buffer of encoding video.\n");
+            } else {
+                ret = avcodec_encode_video2(avctx, &avpkt, pict, &got_frame);
+
+                TRACE("encode video. ret %d got_picture %d outbuf_size %d\n", ret, got_frame, avpkt.size);
+                if (avctx->coded_frame) {
+                    TRACE("encode video. keyframe %d\n", avctx->coded_frame->key_frame);
+                }
+            }
+        }
+    }
+
+    tempbuf_size = sizeof(ret);
+    if (ret < 0) {
+        ERR("failed to encode video. ctx_id %d ret %d\n", ctx_id, ret);
+    } else {
+        tempbuf_size += avpkt.size + sizeof(coded_frame) + sizeof(key_frame);
+    }
+
+    // write encoded video data
+    tempbuf = g_malloc0(tempbuf_size);
+    if (!tempbuf) {
+        ERR("encode video. failed to allocate encoded out buffer.\n");
+    } else {
+        memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
+        size = sizeof(avpkt.size);
+
+        if ((got_frame) && outbuf) {
+            // inform gstreamer plugin about the status of encoded frames
+            // A flag for output buffer in gstreamer is depending on the status.
+            if (avctx->coded_frame) {
+                coded_frame = 1;
+                // if key_frame is 0, this frame cannot be decoded independently.
+                key_frame = avctx->coded_frame->key_frame;
+            }
+            memcpy(tempbuf + size, &coded_frame, sizeof(coded_frame));
+            size += sizeof(coded_frame);
+            memcpy(tempbuf + size, &key_frame, sizeof(key_frame));
+            size += sizeof(key_frame);
+            memcpy(tempbuf + size, outbuf, avpkt.size);
+        }
+    }
+
+    if (outbuf) {
+        TRACE("release encoded output buffer. %p\n", outbuf);
+        g_free(outbuf);
+    }
+
+    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+    TRACE("leave: %s\n", __func__);
+    return true;
+}
+
+static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+    AVCodecContext *avctx = NULL;
+    AVPacket avpkt;
+    uint8_t *audio_in = NULL;
+    int32_t audio_in_size = 0;
+    int ret = 0, got_pkt = 0, size = 0;
+
+    DeviceMemEntry *elem = NULL;
+    uint8_t *tempbuf = NULL;
+    int tempbuf_size = 0;
+
+    AVFrame *in_frame = NULL;
+    AVFrame *resampled_frame = NULL;
+    uint8_t *samples = NULL;
+    int64_t in_timestamp = 0;
+
+    TRACE("enter: %s\n", __func__);
+
+    /*
+     *  copy raw audio data from gstreamer encoder plugin
+     *  audio_in_size: size of raw audio data
+     *  audio_in : raw audio data
+     */
+    elem = (DeviceMemEntry *)data_buf;
+    if (elem && elem->opaque) {
+        memcpy(&audio_in_size, elem->opaque, sizeof(audio_in_size));
+        size += sizeof(audio_in_size);
+
+        memcpy(&in_timestamp, elem->opaque + size, sizeof(in_timestamp));
+        size += sizeof(in_timestamp);
+
+        TRACE("encode_audio. audio_in_size %d\n", audio_in_size);
+        if (audio_in_size > 0) {
+            // audio_in = g_malloc0(audio_in_size);
+            // memcpy(audio_in, elem->buf + size, audio_in_size);
+            audio_in = elem->opaque + size;
+        }
+    } else {
+        TRACE("encode_audio. no input buffer\n");
+        // FIXME: improve error handling
+        // return false;
+    }
+
+    avctx = CONTEXT(s, ctx_id).avctx;
+    if (!avctx) {
+        ERR("[%s] %d of Context is NULL!\n", __func__, ctx_id);
+    } else if (!avctx->codec) {
+        ERR("%d of AVCodec is NULL.\n", ctx_id);
+    } else {
+        int bytes_per_sample = 0;
+        int audio_in_buffer_size = 0;
+        int audio_in_sample_fmt = AV_SAMPLE_FMT_S16;
+
+        in_frame = avcodec_alloc_frame();
+        if (!in_frame) {
+            // FIXME: error handling
+            ERR("encode_audio. failed to allocate in_frame\n");
+            ret = -1;
+        }
+
+        bytes_per_sample = av_get_bytes_per_sample(audio_in_sample_fmt);
+        TRACE("bytes per sample %d, sample format %d\n", bytes_per_sample, audio_in_sample_fmt);
+
+        in_frame->nb_samples = audio_in_size / (bytes_per_sample * avctx->channels);
+        TRACE("in_frame->nb_samples %d\n", in_frame->nb_samples);
+
+        in_frame->format = audio_in_sample_fmt;
+        in_frame->channel_layout = avctx->channel_layout;
+
+        audio_in_buffer_size = av_samples_get_buffer_size(NULL, avctx->channels, avctx->frame_size, audio_in_sample_fmt, 0);
+        TRACE("audio_in_buffer_size: %d, audio_in_size %d\n", audio_in_buffer_size, audio_in_size);
+
+        {
+            samples = av_mallocz(audio_in_buffer_size);
+            memcpy(samples, audio_in, audio_in_size);
+
+            // g_free(audio_in);
+            // audio_in = NULL;
+
+            ret = avcodec_fill_audio_frame(in_frame, avctx->channels, AV_SAMPLE_FMT_S16, (const uint8_t *)samples, audio_in_size, 0);
+            TRACE("fill in_frame. ret: %d frame->ch_layout %lld\n", ret, in_frame->channel_layout);
+        }
+
+        {
+            AVAudioResampleContext *avr = NULL;
+            uint8_t *resampled_audio = NULL;
+            int resampled_buffer_size = 0, resampled_linesize = 0, convert_size;
+            int resampled_nb_samples = 0;
+            int resampled_sample_fmt = AV_SAMPLE_FMT_FLTP;
+
+            avr = avresample_alloc_context();
+
+            av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
+            av_opt_set_int(avr, "in_sample_fmt", audio_in_sample_fmt , 0);
+            av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
+            av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
+            av_opt_set_int(avr, "out_sample_fmt", resampled_sample_fmt, 0);
+            av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
+
+            resampled_nb_samples = in_frame->nb_samples; // av_get_bytes_per_samples(resampled_sample_fmt);
+
+            if (avresample_open(avr) < 0) {
+                ERR("failed to open avresample context\n");
+                avresample_free(&avr);
+            }
+
+            resampled_buffer_size = av_samples_get_buffer_size(&resampled_linesize, avctx->channels, resampled_nb_samples, resampled_sample_fmt, 0);
+            if (resampled_buffer_size < 0) {
+                ERR("failed to get size of sample buffer %d\n", resampled_buffer_size);
+                avresample_close(avr);
+                avresample_free(&avr);
+            }
+
+            TRACE("resampled nb_samples %d linesize %d out_size %d\n", resampled_nb_samples, resampled_linesize, resampled_buffer_size);
+
+            resampled_audio = av_mallocz(resampled_buffer_size);
+            if (!resampled_audio) {
+                ERR("failed to allocate resample buffer\n");
+                avresample_close(avr);
+                avresample_free(&avr);
+            }
+
+            // in_frame->nb_samples = nb_samples;
+            resampled_frame = avcodec_alloc_frame();
+            if (!resampled_frame) {
+                // FIXME: error handling
+                ERR("encode_audio. failed to allocate resampled_frame\n");
+                ret = -1;
+            }
+
+
+            bytes_per_sample = av_get_bytes_per_sample(audio_in_sample_fmt);
+            TRACE("bytes per sample %d, sample format %d\n", bytes_per_sample, audio_in_sample_fmt);
+
+            resampled_frame->nb_samples = in_frame->nb_samples;
+            TRACE("resampled_frame->nb_samples %d\n", resampled_frame->nb_samples);
+
+            resampled_frame->format = resampled_sample_fmt;
+            resampled_frame->channel_layout = avctx->channel_layout;
+
+            ret = avcodec_fill_audio_frame(resampled_frame, avctx->channels, resampled_sample_fmt,
+                    (const uint8_t *)resampled_audio, resampled_buffer_size, 0);
+            TRACE("fill resampled_frame ret: %d frame->ch_layout %lld\n", ret, in_frame->channel_layout);
+
+            convert_size = avresample_convert(avr, resampled_frame->data, resampled_buffer_size, resampled_nb_samples,
+                                        in_frame->data, audio_in_size, in_frame->nb_samples);
+
+            TRACE("resample_audio convert_size %d\n", convert_size);
+
+            avresample_close(avr);
+            avresample_free(&avr);
+        }
+
+        if (ret == 0) {
+            av_init_packet(&avpkt);
+            // packet data will be allocated by encoder
+            avpkt.data = NULL;
+            avpkt.size = 0;
+
+            ret = avcodec_encode_audio2(avctx, &avpkt, (const AVFrame *)resampled_frame, &got_pkt);
+            TRACE("encode audio. ret %d got_pkt %d avpkt.size %d frame_number %d coded_frame %p\n",
+                ret, got_pkt, avpkt.size, avctx->frame_number, avctx->coded_frame);
+        }
+    }
+
+    tempbuf_size = sizeof(ret);
+    if (ret < 0) {
+        ERR("failed to encode audio. ctx_id %d ret %d\n", ctx_id, ret);
+    } else {
+        // tempbuf_size += (max_size); // len;
+        tempbuf_size += (sizeof(avpkt.size) + avpkt.size);
+    }
+    TRACE("encode_audio. writequeue elem buffer size %d\n", tempbuf_size);
+
+    // write encoded audio data
+    tempbuf = g_malloc0(tempbuf_size);
+    if (!tempbuf) {
+        ERR("encode audio. failed to allocate encoded out buffer.\n");
+    } else {
+        memcpy(tempbuf, &ret, sizeof(ret));
+        size = sizeof(ret);
+        if (ret == 0) {
+            memcpy(tempbuf + size, &avpkt.size, sizeof(avpkt.size));
+            size += sizeof(avpkt.size);
+
+            if (got_pkt) {
+                memcpy(tempbuf + size, avpkt.data, avpkt.size);
+                av_free_packet(&avpkt);
+            }
+        }
+    }
+
+    maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+    if (in_frame) {
+        avcodec_free_frame(&in_frame);
+    }
+
+    if (resampled_frame) {
+        avcodec_free_frame(&resampled_frame);
+    }
+
+    TRACE("[%s] leave:\n", __func__);
+
+    return true;
+}
+
+static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx)
+{
+    AVCodecParserContext *parser = NULL;
+
+    if (!avctx) {
+        ERR("context is NULL\n");
+        return NULL;
+    }
+
+    switch (avctx->codec_id) {
+    case CODEC_ID_MPEG4:
+    case CODEC_ID_VC1:
+        TRACE("not using parser.\n");
+        break;
+    case CODEC_ID_H264:
+        if (avctx->extradata_size == 0) {
+            TRACE("H.264 with no extradata, creating parser.\n");
+            parser = av_parser_init (avctx->codec_id);
+        }
+        break;
+    default:
+        parser = av_parser_init (avctx->codec_id);
+        if (parser) {
+            INFO("using parser. %d\n", avctx->codec_id);
+        }
+        break;
+    }
+
+    return parser;
+}
diff --git a/tizen/src/hw/pci/maru_brillcodec.h b/tizen/src/hw/pci/maru_brillcodec.h
new file mode 100644 (file)
index 0000000..770465d
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Virtual Codec device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  Kitae Kim <kt920.kim@samsung.com>
+ *  SeokYeon Hwang <syeon.hwang@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef __MARU_BRILLCODEC_H__
+#define __MARU_BRILLCODEC_H__
+
+#include "hw/pci/pci.h"
+
+#include "libavcodec/avcodec.h"
+
+#define CODEC_CONTEXT_MAX           1024
+#define CODEC_MEM_SIZE          (32 * 1024 * 1024)
+
+#define CONTEXT(s, id)        (s->context[id])
+
+/*
+ *  Codec Device Structures
+ */
+typedef struct CodecParam {
+    int32_t     api_index;
+    int32_t     ctx_index;
+    uint32_t    mem_offset;
+} CodecParam;
+
+typedef struct CodecContext {
+    AVCodecContext          *avctx;
+    AVFrame                 *frame;
+    AVCodecParserContext    *parser_ctx;
+    uint8_t                 *parser_buf;
+    uint16_t                parser_use;
+    bool                    occupied_context;
+    bool                    occupied_thread;
+    bool                    opened_context;
+    bool                    requested_close;
+} CodecContext;
+
+typedef struct CodecThreadPool {
+    QemuThread          *threads;
+    QemuMutex           mutex;
+    QemuCond            cond;
+} CodecThreadPool;
+
+typedef struct DataHandler {
+    void (*get_data)(void *dst, void *src, size_t size);
+    void (*release)(void *opaque);
+} DataHandler;
+
+typedef struct MaruBrillCodecState {
+    PCIDevice           dev;
+
+    uint8_t             *vaddr;
+    MemoryRegion        vram;
+    MemoryRegion        mmio;
+
+    QEMUBH              *codec_bh;
+    QemuMutex           context_mutex;
+    QemuMutex           context_queue_mutex;
+    QemuMutex           ioparam_queue_mutex;
+
+    CodecThreadPool     threadpool;
+    bool                is_thread_running;
+    uint32_t            worker_thread_cnt;
+    uint32_t            idle_thread_cnt;
+
+    int                 irq_raised;
+
+    CodecContext        context[CODEC_CONTEXT_MAX];
+    CodecParam          ioparam;
+} MaruBrillCodecState;
+
+typedef struct DeviceMemEntry {
+    void *opaque;
+    uint32_t data_size;
+    uint32_t ctx_id;
+
+    DataHandler *handler;
+
+    QTAILQ_ENTRY(DeviceMemEntry) node;
+} DeviceMemEntry;
+
+QTAILQ_HEAD(codec_wq, DeviceMemEntry);
+extern struct codec_wq codec_wq;
+
+extern DeviceMemEntry *entry[CODEC_CONTEXT_MAX];
+
+int maru_brill_codec_query_list(MaruBrillCodecState *s);
+int maru_brill_codec_get_context_index(MaruBrillCodecState *s);
+void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index);
+void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t ctx_id);
+void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx);
+
+void *maru_brill_codec_threads(void *opaque);
+
+#endif // __MARU_BRILLCODEC_H__
diff --git a/tizen/src/hw/pci/maru_brillcodec_device.c b/tizen/src/hw/pci/maru_brillcodec_device.c
new file mode 100644 (file)
index 0000000..5869ca9
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Virtual Codec Device
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  Kitae Kim <kt920.kim@samsung.com>
+ *  SeokYeon Hwang <syeon.hwang@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu/main-loop.h"
+
+#include "hw/maru_device_ids.h"
+#include "util/osutil.h"
+#include "maru_brillcodec.h"
+#include "debug_ch.h"
+
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, brillcodec);
+
+#define CODEC_DEVICE_NAME   "codec-pci"
+#define CODEC_DEVICE_THREAD "codec-workthread"
+#define CODEC_VERSION               2
+#define CODEC_REG_SIZE              (256)
+#define DEFAULT_WORKER_THREAD_CNT   8
+
+enum codec_io_cmd {
+    CODEC_CMD_API_INDEX             = 0x28,
+    CODEC_CMD_CONTEXT_INDEX         = 0x2C,
+    CODEC_CMD_DEVICE_MEM_OFFSET     = 0x34,
+    CODEC_CMD_GET_THREAD_STATE      = 0x38,
+    CODEC_CMD_GET_CTX_FROM_QUEUE    = 0x3C,
+    CODEC_CMD_GET_DATA_FROM_QUEUE   = 0x40,
+    CODEC_CMD_RELEASE_CONTEXT       = 0x44,
+    CODEC_CMD_GET_VERSION           = 0x50,
+    CODEC_CMD_GET_ELEMENT           = 0x54,
+    CODEC_CMD_GET_CONTEXT_INDEX     = 0x58,
+};
+
+enum thread_state {
+    CODEC_TASK_START    = 0,
+    CODEC_TASK_END      = 0x1f,
+};
+
+static void maru_brill_codec_threads_create(MaruBrillCodecState *s)
+{
+    int index;
+    QemuThread *pthread = NULL;
+
+    TRACE("enter: %s\n", __func__);
+
+    pthread = g_malloc(sizeof(QemuThread) * s->worker_thread_cnt);
+    if (!pthread) {
+        ERR("failed to allocate threadpool memory.\n");
+        return;
+    }
+
+    qemu_cond_init(&s->threadpool.cond);
+    qemu_mutex_init(&s->threadpool.mutex);
+
+    s->is_thread_running = true;
+
+    qemu_mutex_lock(&s->context_mutex);
+    s->idle_thread_cnt = 0;
+    qemu_mutex_unlock(&s->context_mutex);
+
+    for (index = 0; index < s->worker_thread_cnt; index++) {
+        qemu_thread_create(&pthread[index], CODEC_DEVICE_THREAD,
+            maru_brill_codec_threads, (void *)s, QEMU_THREAD_JOINABLE);
+    }
+
+    s->threadpool.threads = pthread;
+
+    TRACE("leave: %s\n", __func__);
+}
+
+static void maru_brill_codec_get_cpu_cores(MaruBrillCodecState *s)
+{
+    s->worker_thread_cnt = get_number_of_processors();
+    if (s->worker_thread_cnt < DEFAULT_WORKER_THREAD_CNT) {
+        s->worker_thread_cnt = DEFAULT_WORKER_THREAD_CNT;
+    }
+
+    TRACE("number of threads: %d\n", s->worker_thread_cnt);
+}
+
+static void maru_brill_codec_bh_callback(void *opaque)
+{
+    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+    TRACE("enter: %s\n", __func__);
+
+    qemu_mutex_lock(&s->context_queue_mutex);
+    if (!QTAILQ_EMPTY(&codec_wq)) {
+        qemu_mutex_unlock(&s->context_queue_mutex);
+
+        TRACE("raise irq\n");
+        pci_set_irq(&s->dev, 1);
+        s->irq_raised = 1;
+    } else {
+        qemu_mutex_unlock(&s->context_queue_mutex);
+        TRACE("codec_wq is empty!!\n");
+    }
+
+    TRACE("leave: %s\n", __func__);
+}
+
+static uint64_t maru_brill_codec_read(void *opaque,
+                                        hwaddr addr,
+                                        unsigned size)
+{
+    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case CODEC_CMD_GET_THREAD_STATE:
+        qemu_mutex_lock(&s->context_queue_mutex);
+        if (s->irq_raised) {
+            ret = CODEC_TASK_END;
+            pci_set_irq(&s->dev, 0);
+            s->irq_raised = 0;
+        }
+        qemu_mutex_unlock(&s->context_queue_mutex);
+
+        TRACE("get thread_state. ret: %d\n", ret);
+        break;
+
+    case CODEC_CMD_GET_CTX_FROM_QUEUE:
+    {
+        DeviceMemEntry *head = NULL;
+
+        qemu_mutex_lock(&s->context_queue_mutex);
+        head = QTAILQ_FIRST(&codec_wq);
+        if (head) {
+            ret = head->ctx_id;
+            QTAILQ_REMOVE(&codec_wq, head, node);
+            entry[ret] = head;
+            TRACE("get a elem from codec_wq. 0x%x\n", head);
+        } else {
+            ret = 0;
+        }
+        qemu_mutex_unlock(&s->context_queue_mutex);
+
+        TRACE("get a head from a writequeue. head: %x\n", ret);
+    }
+        break;
+
+    case CODEC_CMD_GET_VERSION:
+        ret = CODEC_VERSION;
+        TRACE("codec version: %d\n", ret);
+        break;
+
+    case CODEC_CMD_GET_ELEMENT:
+        ret = maru_brill_codec_query_list(s);
+        break;
+
+    case CODEC_CMD_GET_CONTEXT_INDEX:
+        ret = maru_brill_codec_get_context_index(s);
+        TRACE("get context index: %d\n", ret);
+        break;
+
+    default:
+        ERR("no avaiable command for read. %d\n", addr);
+    }
+
+    return ret;
+}
+
+static void maru_brill_codec_write(void *opaque, hwaddr addr,
+                                    uint64_t value, unsigned size)
+{
+    MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+    switch (addr) {
+    case CODEC_CMD_API_INDEX:
+        TRACE("set codec_cmd value: %d\n", value);
+        s->ioparam.api_index = value;
+        maru_brill_codec_wakeup_threads(s, value);
+        break;
+
+    case CODEC_CMD_CONTEXT_INDEX:
+        TRACE("set context_index value: %d\n", value);
+        s->ioparam.ctx_index = value;
+        break;
+
+    case CODEC_CMD_DEVICE_MEM_OFFSET:
+        TRACE("set mem_offset value: 0x%x\n", value);
+        s->ioparam.mem_offset = value;
+        break;
+
+    case CODEC_CMD_RELEASE_CONTEXT:
+    {
+        int ctx_id = (int32_t)value;
+
+        if (CONTEXT(s, ctx_id).occupied_thread) {
+            CONTEXT(s, ctx_id).requested_close = true;
+            INFO("make running thread to handle deinit\n");
+        } else {
+            maru_brill_codec_release_context(s, ctx_id);
+        }
+    }
+        break;
+
+    case CODEC_CMD_GET_DATA_FROM_QUEUE:
+        maru_brill_codec_pop_writequeue(s, (uint32_t)value);
+        break;
+
+    default:
+        ERR("no available command for write. %d\n", addr);
+    }
+}
+
+static const MemoryRegionOps maru_brill_codec_mmio_ops = {
+    .read = maru_brill_codec_read,
+    .write = maru_brill_codec_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int maru_brill_codec_initfn(PCIDevice *dev)
+{
+    MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    INFO("device initialization.\n");
+    pci_config_set_interrupt_pin(pci_conf, 1);
+
+    memory_region_init_ram(&s->vram, OBJECT(s), "maru_brill_codec.vram", CODEC_MEM_SIZE);
+    s->vaddr = (uint8_t *)memory_region_get_ram_ptr(&s->vram);
+
+    memory_region_init_io(&s->mmio, OBJECT(s), &maru_brill_codec_mmio_ops, s,
+                        "maru_brill_codec.mmio", CODEC_REG_SIZE);
+
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+    qemu_mutex_init(&s->context_mutex);
+    qemu_mutex_init(&s->context_queue_mutex);
+    qemu_mutex_init(&s->ioparam_queue_mutex);
+
+    maru_brill_codec_get_cpu_cores(s);
+    maru_brill_codec_threads_create(s);
+
+    // register a function to qemu bottom-halves to switch context.
+    s->codec_bh = qemu_bh_new(maru_brill_codec_bh_callback, s);
+
+    return 0;
+}
+
+static void maru_brill_codec_exitfn(PCIDevice *dev)
+{
+    MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
+    INFO("device exit\n");
+
+    qemu_mutex_destroy(&s->context_mutex);
+    qemu_mutex_destroy(&s->context_queue_mutex);
+    qemu_mutex_destroy(&s->ioparam_queue_mutex);
+
+    qemu_bh_delete(s->codec_bh);
+
+    memory_region_destroy(&s->vram);
+    memory_region_destroy(&s->mmio);
+}
+
+static void maru_brill_codec_reset(DeviceState *d)
+{
+    MaruBrillCodecState *s = (MaruBrillCodecState *)d;
+    INFO("device reset\n");
+
+    s->irq_raised = 0;
+
+    memset(&s->context, 0, sizeof(CodecContext) * CODEC_CONTEXT_MAX);
+    memset(&s->ioparam, 0, sizeof(CodecParam));
+}
+
+static void maru_brill_codec_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = maru_brill_codec_initfn;
+    k->exit = maru_brill_codec_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_TIZEN;
+    k->device_id = PCI_DEVICE_ID_VIRTUAL_BRILL_CODEC;
+    k->class_id = PCI_CLASS_OTHERS;
+    dc->reset = maru_brill_codec_reset;
+    dc->desc = "Virtual new codec device for Tizen emulator";
+}
+
+static TypeInfo codec_device_info = {
+    .name          = CODEC_DEVICE_NAME,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(MaruBrillCodecState),
+    .class_init    = maru_brill_codec_class_init,
+};
+
+static void codec_register_types(void)
+{
+    type_register_static(&codec_device_info);
+}
+
+type_init(codec_register_types)