Rockchip: new plugin to support h.264 and vp8 enc
New plugin to support h.264 and vp8 encoder on Rockchip soc.
The rk3288 vp8 encoder driver need some revision before using
this plugin.
Change-Id: Ie934e507b44dfdae2179591bf8d1b10b951e2b3a
Signed-off-by: Alpha Lin <alpha.lin@rock-chips.com>
Reviewed-on: https://chromium-review.googlesource.com/361664
Commit-Ready: Kuang-che Wu <kcwu@chromium.org>
Tested-by: Kuang-che Wu <kcwu@chromium.org>
Reviewed-by: Kuang-che Wu <kcwu@chromium.org>
diff --git a/libv4l-rockchip_v2/Makefile.am b/libv4l-rockchip_v2/Makefile.am
index 94503a7..69f0239 100644
--- a/libv4l-rockchip_v2/Makefile.am
+++ b/libv4l-rockchip_v2/Makefile.am
@@ -2,3 +2,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+if WITH_V4L_PLUGINS
+libv4l2plugin_LTLIBRARIES = libv4l-encplugin.la
+endif
+
+libv4l_encplugin_la_SOURCES = \
+ libv4l-encplugin-rockchip.c \
+ libvepu/rk_vepu.c \
+ libvepu/rk_vepu_debug.c \
+ libvepu/h264e/h264e.c \
+ libvepu/vp8e/vp8e.c \
+ libvepu/vp8e/boolhuff.c \
+ libvepu/vp8e/vp8e_bitstream.c \
+ libvepu/vp8e/vp8e_prob_adapt.c
+
+libv4l_encplugin_la_CPPFLAGS = $(CFLAG_VISIBILITY)
+libv4l_encplugin_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+libv4l_encplugin_la_LIBADD = -lpthread
diff --git a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c
new file mode 100644
index 0000000..56b828f
--- /dev/null
+++ b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c
@@ -0,0 +1,716 @@
+/* Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <linux/videodev2.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <sys/syscall.h>
+#include "config.h" /* For HAVE_VISIBILITY */
+#include "libv4l-plugin.h"
+#include "libvepu/rk_vepu_debug.h"
+#include "libvepu/rk_vepu_interface.h"
+
+#define VLOG(log_level, str, ...) ((g_log_level >= log_level) ? \
+ (void) fprintf(stderr, "%s: " str "\n", __func__, ##__VA_ARGS__) \
+ : (void) 0)
+
+#define VLOG_FD(log_level, str, ...) ((g_log_level >= log_level) ? \
+ (void) fprintf(stderr, \
+ "%s: fd=%d. " str "\n", __func__, fd, ##__VA_ARGS__) : (void) 0)
+
+#define SYS_IOCTL(fd, cmd, arg) ({ \
+ int ret = syscall(SYS_ioctl, (int)(fd), (unsigned long)(cmd), \
+ (void *)(arg)); \
+ if ((ret && errno != EAGAIN) || g_log_level >= 2) \
+ fprintf(stderr, "SYS_ioctl: %s(%lu): fd=%d, ret=%d, errno=%d\n",\
+ v4l_cmd2str(cmd), _IOC_NR((unsigned long)cmd), fd, ret, \
+ errno); \
+ ret; \
+ })
+
+#if HAVE_VISIBILITY
+#define PLUGIN_PUBLIC __attribute__ ((__visibility__("default")))
+#else
+#define PLUGIN_PUBLIC
+#endif
+
+#define DEFAULT_FRAME_RATE 30
+#define DEFAULT_BITRATE 1000000
+#define PENDING_BUFFER_QUEUE_SIZE VIDEO_MAX_FRAME
+
+/*
+ * struct pending_buffer - A v4l2 buffer pending for QBUF.
+ * @buffer: v4l2 buffer for QBUF.
+ * @planes: plane info of v4l2 buffer.
+ * @next_runtime_param: runtime parameters like framerate, bitrate, and
+ * keyframe for the next buffer.
+ */
+struct pending_buffer {
+ struct v4l2_buffer buffer;
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct rk_vepu_runtime_param next_runtime_param;
+};
+
+/*
+ * struct pending_buffer_queue - a ring buffer of pending buffers.
+ * @count: the number of buffers stored in the array.
+ * @front: the index of the first ready buffer.
+ * @buf_array: pending buffer array.
+ */
+struct pending_buffer_queue {
+ uint32_t count;
+ int32_t front;
+ struct pending_buffer buf_array[PENDING_BUFFER_QUEUE_SIZE];
+};
+
+/*
+ * struct encoder_context - the context of an encoder instance.
+ * @enc: Encoder instance returned from rk_vepu_create().
+ * @mutex: The mutex to protect encoder_context.
+ * @output_streamon_type: Type of output interface when it streams on.
+ * @capture_streamon_type: Type of capture interface when it streams on.
+ * @init_param: Encoding parameters like input format, resolution, and etc.
+ * These parameters will be passed to encoder at libvpu
+ * initialization.
+ * @runtime_param: Runtime parameters like framerate, bitrate, and
+ * keyframe. This is only used for receiving ext_ctrls
+ * before streamon and pending buffer queue is empty.
+ * @pending_buffers: The pending v4l2 buffers waiting for the encoding
+ * configuration. After a previous buffer is dequeued,
+ * one buffer from the queue can be queued.
+ * @can_qbuf: Indicate that we can queue one source buffer. This is true only
+ * when the parameters to pass together with the source buffer are
+ * ready; those params are received on dequeing the previous
+ * destination buffer.
+ * @get_param_payload: Payload of V4L2_CID_PRIVATE_ROCKCHIP_GET_PARAMS. This is
+ * used to update the encoder configuration by
+ * rk_vepu_update_config().
+ * @get_param_payload_size: The size of get_param_payload.
+ * @v4l2_ctrls: v4l2 controls for VIDIOC_S_EXT_CTRLS.
+ */
+struct encoder_context {
+ void *enc;
+ pthread_mutex_t mutex;
+ enum v4l2_buf_type output_streamon_type;
+ enum v4l2_buf_type capture_streamon_type;
+ struct rk_vepu_init_param init_param;
+ struct rk_vepu_runtime_param runtime_param;
+ struct pending_buffer_queue pending_buffers;
+ bool can_qbuf;
+ void *get_param_payload;
+ size_t get_param_payload_size;
+ struct v4l2_ext_control v4l2_ctrls[MAX_NUM_GET_CONFIG_CTRLS];
+};
+
+static void *plugin_init(int fd);
+static void plugin_close(void *dev_ops_priv);
+static int plugin_ioctl(void *dev_ops_priv, int fd, unsigned long int cmd,
+ void *arg);
+
+/* Functions to handle various ioctl. */
+static int ioctl_streamon_locked(
+ struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
+static int ioctl_streamoff_locked(
+ struct encoder_context *ctx, int fd, enum v4l2_buf_type *type);
+static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_buffer *buffer);
+static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_buffer *buffer);
+static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_ext_controls *ext_ctrls);
+static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_streamparm *parms);
+static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_requestbuffers *reqbufs);
+
+/* Helper functions to manipulate the pending buffer queue. */
+
+static void queue_init(struct pending_buffer_queue *queue);
+static bool queue_empty(struct pending_buffer_queue *queue);
+static bool queue_full(struct pending_buffer_queue *queue);
+/* Insert a buffer to the tail of the queue. */
+static int queue_push_back(struct pending_buffer_queue *queue,
+ struct v4l2_buffer *buffer);
+/* Remove a buffer from the head of the queue. */
+static void queue_pop_front(struct pending_buffer_queue *queue);
+static struct pending_buffer *queue_front(struct pending_buffer_queue *queue);
+static struct pending_buffer *queue_back(struct pending_buffer_queue *queue);
+
+/* Returns true if the fd is Rockchip encoder device. */
+bool is_rockchip_encoder(int fd);
+/* Set encoder configuration to the driver. */
+int set_encoder_config_locked(struct encoder_context *ctx, int fd,
+ uint32_t buffer_index, size_t num_ctrls, uint32_t ctrls_ids[],
+ void **payloads, uint32_t payload_sizes[]);
+/* QBUF a buffer from the pending buffer queue if it is not empty. */
+static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
+ int fd);
+/* Get the encoder parameters using G_FMT and initialize libvpu. */
+static int initialize_libvpu(struct encoder_context *ctx, int fd);
+/* Return the string represenation of a libv4l command for debugging. */
+static const char *v4l_cmd2str(unsigned long int cmd);
+/* Get the log level from the environment variable LIBV4L_PLUGIN_LOG_LEVEL. */
+static void get_log_level();
+static pthread_once_t g_get_log_level_once = PTHREAD_ONCE_INIT;
+
+static void *plugin_init(int fd)
+{
+ int ret;
+ struct v4l2_query_ext_ctrl ext_ctrl;
+
+ pthread_once(&g_get_log_level_once, get_log_level);
+
+ VLOG_FD(1, "");
+ if (!is_rockchip_encoder(fd))
+ return NULL;
+
+ struct encoder_context *ctx = (struct encoder_context *)
+ calloc(1, sizeof(struct encoder_context));
+ if (ctx == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ ret = pthread_mutex_init(&ctx->mutex, NULL);
+ if (ret) {
+ free(ctx);
+ return NULL;
+ }
+ queue_init(&ctx->pending_buffers);
+
+ memset(&ext_ctrl, 0, sizeof(ext_ctrl));
+ ext_ctrl.id = V4L2_CID_PRIVATE_ROCKCHIP_GET_PARAMS;
+ ret = SYS_IOCTL(fd, VIDIOC_QUERY_EXT_CTRL, &ext_ctrl);
+ if (ret) {
+ goto fail;
+ }
+ ctx->get_param_payload_size = ext_ctrl.elem_size;
+ ctx->get_param_payload = calloc(1, ctx->get_param_payload_size);
+ if (ctx->get_param_payload == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+ ctx->runtime_param.framerate_numer = DEFAULT_FRAME_RATE;
+ ctx->runtime_param.framerate_denom = 1;
+ ctx->runtime_param.bitrate = DEFAULT_BITRATE;
+ VLOG_FD(1, "Success. ctx=%p", ctx);
+ return ctx;
+
+fail:
+ plugin_close(ctx);
+ return NULL;
+}
+
+static void plugin_close(void *dev_ops_priv)
+{
+ struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
+
+ VLOG(1, "ctx=%p", ctx);
+ if (ctx == NULL)
+ return;
+
+ pthread_mutex_lock(&ctx->mutex);
+ if (ctx->enc)
+ rk_vepu_deinit(ctx->enc);
+ free(ctx->get_param_payload);
+ ctx->get_param_payload = NULL;
+ pthread_mutex_unlock(&ctx->mutex);
+ pthread_mutex_destroy(&ctx->mutex);
+
+ free(ctx);
+}
+
+static int plugin_ioctl(void *dev_ops_priv, int fd,
+ unsigned long int cmd, void *arg)
+{
+ int ret;
+ struct encoder_context *ctx = (struct encoder_context *)dev_ops_priv;
+
+ VLOG_FD(2, "%s(%lu)", v4l_cmd2str(cmd), _IOC_NR(cmd));
+
+ pthread_mutex_lock(&ctx->mutex);
+ switch (cmd) {
+ case VIDIOC_STREAMON:
+ ret = ioctl_streamon_locked(ctx, fd, arg);
+ break;
+
+ case VIDIOC_STREAMOFF:
+ ret = ioctl_streamoff_locked(ctx, fd, arg);
+ break;
+
+ case VIDIOC_QBUF:
+ ret = ioctl_qbuf_locked(ctx, fd, arg);
+ break;
+
+ case VIDIOC_DQBUF:
+ ret = ioctl_dqbuf_locked(ctx, fd, arg);
+ break;
+
+ case VIDIOC_S_EXT_CTRLS:
+ ret = ioctl_s_ext_ctrls_locked(ctx, fd, arg);
+ break;
+
+ case VIDIOC_S_PARM:
+ ret = ioctl_s_parm_locked(ctx, fd, arg);
+ break;
+
+ case VIDIOC_REQBUFS:
+ ret = ioctl_reqbufs_locked(ctx, fd, arg);
+ break;
+
+ default:
+ ret = SYS_IOCTL(fd, cmd, arg);
+ break;
+ }
+ pthread_mutex_unlock(&ctx->mutex);
+ return ret;
+}
+
+static int ioctl_streamon_locked(
+ struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
+{
+ int ret = SYS_IOCTL(fd, VIDIOC_STREAMON, type);
+ if (ret)
+ return ret;
+
+ if (V4L2_TYPE_IS_OUTPUT(*type))
+ ctx->output_streamon_type = *type;
+ else
+ ctx->capture_streamon_type = *type;
+ if (ctx->output_streamon_type && ctx->capture_streamon_type) {
+ ret = initialize_libvpu(ctx, fd);
+ if (ret)
+ return ret;
+ ctx->can_qbuf = true;
+ return qbuf_if_pending_buffer_exists_locked(ctx, fd);
+ }
+ return 0;
+}
+
+static int ioctl_streamoff_locked(
+ struct encoder_context *ctx, int fd, enum v4l2_buf_type *type)
+{
+ int ret = SYS_IOCTL(fd, VIDIOC_STREAMOFF, type);
+ if (ret)
+ return ret;
+
+ if (V4L2_TYPE_IS_OUTPUT(*type))
+ ctx->output_streamon_type = 0;
+ else
+ ctx->capture_streamon_type = 0;
+ return 0;
+}
+
+static int ioctl_qbuf_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_buffer *buffer)
+{
+ size_t num_ctrls = 0;
+ uint32_t *ctrl_ids = NULL, *payload_sizes = NULL;
+ void **payloads = NULL;
+ int ret;
+
+ if (!V4L2_TYPE_IS_OUTPUT(buffer->type)) {
+ return SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
+ }
+
+ if (!ctx->can_qbuf) {
+ VLOG_FD(1, "Put buffer (%d) in the pending queue.",
+ buffer->index);
+ /*
+ * The last frame is not encoded yet. Put the buffer to the
+ * pending queue.
+ */
+ return queue_push_back(&ctx->pending_buffers, buffer);
+ }
+ /* Get the encoder configuration from the library. */
+ if (rk_vepu_get_config(ctx->enc, &num_ctrls, &ctrl_ids, &payloads,
+ &payload_sizes)) {
+ VLOG_FD(0, "rk_vepu_get_config failed");
+ return -EIO;
+ }
+ /* Set the encoder configuration to the driver. */
+ ret = set_encoder_config_locked(ctx, fd, buffer->index, num_ctrls, ctrl_ids,
+ payloads, payload_sizes);
+ if (ret)
+ return ret;
+
+ buffer->config_store = buffer->index + 1;
+ ret = SYS_IOCTL(fd, VIDIOC_QBUF, buffer);
+ if (ret == 0)
+ ctx->can_qbuf = false;
+ else
+ VLOG(0, "QBUF failed. errno=%d", errno);
+ return ret;
+}
+
+static int ioctl_dqbuf_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_buffer *buffer)
+{
+ struct v4l2_ext_controls ext_ctrls;
+ struct v4l2_ext_control v4l2_ctrl;
+ int ret;
+ uint32_t bytesused;
+
+ if (V4L2_TYPE_IS_OUTPUT(buffer->type)) {
+ return SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
+ }
+
+ ret = SYS_IOCTL(fd, VIDIOC_DQBUF, buffer);
+ if (ret)
+ return ret;
+
+ assert(!ctx->can_qbuf);
+
+ /* Get the encoder configuration and update the library. */
+ memset(ctx->get_param_payload, 0, ctx->get_param_payload_size);
+ memset(&v4l2_ctrl, 0, sizeof(v4l2_ctrl));
+ v4l2_ctrl.id = V4L2_CID_PRIVATE_ROCKCHIP_GET_PARAMS;
+ v4l2_ctrl.size = ctx->get_param_payload_size;
+ v4l2_ctrl.ptr = ctx->get_param_payload;
+ memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+ /* TODO: change this to config_store after the header is updated. */
+ ext_ctrls.ctrl_class = 0;
+ ext_ctrls.count = 1;
+ ext_ctrls.controls = &v4l2_ctrl;
+ ret = SYS_IOCTL(fd, VIDIOC_G_EXT_CTRLS, &ext_ctrls);
+ if (ret)
+ return ret;
+ bytesused = V4L2_TYPE_IS_MULTIPLANAR(buffer->type) ?
+ buffer->m.planes[0].bytesused : buffer->bytesused;
+
+ if (rk_vepu_update_config(ctx->enc, v4l2_ctrl.ptr, v4l2_ctrl.size,
+ bytesused)) {
+ VLOG_FD(0, "rk_vepu_update_config failed.");
+ return -EIO;
+ }
+ ctx->can_qbuf = true;
+ return qbuf_if_pending_buffer_exists_locked(ctx, fd);
+}
+
+static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_ext_controls *ext_ctrls)
+{
+ size_t i;
+ struct rk_vepu_runtime_param *runtime_param_ptr;
+
+ bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
+ /*
+ * If buffer queue is empty, update parameters directly.
+ * If buffer queue is not empty, save parameters to the last buffer. And
+ * these values will be sent again when the buffer is ready to deliver.
+ */
+ if (!no_pending_buffer) {
+ struct pending_buffer *element = queue_back(&ctx->pending_buffers);
+ runtime_param_ptr = &element->next_runtime_param;
+ } else {
+ runtime_param_ptr = &ctx->runtime_param;
+ }
+
+ /*
+ * Check each extension control to update keyframe and bitrate
+ * parameters.
+ */
+ for (i = 0; i < ext_ctrls->count; i++) {
+ switch (ext_ctrls->controls[i].id) {
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+ runtime_param_ptr->keyframe_request = true;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ runtime_param_ptr->bitrate = ext_ctrls->controls[i].value;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (no_pending_buffer && ctx->enc) {
+ if (rk_vepu_update_param(ctx->enc, runtime_param_ptr)) {
+ VLOG_FD(0, "rk_vepu_update_param failed.");
+ return -EIO;
+ }
+ memset(runtime_param_ptr, 0, sizeof(*runtime_param_ptr));
+ }
+ /* Driver should ignore keyframe and bitrate controls */
+ return SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, ext_ctrls);
+}
+
+static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_streamparm *parms)
+{
+ if (V4L2_TYPE_IS_OUTPUT(parms->type)
+ && parms->parm.output.timeperframe.denominator) {
+ struct rk_vepu_runtime_param *runtime_param_ptr;
+ bool no_pending_buffer = queue_empty(&ctx->pending_buffers);
+ struct pending_buffer *element = queue_back(&ctx->pending_buffers);
+
+ runtime_param_ptr = no_pending_buffer ? &ctx->runtime_param :
+ &element->next_runtime_param;
+ runtime_param_ptr->framerate_numer =
+ parms->parm.output.timeperframe.denominator;
+ runtime_param_ptr->framerate_denom =
+ parms->parm.output.timeperframe.numerator;
+
+ if (!no_pending_buffer || !ctx->enc)
+ return 0;
+ if (rk_vepu_update_param(ctx->enc, runtime_param_ptr)) {
+ VLOG_FD(0, "rk_vepu_update_param failed.");
+ return -EIO;
+ }
+ memset(runtime_param_ptr, 0, sizeof(*runtime_param_ptr));
+ return 0;
+ }
+ return SYS_IOCTL(fd, VIDIOC_S_PARM, parms);
+}
+
+static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ int ret = SYS_IOCTL(fd, VIDIOC_REQBUFS, reqbufs);
+ if (ret)
+ return ret;
+ queue_init(&ctx->pending_buffers);
+ return 0;
+}
+
+bool is_rockchip_encoder(int fd) {
+ struct v4l2_capability cap;
+ memset(&cap, 0, sizeof(cap));
+ int ret = SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
+ if (ret)
+ return false;
+ VLOG_FD(0, "driver name return %s\n", (char*)cap.card);
+ return strstr((const char *)cap.card, "-enc") != NULL;
+}
+
+int set_encoder_config_locked(struct encoder_context *ctx, int fd,
+ uint32_t buffer_index, size_t num_ctrls, uint32_t ctrl_ids[],
+ void **payloads, uint32_t payload_sizes[])
+{
+ size_t i;
+ struct v4l2_ext_controls ext_ctrls;
+
+ if (num_ctrls <= 0)
+ return 0;
+
+ assert(num_ctrls <= MAX_NUM_GET_CONFIG_CTRLS);
+ if (num_ctrls > MAX_NUM_GET_CONFIG_CTRLS) {
+ VLOG_FD(0, "The number of controls exceeds limit.");
+ return -EIO;
+ }
+ memset(&ext_ctrls, 0, sizeof(ext_ctrls));
+ ext_ctrls.config_store = buffer_index + 1;
+ ext_ctrls.count = num_ctrls;
+ ext_ctrls.controls = ctx->v4l2_ctrls;
+ memset(ctx->v4l2_ctrls, 0, sizeof(ctx->v4l2_ctrls));
+ for (i = 0; i < num_ctrls; ++i) {
+ ctx->v4l2_ctrls[i].id = ctrl_ids[i];
+ ctx->v4l2_ctrls[i].ptr = payloads[i];
+ ctx->v4l2_ctrls[i].size = payload_sizes[i];
+ }
+ int ret = SYS_IOCTL(fd, VIDIOC_S_EXT_CTRLS, &ext_ctrls);
+ if (ret) {
+ return ret;
+ }
+ return 0;
+}
+
+static int qbuf_if_pending_buffer_exists_locked(struct encoder_context *ctx,
+ int fd)
+{
+ if (!queue_empty(&ctx->pending_buffers)) {
+ int ret;
+ struct pending_buffer *element = queue_front(&ctx->pending_buffers);
+ VLOG_FD(1, "QBUF a buffer (%d) from the pending queue.",
+ element->buffer.index);
+ if (rk_vepu_update_param(ctx->enc, &element->next_runtime_param)) {
+ VLOG_FD(0, "rk_vepu_update_param failed.");
+ return -EIO;
+ }
+ memset(&element->next_runtime_param, 0,
+ sizeof(element->next_runtime_param));
+ ret = ioctl_qbuf_locked(ctx, fd, &element->buffer);
+ if (ret)
+ return ret;
+ queue_pop_front(&ctx->pending_buffers);
+ }
+ return 0;
+}
+
+static int initialize_libvpu(struct encoder_context *ctx, int fd)
+{
+ struct rk_vepu_init_param init_param;
+ memset(&init_param, 0, sizeof(init_param));
+
+ /* Get the input format. */
+ struct v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = ctx->output_streamon_type;
+ int ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
+ if (ret)
+ return ret;
+ init_param.input_format = format.fmt.pix_mp.pixelformat;
+
+ /* Get the output format. */
+ memset(&format, 0, sizeof(format));
+ format.type = ctx->capture_streamon_type;
+ ret = SYS_IOCTL(fd, VIDIOC_G_FMT, &format);
+ if (ret)
+ return ret;
+ init_param.output_format = format.fmt.pix_mp.pixelformat;
+
+ /* Get the cropped size. */
+ struct v4l2_crop crop;
+ memset(&crop, 0, sizeof(crop));
+ crop.type = ctx->output_streamon_type;
+ ret = SYS_IOCTL(fd, VIDIOC_G_CROP, &crop);
+ if (ret)
+ return ret;
+ init_param.width = crop.c.width;
+ init_param.height = crop.c.height;
+
+ /*
+ * If the encoder library has initialized and parameters have not
+ * changed, skip the initialization.
+ */
+ if (ctx->enc && memcmp(&init_param, &ctx->init_param, sizeof(init_param))) {
+ rk_vepu_deinit(ctx->enc);
+ ctx->enc = NULL;
+ }
+ if (!ctx->enc) {
+ memcpy(&ctx->init_param, &init_param, sizeof(init_param));
+ ctx->enc = rk_vepu_init(&init_param);
+ if (ctx->enc == NULL) {
+ VLOG_FD(0, "Failed to initialize encoder library.");
+ return -EIO;
+ }
+ }
+ if (rk_vepu_update_param(ctx->enc, &ctx->runtime_param)) {
+ VLOG_FD(0, "rk_vepu_update_param failed.");
+ return -EIO;
+ }
+ memset(&ctx->runtime_param, 0, sizeof(struct rk_vepu_runtime_param));
+ return 0;
+}
+
+static void queue_init(struct pending_buffer_queue *queue)
+{
+ memset(queue, 0, sizeof(struct pending_buffer_queue));
+}
+
+static bool queue_empty(struct pending_buffer_queue *queue)
+{
+ return queue->count == 0;
+}
+
+static bool queue_full(struct pending_buffer_queue *queue)
+{
+ return queue->count == PENDING_BUFFER_QUEUE_SIZE;
+}
+
+static int queue_push_back(struct pending_buffer_queue *queue,
+ struct v4l2_buffer *buffer)
+{
+ if (queue_full(queue))
+ return -ENOMEM;
+ int rear = (queue->front + queue->count) % PENDING_BUFFER_QUEUE_SIZE;
+ queue->count++;
+ struct pending_buffer *entry = &queue->buf_array[rear];
+ memset(entry, 0, sizeof(*entry));
+
+ entry->buffer = *buffer;
+ if (V4L2_TYPE_IS_MULTIPLANAR(buffer->type)) {
+ memcpy(entry->planes, buffer->m.planes,
+ sizeof(struct v4l2_plane) * buffer->length);
+ entry->buffer.m.planes = entry->planes;
+ }
+ return 0;
+}
+
+static void queue_pop_front(struct pending_buffer_queue *queue)
+{
+ assert(!queue_empty(queue));
+ queue->count--;
+ queue->front = (queue->front + 1) % PENDING_BUFFER_QUEUE_SIZE;
+}
+
+static struct pending_buffer *queue_front(struct pending_buffer_queue *queue)
+{
+ if (queue_empty(queue))
+ return NULL;
+ return &queue->buf_array[queue->front];
+}
+
+static struct pending_buffer *queue_back(struct pending_buffer_queue *queue)
+{
+ if (queue_empty(queue))
+ return NULL;
+ return &queue->buf_array[(queue->front + queue->count - 1) %
+ PENDING_BUFFER_QUEUE_SIZE];
+}
+
+static void get_log_level()
+{
+ char *log_level_str = getenv("LIBV4L_PLUGIN_LOG_LEVEL");
+ if (log_level_str != NULL)
+ g_log_level = strtol(log_level_str, NULL, 10);
+}
+
+static const char* v4l_cmd2str(unsigned long int cmd)
+{
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ return "VIDIOC_QUERYCAP";
+ case VIDIOC_TRY_FMT:
+ return "VIDIOC_TRY_FMT";
+ case VIDIOC_S_FMT:
+ return "VIDIOC_S_FMT";
+ case VIDIOC_G_FMT:
+ return "VIDIOC_G_FMT";
+ case VIDIOC_ENUM_FMT:
+ return "VIDIOC_ENUM_FMT";
+ case VIDIOC_S_PARM:
+ return "VIDIOC_S_PARM";
+ case VIDIOC_G_PARM:
+ return "VIDIOC_G_PARM";
+ case VIDIOC_QBUF:
+ return "VIDIOC_QBUF";
+ case VIDIOC_DQBUF:
+ return "VIDIOC_DQBUF";
+ case VIDIOC_PREPARE_BUF:
+ return "VIDIOC_PREPARE_BUF";
+ case VIDIOC_CREATE_BUFS:
+ return "VIDIOC_CREATE_BUFS";
+ case VIDIOC_REQBUFS:
+ return "VIDIOC_REQBUFS";
+ case VIDIOC_STREAMON:
+ return "VIDIOC_STREAMON";
+ case VIDIOC_STREAMOFF:
+ return "VIDIOC_STREAMOFF";
+ case VIDIOC_S_CROP:
+ return "VIDIOC_S_CROP";
+ case VIDIOC_S_CTRL:
+ return "VIDIOC_S_CTRL";
+ case VIDIOC_G_EXT_CTRLS:
+ return "VIDIOC_G_EXT_CTRLS";
+ case VIDIOC_S_EXT_CTRLS:
+ return "VIDIOC_S_EXT_CTRLS";
+ case VIDIOC_QUERYBUF:
+ return "VIDIOC_QUERYBUF";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+PLUGIN_PUBLIC const struct libv4l_dev_ops libv4l2_plugin = {
+ .init = &plugin_init,
+ .close = &plugin_close,
+ .ioctl = &plugin_ioctl,
+};
diff --git a/libv4l-rockchip_v2/libvepu/common/rk_venc.h b/libv4l-rockchip_v2/libvepu/common/rk_venc.h
new file mode 100644
index 0000000..ddd329e
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/common/rk_venc.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2016 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _V4L2_PLUGIN_RK_VENC_H_
+#define _V4L2_PLUGIN_RK_VENC_H_
+
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../rk_vepu_interface.h"
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+
+#define ABS(x) ((x) < (0) ? -(x) : (x))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define SIGN(a) ((a) < (0) ? (-1) : (1))
+#define CLIP3(v, min, max) ((v) < (min) ? (min) : ((v) > (max) ? (max) : (v)))
+#define MB_COUNT(x) (((x) + 15) >> 4)
+#define DIV(a, b) ((b) ? ((a) + (SIGN(a) * (b)) / 2) / (b) : (a))
+
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct rk_venc;
+
+struct rk_venc_ops {
+ int (*init)(struct rk_venc *enc, struct rk_vepu_init_param *enc_parms);
+ int (*before_encode)(struct rk_venc *enc);
+ int (*after_encode)(struct rk_venc *enc, uint32_t outputStreamSize);
+ void (*deinit)(struct rk_venc *enc);
+ int (*update_priv)(struct rk_venc *enc, void *config, uint32_t len);
+ void (*apply_param)(struct rk_venc *enc);
+ void (*get_payloads)(struct rk_venc *enc, size_t *num, uint32_t **ids,
+ void ***payloads, uint32_t **payload_sizes);
+};
+
+enum ENC_FORMAT {
+ ENC_FORMAT_H264,
+ ENC_FORMAT_VP8
+};
+
+struct rk_venc {
+ struct rk_venc_ops *ops;
+ struct rk_vepu_runtime_param runtime_param;
+
+ enum ENC_FORMAT fmt;
+};
+
+/**
+ * struct rk3288_vp8e_reg_params - low level encoding parameters
+ * TODO: Create abstract structures for more generic controls or just
+ * remove unused fields.
+ */
+struct rk3288_vp8e_reg_params {
+ u32 unused_00[5];
+ u32 hdr_len;
+ u32 unused_18[8];
+ u32 enc_ctrl;
+ u32 unused_3c;
+ u32 enc_ctrl0;
+ u32 enc_ctrl1;
+ u32 enc_ctrl2;
+ u32 enc_ctrl3;
+ u32 enc_ctrl5;
+ u32 enc_ctrl4;
+ u32 str_hdr_rem_msb;
+ u32 str_hdr_rem_lsb;
+ u32 unused_60;
+ u32 mad_ctrl;
+ u32 unused_68;
+ u32 qp_val[8];
+ u32 bool_enc;
+ u32 vp8_ctrl0;
+ u32 rlc_ctrl;
+ u32 mb_ctrl;
+ u32 unused_9c[14];
+ u32 rgb_yuv_coeff[2];
+ u32 rgb_mask_msb;
+ u32 intra_area_ctrl;
+ u32 cir_intra_ctrl;
+ u32 unused_e8[2];
+ u32 first_roi_area;
+ u32 second_roi_area;
+ u32 mvc_ctrl;
+ u32 unused_fc;
+ u32 intra_penalty[7];
+ u32 unused_11c;
+ u32 seg_qp[24];
+ u32 dmv_4p_1p_penalty[32];
+ u32 dmv_qpel_penalty[32];
+ u32 vp8_ctrl1;
+ u32 bit_cost_golden;
+ u32 loop_flt_delta[2];
+};
+
+/**
+ * struct rk3288_h264e_reg_params - low level encoding parameters
+ * TODO: Create abstract structures for more generic controls or just
+ * remove unused fields.
+ */
+struct rk3288_h264e_reg_params {
+ u32 frame_coding_type;
+ s32 pic_init_qp;
+ s32 slice_alpha_offset;
+ s32 slice_beta_offset;
+ s32 chroma_qp_index_offset;
+ s32 filter_disable;
+ u16 idr_pic_id;
+ s32 pps_id;
+ s32 frame_num;
+ s32 slice_size_mb_rows;
+ s32 h264_inter4x4_disabled;
+ s32 enable_cabac;
+ s32 transform8x8_mode;
+ s32 cabac_init_idc;
+
+ /* rate control relevant */
+ s32 qp;
+ s32 mad_qp_delta;
+ s32 mad_threshold;
+ s32 qp_min;
+ s32 qp_max;
+ s32 cp_distance_mbs;
+ s32 cp_target[10];
+ s32 target_error[7];
+ s32 delta_qp[7];
+};
+
+/**
+ * struct rk3399_vp8e_reg_params - low level encoding parameters
+ * TODO: Create abstract structures for more generic controls or just
+ * remove unused fields.
+ */
+struct rk3399_vp8e_reg_params {
+ u32 is_intra;
+ u32 frm_hdr_size;
+
+ u32 qp;
+
+ s32 mv_prob[2][19];
+ s32 intra_prob;
+
+ u32 bool_enc_value;
+ u32 bool_enc_value_bits;
+ u32 bool_enc_range;
+
+ u32 filterDisable;
+ u32 filter_sharpness;
+ u32 filter_level;
+
+ s32 intra_frm_delta;
+ s32 last_frm_delta;
+ s32 golden_frm_delta;
+ s32 altref_frm_delta;
+
+ s32 bpred_mode_delta;
+ s32 zero_mode_delta;
+ s32 newmv_mode_delta;
+ s32 splitmv_mode_delta;
+};
+
+/**
+ * struct rockchip_reg_params - low level encoding parameters
+ */
+struct rockchip_reg_params {
+ /* Mode-specific data. */
+ union {
+ const struct rk3288_h264e_reg_params rk3288_h264e;
+ const struct rk3288_vp8e_reg_params rk3288_vp8e;
+ const struct rk3399_vp8e_reg_params rk3399_vp8e;
+ };
+};
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e.c b/libv4l-rockchip_v2/libvepu/h264e/h264e.c
new file mode 100644
index 0000000..775098d
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <malloc.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "h264e.h"
+#include "../rk_vepu_debug.h"
+
+const int32_t h264e_qp_tbl[2][11] = {
+ { 27, 44, 72, 119, 192, 314, 453, 653, 952, 1395, 0x7FFFFFFF },
+ { 51, 47, 43, 39, 35, 31, 27, 23, 19, 15, 11} };
+
+static void h264e_init_sps(struct v4l2_plugin_h264_sps *sps)
+{
+ sps->profile_idc = 77;
+
+ /* fixed values limited by hardware */
+ sps->constraint_set0_flag = 1;
+ sps->constraint_set1_flag = 1;
+ sps->constraint_set2_flag = 1;
+
+ /* if level idc == 1b, constraint_set3_flag need to be set true */
+ sps->constraint_set3_flag = 0;
+
+ /* if level max than 31, we prefer disable 4x4 mv mode
+ to limit max mv count per 2mb */
+ sps->level_idc = H264ENC_LEVEL_4_0;
+ sps->seq_parameter_set_id = 0;
+
+ /* fixed values limited by hardware */
+ sps->chroma_format_idc = 1;
+ sps->bit_depth_luma_minus8 = 0;
+ sps->bit_depth_chroma_minus8 = 0;
+ sps->qpprime_y_zero_transform_bypass_flag = 0;
+ sps->log2_max_frame_num_minus4 = 12;
+ sps->pic_order_cnt_type = 2;
+
+ sps->max_num_ref_frames = 1;
+ sps->gaps_in_frame_num_value_allowed_flag = 0;
+ sps->pic_width_in_mbs = 1280 / 16;
+ sps->pic_height_in_map_units = 720 / 16;
+ sps->frame_mbs_only_flag = 1;
+
+ sps->direct_8x8_inference_flag = 1;
+ sps->frame_cropping_flag = 0;
+
+ sps->vui_parameters_present_flag = 1;
+}
+
+static void h264e_init_pps(struct v4l2_plugin_h264_pps *pps)
+{
+ pps->pic_parameter_set_id = 0;
+ pps->seq_parameter_set_id = 0;
+
+ /* enable cabac coding need set profile_idc large than 77 */
+ pps->entropy_coding_mode_flag = 1;
+
+ /* fixed value limited by hardware */
+ pps->pic_order_present_flag = 0;
+
+ pps->num_ref_idx_l0_default_active_minus1 = 0;
+ pps->num_ref_idx_l1_default_active_minus1 = 0;
+
+ /* fixed value limited by hardware */
+ pps->weighted_pred_flag = 0;
+ pps->weighted_bipred_idc = 0;
+
+ pps->pic_init_qp_minus26 = 0;
+ pps->pic_init_qs_minus26 = 0;
+ pps->chroma_qp_index_offset = 2;
+ pps->deblocking_filter_control_present_flag = 1;
+ pps->constrained_intra_pred_flag = 0;
+ pps->num_slice_groups_minus_1 = 0;
+
+ /* fixed value limited by hardware */
+ pps->redundant_pic_cnt_present_flag = 0;
+
+ /* enable transform_8x8, need profile_idc large than 100 */
+ pps->transform_8x8_mode_flag = 0;
+}
+
+static void h264e_init_slice(struct v4l2_plugin_h264_slice_param *slice)
+{
+ slice->slice_type = ISLICE;
+ slice->pic_parameter_set_id = 0;
+ slice->frame_num = 0;
+ slice->idr_pic_id = -1;
+ slice->cabac_init_idc = 0;
+ slice->disable_deblocking_filter_idc = 0;
+ slice->slice_alpha_c0_offset_div2 = 0;
+ slice->slice_beta_offset_div2 = 0;
+}
+
+static int h264e_init(struct rk_venc *ictx,
+ struct rk_vepu_init_param *param)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+
+ ictx->fmt = ENC_FORMAT_H264;
+
+ h264e_init_sps(&ctx->sps);
+ h264e_init_pps(&ctx->pps);
+ h264e_init_slice(&ctx->slice);
+
+ ctx->width = param->width;
+ ctx->height = param->height;
+ ctx->slice_size_mb_rows = 0;
+ ctx->frm_in_gop = 0;
+
+ ctx->sps.pic_width_in_mbs = MB_COUNT(ctx->width);
+ ctx->sps.pic_height_in_map_units = MB_COUNT(ctx->height);
+
+ if (ctx->width != ctx->sps.pic_width_in_mbs * 16 ||
+ ctx->height != ctx->sps.pic_height_in_map_units * 16) {
+ ctx->sps.frame_cropping_flag = 1;
+ ctx->sps.frame_crop_right_offset =
+ ctx->sps.pic_width_in_mbs * 16 - ctx->width;
+ ctx->sps.frame_crop_bottom_offset =
+ ctx->sps.pic_height_in_map_units * 16 - ctx->height;
+ }
+
+ if (ctx->sps.level_idc >= H264ENC_LEVEL_3_1)
+ ctx->h264_inter4x4_disabled = 1;
+ else
+ ctx->h264_inter4x4_disabled = 0;
+
+ if (ctx->pps.transform_8x8_mode_flag == 2)
+ ctx->pps.transform_8x8_mode_flag = 1;
+
+ ctx->rk_ctrl_ids[0] = V4L2_CID_PRIVATE_ROCKCHIP_REG_PARAMS;
+
+ return 0;
+}
+
+static void h264e_deinit(struct rk_venc *ictx)
+{
+
+}
+
+static int h264e_begin_picture(struct rk_venc *ictx)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+ struct rk3288_h264e_reg_params *hw_info = &ctx->hw_info;
+
+ if (ictx->runtime_param.keyframe_request) {
+ VPU_PLG_INF("got key frame request\n");
+ ctx->frm_in_gop = 0;
+ ictx->runtime_param.keyframe_request = 0;
+ }
+
+ hw_info->frame_coding_type = FRAME_CODING_TYPE_INTER;
+ if (ctx->frm_in_gop == 0) {
+ ctx->slice.idr_pic_id++;
+ ctx->slice.idr_pic_id %= 16;
+ ctx->slice.frame_num = 0;
+ hw_info->frame_coding_type = FRAME_CODING_TYPE_INTRA;
+ }
+
+ hw_info->pic_init_qp = ctx->pps.pic_init_qp_minus26 + 26;
+ hw_info->transform8x8_mode = ctx->pps.transform_8x8_mode_flag;
+ hw_info->enable_cabac = ctx->pps.entropy_coding_mode_flag != 0;
+
+ hw_info->chroma_qp_index_offset = ctx->pps.chroma_qp_index_offset;
+ hw_info->pps_id = ctx->pps.pic_parameter_set_id;
+
+ hw_info->filter_disable = ctx->slice.disable_deblocking_filter_idc;
+ hw_info->slice_alpha_offset = ctx->slice.slice_alpha_c0_offset_div2 * 2;
+ hw_info->slice_beta_offset = ctx->slice.slice_beta_offset_div2 * 2;
+ hw_info->idr_pic_id = ctx->slice.idr_pic_id;
+ hw_info->frame_num = ctx->slice.frame_num;
+ hw_info->slice_size_mb_rows = ctx->slice_size_mb_rows;
+ hw_info->cabac_init_idc = ctx->slice.cabac_init_idc;
+
+ hw_info->qp = 30;
+
+ hw_info->mad_qp_delta = 0;
+ hw_info->mad_threshold = 0;
+ hw_info->qp_min = 10;
+ hw_info->qp_max = 51;
+ hw_info->cp_distance_mbs = 0;
+
+ hw_info->h264_inter4x4_disabled = ctx->h264_inter4x4_disabled;
+
+ ctx->rk_payloads[0] = hw_info;
+ ctx->rk_payload_sizes[0] = sizeof(struct rockchip_reg_params);
+
+ return 0;
+}
+
+static int h264e_end_picture(struct rk_venc *ictx,
+ uint32_t outputStreamSize)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+
+ ctx->frm_in_gop++;
+ ctx->frm_in_gop %= 150;
+
+ ctx->slice.frame_num++;
+ ctx->slice.frame_num %=
+ (1 << (ctx->sps.log2_max_frame_num_minus4 + 4));
+
+ return 0;
+}
+
+static int h264e_update_priv(struct rk_venc *ictx, void *config, uint32_t cfglen)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+
+ assert(ctx);
+ assert(config);
+
+ memcpy(&ctx->feedback, config, sizeof(ctx->feedback));
+
+ return 0;
+}
+
+static void h264e_apply_param(struct rk_venc *ictx)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+
+ assert(ctx);
+
+ /* todo, apply parameters to rate control */
+}
+
+static void h264e_get_payloads(struct rk_venc *ictx, size_t *num, uint32_t **ids,
+ void ***payloads, uint32_t **payload_sizes)
+{
+ struct rk_h264_encoder *ctx = (struct rk_h264_encoder *)ictx;
+
+ *num = H264E_NUM_CTRLS;
+ *ids = ctx->rk_ctrl_ids;
+ *payloads = ctx->rk_payloads;
+ *payload_sizes = ctx->rk_payload_sizes;
+}
+
+static struct rk_venc_ops h264_enc_ops = {
+ .init = h264e_init,
+ .before_encode = h264e_begin_picture,
+ .after_encode = h264e_end_picture,
+ .deinit = h264e_deinit,
+ .update_priv = h264e_update_priv,
+ .apply_param = h264e_apply_param,
+ .get_payloads = h264e_get_payloads,
+};
+
+struct rk_venc* rk_h264_encoder_alloc_ctx(void)
+{
+ struct rk_venc* enc =
+ (struct rk_venc*)calloc(1, sizeof(struct rk_h264_encoder));
+
+ if (enc == NULL) {
+ return NULL;
+ }
+
+ enc->ops = &h264_enc_ops;
+
+ return enc;
+}
+
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e.h b/libv4l-rockchip_v2/libvepu/h264e/h264e.h
new file mode 100644
index 0000000..d62443e
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _V4L2_PLUGIN_RK_H264E_H_
+#define _V4L2_PLUGIN_RK_H264E_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../rk_vepu_interface.h"
+
+#include "h264e_common.h"
+#include "../common/rk_venc.h"
+
+#define H264E_NUM_CTRLS 1
+struct rk_h264_encoder {
+ struct rk_venc venc;
+
+ struct v4l2_plugin_h264_sps sps;
+ struct v4l2_plugin_h264_pps pps;
+ struct v4l2_plugin_h264_slice_param slice;
+ struct rk3288_h264e_reg_params hw_info;
+ struct v4l2_plugin_h264_feedback feedback;
+
+ int width;
+ int height;
+
+ int slice_size_mb_rows;
+ int h264_inter4x4_disabled;
+
+ int frm_in_gop;
+
+ uint32_t rk_ctrl_ids[H264E_NUM_CTRLS];
+ void *rk_payloads[H264E_NUM_CTRLS];
+ uint32_t rk_payload_sizes[H264E_NUM_CTRLS];
+};
+
+struct rk_venc* rk_h264_encoder_alloc_ctx(void);
+void rk_h264_encoder_free_ctx(struct rk_h264_encoder *enc);
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/h264e/h264e_common.h b/libv4l-rockchip_v2/libvepu/h264e/h264e_common.h
new file mode 100644
index 0000000..d475edd
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/h264e/h264e_common.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _V4L2_PLUGIN_RK_H264E_COMMON_H_
+#define _V4L2_PLUGIN_RK_H264E_COMMON_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../common/rk_venc.h"
+
+#define MB_PER_PIC(ctx) \
+ (ctx->sps.pic_width_in_mbs * ctx->sps.pic_height_in_map_units)
+
+/* frame coding type defined by hardware */
+#define FRAME_CODING_TYPE_INTER 0
+#define FRAME_CODING_TYPE_INTRA 1
+
+enum H264ENC_LEVEL {
+ H264ENC_LEVEL_1 = 10,
+ H264ENC_LEVEL_1_b = 99,
+ H264ENC_LEVEL_1_1 = 11,
+ H264ENC_LEVEL_1_2 = 12,
+ H264ENC_LEVEL_1_3 = 13,
+ H264ENC_LEVEL_2 = 20,
+ H264ENC_LEVEL_2_1 = 21,
+ H264ENC_LEVEL_2_2 = 22,
+ H264ENC_LEVEL_3 = 30,
+ H264ENC_LEVEL_3_1 = 31,
+ H264ENC_LEVEL_3_2 = 32,
+ H264ENC_LEVEL_4_0 = 40,
+ H264ENC_LEVEL_4_1 = 41
+};
+
+enum sliceType_e {
+ PSLICE = 0,
+ ISLICE = 2,
+ PSLICES = 5,
+ ISLICES = 7
+};
+
+struct v4l2_plugin_h264_feedback {
+ int32_t qpSum;
+ int32_t cp[10];
+ int32_t madCount;
+ int32_t rlcCount;
+};
+
+struct v4l2_plugin_h264_sps {
+ u8 profile_idc;
+ u8 constraint_set0_flag :1;
+ u8 constraint_set1_flag :1;
+ u8 constraint_set2_flag :1;
+ u8 constraint_set3_flag :1;
+ u8 level_idc;
+ u8 seq_parameter_set_id;
+ u8 chroma_format_idc;
+ u8 bit_depth_luma_minus8;
+ u8 bit_depth_chroma_minus8;
+ u8 qpprime_y_zero_transform_bypass_flag :1;
+ u16 log2_max_frame_num_minus4;
+ u8 pic_order_cnt_type;
+ u8 max_num_ref_frames;
+ u8 gaps_in_frame_num_value_allowed_flag :1;
+ u16 pic_width_in_mbs;
+ u16 pic_height_in_map_units;
+ u8 frame_mbs_only_flag :1;
+ u8 direct_8x8_inference_flag :1;
+ u8 frame_cropping_flag :1;
+ u32 frame_crop_left_offset;
+ u32 frame_crop_right_offset;
+ u32 frame_crop_top_offset;
+ u32 frame_crop_bottom_offset;
+ u8 vui_parameters_present_flag :1;
+};
+
+struct v4l2_plugin_h264_pps {
+ u8 pic_parameter_set_id;
+ u8 seq_parameter_set_id;
+ u8 entropy_coding_mode_flag :1;
+ u8 pic_order_present_flag :1;
+ u8 num_slice_groups_minus_1;
+ u8 num_ref_idx_l0_default_active_minus1;
+ u8 num_ref_idx_l1_default_active_minus1;
+ u8 weighted_pred_flag :1;
+ u8 weighted_bipred_idc;
+ s8 pic_init_qp_minus26;
+ s8 pic_init_qs_minus26;
+ s8 chroma_qp_index_offset;
+ u8 deblocking_filter_control_present_flag :1;
+ u8 constrained_intra_pred_flag :1;
+ u8 redundant_pic_cnt_present_flag :1;
+ u8 transform_8x8_mode_flag :1;
+};
+
+struct v4l2_plugin_h264_slice_param {
+ u8 slice_type;
+ u8 pic_parameter_set_id;
+ u16 frame_num;
+ u16 idr_pic_id;
+ u8 cabac_init_idc;
+ u8 disable_deblocking_filter_idc;
+ s8 slice_alpha_c0_offset_div2;
+ s8 slice_beta_offset_div2;
+};
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/rk_vepu.c b/libv4l-rockchip_v2/libvepu/rk_vepu.c
new file mode 100644
index 0000000..7959184
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/rk_vepu.c
@@ -0,0 +1,121 @@
+/* Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "libvepu/rk_vepu_interface.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libvepu/rk_vepu_debug.h"
+#include "h264e/h264e.h"
+#include "vp8e/vp8e.h"
+
+void *rk_vepu_init(struct rk_vepu_init_param *param) {
+ int retval;
+ struct rk_venc *enc;
+
+ assert(param != NULL);
+
+ switch (param->output_format) {
+ case V4L2_PIX_FMT_H264:
+ enc = rk_h264_encoder_alloc_ctx();
+ break;
+ case V4L2_PIX_FMT_VP8:
+ enc = rk_vp8_encoder_alloc_ctx();
+ break;
+ default:
+ VPU_PLG_ERR("Unsupported format set\n");
+ return NULL;
+ }
+
+ if (enc == NULL) {
+ VPU_PLG_ERR("Allocate encoder instance failed\n");
+ return NULL;
+ }
+
+ retval = enc->ops->init(enc, param);
+ if (retval < 0) {
+ VPU_PLG_ERR("Encoder initialize failed\n");
+ free(enc);
+ return NULL;
+ }
+ return enc;
+}
+
+void rk_vepu_deinit(void *enc) {
+ struct rk_venc *ienc = (struct rk_venc*)enc;
+
+ assert(enc != NULL);
+ ienc->ops->deinit(ienc);
+ free(ienc);
+}
+
+int rk_vepu_get_config(void *enc, size_t *num_ctrls, uint32_t **ctrl_ids,
+ void ***payloads, uint32_t **payload_sizes)
+{
+ int retval;
+ struct rk_venc *ienc = (struct rk_venc*)enc;
+ int i;
+
+ assert(enc != NULL && num_ctrls != NULL && ctrl_ids != NULL);
+ assert(payloads != NULL && payload_sizes != NULL);
+
+ retval = ienc->ops->before_encode(ienc);
+ if (retval < 0) {
+ VPU_PLG_ERR("Generate configuration failed\n");
+ return -1;
+ }
+
+ ienc->ops->get_payloads(ienc, num_ctrls,
+ ctrl_ids, payloads, payload_sizes);
+
+ VPU_PLG_DBG("num_ctrls %d\n", *num_ctrls);
+
+ for (i = 0; i < *num_ctrls; i++)
+ VPU_PLG_DBG("ctrl_ids[%d] = 0x%x, payload_sizes[%d] = %u\n",
+ i, (*ctrl_ids)[i], i, (*payload_sizes)[i]);
+
+ return 0;
+}
+
+int rk_vepu_update_config(void *enc, void *config, uint32_t config_size,
+ uint32_t buffer_size) {
+ int retval;
+ struct rk_venc *ienc = (struct rk_venc*)enc;
+
+ assert(enc != NULL && config != NULL);
+
+ retval = ienc->ops->update_priv(ienc, config, config_size);
+ if (retval < 0) {
+ VPU_PLG_ERR("Update encoder private data failed\n");
+ return -1;
+ }
+ return ienc->ops->after_encode(ienc, buffer_size);
+}
+
+int rk_vepu_update_param(void *enc,
+ struct rk_vepu_runtime_param *param) {
+ struct rk_venc *ienc = (struct rk_venc*)enc;
+
+ assert(enc != NULL && param != NULL);
+
+ if (param->bitrate != 0)
+ ienc->runtime_param.bitrate = param->bitrate;
+
+ if (param->framerate_numer != 0)
+ ienc->runtime_param.framerate_numer = param->framerate_numer;
+
+ if (param->framerate_denom != 0)
+ ienc->runtime_param.framerate_denom = param->framerate_denom;
+
+ if (param->keyframe_request != 0)
+ ienc->runtime_param.keyframe_request = param->keyframe_request;
+
+ ienc->ops->apply_param(ienc);
+ return 0;
+}
diff --git a/libv4l-rockchip_v2/libvepu/rk_vepu_debug.c b/libv4l-rockchip_v2/libvepu/rk_vepu_debug.c
new file mode 100644
index 0000000..885ef0e
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/rk_vepu_debug.c
@@ -0,0 +1,5 @@
+/* Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+int g_log_level = 0;
diff --git a/libv4l-rockchip_v2/libvepu/rk_vepu_debug.h b/libv4l-rockchip_v2/libvepu/rk_vepu_debug.h
new file mode 100644
index 0000000..513d084
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/rk_vepu_debug.h
@@ -0,0 +1,36 @@
+/* Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef LIBVPU_RK_VEPU_DEBUG_H_
+#define LIBVPU_RK_VEPU_DEBUG_H_
+
+#include <stdio.h>
+
+/*
+ * The current log level. Higher value will enable more logs.
+ */
+extern int g_log_level;
+
+#define VPU_PLG_DBG(fmt, args...) ((g_log_level >= 2) ? \
+ (void) fprintf(stderr, "%s:%d: " fmt, __func__, __LINE__, ## args) \
+ : (void) 0)
+
+#define VPU_PLG_ENTER() ((g_log_level >= 2) ? \
+ (void) fprintf(stderr, "%s:%d: enter\n", __func__, __LINE__) \
+ : (void) 0)
+
+#define VPU_PLG_LEAVE() ((g_log_level >= 2) ? \
+ (void) fprintf(stderr, "%s:%d: leave\n", __func__, __LINE__) \
+ : (void) 0)
+
+#define VPU_PLG_INF(fmt, args...) ((g_log_level >= 1) ? \
+ (void) fprintf(stderr, "%s:%d: " fmt, __func__, __LINE__, ## args) \
+ : (void) 0)
+
+#define VPU_PLG_ERR(fmt, args...) ((g_log_level >= 0) ? \
+ (void) fprintf(stderr, "ERR, %s:%d: " fmt, __func__, __LINE__, ## args) \
+ : (void) 0)
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h b/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h
new file mode 100644
index 0000000..eb6e98e
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/rk_vepu_interface.h
@@ -0,0 +1,113 @@
+/* Copyright 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * Rockchip VPU (video processing unit) encoder library module.
+ *
+ * This library is not thread-safe.
+ */
+
+#ifndef LIBVPU_RK_VEPU_INTERFACE_H_
+#define LIBVPU_RK_VEPU_INTERFACE_H_
+
+#include <linux/videodev2.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* TODO(wuchengli): Remove these after the header is updated. */
+#define V4L2_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0x1000)
+#define V4L2_CID_PRIVATE_ROCKCHIP_HEADER (V4L2_CID_CUSTOM_BASE)
+#define V4L2_CID_PRIVATE_ROCKCHIP_REG_PARAMS (V4L2_CID_CUSTOM_BASE + 1)
+#define V4L2_CID_PRIVATE_ROCKCHIP_HW_PARAMS (V4L2_CID_CUSTOM_BASE + 2)
+#define V4L2_CID_PRIVATE_ROCKCHIP_GET_PARAMS (V4L2_CID_CUSTOM_BASE + 3)
+
+/* The maximum number of controls returned by rk_vepu_get_config(). */
+#define MAX_NUM_GET_CONFIG_CTRLS 5
+
+struct rk_vepu_init_param {
+ uint32_t width; /* video width */
+ uint32_t height; /* video height */
+ uint32_t input_format; /* V4L2 fourcc pixel format */
+ uint32_t output_format; /* V4L2 fourcc pixel format */
+};
+
+struct rk_vepu_runtime_param {
+ int32_t framerate_numer; /* frame rate */
+ int32_t framerate_denom;
+ int32_t bitrate; /* bits per second */
+ bool keyframe_request; /* have keyframe request */
+};
+
+/**
+ * Create and initialize an encoder instance with encode parameters.
+ *
+ * @param param: vpu encoder parameters, see struct rk_vepu_init_param.
+ *
+ * @return the encoder instance. NULL if failed.
+ */
+void *rk_vepu_init(struct rk_vepu_init_param *param);
+
+/**
+ * Deinitialize and destroy the encoder instance.
+ *
+ * @param enc: the instance generated by rk_vepu_init. The implementation will
+ * release the memory in enc.
+ */
+void rk_vepu_deinit(void *enc);
+
+/**
+ * Get configuration for driver to configure the hardware.
+ *
+ * @param enc: the instance generated by rk_vepu_init.
+ * @param num_ctrls: pointer to the number of controls.
+ * @param ctrls_ids: pointer to a num_ctrls element array of V4L2 control IDs
+ * corresponding to elements in ctrls.
+ * @param payloads: pointer to a num_ctrls element array of pointers to control
+ * payloads.
+ * @param payload_sizes: pointer to a num_ctrls element array of sizes for each
+ * payload.
+ *
+ * Get a set of control payloads and IDs from library for the plugin to pass as
+ * V4L2 controls to the driver. num_ctrls, ctrl_ids, payloads, and payload_size
+ * are output. The library owns the memory. But it can only change or free the
+ * memory on next rk_vepu_get_config() call or rk_vepu_deinit().
+ *
+ * @return -1 failure, 0 success.
+ */
+int rk_vepu_get_config(void *enc, size_t *num_ctrls, uint32_t **ctrl_ids,
+ void ***payloads, uint32_t **payload_sizes);
+
+/**
+ * Update the encoder configuration by previous encoding output.
+ *
+ * @param enc: the instance generated by rk_vepu_init.
+ * @param config: the configuration got from driver by G_EXT_CTRLS. The caller
+ * owns the memory and the encoder library cannot use the buffer after this
+ * function returns.
+ * @param config_size: size of the configuration.
+ * @param buffer_size: size of the previous encoded buffer.
+ *
+ * @return -1 failure, 0 success.
+ */
+int rk_vepu_update_config(void *enc, void *config, uint32_t config_size,
+ uint32_t buffer_size);
+
+/**
+ * Update the runtime parameters.
+ *
+ * @param enc: the instance generated by rk_vepu_init.
+ * @param runtime_param: encoder runtime parameters, see struct
+ * rk_vepu_runtime_param. If bitrate or framerate_numer is 0, it will be
+ * ignored by the library. If keyframe_request is false, keyframe_value will
+ * be ignored.
+ *
+ * @return -1 failure, 0 success.
+ */
+int rk_vepu_update_param(void *enc,
+ struct rk_vepu_runtime_param *runtime_param);
+
+#endif // LIBVPU_RK_VEPU_INTERFACE_H_
+
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/boolhuff.c b/libv4l-rockchip_v2/libvepu/vp8e/boolhuff.c
new file mode 100644
index 0000000..290faf5
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/boolhuff.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "boolhuff.h"
+
+void vp8_start_encode(BOOL_CODER *br, unsigned char *source)
+{
+ br->lowvalue = 0;
+ br->range = 255;
+ br->value = 0;
+ br->count = -24;
+ br->buffer = source;
+ br->pos = 0;
+}
+
+void vp8_stop_encode(BOOL_CODER *br)
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ vp8_encode_bool(br, 0, 128);
+}
+
+static const unsigned int norm[256] =
+{
+ 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void vp8_encode_bool(BOOL_CODER *br, int bit, int probability)
+{
+ unsigned int split;
+ int count = br->count;
+ unsigned int range = br->range;
+ unsigned int lowvalue = br->lowvalue;
+ register unsigned int shift;
+
+ split = 1 + (((range - 1) * probability) >> 8);
+
+ range = split;
+
+ if (bit) {
+ lowvalue += split;
+ range = br->range - split;
+ }
+
+ shift = norm[range];
+
+ range <<= shift;
+ count += shift;
+
+ if (count >= 0) {
+ int offset = shift - count;
+
+ if ((lowvalue << (offset - 1)) & 0x80000000) {
+ int x = br->pos - 1;
+
+ while (x >= 0 && br->buffer[x] == 0xff) {
+ br->buffer[x] = (unsigned char)0;
+ x--;
+ }
+
+ br->buffer[x] += 1;
+ }
+
+ br->buffer[br->pos++] = (lowvalue >> (24 - offset));
+ lowvalue <<= offset;
+ shift = count;
+ lowvalue &= 0xffffff;
+ count -= 8 ;
+ }
+
+ lowvalue <<= shift;
+ br->count = count;
+ br->lowvalue = lowvalue;
+ br->range = range;
+}
+
+void vp8_encode_value(BOOL_CODER *br, int data, int bits)
+{
+ int bit;
+
+ for (bit = bits - 1; bit >= 0; bit--)
+ vp8_encode_bool(br, (1 & (data >> bit)), 0x80);
+}
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/boolhuff.h b/libv4l-rockchip_v2/libvepu/vp8e/boolhuff.h
new file mode 100644
index 0000000..22b71af
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/boolhuff.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+
+/****************************************************************************
+ *
+ * Module Title : boolhuff.h
+ *
+ * Description : Bool Coder header file.
+ *
+ ****************************************************************************/
+#ifndef __INC_BOOLHUFF_H
+#define __INC_BOOLHUFF_H
+
+
+typedef struct
+{
+ unsigned int lowvalue;
+ unsigned int range;
+ unsigned int value;
+ int count;
+ unsigned int pos;
+ unsigned char *buffer;
+
+ // Variables used to track bit costs without outputing to the bitstream
+ unsigned int measure_cost;
+ unsigned long bit_counter;
+} BOOL_CODER;
+
+extern void vp8_start_encode(BOOL_CODER *bc, unsigned char *buffer);
+extern void vp8_encode_bool(BOOL_CODER *bc, int x, int context);
+extern void vp8_encode_value(BOOL_CODER *br, int data, int bits);
+extern void vp8_stop_encode(BOOL_CODER *bc);
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c b/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c
new file mode 100644
index 0000000..c0d8360
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <malloc.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "vp8e.h"
+#include "vp8e_bitstream.h"
+#include "../rk_vepu_debug.h"
+
+static int vp8e_init(struct rk_venc *ictx,
+ struct rk_vepu_init_param *param)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+
+ ictx->fmt = ENC_FORMAT_VP8;
+
+ ctx->width = param->width;
+ ctx->height = param->height;
+ ctx->frm_in_gop = 0;
+
+ ctx->hw_info.intra_frm_delta = 2;
+ ctx->hw_info.last_frm_delta = 0;
+ ctx->hw_info.golden_frm_delta = -2;
+ ctx->hw_info.altref_frm_delta = -2;
+
+ ctx->hw_info.bpred_mode_delta = 4;
+ ctx->hw_info.zero_mode_delta = -2;
+ ctx->hw_info.newmv_mode_delta = 2;
+ ctx->hw_info.splitmv_mode_delta = 4;
+
+ ctx->refresh_entropy = 1;
+ ctx->frame_cnt = 0;
+ ctx->last_frm_intra = false;
+
+ ctx->hw_info.filter_sharpness = 0;
+ ctx->hw_info.filter_level = 26; /* 0 ~ 63 */
+
+ ctx->priv_data = (struct vp8_hw_privdata *)calloc(1, sizeof(*ctx->priv_data));
+ if (ctx->priv_data == NULL) {
+ VPU_PLG_ERR("allocate private data buffer failed\n");
+ return -1;
+ }
+
+ ctx->rk_ctrl_ids[0] = V4L2_CID_PRIVATE_ROCKCHIP_HEADER;
+ ctx->rk_ctrl_ids[1] = V4L2_CID_PRIVATE_ROCKCHIP_REG_PARAMS;
+ ctx->rk_ctrl_ids[2] = V4L2_CID_PRIVATE_ROCKCHIP_HW_PARAMS;
+
+ return 0;
+}
+
+static void vp8e_deinit(struct rk_venc *ictx)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+
+ free(ctx->priv_data);
+}
+
+static int vp8e_begin_picture(struct rk_venc *ictx)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+ struct rk3399_vp8e_reg_params *hw_info = &ctx->hw_info;
+
+ VPU_PLG_ENTER();
+
+ if (ictx->runtime_param.keyframe_request) {
+ VPU_PLG_INF("got key frame request\n");
+ ctx->frm_in_gop = 0;
+ ictx->runtime_param.keyframe_request = 0;
+ }
+
+ hw_info->is_intra = 0;
+ hw_info->filter_level = 28;
+ if (ctx->frm_in_gop == 0) {
+ hw_info->is_intra = 1;
+ hw_info->filter_level = 48;
+ }
+
+ hw_info->qp = 80;
+
+ prepare_prob(&ctx->probs);
+
+ vp8_pack_bitstream(ctx);
+
+ hw_info->frm_hdr_size = ctx->hdr_len;
+ hw_info->bool_enc_value = ctx->writer.lowvalue;
+ hw_info->bool_enc_value_bits = 24 + ctx->writer.count;
+ hw_info->bool_enc_range = ctx->writer.range;
+ memcpy(hw_info->mv_prob, ctx->probs.mv, sizeof(ctx->probs.mv));
+ hw_info->intra_prob = ctx->probs.intra;
+
+ ctx->rk_payloads[0] = ctx->frmhdr;
+ ctx->rk_payload_sizes[0] = FRAME_HEADER_SIZE;
+
+ ctx->rk_payloads[1] = hw_info;
+ ctx->rk_payload_sizes[1] = sizeof(struct rockchip_reg_params);
+
+ ctx->rk_payloads[2] = ctx->priv_data;
+ ctx->rk_payload_sizes[2] = sizeof(*ctx->priv_data);
+
+ VPU_PLG_LEAVE();
+
+ return 0;
+}
+
+static int vp8e_end_picture(struct rk_venc *ictx,
+ uint32_t outputStreamSize)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+
+ VPU_PLG_ENTER();
+
+ ctx->last_frm_intra = ctx->hw_info.is_intra;
+
+ ctx->frm_in_gop++;
+ ctx->frm_in_gop %= 150;
+
+ ctx->frame_cnt++;
+
+ VPU_PLG_LEAVE();
+
+ return 0;
+}
+
+static int vp8e_update_priv(struct rk_venc *ictx, void *config, uint32_t cfglen)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+
+ assert(ctx);
+ assert(config);
+
+ memcpy(&ctx->count, config, cfglen);
+
+ return 0;
+}
+
+static void vp8e_apply_param(struct rk_venc *ictx)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+
+ assert(ctx);
+
+ /* todo, apply parameters to rate control */
+}
+
+static void vp8e_get_payloads(struct rk_venc *ictx, size_t *num, uint32_t **ids,
+ void ***payloads, uint32_t **payload_sizes)
+{
+ struct rk_vp8_encoder *ctx = (struct rk_vp8_encoder *)ictx;
+
+ VPU_PLG_ENTER();
+
+ *num = VP8E_NUM_CTRLS;
+ *ids = ctx->rk_ctrl_ids;
+ *payloads = ctx->rk_payloads;
+ *payload_sizes = ctx->rk_payload_sizes;
+
+ VPU_PLG_LEAVE();
+}
+
+static struct rk_venc_ops vp8_enc_ops = {
+ .init = vp8e_init,
+ .before_encode = vp8e_begin_picture,
+ .after_encode = vp8e_end_picture,
+ .deinit = vp8e_deinit,
+ .update_priv = vp8e_update_priv,
+ .apply_param = vp8e_apply_param,
+ .get_payloads = vp8e_get_payloads,
+};
+
+struct rk_venc* rk_vp8_encoder_alloc_ctx(void)
+{
+ struct rk_venc* enc =
+ (struct rk_venc *)calloc(1, sizeof(struct rk_vp8_encoder));
+
+ if (enc == NULL) {
+ return NULL;
+ }
+
+ enc->ops = &vp8_enc_ops;
+
+ return enc;
+}
+
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e.h b/libv4l-rockchip_v2/libvepu/vp8e/vp8e.h
new file mode 100644
index 0000000..b9abcc6
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _V4L2_PLUGIN_RK_VP8E_H_
+#define _V4L2_PLUGIN_RK_VP8E_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "../rk_vepu_interface.h"
+
+#include "vp8e_prob_adapt.h"
+#include "boolhuff.h"
+
+#include "../common/rk_venc.h"
+
+#define FRAME_HEADER_SIZE 1280
+
+#define VP8E_NUM_CTRLS 3
+
+#define VP8_PRIV_DATA_HEADER 192
+#define VP8_PROBS_CTX_SIZE ((55 + 96) << 3)
+#define VP8_SEGMENT_MAP_SIZE 4087//((1920 * 1088 * 4 / 256 + 63) / 64 * 8)
+
+struct vp8_hw_privdata {
+ uint8_t hdr[VP8_PRIV_DATA_HEADER];
+ struct vp8_probs_hw probs_hw;
+ uint8_t segmap[VP8_SEGMENT_MAP_SIZE];
+};
+
+struct rk_vp8_encoder {
+ struct rk_venc venc;
+
+ uint8_t frmhdr[FRAME_HEADER_SIZE];
+ uint32_t hdr_len;
+
+ uint8_t hw_prob_table[1208];
+ struct vp8_probs probs;
+ struct prob_count count;
+
+ struct vp8_hw_privdata *priv_data;
+
+ int frm_in_gop;
+ int width;
+ int height;
+
+ int frame_cnt;
+ bool last_frm_intra;
+
+ bool refresh_entropy;
+
+ bool default_coeff_prob_flag; /* Flag for coeffProb == defaultCoeffProb */
+ bool update_coeff_prob_flag; /* Flag for coeffProb != oldCoeffProb */
+
+ BOOL_CODER writer;
+
+ struct rk3399_vp8e_reg_params hw_info;
+
+ uint32_t rk_ctrl_ids[VP8E_NUM_CTRLS];
+ void *rk_payloads[VP8E_NUM_CTRLS];
+ uint32_t rk_payload_sizes[VP8E_NUM_CTRLS];
+};
+
+struct rk_venc* rk_vp8_encoder_alloc_ctx(void);
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e_bitstream.c b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_bitstream.c
new file mode 100644
index 0000000..d0c67e4
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_bitstream.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#include "vp8e_bitstream.h"
+
+#include <memory.h>
+
+#include "../rk_vepu_debug.h"
+#include "boolhuff.h"
+
+typedef BOOL_CODER vp8_writer;
+
+#define vp8_write vp8_encode_bool
+#define vp8_write_literal vp8_encode_value
+#define vp8_write_bit(W, V) vp8_write(W, V, 0x80)
+
+static void pack_mv_prob(vp8_writer *bc, int32_t curr[2][19], int32_t prev[2][19]) {
+ int32_t i, j;
+ int32_t prob, new, old;
+
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 19; j++) {
+ prob = mv_update_prob[i][j];
+ old = prev[i][j];
+ new = curr[i][j];
+
+ if (new == old) {
+ vp8_write(bc, 0, prob);
+ } else {
+ vp8_write(bc, 1, prob);
+ vp8_write_literal(bc, new >> 1, 7);
+ }
+ }
+ }
+}
+
+static void pack_coeff_prob(vp8_writer* bc, int32_t curr[4][8][3][11],
+ int32_t prev[4][8][3][11]) {
+ int32_t i, j, k, l;
+ int32_t prob, new_prob, old_prob;
+
+ VPU_PLG_ENTER();
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++) {
+ for (k = 0; k < 3; k++) {
+ for (l = 0; l < 11; l++) {
+ prob = coeff_update_prob[i][j][k][l];
+ old_prob = prev[i][j][k][l];
+ new_prob = curr[i][j][k][l];
+
+ if (new_prob == old_prob) {
+ vp8_write(bc, 0, prob);
+ } else {
+ vp8_write(bc, 1, prob);
+ vp8_write_literal(bc, new_prob, 8);
+ }
+ }
+ }
+ }
+ }
+
+ VPU_PLG_LEAVE();
+}
+
+static void vp8_pack_ref_mb_delta(vp8_writer *bc, int32_t delta)
+{
+ if (delta != 0) {
+ vp8_write_bit(bc, 1);
+ vp8_write_literal(bc, ABS(delta), 6);
+ vp8_write_bit(bc, delta < 0);
+ } else {
+ vp8_write_bit(bc, 0);
+ }
+}
+
+#define FRAME_SHOW 1
+#define FRAME_PROFILE 1
+void vp8_pack_bitstream(struct rk_vp8_encoder *ctx)
+{
+ struct vp8_probs *entropy = &ctx->probs;
+ vp8_writer *bc = &ctx->writer; /* "Frame header" buffer */
+ int frm_tag_len = ctx->frm_in_gop == 0 ? 10 : 3;
+ int32_t tmp;
+ int idx = 0;
+
+ vp8_start_encode(bc, ctx->frmhdr + frm_tag_len);
+
+ /* Color space and pixel Type (Key frames only) */
+ if (ctx->frm_in_gop == 0) {
+ /* color space type */
+ vp8_write_bit(bc, 0);
+
+ /* clamping type */
+ vp8_write_bit(bc, 0);
+ }
+
+ /* segmentation flag, disable segmentation by default
+ * if roi or intra area enabled, segmentation need to
+ * be configured
+ */
+ vp8_write_bit(bc, 0);
+
+ /* filter type, USING NORMAL filter type by default */
+ vp8_write_bit(bc, 0);
+
+ /* filter level, can be set to 0 ~ 63*/
+ vp8_write_literal(bc, ctx->hw_info.filter_level, 6);
+
+ /* filter sharpness level */
+ vp8_write_literal(bc, ctx->hw_info.filter_sharpness, 3);
+
+ /* Loop filter adjustments */
+ vp8_write_bit(bc, 1);
+ /* Filter level delta references reset by key frame */
+ /* following code present only on filter adjustment enabled */
+ /* we are fix the loop filter delta adjustment, so only update
+ when intra frame account */
+ if (ctx->frm_in_gop == 0) {
+ /* Do the deltas need to be updated */
+ vp8_write_bit(bc, 1);
+
+ /* ref frame mode based deltas */
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.intra_frm_delta);
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.last_frm_delta);
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.golden_frm_delta);
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.altref_frm_delta);
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.bpred_mode_delta);
+ /* mb mode based deltas */
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.zero_mode_delta);
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.newmv_mode_delta);
+ vp8_pack_ref_mb_delta(bc, ctx->hw_info.splitmv_mode_delta);
+ } else {
+ /* Do the deltas need to be updated */
+ vp8_write_bit(bc, 0);
+ }
+
+ /* token partition, support 0 or 1, so there are two
+ dct partions supported, we use only 1 here */
+ vp8_write_literal(bc, 0, 2);
+
+ /* YacQi quantizer index */
+ vp8_write_literal(bc, ctx->hw_info.qp, 7);
+
+ /* TODO: delta quantization index, we disabled here */
+ /* YdcDelta flag */
+ vp8_write_bit(bc, 0);
+
+ /* Y2dcDelta flag */
+ vp8_write_bit(bc, 0);
+
+ /* Y2acDelta flag */
+ vp8_write_bit(bc, 0);
+
+ /* UVdecDelta flag */
+ vp8_write_bit(bc, 0);
+
+ /* UVacDelta flag */
+ vp8_write_bit(bc, 0);
+
+ /* Update grf and arf buffers and sing bias, see decodframe.c 863.
+ * TODO swaping arg->grf and grf->arf in the same time is not working
+ * because of bug in the libvpx? */
+ if (ctx->frm_in_gop != 0) {
+ /* Input picture after reconstruction is set to new grf/arf */
+ vp8_write_bit(bc, 0); /* Grf refresh */
+ vp8_write_bit(bc, 0); /* Arf refresh */
+
+ vp8_write_literal(bc, 0, 2); /* Not updated */
+
+ vp8_write_literal(bc, 0, 2); /* Not updated */
+
+ /* sign bias, do not using golden or altref here, set them to false */
+ vp8_write_bit(bc, 0); /* Grf */
+ vp8_write_bit(bc, 0); /* Arf */
+ }
+
+
+ /* Refresh entropy probs flag,
+ if 0 -> put default proabilities.
+ If 1 -> use previous frame probabilities */
+ vp8_write_bit(bc, 1);
+
+ /* ipf refresh last frame flag. Note that key frame always updates ipf */
+ if (ctx->frm_in_gop != 0)
+ vp8_write_bit(bc, 1);
+
+ /* Coeff probabilities, TODO: real updates */
+ pack_coeff_prob(bc, entropy->coeff, entropy->last_coeff);
+
+ /* mb_no_coeff_skip . This flag indicates at the frame level if
+ * skipping of macroblocks with no non-zero coefficients is enabled.
+ * If it is set to 0 then prob_skip_false is not read and
+ * mb_skip_coeff is forced to 0 for all macroblocks (see Sections 11.1
+ * and 12.1). TODO */
+ vp8_write_bit(bc, 1);
+
+ /* Probability used for decoding noCoeff flag, depens above flag TODO*/
+ vp8_write_literal(bc, entropy->skip_false, 8);
+
+ if (ctx->frm_in_gop == 0)
+ goto tag_write;
+
+ /* The rest are inter frame only */
+
+ /* Macroblock is intra predicted probability */
+ vp8_write_literal(bc, entropy->intra, 8);
+
+ /* Inter is predicted from immediately previous frame probability */
+ vp8_write_literal(bc, entropy->last_prob, 8);
+
+ /* Inter is predicted from golden frame probability */
+ vp8_write_literal(bc, entropy->gf_prob, 8);
+
+ /* Intra mode probability updates not supported yet TODO */
+ vp8_write_bit(bc, 0);
+
+ /* Intra chroma probability updates not supported yet TODO */
+ vp8_write_bit(bc, 0);
+
+ /* Motion vector probability update not supported yet TOTO real updates */
+ pack_mv_prob(bc, entropy->mv, entropy->last_mv);
+
+tag_write:
+ /* Frame tag contains (lsb first):
+ * 1. A 1-bit frame type (0 for key frames, 1 for inter frames)
+ * 2. A 3-bit version number (0 - 3 are defined as 4 different profiles
+ * 3. A 1-bit showFrame flag (1 when current frame is display)
+ * 4. A 19-bit size of the first data partition in bytes
+ * Note that frame tag is written to the stream in little endian mode */
+
+ tmp = ((ctx->writer.pos) << 5) |
+ ((FRAME_SHOW ? 1 : 0) << 4) |
+ (FRAME_PROFILE << 1) |
+ (ctx->frm_in_gop != 0);
+
+ /* Note that frame tag is written _really_ literal to buffer, don't use
+ * vp8_write_literal() use VP8PutBit() instead */
+
+ ctx->frmhdr[idx++] = tmp & 0xff;
+ ctx->frmhdr[idx++] = (tmp >> 8) & 0xff;
+ ctx->frmhdr[idx++] = (tmp >> 16) & 0xff;
+
+ if (ctx->frm_in_gop != 0)
+ goto ret;
+
+ /* For key frames this is followed by a further 7 bytes of uncompressed
+ * data as follows */
+ ctx->frmhdr[idx++] = 0x9d;
+ ctx->frmhdr[idx++] = 0x01;
+ ctx->frmhdr[idx++] = 0x2a;
+
+ ctx->frmhdr[idx++] = ctx->width & 0xff;
+ ctx->frmhdr[idx++] = ctx->width >> 8;
+
+ ctx->frmhdr[idx++] = ctx->height & 0xff;
+ ctx->frmhdr[idx++] = ctx->height >> 8;
+
+ret:
+ ctx->hdr_len = frm_tag_len + bc->pos;
+}
+
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e_bitstream.h b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_bitstream.h
new file mode 100644
index 0000000..85e0adc
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_bitstream.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _VP8E_BITSTREAM_H_
+#define _VP8E_BITSTREAM_H_
+
+#include "vp8e.h"
+
+void vp8_pack_bitstream(struct rk_vp8_encoder *ctx);
+
+#endif
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e_prob_adapt.c b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_prob_adapt.c
new file mode 100644
index 0000000..af6aaa7
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_prob_adapt.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#include "vp8e_prob_adapt.h"
+
+#include <assert.h>
+#include <memory.h>
+
+#include "vp8e.h"
+#include "../common/rk_venc.h"
+#include "../rk_vepu_debug.h"
+
+enum {
+ MAX_BAND = 7,
+ MAX_CTX = 3,
+};
+
+static void swap_endianess(uint32_t *buf, uint32_t size)
+{
+ uint32_t i = 0;
+ uint32_t dw = size / 4;
+
+ assert((size % 8) == 0);
+
+ while (dw > 0) {
+ uint32_t tmp1 = 0;
+ uint32_t tmp2 = 0;
+
+ tmp1 |= (buf[i] & 0xFF) << 24;
+ tmp1 |= (buf[i] & 0xFF00) << 8;
+ tmp1 |= (buf[i] & 0xFF0000) >> 8;
+ tmp1 |= (buf[i] & 0xFF000000) >> 24;
+
+ tmp2 |= (buf[i + 1] & 0xFF) << 24;
+ tmp2 |= (buf[i + 1] & 0xFF00) << 8;
+ tmp2 |= (buf[i + 1] & 0xFF0000) >> 8;
+ tmp2 |= (buf[i + 1] & 0xFF000000) >> 24;
+
+ buf[i++] = tmp2;
+ buf[i++] = tmp1;
+
+ dw -= 2;
+ }
+}
+
+static void pack_prob_table(struct vp8_probs* probs)
+{
+ struct rk_vp8_encoder *ctx =
+ (struct rk_vp8_encoder *)container_of(probs,
+ struct rk_vp8_encoder, probs);
+ struct vp8_hw_privdata *priv_data = ctx->priv_data;
+ struct vp8_probs_hw *probs_hw = &priv_data->probs_hw;
+ int32_t i, j, k, l;
+
+ VPU_PLG_ENTER();
+
+ /* create probabilities table for hw */
+ memset(probs_hw, 0, 56);
+
+#define PROB_TRANS(x) (probs_hw->x = probs->x)
+ PROB_TRANS(skip_false);
+ PROB_TRANS(intra);
+ PROB_TRANS(last_prob);
+ PROB_TRANS(gf_prob);
+ PROB_TRANS(segment[0]);
+ PROB_TRANS(segment[1]);
+ PROB_TRANS(segment[2]);
+ PROB_TRANS(y_mode[0]);
+ PROB_TRANS(y_mode[1]);
+ PROB_TRANS(y_mode[2]);
+ PROB_TRANS(y_mode[3]);
+ PROB_TRANS(uv_mode[0]);
+ PROB_TRANS(uv_mode[1]);
+ PROB_TRANS(uv_mode[2]);
+
+ probs_hw->mv_short[0] = probs->mv[1][0];
+ probs_hw->mv_short[1] = probs->mv[0][0];
+
+ probs_hw->mv_sign[0] = probs->mv[1][1];
+ probs_hw->mv_sign[1] = probs->mv[0][1];
+
+ probs_hw->mv_x_8 = probs->mv[1][17];
+ probs_hw->mv_x_9 = probs->mv[1][18];
+
+ probs_hw->mv_y_8 = probs->mv[0][17];
+ probs_hw->mv_y_9 = probs->mv[0][18];
+
+ for (i = 0; i < 8; i++) {
+ /* mv size */
+ probs_hw->mv_x_size_9_16[i] = probs->mv[1][9 + i];
+ probs_hw->mv_y_size_9_16[i] = probs->mv[0][9 + i];
+
+ if (i == 7)
+ break;
+
+ /* mv short tree */
+ probs_hw->mv_x_short_tree[i] = probs->mv[1][2 + i];
+ probs_hw->mv_y_short_tree[i] = probs->mv[0][2 + i];
+ }
+
+ if (ctx->update_coeff_prob_flag) {
+ /* DCT coeff probabilities 0-2, two fields per line. */
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 3; k++) {
+ for (l = 0; l < 3; l++) {
+ probs_hw->coeff0[i][j][k][l] =
+ probs->coeff[i][j][k][l];
+ }
+ probs_hw->coeff0[i][j][k][3] = 0;
+ }
+
+ /* second probability table in ext mem.
+ * DCT coeff probabilities 4 5 6 7 8 9 10 3 on each line.
+ * coeff 3 was moved from first table to second so it is last. */
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++) {
+ for (k = 0; k < 3; k++) {
+ for (l = 4; l < 11; l++)
+ probs_hw->coeff1[i][j][k][l - 4] =
+ probs->coeff[i][j][k][l];
+ probs_hw->coeff1[i][j][k][7] =
+ probs->coeff[i][j][k][3];
+ }
+ }
+ }
+ }
+
+ if (ctx->update_coeff_prob_flag) {
+ swap_endianess((uint32_t *)probs_hw, sizeof(*probs_hw));
+ } else {
+ swap_endianess((uint32_t *)probs_hw, 56);
+ }
+
+ VPU_PLG_LEAVE();
+}
+
+/*------------------------------------------------------------------------------
+ update
+ determine if given probability is to be updated (savings larger than
+ cost of update)
+------------------------------------------------------------------------------*/
+static uint32_t update_prob_on_cost(uint32_t updP, uint32_t left, uint32_t right, uint32_t oldP,
+ uint32_t newP, uint32_t fixed) {
+ int32_t u, s;
+
+ /* how much it costs to update a coeff */
+ u = (int32_t)fixed + ((vp8_prob_cost[255 - updP] - vp8_prob_cost[updP]) >> 8);
+ /* bit savings if updated */
+ s = ((int32_t)left * /* zero branch count */
+ /* diff cost for '0' bin */
+ (vp8_prob_cost[oldP] - vp8_prob_cost[newP]) +
+ (int32_t)right * /* one branch count */
+ /* diff cost for '1' bin */
+ (vp8_prob_cost[255 - oldP] - vp8_prob_cost[255 - newP])) >> 8;
+
+ return (s > u);
+}
+
+static uint32_t calculate_prob(uint32_t left, uint32_t right, uint32_t last_prob) {
+ uint32_t prob;
+
+ if (left + right) {
+ prob = (left * 255) / (left + right);
+ prob &= -2;
+ if (!prob)
+ prob = 1;
+ } else {
+ prob = last_prob;
+ }
+
+ return prob;
+}
+
+/* In order to save the memory of count stored,
+ hardware skip some coefficients without meaning */
+const int32_t eob_token_index[4][MAX_BAND][MAX_CTX] = {
+ {
+ {-1, -1, -1}, {0, 1, 2}, {-1, 3, 4}, {-1, 5, 6},
+ {-1, 7, 8}, {-1, 9, 10}, {-1, 11, 12}
+ }, {
+ {13, 14, 15}, {-1, 16, 17}, {-1, 18, 19}, {-1, 20, 21},
+ {-1, 22, 23}, {-1, 24, 25}, {-1, 26, 27}
+ }, {
+ {28, 29, 30}, {-1, 31, 32}, {-1, 33, 34}, {-1, 35, 36},
+ {-1, 37, 38}, {-1, 39, 40}, {-1, 41, 42}
+ }, {
+ {43, 44, 45}, {-1, 46, 47}, {-1, 48, 49}, {-1, 50, 51},
+ {-1, 52, 53}, {-1, 54, 55}, {-1, 56, 57}
+ }
+};
+
+const int32_t zero_peg_token_index[4][MAX_BAND][MAX_CTX] = {
+ {
+ {-1, -1, -1}, {0, 1, 2}, {3, 4, 5},
+ {6, 7, 8}, {9, 10, 11},{12, 13, 14},{15, 16, 17}
+ }, {
+ {18, 19, 20}, {21, 22, 23}, {24, 25, 26},
+ {27, 28, 29}, {30, 31, 32}, {33, 34, 35}, {36, 37, 38}
+ }, {
+ {39, 40, 41}, {42, 43, 44}, {45, 46, 47},
+ {48, 49, 50}, {51, 52, 53}, {54, 55, 56}, {57, 58, 59}
+ }, {
+ {60, 61, 62}, {63, 64, 65}, {66, 67, 68},
+ {69, 70, 71}, {72, 73, 74}, {75, 76, 77}, {78, 79, 80}
+ }
+};
+
+/* adapt entropy using previous frame encoder output symbols count */
+static void adapt_probs(struct vp8_probs *probs)
+{
+ struct rk_vp8_encoder *enc = container_of(probs, struct rk_vp8_encoder, probs);
+ int32_t i, j, k;
+ uint32_t prob, left, right, oldP, updP;
+ uint32_t subtree0_count, subtree1_count;
+ uint32_t subtree_count[2];
+
+ struct prob_count *cnt_tbl = &enc->count;
+ u32 mb_per_frame = MB_COUNT(enc->width) * MB_COUNT(enc->height);
+
+ /* Update the HW prob table only when needed. */
+ enc->update_coeff_prob_flag = false;
+
+ /* Use default propabilities as reference when needed. */
+ if (!enc->refresh_entropy || enc->frm_in_gop == 0) {
+ /* Only do the copying when something has changed. */
+ if (!enc->default_coeff_prob_flag) {
+ memcpy(probs->coeff, defaultCoeffProb,
+ sizeof(defaultCoeffProb));
+ enc->update_coeff_prob_flag = true;
+ }
+ memcpy(probs->mv, defaultMvProb, sizeof(defaultMvProb));
+ enc->default_coeff_prob_flag = 1;
+ }
+
+ /* store current probs */
+ memcpy(probs->last_coeff, probs->coeff, sizeof(probs->coeff));
+ if (enc->frame_cnt == 0 || !enc->last_frm_intra)
+ memcpy(probs->last_mv, probs->mv, sizeof(probs->mv));
+
+ /* init probs */
+ probs->skip_false = defaultSkipFalseProb[enc->hw_info.qp];
+
+ /* Do not update on first frame, token/branch counters not valid yet. */
+ if (enc->frame_cnt == 0)
+ return;
+
+ for (i = 0; i < 4; i++) {
+ /* All but last (==7) bands */
+ for (j = 0; j < MAX_BAND; j++) {
+ /* All three neighbour contexts */
+ for (k = 0; k < MAX_CTX; k++) {
+ /* last token of current (type,band,ctx) */
+
+ /* caculate prob count index of other token */
+ s32 index = zero_peg_token_index[i][j][k];
+
+ right = index >= 0 ? cnt_tbl->token_other[index] : 0;
+
+ /* probability about zero token */
+ oldP = probs->coeff[i][j][k][1];
+ updP = coeff_update_prob[i][j][k][1];
+
+ /* caculate prob count index of zero token */
+ index = zero_peg_token_index[i][j][k];
+
+ left = index >= 0 ? cnt_tbl->token_zero[index] : 0;
+
+ if (left + right) {
+ prob = ((left * 256) + ((left + right) >> 1)) /
+ (left + right);
+ if (prob > 255) prob = 255;
+ } else {
+ prob = oldP;
+ }
+
+ if (update_prob_on_cost(updP, left, right, oldP, prob, 8)) {
+ probs->coeff[i][j][k][1] = prob;
+ enc->update_coeff_prob_flag = true;
+ }
+ right += left;
+
+ oldP = probs->coeff[i][j][k][0];
+ updP = coeff_update_prob[i][j][k][0];
+
+ index = eob_token_index[i][j][k];
+
+ left = index >= 0 ? cnt_tbl->token_eob[index] : 0;
+
+ if (left + right) {
+ prob = ((left * 256) + ((left + right) >> 1)) / (left + right);
+ if (prob > 255) prob = 255;
+ } else {
+ prob = oldP;
+ }
+
+ if (update_prob_on_cost(updP, left, right, oldP, prob, 8)) {
+ probs->coeff[i][j][k][0] = prob;
+ enc->update_coeff_prob_flag = true;
+ }
+ }
+ }
+ }
+
+ /* If updating coeffProbs the defaults are no longer in use. */
+ if (enc->update_coeff_prob_flag)
+ enc->default_coeff_prob_flag = false;
+
+ /* skip prob */
+ prob = cnt_tbl->skip_mb * 256 / mb_per_frame;
+ probs->skip_false = CLIP3(256 - (int32_t)prob, 0, 255);
+
+ /* intra prob, do not update if previous was intra frame,
+ set it to default value */
+ probs->intra = 63;
+ if (!enc->last_frm_intra) {
+ prob = cnt_tbl->intra_mb * 255 / mb_per_frame;
+ probs->intra = CLIP3(prob, 0, 255);
+ }
+
+ /* mv probs should not be updated if previous or current frame is intra,
+ no mv information in intra frame */
+ if (enc->last_frm_intra || enc->frm_in_gop == 0)
+ return;
+
+ /* mv probs i = 0 for mv vertical component
+ i = 1 for mv horizontal component */
+ /* see vp8 document 17. Motion Vector Decoding*/
+ for (i = 0; i < 2; i++) {
+ left = cnt_tbl->mv[i].short_mv;
+ right = cnt_tbl->mv[i].long_mv;
+
+ prob = calculate_prob(left, right, probs->last_mv[i][0]);
+ if (update_prob_on_cost(mv_update_prob[i][0], left, right,
+ probs->last_mv[i][0], prob, 6))
+ probs->mv[i][0] = prob;
+
+ /* sign prob */
+ right += left; /* total mvs */
+ left = cnt_tbl->mv[i].mv_sign; /* positive mvs count */
+ /* amount of negative vectors = total - positive - zero vectors */
+ right -= (left + cnt_tbl->mv[i].mv[0]);
+
+ prob = calculate_prob(left, right, probs->last_mv[i][1]);
+ if (update_prob_on_cost(mv_update_prob[i][1], left, right,
+ probs->last_mv[i][1], prob, 6))
+ probs->mv[i][1] = prob;
+
+ /* short mv probs, sub tree 00 and 01 (0/1 and 2/3) */
+ for (j = 0; j < 2; j++) {
+ left = cnt_tbl->mv[i].mv[j * 2];
+ right = cnt_tbl->mv[i].mv[j * 2 + 1];
+ prob = calculate_prob(left, right, probs->last_mv[i][4 + j]);
+ if (update_prob_on_cost(mv_update_prob[i][4 + j], left, right,
+ probs->last_mv[i][4+j], prob, 6))
+ probs->mv[i][4 + j] = prob;
+ /* count for subtree 00/01 */
+ subtree_count[j] = left + right;
+ }
+ /* short mv probs, subtree 0 */
+ prob = calculate_prob(subtree_count[0], subtree_count[1], probs->last_mv[i][3]);
+ if (update_prob_on_cost(mv_update_prob[i][3], subtree_count[0], subtree_count[1],
+ probs->last_mv[i][3], prob, 6))
+ probs->mv[i][3] = prob;
+
+ /* total count for subtree 0 = sum of count subtree 00 and subtree 01 */
+ subtree0_count = subtree_count[0] + subtree_count[1];
+
+ /* short mv probs, subtree 10 and 11 (4/5 and 6/7) */
+ for (j = 0; j < 2; j++) {
+ left = cnt_tbl->mv[i].mv[j * 2 + 4];
+ right = cnt_tbl->mv[i].mv[j * 2 + 5];
+
+ prob = calculate_prob(left, right, probs->last_mv[i][7 + j]);
+ if (update_prob_on_cost(mv_update_prob[i][7 + j], left, right,
+ probs->last_mv[i][7 + j], prob, 6))
+ probs->mv[i][7 + j] = prob;
+ /* count for subtree 10/11 */
+ subtree_count[j] = left + right;
+ }
+ /* short mv probs, subtree 1 */
+ prob = calculate_prob(subtree_count[0], subtree_count[1], probs->last_mv[i][6]);
+ if (update_prob_on_cost(mv_update_prob[i][6], subtree_count[0], subtree_count[1],
+ probs->last_mv[i][6], prob, 6))
+ probs->mv[i][6] = prob;
+
+ subtree1_count = subtree_count[0] + subtree_count[1];
+
+ /* short mv probs, root tree */
+ prob = calculate_prob(subtree0_count, subtree1_count,
+ probs->last_mv[i][2]);
+ if (update_prob_on_cost(mv_update_prob[i][2], subtree0_count, subtree1_count,
+ probs->last_mv[i][2], prob, 6))
+ probs->mv[i][2] = prob;
+ }
+}
+
+void prepare_prob(struct vp8_probs *entropy)
+{
+ assert(sizeof(defaultCoeffProb) == sizeof(entropy->coeff));
+ assert(sizeof(defaultCoeffProb) == sizeof(coeff_update_prob));
+ assert(sizeof(defaultMvProb) == sizeof(mv_update_prob));
+ assert(sizeof(defaultMvProb) == sizeof(entropy->mv));
+
+ adapt_probs(entropy);
+
+ /* Default propability */
+ entropy->last_prob = 255; /* Stetson-Harrison method TODO */
+ entropy->gf_prob = 128; /* Stetson-Harrison method TODO */
+ memcpy(entropy->y_mode, YmodeProb, sizeof(YmodeProb));
+ memcpy(entropy->uv_mode, UVmodeProb, sizeof(UVmodeProb));
+
+ pack_prob_table(entropy);
+}
+
diff --git a/libv4l-rockchip_v2/libvepu/vp8e/vp8e_prob_adapt.h b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_prob_adapt.h
new file mode 100644
index 0000000..54412e1
--- /dev/null
+++ b/libv4l-rockchip_v2/libvepu/vp8e/vp8e_prob_adapt.h
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2015 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _VP8E_PROB_ADAPT_H_
+#define _VP8E_PROB_ADAPT_H_
+
+#include <stdint.h>
+
+#define NUM_DCT_TOKENS 12
+
+static const int32_t defaultCoeffProb[4][8][3][11] = {
+ {
+ {
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}
+ },
+ {
+ {253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128},
+ {189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128},
+ {106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128}
+ },
+ {
+ { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128},
+ {181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128},
+ { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128}
+ },
+ {
+ { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128},
+ {184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128},
+ { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128}
+ },
+ {
+ { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128},
+ {170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128},
+ { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128}
+ },
+ {
+ { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128},
+ {207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128},
+ {102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128}
+ },
+ {
+ { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128},
+ {177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128},
+ { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128}
+ },
+ {
+ { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}
+ }
+ },
+
+ {
+ {
+ {198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62},
+ {131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1},
+ { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128}
+ },
+ {
+ { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128},
+ {184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128},
+ { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128}
+ },
+ {
+ { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128},
+ { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128},
+ { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128}
+ },
+ {
+ { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128},
+ {109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128},
+ { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128}
+ },
+ {
+ { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128},
+ { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128},
+ { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128}
+ },
+ {
+ { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128},
+ {124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128},
+ { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128}
+ },
+ {
+ { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128},
+ {121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128},
+ { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128}
+ },
+ {
+ { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128},
+ {203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128},
+ {137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128}
+ }
+ },
+
+ {
+ {
+ {253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128},
+ {175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128},
+ { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128}
+ },
+ {
+ { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128},
+ {239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128},
+ {155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128}
+ },
+ {
+ { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128},
+ {201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128},
+ { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128}
+ },
+ {
+ { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128},
+ {223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128},
+ {141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128}
+ },
+ {
+ { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128},
+ {190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128},
+ {149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128}
+ },
+ {
+ { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128}
+ },
+ {
+ { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128},
+ {213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128},
+ { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128}
+ },
+ {
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}
+ }
+ },
+
+ {
+ {
+ {202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255},
+ {126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128},
+ { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128}
+ },
+ {
+ { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128},
+ {166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128},
+ { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128}
+ },
+ {
+ { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128},
+ {124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128},
+ { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128}
+ },
+ {
+ { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128},
+ {149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128},
+ { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128}
+ },
+ {
+ { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128},
+ {123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128},
+ { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128}
+ },
+ {
+ { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128},
+ {168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128},
+ { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128}
+ },
+ {
+ { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128},
+ {141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128},
+ { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128}
+ },
+ {
+ { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128}
+ }
+ }
+};
+
+static const int32_t mv_update_prob[2][19] = {
+ { 237, 246, 253, 253, 254, 254, 254, 254, 254, 254,
+ 254, 254, 254, 254, 250, 250, 252, 254, 254 },
+
+ { 231, 243, 245, 253, 254, 254, 254, 254, 254, 254,
+ 254, 254, 254, 254, 251, 251, 254, 254, 254 }
+};
+
+static const int32_t defaultMvProb[2][19] = {
+ { 162, 128, 225, 146, 172, 147, 214, 39, 156, 128,
+ 129, 132, 75, 145, 178, 206, 239, 254, 254 },
+
+ { 164, 128, 204, 170, 119, 235, 140, 230, 228, 128,
+ 130, 130, 74, 148, 180, 203, 236, 254, 254 }
+};
+
+static const int32_t coeff_update_prob[4][8][3][11] = {
+ {
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255},
+ {249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255},
+ {234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255},
+ {250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ }
+ },
+ {
+ {
+ {217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255},
+ {234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255}
+ },
+ {
+ {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ }
+ },
+
+ {
+ {
+ {186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255},
+ {234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255},
+ {251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255}
+ },
+ {
+ {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ }
+ },
+
+ {
+ {
+ {248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255},
+ {248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255},
+ {248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
+ }
+ }
+};
+
+struct mv_counts {
+ uint16_t short_mv;
+ uint16_t long_mv;
+ uint16_t mv_sign;
+ uint16_t mv[8]; /* 8 short MVs count, 0 for zero MVs count */
+};
+
+/* count output from hardware */
+struct prob_count {
+ uint16_t token_eob[58];
+ uint16_t token_zero[81];
+ uint16_t token_other[81];
+ uint16_t skip_mb;
+ uint16_t intra_mb;
+ /* index 0: mv vertical component; index 1: mv horizontal component */
+ struct mv_counts mv[2];
+};
+
+/* HW prob table layout */
+struct vp8_probs_hw {
+ uint8_t skip_false;
+ uint8_t intra;
+ uint8_t last_prob;
+ uint8_t gf_prob;
+ uint8_t segment[3];
+ uint8_t res0;
+ uint8_t y_mode[4];
+ uint8_t uv_mode[3];
+ uint8_t res1;
+ uint8_t mv_short[2];
+ uint8_t mv_sign[2];
+ uint8_t mv_x_8;
+ uint8_t mv_x_9;
+ uint8_t mv_y_8;
+ uint8_t mv_y_9;
+ uint8_t mv_x_size_9_16[8];
+ uint8_t mv_y_size_9_16[8];
+ uint8_t mv_x_short_tree[7];
+ uint8_t res2;
+ uint8_t mv_y_short_tree[7];
+ uint8_t res3;
+ /* coeff0[][][][3] for align */
+ uint8_t coeff0[4][8][3][4];
+ uint8_t coeff1[4][8][3][8];
+};
+
+static const int32_t kfYmodeProb[4] = {
+ 145, 156, 163, 128
+};
+
+static const int32_t YmodeProb[4] = {
+ 112, 86, 140, 37
+};
+
+static const int32_t UVmodeProb[3] = {
+ 162, 101, 204
+};
+
+/* If probability being zero is p, then avarage bits used when bool is
+ zero = log2(1/p) and when bool is one = log2(1/(1-p)).
+
+ For example bins probability being zero is p = 0.5
+ bin = 0 -> average bits used is log2(1/0.5) = 1 bits/bin
+ bin = 1 -> average bits used is log2(1/(1 - 0.5) = 1 bits/bin
+
+ For example bins probability being zero is p = 0.95
+ bin = 0 -> average bits used is log2(1/0.95) = 0.074 bits/bin
+ bin = 1 -> average bits used is log2(1/(1 - 0.95) = 4.321 bits/bin
+
+ Table cost[] below is calculated as follow: cost[p] is zero bin's average bit
+ cost at given p = [1..255] (note that probability is p/256) scaled up by SCALE.
+ for (i = 0; i < 256; i++) cost[i] = round((log2((double)256/i) * SCALE)).
+ Magic number SCALE = 256. */
+static const int32_t vp8_prob_cost[] = {
+ 2048, 2048, 1792, 1642, 1536, 1454, 1386, 1329, 1280, 1236,
+ 1198, 1162, 1130, 1101, 1073, 1048, 1024, 1002, 980, 961,
+ 942, 924, 906, 890, 874, 859, 845, 831, 817, 804,
+ 792, 780, 768, 757, 746, 735, 724, 714, 705, 695,
+ 686, 676, 668, 659, 650, 642, 634, 626, 618, 611,
+ 603, 596, 589, 582, 575, 568, 561, 555, 548, 542,
+ 536, 530, 524, 518, 512, 506, 501, 495, 490, 484,
+ 479, 474, 468, 463, 458, 453, 449, 444, 439, 434,
+ 430, 425, 420, 416, 412, 407, 403, 399, 394, 390,
+ 386, 382, 378, 374, 370, 366, 362, 358, 355, 351,
+ 347, 343, 340, 336, 333, 329, 326, 322, 319, 315,
+ 312, 309, 305, 302, 299, 296, 292, 289, 286, 283,
+ 280, 277, 274, 271, 268, 265, 262, 259, 256, 253,
+ 250, 247, 245, 242, 239, 236, 234, 231, 228, 226,
+ 223, 220, 218, 215, 212, 210, 207, 205, 202, 200,
+ 197, 195, 193, 190, 188, 185, 183, 181, 178, 176,
+ 174, 171, 169, 167, 164, 162, 160, 158, 156, 153,
+ 151, 149, 147, 145, 143, 140, 138, 136, 134, 132,
+ 130, 128, 126, 124, 122, 120, 118, 116, 114, 112,
+ 110, 108, 106, 104, 102, 101, 99, 97, 95, 93,
+ 91, 89, 87, 86, 84, 82, 80, 78, 77, 75,
+ 73, 71, 70, 68, 66, 64, 63, 61, 59, 58,
+ 56, 54, 53, 51, 49, 48, 46, 44, 43, 41,
+ 40, 38, 36, 35, 33, 32, 30, 28, 27, 25,
+ 24, 22, 21, 19, 18, 16, 15, 13, 12, 10,
+ 9, 7, 6, 4, 3, 1
+};
+
+static const int32_t defaultSkipFalseProb[128] =
+{
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 251, 248, 244, 240, 236, 232, 229, 225,
+ 221, 217, 213, 208, 204, 199, 194, 190,
+ 187, 183, 179, 175, 172, 168, 164, 160,
+ 157, 153, 149, 145, 142, 138, 134, 130,
+ 127, 124, 120, 117, 114, 110, 107, 104,
+ 101, 98, 95, 92, 89, 86, 83, 80,
+ 77, 74, 71, 68, 65, 62, 59, 56,
+ 53, 50, 47, 44, 41, 38, 35, 32,
+ 30, 28, 26, 24, 22, 20, 18, 16,
+};
+
+struct vp8_probs {
+ int32_t skip_false;
+ int32_t intra;
+ int32_t last_prob;
+ int32_t gf_prob;
+ int32_t y_mode[4];
+ int32_t uv_mode[3];
+ int32_t coeff[4][8][3][11];
+ int32_t last_coeff[4][8][3][11];
+ int32_t mv[2][19];
+ int32_t last_mv[2][19];
+ int32_t segment[3];
+};
+
+void prepare_prob(struct vp8_probs *entropy);
+
+#endif