summaryrefslogtreecommitdiff
authorbrian.zhu <brian.zhu@amlogic.com>2014-01-27 09:28:54 (GMT)
committer Sandy lUo <sandy.luo@amlogic.com>2014-02-17 11:48:40 (GMT)
commita63700c49b6dd9aada1fa6d6460d2dd8e1e59634 (patch)
tree31eb3cf03f35eab3982a96c100c2863f7127ddcb
parent66e38b28cd5abccf7cd62fa5d8b0eb6be1d40f67 (diff)
downloadcamera-a63700c49b6dd9aada1fa6d6460d2dd8e1e59634.zip
camera-a63700c49b6dd9aada1fa6d6460d2dd8e1e59634.tar.gz
camera-a63700c49b6dd9aada1fa6d6460d2dd8e1e59634.tar.bz2
PD #86949 add hw jpeg encode
Diffstat
-rwxr-xr-xAndroid.mk16
-rwxr-xr-xAppCallbackNotifier.cpp32
-rwxr-xr-xEncoder_libjpeg.cpp53
-rwxr-xr-xinc/Encoder_libjpeg.h7
-rwxr-xr-xinc/jpegenc_hw/jpegenc.h88
-rwxr-xr-xjpegenc_hw/jpegenc.cpp374
6 files changed, 535 insertions, 35 deletions
diff --git a/Android.mk b/Android.mk
index b94e99f..9494f4a 100755
--- a/Android.mk
+++ b/Android.mk
@@ -35,6 +35,9 @@ CAMERA_HAL_VERTURAL_CAMERA_SRC:= \
CAMERA_HAL_JPEG_SRC:=\
mjpeg/jpegdec.c \
mjpeg/colorspaces.c
+
+CAMERA_HAL_HW_JPEGENC_SRC:=\
+ jpegenc_hw/jpegenc.cpp
include $(CLEAR_VARS)
@@ -45,6 +48,10 @@ LOCAL_SRC_FILES:= \
$(CAMERA_UTILS_SRC) \
$(CAMERA_HAL_JPEG_SRC)
+ifeq ($(BOARD_HAVE_HW_JPEGENC),true)
+LOCAL_SRC_FILES += $(CAMERA_HAL_HW_JPEGENC_SRC)
+endif
+
ifneq (,$(wildcard hardware/amlogic/gralloc))
GRALLOC_DIR := hardware/amlogic/gralloc
else
@@ -65,6 +72,11 @@ LOCAL_C_INCLUDES += \
$(GRALLOC_DIR) \
system/core/include/utils
+ifeq ($(BOARD_HAVE_HW_JPEGENC),true)
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/inc/jpegenc_hw/
+endif
+
LOCAL_C_INCLUDES_VIRCAM := \
$(LOCAL_PATH)/vircam/inc
@@ -153,6 +165,10 @@ ifeq ($(BOARD_HAVE_VIRTUAL_CAMERA),true)
$(LOCAL_C_INCLUDES_VIRCAM)
endif
+ifeq ($(BOARD_HAVE_HW_JPEGENC),true)
+ LOCAL_CFLAGS += -DAMLOGIC_HW_JPEGENC
+endif
+
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE:= camera.amlogic
LOCAL_MODULE_TAGS:= optional
diff --git a/AppCallbackNotifier.cpp b/AppCallbackNotifier.cpp
index 197c604..886fa1c 100755
--- a/AppCallbackNotifier.cpp
+++ b/AppCallbackNotifier.cpp
@@ -921,37 +921,6 @@ void AppCallbackNotifier::notifyFrame()
main_jpeg->format = CameraParameters::PIXEL_FORMAT_YUV420SP;
}
-// disable thumbnail for now. preview was stopped and mPreviewBufs was
-// cleared, so this won't work.
-#if 0
- tn_width = parameters.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
- tn_height = parameters.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
-
- if ((tn_width > 0) && (tn_height > 0)) {
- tn_jpeg = (Encoder_libjpeg::params*)
- malloc(sizeof(Encoder_libjpeg::params));
- // if malloc fails just keep going and encode main jpeg
- if (!tn_jpeg) {
- tn_jpeg = NULL;
- }
- }
-
- if (tn_jpeg) {
- int width, height;
- parameters.getPreviewSize(&width,&height);
- current_snapshot = (mPreviewBufCount + MAX_BUFFERS - 1) % MAX_BUFFERS;
- tn_jpeg->src = (uint8_t*) mPreviewBufs[current_snapshot];
- tn_jpeg->src_size = mPreviewMemory->size / MAX_BUFFERS;
- tn_jpeg->dst = (uint8_t*) malloc(tn_jpeg->src_size);
- tn_jpeg->dst_size = tn_jpeg->src_size;
- tn_jpeg->quality = tn_quality;
- tn_jpeg->in_width = width;
- tn_jpeg->in_height = height;
- tn_jpeg->out_width = tn_width;
- tn_jpeg->out_height = tn_height;
- tn_jpeg->format = CameraParameters::PIXEL_FORMAT_YUV420SP;;
- }
-#else
tn_width = parameters.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
tn_height = parameters.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
@@ -993,7 +962,6 @@ void AppCallbackNotifier::notifyFrame()
CAMHAL_LOGEA("Error! Thumbnail Jpeg encoder malloc memory fail!");
}
}
-#endif
CAMHAL_LOGDA("IMAGE_FRAME ENCODE_RAW..");
sp<Encoder_libjpeg> encoder = new Encoder_libjpeg(main_jpeg,
diff --git a/Encoder_libjpeg.cpp b/Encoder_libjpeg.cpp
index 8eaf885..8b57aca 100755
--- a/Encoder_libjpeg.cpp
+++ b/Encoder_libjpeg.cpp
@@ -43,6 +43,7 @@ extern "C" {
#include "jerror.h"
}
+
#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0]))
namespace android {
@@ -50,7 +51,6 @@ struct string_pair {
const char* string1;
const char* string2;
};
-
static string_pair degress_to_exif_lut [] = {
// degrees, exif_orientation
{"0", "1"},
@@ -443,6 +443,7 @@ size_t Encoder_libjpeg::encode(params* input) {
int out_width = 0, in_width = 0;
int out_height = 0, in_height = 0;
int bpp = 2; // for uyvy
+
Encoder_libjpeg::format informat = Encoder_libjpeg::YUV422I;
if (!input) {
@@ -455,9 +456,16 @@ size_t Encoder_libjpeg::encode(params* input) {
in_height = input->in_height;
src = input->src;
input->jpeg_size = 0;
-
libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size);
+#ifdef AMLOGIC_HW_JPEGENC
+ if((out_width == in_width)&&(out_height == in_height)
+ &&(out_height%16 == 0)&&(out_width%16 == 0)){
+ goto HW_CASE;
+ }
+SOFTWARE_ENC:
+#endif
+
// param check...
if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) ||
(src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) ||
@@ -500,7 +508,7 @@ size_t Encoder_libjpeg::encode(params* input) {
jpeg_create_compress(&cinfo);
- CAMHAL_LOGDB("encoding... \n\t"
+ CAMHAL_LOGDB("software encoding... \n\t"
"width: %d \n\t"
"height:%d \n\t"
"dest %p \n\t"
@@ -569,6 +577,45 @@ size_t Encoder_libjpeg::encode(params* input) {
exit:
input->jpeg_size = dest_mgr.jpegsize;
return dest_mgr.jpegsize;
+
+#ifdef AMLOGIC_HW_JPEGENC
+HW_CASE:
+ size_t jpeg_size = 0;
+ memset(&hw_info,0, sizeof(hw_info));
+ if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
+ hw_info.in_format = FMT_NV21;
+ } else if (strcmp(input->format, CameraProperties::PIXEL_FORMAT_RGB24) == 0) {
+ hw_info.in_format = FMT_RGB888;
+ } else if(strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)== 0){
+ hw_info.in_format = FMT_YUV422_SINGLE;
+ } else{
+ hw_info.in_format = FMT_NV21;
+ }
+ hw_info.fd = -1;
+ hw_info.width = out_width;
+ hw_info.height = out_height;
+ hw_info.src = input->src;
+ hw_info.src_size= input->src_size;
+ hw_info.dst= input->dst;
+ hw_info.dst_size= input->dst_size;
+ hw_info.quality = input->quality;
+
+ CAMHAL_LOGDB("hardware encoding... \n\t"
+ "width: %d \n\t"
+ "height:%d \n\t"
+ "dest %p \n\t"
+ "dest size:%d \n\t"
+ "mSrc %p",
+ out_width, out_height, input->dst,
+ input->dst_size, input->src);
+ jpeg_size = hw_encode(&hw_info);
+ if(jpeg_size<=0){
+ CAMHAL_LOGEA("HW Encode fail, re-encode with software.");
+ goto SOFTWARE_ENC;
+ }
+ input->jpeg_size = jpeg_size;
+ return jpeg_size;
+#endif
}
} // namespace android
diff --git a/inc/Encoder_libjpeg.h b/inc/Encoder_libjpeg.h
index 5075f41..42780e5 100755
--- a/inc/Encoder_libjpeg.h
+++ b/inc/Encoder_libjpeg.h
@@ -27,6 +27,10 @@
#include <utils/threads.h>
#include <utils/RefBase.h>
+#ifdef AMLOGIC_HW_JPEGENC
+#include "jpegenc.h"
+#endif
+
extern "C" {
#include "jhead.h"
}
@@ -174,6 +178,9 @@ class Encoder_libjpeg : public Thread {
sp<Encoder_libjpeg> mThumb;
size_t encode(params*);
+#ifdef AMLOGIC_HW_JPEGENC
+ hw_jpegenc_t hw_info;
+#endif
};
}
diff --git a/inc/jpegenc_hw/jpegenc.h b/inc/jpegenc_hw/jpegenc.h
new file mode 100755
index 0000000..f408a1f
--- a/dev/null
+++ b/inc/jpegenc_hw/jpegenc.h
@@ -0,0 +1,88 @@
+#ifndef AML_JPEG_ENCODER_M8_
+#define AML_JPEG_ENCODER_M8_
+
+#define JPEGENC_IOC_MAGIC 'E'
+
+#define JPEGENC_IOC_GET_DEVINFO _IOW(JPEGENC_IOC_MAGIC, 0xf0, unsigned int)
+
+#define JPEGENC_IOC_GET_ADDR _IOW(JPEGENC_IOC_MAGIC, 0x00, unsigned int)
+#define JPEGENC_IOC_INPUT_UPDATE _IOW(JPEGENC_IOC_MAGIC, 0x01, unsigned int)
+#define JPEGENC_IOC_GET_STATUS _IOW(JPEGENC_IOC_MAGIC, 0x02, unsigned int)
+#define JPEGENC_IOC_NEW_CMD _IOW(JPEGENC_IOC_MAGIC, 0x03, unsigned int)
+#define JPEGENC_IOC_GET_STAGE _IOW(JPEGENC_IOC_MAGIC, 0x04, unsigned int)
+#define JPEGENC_IOC_GET_OUTPUT_SIZE _IOW(JPEGENC_IOC_MAGIC, 0x05, unsigned int)
+#define JPEGENC_IOC_SET_QUALITY _IOW(JPEGENC_IOC_MAGIC, 0x06, unsigned int)
+#define JPEGENC_IOC_SET_ENCODER_WIDTH _IOW(JPEGENC_IOC_MAGIC, 0x07, unsigned int)
+#define JPEGENC_IOC_SET_ENCODER_HEIGHT _IOW(JPEGENC_IOC_MAGIC, 0x08, unsigned int)
+#define JPEGENC_IOC_CONFIG_INIT _IOW(JPEGENC_IOC_MAGIC, 0x09, unsigned int)
+#define JPEGENC_IOC_FLUSH_CACHE _IOW(JPEGENC_IOC_MAGIC, 0x0a, unsigned int)
+#define JPEGENC_IOC_FLUSH_DMA _IOW(JPEGENC_IOC_MAGIC, 0x0b, unsigned int)
+#define JPEGENC_IOC_GET_BUFFINFO _IOW(JPEGENC_IOC_MAGIC, 0x0c, unsigned int)
+#define JPEGENC_IOC_INPUT_FORMAT _IOW(JPEGENC_IOC_MAGIC, 0x0d, unsigned int)
+#define JPEGENC_IOC_SEL_QUANT_TABLE _IOW(JPEGENC_IOC_MAGIC, 0x0e, unsigned int)
+#define JPEGENC_IOC_SET_EXT_QUANT_TABLE _IOW(JPEGENC_IOC_MAGIC, 0x0f, unsigned int)
+
+//---------------------------------------------------
+// ENCODER_STATUS define
+//---------------------------------------------------
+#define ENCODER_IDLE 0
+#define ENCODER_START 1
+//#define ENCODER_SOS_HEADER 2
+#define ENCODER_MCU 3
+#define ENCODER_DONE 4
+
+
+#define JPEGENC_BUFFER_INPUT 0
+#define JPEGENC_BUFFER_OUTPUT 1
+
+typedef enum{
+ LOCAL_BUFF = 0,
+ CANVAS_BUFF,
+ PHYSICAL_BUFF,
+ MAX_BUFF_TYPE
+}jpegenc_mem_type;
+
+typedef enum{
+ FMT_YUV422_SINGLE = 0,
+ FMT_YUV444_SINGLE,
+ FMT_NV21,
+ FMT_NV12,
+ FMT_YUV420,
+ FMT_YUV444_PLANE,
+ FMT_RGB888,
+ FMT_RGB888_PLANE,
+ FMT_RGB565,
+ FMT_RGBA8888,
+ MAX_FRAME_FMT
+}jpegenc_frame_fmt;
+
+#define ENCODER_PATH "/dev/jpegenc"
+
+typedef struct{
+ unsigned char* addr;
+ unsigned size;
+}jpegenc_buff_t;
+
+typedef struct hw_jpegenc_s {
+ uint8_t* src;
+ unsigned src_size;
+ uint8_t* dst;
+ unsigned dst_size;
+ int quality;
+ int qtbl_id;
+ unsigned width;
+ unsigned height;
+ int bpp;
+ jpegenc_mem_type type;
+ jpegenc_frame_fmt in_format;
+ jpegenc_frame_fmt out_format;
+ size_t jpeg_size;
+
+ int fd;
+ jpegenc_buff_t mmap_buff;
+ jpegenc_buff_t input_buf;
+ jpegenc_buff_t output_buf;
+ }hw_jpegenc_t;
+
+extern size_t hw_encode(hw_jpegenc_t* hw_info);
+#endif \ No newline at end of file
diff --git a/jpegenc_hw/jpegenc.cpp b/jpegenc_hw/jpegenc.cpp
new file mode 100755
index 0000000..e9bb535
--- a/dev/null
+++ b/jpegenc_hw/jpegenc.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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.
+ */
+
+ #define LOG_TAG "HW_JPEGENC"
+
+#include "CameraHal.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+
+#include "jpegenc.h"
+
+#define ENCODE_DONE_TIMEOUT 5000
+
+//#define DEBUG_TIME
+#ifdef DEBUG_TIME
+static struct timeval start_test, end_test;
+#endif
+
+static int RGBX32_To_RGB24Plane_NEON(unsigned char *src, unsigned char *dest, int width, int height)
+{
+ unsigned char *R;
+ unsigned char *G;
+ unsigned char *B;
+ int canvas_w = ((width+31)>>5)<<5;
+ int i, j;
+ int aligned = canvas_w - width;
+
+ if( !src || !dest )
+ return -1;
+
+ R = dest;
+ G = R + canvas_w * height;
+ B = G + canvas_w * height;
+
+ for( i = 0; i < height; i += 1 ){
+ for( j = 0; j < width; j += 8 ){
+ asm volatile (
+ "vld4.8 {d0, d1, d2, d3}, [%[src]]! \n" // load 8 more ABGR pixels.
+ "vst1.8 {d0}, [%[R]]! \n" // store R.
+ "vst1.8 {d1}, [%[G]]! \n" // store G.
+ "vst1.8 {d2}, [%[B]]! \n" // store B.
+
+ : [src] "+r" (src), [R] "+r" (R),
+ [G] "+r" (G), [B] "+r" (B)
+ :
+ : "cc", "memory", "d0", "d1", "d2", "d3"
+ );
+ }
+ if(aligned){
+ R+=aligned;
+ G+=aligned;
+ B+=aligned;
+ }
+ }
+ return canvas_w*height*3;
+}
+
+static int RGB24_To_RGB24Plane_NEON(unsigned char *src, unsigned char *dest, int width, int height)
+{
+ unsigned char *R;
+ unsigned char *G;
+ unsigned char *B;
+ int i, j;
+ int canvas_w = ((width+31)>>5)<<5;
+ int aligned = canvas_w - width;
+
+ if( !src || !dest )
+ return -1;
+
+#ifdef DEBUG_TIME
+ unsigned total_time = 0;
+ struct timeval start_test1, end_test1;
+ gettimeofday(&start_test1, NULL);
+#endif
+ R = dest;
+ G = R + canvas_w * height;
+ B = G + canvas_w * height;
+
+ for( i = 0; i < height; i += 1 ){
+ for( j = 0; j < width; j += 8 ){
+ asm volatile (
+ "vld3.8 {d0, d1, d2}, [%[src]]! \n" // load 8 more BGR pixels.
+ "vst1.8 {d0}, [%[R]]! \n" // store R.
+ "vst1.8 {d1}, [%[G]]! \n" // store G.
+ "vst1.8 {d2}, [%[B]]! \n" // store B.
+
+ : [src] "+r" (src), [R] "+r" (R),
+ [G] "+r" (G), [B] "+r" (B)
+ :
+ : "cc", "memory", "d0", "d1", "d2"
+ );
+ }
+ if(aligned){
+ R+=aligned;
+ G+=aligned;
+ B+=aligned;
+ }
+ }
+#ifdef DEBUG_TIME
+ gettimeofday(&end_test1, NULL);
+ total_time = (end_test1.tv_sec - start_test1.tv_sec)*1000000 + end_test1.tv_usec -start_test1.tv_usec;
+ ALOGD("RGB24_To_RGB24Plane_NEON: need time: %d us",total_time);
+#endif
+ return canvas_w*height*3;
+}
+
+static int encode_poll(int fd, int timeout)
+{
+ struct pollfd poll_fd[1];
+ poll_fd[0].fd = fd;
+ poll_fd[0].events = POLLIN |POLLERR;
+ return poll(poll_fd, 1, timeout);
+}
+
+static unsigned copy_to_local(hw_jpegenc_t* hw_info)
+{
+ unsigned offset = 0;
+ int bytes_per_line = 0, active = 0;;
+ unsigned i = 0;
+ unsigned total_size = 0;
+ unsigned char* src = NULL;
+ unsigned char* dst = NULL;
+ int plane_num = 1;
+
+ if((hw_info->bpp !=12)&&(hw_info->in_format != FMT_YUV444_PLANE)&&(hw_info->in_format != FMT_RGB888_PLANE))
+ bytes_per_line = hw_info->width*hw_info->bpp/8;
+ else
+ bytes_per_line = hw_info->width;
+
+ if((hw_info->in_format == FMT_YUV420)||(hw_info->in_format == FMT_YUV444_PLANE)||(hw_info->in_format == FMT_RGB888_PLANE))
+ plane_num = 3;
+ else if ((hw_info->in_format == FMT_NV12)||(hw_info->in_format == FMT_NV21))
+ plane_num = 2;
+
+ active = bytes_per_line;
+
+ if(hw_info->in_format == FMT_YUV420)
+ bytes_per_line = ((bytes_per_line+63)>>6)<<6;
+ else if((hw_info->in_format == FMT_NV12)||(hw_info->in_format == FMT_NV21)||(hw_info->in_format == FMT_RGB888)
+ ||(hw_info->in_format == FMT_YUV422_SINGLE)||(hw_info->in_format == FMT_YUV444_SINGLE)||(hw_info->in_format == FMT_YUV444_PLANE)
+ ||(hw_info->in_format == FMT_RGB888_PLANE))
+ bytes_per_line = ((bytes_per_line+31)>>5)<<5;
+
+ src = (unsigned char*)hw_info->src;
+ dst = hw_info->input_buf.addr;
+ if(bytes_per_line != active){
+ for(i =0; i<hw_info->height; i++){
+ memcpy(dst, src,active);
+ dst+=bytes_per_line;
+ src+=active;
+ }
+ }else{
+ memcpy(dst, src,hw_info->height*bytes_per_line);
+ }
+
+ if(plane_num == 2){
+ offset = hw_info->height*bytes_per_line;
+ src = (unsigned char*)(hw_info->src + hw_info->height*active);
+ dst = (unsigned char*)(hw_info->input_buf.addr+offset);
+ if(bytes_per_line != active){
+ for(i =0; i<hw_info->height/2; i++){
+ memcpy(dst, src,active);
+ dst+=bytes_per_line;
+ src+=active;
+ }
+ }else{
+ memcpy(dst, src,hw_info->height*bytes_per_line/2);
+ }
+ }else if(plane_num == 3){
+ unsigned temp_active = ((hw_info->in_format == FMT_YUV444_PLANE)||(hw_info->in_format == FMT_RGB888_PLANE))?active:active/2;
+ unsigned temp_h = ((hw_info->in_format == FMT_YUV444_PLANE)||(hw_info->in_format == FMT_RGB888_PLANE))?hw_info->height:hw_info->height/2;
+ unsigned temp_bytes = ((hw_info->in_format == FMT_YUV444_PLANE)||(hw_info->in_format == FMT_RGB888_PLANE))?bytes_per_line:bytes_per_line/2;
+ offset = hw_info->height*bytes_per_line;
+ src = (unsigned char*)(hw_info->src + hw_info->height*active);
+ dst = (unsigned char*)(hw_info->input_buf.addr+offset);
+ if(bytes_per_line != active){
+ for(i =0; i<temp_h; i++){
+ memcpy(dst, src,temp_active);
+ dst+=temp_bytes;
+ src+=temp_active;
+ }
+ }else{
+ memcpy(dst, src,temp_bytes*temp_h);
+ }
+ offset = temp_h*temp_bytes+hw_info->height*bytes_per_line;
+ src = (unsigned char*)(hw_info->src + hw_info->height*active +temp_h*temp_active);
+ dst = (unsigned char*)(hw_info->input_buf.addr+offset);
+ if(bytes_per_line != active){
+ for(i =0; i<temp_h; i++){
+ memcpy(dst, src,temp_active);
+ dst+=temp_bytes;
+ src+=temp_active;
+ }
+ }else{
+ memcpy(dst, src,temp_bytes*temp_h);
+ }
+ }
+ if((hw_info->bpp !=12)&&(hw_info->in_format != FMT_YUV444_PLANE)&&(hw_info->in_format != FMT_RGB888_PLANE))
+ total_size = bytes_per_line*hw_info->height;
+ else
+ total_size = bytes_per_line*hw_info->height*hw_info->bpp/8;
+ return total_size;
+}
+
+static size_t start_encoder(hw_jpegenc_t* hw_info)
+{
+ int i;
+ int bpp;
+ unsigned size = 0;
+ unsigned cmd[7] , status;
+ unsigned in_format = hw_info->in_format;
+ if(hw_info->type == LOCAL_BUFF){
+ if((hw_info->in_format != FMT_RGB888)&&(hw_info->in_format != FMT_RGBA8888)){
+ cmd[5] = copy_to_local(hw_info);
+ }else if(hw_info->in_format == FMT_RGB888){
+ cmd[5] = RGB24_To_RGB24Plane_NEON(hw_info->src, hw_info->input_buf.addr, hw_info->width, hw_info->height);
+ in_format = FMT_RGB888_PLANE;
+ }else{
+ cmd[5] = RGBX32_To_RGB24Plane_NEON(hw_info->src, hw_info->input_buf.addr, hw_info->width, hw_info->height);
+ in_format = FMT_RGB888_PLANE;
+ }
+ }else{
+ cmd[5] = hw_info->width*hw_info->height*hw_info->bpp/8;
+ }
+
+ cmd[0] = hw_info->type; //input buffer type
+ cmd[1] = in_format;
+ cmd[2] = hw_info->out_format;
+ cmd[3] = (unsigned)hw_info->input_buf.addr;
+ cmd[4] = 0;
+ //cmd[5] = hw_info->width*hw_info->height*bpp/8;
+ cmd[6] = 1;
+
+ ioctl(hw_info->fd, JPEGENC_IOC_NEW_CMD, cmd);
+ if(encode_poll(hw_info->fd, ENCODE_DONE_TIMEOUT)<=0){
+ ALOGE("hw_encode: poll fail");
+ return 0;
+ }
+
+ ioctl(hw_info->fd, JPEGENC_IOC_GET_STAGE, &status);
+ if(status == ENCODER_DONE){
+ ioctl(hw_info->fd, JPEGENC_IOC_GET_OUTPUT_SIZE, &size);
+ if((size < hw_info->output_buf.size)&&(size>0)&&(size<=hw_info->dst_size)){
+ cmd[0] = JPEGENC_BUFFER_OUTPUT;
+ cmd[1] = 0 ;
+ cmd[2] = size ;
+ ioctl(hw_info->fd, JPEGENC_IOC_FLUSH_DMA ,cmd);
+ memcpy(hw_info->dst,hw_info->output_buf.addr,size);
+ ALOGV("hw_encode: done size: %d ",size);
+ }else{
+ ALOGE("hw_encode: output buffer size error: bitstream buffer size: %d, jpeg size: %d, output buffer size: %d",hw_info->output_buf.size, size, hw_info->dst_size);
+ size = 0;
+ }
+ }
+ return size;
+}
+
+size_t hw_encode(hw_jpegenc_t* hw_info)
+{
+ unsigned buff_info[5];
+ int ret;
+ unsigned encoder_width = hw_info->width;
+ unsigned encoder_height = hw_info->height;
+
+#ifdef DEBUG_TIME
+ unsigned total_time = 0;
+ gettimeofday(&start_test, NULL);
+#endif
+ hw_info->jpeg_size = 0;
+ hw_info->fd = open(ENCODER_PATH, O_RDWR);
+ if(hw_info->fd < 0){
+ ALOGD("hw_encode open device fail");
+ goto EXIT;
+ }
+
+ memset(buff_info,0,sizeof(buff_info));
+ ret = ioctl(hw_info->fd, JPEGENC_IOC_GET_BUFFINFO,&buff_info[0]);
+ if((ret)||(buff_info[0]==0)){
+ ALOGE("hw_encode -- no buffer information!");
+ goto EXIT;
+ }
+ hw_info->mmap_buff.addr = (unsigned char*)mmap(0,buff_info[0], PROT_READ|PROT_WRITE , MAP_SHARED ,hw_info->fd, 0);
+ if (hw_info->mmap_buff.addr == MAP_FAILED) {
+ ALOGE("hw_encode Error: failed to map framebuffer device to memory.\n");
+ goto EXIT;
+ }
+
+ hw_info->mmap_buff.size = buff_info[0];
+ hw_info->input_buf.addr = hw_info->mmap_buff.addr+buff_info[1];
+ hw_info->input_buf.size = buff_info[3]-buff_info[1];
+ hw_info->output_buf.addr = hw_info->mmap_buff.addr +buff_info[3];
+ hw_info->output_buf.size = buff_info[4];
+
+ hw_info->qtbl_id = 0;
+
+ switch(hw_info->in_format){
+ case FMT_NV21:
+ hw_info->bpp = 12;
+ break;
+ case FMT_RGB888:
+ hw_info->bpp = 24;
+ break;
+ case FMT_YUV422_SINGLE:
+ hw_info->bpp = 16;
+ break;
+ case FMT_YUV444_PLANE:
+ case FMT_RGB888_PLANE:
+ hw_info->bpp = 24;
+ break;
+ default:
+ hw_info->bpp = 12;
+ }
+
+ ioctl(hw_info->fd, JPEGENC_IOC_SET_ENCODER_WIDTH ,&encoder_width);
+ ioctl(hw_info->fd, JPEGENC_IOC_SET_ENCODER_HEIGHT ,&encoder_height);
+
+ if((hw_info->width!= encoder_width)||(hw_info->height!= encoder_height)){
+ ALOGE("hw_encode: set encode size fail. set as %dx%d, but max size is %dx%d.",hw_info->width,hw_info->height,encoder_width,encoder_height);
+ goto EXIT;
+ }
+
+ ioctl(hw_info->fd, JPEGENC_IOC_SET_QUALITY ,&hw_info->quality);
+ ioctl(hw_info->fd, JPEGENC_IOC_SEL_QUANT_TABLE ,&hw_info->qtbl_id);
+ //ioctl(hw_info->fd, JPEGENC_IOC_SET_EXT_QUANT_TABLE ,NULL);
+
+ ioctl(hw_info->fd, JPEGENC_IOC_CONFIG_INIT,NULL);
+
+ hw_info->type = LOCAL_BUFF;
+ hw_info->out_format = FMT_YUV420; //FMT_YUV422_SINGLE
+ hw_info->jpeg_size = start_encoder(hw_info);
+EXIT:
+ if(hw_info->mmap_buff.addr){
+ munmap(hw_info->mmap_buff.addr ,hw_info->mmap_buff.size);
+ }
+ close(hw_info->fd);
+ hw_info->fd = -1;
+#ifdef DEBUG_TIME
+ gettimeofday(&end_test, NULL);
+ total_time = (end_test.tv_sec - start_test.tv_sec)*1000000 + end_test.tv_usec -start_test.tv_usec;
+ ALOGD("hw_encode: need time: %d us, jpeg size:%d",total_time,hw_info->jpeg_size);
+#endif
+ return hw_info->jpeg_size;
+}
+