hardware: exynos5: add initial exynos_omx

Change-Id: I22fd3ef5b76884d520e8bb3441c64aa3e145a5f2
Signed-off-by: Jiho Chang <jiho04.chang@samsung.com>
diff --git a/exynos_omx/codecs/exynos_codecs/video/exynos5/mfc_v4l2/dec/src/ExynosVideoDecoder.c b/exynos_omx/codecs/exynos_codecs/video/exynos5/mfc_v4l2/dec/src/ExynosVideoDecoder.c
new file mode 100644
index 0000000..82b9e44
--- /dev/null
+++ b/exynos_omx/codecs/exynos_codecs/video/exynos5/mfc_v4l2/dec/src/ExynosVideoDecoder.c
@@ -0,0 +1,1432 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * @file        ExynosVideoDecoder.c
+ * @brief
+ * @author      Jinsung Yang (jsgood.yang@samsung.com)
+ * @version     1.0.0
+ * @history
+ *   2012.01.15: Initial Version
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <sys/poll.h>
+
+#include "ExynosVideoApi.h"
+#include "ExynosVideoDec.h"
+#include "exynos_v4l2.h"
+
+/* #define LOG_NDEBUG 0 */
+#define LOG_TAG "ExynosVideoDecoder"
+#include <utils/Log.h>
+
+/*
+ * [Common] __CodingType_To_V4L2PixelFormat
+ */
+static unsigned int __CodingType_To_V4L2PixelFormat(ExynosVideoCodingType codingType)
+{
+    unsigned int pixelformat = V4L2_PIX_FMT_H264;
+
+    switch (codingType) {
+    case VIDEO_CODING_AVC:
+        pixelformat = V4L2_PIX_FMT_H264;
+        break;
+    case VIDEO_CODING_MPEG4:
+        pixelformat = V4L2_PIX_FMT_MPEG4;
+        break;
+    case VIDEO_CODING_VP8:
+        pixelformat = V4L2_PIX_FMT_VP8;
+        break;
+    case VIDEO_CODING_H263:
+        pixelformat = V4L2_PIX_FMT_H263;
+        break;
+    case VIDEO_CODING_VC1:
+        pixelformat = V4L2_PIX_FMT_VC1_ANNEX_G;
+        break;
+    case VIDEO_CODING_VC1_RCV:
+        pixelformat = V4L2_PIX_FMT_VC1_ANNEX_L;
+        break;
+    case VIDEO_CODING_MPEG2:
+        pixelformat = V4L2_PIX_FMT_MPEG1;
+        break;
+    default:
+        pixelformat = V4L2_PIX_FMT_H264;
+        break;
+    }
+
+    return pixelformat;
+}
+
+/*
+ * [Common] __ColorFormatType_To_V4L2PixelFormat
+ */
+static unsigned int __ColorFormatType_To_V4L2PixelFormat(ExynosVideoColorFormatType colorFormatType)
+{
+    unsigned int pixelformat = V4L2_PIX_FMT_NV12M;
+
+    switch (colorFormatType) {
+    case VIDEO_COLORFORMAT_NV12_TILED:
+        pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
+        break;
+    case VIDEO_COLORFORMAT_NV21:
+        pixelformat = V4L2_PIX_FMT_NV21M;
+        break;
+    case VIDEO_COLORFORMAT_NV12:
+    default:
+        pixelformat = V4L2_PIX_FMT_NV12M;
+        break;
+    }
+
+    return pixelformat;
+}
+
+/*
+ * [Decoder OPS] Init
+ */
+static void *MFC_Decoder_Init(void)
+{
+    ExynosVideoDecContext *pCtx     = NULL;
+    int                    needCaps = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING);
+
+    pCtx = (ExynosVideoDecContext *)malloc(sizeof(*pCtx));
+    if (pCtx == NULL) {
+        LOGE("%s: Failed to allocate decoder context buffer", __func__);
+        goto EXIT_ALLOC_FAIL;
+    }
+
+    memset(pCtx, 0, sizeof(*pCtx));
+
+    pCtx->hDec = exynos_v4l2_open_devname(VIDEO_DECODER_NAME, O_RDWR | O_NONBLOCK, 0);
+    if (pCtx->hDec < 0) {
+        LOGE("%s: Failed to open decoder device", __func__);
+        goto EXIT_OPEN_FAIL;
+    }
+
+    if (!exynos_v4l2_querycap(pCtx->hDec, needCaps)) {
+        LOGE("%s: Failed to querycap", __func__);
+        goto EXIT_QUERYCAP_FAIL;
+    }
+
+    pCtx->bStreamonInbuf = VIDEO_FALSE;
+    pCtx->bStreamonOutbuf = VIDEO_FALSE;
+
+    return (void *)pCtx;
+
+EXIT_QUERYCAP_FAIL:
+    close(pCtx->hDec);
+
+EXIT_OPEN_FAIL:
+    free(pCtx);
+    pCtx = NULL;
+
+EXIT_ALLOC_FAIL:
+    return NULL;
+}
+
+/*
+ * [Decoder OPS] Finalize
+ */
+static ExynosVideoErrorType MFC_Decoder_Finalize(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+    ExynosVideoPlane      *pVideoPlane;
+
+    int i, j;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (pCtx->bShareInbuf == VIDEO_FALSE) {
+        for (i = 0; i < pCtx->nInbufs; i++) {
+            for (j = 0; j < VIDEO_DECODER_INBUF_PLANES; j++) {
+                pVideoPlane = &pCtx->pInbuf[i].planes[j];
+                if (pVideoPlane->addr != NULL) {
+                    munmap(pVideoPlane->addr, pVideoPlane->allocSize);
+                    pVideoPlane->addr = NULL;
+                    pVideoPlane->allocSize = 0;
+                    pVideoPlane->dataSize = 0;
+                }
+
+                pCtx->pInbuf[i].pGeometry = NULL;
+                pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
+            }
+        }
+    }
+
+    if (pCtx->bShareOutbuf == VIDEO_FALSE) {
+        for (i = 0; i < pCtx->nOutbufs; i++) {
+            for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
+                pVideoPlane = &pCtx->pOutbuf[i].planes[j];
+                if (pVideoPlane->addr != NULL) {
+                    munmap(pVideoPlane->addr, pVideoPlane->allocSize);
+                    pVideoPlane->addr = NULL;
+                    pVideoPlane->allocSize = 0;
+                    pVideoPlane->dataSize = 0;
+                }
+
+                pCtx->pOutbuf[i].pGeometry = NULL;
+                pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
+            }
+        }
+    }
+
+    if (pCtx->pInbuf != NULL)
+        free(pCtx->pInbuf);
+
+    if (pCtx->pOutbuf != NULL)
+        free(pCtx->pOutbuf);
+
+    if (pCtx->hDec > 0)
+        close(pCtx->hDec);
+
+    free(pCtx);
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder OPS] Set Frame Tag
+ */
+static ExynosVideoErrorType MFC_Decoder_Set_FrameTag(
+    void *pHandle,
+    int   frameTag)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, frameTag)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder OPS] Get Frame Tag
+ */
+static int MFC_Decoder_Get_FrameTag(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    int frameTag = -1;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        goto EXIT;
+    }
+
+    exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, &frameTag);
+
+EXIT:
+    return frameTag;
+}
+
+/*
+ * [Decoder OPS] Get Buffer Count
+ */
+static int MFC_Decoder_Get_ActualBufferCount(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    int bufferCount = -1;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        goto EXIT;
+    }
+
+    exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, &bufferCount);
+
+EXIT:
+    return bufferCount;
+}
+
+/*
+ * [Decoder OPS] Set Cacheable
+ */
+static ExynosVideoErrorType MFC_Decoder_Enable_Cacheable(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_CACHEABLE, 1)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder OPS] Set Display Delay
+ */
+static ExynosVideoErrorType MFC_Decoder_Set_DisplayDelay(
+    void *pHandle,
+    int   delay)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, delay)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder OPS] Enable Packed PB
+ */
+static ExynosVideoErrorType MFC_Decoder_Enable_PackedPB(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB, 1)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder OPS] Enable Loop Filter
+ */
+static ExynosVideoErrorType MFC_Decoder_Enable_LoopFilter(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, 1)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder OPS] Enable Slice Mode
+ */
+static ExynosVideoErrorType MFC_Decoder_Enable_SliceMode(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (exynos_v4l2_s_ctrl(pCtx->hDec, V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, 1)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Set Shareable Buffer (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Set_Shareable_Inbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    pCtx->bShareInbuf = VIDEO_TRUE;
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Set Shareable Buffer (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Set_Shareable_Outbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    pCtx->bShareOutbuf = VIDEO_TRUE;
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Get Buffer Info (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Get_BufferInfo_Inbuf(
+    void              *pHandle,
+    int                nIndex,
+    ExynosVideoBuffer *pBuffer)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_NOBUFFERS;
+        goto EXIT;
+    }
+
+    memcpy(pBuffer, &pCtx->pInbuf[nIndex], sizeof(*pBuffer));
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Get Buffer Info (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Get_BufferInfo_Outbuf(
+    void              *pHandle,
+    int                nIndex,
+    ExynosVideoBuffer *pBuffer)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_NOBUFFERS;
+        goto EXIT;
+    }
+
+    memcpy(pBuffer, &pCtx->pOutbuf[nIndex], sizeof(*pBuffer));
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Set Geometry (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Set_Geometry_Inbuf(
+    void                *pHandle,
+    ExynosVideoGeometry *bufferConf)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    struct v4l2_format fmt;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (bufferConf == NULL) {
+        LOGE("%s: Buffer geometry must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&fmt, 0, sizeof(fmt));
+
+    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    fmt.fmt.pix_mp.pixelformat = __CodingType_To_V4L2PixelFormat(bufferConf->eCompressionFormat);
+    fmt.fmt.pix_mp.plane_fmt[0].sizeimage = bufferConf->nSizeImage;
+
+    if (exynos_v4l2_s_fmt(pCtx->hDec, &fmt)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    memcpy(&pCtx->inbufGeometry, bufferConf, sizeof(pCtx->inbufGeometry));
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Set Geometry (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Set_Geometry_Outbuf(
+    void                *pHandle,
+    ExynosVideoGeometry *bufferConf)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    struct v4l2_format fmt;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (bufferConf == NULL) {
+        LOGE("%s: Buffer geometry must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&fmt, 0, sizeof(fmt));
+
+    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    fmt.fmt.pix_mp.pixelformat = __ColorFormatType_To_V4L2PixelFormat(bufferConf->eColorFormat);
+
+    if (exynos_v4l2_s_fmt(pCtx->hDec, &fmt)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    memcpy(&pCtx->outbufGeometry, bufferConf, sizeof(pCtx->outbufGeometry));
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Get Geometry (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Get_Geometry_Outbuf(
+    void                *pHandle,
+    ExynosVideoGeometry *bufferConf)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    struct v4l2_format fmt;
+    struct v4l2_crop   crop;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (bufferConf == NULL) {
+        LOGE("%s: Buffer geometry must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&fmt, 0, sizeof(fmt));
+    memset(&crop, 0, sizeof(crop));
+
+    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    if (exynos_v4l2_g_fmt(pCtx->hDec, &fmt)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    if (exynos_v4l2_g_crop(pCtx->hDec, &crop)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    bufferConf->nFrameWidth = fmt.fmt.pix_mp.width;
+    bufferConf->nFrameHeight = fmt.fmt.pix_mp.height;
+
+    bufferConf->cropRect.nTop = crop.c.top;
+    bufferConf->cropRect.nLeft = crop.c.left;
+    bufferConf->cropRect.nWidth = crop.c.width;
+    bufferConf->cropRect.nHeight = crop.c.height;
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Setup (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Setup_Inbuf(
+    void         *pHandle,
+    unsigned int  nBufferCount)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+    ExynosVideoPlane      *pVideoPlane;
+
+    struct v4l2_requestbuffers req;
+    struct v4l2_buffer         buf;
+    struct v4l2_plane          planes[VIDEO_DECODER_INBUF_PLANES];
+    int i;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (nBufferCount == 0) {
+        LOGE("%s: Buffer count must be greater than 0", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&req, 0, sizeof(req));
+
+    req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    req.count = nBufferCount;
+
+    if (pCtx->bShareInbuf == VIDEO_TRUE)
+        req.memory = V4L2_MEMORY_USERPTR;
+    else
+        req.memory = V4L2_MEMORY_MMAP;
+
+    if (exynos_v4l2_reqbufs(pCtx->hDec, &req)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    pCtx->nInbufs = (int)req.count;
+
+    pCtx->pInbuf = malloc(sizeof(*pCtx->pInbuf) * pCtx->nInbufs);
+    if (pCtx->pInbuf == NULL) {
+        LOGE("Failed to allocate input buffer context");
+        ret = VIDEO_ERROR_NOMEM;
+        goto EXIT;
+    }
+    memset(pCtx->pInbuf, 0, sizeof(*pCtx->pInbuf) * pCtx->nInbufs);
+
+    memset(&buf, 0, sizeof(buf));
+
+    if (pCtx->bShareInbuf == VIDEO_FALSE) {
+        buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+        buf.memory = V4L2_MEMORY_MMAP;
+        buf.m.planes = planes;
+        buf.length = VIDEO_DECODER_INBUF_PLANES;
+
+        for (i = 0; i < pCtx->nInbufs; i++) {
+            buf.index = i;
+            if (exynos_v4l2_querybuf(pCtx->hDec, &buf)) {
+                ret = VIDEO_ERROR_APIFAIL;
+                goto EXIT;
+            }
+
+            pVideoPlane = &pCtx->pInbuf[i].planes[0];
+
+            pVideoPlane->addr = mmap(NULL,
+                    buf.m.planes[0].length, PROT_READ | PROT_WRITE,
+                    MAP_SHARED, pCtx->hDec, buf.m.planes[0].m.mem_offset);
+
+            if (pVideoPlane->addr == MAP_FAILED) {
+                ret = VIDEO_ERROR_MAPFAIL;
+                goto EXIT;
+            }
+
+            pVideoPlane->allocSize = buf.m.planes[0].length;
+            pVideoPlane->dataSize = 0;
+
+            pCtx->pInbuf[i].pGeometry = &pCtx->inbufGeometry;
+            pCtx->pInbuf[i].bQueued = VIDEO_TRUE;
+        }
+    }
+
+    return ret;
+
+EXIT:
+    if (pCtx->bShareInbuf == VIDEO_FALSE) {
+        for (i = 0; i < pCtx->nInbufs; i++) {
+            pVideoPlane = &pCtx->pInbuf[i].planes[0];
+            if (pVideoPlane->addr == MAP_FAILED) {
+                pVideoPlane->addr = NULL;
+                break;
+            }
+
+            munmap(pVideoPlane->addr, pVideoPlane->allocSize);
+            pVideoPlane->allocSize = 0;
+            pVideoPlane->dataSize = 0;
+
+            pCtx->pInbuf[i].pGeometry = NULL;
+            pCtx->pInbuf[i].bQueued = VIDEO_FALSE;
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Setup (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Setup_Outbuf(
+    void         *pHandle,
+    unsigned int  nBufferCount)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+    ExynosVideoPlane      *pVideoPlane;
+
+    struct v4l2_requestbuffers req;
+    struct v4l2_buffer         buf;
+    struct v4l2_plane          planes[VIDEO_DECODER_OUTBUF_PLANES];
+    int i, j;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (nBufferCount == 0) {
+        LOGE("%s: Buffer count must be greater than 0", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&req, 0, sizeof(req));
+
+    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    req.count = nBufferCount;
+
+    if (pCtx->bShareOutbuf == VIDEO_TRUE)
+        req.memory = V4L2_MEMORY_USERPTR;
+    else
+        req.memory = V4L2_MEMORY_MMAP;
+
+    if (exynos_v4l2_reqbufs(pCtx->hDec, &req)) {
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    pCtx->nOutbufs = req.count;
+
+    pCtx->pOutbuf = malloc(sizeof(*pCtx->pOutbuf) * pCtx->nOutbufs);
+    if (pCtx->pOutbuf == NULL) {
+        LOGE("Failed to allocate output buffer context");
+        ret = VIDEO_ERROR_NOMEM;
+        goto EXIT;
+    }
+    memset(pCtx->pOutbuf, 0, sizeof(*pCtx->pOutbuf) * pCtx->nOutbufs);
+
+    memset(&buf, 0, sizeof(buf));
+
+    if (pCtx->bShareOutbuf == VIDEO_FALSE) {
+        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+        buf.memory = V4L2_MEMORY_MMAP;
+        buf.m.planes = planes;
+        buf.length = VIDEO_DECODER_OUTBUF_PLANES;
+
+        for (i = 0; i < pCtx->nOutbufs; i++) {
+            buf.index = i;
+            if (exynos_v4l2_querybuf(pCtx->hDec, &buf)) {
+                ret = VIDEO_ERROR_APIFAIL;
+                goto EXIT;
+            }
+
+            for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
+                pVideoPlane = &pCtx->pOutbuf[i].planes[j];
+                pVideoPlane->addr = mmap(NULL,
+                        buf.m.planes[j].length, PROT_READ | PROT_WRITE,
+                        MAP_SHARED, pCtx->hDec, buf.m.planes[j].m.mem_offset);
+
+                if (pVideoPlane->addr == MAP_FAILED) {
+                    ret = VIDEO_ERROR_MAPFAIL;
+                    goto EXIT;
+                }
+
+                pVideoPlane->allocSize = buf.m.planes[j].length;
+                pVideoPlane->dataSize = 0;
+            }
+
+            pCtx->pOutbuf[i].pGeometry = &pCtx->outbufGeometry;
+            pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
+        }
+    }
+
+    return ret;
+
+EXIT:
+    if (pCtx->bShareOutbuf == VIDEO_FALSE) {
+        for (i = 0; i < pCtx->nOutbufs; i++) {
+            for (j = 0; j < VIDEO_DECODER_OUTBUF_PLANES; j++) {
+                pVideoPlane = &pCtx->pOutbuf[i].planes[j];
+                if (pVideoPlane->addr == MAP_FAILED) {
+                    pVideoPlane->addr = NULL;
+                    break;
+                }
+
+                munmap(pVideoPlane->addr, pVideoPlane->allocSize);
+                pVideoPlane->allocSize = 0;
+                pVideoPlane->dataSize = 0;
+            }
+
+            pCtx->pOutbuf[i].pGeometry = NULL;
+            pCtx->pOutbuf[i].bQueued = VIDEO_FALSE;
+        }
+    }
+
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Run (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Run_Inbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (pCtx->bStreamonInbuf == VIDEO_FALSE) {
+        if (exynos_v4l2_streamon(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+            LOGE("%s: Failed to streamon for input buffer", __func__);
+            ret = VIDEO_ERROR_APIFAIL;
+            goto EXIT;
+        }
+        pCtx->bStreamonInbuf = VIDEO_TRUE;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Run (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Run_Outbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
+        if (exynos_v4l2_streamon(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+            LOGE("%s: Failed to streamon for output buffer", __func__);
+            ret = VIDEO_ERROR_APIFAIL;
+            goto EXIT;
+        }
+        pCtx->bStreamonOutbuf = VIDEO_TRUE;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Stop (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Stop_Inbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (pCtx->bStreamonInbuf == VIDEO_TRUE) {
+        if (exynos_v4l2_streamoff(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+            LOGE("%s: Failed to streamoff for input buffer", __func__);
+            ret = VIDEO_ERROR_APIFAIL;
+            goto EXIT;
+        }
+        pCtx->bStreamonInbuf = VIDEO_FALSE;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Stop (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Stop_Outbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    if (pCtx->bStreamonOutbuf == VIDEO_TRUE) {
+        if (exynos_v4l2_streamoff(pCtx->hDec, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+            LOGE("%s: Failed to streamoff for output buffer", __func__);
+            ret = VIDEO_ERROR_APIFAIL;
+            goto EXIT;
+        }
+        pCtx->bStreamonOutbuf = VIDEO_FALSE;
+    }
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Wait (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Wait_Inbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    struct pollfd poll_events;
+    int poll_state;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    poll_events.fd = pCtx->hDec;
+    poll_events.events = POLLOUT | POLLERR;
+    poll_events.revents = 0;
+
+    do {
+        poll_state = poll((struct pollfd*)&poll_events, 1, VIDEO_DECODER_POLL_TIMEOUT);
+        if (poll_state > 0) {
+            if (poll_events.revents & POLLOUT) {
+                break;
+            } else {
+                LOGE("%s: Poll return error", __func__);
+                ret = VIDEO_ERROR_POLL;
+                break;
+            }
+        } else if (poll_state < 0) {
+            LOGE("%s: Poll state error", __func__);
+            ret = VIDEO_ERROR_POLL;
+            break;
+        }
+    } while (poll_state == 0);
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Find (Input)
+ */
+static int MFC_Decoder_Find_Inbuf(
+    void          *pHandle,
+    unsigned char *pBuffer)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    int nIndex = -1;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        nIndex = -1;
+        goto EXIT;
+    }
+
+    if (pBuffer == NULL) {
+        for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
+            if (pCtx->pInbuf[nIndex].bQueued == VIDEO_FALSE)
+                break;
+        }
+    } else {
+        for (nIndex = 0; nIndex < pCtx->nInbufs; nIndex++) {
+            if (pCtx->pInbuf[nIndex].planes[0].addr == pBuffer)
+                break;
+        }
+    }
+
+    if (nIndex == pCtx->nInbufs) {
+        nIndex = -1;
+        goto EXIT;
+    }
+
+EXIT:
+    return nIndex;
+}
+
+/*
+ * [Decoder Buffer OPS] Find (Outnput)
+ */
+static int MFC_Decoder_Find_Outbuf(
+    void          *pHandle,
+    unsigned char *pBuffer)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    int nIndex = -1;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        nIndex = -1;
+        goto EXIT;
+    }
+
+    if (pBuffer == NULL) {
+        for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
+            if (pCtx->pOutbuf[nIndex].bQueued == VIDEO_FALSE)
+                break;
+        }
+    } else {
+        for (nIndex = 0; nIndex < pCtx->nOutbufs; nIndex++) {
+            if (pCtx->pOutbuf[nIndex].planes[0].addr == pBuffer)
+                break;
+        }
+    }
+
+    if (nIndex == pCtx->nOutbufs) {
+        nIndex = -1;
+        goto EXIT;
+    }
+
+EXIT:
+    return nIndex;
+}
+
+/*
+ * [Decoder Buffer OPS] Enqueue (Input)
+ */
+static ExynosVideoErrorType MFC_Decoder_Enqueue_Inbuf(
+    void          *pHandle,
+    unsigned char *pBuffer[],
+    unsigned int   dataSize[],
+    int            nPlanes,
+    void          *pPrivate)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    struct v4l2_plane  planes[VIDEO_DECODER_INBUF_PLANES];
+    struct v4l2_buffer buf;
+    int index, i;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+
+    buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    buf.m.planes = planes;
+    buf.length = VIDEO_DECODER_INBUF_PLANES;
+
+    if ((pCtx->bShareInbuf == VIDEO_TRUE) || (pBuffer == NULL))
+        index = MFC_Decoder_Find_Inbuf(pCtx, NULL);
+    else
+        index = MFC_Decoder_Find_Inbuf(pCtx, pBuffer[0]);
+
+    if (index == -1) {
+        ret = VIDEO_ERROR_NOBUFFERS;
+        goto EXIT;
+    }
+
+    buf.index = index;
+
+    if (pCtx->bShareInbuf == VIDEO_TRUE) {
+        buf.memory = V4L2_MEMORY_USERPTR;
+        for (i = 0; i < nPlanes; i++) {
+            buf.m.planes[i].m.userptr = (unsigned long)pBuffer[i];
+            buf.m.planes[i].length = VIDEO_DECODER_INBUF_SIZE;
+            buf.m.planes[i].bytesused = dataSize[i];
+            pCtx->pInbuf[buf.index].planes[i].addr = pBuffer[i];
+        }
+    } else {
+        buf.memory = V4L2_MEMORY_MMAP;
+        for (i = 0; i < nPlanes; i++)
+            buf.m.planes[i].bytesused = dataSize[i];
+    }
+
+    if (exynos_v4l2_qbuf(pCtx->hDec, &buf)) {
+        LOGE("%s: Failed to enqueue input buffer", __func__);
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    pCtx->pInbuf[buf.index].pPrivate = pPrivate;
+    pCtx->pInbuf[buf.index].bQueued = VIDEO_TRUE;
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Enqueue (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Enqueue_Outbuf(
+    void          *pHandle,
+    unsigned char *pBuffer[],
+    unsigned int   dataSize[],
+    int            nPlanes,
+    void          *pPrivate)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    struct v4l2_plane  planes[VIDEO_DECODER_OUTBUF_PLANES];
+    struct v4l2_buffer buf;
+    int i, index;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+
+    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    buf.m.planes = planes;
+    buf.length = VIDEO_DECODER_OUTBUF_PLANES;
+
+    if ((pCtx->bShareOutbuf == VIDEO_TRUE) || (pBuffer == NULL))
+        index = MFC_Decoder_Find_Outbuf(pCtx, NULL);
+    else
+        index = MFC_Decoder_Find_Outbuf(pCtx, pBuffer[0]);
+
+    if (index == -1) {
+        ret = VIDEO_ERROR_NOBUFFERS;
+        goto EXIT;
+    }
+
+    buf.index = index;
+
+    if (pCtx->bShareOutbuf == VIDEO_TRUE) {
+        buf.memory = V4L2_MEMORY_USERPTR;
+        for (i = 0; i < nPlanes; i++) {
+            buf.m.planes[i].m.userptr = (unsigned long)pBuffer[i];
+            buf.m.planes[i].length = dataSize[i];
+            buf.m.planes[i].bytesused = dataSize[i];
+            pCtx->pOutbuf[buf.index].planes[i].addr = pBuffer[i];
+        }
+    } else {
+        buf.memory = V4L2_MEMORY_MMAP;
+    }
+
+    if (exynos_v4l2_qbuf(pCtx->hDec, &buf)) {
+        LOGE("%s: Failed to enqueue output buffer", __func__);
+        ret = VIDEO_ERROR_APIFAIL;
+        goto EXIT;
+    }
+
+    pCtx->pOutbuf[buf.index].pPrivate = pPrivate;
+    pCtx->pOutbuf[buf.index].bQueued = VIDEO_TRUE;
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Dequeue (Input)
+ */
+static ExynosVideoBuffer *MFC_Decoder_Dequeue_Inbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx    = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoBuffer     *pOutbuf = NULL;
+
+    struct v4l2_buffer buf;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        pOutbuf = NULL;
+        goto EXIT;
+    }
+
+    if (pCtx->bStreamonInbuf == VIDEO_FALSE) {
+        LOGE("%s: Input buffer stream is off", __func__);
+        goto EXIT;
+    }
+
+    if (MFC_Decoder_Wait_Inbuf(pCtx) != VIDEO_ERROR_NONE) {
+        LOGE("%s: Failed to poll for input buffer", __func__);
+        pOutbuf = NULL;
+        goto EXIT;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+
+    buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+    if (pCtx->bShareInbuf == VIDEO_TRUE)
+        buf.memory = V4L2_MEMORY_USERPTR;
+    else
+        buf.memory = V4L2_MEMORY_MMAP;
+
+    if (exynos_v4l2_dqbuf(pCtx->hDec, &buf) == 0) {
+        pCtx->pInbuf[buf.index].bQueued = VIDEO_FALSE;
+        pOutbuf = &pCtx->pInbuf[buf.index];
+    } else {
+        LOGE("%s: Failed to dequeue input buffer", __func__);
+        pOutbuf = NULL;
+        goto EXIT;
+    }
+
+EXIT:
+    return pOutbuf;
+}
+
+/*
+ * [Decoder Buffer OPS] Enqueue All (Output)
+ */
+static ExynosVideoErrorType MFC_Decoder_Enqueue_All_Outbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoErrorType   ret  = VIDEO_ERROR_NONE;
+
+    int i;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    for (i = 0; i < pCtx->nOutbufs; i++)
+        MFC_Decoder_Enqueue_Outbuf(pCtx, NULL, NULL, 0, NULL);
+
+EXIT:
+    return ret;
+}
+
+/*
+ * [Decoder Buffer OPS] Dequeue (Output)
+ */
+static ExynosVideoBuffer *MFC_Decoder_Dequeue_Outbuf(void *pHandle)
+{
+    ExynosVideoDecContext *pCtx    = (ExynosVideoDecContext *)pHandle;
+    ExynosVideoBuffer     *pOutbuf = NULL;
+
+    struct v4l2_buffer buf;
+    int value;
+
+    if (pCtx == NULL) {
+        LOGE("%s: Video context info must be supplied", __func__);
+        pOutbuf = NULL;
+        goto EXIT;
+    }
+
+    if (pCtx->bStreamonOutbuf == VIDEO_FALSE) {
+        LOGE("%s: Output buffer stream is off", __func__);
+        goto EXIT;
+    }
+
+    memset(&buf, 0, sizeof(buf));
+
+    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+    if (pCtx->bShareOutbuf == VIDEO_TRUE)
+        buf.memory = V4L2_MEMORY_USERPTR;
+    else
+        buf.memory = V4L2_MEMORY_MMAP;
+
+    /* HACK: pOutbuf return -1 means DECODING_ONLY for almost cases */
+    if (exynos_v4l2_dqbuf(pCtx->hDec, &buf)) {
+        LOGW("%s: Failed to dequeue output buffer or DECODING_ONLY", __func__);
+        pOutbuf = NULL;
+        goto EXIT;
+    }
+
+    pOutbuf = &pCtx->pOutbuf[buf.index];
+
+    exynos_v4l2_g_ctrl(pCtx->hDec, V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS, &value);
+
+    switch (value) {
+    case 0:
+        pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DECODING_ONLY;
+        break;
+    case 1:
+        pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DISPLAY_DECODING;
+        break;
+    case 2:
+        pOutbuf->displayStatus = VIDEO_FRAME_STATUS_DISPLAY_ONLY;
+            break;
+    case 3:
+        pOutbuf->displayStatus = VIDEO_FRAME_STATUS_CHANGE_RESOL;
+        break;
+    default:
+        pOutbuf->displayStatus = VIDEO_FRAME_STATUS_UNKNOWN;
+        break;
+    }
+
+    switch (buf.flags & (0x7 << 3)) {
+    case V4L2_BUF_FLAG_KEYFRAME:
+        pOutbuf->frameType = VIDEO_FRAME_I;
+        break;
+    case V4L2_BUF_FLAG_PFRAME:
+        pOutbuf->frameType = VIDEO_FRAME_P;
+        break;
+    case V4L2_BUF_FLAG_BFRAME:
+        pOutbuf->frameType = VIDEO_FRAME_B;
+        break;
+    default:
+        pOutbuf->frameType = VIDEO_FRAME_OTHERS;
+        break;
+    };
+
+    pOutbuf->bQueued = VIDEO_FALSE;
+
+EXIT:
+    return pOutbuf;
+}
+
+/*
+ * [Decoder OPS] Common
+ */
+static ExynosVideoDecOps defDecOps = {
+    .nSize = 0,
+    .Init = MFC_Decoder_Init,
+    .Finalize = MFC_Decoder_Finalize,
+    .Enable_Cacheable = MFC_Decoder_Enable_Cacheable,
+    .Set_DisplayDelay = MFC_Decoder_Set_DisplayDelay,
+    .Enable_PackedPB = MFC_Decoder_Enable_PackedPB,
+    .Enable_LoopFilter = MFC_Decoder_Enable_LoopFilter,
+    .Enable_SliceMode = MFC_Decoder_Enable_SliceMode,
+    .Get_ActualBufferCount = MFC_Decoder_Get_ActualBufferCount,
+    .Set_FrameTag = MFC_Decoder_Set_FrameTag,
+    .Get_FrameTag = MFC_Decoder_Get_FrameTag,
+};
+
+/*
+ * [Decoder Buffer OPS] Input
+ */
+static ExynosVideoDecBufferOps defInbufOps = {
+    .nSize = 0,
+    .Set_Shareable = MFC_Decoder_Set_Shareable_Inbuf,
+    .Get_BufferInfo = MFC_Decoder_Get_BufferInfo_Inbuf,
+    .Set_Geometry = MFC_Decoder_Set_Geometry_Inbuf,
+    .Get_Geometry = NULL,
+    .Setup = MFC_Decoder_Setup_Inbuf,
+    .Run = MFC_Decoder_Run_Inbuf,
+    .Stop = MFC_Decoder_Stop_Inbuf,
+    .Enqueue = MFC_Decoder_Enqueue_Inbuf,
+    .Enqueue_All = NULL,
+    .Dequeue = MFC_Decoder_Dequeue_Inbuf,
+};
+
+/*
+ * [Decoder Buffer OPS] Output
+ */
+static ExynosVideoDecBufferOps defOutbufOps = {
+    .nSize = 0,
+    .Set_Shareable = MFC_Decoder_Set_Shareable_Outbuf,
+    .Get_BufferInfo = MFC_Decoder_Get_BufferInfo_Outbuf,
+    .Set_Geometry = MFC_Decoder_Set_Geometry_Outbuf,
+    .Get_Geometry = MFC_Decoder_Get_Geometry_Outbuf,
+    .Setup = MFC_Decoder_Setup_Outbuf,
+    .Run = MFC_Decoder_Run_Outbuf,
+    .Stop = MFC_Decoder_Stop_Outbuf,
+    .Enqueue = MFC_Decoder_Enqueue_Outbuf,
+    .Enqueue_All = MFC_Decoder_Enqueue_All_Outbuf,
+    .Dequeue = MFC_Decoder_Dequeue_Outbuf,
+};
+
+int Exynos_Video_Register_Decoder(
+    ExynosVideoDecOps       *pDecOps,
+    ExynosVideoDecBufferOps *pInbufOps,
+    ExynosVideoDecBufferOps *pOutbufOps)
+{
+    ExynosVideoErrorType ret = VIDEO_ERROR_NONE;
+
+    if ((pDecOps == NULL) || (pInbufOps == NULL) || (pOutbufOps == NULL)) {
+        ret = VIDEO_ERROR_BADPARAM;
+        goto EXIT;
+    }
+
+    defDecOps.nSize = sizeof(defDecOps);
+    defInbufOps.nSize = sizeof(defInbufOps);
+    defOutbufOps.nSize = sizeof(defOutbufOps);
+
+    memcpy((char *)pDecOps + sizeof(pDecOps->nSize), (char *)&defDecOps + sizeof(defDecOps.nSize),
+            pDecOps->nSize - sizeof(pDecOps->nSize));
+
+    memcpy((char *)pInbufOps + sizeof(pInbufOps->nSize), (char *)&defInbufOps + sizeof(defInbufOps.nSize),
+            pInbufOps->nSize - sizeof(pInbufOps->nSize));
+
+    memcpy((char *)pOutbufOps + sizeof(pOutbufOps->nSize), (char *)&defOutbufOps + sizeof(defOutbufOps.nSize),
+            pOutbufOps->nSize - sizeof(pOutbufOps->nSize));
+
+EXIT:
+    return ret;
+}