From 7da86bb9b2d4a39bc842cc0482b584f60e0da11f Mon Sep 17 00:00:00 2001 From: SeokYeon Hwang Date: Sat, 2 Aug 2014 21:17:33 +0900 Subject: [PATCH] brillcodec: prepare plugin structure for hardware accleration Change-Id: I009c3f3eb2e0d15833c9e70716b7e3fee7b324ad Signed-off-by: SeokYeon Hwang --- tizen/src/hw/pci/maru_brillcodec.c | 153 +++++++++++++++++++++++------- tizen/src/hw/pci/maru_brillcodec.h | 28 +++++- tizen/src/hw/pci/maru_brillcodec_device.c | 11 ++- 3 files changed, 153 insertions(+), 39 deletions(-) diff --git a/tizen/src/hw/pci/maru_brillcodec.c b/tizen/src/hw/pci/maru_brillcodec.c index 5920019..2fb6efe 100644 --- a/tizen/src/hw/pci/maru_brillcodec.c +++ b/tizen/src/hw/pci/maru_brillcodec.c @@ -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) { diff --git a/tizen/src/hw/pci/maru_brillcodec.h b/tizen/src/hw/pci/maru_brillcodec.h index 770465d..3e0ab9d 100644 --- a/tizen/src/hw/pci/maru_brillcodec.h +++ b/tizen/src/hw/pci/maru_brillcodec.h @@ -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__ diff --git a/tizen/src/hw/pci/maru_brillcodec_device.c b/tizen/src/hw/pci/maru_brillcodec_device.c index 5869ca9..2a05e5f 100644 --- a/tizen/src/hw/pci/maru_brillcodec_device.c +++ b/tizen/src/hw/pci/maru_brillcodec_device.c @@ -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; } -- 2.7.4