CODEC_PICTURE_COPY,
CODEC_DEINIT,
CODEC_FLUSH_BUFFERS,
+ CODEC_DECODE_VIDEO2,
};
enum codec_type {
static bool codec_encode_audio(MaruBrillCodecState *, int, void *);
static bool codec_picture_copy(MaruBrillCodecState *, int, void *);
static bool codec_flush_buffers(MaruBrillCodecState *, int, void *);
+static bool codec_decode_video2(MaruBrillCodecState *, int, void *);
typedef bool (*CodecFuncEntry)(MaruBrillCodecState *, int, void *);
static CodecFuncEntry codec_func_handler[] = {
codec_picture_copy,
codec_deinit,
codec_flush_buffers,
+ codec_decode_video2,
};
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,
+static void brillcodec_push_readqueue(MaruBrillCodecState *s, CodecParam *ioparam);
+static void brillcodec_push_write_queue(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 *brillcodec_store_inbuf(uint8_t *mem_base, CodecParam *ioparam);
// default handler
-static void default_get_data(void *dst, void *src, size_t size) {
+static void default_get_data(void *dst, void *src, size_t size)
+{
memcpy(dst, src, size);
}
-static void default_release(void *opaque) {
+static void default_release(void *opaque)
+{
g_free(opaque);
}
};
// 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 copy_picture(void *dst, void *opaque, size_t size)
+{
+ DataContainer *dc = (DataContainer *)opaque;
+ if (dc->len_data_buffer) {
+ memcpy(dst, dc->data_buffer, dc->len_data_buffer);
+ }
+ if (dc->frame) {
+ avpicture_layout((AVPicture *)dc->frame, PIX_FMT_YUV420P, dc->frame->width, dc->frame->height,
+ dst + OFFSET_PICTURE_BUFFER, size - OFFSET_PICTURE_BUFFER); // FIXME
+ }
}
-static void release(void *buf) {}
+static void release(void *opaque) {
+ DataContainer *dc = (DataContainer *)opaque;
+ g_free(dc->data_buffer);
+ g_free(dc);
+}
static DataHandler default_video_decode_data_handler = {
- .get_data = extract,
+ .get_data = copy_picture,
.release = release,
};
TRACE("leave: %s\n", __func__);
}
-void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
+void brillcodec_wakeup_threads(MaruBrillCodecState *s, int api_index)
{
CodecParam *ioparam = NULL;
qemu_mutex_unlock(&s->context_mutex);
- maru_brill_codec_push_readqueue(s, ioparam);
+ brillcodec_push_readqueue(s, ioparam);
qemu_mutex_lock(&s->context_mutex);
// W/A for threads starvation.
TRACE("after sending conditional signal\n");
}
-void *maru_brill_codec_threads(void *opaque)
+void *brillcodec_threads(void *opaque)
{
MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
bool ret = false;
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);
+ brillcodec_release_context(s, ctx_id);
CONTEXT(s, ctx_id)->requested_close = false;
}
qemu_mutex_unlock(&s->context_mutex);
}
// queue
-static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s,
+static void brillcodec_push_readqueue(MaruBrillCodecState *s,
CodecParam *ioparam)
{
CodecDataStg *elem = NULL;
switch(ioparam->api_index) {
case CODEC_INIT ... CODEC_ENCODE_AUDIO:
- data_buf = maru_brill_codec_store_inbuf((uint8_t *)s->vaddr, ioparam);
+ case CODEC_DECODE_VIDEO2:
+ data_buf = brillcodec_store_inbuf((uint8_t *)s->vaddr, ioparam);
break;
default:
TRACE("no buffer from guest\n");
qemu_mutex_unlock(&s->ioparam_queue_mutex);
}
-static void *maru_brill_codec_store_inbuf(uint8_t *mem_base,
+static void *brillcodec_store_inbuf(uint8_t *mem_base,
CodecParam *ioparam)
{
DeviceMemEntry *elem = NULL;
return elem;
}
-static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
+static void brillcodec_push_write_queue(MaruBrillCodecState *s, void* opaque,
size_t data_size, int ctx_id,
DataHandler *handler)
{
qemu_mutex_unlock(&s->context_queue_mutex);
}
-void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
+void brillcodec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
{
DeviceMemEntry *elem = NULL;
uint32_t mem_offset = 0;
avctx->channels, avctx->sample_rate, avctx->sample_fmt, avctx->channel_layout);
}
-void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t ctx_id)
+void brillcodec_release_context(MaruBrillCodecState *s, int32_t ctx_id)
{
DeviceMemEntry *wq_elem = NULL, *wnext = NULL;
CodecDataStg *rq_elem = NULL, *rnext = NULL;
TRACE("leave: %s\n", __func__);
}
-int maru_brill_codec_query_list (MaruBrillCodecState *s)
+int brillcodec_query_list (MaruBrillCodecState *s)
{
AVCodec *codec = NULL;
uint32_t size = 0, mem_size = 0;
return 0;
}
-int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
+int brillcodec_get_context_index(MaruBrillCodecState *s)
{
int ctx_id;
}
}
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+ brillcodec_push_write_queue(s, tempbuf, tempbuf_size, ctx_id, NULL);
TRACE("leave: %s\n", __func__);
CONTEXT(s, ctx_id)->parser_ctx = NULL;
}
- maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+ brillcodec_push_write_queue(s, NULL, 0, ctx_id, NULL);
TRACE("leave: %s\n", __func__);
avcodec_flush_buffers(avctx);
}
- maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+ brillcodec_push_write_queue(s, NULL, 0, ctx_id, NULL);
+
+ TRACE("leave: %s\n", __func__);
+
+ return ret;
+}
+
+static bool codec_decode_video2(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 {
+ TRACE("decode_video. bitrate %d\n", avctx->bit_rate);
+
+ 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 video 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; // FIXME
+ deserialize_video_data(avctx, &video);
+ memcpy(tempbuf + size, &video, sizeof(struct video_data));
+ }
+ }
+
+ TRACE("decoded image. pix_fmt: %d width: %d, height: %d\n",
+ avctx->pix_fmt, avctx->width, avctx->height);
+ int pict_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
+ bool ret = true;
+
+ if ((pict_size) < 0) {
+ ERR("picture size: %d\n", pict_size);
+ ret = false;
+ } else {
+ TRACE("picture size: %d\n", pict_size);
+
+ DataContainer *dc = g_malloc0(sizeof(DataContainer));
+ dc->data_buffer = tempbuf;
+ dc->len_data_buffer = tempbuf_size;
+ if (got_picture) {
+ dc->frame = picture;
+ }
+
+ if (CONTEXT(s, ctx_id)->is_hwaccel) {
+ brillcodec_push_write_queue(s, dc, OFFSET_PICTURE_BUFFER + pict_size, ctx_id, s->hwaccel_plugin->video_decode_data_handler);
+ } else {
+ brillcodec_push_write_queue(s, dc, OFFSET_PICTURE_BUFFER + pict_size, ctx_id, &default_video_decode_data_handler);
+ }
+ }
TRACE("leave: %s\n", __func__);
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_;
-
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P; // FIXME
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);
+ brillcodec_push_write_queue(s, tempbuf, tempbuf_size, ctx_id, NULL);
TRACE("leave: %s\n", __func__);
return true;
}
-
+// for old decode API
static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
{
AVCodecContext *avctx = NULL;
- AVPicture *src = NULL;
+ AVFrame *frame = NULL;
int pict_size = 0;
bool ret = true;
TRACE("copy decoded image of %d context.\n", ctx_id);
avctx = CONTEXT(s, ctx_id)->avctx;
- src = (AVPicture *)CONTEXT(s, ctx_id)->frame;
+ frame = 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) {
+ } else if (!frame) {
ERR("picture_copy. %d of AVFrame is NULL.\n", ctx_id);
ret = false;
} else {
ret = false;
} else {
TRACE("picture size: %d\n", pict_size);
+
+ DataContainer *dc = g_malloc0(sizeof(DataContainer));
+ dc->frame = frame;
+
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);
+ brillcodec_push_write_queue(s, dc, 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);
+ brillcodec_push_write_queue(s, dc, pict_size, ctx_id, &default_video_decode_data_handler);
}
}
}
}
}
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+ brillcodec_push_write_queue(s, tempbuf, tempbuf_size, ctx_id, NULL);
if (audio_out) {
avcodec_free_frame(&audio_out);
g_free(outbuf);
}
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+ brillcodec_push_write_queue(s, tempbuf, tempbuf_size, ctx_id, NULL);
TRACE("leave: %s\n", __func__);
return true;
}
}
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+ brillcodec_push_write_queue(s, tempbuf, tempbuf_size, ctx_id, NULL);
if (in_frame) {
avcodec_free_frame(&in_frame);
}
#define CODEC_DEVICE_NAME "codec-pci"
#define CODEC_DEVICE_THREAD "codec-workthread"
-#define CODEC_VERSION 2
+#define CODEC_VERSION 3
#define CODEC_REG_SIZE (256)
#define DEFAULT_WORKER_THREAD_CNT 8
CODEC_TASK_END = 0x1f,
};
-static void maru_brill_codec_threads_create(MaruBrillCodecState *s)
+static void brillcodec_threads_create(MaruBrillCodecState *s)
{
int index;
QemuThread *pthread = NULL;
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);
+ brillcodec_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)
+static void brillcodec_get_cpu_cores(MaruBrillCodecState *s)
{
s->worker_thread_cnt = get_number_of_processors();
if (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)
+static void brillcodec_bh_callback(void *opaque)
{
MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
TRACE("leave: %s\n", __func__);
}
-static uint64_t maru_brill_codec_read(void *opaque,
+static uint64_t brillcodec_read(void *opaque,
hwaddr addr,
unsigned size)
{
break;
case CODEC_CMD_GET_ELEMENT:
- ret = maru_brill_codec_query_list(s);
+ ret = brillcodec_query_list(s);
break;
case CODEC_CMD_GET_CONTEXT_INDEX:
- ret = maru_brill_codec_get_context_index(s);
+ ret = brillcodec_get_context_index(s);
TRACE("get context index: %d\n", ret);
break;
return ret;
}
-static void maru_brill_codec_write(void *opaque, hwaddr addr,
+static void brillcodec_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
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);
+ brillcodec_wakeup_threads(s, value);
break;
case CODEC_CMD_CONTEXT_INDEX:
CONTEXT(s, ctx_id)->requested_close = true;
INFO("make running thread to handle deinit\n");
} else {
- maru_brill_codec_release_context(s, ctx_id);
+ brillcodec_release_context(s, ctx_id);
}
}
break;
case CODEC_CMD_GET_DATA_FROM_QUEUE:
- maru_brill_codec_pop_writequeue(s, (uint32_t)value);
+ brillcodec_pop_writequeue(s, (uint32_t)value);
break;
default:
}
}
-static const MemoryRegionOps maru_brill_codec_mmio_ops = {
- .read = maru_brill_codec_read,
- .write = maru_brill_codec_write,
+static const MemoryRegionOps brillcodec_mmio_ops = {
+ .read = brillcodec_read,
+ .write = brillcodec_write,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
}
#endif
-static int maru_brill_codec_initfn(PCIDevice *dev)
+static int brillcodec_initfn(PCIDevice *dev)
{
MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
uint8_t *pci_conf = s->dev.config;
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,
+ memory_region_init_io(&s->mmio, OBJECT(s), &brillcodec_mmio_ops, s,
"maru_brill_codec.mmio", CODEC_REG_SIZE);
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
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);
+ brillcodec_get_cpu_cores(s);
+ brillcodec_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);
+ s->codec_bh = qemu_bh_new(brillcodec_bh_callback, s);
// register plugins
#ifdef CONFIG_VAAPI
return 0;
}
-static void maru_brill_codec_exitfn(PCIDevice *dev)
+static void brillcodec_exitfn(PCIDevice *dev)
{
MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
INFO("device exit\n");
memory_region_destroy(&s->mmio);
}
-static void maru_brill_codec_reset(DeviceState *d)
+static void brillcodec_reset(DeviceState *d)
{
MaruBrillCodecState *s = (MaruBrillCodecState *)d;
INFO("device reset\n");
memset(&s->ioparam, 0, sizeof(CodecParam));
}
-static void maru_brill_codec_class_init(ObjectClass *klass, void *data)
+static void brillcodec_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->init = brillcodec_initfn;
+ k->exit = brillcodec_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->reset = brillcodec_reset;
dc->desc = "Virtual new codec device for Tizen emulator";
}
.name = CODEC_DEVICE_NAME,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MaruBrillCodecState),
- .class_init = maru_brill_codec_class_init,
+ .class_init = brillcodec_class_init,
};
static void codec_register_types(void)