diff options
Diffstat (limited to 'exynos5/hal/libhwjpeg')
-rw-r--r-- | exynos5/hal/libhwjpeg/Android.mk | 37 | ||||
-rw-r--r-- | exynos5/hal/libhwjpeg/SecJpegCodecHal.cpp | 338 | ||||
-rw-r--r-- | exynos5/hal/libhwjpeg/SecJpegDecoderHal.cpp | 498 | ||||
-rw-r--r-- | exynos5/hal/libhwjpeg/SecJpegEncoder.cpp | 952 | ||||
-rw-r--r-- | exynos5/hal/libhwjpeg/SecJpegEncoderHal.cpp | 497 |
5 files changed, 2322 insertions, 0 deletions
diff --git a/exynos5/hal/libhwjpeg/Android.mk b/exynos5/hal/libhwjpeg/Android.mk new file mode 100644 index 0000000..70e25fe --- /dev/null +++ b/exynos5/hal/libhwjpeg/Android.mk @@ -0,0 +1,37 @@ +# Copyright (C) 2008 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include + +LOCAL_SRC_FILES:= \ + SecJpegCodecHal.cpp \ + SecJpegEncoderHal.cpp \ + SecJpegEncoder.cpp \ + SecJpegDecoderHal.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libion + +#LOCAL_STATIC_LIBRARIES := \ + +LOCAL_MODULE:= libhwjpeg + +LOCAL_MODULE_TAGS := eng + +include $(BUILD_SHARED_LIBRARY) diff --git a/exynos5/hal/libhwjpeg/SecJpegCodecHal.cpp b/exynos5/hal/libhwjpeg/SecJpegCodecHal.cpp new file mode 100644 index 0000000..b78212b --- /dev/null +++ b/exynos5/hal/libhwjpeg/SecJpegCodecHal.cpp @@ -0,0 +1,338 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2011 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/mman.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <math.h> +#include <sys/poll.h> + +#include <cutils/log.h> + +#include <utils/Log.h> + +#include "SecJpegCodecHal.h" + +#define JPEG_ERROR_LOG(fmt,...) + +SecJpegCodecHal::SecJpegCodecHal() +{ +} + +SecJpegCodecHal::~SecJpegCodecHal() +{ +} + +int SecJpegCodecHal::t_v4l2Querycap(int iFd) +{ + struct v4l2_capability cap; + int iRet = ERROR_NONE; + + iRet = ioctl(iFd, VIDIOC_QUERYCAP, &cap); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: VIDIOC_QUERYCAP failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2SetJpegcomp(int iFd, int iQuality) +{ + struct v4l2_jpegcompression arg; + int iRet = ERROR_NONE; + + arg.quality = iQuality; + + iRet = ioctl(iFd, VIDIOC_S_JPEGCOMP, &arg); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: VIDIOC_S_JPEGCOMP failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2SetFmt(int iFd, enum v4l2_buf_type eType, struct CONFIG *pstConfig) +{ + struct v4l2_format fmt; + int iRet = ERROR_NONE; + + fmt.type = eType; + fmt.fmt.pix_mp.width = pstConfig->width; + fmt.fmt.pix_mp.height = pstConfig->height; + fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; + fmt.fmt.pix_mp.num_planes = pstConfig->numOfPlanes; + + if (pstConfig->mode == MODE_ENCODE) + fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_JPEG; + + switch (fmt.type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: // fall through + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (pstConfig->mode == MODE_ENCODE) { + fmt.fmt.pix_mp.pixelformat = pstConfig->pix.enc_fmt.in_fmt; + } else { + fmt.fmt.pix_mp.pixelformat = pstConfig->pix.dec_fmt.in_fmt; + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = pstConfig->sizeJpeg; + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (pstConfig->mode == MODE_ENCODE) { + fmt.fmt.pix_mp.pixelformat = pstConfig->pix.enc_fmt.out_fmt; + } else { + fmt.fmt.pix_mp.pixelformat = pstConfig->pix.dec_fmt.out_fmt; + fmt.fmt.pix_mp.width = pstConfig->scaled_width; + fmt.fmt.pix_mp.height = pstConfig->scaled_height; + } + break; + default: + return -ERROR_INVALID_V4l2_BUF_TYPE; + break; + } + + iRet = ioctl(iFd, VIDIOC_S_FMT, &fmt); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: VIDIOC_S_FMT failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2GetFmt(int iFd, enum v4l2_buf_type eType, struct CONFIG *pstConfig) +{ + struct v4l2_format fmt; + int iRet = ERROR_NONE; + + fmt.type = eType; + iRet = ioctl(iFd, VIDIOC_G_FMT, &fmt); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: VIDIOC_G_FMT failed", __func__, iRet); + return iRet; + } + + switch (fmt.type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: // fall through + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pstConfig->width = fmt.fmt.pix.width; + pstConfig->height = fmt.fmt.pix.height; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pstConfig->width = fmt.fmt.pix_mp.width; + pstConfig->height = fmt.fmt.pix_mp.height; + if (pstConfig->mode == MODE_ENCODE) + pstConfig->pix.enc_fmt.in_fmt = fmt.fmt.pix_mp.pixelformat; + else + pstConfig->pix.dec_fmt.in_fmt = fmt.fmt.pix_mp.pixelformat; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + pstConfig->width = fmt.fmt.pix_mp.width; + pstConfig->height = fmt.fmt.pix_mp.height; + if (pstConfig->mode == MODE_ENCODE) + pstConfig->pix.enc_fmt.out_fmt = fmt.fmt.pix_mp.pixelformat; + else + pstConfig->pix.dec_fmt.out_fmt = fmt.fmt.pix_mp.pixelformat; + break; + default: + return -ERROR_INVALID_V4l2_BUF_TYPE; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2Reqbufs(int iFd, int iBufCount, struct BUF_INFO *pstBufInfo) +{ + struct v4l2_requestbuffers req; + int iRet = ERROR_NONE; + + memset(&req, 0, sizeof(req)); + + req.type = pstBufInfo->buf_type; + req.memory = pstBufInfo->memory; + + //if (pstBufInfo->memory == V4L2_MEMORY_MMAP) + req.count = iBufCount; + + iRet = ioctl(iFd, VIDIOC_REQBUFS, &req); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: VIDIOC_REQBUFS failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2Querybuf(int iFd, struct BUF_INFO *pstBufInfo, struct BUFFER *pstBuf) +{ + struct v4l2_buffer v4l2_buf; + struct v4l2_plane plane[JPEG_MAX_PLANE_CNT]; + int iRet = ERROR_NONE; + int i; + + memset(plane, 0, (int)JPEG_MAX_PLANE_CNT * sizeof(struct v4l2_plane)); + + v4l2_buf.index = 0; + v4l2_buf.type = pstBufInfo->buf_type; + v4l2_buf.memory = pstBufInfo->memory; + v4l2_buf.length = pstBufInfo->numOfPlanes; + v4l2_buf.m.planes = plane; + + iRet = ioctl(iFd, VIDIOC_QUERYBUF, &v4l2_buf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: VIDIOC_QUERYBUF failed", __func__, iRet); + return iRet; + } + + for (i= 0; i < v4l2_buf.length; i++) { + pstBuf->size[i] = v4l2_buf.m.planes[i].length; + pstBuf->addr[i] = (char *) mmap(0, + pstBuf->size[i], + PROT_READ | PROT_WRITE, MAP_SHARED, iFd, + v4l2_buf.m.planes[i].m.mem_offset); + + if (pstBuf->addr[i] == MAP_FAILED) { + JPEG_ERROR_LOG("[%s]: mmap failed", __func__); + return -ERROR_MMAP_FAILED; + } + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2Qbuf(int iFd, struct BUF_INFO *pstBufInfo, struct BUFFER *pstBuf) +{ + struct v4l2_buffer v4l2_buf; + struct v4l2_plane plane[JPEG_MAX_PLANE_CNT]; + int i; + int iRet = ERROR_NONE; + + memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer)); + memset(plane, 0, (int)JPEG_MAX_PLANE_CNT * sizeof(struct v4l2_plane)); + + v4l2_buf.index = 0; + v4l2_buf.type = pstBufInfo->buf_type; + v4l2_buf.memory = pstBufInfo->memory; + v4l2_buf.length = pstBufInfo->numOfPlanes; + v4l2_buf.m.planes = plane; + + if (pstBufInfo->memory == V4L2_MEMORY_USERPTR) { + for (i = 0; i < pstBufInfo->numOfPlanes; i++) { + v4l2_buf.m.planes[i].m.userptr = (unsigned long)pstBuf->addr[i]; + v4l2_buf.m.planes[i].length = pstBuf->size[i]; + } + } + + iRet = ioctl(iFd, VIDIOC_QBUF, &v4l2_buf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d] VIDIOC_QBUF failed", __func__, iRet); + pstBuf->numOfPlanes = 0; + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2Dqbuf(int iFd, enum v4l2_buf_type eType, enum v4l2_memory eMemory) +{ + struct v4l2_buffer buf; + int iRet = ERROR_NONE; + + memset(&buf, 0, sizeof(struct v4l2_buffer)); + + buf.type = eType; + buf.memory = eMemory; + + iRet = ioctl(iFd, VIDIOC_DQBUF, &buf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d] VIDIOC_DQBUF failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2StreamOn(int iFd, enum v4l2_buf_type eType) +{ + int iRet = ERROR_NONE; + + iRet = ioctl(iFd, VIDIOC_STREAMON, &eType); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d] VIDIOC_STREAMON failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2StreamOff(int iFd, enum v4l2_buf_type eType) +{ + int iRet = ERROR_NONE; + + iRet = ioctl(iFd, VIDIOC_STREAMOFF, &eType); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d] VIDIOC_STREAMOFF failed", __func__, iRet); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2SetCtrl(int iFd, int iCid, int iValue) +{ + struct v4l2_control vc; + int iRet = ERROR_NONE; + + vc.id = iCid; + vc.value = iValue; + + iRet = ioctl(iFd, VIDIOC_S_CTRL, &vc); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s] VIDIOC_S_CTRL failed : cid(%d), value(%d)\n", __func__, iCid, iValue); + return iRet; + } + + return iRet; +} + +int SecJpegCodecHal::t_v4l2GetCtrl(int iFd, int iCid) +{ + struct v4l2_control ctrl; + int iRet = ERROR_NONE; + + ctrl.id = iCid; + + iRet = ioctl(iFd, VIDIOC_G_CTRL, &ctrl); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s] VIDIOC_G_CTRL failed : cid(%d)\n", __func__, ctrl.id); + return iRet; + } + + return ctrl.value; +} + diff --git a/exynos5/hal/libhwjpeg/SecJpegDecoderHal.cpp b/exynos5/hal/libhwjpeg/SecJpegDecoderHal.cpp new file mode 100644 index 0000000..563b15a --- /dev/null +++ b/exynos5/hal/libhwjpeg/SecJpegDecoderHal.cpp @@ -0,0 +1,498 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2011 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/mman.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <math.h> +#include <sys/poll.h> + +#include <cutils/log.h> + +#include <utils/Log.h> + +#include "SecJpegCodecHal.h" + +#define JPEG_ERROR_LOG(fmt,...) + +#define NUM_PLANES (1) +#define NUM_BUFFERS (1) + +SecJpegDecoderHal::SecJpegDecoderHal() +{ + t_iJpegFd = -1; + t_bFlagCreate = false; +} + +SecJpegDecoderHal::~SecJpegDecoderHal() +{ + if (t_bFlagCreate == true) { + this->destroy(); + } +} + +int SecJpegDecoderHal::create(void) +{ + if (t_bFlagCreate == true) { + return ERROR_JPEG_DEVICE_ALREADY_CREATE; + } + + int iRet = ERROR_NONE; + + t_iJpegFd = open(JPEG_DEC_NODE, O_RDWR, 0); + + if (t_iJpegFd < 0) { + t_iJpegFd = -1; + JPEG_ERROR_LOG("[%s]: JPEG_DEC_NODE open failed", __func__); + return ERROR_CANNOT_OPEN_JPEG_DEVICE; + } + + if (t_iJpegFd <= 0) { + t_iJpegFd = -1; + JPEG_ERROR_LOG("ERR(%s):JPEG device was closed\n", __func__); + return ERROR_JPEG_DEVICE_ALREADY_CLOSED; + } + + iRet = t_v4l2Querycap(t_iJpegFd); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s]: QUERYCAP failed", __func__); + close(t_iJpegFd); + return ERROR_CANNOT_OPEN_JPEG_DEVICE; + } + + memset(&t_stJpegConfig, 0, sizeof(struct CONFIG)); + memset(&t_stJpegInbuf, 0, sizeof(struct BUFFER)); + memset(&t_stJpegOutbuf, 0, sizeof(struct BUFFER)); + + t_stJpegConfig.mode = MODE_DECODE; + + t_bFlagCreate = true; + t_bFlagCreateInBuf = false; + t_bFlagCreateOutBuf = false; + t_bFlagExcute = false; + + t_iPlaneNum = 0; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::destroy(void) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_ALREADY_DESTROY; + } + + if (t_iJpegFd > 0) { + struct BUF_INFO stBufInfo; + int iRet = ERROR_NONE; + + if (t_bFlagExcute) { + iRet = t_v4l2StreamOff(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + } + + if (t_bFlagExcute) { + stBufInfo.numOfPlanes = NUM_PLANES; + stBufInfo.memory = V4L2_MEMORY_MMAP; + + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + iRet = t_v4l2Reqbufs(t_iJpegFd, 0, &stBufInfo); + + stBufInfo.numOfPlanes = t_iPlaneNum; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + iRet = t_v4l2Reqbufs(t_iJpegFd, 0, &stBufInfo); + } + + iRet = close(t_iJpegFd); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: JPEG_DEC_NODE close failed", __func__, iRet); + } + } + + t_iJpegFd = -1; + t_bFlagCreate = false; + return ERROR_NONE; +} + +int SecJpegDecoderHal::setSize(int iW, int iH) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (iW < 0 || MAX_JPG_WIDTH < iW) { + return ERROR_INVALID_IMAGE_SIZE; + } + + if (iH < 0 || MAX_JPG_HEIGHT < iH) { + return ERROR_INVALID_IMAGE_SIZE; + } + + t_stJpegConfig.width = iW; + t_stJpegConfig.height = iH; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setJpegConfig(void *pConfig) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (pConfig == NULL) { + return ERROR_JPEG_CONFIG_POINTER_NULL; + } + + memcpy(&t_stJpegConfig, pConfig, sizeof(struct CONFIG)); + + if (t_stJpegConfig.pix.dec_fmt.out_fmt == V4L2_PIX_FMT_NV12) { + t_iPlaneNum = 2; + } else { + t_iPlaneNum = 1; + } + + return ERROR_NONE; +} + +void *SecJpegDecoderHal::getJpegConfig(void) +{ + if (t_bFlagCreate == false) { + return NULL; + } + + return &t_stJpegConfig; +} + +char *SecJpegDecoderHal::getInBuf(int *piInputSize) +{ + if (t_bFlagCreate == false) { + return NULL; + } + + if (t_bFlagCreateInBuf == false) { + + *piInputSize = 0; + return NULL; + } + + *piInputSize = t_stJpegInbuf.size[0]; + + return (char *)(t_stJpegInbuf.addr[0]); +} + +char **SecJpegDecoderHal::getOutBuf(int *piOutputSize) +{ + if (t_bFlagCreate == false) { + return NULL; + } + + if (t_bFlagCreateOutBuf == false) { + + *piOutputSize = 0; + return NULL; + } + + for (int i=0;i<t_iPlaneNum;i++) { + piOutputSize[i] = t_stJpegOutbuf.size[i]; + } + + return t_stJpegOutbuf.addr; +} + +int SecJpegDecoderHal::setInBuf(char *pcBuf, int iSize) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (pcBuf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (iSize<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + t_stJpegInbuf.addr[0] = pcBuf; + t_stJpegInbuf.size[0] = iSize; + t_stJpegInbuf.numOfPlanes = NUM_PLANES; + + t_bFlagCreateInBuf = true; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setOutBuf(char **pcBuf, int *iSize) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (pcBuf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (iSize<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + for(int i=0;i<t_iPlaneNum;i++) { + t_stJpegOutbuf.addr[i] = pcBuf[i]; + t_stJpegOutbuf.size[i] = iSize[i]; + } + + t_stJpegOutbuf.numOfPlanes = t_iPlaneNum; + + t_bFlagCreateOutBuf = true; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setCache(int iValue) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (t_v4l2SetCtrl(t_iJpegFd, V4L2_CID_CACHEABLE, iValue)<0) { + JPEG_ERROR_LOG("%s::cache setting failed\n", __func__); + return ERROR_CANNOT_CHANGE_CACHE_SETTING; + } + + return ERROR_NONE; +} + +int SecJpegDecoderHal::getSize(int *piW, int *piH) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + int iRet = t_v4l2GetFmt(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, &t_stJpegConfig); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s,%d]: get image size failed", __func__,iRet); + return ERROR_GET_SIZE_FAIL; + } + + *piW = t_stJpegConfig.width; + *piH = t_stJpegConfig.height; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setColorFormat(int iV4l2ColorFormat) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + switch(iV4l2ColorFormat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + t_stJpegConfig.pix.dec_fmt.out_fmt = iV4l2ColorFormat; + break; + default: + t_iPlaneNum = 0; + return ERROR_INVALID_COLOR_FORMAT; + break; + } + + if (iV4l2ColorFormat == V4L2_PIX_FMT_NV12) { + t_iPlaneNum = 2; + } else { + t_iPlaneNum = 1; + } + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setJpegFormat(int iV4l2JpegFormat) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + switch(iV4l2JpegFormat) { + case V4L2_PIX_FMT_JPEG_444: + case V4L2_PIX_FMT_JPEG_422: + case V4L2_PIX_FMT_JPEG_420: + case V4L2_PIX_FMT_JPEG_GRAY: + t_stJpegConfig.pix.dec_fmt.in_fmt = iV4l2JpegFormat; + break; + default: + return ERROR_INVALID_JPEG_FORMAT; + break; + } + + return ERROR_NONE; +} + +int SecJpegDecoderHal::updateConfig(void) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + int iRet = ERROR_NONE; + + t_stJpegConfig.numOfPlanes = NUM_PLANES; + + t_stJpegConfig.mode = MODE_DECODE; + + iRet = t_v4l2SetFmt(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, &t_stJpegConfig); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s,%d]: jpeg input S_FMT failed", __func__,iRet); + return ERROR_INVALID_JPEG_CONFIG; + } + + struct BUF_INFO stBufInfo; + + stBufInfo.numOfPlanes = NUM_PLANES; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + stBufInfo.memory = V4L2_MEMORY_USERPTR; + + iRet = t_v4l2Reqbufs(t_iJpegFd, NUM_BUFFERS, &stBufInfo); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Input REQBUFS failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + t_stJpegConfig.numOfPlanes = t_iPlaneNum; + iRet = t_v4l2SetFmt(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, &t_stJpegConfig); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s,%d]: jpeg output S_FMT failed", __func__,iRet); + return ERROR_INVALID_JPEG_CONFIG; + } + + stBufInfo.numOfPlanes = t_iPlaneNum; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + iRet = t_v4l2Reqbufs(t_iJpegFd, NUM_BUFFERS, &stBufInfo); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Output REQBUFS failed", __func__, iRet); + return ERROR_REQBUF_FAIL; + } + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setScaledSize(int iW, int iH) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (iW < 0 || MAX_JPG_WIDTH < iW) { + return ERROR_INVALID_IMAGE_SIZE; + } + + if (iH < 0 || MAX_JPG_HEIGHT < iH) { + return ERROR_INVALID_IMAGE_SIZE; + } + + t_stJpegConfig.scaled_width = iW; + t_stJpegConfig.scaled_height = iH; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::setJpegSize(int iJpegSize) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (iJpegSize<=0) { + return ERROR_JPEG_SIZE_TOO_SMALL; + } + + t_stJpegConfig.sizeJpeg = iJpegSize; + + return ERROR_NONE; +} + +int SecJpegDecoderHal::decode(void) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + struct BUF_INFO stBufInfo; + int iRet = ERROR_NONE; + + t_bFlagExcute = true; + + stBufInfo.numOfPlanes = NUM_PLANES; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + stBufInfo.memory = V4L2_MEMORY_USERPTR; + + iRet = t_v4l2Qbuf(t_iJpegFd, &stBufInfo, &t_stJpegInbuf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Input QBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + stBufInfo.numOfPlanes = t_iPlaneNum; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + iRet = t_v4l2Qbuf(t_iJpegFd, &stBufInfo, &t_stJpegOutbuf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Output QBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + stBufInfo.numOfPlanes = NUM_PLANES; + iRet = t_v4l2StreamOn(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: input stream on failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + stBufInfo.numOfPlanes = t_iPlaneNum; + iRet = t_v4l2StreamOn(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: output stream on failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + stBufInfo.numOfPlanes = NUM_PLANES; + iRet = t_v4l2Dqbuf(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_MEMORY_MMAP); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Intput DQBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + stBufInfo.numOfPlanes = t_iPlaneNum; + iRet = t_v4l2Dqbuf(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, V4L2_MEMORY_MMAP); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Output DQBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + return ERROR_NONE; +} + diff --git a/exynos5/hal/libhwjpeg/SecJpegEncoder.cpp b/exynos5/hal/libhwjpeg/SecJpegEncoder.cpp new file mode 100644 index 0000000..6c118e1 --- /dev/null +++ b/exynos5/hal/libhwjpeg/SecJpegEncoder.cpp @@ -0,0 +1,952 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * 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. + */ + +#include <utils/Log.h> + +#include "SecJpegEncoder.h" + +static const char ExifAsciiPrefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; + +#define JPEG_ERROR_LOG(fmt,...) + +#define JPEG_MAIN_DUMP (0) +#define JPEG_THUMB_DUMP (0) + +SecJpegEncoder::SecJpegEncoder() +{ + m_flagCreate = false; + m_jpegMain = NULL; + m_jpegThumb = NULL; + m_thumbnailW = 0; + m_thumbnailH = 0; + m_pThumbInputBuffer = NULL; + m_pThumbOutputBuffer = NULL; +#ifdef JPEG_WA_FOR_PAGEFAULT + m_pJpegInputBuffer = 0; + m_pExtInBuf = NULL; + m_iInBufSize = 0; +#endif // JPEG_WA_FOR_PAGEFAULT + m_ionJpegClient = 0;; + m_ionThumbInBuffer = 0; + m_ionThumbOutBuffer = 0; +#ifdef JPEG_WA_FOR_PAGEFAULT + m_ionJpegInBuffer = 0;; +#endif // JPEG_WA_FOR_PAGEFAULT +} + +SecJpegEncoder::~SecJpegEncoder() +{ + if (m_flagCreate == true) { + this->destroy(); + } +} + +bool SecJpegEncoder::flagCreate(void) +{ + return m_flagCreate; +} + +int SecJpegEncoder::create(void) +{ + int ret = ERROR_NONE; + if (m_flagCreate == true) { + return ERROR_ALREADY_CREATE; + } + + if (m_jpegMain == NULL) { + m_jpegMain = new SecJpegEncoderHal; + + if (m_jpegMain == NULL) { + JPEG_ERROR_LOG("ERR(%s):Cannot create SecJpegEncoderHal class\n", __func__); + return ERROR_CANNOT_CREATE_SEC_JPEG_ENC_HAL; + } + + ret = m_jpegMain->create(); + if (ret) { + return ret; + } + + ret = m_jpegMain->setCache(JPEG_CACHE_ON); + + if (ret) { + m_jpegMain->destroy(); + return ret; + } + } + + m_flagCreate = true; + + return ERROR_NONE; +} + +int SecJpegEncoder::destroy(void) +{ + if (m_flagCreate == false) { + return ERROR_ALREADY_DESTROY; + } + + if (m_jpegMain != NULL) { + m_jpegMain->destroy(); + delete m_jpegMain; + m_jpegMain = NULL; + } + + if (m_jpegThumb != NULL) { + int iSize = sizeof(char)*m_thumbnailW*m_thumbnailH*4; + +#ifdef JPEG_WA_FOR_PAGEFAULT + iSize += JPEG_WA_BUFFER_SIZE; + + freeJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, m_iInBufSize); +#endif //JPEG_WA_FOR_PAGEFAULT + + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iSize); + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iSize); + + if (m_ionJpegClient != 0) { + ion_client_destroy(m_ionJpegClient); + m_ionJpegClient = 0; + } + + m_jpegThumb->destroy(); + delete m_jpegThumb; + m_jpegThumb = NULL; + } + + m_flagCreate = false; + m_thumbnailW = 0; + m_thumbnailH = 0; + return ERROR_NONE; +} + +int SecJpegEncoder::setSize(int w, int h) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setSize(w, h); +} + + +int SecJpegEncoder::setQuality(int quality) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setQuality(quality); +} + +int SecJpegEncoder::setColorFormat(int colorFormat) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setColorFormat(colorFormat); +} + +int SecJpegEncoder::setJpegFormat(int jpegFormat) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->setJpegFormat(jpegFormat); +} + +int SecJpegEncoder::updateConfig(void) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + return m_jpegMain->updateConfig(); +} + +char *SecJpegEncoder::getInBuf(int *input_size) +{ + if (m_flagCreate == false) { + return NULL; + } + + int inSize = 0; + char *inBuf = *(m_jpegMain->getInBuf(&inSize)); + + if (inBuf == NULL) { + JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); + return NULL; + } + + *input_size = inSize; + + return inBuf; +} + +char *SecJpegEncoder::getOutBuf(int *output_size) +{ + if (m_flagCreate == false) { + return NULL; + } + + int outSize = 0; + char *outBuf = m_jpegMain->getOutBuf(&outSize); + + if (outBuf == NULL) { + JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); + return NULL; + } + + *output_size = outSize; + + return outBuf; +} + +int SecJpegEncoder::setInBuf(char *buf, int size) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + if (buf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (size<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + int ret = ERROR_NONE; + +#ifdef JPEG_WA_FOR_PAGEFAULT + size += JPEG_WA_BUFFER_SIZE; + + freeJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, size); + + if (m_ionJpegClient == 0) { + m_ionJpegClient = ion_client_create(); + if (m_ionJpegClient < 0) { + JPEG_ERROR_LOG("[%s]src ion client create failed, value = %d\n", __func__, size); + m_ionJpegClient = 0; + return ret; + } + } + + ret = allocJpegIonMemory(m_ionJpegClient, &m_ionJpegInBuffer, &m_pJpegInputBuffer, size); + if (ret != ERROR_NONE) { + return ret; + } + + ret = m_jpegMain->setInBuf(&m_pJpegInputBuffer, &size); + if (ret) { + JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); + return ret; + } + m_iInBufSize = size; + + m_pExtInBuf = buf; + +#else // NO JPEG_WA_FOR_PAGEFAULT + ret = m_jpegMain->setInBuf(&buf, &size); + if (ret) { + JPEG_ERROR_LOG("%s::Fail to JPEG input buffer!!\n", __func__); + return ret; + } +#endif // JPEG_WA_FOR_PAGEFAULT + + return ERROR_NONE; +} + +int SecJpegEncoder::setOutBuf(char *buf, int size) +{ + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + + if (buf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (size<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + int ret = ERROR_NONE; + ret = m_jpegMain->setOutBuf(buf, size); + if (ret) { + JPEG_ERROR_LOG("%s::Fail to JPEG output buffer!!\n", __func__); + return ret; + } + + return ERROR_NONE; +} + +int SecJpegEncoder::encode(int *size, exif_attribute_t *exifInfo) +{ + int ret = ERROR_NONE; + unsigned char *exifOut = NULL; + + if (m_flagCreate == false) { + return ERROR_NOT_YET_CREATED; + } + +#ifdef JPEG_WA_FOR_PAGEFAULT + memcpy(m_pJpegInputBuffer, m_pExtInBuf, m_iInBufSize-JPEG_WA_BUFFER_SIZE); +#endif // JPEG_WA_FOR_PAGEFAULT + + ret = m_jpegMain->encode(); + if (ret) { + JPEG_ERROR_LOG("encode failed\n"); + return ret; + } + + int iJpegSize = m_jpegMain->getJpegSize(); + + if (iJpegSize<=0) { + JPEG_ERROR_LOG("%s:: output_size is too small(%d)!!\n", __func__, iJpegSize); + return ERROR_OUT_BUFFER_SIZE_TOO_SMALL; + } + + int iOutputSize = 0; + char *pcJpegBuffer = m_jpegMain->getOutBuf(&iOutputSize); + + if (pcJpegBuffer == NULL) { + JPEG_ERROR_LOG("%s::buffer is null!!\n", __func__); + return ERROR_OUT_BUFFER_CREATE_FAIL; + } + + if (exifInfo != NULL) { + unsigned int thumbLen, exifLen; + + unsigned int bufSize = 0; + if (exifInfo->enableThumb) { + if (encodeThumbnail(&thumbLen)) { + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } else { + if (thumbLen > EXIF_LIMIT_SIZE) { + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } + else { + bufSize = EXIF_FILE_SIZE + thumbLen; + } + } + } else { + bufSize = EXIF_FILE_SIZE; + exifInfo->enableThumb = false; + } + + exifOut = new unsigned char[bufSize]; + if (exifOut == NULL) { + JPEG_ERROR_LOG("%s::Failed to allocate for exifOut", __func__); + delete[] exifOut; + return ERROR_EXIFOUT_ALLOC_FAIL; + } + memset(exifOut, 0, bufSize); + + if (makeExif (exifOut, exifInfo, &exifLen)) { + JPEG_ERROR_LOG("%s::Failed to make EXIF", __func__); + delete[] exifOut; + return ERROR_MAKE_EXIF_FAIL; + } + + if (exifLen <= EXIF_LIMIT_SIZE) { + memmove(pcJpegBuffer+exifLen+2, pcJpegBuffer+2, iJpegSize - 2); + memcpy(pcJpegBuffer+2, exifOut, exifLen); + iJpegSize += exifLen; + } + + delete[] exifOut; + } + + *size = iJpegSize; + + return ERROR_NONE; +} + +int SecJpegEncoder::makeExif (unsigned char *exifOut, + exif_attribute_t *exifInfo, + unsigned int *size, + bool useMainbufForThumb) +{ + unsigned char *pCur, *pApp1Start, *pIfdStart, *pGpsIfdPtr, *pNextIfdOffset; + unsigned int tmp, LongerTagOffest = 0, exifSizeExceptThumb; + pApp1Start = pCur = exifOut; + + //2 Exif Identifier Code & TIFF Header + pCur += 4; // Skip 4 Byte for APP1 marker and length + unsigned char ExifIdentifierCode[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + memcpy(pCur, ExifIdentifierCode, 6); + pCur += 6; + + /* Byte Order - little endian, Offset of IFD - 0x00000008.H */ + unsigned char TiffHeader[8] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; + memcpy(pCur, TiffHeader, 8); + pIfdStart = pCur; + pCur += 8; + + //2 0th IFD TIFF Tags + if (exifInfo->enableGps) + tmp = NUM_0TH_IFD_TIFF; + else + tmp = NUM_0TH_IFD_TIFF - 1; + + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += 8 + NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, + 1, exifInfo->width); + writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, + 1, exifInfo->height); + writeExifIfd(&pCur, EXIF_TAG_MAKE, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->maker) + 1, exifInfo->maker, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_MODEL, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->model) + 1, exifInfo->model, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + 1, exifInfo->orientation); + writeExifIfd(&pCur, EXIF_TAG_SOFTWARE, EXIF_TYPE_ASCII, + strlen((char *)exifInfo->software) + 1, exifInfo->software, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_YCBCR_POSITIONING, EXIF_TYPE_SHORT, + 1, exifInfo->ycbcr_positioning); + writeExifIfd(&pCur, EXIF_TAG_EXIF_IFD_POINTER, EXIF_TYPE_LONG, + 1, LongerTagOffest); + if (exifInfo->enableGps) { + pGpsIfdPtr = pCur; + pCur += IFD_SIZE; // Skip a ifd size for gps IFD pointer + } + + pNextIfdOffset = pCur; // Skip a offset size for next IFD offset + pCur += OFFSET_SIZE; + + //2 0th IFD Exif Private Tags + pCur = pIfdStart + LongerTagOffest; + + tmp = NUM_0TH_IFD_EXIF; + memcpy(pCur, &tmp , NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + NUM_0TH_IFD_EXIF*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_TIME, EXIF_TYPE_RATIONAL, + 1, &exifInfo->exposure_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_FNUMBER, EXIF_TYPE_RATIONAL, + 1, &exifInfo->fnumber, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_PROGRAM, EXIF_TYPE_SHORT, + 1, exifInfo->exposure_program); + writeExifIfd(&pCur, EXIF_TAG_ISO_SPEED_RATING, EXIF_TYPE_SHORT, + 1, exifInfo->iso_speed_rating); + writeExifIfd(&pCur, EXIF_TAG_EXIF_VERSION, EXIF_TYPE_UNDEFINED, + 4, exifInfo->exif_version); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_ORG, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_TYPE_ASCII, + 20, exifInfo->date_time, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_SHUTTER_SPEED, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->shutter_speed, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_APERTURE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->aperture, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_BRIGHTNESS, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->brightness, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_BIAS, EXIF_TYPE_SRATIONAL, + 1, (rational_t *)&exifInfo->exposure_bias, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_MAX_APERTURE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->max_aperture, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_METERING_MODE, EXIF_TYPE_SHORT, + 1, exifInfo->metering_mode); + writeExifIfd(&pCur, EXIF_TAG_FLASH, EXIF_TYPE_SHORT, + 1, exifInfo->flash); + writeExifIfd(&pCur, EXIF_TAG_FOCAL_LENGTH, EXIF_TYPE_RATIONAL, + 1, &exifInfo->focal_length, &LongerTagOffest, pIfdStart); + char code[8] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 }; + int commentsLen = strlen((char *)exifInfo->user_comment) + 1; + memmove(exifInfo->user_comment + sizeof(code), exifInfo->user_comment, commentsLen); + memcpy(exifInfo->user_comment, code, sizeof(code)); + writeExifIfd(&pCur, EXIF_TAG_USER_COMMENT, EXIF_TYPE_UNDEFINED, + commentsLen + sizeof(code), exifInfo->user_comment, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_COLOR_SPACE, EXIF_TYPE_SHORT, + 1, exifInfo->color_space); + writeExifIfd(&pCur, EXIF_TAG_PIXEL_X_DIMENSION, EXIF_TYPE_LONG, + 1, exifInfo->width); + writeExifIfd(&pCur, EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_TYPE_LONG, + 1, exifInfo->height); + writeExifIfd(&pCur, EXIF_TAG_EXPOSURE_MODE, EXIF_TYPE_LONG, + 1, exifInfo->exposure_mode); + writeExifIfd(&pCur, EXIF_TAG_WHITE_BALANCE, EXIF_TYPE_LONG, + 1, exifInfo->white_balance); + writeExifIfd(&pCur, EXIF_TAG_SCENCE_CAPTURE_TYPE, EXIF_TYPE_LONG, + 1, exifInfo->scene_capture_type); + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + + //2 0th IFD GPS Info Tags + if (exifInfo->enableGps) { + writeExifIfd(&pGpsIfdPtr, EXIF_TAG_GPS_IFD_POINTER, EXIF_TYPE_LONG, + 1, LongerTagOffest); // GPS IFD pointer skipped on 0th IFD + + pCur = pIfdStart + LongerTagOffest; + + if (exifInfo->gps_processing_method[0] == 0) { + // don't create GPS_PROCESSING_METHOD tag if there isn't any + tmp = NUM_0TH_IFD_GPS - 1; + } else { + tmp = NUM_0TH_IFD_GPS; + } + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + tmp*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_GPS_VERSION_ID, EXIF_TYPE_BYTE, + 4, exifInfo->gps_version_id); + writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE_REF, EXIF_TYPE_ASCII, + 2, exifInfo->gps_latitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_LATITUDE, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_latitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_TYPE_ASCII, + 2, exifInfo->gps_longitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_LONGITUDE, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_longitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_TYPE_BYTE, + 1, exifInfo->gps_altitude_ref); + writeExifIfd(&pCur, EXIF_TAG_GPS_ALTITUDE, EXIF_TYPE_RATIONAL, + 1, &exifInfo->gps_altitude, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_GPS_TIMESTAMP, EXIF_TYPE_RATIONAL, + 3, exifInfo->gps_timestamp, &LongerTagOffest, pIfdStart); + tmp = strlen((char*)exifInfo->gps_processing_method); + if (tmp > 0) { + if (tmp > 100) { + tmp = 100; + } + unsigned char tmp_buf[100+sizeof(ExifAsciiPrefix)]; + memcpy(tmp_buf, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)); + memcpy(&tmp_buf[sizeof(ExifAsciiPrefix)], exifInfo->gps_processing_method, tmp); + writeExifIfd(&pCur, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_TYPE_UNDEFINED, + tmp+sizeof(ExifAsciiPrefix), tmp_buf, &LongerTagOffest, pIfdStart); + } + writeExifIfd(&pCur, EXIF_TAG_GPS_DATESTAMP, EXIF_TYPE_ASCII, + 11, exifInfo->gps_datestamp, &LongerTagOffest, pIfdStart); + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + } + + //2 1th IFD TIFF Tags + char *thumbBuf = NULL; + unsigned int thumbSize = 0; + + if (useMainbufForThumb) { + if (m_jpegMain) { + thumbBuf = m_jpegMain->getOutBuf((int *)&thumbSize); + thumbSize = m_jpegMain->getJpegSize(); + } + } else { + if (m_jpegThumb) { + thumbBuf = m_jpegThumb->getOutBuf((int *)&thumbSize); + thumbSize = m_jpegThumb->getJpegSize(); + } + } + + if (exifInfo->enableThumb && (thumbBuf != NULL) && (thumbSize != 0)) { + exifSizeExceptThumb = tmp = LongerTagOffest; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + + pCur = pIfdStart + LongerTagOffest; + + tmp = NUM_1TH_IFD_TIFF; + memcpy(pCur, &tmp, NUM_SIZE); + pCur += NUM_SIZE; + + LongerTagOffest += NUM_SIZE + NUM_1TH_IFD_TIFF*IFD_SIZE + OFFSET_SIZE; + + writeExifIfd(&pCur, EXIF_TAG_IMAGE_WIDTH, EXIF_TYPE_LONG, + 1, exifInfo->widthThumb); + writeExifIfd(&pCur, EXIF_TAG_IMAGE_HEIGHT, EXIF_TYPE_LONG, + 1, exifInfo->heightThumb); + writeExifIfd(&pCur, EXIF_TAG_COMPRESSION_SCHEME, EXIF_TYPE_SHORT, + 1, exifInfo->compression_scheme); + writeExifIfd(&pCur, EXIF_TAG_ORIENTATION, EXIF_TYPE_SHORT, + 1, exifInfo->orientation); + writeExifIfd(&pCur, EXIF_TAG_X_RESOLUTION, EXIF_TYPE_RATIONAL, + 1, &exifInfo->x_resolution, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_Y_RESOLUTION, EXIF_TYPE_RATIONAL, + 1, &exifInfo->y_resolution, &LongerTagOffest, pIfdStart); + writeExifIfd(&pCur, EXIF_TAG_RESOLUTION_UNIT, EXIF_TYPE_SHORT, + 1, exifInfo->resolution_unit); + writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_TYPE_LONG, + 1, LongerTagOffest); + writeExifIfd(&pCur, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, EXIF_TYPE_LONG, + 1, thumbSize); + + tmp = 0; + memcpy(pCur, &tmp, OFFSET_SIZE); // next IFD offset + pCur += OFFSET_SIZE; + + memcpy(pIfdStart + LongerTagOffest, + thumbBuf, thumbSize); + LongerTagOffest += thumbSize; + if (LongerTagOffest > EXIF_LIMIT_SIZE) { + LongerTagOffest = exifSizeExceptThumb; + tmp = 0; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + } + } else { + tmp = 0; + memcpy(pNextIfdOffset, &tmp, OFFSET_SIZE); // NEXT IFD offset skipped on 0th IFD + } + + unsigned char App1Marker[2] = { 0xff, 0xe1 }; + memcpy(pApp1Start, App1Marker, 2); + pApp1Start += 2; + + *size = 10 + LongerTagOffest; + tmp = *size - 2; // APP1 Maker isn't counted + unsigned char size_mm[2] = {(tmp >> 8) & 0xFF, tmp & 0xFF}; + memcpy(pApp1Start, size_mm, 2); + + return ERROR_NONE; +} + +/* + * private member functions +*/ +inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned int value) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, &value, 4); + *pCur += 4; +} + +inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue) +{ + char buf[4] = { 0,}; + + memcpy(buf, pValue, count); + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, buf, 4); + *pCur += 4; +} + +inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + unsigned char *pValue, + unsigned int *offset, + unsigned char *start) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, offset, 4); + *pCur += 4; + memcpy(start + *offset, pValue, count); + *offset += count; +} + +inline void SecJpegEncoder::writeExifIfd(unsigned char **pCur, + unsigned short tag, + unsigned short type, + unsigned int count, + rational_t *pValue, + unsigned int *offset, + unsigned char *start) +{ + memcpy(*pCur, &tag, 2); + *pCur += 2; + memcpy(*pCur, &type, 2); + *pCur += 2; + memcpy(*pCur, &count, 4); + *pCur += 4; + memcpy(*pCur, offset, 4); + *pCur += 4; + memcpy(start + *offset, pValue, 8 * count); + *offset += 8 * count; +} + +int SecJpegEncoder::m_scaleDownYuv422(char *srcBuf, unsigned int srcW, unsigned int srcH, + char *dstBuf, unsigned int dstW, unsigned int dstH) +{ + int step_x, step_y; + int iXsrc, iXdst; + int x, y, src_y_start_pos, dst_pos, src_pos; + + if (dstW & 0x01 || dstH & 0x01) { + return ERROR_INVALID_SCALING_WIDTH_HEIGHT; + } + + step_x = srcW / dstW; + step_y = srcH / dstH; + + unsigned int srcWStride = srcW * 2; + unsigned int stepXStride = step_x * 2; + + dst_pos = 0; + for (unsigned int y = 0; y < dstH; y++) { + src_y_start_pos = srcWStride * step_y * y; + + for (unsigned int x = 0; x < dstW; x += 2) { + src_pos = src_y_start_pos + (stepXStride * x); + + dstBuf[dst_pos++] = srcBuf[src_pos ]; + dstBuf[dst_pos++] = srcBuf[src_pos + 1]; + dstBuf[dst_pos++] = srcBuf[src_pos + 2]; + dstBuf[dst_pos++] = srcBuf[src_pos + 3]; + } + } + + return ERROR_NONE; +} + +// thumbnail +int SecJpegEncoder::setThumbnailSize(int w, int h) +{ + if (m_flagCreate == false) { + return ERROR_CANNOT_CREATE_SEC_JPEG_ENC_HAL; + } + + if (w < 0 || MAX_JPG_WIDTH < w) { + return false; + } + + if (h < 0 || MAX_JPG_HEIGHT < h) { + return false; + } + + m_thumbnailW = w; + m_thumbnailH = h; + return ERROR_NONE; +} + + +int SecJpegEncoder::encodeThumbnail(unsigned int *size, bool useMain) +{ + int ret = ERROR_NONE; + + if (m_flagCreate == false) { + return ERROR_CANNOT_CREATE_SEC_JPEG_ENC_HAL; + } + + // create jpeg thumbnail class + if (m_jpegThumb == NULL) { + m_jpegThumb = new SecJpegEncoderHal; + + if (m_jpegThumb == NULL) { + JPEG_ERROR_LOG("ERR(%s):Cannot open a jpeg device file\n", __func__); + return ERROR_CANNOT_CREATE_SEC_THUMB; + } + } + + ret = m_jpegThumb->create(); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail create\n", __func__); + return ret; + } + + ret = m_jpegThumb->setCache(JPEG_CACHE_ON); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail cache set\n", __func__); + return ret; + } + + void *pConfig = m_jpegMain->getJpegConfig(); + if (pConfig == NULL) { + JPEG_ERROR_LOG("ERR(%s):Fail getJpegConfig\n", __func__); + return ERROR_BUFFR_IS_NULL; + } + + ret = m_jpegThumb->setJpegConfig(pConfig); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setJpegConfig\n", __func__); + return ret; + } + + ret = m_jpegThumb->setQuality(JPEG_THUMBNAIL_QUALITY); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setQuality\n", __func__); + return ret; + } + + ret = m_jpegThumb->setSize(m_thumbnailW, m_thumbnailH); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setSize\n", __func__); + return ret; + } + + int iThumbSize = sizeof(char)*m_thumbnailW*m_thumbnailH*4; +#ifdef JPEG_WA_FOR_PAGEFAULT + iThumbSize += JPEG_WA_BUFFER_SIZE; +#endif //JPEG_WA_FOR_PAGEFAULT + + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iThumbSize); + freeJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iThumbSize); + + if (m_ionJpegClient == 0) { + m_ionJpegClient = ion_client_create(); + if (m_ionJpegClient < 0) { + JPEG_ERROR_LOG("[%s]src ion client create failed, value = %d\n", __func__, m_ionJpegClient); + m_ionJpegClient = 0; + return ret; + } + } + + ret = allocJpegIonMemory(m_ionJpegClient, &m_ionThumbInBuffer, &m_pThumbInputBuffer, iThumbSize); + if (ret != ERROR_NONE) { + return ret; + } + + ret = m_jpegThumb->setInBuf(&m_pThumbInputBuffer, &iThumbSize); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setInBuf\n", __func__); + return ret; + } + + ret = allocJpegIonMemory(m_ionJpegClient, &m_ionThumbOutBuffer, &m_pThumbOutputBuffer, iThumbSize); + if (ret != ERROR_NONE) { + return ret; + } + + ret = m_jpegThumb->setOutBuf((char *)m_pThumbOutputBuffer, iThumbSize); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setOutBuf\n", __func__); + return ret; + } + + ret = m_jpegThumb->updateConfig(); + if (ret) { + JPEG_ERROR_LOG("update config failed\n"); + return ret; + } + + if (useMain) { + + int iW=0, iH=0; + int input_sizeMain=0, input_sizeThumb=0; + + ret = m_jpegMain->getSize(&iW, &iH); + if (ret) { + JPEG_ERROR_LOG("ERR(%s):Fail setJpegConfig\n", __func__); + return ret; + } + + ret = m_scaleDownYuv422(*(m_jpegMain->getInBuf(&input_sizeMain)), + iW, + iH, + *(m_jpegThumb->getInBuf(&input_sizeThumb)), + m_thumbnailW, + m_thumbnailH); + if (ret) { + JPEG_ERROR_LOG("%s::m_scaleDownYuv422(%d, %d, %d, %d) fail", __func__, iW, iH, m_thumbnailW, m_thumbnailH); + return ret; + } + } + else { + return ERROR_IMPLEMENT_NOT_YET; + } + + int outSizeThumb; + + ret = m_jpegThumb->encode(); + if (ret) { + JPEG_ERROR_LOG("encode failed\n"); + return ret; + } + + outSizeThumb = m_jpegThumb->getJpegSize(); + if (outSizeThumb<=0) { + JPEG_ERROR_LOG("jpeg size is too small\n"); + return ERROR_THUMB_JPEG_SIZE_TOO_SMALL; + } + + *size = (unsigned int)outSizeThumb; + + return ERROR_NONE; + +} + +int SecJpegEncoder::allocJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size) +{ + int ret = ERROR_NONE; + + if (ionClient == 0) { + JPEG_ERROR_LOG("[%s]ionClient is zero (%d)\n", __func__, ionClient); + return ERROR_BUFFR_IS_NULL; + } + + *ionBuffer = ion_alloc(ionClient, size, 0, ION_HEAP_SYSTEM_MASK); + if (*ionBuffer == -1) { + JPEG_ERROR_LOG("[%s]ion_alloc(%d) failed\n", __func__, size); + *ionBuffer = 0; + return ret; + } + + *buffer = (char *)ion_map(*ionBuffer, size, 0); + if (*buffer == MAP_FAILED) { + JPEG_ERROR_LOG("[%s]src ion map failed(%d)\n", __func__, size); + ion_free(*ionBuffer); + *ionBuffer = 0; + *buffer = NULL; + return ret; + } + + return ret; +} + +void SecJpegEncoder::freeJpegIonMemory(ion_client ionClient, ion_buffer *ionBuffer, char **buffer, int size) +{ + if (ionClient == 0) { + return; + } + + if (*buffer != NULL) { + ion_unmap(*buffer, size); + *buffer = NULL; + } + + if (*ionBuffer != 0) { + ion_free(*ionBuffer); + *ionBuffer = 0; + } +} + diff --git a/exynos5/hal/libhwjpeg/SecJpegEncoderHal.cpp b/exynos5/hal/libhwjpeg/SecJpegEncoderHal.cpp new file mode 100644 index 0000000..1a3deca --- /dev/null +++ b/exynos5/hal/libhwjpeg/SecJpegEncoderHal.cpp @@ -0,0 +1,497 @@ +/* + * Copyright Samsung Electronics Co.,LTD. + * Copyright (C) 2011 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/mman.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <math.h> +#include <sys/poll.h> + +#include <cutils/log.h> + +#include <utils/Log.h> + +#include "SecJpegCodecHal.h" + +#define JPEG_ERROR_LOG(fmt,...) + +#define NUM_PLANES (1) +#define NUM_BUFFERS (1) + +SecJpegEncoderHal::SecJpegEncoderHal() +{ + t_iJpegFd = -1; + t_bFlagCreate = false; +} + +SecJpegEncoderHal::~SecJpegEncoderHal() +{ + if (t_bFlagCreate == true) { + this->destroy(); + } +} + +int SecJpegEncoderHal::create(void) +{ + if (t_bFlagCreate == true) { + return ERROR_JPEG_DEVICE_ALREADY_CREATE; + } + + int iRet = ERROR_NONE; + + t_iJpegFd = open(JPEG_ENC_NODE, O_RDWR, 0); + + if (t_iJpegFd < 0) { + t_iJpegFd = -1; + JPEG_ERROR_LOG("[%s]: JPEG_ENC_NODE open failed", __func__); + return ERROR_CANNOT_OPEN_JPEG_DEVICE; + } + + if (t_iJpegFd <= 0) { + t_iJpegFd = -1; + JPEG_ERROR_LOG("ERR(%s):JPEG device was closed\n", __func__); + return ERROR_JPEG_DEVICE_ALREADY_CLOSED; + } + + iRet = t_v4l2Querycap(t_iJpegFd); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s]: QUERYCAP failed", __func__); + close(t_iJpegFd); + return ERROR_CANNOT_OPEN_JPEG_DEVICE; + } + + memset(&t_stJpegConfig, 0, sizeof(struct CONFIG)); + memset(&t_stJpegInbuf, 0, sizeof(struct BUFFER)); + memset(&t_stJpegOutbuf, 0, sizeof(struct BUFFER)); + + t_stJpegConfig.mode = MODE_ENCODE; + + t_bFlagCreate = true; + t_bFlagCreateInBuf = false; + t_bFlagCreateOutBuf = false; + t_bFlagExcute = false; + + t_iPlaneNum = 0; + + return ERROR_NONE; +} + +int SecJpegEncoderHal::destroy(void) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_ALREADY_DESTROY; + } + + if (t_iJpegFd > 0) { + struct BUF_INFO stBufInfo; + int iRet = ERROR_NONE; + + if (t_bFlagExcute) { + iRet = t_v4l2StreamOff(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + } + + if (t_bFlagExcute) { + stBufInfo.numOfPlanes = t_iPlaneNum; + stBufInfo.memory = V4L2_MEMORY_MMAP; + + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + iRet = t_v4l2Reqbufs(t_iJpegFd, 0, &stBufInfo); + + stBufInfo.numOfPlanes = NUM_PLANES; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + iRet = t_v4l2Reqbufs(t_iJpegFd, 0, &stBufInfo); + } + + iRet = close(t_iJpegFd); + } + + t_iJpegFd = -1; + t_bFlagCreate = false; + return ERROR_NONE; +} + +int SecJpegEncoderHal::setSize(int iW, int iH) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (iW < 0 || MAX_JPG_WIDTH < iW) { + return ERROR_INVALID_IMAGE_SIZE; + } + + if (iH < 0 || MAX_JPG_HEIGHT < iH) { + return ERROR_INVALID_IMAGE_SIZE; + } + + t_stJpegConfig.width = iW; + t_stJpegConfig.height = iH; + + return ERROR_NONE; +} + +int SecJpegEncoderHal::setJpegConfig(void *pConfig) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (pConfig == NULL) { + return ERROR_JPEG_CONFIG_POINTER_NULL; + } + + memcpy(&t_stJpegConfig, pConfig, sizeof(struct CONFIG)); + + if (t_stJpegConfig.pix.enc_fmt.in_fmt == V4L2_PIX_FMT_NV12) { + t_iPlaneNum = 2; + } else { + t_iPlaneNum = 1; + } + + return ERROR_NONE; +} + +void *SecJpegEncoderHal::getJpegConfig(void) +{ + if (t_bFlagCreate == false) { + return NULL; + } + + return &t_stJpegConfig; +} + +char **SecJpegEncoderHal::getInBuf(int *piInputSize) +{ + if (t_bFlagCreate == false) { + return NULL; + } + + if (t_bFlagCreateInBuf == false) { + + *piInputSize = 0; + return NULL; + } + + for (int i=0;i<t_iPlaneNum;i++) { + piInputSize[i] = t_stJpegInbuf.size[i]; + } + + return t_stJpegInbuf.addr; +} + +char *SecJpegEncoderHal::getOutBuf(int *piOutputSize) +{ + if (t_bFlagCreate == false) { + return NULL; + } + + if (t_bFlagCreateOutBuf == false) { + + *piOutputSize = 0; + return NULL; + } + + *piOutputSize = t_stJpegOutbuf.size[0]; + + return (char *)(t_stJpegOutbuf.addr[0]); +} + +int SecJpegEncoderHal::setInBuf(char **pcBuf, int *iSize) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (pcBuf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (iSize<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + for(int i=0;i<t_iPlaneNum;i++) { + t_stJpegInbuf.addr[i] = pcBuf[i]; + t_stJpegInbuf.size[i] = iSize[i]; + } + + t_stJpegInbuf.numOfPlanes = t_iPlaneNum; + + t_bFlagCreateInBuf = true; + + return ERROR_NONE; +} + +int SecJpegEncoderHal::setOutBuf(char *pcBuf, int iSize) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (pcBuf == NULL) { + return ERROR_BUFFR_IS_NULL; + } + + if (iSize<=0) { + return ERROR_BUFFER_TOO_SMALL; + } + + t_stJpegOutbuf.addr[0] = pcBuf; + t_stJpegOutbuf.size[0] = iSize; + t_stJpegOutbuf.numOfPlanes = NUM_PLANES; + + t_bFlagCreateOutBuf = true; + + return ERROR_NONE; +} + +int SecJpegEncoderHal::setCache(int iValue) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (t_v4l2SetCtrl(t_iJpegFd, V4L2_CID_CACHEABLE, iValue)<0) { + JPEG_ERROR_LOG("%s::cache setting failed\n", __func__); + return ERROR_CANNOT_CHANGE_CACHE_SETTING; + } + + return ERROR_NONE; +} + +int SecJpegEncoderHal::getSize(int *piW, int *piH) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (t_stJpegConfig.width == 0 && t_stJpegConfig.height == 0) { + return ERROR_SIZE_NOT_SET_YET; + } + + *piW = t_stJpegConfig.width; + *piH = t_stJpegConfig.height; + + return ERROR_NONE; +} + +int SecJpegEncoderHal::setColorFormat(int iV4l2ColorFormat) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + switch(iV4l2ColorFormat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + t_stJpegConfig.pix.enc_fmt.in_fmt = iV4l2ColorFormat; + break; + default: + t_iPlaneNum = 0; + return ERROR_INVALID_COLOR_FORMAT; + break; + } + + if (iV4l2ColorFormat == V4L2_PIX_FMT_NV12) { + t_iPlaneNum = 2; + } else { + t_iPlaneNum = 1; + } + + return ERROR_NONE; +} + +int SecJpegEncoderHal::setJpegFormat(int iV4l2JpegFormat) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + switch(iV4l2JpegFormat) { + case V4L2_PIX_FMT_JPEG_444: + case V4L2_PIX_FMT_JPEG_422: + case V4L2_PIX_FMT_JPEG_420: + case V4L2_PIX_FMT_JPEG_GRAY: + t_stJpegConfig.pix.enc_fmt.out_fmt = iV4l2JpegFormat; + break; + default: + return ERROR_INVALID_JPEG_FORMAT; + break; + } + + return ERROR_NONE; +} + +int SecJpegEncoderHal::updateConfig(void) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + int iRet = ERROR_NONE; + + iRet = t_v4l2SetJpegcomp(t_iJpegFd, t_stJpegConfig.enc_qual); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s,%d]: S_JPEGCOMP failed", __func__,iRet); + return ERROR_INVALID_JPEG_CONFIG; + } + + t_stJpegConfig.numOfPlanes = t_iPlaneNum; + + t_stJpegConfig.mode = MODE_ENCODE; + + iRet = t_v4l2SetFmt(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, &t_stJpegConfig); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s,%d]: jpeg input S_FMT failed", __func__,iRet); + return ERROR_INVALID_JPEG_CONFIG; + } + + struct BUF_INFO stBufInfo; + + stBufInfo.numOfPlanes = t_iPlaneNum; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + stBufInfo.memory = V4L2_MEMORY_USERPTR; + + iRet = t_v4l2Reqbufs(t_iJpegFd, NUM_BUFFERS, &stBufInfo); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Input REQBUFS failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + t_stJpegConfig.numOfPlanes = NUM_PLANES; + iRet = t_v4l2SetFmt(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, &t_stJpegConfig); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s,%d]: jpeg output S_FMT failed", __func__,iRet); + return ERROR_INVALID_JPEG_CONFIG; + } + + stBufInfo.numOfPlanes = NUM_PLANES; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + iRet = t_v4l2Reqbufs(t_iJpegFd, NUM_BUFFERS, &stBufInfo); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Output REQBUFS failed", __func__, iRet); + return ERROR_REQBUF_FAIL; + } + + return ERROR_NONE; +} + +int SecJpegEncoderHal::setQuality(int iV4l2Quality) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + if (iV4l2Quality >= 90) + t_stJpegConfig.enc_qual = QUALITY_LEVEL_1; + else if (iV4l2Quality >= 80) + t_stJpegConfig.enc_qual = QUALITY_LEVEL_2; + else if (iV4l2Quality >= 70) + t_stJpegConfig.enc_qual = QUALITY_LEVEL_3; + else + t_stJpegConfig.enc_qual = QUALITY_LEVEL_4; + + return ERROR_NONE; +} + +int SecJpegEncoderHal::getJpegSize(void) +{ + if (t_bFlagCreate == false) { + return 0; + } + + int iSize = t_v4l2GetCtrl(t_iJpegFd, V4L2_CID_CAM_JPEG_ENCODEDSIZE); + + if (iSize < 0) { + JPEG_ERROR_LOG("%s::Fail to JPEG output buffer!!\n", __func__); + return 0; + } + + return iSize; +} + +int SecJpegEncoderHal::encode(void) +{ + if (t_bFlagCreate == false) { + return ERROR_JPEG_DEVICE_NOT_CREATE_YET; + } + + struct BUF_INFO stBufInfo; + int iRet = ERROR_NONE; + + t_bFlagExcute = true; + + stBufInfo.numOfPlanes = t_iPlaneNum; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + stBufInfo.memory = V4L2_MEMORY_USERPTR; + + iRet = t_v4l2Qbuf(t_iJpegFd, &stBufInfo, &t_stJpegInbuf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Input QBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + stBufInfo.numOfPlanes = NUM_PLANES; + stBufInfo.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + iRet = t_v4l2Qbuf(t_iJpegFd, &stBufInfo, &t_stJpegOutbuf); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Output QBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + stBufInfo.numOfPlanes = t_iPlaneNum; + iRet = t_v4l2StreamOn(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: input stream on failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + stBufInfo.numOfPlanes = NUM_PLANES; + iRet = t_v4l2StreamOn(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: output stream on failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + + stBufInfo.numOfPlanes = t_iPlaneNum; + iRet = t_v4l2Dqbuf(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_MEMORY_MMAP); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Intput DQBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + stBufInfo.numOfPlanes = NUM_PLANES; + iRet = t_v4l2Dqbuf(t_iJpegFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, V4L2_MEMORY_MMAP); + if (iRet < 0) { + JPEG_ERROR_LOG("[%s:%d]: Output DQBUF failed", __func__, iRet); + return ERROR_EXCUTE_FAIL; + } + return ERROR_NONE; +} + |