From: Daniel Kucera <daniel.kuc...@gmail.com>

Signed-off-by: Daniel Kucera <daniel.kuc...@gmail.com>
---
 libavcodec/Makefile              |   1 +
 libavcodec/allcodecs.c           |   1 +
 libavcodec/arm/sunxi/cedar_ve.h  |  79 ++++++
 libavcodec/arm/sunxi/ion.h       | 377 ++++++++++++++++++++++++++
 libavcodec/arm/sunxi/ion_sunxi.h | 108 ++++++++
 libavcodec/arm/sunxi/ve.c        | 552 +++++++++++++++++++++++++++++++++++++++
 libavcodec/arm/sunxi/ve.h        | 193 ++++++++++++++
 libavcodec/cedrus264.c           | 402 ++++++++++++++++++++++++++++
 8 files changed, 1713 insertions(+)
 create mode 100644 libavcodec/arm/sunxi/cedar_ve.h
 create mode 100644 libavcodec/arm/sunxi/ion.h
 create mode 100644 libavcodec/arm/sunxi/ion_sunxi.h
 create mode 100755 libavcodec/arm/sunxi/ve.c
 create mode 100755 libavcodec/arm/sunxi/ve.h
 create mode 100755 libavcodec/cedrus264.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3ab071a..f3821af 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -987,6 +987,7 @@ OBJS-$(CONFIG_LIBX265_ENCODER)            += libx265.o
 OBJS-$(CONFIG_LIBXAVS_ENCODER)            += libxavs.o
 OBJS-$(CONFIG_LIBXVID_ENCODER)            += libxvid.o
 OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER)   += libzvbi-teletextdec.o ass.o
+OBJS-$(CONFIG_CEDRUS264_ENCODER)          += cedrus264.o arm/sunxi/ve.o
 
 # parsers
 OBJS-$(CONFIG_AAC_LATM_PARSER)         += latm_parser.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 7b7a8c7..a153576 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -66,6 +66,7 @@ extern AVCodec ff_c93_decoder;
 extern AVCodec ff_cavs_decoder;
 extern AVCodec ff_cdgraphics_decoder;
 extern AVCodec ff_cdxl_decoder;
+extern AVCodec ff_cedrus264_encoder;
 extern AVCodec ff_cfhd_decoder;
 extern AVCodec ff_cinepak_encoder;
 extern AVCodec ff_cinepak_decoder;
diff --git a/libavcodec/arm/sunxi/cedar_ve.h b/libavcodec/arm/sunxi/cedar_ve.h
new file mode 100644
index 0000000..92faf59
--- /dev/null
+++ b/libavcodec/arm/sunxi/cedar_ve.h
@@ -0,0 +1,79 @@
+#ifndef _CEDAR_VE_H_
+#define _CEDAR_VE_H_
+
+enum IOCTL_CMD {
+       IOCTL_UNKOWN = 0x100,
+       IOCTL_GET_ENV_INFO,
+       IOCTL_WAIT_VE_DE,
+       IOCTL_WAIT_VE_EN,
+       IOCTL_RESET_VE,
+       IOCTL_ENABLE_VE,
+       IOCTL_DISABLE_VE,
+       IOCTL_SET_VE_FREQ,
+
+       IOCTL_CONFIG_AVS2 = 0x200,
+       IOCTL_GETVALUE_AVS2 ,
+       IOCTL_PAUSE_AVS2 ,
+       IOCTL_START_AVS2 ,
+       IOCTL_RESET_AVS2 ,
+       IOCTL_ADJUST_AVS2,
+       IOCTL_ENGINE_REQ,
+       IOCTL_ENGINE_REL,
+       IOCTL_ENGINE_CHECK_DELAY,
+       IOCTL_GET_IC_VER,
+       IOCTL_ADJUST_AVS2_ABS,
+       IOCTL_FLUSH_CACHE,
+       IOCTL_SET_REFCOUNT,
+
+       IOCTL_READ_REG = 0x300,
+       IOCTL_WRITE_REG,
+
+       IOCTL_SET_VOL = 0x400,
+
+#if defined CONFIG_ARCH_SUN8IW8P1
+       IOCTL_WAIT_JPEG_DEC = 0x500,
+#endif
+};
+
+struct cedarv_env_infomation{
+       unsigned int phymem_start;
+       int  phymem_total_size;
+       unsigned int  address_macc;
+};
+
+struct cedarv_cache_range{
+       long start;
+       long end;
+};
+
+/*struct __cedarv_task {
+       int task_prio;
+       int ID;
+       unsigned long timeout;
+       unsigned int frametime;
+       unsigned int block_mode;
+};
+
+struct cedarv_engine_task {
+       struct __cedarv_task t;
+       struct list_head list;
+       struct task_struct *task_handle;
+       unsigned int status;
+       unsigned int running;
+       unsigned int is_first_task;
+};
+
+struct cedarv_engine_task_info {
+       int task_prio;
+       unsigned int frametime;
+       unsigned int total_time;
+};*/
+
+struct cedarv_regop {
+    unsigned int addr;
+    unsigned int value;
+};
+/*--------------------------------------------------------------------------------*/
+
+
+#endif
diff --git a/libavcodec/arm/sunxi/ion.h b/libavcodec/arm/sunxi/ion.h
new file mode 100644
index 0000000..e777c69
--- /dev/null
+++ b/libavcodec/arm/sunxi/ion.h
@@ -0,0 +1,377 @@
+/*
+ * include/linux/ion.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_ION_H
+#define _LINUX_ION_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+
+struct ion_handle;
+/**
+ * enum ion_heap_types - list of all possible types of heaps
+ * @ION_HEAP_TYPE_SYSTEM:       memory allocated via vmalloc
+ * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
+ * @ION_HEAP_TYPE_CARVEOUT:     memory allocated from a prereserved
+ *                              carveout heap, allocations are physically
+ *                              contiguous
+ * @ION_HEAP_TYPE_DMA:          memory allocated via DMA API
+ * @ION_NUM_HEAPS:              helper for iterating over heaps, a bit mask
+ *                              is used to identify the heaps, so only 32
+ *                              total heap types are supported
+ */
+enum ion_heap_type {
+       ION_HEAP_TYPE_SYSTEM,
+       ION_HEAP_TYPE_SYSTEM_CONTIG,
+       ION_HEAP_TYPE_CARVEOUT,
+       ION_HEAP_TYPE_CHUNK,
+       ION_HEAP_TYPE_DMA,
+       ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
+                                are at the end of this enum */
+       ION_NUM_HEAPS = 16,
+};
+
+#define ION_HEAP_SYSTEM_MASK           (1 << ION_HEAP_TYPE_SYSTEM)
+#define ION_HEAP_SYSTEM_CONTIG_MASK    (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
+#define ION_HEAP_CARVEOUT_MASK         (1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_TYPE_DMA_MASK          (1 << ION_HEAP_TYPE_DMA)
+
+#define ION_NUM_HEAP_IDS               sizeof(unsigned int) * 8
+
+/**
+ * allocation flags - the lower 16 bits are used by core ion, the upper 16
+ * bits are reserved for use by the heaps themselves.
+ */
+#define ION_FLAG_CACHED 1              /* mappings of this buffer should be
+                                          cached, ion will do cache
+                                          maintenance when the buffer is
+                                          mapped for dma */
+#define ION_FLAG_CACHED_NEEDS_SYNC 2   /* mappings of this buffer will created
+                                          at mmap time, if this is set
+                                          caches must be managed manually */
+
+#ifdef __KERNEL__
+struct ion_device;
+struct ion_heap;
+struct ion_mapper;
+struct ion_client;
+struct ion_buffer;
+
+/* This should be removed some day when phys_addr_t's are fully
+   plumbed in the kernel, and all instances of ion_phys_addr_t should
+   be converted to phys_addr_t.  For the time being many kernel interfaces
+   do not accept phys_addr_t's that would have to */
+#define ion_phys_addr_t unsigned long
+
+/**
+ * struct ion_platform_heap - defines a heap in the given platform
+ * @type:      type of the heap from ion_heap_type enum
+ * @id:                unique identifier for heap.  When allocating higher 
numbers
+ *             will be allocated from first.  At allocation these are passed
+ *             as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS.
+ * @name:      used for debug purposes
+ * @base:      base address of heap in physical memory if applicable
+ * @size:      size of the heap in bytes if applicable
+ * @align:     required alignment in physical memory if applicable
+ * @priv:      private info passed from the board file
+ *
+ * Provided by the board file.
+ */
+struct ion_platform_heap {
+       enum ion_heap_type type;
+       unsigned int id;
+       const char *name;
+       ion_phys_addr_t base;
+       size_t size;
+       ion_phys_addr_t align;
+       void *priv;
+};
+
+/**
+ * struct ion_platform_data - array of platform heaps passed from board file
+ * @nr:                number of structures in the array
+ * @heaps:     array of platform_heap structions
+ *
+ * Provided by the board file in the form of platform data to a platform 
device.
+ */
+struct ion_platform_data {
+       int nr;
+       struct ion_platform_heap heaps[];
+};
+
+/**
+ * ion_reserve() - reserve memory for ion heaps if applicable
+ * @data:      platform data specifying starting physical address and
+ *             size
+ *
+ * Calls memblock reserve to set aside memory for heaps that are
+ * located at specific memory addresses or of specfic sizes not
+ * managed by the kernel
+ */
+void ion_reserve(struct ion_platform_data *data);
+
+/**
+ * ion_client_create() -  allocate a client and returns it
+ * @dev:               the global ion device
+ * @heap_type_mask:    mask of heaps this client can allocate from
+ * @name:              used for debugging
+ */
+struct ion_client *ion_client_create(struct ion_device *dev,
+                                    const char *name);
+
+/**
+ * ion_client_destroy() -  free's a client and all it's handles
+ * @client:    the client
+ *
+ * Free the provided client and all it's resources including
+ * any handles it is holding.
+ */
+void ion_client_destroy(struct ion_client *client);
+
+/**
+ * ion_alloc - allocate ion memory
+ * @client:            the client
+ * @len:               size of the allocation
+ * @align:             requested allocation alignment, lots of hardware blocks
+ *                     have alignment requirements of some kind
+ * @heap_id_mask:      mask of heaps to allocate from, if multiple bits are set
+ *                     heaps will be tried in order from highest to lowest
+ *                     id
+ * @flags:             heap flags, the low 16 bits are consumed by ion, the
+ *                     high 16 bits are passed on to the respective heap and
+ *                     can be heap custom
+ *
+ * Allocate memory in one of the heaps provided in heap mask and return
+ * an opaque handle to it.
+ */
+struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
+                            size_t align, unsigned int heap_id_mask,
+                            unsigned int flags);
+
+/**
+ * ion_free - free a handle
+ * @client:    the client
+ * @handle:    the handle to free
+ *
+ * Free the provided handle.
+ */
+void ion_free(struct ion_client *client, struct ion_handle *handle);
+
+/**
+ * ion_phys - returns the physical address and len of a handle
+ * @client:    the client
+ * @handle:    the handle
+ * @addr:      a pointer to put the address in
+ * @len:       a pointer to put the length in
+ *
+ * This function queries the heap for a particular handle to get the
+ * handle's physical address.  It't output is only correct if
+ * a heap returns physically contiguous memory -- in other cases
+ * this api should not be implemented -- ion_sg_table should be used
+ * instead.  Returns -EINVAL if the handle is invalid.  This has
+ * no implications on the reference counting of the handle --
+ * the returned value may not be valid if the caller is not
+ * holding a reference.
+ */
+int ion_phys(struct ion_client *client, struct ion_handle *handle,
+            ion_phys_addr_t *addr, size_t *len);
+
+/**
+ * ion_map_dma - return an sg_table describing a handle
+ * @client:    the client
+ * @handle:    the handle
+ *
+ * This function returns the sg_table describing
+ * a particular ion handle.
+ */
+struct sg_table *ion_sg_table(struct ion_client *client,
+                             struct ion_handle *handle);
+
+/**
+ * ion_map_kernel - create mapping for the given handle
+ * @client:    the client
+ * @handle:    handle to map
+ *
+ * Map the given handle into the kernel and return a kernel address that
+ * can be used to access this address.
+ */
+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
+
+/**
+ * ion_unmap_kernel() - destroy a kernel mapping for a handle
+ * @client:    the client
+ * @handle:    handle to unmap
+ */
+void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle);
+
+/**
+ * ion_share_dma_buf() - share buffer as dma-buf
+ * @client:    the client
+ * @handle:    the handle
+ */
+struct dma_buf *ion_share_dma_buf(struct ion_client *client,
+                                               struct ion_handle *handle);
+
+/**
+ * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd
+ * @client:    the client
+ * @handle:    the handle
+ */
+int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle);
+
+/**
+ * ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle
+ * @client:    the client
+ * @fd:                the dma-buf fd
+ *
+ * Given an dma-buf fd that was allocated through ion via ion_share_dma_buf,
+ * import that fd and return a handle representing it.  If a dma-buf from
+ * another exporter is passed in this function will return ERR_PTR(-EINVAL)
+ */
+struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd);
+
+#endif /* __KERNEL__ */
+
+/**
+ * DOC: Ion Userspace API
+ *
+ * create a client by opening /dev/ion
+ * most operations handled via following ioctls
+ *
+ */
+
+/**
+ * struct ion_allocation_data - metadata passed from userspace for allocations
+ * @len:               size of the allocation
+ * @align:             required alignment of the allocation
+ * @heap_id_mask:      mask of heap ids to allocate from
+ * @flags:             flags passed to heap
+ * @handle:            pointer that will be populated with a cookie to use to
+ *                     refer to this allocation
+ *
+ * Provided by userspace as an argument to the ioctl
+ */
+struct ion_allocation_data {
+       size_t len;
+       size_t align;
+       unsigned int heap_id_mask;
+       unsigned int flags;
+       struct ion_handle *handle;
+};
+
+/**
+ * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair
+ * @handle:    a handle
+ * @fd:                a file descriptor representing that handle
+ *
+ * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with
+ * the handle returned from ion alloc, and the kernel returns the file
+ * descriptor to share or map in the fd field.  For ION_IOC_IMPORT, userspace
+ * provides the file descriptor and the kernel returns the handle.
+ */
+struct ion_fd_data {
+       struct ion_handle *handle;
+       int fd;
+};
+
+/**
+ * struct ion_handle_data - a handle passed to/from the kernel
+ * @handle:    a handle
+ */
+struct ion_handle_data {
+       struct ion_handle *handle;
+};
+
+/**
+ * struct ion_custom_data - metadata passed to/from userspace for a custom 
ioctl
+ * @cmd:       the custom ioctl function to call
+ * @arg:       additional data to pass to the custom ioctl, typically a user
+ *             pointer to a predefined structure
+ *
+ * This works just like the regular cmd and arg fields of an ioctl.
+ */
+struct ion_custom_data {
+       unsigned int cmd;
+       unsigned long arg;
+};
+
+#define ION_IOC_MAGIC          'I'
+
+/**
+ * DOC: ION_IOC_ALLOC - allocate memory
+ *
+ * Takes an ion_allocation_data struct and returns it with the handle field
+ * populated with the opaque handle for the allocation.
+ */
+#define ION_IOC_ALLOC          _IOWR(ION_IOC_MAGIC, 0, \
+                                     struct ion_allocation_data)
+
+/**
+ * DOC: ION_IOC_FREE - free memory
+ *
+ * Takes an ion_handle_data struct and frees the handle.
+ */
+#define ION_IOC_FREE           _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
+
+/**
+ * DOC: ION_IOC_MAP - get a file descriptor to mmap
+ *
+ * Takes an ion_fd_data struct with the handle field populated with a valid
+ * opaque handle.  Returns the struct with the fd field set to a file
+ * descriptor open in the current address space.  This file descriptor
+ * can then be used as an argument to mmap.
+ */
+#define ION_IOC_MAP            _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation
+ *
+ * Takes an ion_fd_data struct with the handle field populated with a valid
+ * opaque handle.  Returns the struct with the fd field set to a file
+ * descriptor open in the current address space.  This file descriptor
+ * can then be passed to another process.  The corresponding opaque handle can
+ * be retrieved via ION_IOC_IMPORT.
+ */
+#define ION_IOC_SHARE          _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_IMPORT - imports a shared file descriptor
+ *
+ * Takes an ion_fd_data struct with the fd field populated with a valid file
+ * descriptor obtained from ION_IOC_SHARE and returns the struct with the 
handle
+ * filed set to the corresponding opaque handle.
+ */
+#define ION_IOC_IMPORT         _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory
+ *
+ * Deprecated in favor of using the dma_buf api's correctly (syncing
+ * will happend automatically when the buffer is mapped to a device).
+ * If necessary should be used after touching a cached buffer from the cpu,
+ * this will make the buffer in memory coherent.
+ */
+#define ION_IOC_SYNC           _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
+
+/**
+ * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl
+ *
+ * Takes the argument of the architecture specific ioctl to call and
+ * passes appropriate userdata for that ioctl
+ */
+#define ION_IOC_CUSTOM         _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
+
+#endif /* _LINUX_ION_H */
diff --git a/libavcodec/arm/sunxi/ion_sunxi.h b/libavcodec/arm/sunxi/ion_sunxi.h
new file mode 100644
index 0000000..d7468ae
--- /dev/null
+++ b/libavcodec/arm/sunxi/ion_sunxi.h
@@ -0,0 +1,108 @@
+/*
+ * include/linux/ion_sunxi.h
+ *
+ * Copyright(c) 2013-2015 Allwinnertech Co., Ltd.
+ *      http://www.allwinnertech.com
+ *
+ * Author: liugang <liug...@allwinnertech.com>
+ *
+ * sunxi ion header file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __ION_SUNXI_H
+#define __ION_SUNXI_H
+
+#define ION_HEAP_TYPE_SUNXI_START (ION_HEAP_TYPE_CUSTOM + 1)
+#define ION_HEAP_TYPE_SECURE     (ION_HEAP_TYPE_SUNXI_START)
+
+typedef struct {
+       long    start;
+       long    end;
+}sunxi_cache_range;
+
+typedef struct {
+       void *handle;
+       unsigned long phys_addr;
+       unsigned long size;
+}sunxi_phys_data;
+
+#define DMA_BUF_MAXCNT         8
+
+typedef struct {
+       unsigned int src_va;
+       unsigned int src_pa;
+       unsigned int dst_va;
+       unsigned int dst_pa;
+       unsigned int size;
+}dma_buf_item;
+
+typedef struct {
+       int multi_dma;
+       unsigned int cnt;
+       dma_buf_item item[DMA_BUF_MAXCNT];
+}dma_buf_group;
+
+#define ION_IOC_SUNXI_FLUSH_RANGE           5
+#define ION_IOC_SUNXI_FLUSH_ALL             6
+#define ION_IOC_SUNXI_PHYS_ADDR             7
+#define ION_IOC_SUNXI_DMA_COPY              8
+#define ION_IOC_SUNXI_DUMP                  9
+
+#ifdef __KERNEL__
+
+int flush_clean_user_range(long start, long end);
+int flush_user_range(long start, long end);
+void flush_dcache_all(void);
+
+/**
+ * sunxi_buf_alloc - alloc phys contigous memory in SUNXI platform.
+ * @size: size in bytes to allocate.
+ * @paddr: store the start phys address allocated.
+ *
+ * return the start virtual address, or 0 if failed.
+ */
+void *sunxi_buf_alloc(unsigned int size, unsigned int *paddr);
+/**
+ * sunxi_buf_free - free buffer allocated by sunxi_buf_alloc.
+ * @vaddr: the kernel virt addr of the area.
+ * @paddr: the start phys addr of the area.
+ * @size: size in bytes of the area.
+ */
+void sunxi_buf_free(void *vaddr, unsigned int paddr, unsigned int size);
+/**
+ * sunxi_alloc_phys - alloc phys contigous memory in SUNXI platform.
+ * @size: size in bytes to allocate.
+ *
+ * return the start phys addr, or 0 if failed.
+ */
+u32 sunxi_alloc_phys(size_t size);
+/**
+ * sunxi_free_phys - free phys contigous memory allocted by sunxi_alloc_phys.
+ * @paddr: the start phys addr of the area.
+ * @size: size in bytes of the area.
+ */
+void sunxi_free_phys(u32 paddr, size_t size);
+/**
+ * sunxi_map_kernel - map phys contigous memory to kernel virtual space.
+ * @paddr: the start phys addr of the area.
+ * @size: size in bytes of the area.
+ *
+ * return the start virt addr which is in vmalloc space, or NULL if failed.
+ */
+void *sunxi_map_kernel(unsigned int paddr, unsigned int size);
+/**
+ * sunxi_unmap_kernel - unmap phys contigous memory from kernel space.
+ * @vaddr: the kernel virt addr of the area.
+ * @paddr: the start phys addr of the area.
+ * @size: size in bytes of the area.
+ */
+void sunxi_unmap_kernel(void *vaddr, unsigned int paddr, unsigned int size);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/libavcodec/arm/sunxi/ve.c b/libavcodec/arm/sunxi/ve.c
new file mode 100755
index 0000000..b44b17e
--- /dev/null
+++ b/libavcodec/arm/sunxi/ve.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2013-2014 Jens Kuske <jensku...@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ *
+ */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+#include "ve.h"
+#include "ion.h"
+#include "ion_sunxi.h"
+#include "cedar_ve.h"
+
+#define LOCKFILE "/tmp/cedar_dev.lck"
+#define DEVICE "/dev/cedar_dev"
+#define PAGE_OFFSET (0xc0000000) // from kernel
+#define PAGE_SIZE (4096)
+
+#define typeof __typeof__
+
+#define container_of(ptr, type, member) ({                      \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+static int fd = -1, lockfd = -1;       
+//void memlist_add(struct ve_mem *mem);        
+//struct mem_list *memlist_find(struct ve_mem *mem);
+//int memlist_del(struct ve_mem *mem);
+//void memlist_del_all();
+
+struct memchunk_t
+{
+       struct ve_mem mem;
+       struct memchunk_t *next;
+};
+
+struct ion_mem
+{
+       struct ion_handle *handle;
+       int fd;
+       struct ve_mem mem;
+};
+
+static struct
+{
+       int fd;
+       int ion_fd;
+       void *regs;
+       int version;
+       struct memchunk_t first_memchunk;
+       pthread_rwlock_t memory_lock;
+       pthread_mutex_t device_lock;
+} ve = { .fd = -1, .ion_fd = -1, .memory_lock = PTHREAD_RWLOCK_INITIALIZER, 
.device_lock = PTHREAD_MUTEX_INITIALIZER };
+
+
+struct mem_list {
+       struct ve_mem *mem;
+       struct mem_list *next;
+} *memlist = NULL;
+
+static void memlist_add(struct ve_mem *mem) {
+       struct mem_list *m, *k;
+       if (memlist == NULL) {
+               memlist = (struct mem_list *)malloc(sizeof (struct mem_list));
+               memlist->mem = mem;
+               memlist->next = NULL;
+               return;
+       }
+       m = k = memlist;
+       while (m) {
+               k = m;
+               m = m->next;
+       }
+       m = (struct mem_list *)malloc(sizeof (struct mem_list));
+       m->mem = mem;
+       m->next = NULL;
+       k->next = m;
+}
+
+static struct mem_list *memlist_find(struct ve_mem *mem) {
+       struct mem_list *m = memlist;
+       
+       while (m) {
+               if (m->mem == mem) return m;
+               m = m->next;
+       }
+       return NULL;
+}
+
+static int memlist_del(struct ve_mem *mem) {
+       struct mem_list *m = memlist;
+       struct mem_list *prev = m;
+       
+       while (m) {
+               if (m->mem == mem) {
+                       prev->next = m->next;
+                       free(m);
+                       return 0;
+               }
+               prev = m;
+               m = m->next;
+       }
+       return -1;
+}
+
+static void memlist_del_all(void) {
+       struct mem_list *m = memlist;
+       
+       while (m) {
+               struct mem_list *k = m;
+               m = m->next;
+               free(k);
+       }
+       memlist = NULL;
+}
+
+int ve_open(void)
+{
+       if (ve.fd != -1)
+               return 0;
+
+       struct cedarv_env_infomation info;
+
+       ve.fd = open(DEVICE, O_RDWR);
+       if (ve.fd == -1)
+               return 0;
+
+       if (ioctl(ve.fd, IOCTL_GET_ENV_INFO, (void *)(&info)) == -1)
+               goto close;
+
+       ve.regs = mmap(NULL, 0x800, PROT_READ | PROT_WRITE, MAP_SHARED, ve.fd, 
info.address_macc);
+       if (ve.regs == MAP_FAILED)
+               goto close;
+
+       ve.first_memchunk.mem.phys = info.phymem_start - PAGE_OFFSET;
+       ve.first_memchunk.mem.size = info.phymem_total_size;
+
+       if (ve.first_memchunk.mem.size == 0)
+       {
+               ve.ion_fd = open("/dev/ion", O_RDONLY);
+               if (ve.ion_fd == -1)
+                       goto unmap;
+       }
+
+       ioctl(ve.fd, IOCTL_ENGINE_REQ, 0);
+       ioctl(ve.fd, IOCTL_ENABLE_VE, 0);
+       ioctl(ve.fd, IOCTL_SET_VE_FREQ, 320);
+       ioctl(ve.fd, IOCTL_RESET_VE, 0);
+
+       writel(0x00130007, ve.regs + VE_CTRL);
+
+       ve.version = readl(ve.regs + VE_VERSION) >> 16;
+       printf("[VDPAU SUNXI] VE version 0x%04x opened.\n", ve.version);
+
+       return 1;
+
+unmap:
+       munmap(ve.regs, 0x800);
+close:
+       close(ve.fd);
+       ve.fd = -1;
+       return 0;
+}
+
+int ve_lock(void) {
+       /* We must lock another file than /dev/cedar_dev, 
+        * because opening the device already do problems.
+        * (If device is opened, it will be closed at program exit and ve
+        * interrupt will be disabled, also if anohter process was using it) */
+       if(lockfd == -1) lockfd = open(LOCKFILE, O_CREAT | O_RDWR, 0666);
+       if(lockfd == -1) return 0;
+       if(flock(lockfd, LOCK_EX | LOCK_NB) < 0) return 0;
+       return 1;
+}
+
+void ve_unlock(void) {
+       if (lockfd == -1) return;
+       flock(lockfd, LOCK_UN);
+       close(lockfd);
+       lockfd = -1;
+       /* Don't try to unlink file, it causes race conditions. */
+}
+
+void ve_close(void)
+{
+       if (ve.fd == -1)
+               return;
+
+       ioctl(ve.fd, IOCTL_DISABLE_VE, 0);
+       ioctl(ve.fd, IOCTL_ENGINE_REL, 0);
+
+       munmap(ve.regs, 0x800);
+       ve.regs = NULL;
+
+       if (ve.ion_fd != -1)
+               close(ve.ion_fd);
+
+       close(ve.fd);
+       ve.fd = -1;
+}
+
+int ve_get_version(void)
+{
+       return ve.version;
+}
+
+int ve_wait(int timeout)
+{
+       if (ve.fd == -1)
+               return 0;
+       if (ve_get_version() >= 0x1633)
+               return ioctl(ve.fd, IOCTL_WAIT_VE_EN, timeout);
+       else
+               return ioctl(ve.fd, IOCTL_WAIT_VE_DE, timeout);
+}
+
+void *ve_get(int engine, uint32_t flags)
+{
+       if (pthread_mutex_lock(&ve.device_lock))
+               return NULL;
+       if (ve_get_version() >= 0x1633)
+               writel(0x001300C0 | (engine & 0xf) | (flags & ~0xf), ve.regs + 
VE_CTRL);
+       else
+               writel(0x00130000 | (engine & 0xf) | (flags & ~0xf), ve.regs + 
VE_CTRL);
+
+       return ve.regs;
+}
+
+void ve_put(void)
+{
+       writel(0x00130007, ve.regs + VE_CTRL);
+       pthread_mutex_unlock(&ve.device_lock);
+}
+
+static struct ve_mem *ion_malloc(int size)
+{
+       struct ion_mem *imem = calloc(1, sizeof(struct ion_mem));
+       if (!imem)
+       {
+               perror("calloc ion_buffer failed");
+               return NULL;
+       }
+
+       struct ion_allocation_data alloc = {
+               .len = size,
+               .align = 4096,
+               .heap_id_mask = ION_HEAP_TYPE_DMA,
+               .flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC,
+       };
+
+       if (ioctl(ve.ion_fd, ION_IOC_ALLOC, &alloc))
+       {
+               perror("ION_IOC_ALLOC failed");
+               free(imem);
+               return NULL;
+       }
+
+       imem->handle = alloc.handle;
+       imem->mem.size = size;
+
+       struct ion_fd_data map = {
+               .handle = imem->handle,
+       };
+
+       if (ioctl(ve.ion_fd, ION_IOC_MAP, &map))
+       {
+               perror("ION_IOC_MAP failed");
+               free(imem);
+               return NULL;
+       }
+
+       imem->fd = map.fd;
+
+       imem->mem.virt = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, 
imem->fd, 0);
+       if (imem->mem.virt == MAP_FAILED)
+       {
+               perror("mmap failed");
+               return NULL;
+       }
+
+       sunxi_phys_data phys = {
+               .handle = imem->handle,
+       };
+
+       struct ion_custom_data custom = {
+               .cmd = ION_IOC_SUNXI_PHYS_ADDR,
+               .arg = (unsigned long)(&phys),
+       };
+
+       if (ioctl(ve.ion_fd, ION_IOC_CUSTOM, &custom))
+       {
+               perror("ION_IOC_CUSTOM(SUNXI_PHYS_ADDR) failed");
+               free(imem);
+               return NULL;
+       }
+
+       imem->mem.phys = phys.phys_addr - 0x40000000;
+
+       memlist_add(&imem->mem);
+       
+       return &imem->mem;
+}
+
+struct ve_mem *ve_malloc(int size)
+{
+       if (ve.fd == -1)
+               return NULL;
+
+       if (ve.ion_fd != -1)
+               return ion_malloc(size);
+
+       if (pthread_rwlock_wrlock(&ve.memory_lock))
+               return NULL;
+
+       void *addr = NULL;
+       struct ve_mem *ret = NULL;
+
+       size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+       struct memchunk_t *c, *best_chunk = NULL;
+       for (c = &ve.first_memchunk; c != NULL; c = c->next)
+       {
+               if(c->mem.virt == NULL && c->mem.size >= size)
+               {
+                       if (best_chunk == NULL || c->mem.size < 
best_chunk->mem.size)
+                               best_chunk = c;
+
+                       if (c->mem.size == size)
+                               break;
+               }
+       }
+
+       if (!best_chunk)
+               goto out;
+
+       int left_size = best_chunk->mem.size - size;
+
+       addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ve.fd, 
best_chunk->mem.phys + PAGE_OFFSET);
+       if (addr == MAP_FAILED)
+       {
+               ret = NULL;
+               goto out;
+       }
+
+       best_chunk->mem.virt = addr;
+       best_chunk->mem.size = size;
+
+       if (left_size > 0)
+       {
+               c = malloc(sizeof(struct memchunk_t));
+               c->mem.phys = best_chunk->mem.phys + size;
+               c->mem.size = left_size;
+               c->mem.virt = NULL;
+               c->next = best_chunk->next;
+               best_chunk->next = c;
+       }
+
+       ret = &best_chunk->mem;
+out:
+       pthread_rwlock_unlock(&ve.memory_lock);
+       return ret;
+}
+
+static void ion_free(struct ve_mem *mem)
+{
+       if (ve.ion_fd == -1 || !mem)
+               return;
+
+       struct ion_mem *imem = container_of(mem, struct ion_mem, mem);
+
+       if (munmap(mem->virt, mem->size))
+       {
+               perror("munmap failed");
+               return;
+       }
+       
+       memlist_del(mem);
+
+       close(imem->fd);
+
+       struct ion_handle_data handle = {
+               .handle = imem->handle,
+       };
+
+       if (ioctl(ve.ion_fd, ION_IOC_FREE, &handle))
+       {
+               perror("ION_IOC_FREE failed");
+               free(imem);
+               return;
+       }
+}
+
+void ve_free(struct ve_mem *mem)
+{
+       if (ve.fd == -1)
+               return;
+
+       if (mem == NULL)
+               return;
+
+       if (ve.ion_fd != -1)
+               ion_free(mem);
+
+       if (pthread_rwlock_wrlock(&ve.memory_lock))
+               return;
+
+       struct memchunk_t *c;
+       for (c = &ve.first_memchunk; c != NULL; c = c->next)
+       {
+               if (&c->mem == mem)
+               {
+                       munmap(c->mem.virt, c->mem.size);
+                       c->mem.virt = NULL;
+                       break;
+               }
+       }
+
+       for (c = &ve.first_memchunk; c != NULL; c = c->next)
+       {
+               if (c->mem.virt == NULL)
+               {
+                       while (c->next != NULL && c->next->mem.virt == NULL)
+                       {
+                               struct memchunk_t *n = c->next;
+                               c->mem.size += n->mem.size;
+                               c->next = n->next;
+                               free(n);
+                       }
+               }
+       }
+
+       pthread_rwlock_unlock(&ve.memory_lock);
+}
+
+uint32_t ve_virt2phys(void *ptr)
+{
+       uint32_t addr = 0;
+       
+       if (ve.fd == -1)
+               return 0;
+       
+       if (ve.ion_fd != -1) {
+               
+               struct mem_list *m = memlist;
+               
+               while (m) {
+                       struct ve_mem *mem = m->mem;
+                       if (!mem) {
+                               m = m->next;
+                               continue;
+                       }
+                       
+                       //printf("c->mem: virt 0x%08X, phys 0x%08X, ptr 
0x%08X\n", (unsigned int)mem->virt, mem->phys, (unsigned int)ptr);
+                       if (mem->virt == NULL)
+                               continue;
+
+                       if (mem->virt == ptr)
+                       {
+                               addr = mem->phys;
+                               break;
+                       }
+                       else if (ptr > mem->virt && ptr < (mem->virt + 
mem->size))
+                       {
+                               addr = mem->phys + (ptr - mem->virt);
+                               break;
+                       }
+                       m = m->next;
+               }
+               return addr;
+       }
+       
+
+       //if (pthread_rwlock_rdlock(&ve.memory_lock))
+       //      return 0;
+
+       
+
+       struct memchunk_t *c;
+       for (c = &ve.first_memchunk; c != NULL; c = c->next)
+       {
+               printf("c->mem: virt 0x%08X, phys 0x%08X, ptr 0x%08X\n", 
(unsigned int)c->mem.virt, c->mem.phys, (unsigned int)ptr);
+               if (c->mem.virt == NULL)
+                       continue;
+
+               if (c->mem.virt == ptr)
+               {
+                       addr = c->mem.phys;
+                       break;
+               }
+               else if (ptr > c->mem.virt && ptr < (c->mem.virt + c->mem.size))
+               {
+                       addr = c->mem.phys + (ptr - c->mem.virt);
+                       break;
+               }
+       }
+
+       //pthread_rwlock_unlock(&ve.memory_lock);
+       return addr;
+}
+
+
+void ve_flush_cache(struct ve_mem *mem)
+{
+       if (ve.fd == -1)
+               return;
+
+       if (ve.ion_fd != -1)
+       {
+               sunxi_cache_range range = {
+                       .start = (long)mem->virt,
+                       .end = (long)mem->virt + mem->size,
+               };
+
+               struct ion_custom_data cache = {
+                       .cmd = ION_IOC_SUNXI_FLUSH_RANGE,
+                       .arg = (unsigned long)(&range),
+               };
+
+               if (ioctl(ve.ion_fd, ION_IOC_CUSTOM, &cache))
+                       perror("ION_IOC_CUSTOM(SUNXI_FLUSH_RANGE) failed");
+       }
+       else
+       {
+               struct cedarv_cache_range range =
+               {
+                       .start = (int)mem->virt,
+                       .end = (int)mem->virt + mem->size
+               };
+
+               ioctl(ve.fd, IOCTL_FLUSH_CACHE, (void*)(&range));
+       }
+}
diff --git a/libavcodec/arm/sunxi/ve.h b/libavcodec/arm/sunxi/ve.h
new file mode 100755
index 0000000..c5dcc72
--- /dev/null
+++ b/libavcodec/arm/sunxi/ve.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2013 Jens Kuske <jensku...@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ *
+ */
+
+#ifndef __VE_H__
+#define __VE_H__
+
+#include <stdint.h>
+
+int ve_lock(void);
+void ve_unlock(void);
+int ve_open(void);
+void ve_close(void);
+int ve_get_version(void);
+int ve_wait(int timeout);
+void *ve_get(int engine, uint32_t flags);
+void ve_put(void);
+
+struct ve_mem
+{
+       void *virt;
+       uint32_t phys;
+       int size;
+};
+
+struct ve_mem *ve_malloc(int size);
+void ve_free(struct ve_mem *mem);
+void ve_flush_cache(struct ve_mem *mem);
+uint32_t ve_virt2phys(void *ptr);
+
+static inline void writeb(uint8_t val, void *addr)
+{
+       *((volatile uint8_t *)addr) = val;
+}
+
+static inline void writel(uint32_t val, void *addr)
+{
+       *((volatile uint32_t *)addr) = val;
+}
+
+static inline uint32_t readl(void *addr)
+{
+       return *((volatile uint32_t *) addr);
+}
+
+#define VE_ENGINE_MPEG                 0x0
+#define VE_ENGINE_H264                 0x1
+#define VE_ENGINE_HEVC                 0x4
+#define VE_ENGINE_AVC                  0xb
+
+#define VE_CTRL                                0x000
+#define VE_EXTRA_OUT_FMT_OFFSET                0x0e8
+#define VE_VERSION                     0x0f0
+
+#define VE_MPEG_PIC_HDR                        0x100
+#define VE_MPEG_VOP_HDR                        0x104
+#define VE_MPEG_SIZE                   0x108
+#define VE_MPEG_FRAME_SIZE             0x10c
+#define VE_MPEG_MBA                    0x110
+#define VE_MPEG_CTRL                   0x114
+#define VE_MPEG_TRIGGER                        0x118
+#define VE_MPEG_STATUS                 0x11c
+#define VE_MPEG_TRBTRD_FIELD           0x120
+#define VE_MPEG_TRBTRD_FRAME           0x124
+#define VE_MPEG_VLD_ADDR               0x128
+#define VE_MPEG_VLD_OFFSET             0x12c
+#define VE_MPEG_VLD_LEN                        0x130
+#define VE_MPEG_VLD_END                        0x134
+#define VE_MPEG_MBH_ADDR               0x138
+#define VE_MPEG_DCAC_ADDR              0x13c
+#define VE_MPEG_NCF_ADDR               0x144
+#define VE_MPEG_REC_LUMA               0x148
+#define VE_MPEG_REC_CHROMA             0x14c
+#define VE_MPEG_FWD_LUMA               0x150
+#define VE_MPEG_FWD_CHROMA             0x154
+#define VE_MPEG_BACK_LUMA              0x158
+#define VE_MPEG_BACK_CHROMA            0x15c
+#define VE_MPEG_IQ_MIN_INPUT           0x180
+#define VE_MPEG_QP_INPUT               0x184
+
+#define VE_MPEG_ROT_LUMA               0x1cc
+#define VE_MPEG_ROT_CHROMA             0x1d0
+#define VE_MPEG_SDROT_CTRL             0x1d4
+
+#define VE_H264_FRAME_SIZE             0x200
+#define VE_H264_PIC_HDR                        0x204
+#define VE_H264_SLICE_HDR              0x208
+#define VE_H264_SLICE_HDR2             0x20c
+#define VE_H264_PRED_WEIGHT            0x210
+#define VE_H264_QP_PARAM               0x21c
+#define VE_H264_CTRL                   0x220
+#define VE_H264_TRIGGER                        0x224
+#define VE_H264_STATUS                 0x228
+#define VE_H264_CUR_MB_NUM             0x22c
+#define VE_H264_VLD_ADDR               0x230
+#define VE_H264_VLD_OFFSET             0x234
+#define VE_H264_VLD_LEN                        0x238
+#define VE_H264_VLD_END                        0x23c
+#define VE_H264_SDROT_CTRL             0x240
+#define VE_H264_SDROT_LUMA             0x244
+#define VE_H264_SDROT_CHROMA           0x248
+#define VE_H264_OUTPUT_FRAME_IDX       0x24c
+#define VE_H264_EXTRA_BUFFER1          0x250
+#define VE_H264_EXTRA_BUFFER2          0x254
+#define VE_H264_BASIC_BITS             0x2dc
+#define VE_H264_RAM_WRITE_PTR          0x2e0
+#define VE_H264_RAM_WRITE_DATA         0x2e4
+
+#define VE_SRAM_H264_PRED_WEIGHT_TABLE 0x000
+#define VE_SRAM_H264_FRAMEBUFFER_LIST  0x400
+#define VE_SRAM_H264_REF_LIST0         0x640
+#define VE_SRAM_H264_REF_LIST1         0x664
+#define VE_SRAM_H264_SCALING_LISTS     0x800
+
+#define VE_HEVC_NAL_HDR                        0x500
+#define VE_HEVC_SPS                    0x504
+#define VE_HEVC_PIC_SIZE               0x508
+#define VE_HEVC_PCM_HDR                        0x50c
+#define VE_HEVC_PPS0                   0x510
+#define VE_HEVC_PPS1                   0x514
+#define VE_HEVC_SLICE_HDR0             0x520
+#define VE_HEVC_SLICE_HDR1             0x524
+#define VE_HEVC_SLICE_HDR2             0x528
+#define VE_HEVC_CTB_ADDR               0x52c
+#define VE_HEVC_CTRL                   0x530
+#define VE_HEVC_TRIG                   0x534
+#define VE_HEVC_STATUS                 0x538
+#define VE_HEVC_CTU_NUM                        0x53c
+#define VE_HEVC_BITS_ADDR              0x540
+#define VE_HEVC_BITS_OFFSET            0x544
+#define VE_HEVC_BITS_LEN               0x548
+#define VE_HEVC_BITS_END_ADDR          0x54c
+#define VE_HEVC_REC_BUF_IDX            0x55c
+#define VE_HEVC_NEIGHBOR_INFO_ADDR     0x560
+#define VE_HEVC_TILE_LIST_ADDR         0x564
+#define VE_HEVC_TILE_START_CTB         0x568
+#define VE_HEVC_TILE_END_CTB           0x56c
+#define VE_HEVC_BITS_DATA              0x5dc
+#define VE_HEVC_SRAM_ADDR              0x5e0
+#define VE_HEVC_SRAM_DATA              0x5e4
+
+#define VE_SRAM_HEVC_PRED_WEIGHT_LUMA_L0       0x000
+#define VE_SRAM_HEVC_PRED_WEIGHT_CHROMA_L0     0x020
+#define VE_SRAM_HEVC_PRED_WEIGHT_LUMA_L1       0x060
+#define VE_SRAM_HEVC_PRED_WEIGHT_CHROMA_L1     0x080
+#define VE_SRAM_HEVG_PIC_LIST                  0x400
+#define VE_SRAM_HEVC_REF_PIC_LIST0             0xc00
+#define VE_SRAM_HEVC_REF_PIC_LIST1             0xc10
+
+#define VE_ISP_INPUT_SIZE              0xa00
+#define VE_ISP_INPUT_STRIDE            0xa04
+#define VE_ISP_CTRL                    0xa08
+#define VE_ISP_INPUT_LUMA              0xa78
+#define VE_ISP_INPUT_CHROMA            0xa7c
+
+#define VE_AVC_PARAM                   0xb04
+#define VE_AVC_QP                      0xb08
+#define VE_AVC_MOTION_EST              0xb10
+#define VE_AVC_CTRL                    0xb14
+#define VE_AVC_TRIGGER                 0xb18
+#define VE_AVC_STATUS                  0xb1c
+#define VE_AVC_BASIC_BITS              0xb20
+#define VE_AVC_UNK_BUF                 0xb60
+#define VE_AVC_VLE_ADDR                        0xb80
+#define VE_AVC_VLE_END                 0xb84
+#define VE_AVC_VLE_OFFSET              0xb88
+#define VE_AVC_VLE_MAX                 0xb8c
+#define VE_AVC_VLE_LENGTH              0xb90
+#define VE_AVC_REF_LUMA                        0xba0
+#define VE_AVC_REF_CHROMA              0xba4
+#define VE_AVC_REC_LUMA                        0xbb0
+#define VE_AVC_REC_CHROMA              0xbb4
+#define VE_AVC_REF_SLUMA               0xbb8
+#define VE_AVC_REC_SLUMA               0xbbc
+#define VE_AVC_MB_INFO                 0xbc0
+
+
+#endif
diff --git a/libavcodec/cedrus264.c b/libavcodec/cedrus264.c
new file mode 100755
index 0000000..5e62361
--- /dev/null
+++ b/libavcodec/cedrus264.c
@@ -0,0 +1,402 @@
+/*
+ * Cedrus 264 Video Encoder
+ * Copyright (c) 2014 Julien Folly
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Cedrus 264 Encoder
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/mem.h"
+#include "libavutil/pixdesc.h"
+#include "avcodec.h"
+#include "internal.h"
+
+#include "arm/sunxi/ve.h"
+
+/* byte stream utils from:
+ * https://github.com/jemk/cedrus/tree/master/h264enc
+ */
+static void put_bits(void* regs, uint32_t x, int num)
+{
+       writel(x, (uint8_t *)regs + VE_AVC_BASIC_BITS);
+       writel(0x1 | ((num & 0x1f) << 8), (uint8_t *)regs + VE_AVC_TRIGGER);
+       // again the problem, how to check for finish?
+}
+
+static void put_ue(void* regs, uint32_t x)
+{
+       x++;
+       put_bits(regs, x, (32 - __builtin_clz(x)) * 2 - 1);
+}
+
+static void put_se(void* regs, int x)
+{
+       x = 2 * x - 1;
+       x ^= (x >> 31);
+       put_ue(regs, x);
+}
+
+static void put_start_code(void* regs)
+{
+       uint32_t tmp = readl((uint8_t *)regs + VE_AVC_PARAM);
+
+       /* Disable emulation_prevention_three_byte */
+       writel(tmp | (0x1 << 31), (uint8_t *)regs + VE_AVC_PARAM);
+
+       put_bits(regs, 0, 31);
+       put_bits(regs, 1, 1);
+
+       writel(tmp, (uint8_t *)regs + VE_AVC_PARAM);
+}
+
+static void put_rbsp_trailing_bits(void* regs)
+{
+       unsigned int cur_bs_len = readl((uint8_t *)regs + VE_AVC_VLE_LENGTH);
+
+       int num_zero_bits = 8 - ((cur_bs_len + 1) & 0x7);
+       put_bits(regs, 1 << num_zero_bits, num_zero_bits + 1);
+}
+
+static void put_seq_parameter_set(void* regs, int width, int height)
+{
+       put_bits(regs, 3 << 5 | 7 << 0, 8);     // NAL Header
+       put_bits(regs, 77, 8);                  // profile_idc
+       put_bits(regs, 0x0, 8);                 // constraints
+       put_bits(regs, 4 * 10 + 1, 8);          // level_idc
+       put_ue(regs, 0);                        // seq_parameter_set_id
+
+       put_ue(regs, 0);                        // log2_max_frame_num_minus4
+       put_ue(regs, 0);                        // pic_order_cnt_type
+       // if (pic_order_cnt_type == 0)
+               put_ue(regs, 4);                // 
log2_max_pic_order_cnt_lsb_minus4
+
+       put_ue(regs, 1);                        // max_num_ref_frames
+       put_bits(regs, 0, 1);                   // 
gaps_in_frame_num_value_allowed_flag
+
+       put_ue(regs, width - 1);                // pic_width_in_mbs_minus1
+       put_ue(regs, height - 1);               // 
pic_height_in_map_units_minus1
+
+       put_bits(regs, 1, 1);                   // frame_mbs_only_flag
+       // if (!frame_mbs_only_flag)
+
+       put_bits(regs, 1, 1);                   // direct_8x8_inference_flag
+       put_bits(regs, 0, 1);                   // frame_cropping_flag
+       // if (frame_cropping_flag)
+
+       put_bits(regs, 0, 1);                   // vui_parameters_present_flag
+       // if (vui_parameters_present_flag)
+}
+
+static void put_pic_parameter_set(void *regs, int qp_minus30)
+{
+       put_bits(regs, 3 << 5 | 8 << 0, 8);     // NAL Header
+       put_ue(regs, 0);                        // pic_parameter_set_id
+       put_ue(regs, 0);                        // seq_parameter_set_id
+       put_bits(regs, 1, 1);                   // entropy_coding_mode_flag
+       put_bits(regs, 0, 1);                   // 
bottom_field_pic_order_in_frame_present_flag
+       put_ue(regs, 0);                        // num_slice_groups_minus1
+       // if (num_slice_groups_minus1 > 0)
+
+       put_ue(regs, 0);                        // 
num_ref_idx_l0_default_active_minus1
+       put_ue(regs, 0);                        // 
num_ref_idx_l1_default_active_minus1
+       put_bits(regs, 0, 1);                   // weighted_pred_flag
+       put_bits(regs, 0, 2);                   // weighted_bipred_idc
+       //put_se(regs, 0);                      // pic_init_qp_minus26 (minus 
slice_qp_delta)
+       //put_se(regs, 0);                      // pic_init_qs_minus26
+       put_se(regs, qp_minus30);               // pic_init_qp_minus26 (minus 
slice_qp_delta)
+       put_se(regs, qp_minus30);               // pic_init_qs_minus26
+       put_se(regs, 4);                        // chroma_qp_index_offset
+       put_bits(regs, 1, 1);                   // 
deblocking_filter_control_present_flag
+       put_bits(regs, 0, 1);                   // constrained_intra_pred_flag
+       put_bits(regs, 0, 1);                   // 
redundant_pic_cnt_present_flag
+}
+
+static void put_slice_header(void* regs)
+{
+       put_bits(regs, 3 << 5 | 5 << 0, 8);     // NAL Header
+
+       put_ue(regs, 0);                        // first_mb_in_slice
+       put_ue(regs, 2);                        // slice_type
+       put_ue(regs, 0);                        // pic_parameter_set_id
+       put_bits(regs, 0, 4);                   // frame_num
+
+       // if (IdrPicFlag)
+               put_ue(regs, 0);                // idr_pic_id
+
+       // if (pic_order_cnt_type == 0)
+               put_bits(regs, 0, 8);           // pic_order_cnt_lsb
+
+       // dec_ref_pic_marking
+               put_bits(regs, 0, 1);           // no_output_of_prior_pics_flag
+               put_bits(regs, 0, 1);           // long_term_reference_flag
+
+       put_se(regs, 4);                        // slice_qp_delta
+
+       // if (deblocking_filter_control_present_flag)
+               put_ue(regs, 0);                // disable_deblocking_filter_idc
+               // if (disable_deblocking_filter_idc != 1)
+                       put_se(regs, 0);        // slice_alpha_c0_offset_div2
+                       put_se(regs, 0);        // slice_beta_offset_div2
+}
+
+static void put_aud(void* regs)
+{
+       put_bits(regs, 0 << 5 | 9 << 0, 8);     // NAL Header
+
+       put_bits(regs, 7, 3);                   // primary_pic_type
+}
+
+#define CEDAR_OUTPUT_BUF_SIZE  1*1024*1024
+typedef struct cedrus264Context {
+       AVClass *class;
+       uint8_t *ve_regs;
+       struct ve_mem *input_buf, *output_buf, *reconstruct_buf, 
*small_luma_buf, *mb_info_buf;
+       unsigned int tile_w, tile_w2, tile_h, tile_h2, mb_w, mb_h, plane_size, 
frame_size;
+       unsigned int frame_num;
+       int qp, vewait;
+} cedrus264Context;
+
+static av_cold int cedrus264_encode_init(AVCodecContext *avctx)
+{
+       cedrus264Context *c4 = avctx->priv_data;
+       
+       /* Check pixel format */
+       if(avctx->pix_fmt != AV_PIX_FMT_NV12){
+               av_log(avctx, AV_LOG_FATAL, "Unsupported pixel format (use 
-pix_fmt nv12)!\n");
+               return AVERROR(EINVAL);
+       }
+
+       /* Check width */
+       if(avctx->width % 32 != 0){
+               av_log(avctx, AV_LOG_FATAL, "Input width is not a multiple of 
32!\n");
+               return AVERROR(EINVAL);
+       }
+
+       /* Check if VE is available */
+       while(!ve_lock()){
+               if (c4->vewait <= 0){
+                       av_log(avctx, AV_LOG_ERROR, "VE in use!\n");
+                       return AVERROR(ENOMEM);
+               }
+               av_log(avctx, AV_LOG_INFO, "VE in use, wait %i seconds.\r", 
c4->vewait--);
+               sleep(1);
+       }
+
+       /* Open VE */
+       if(!ve_open()){
+               av_log(avctx, AV_LOG_ERROR, "VE Open error.\n");
+               return AVERROR(ENOMEM);
+       }
+       
+
+       /* Compute tile, macroblock and plane size */
+       c4->tile_w = (avctx->width + 31) & ~31;
+       c4->tile_w2 = (avctx->width / 2 + 31) & ~31;
+       c4->tile_h = (avctx->height + 31) & ~31;
+       c4->tile_h2 = (avctx->height / 2 + 31) & ~31;
+       c4->mb_w = (avctx->width + 15) / 16;
+       c4->mb_h = (avctx->height + 15) / 16;
+       c4->plane_size = c4->mb_w * 16 * c4->mb_h * 16;
+       c4->frame_size = c4->plane_size + c4->plane_size / 2;
+
+       /* Alloc buffers */
+       c4->input_buf = ve_malloc(c4->frame_size);
+       c4->output_buf = ve_malloc(CEDAR_OUTPUT_BUF_SIZE);
+       c4->reconstruct_buf = ve_malloc(c4->tile_w * c4->tile_h + c4->tile_w * 
c4->tile_h2);
+       c4->small_luma_buf = ve_malloc(c4->tile_w2 * c4->tile_h2);
+       c4->mb_info_buf = ve_malloc(0x1000);
+       if(!c4->input_buf || !c4->output_buf || !c4->reconstruct_buf || 
!c4->small_luma_buf || !c4->mb_info_buf){
+               av_log(avctx, AV_LOG_FATAL, "Cannot allocate frame.\n");
+               return AVERROR(ENOMEM);
+       }
+
+       /* Activate AVC engine */
+       c4->ve_regs = ve_get(VE_ENGINE_AVC, 0);
+
+       /* ---- Part to put in cedrus264_encode if engine is used by multiple 
process (Need to be checked) */
+
+       /* Input size */
+       writel(c4->mb_w << 16, c4->ve_regs + VE_ISP_INPUT_STRIDE);
+       writel((c4->mb_w << 16) | (c4->mb_h << 0), c4->ve_regs + 
VE_ISP_INPUT_SIZE);
+
+       /* Input buffer */
+       writel(c4->input_buf->phys, c4->ve_regs + VE_ISP_INPUT_LUMA);
+       writel(c4->input_buf->phys + c4->plane_size, c4->ve_regs + 
VE_ISP_INPUT_CHROMA);
+       
+       /* Reference output */
+       writel(c4->reconstruct_buf->phys, c4->ve_regs + VE_AVC_REC_LUMA);
+       writel(c4->reconstruct_buf->phys + c4->tile_w * c4->tile_h, c4->ve_regs 
+ VE_AVC_REC_CHROMA);
+       writel(c4->small_luma_buf->phys, c4->ve_regs + VE_AVC_REC_SLUMA);
+       writel(c4->mb_info_buf->phys, c4->ve_regs + VE_AVC_MB_INFO);
+
+       /* Encoding parameters */
+       writel(0x00000100, c4->ve_regs + VE_AVC_PARAM);
+       writel(0x00040000 | (c4->qp<<8) | c4->qp, c4->ve_regs + VE_AVC_QP);
+       //writel(0x00041e1e, c4->ve_regs + VE_AVC_QP); // Fixed QP=30
+       writel(0x00000104, c4->ve_regs + VE_AVC_MOTION_EST);
+
+       /* ---- Part end ---- */
+
+       /* Alloc Frame */
+       avctx->coded_frame = av_frame_alloc();
+       if(!avctx->coded_frame){
+               av_log(avctx, AV_LOG_FATAL, "Cannot allocate frame.\n");
+               return AVERROR(ENOMEM);
+       }
+
+       /* Init variables */
+       c4->frame_num = 0;
+       avctx->coded_frame->quality = c4->qp * FF_QP2LAMBDA;
+
+       return 0;
+}
+
+static int cedrus264_encode(AVCodecContext *avctx, AVPacket *pkt,
+                      const AVFrame *frame, int *got_packet)
+{
+       cedrus264Context *c4 = avctx->priv_data;
+       unsigned int size;
+       int result;
+
+       /* Copy data */
+       result = avpicture_layout((const AVPicture *)frame, AV_PIX_FMT_NV12,
+               avctx->width, avctx->height, c4->input_buf->virt, 
c4->frame_size);
+       if(result < 0){
+               av_log(avctx, AV_LOG_ERROR, "Input buffer too small.\n");
+               return AVERROR(ENOMEM);
+       }
+       ve_flush_cache(c4->input_buf);
+
+       /* flush output buffer, otherwise we might read old cached data */
+       ve_flush_cache(c4->output_buf);
+       
+       /* Set output buffer */
+       writel(0x0, c4->ve_regs + VE_AVC_VLE_OFFSET);
+       writel(c4->output_buf->phys, c4->ve_regs + VE_AVC_VLE_ADDR);
+       writel(c4->output_buf->phys + CEDAR_OUTPUT_BUF_SIZE - 1, c4->ve_regs + 
VE_AVC_VLE_END);
+
+       writel(0x04000000, c4->ve_regs + 0xb8c); // ???
+       
+       put_start_code(c4->ve_regs);
+       put_aud(c4->ve_regs);
+       put_rbsp_trailing_bits(c4->ve_regs);
+
+       if (c4->frame_num == 0)
+       {
+               put_start_code(c4->ve_regs);
+               put_seq_parameter_set(c4->ve_regs, c4->mb_w, c4->mb_h);
+               put_rbsp_trailing_bits(c4->ve_regs);
+
+               put_start_code(c4->ve_regs);
+               put_pic_parameter_set(c4->ve_regs, c4->qp - 30);
+               put_rbsp_trailing_bits(c4->ve_regs);
+       }
+
+       put_start_code(c4->ve_regs);
+       put_slice_header(c4->ve_regs);
+
+       writel(readl(c4->ve_regs + VE_AVC_CTRL) | 0xf, c4->ve_regs + 
VE_AVC_CTRL);
+       writel(readl(c4->ve_regs + VE_AVC_STATUS) | 0x7, c4->ve_regs + 
VE_AVC_STATUS);
+
+       writel(0x8, c4->ve_regs + VE_AVC_TRIGGER);
+       ve_wait(1);
+
+       writel(readl(c4->ve_regs + VE_AVC_STATUS), c4->ve_regs + VE_AVC_STATUS);
+
+       size = readl(c4->ve_regs + VE_AVC_VLE_LENGTH) / 8;
+       if(size > 0){
+               if ((result = ff_alloc_packet(pkt, size)) < 0){
+                       av_log(avctx, AV_LOG_ERROR, "Packet allocation 
error.\n");
+                       return result;
+               }
+               memcpy(pkt->data, c4->output_buf->virt, size);
+
+               pkt->pts = pkt->dts = frame->pts - 
ff_samples_to_time_base(avctx, avctx->delay);
+               pkt->flags |= AV_PKT_FLAG_KEY;
+               *got_packet = 1;
+       }else *got_packet = 0;
+
+       c4->frame_num++;
+
+       return 0;
+}
+
+static av_cold int cedrus264_close(AVCodecContext *avctx)
+{
+       cedrus264Context *c4 = avctx->priv_data;
+
+       /* Close AVC engine */
+       ve_put();
+
+       /* Free buffers */
+       ve_free(c4->input_buf);
+       ve_free(c4->output_buf);
+       ve_free(c4->reconstruct_buf);
+       ve_free(c4->small_luma_buf);
+       ve_free(c4->mb_info_buf);
+
+       /* Disable and close VE */
+       ve_close();
+       ve_unlock();
+
+       /* Free Frame */
+       av_frame_free(&avctx->coded_frame);
+
+       return 0;
+}
+
+#define OFFSET(x) offsetof(cedrus264Context, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+        /* Quality range form 0 to 51 not working, good is between 2 and 47 */
+       { "qp",         "Constant quantization parameter rate control method", 
OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 30 }, 2, 47, VE },
+       { "vewait",     "Time to wait if the VE is busy (default 0)", 
OFFSET(vewait), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
+       { NULL },
+};
+
+static const AVClass cedrus264_class = {
+       .class_name = "cedrus264",
+       .item_name  = av_default_item_name,
+       .option     = options,
+       .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_cedrus264_encoder = {
+       .name           = "cedrus264",
+       .long_name      = NULL_IF_CONFIG_SMALL("Cedrus H.264 Encoder"),
+       .type           = AVMEDIA_TYPE_VIDEO,
+       .id             = AV_CODEC_ID_H264,
+       .priv_data_size = sizeof(cedrus264Context),
+       .init           = cedrus264_encode_init,
+       .encode2        = cedrus264_encode,
+       .close          = cedrus264_close,
+       .priv_class     = &cedrus264_class,
+};
-- 
2.7.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to