brillcodec: prepare plugin structure for hardware accleration 20/25320/2
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Sat, 2 Aug 2014 12:17:33 +0000 (21:17 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Thu, 7 Aug 2014 05:45:10 +0000 (14:45 +0900)
Change-Id: I009c3f3eb2e0d15833c9e70716b7e3fee7b324ad
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
tizen/src/hw/pci/maru_brillcodec.c
tizen/src/hw/pci/maru_brillcodec.h
tizen/src/hw/pci/maru_brillcodec_device.c

index 5920019..2fb6efe 100644 (file)
@@ -34,6 +34,7 @@
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
 #include "libavformat/avformat.h"
+#include "libavutil/pixdesc.h"
 
 #include "debug_ch.h"
 
@@ -210,7 +211,7 @@ void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
     qemu_mutex_lock(&s->context_mutex);
 
     if (ioparam->api_index != CODEC_INIT) {
-        if (!CONTEXT(s, ioparam->ctx_index).opened_context) {
+        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);
@@ -276,7 +277,7 @@ void *maru_brill_codec_threads(void *opaque)
         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;
+        CONTEXT(s, ctx_id)->occupied_thread = true;
         qemu_mutex_unlock(&s->context_mutex);
 
         ret = codec_func_handler[api_id](s, ctx_id, indata_buf);
@@ -306,11 +307,11 @@ void *maru_brill_codec_threads(void *opaque)
         g_free(elem);
 
         qemu_mutex_lock(&s->context_mutex);
-        if (CONTEXT(s, ctx_id).requested_close) {
+        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;
+            CONTEXT(s, ctx_id)->requested_close = false;
         }
         qemu_mutex_unlock(&s->context_mutex);
 
@@ -318,7 +319,7 @@ void *maru_brill_codec_threads(void *opaque)
         qemu_bh_schedule(s->codec_bh);
 
         qemu_mutex_lock(&s->context_mutex);
-        CONTEXT(s, ctx_id).occupied_thread = false;
+        CONTEXT(s, ctx_id)->occupied_thread = false;
         qemu_mutex_unlock(&s->context_mutex);
     }
 
@@ -543,12 +544,12 @@ void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t ctx_id)
     TRACE("release %d of context\n", ctx_id);
 
     qemu_mutex_lock(&s->threadpool.mutex);
-    if (CONTEXT(s, ctx_id).opened_context) {
+    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;
+    CONTEXT(s, ctx_id)->occupied_context = false;
     qemu_mutex_unlock(&s->threadpool.mutex);
 
     // TODO: check if foreach statment needs lock or not.
@@ -672,9 +673,9 @@ int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
     // 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) {
+        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;
+            CONTEXT(s, ctx_id)->occupied_context = true;
             break;
         }
     }
@@ -691,6 +692,76 @@ int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
     return ctx_id;
 }
 
+static enum PixelFormat get_format(AVCodecContext *avctx,
+                                          const enum PixelFormat *pi_fmt) {
+    bool can_hwaccel = false;
+    int i;
+
+    CodecContext *context = (CodecContext *)avctx->opaque;
+    MaruBrillCodecState *s = context->state;
+
+    if (s->hwaccel_plugin) {
+        goto end;
+    }
+
+    for (i = 0; pi_fmt[i] != PIX_FMT_NONE; ++i) {
+        const AVPixFmtDescriptor *dsc = av_pix_fmt_desc_get(pi_fmt[i]);
+        if (dsc == NULL) {
+            continue;
+        }
+        bool hwaccel = (dsc->flags & PIX_FMT_HWACCEL) != 0;
+
+        if (hwaccel) {
+            can_hwaccel = true;
+        }
+    }
+
+    if (!can_hwaccel) {
+        goto end;
+    }
+
+
+    if (s->hwaccel_plugin->setup(avctx, avctx->width, avctx->height)) {
+        goto end;
+    }
+
+    for (i = 0; pi_fmt[i] != PIX_FMT_NONE; ++i) {
+        if (pi_fmt[i] == s->hwaccel_plugin->pix_fmt) {
+            break;
+        }
+    }
+
+    if (pi_fmt[i] == PIX_FMT_NONE) {
+        goto end;
+    }
+
+    context->is_hwaccel = true;
+    return pi_fmt[i];
+
+end:
+    context->is_hwaccel = false;
+    return avcodec_default_get_format(avctx, pi_fmt);
+}
+
+static int get_buffer(struct AVCodecContext *avctx, AVFrame *frame) {
+    CodecContext *context = (CodecContext *)avctx->opaque;
+
+    if (context->is_hwaccel) {
+        return context->state->hwaccel_plugin->get_buffer(avctx, frame);
+    }
+
+    return avcodec_default_get_buffer(avctx, frame);
+}
+
+static void release_buffer(struct AVCodecContext *avctx, AVFrame *frame) {
+    CodecContext *context = (CodecContext *)avctx->opaque;
+
+    if (context->is_hwaccel) {
+        return context->state->hwaccel_plugin->release_buffer(avctx, frame);
+    }
+
+    return avcodec_default_release_buffer(avctx, frame);
+}
 
 // allocate avcontext and avframe struct.
 static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, int ctx_id)
@@ -698,13 +769,22 @@ static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, in
     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;
+
+    AVCodecContext *avctx = CONTEXT(s, ctx_id)->avctx;
+    avctx = avcodec_alloc_context3(NULL);
+    avctx->get_format = get_format;
+    avctx->get_buffer = get_buffer;
+    avctx->reget_buffer = avcodec_default_reget_buffer;
+    avctx->release_buffer = release_buffer;
+    avctx->opaque = CONTEXT(s, ctx_id);
+
+    CONTEXT(s, ctx_id)->frame = avcodec_alloc_frame();
+    CONTEXT(s, ctx_id)->opened_context = false;
+    CONTEXT(s, ctx_id)->state = s;
 
     TRACE("leave: %s\n", __func__);
 
-    return CONTEXT(s, ctx_id).avctx;
+    return CONTEXT(s, ctx_id)->avctx;
 }
 
 static AVCodec *maru_brill_codec_find_avcodec(uint8_t *mem_buf)
@@ -917,8 +997,8 @@ static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *data_buf)
                            + sizeof(avctx->extradata_size) + avctx->extradata_size)
                            + sizeof(int);
 
-            CONTEXT(s, ctx_id).opened_context = true;
-            CONTEXT(s, ctx_id).parser_ctx =
+            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);
@@ -968,9 +1048,9 @@ static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
 
     TRACE("enter: %s\n", __func__);
 
-    avctx = CONTEXT(s, ctx_id).avctx;
-    frame = CONTEXT(s, ctx_id).frame;
-    parserctx = CONTEXT(s, ctx_id).parser_ctx;
+    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);
@@ -980,31 +1060,31 @@ static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
     INFO("close avcontext of %d\n", ctx_id);
     // qemu_mutex_lock(&s->threadpool.mutex);
     avcodec_close(avctx);
-    CONTEXT(s, ctx_id).opened_context = false;
+    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;
+        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;
+        CONTEXT(s, ctx_id)->frame = NULL;
     }
 
     if (avctx) {
         TRACE("free codec context\n");
         av_free(avctx);
-        CONTEXT(s, ctx_id).avctx = NULL;
+        CONTEXT(s, ctx_id)->avctx = NULL;
     }
 
     if (parserctx) {
         av_parser_close(parserctx);
-        CONTEXT(s, ctx_id).parser_ctx = NULL;
+        CONTEXT(s, ctx_id)->parser_ctx = NULL;
     }
 
     maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
@@ -1021,7 +1101,7 @@ static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_b
 
     TRACE("enter: %s\n", __func__);
 
-    avctx = CONTEXT(s, ctx_id).avctx;
+    avctx = CONTEXT(s, ctx_id)->avctx;
     if (!avctx) {
         ERR("%d of AVCodecContext is NULL.\n", ctx_id);
         ret = false;
@@ -1078,8 +1158,8 @@ static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_bu
     avpkt.data = inbuf;
     avpkt.size = inbuf_size;
 
-    avctx = CONTEXT(s, ctx_id).avctx;
-    picture = CONTEXT(s, ctx_id).frame;
+    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) {
@@ -1135,6 +1215,7 @@ static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_bu
     return true;
 }
 
+
 static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
 {
     AVCodecContext *avctx = NULL;
@@ -1146,8 +1227,8 @@ static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
 
     TRACE("copy decoded image of %d context.\n", ctx_id);
 
-    avctx = CONTEXT(s, ctx_id).avctx;
-    src = (AVPicture *)CONTEXT(s, ctx_id).frame;
+    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;
@@ -1167,7 +1248,11 @@ static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
             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);
+            if (CONTEXT(s, ctx_id)->is_hwaccel) {
+                maru_brill_codec_push_writequeue(s, src, pict_size, ctx_id, s->hwaccel_plugin->video_decode_data_handler);
+            } else {
+                maru_brill_codec_push_writequeue(s, src, pict_size, ctx_id, &default_video_decode_data_handler);
+            }
         }
     }
 
@@ -1214,8 +1299,8 @@ static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_bu
     avpkt.data = inbuf;
     avpkt.size = inbuf_size;
 
-    avctx = CONTEXT(s, ctx_id).avctx;
-    // audio_out = CONTEXT(s, ctx_id).frame;
+    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);
@@ -1336,8 +1421,8 @@ static bool codec_encode_video(MaruBrillCodecState *s, int ctx_id, void *data_bu
     avpkt.data = NULL;
     avpkt.size = 0;
 
-    avctx = CONTEXT(s, ctx_id).avctx;
-    pict = CONTEXT(s, ctx_id).frame;
+    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) {
@@ -1468,7 +1553,7 @@ static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_bu
         // return false;
     }
 
-    avctx = CONTEXT(s, ctx_id).avctx;
+    avctx = CONTEXT(s, ctx_id)->avctx;
     if (!avctx) {
         ERR("[%s] %d of Context is NULL!\n", __func__, ctx_id);
     } else if (!avctx->codec) {
index 770465d..3e0ab9d 100644 (file)
@@ -38,7 +38,7 @@
 #define CODEC_CONTEXT_MAX           1024
 #define CODEC_MEM_SIZE          (32 * 1024 * 1024)
 
-#define CONTEXT(s, id)        (s->context[id])
+#define CONTEXT(s, id)        (&s->context[id])
 
 /*
  *  Codec Device Structures
@@ -49,7 +49,12 @@ typedef struct CodecParam {
     uint32_t    mem_offset;
 } CodecParam;
 
+struct MaruBrillCodecState;
+typedef struct MaruBrillCodecState MaruBrillCodecState;
+
 typedef struct CodecContext {
+    MaruBrillCodecState     *state;
+
     AVCodecContext          *avctx;
     AVFrame                 *frame;
     AVCodecParserContext    *parser_ctx;
@@ -59,6 +64,8 @@ typedef struct CodecContext {
     bool                    occupied_thread;
     bool                    opened_context;
     bool                    requested_close;
+
+    bool                    is_hwaccel;
 } CodecContext;
 
 typedef struct CodecThreadPool {
@@ -72,7 +79,15 @@ typedef struct DataHandler {
     void (*release)(void *opaque);
 } DataHandler;
 
-typedef struct MaruBrillCodecState {
+typedef struct CodecPlugin {
+    enum PixelFormat    pix_fmt;
+    bool                (*setup)(AVCodecContext *, int , int);
+    int                 (*get_buffer)(struct AVCodecContext *, AVFrame *);
+    void                (*release_buffer)(struct AVCodecContext *, AVFrame *);
+    DataHandler         *video_decode_data_handler;
+} CodecPlugin;
+
+struct MaruBrillCodecState {
     PCIDevice           dev;
 
     uint8_t             *vaddr;
@@ -93,7 +108,9 @@ typedef struct MaruBrillCodecState {
 
     CodecContext        context[CODEC_CONTEXT_MAX];
     CodecParam          ioparam;
-} MaruBrillCodecState;
+
+    CodecPlugin         *hwaccel_plugin;
+};
 
 typedef struct DeviceMemEntry {
     void *opaque;
@@ -118,4 +135,9 @@ void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx);
 
 void *maru_brill_codec_threads(void *opaque);
 
+// plugins
+#ifdef CONFIG_VAAPI
+CodecPlugin *vaapi_probe(void);
+#endif
+
 #endif // __MARU_BRILLCODEC_H__
index 5869ca9..2a05e5f 100644 (file)
@@ -212,8 +212,8 @@ static void maru_brill_codec_write(void *opaque, hwaddr addr,
     {
         int ctx_id = (int32_t)value;
 
-        if (CONTEXT(s, ctx_id).occupied_thread) {
-            CONTEXT(s, ctx_id).requested_close = true;
+        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);
@@ -268,6 +268,13 @@ static int maru_brill_codec_initfn(PCIDevice *dev)
     // register a function to qemu bottom-halves to switch context.
     s->codec_bh = qemu_bh_new(maru_brill_codec_bh_callback, s);
 
+    // register plugins
+#ifdef CONFIG_VAAPI
+    if (!(s->hwaccel_plugin = vaapi_probe())) {
+        INFO("VA-API extension is enabled.");
+    }
+#endif
+
     return 0;
 }