codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 1 | /* |
| 2 | ** |
| 3 | ** Copyright 2008, The Android Open Source Project |
| 4 | ** Copyright 2010, Samsung Electronics Co. LTD |
| 5 | ** |
| 6 | ** Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | ** you may not use this file except in compliance with the License. |
| 8 | ** You may obtain a copy of the License at |
| 9 | ** |
| 10 | ** http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | ** |
| 12 | ** Unless required by applicable law or agreed to in writing, software |
| 13 | ** distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | ** See the License for the specific language governing permissions and |
| 16 | ** limitations under the License. |
| 17 | */ |
| 18 | |
Daniel Hillenbrand | 353fecb | 2012-07-22 16:14:08 +0200 | [diff] [blame] | 19 | //#define LOG_NDEBUG 0 |
| 20 | #define LOG_TAG "Jpeg-api" |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 21 | |
| 22 | #include <utils/Log.h> |
| 23 | #include <stdio.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <sys/types.h> |
| 26 | #include <sys/stat.h> |
| 27 | #include <sys/ioctl.h> |
| 28 | #include <fcntl.h> |
| 29 | #include <ctype.h> |
| 30 | #include <unistd.h> |
| 31 | #include <sys/mman.h> |
| 32 | #include <string.h> |
| 33 | #include <errno.h> |
| 34 | #include <sys/time.h> |
| 35 | #include <signal.h> |
| 36 | #include <math.h> |
| 37 | #include <sys/poll.h> |
| 38 | |
| 39 | #ifdef S5P_VMEM |
| 40 | #include "s5p_vmem_api.h" |
| 41 | #endif |
| 42 | #include "jpeg_api.h" |
| 43 | |
| 44 | static struct jpeg_lib *jpeg_ctx = NULL; |
| 45 | #ifdef S5P_VMEM |
| 46 | static int mem_fp; |
| 47 | unsigned int cookie; |
| 48 | #endif /* S5P_VMEM */ |
| 49 | |
| 50 | static unsigned int get_yuv_size(enum jpeg_frame_format out_format, |
| 51 | unsigned int width, unsigned int height) |
| 52 | { |
| 53 | switch (out_format) { |
| 54 | case YUV_422 : |
| 55 | if (width % 16 != 0) |
| 56 | width += 16 - (width % 16); |
| 57 | if (height % 8 != 0) |
| 58 | height += 8 - (height % 8); |
| 59 | break; |
| 60 | |
| 61 | case YUV_420 : |
| 62 | if (width % 16 != 0) |
| 63 | width += 16 - (width % 16); |
| 64 | if (height % 16 != 0) |
| 65 | height += 16 - (height % 16); |
| 66 | break; |
| 67 | |
| 68 | default: |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 69 | ALOGV("get_yuv_size return fmt(%d)\n", out_format); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 70 | return(0); |
| 71 | } |
| 72 | |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 73 | ALOGV("get_yuv_size width(%d) height(%d)\n", width, height); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 74 | |
| 75 | switch (out_format) { |
| 76 | case YUV_422 : |
| 77 | return(width*height*2); |
| 78 | case YUV_420 : |
| 79 | return((width*height) + (width*height >> 1)); |
| 80 | default : |
| 81 | return(0); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | static int check_input_size(unsigned int width, unsigned int height) |
| 86 | { |
| 87 | if ((width % 16) != 0 || (height % 8) != 0) |
| 88 | return -1; |
| 89 | |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | static void init_decode_param(void) |
| 94 | { |
| 95 | jpeg_ctx = (struct jpeg_lib *)malloc(sizeof(struct jpeg_lib)); |
| 96 | memset(jpeg_ctx, 0x00, sizeof(struct jpeg_lib)); |
| 97 | |
| 98 | jpeg_ctx->args.dec_param = (struct jpeg_dec_param *)malloc(sizeof(struct jpeg_dec_param)); |
| 99 | memset(jpeg_ctx->args.dec_param, 0x00, sizeof(struct jpeg_dec_param)); |
| 100 | } |
| 101 | |
| 102 | static void init_encode_param(void) |
| 103 | { |
| 104 | jpeg_ctx = (struct jpeg_lib *)malloc(sizeof(struct jpeg_lib)); |
| 105 | memset(jpeg_ctx, 0x00, sizeof(struct jpeg_lib)); |
| 106 | |
| 107 | jpeg_ctx->args.enc_param = (struct jpeg_enc_param *)malloc(sizeof(struct jpeg_enc_param)); |
| 108 | memset(jpeg_ctx->args.enc_param, 0x00, sizeof(struct jpeg_enc_param)); |
| 109 | } |
| 110 | |
| 111 | int api_jpeg_decode_init() |
| 112 | { |
| 113 | init_decode_param(); |
| 114 | jpeg_ctx->jpeg_fd = open(JPEG_DRIVER_NAME, O_RDWR); |
| 115 | |
| 116 | if (jpeg_ctx->jpeg_fd < 0) { |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 117 | ALOGE("JPEG driver open failed\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 118 | return -1; |
| 119 | } |
| 120 | |
| 121 | #ifdef S5P_VMEM |
| 122 | mem_fp = s5p_vmem_open(); |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 123 | ALOGV("s5p_vmem_open\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 124 | #else |
| 125 | jpeg_ctx->args.mmapped_addr = (char *) mmap(0, |
| 126 | JPEG_TOTAL_BUF_SIZE, |
| 127 | PROT_READ | PROT_WRITE, |
| 128 | MAP_SHARED, |
| 129 | jpeg_ctx->jpeg_fd, 0); |
| 130 | |
| 131 | if (jpeg_ctx->args.mmapped_addr == NULL) { |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 132 | ALOGE("JPEG mmap failed\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 133 | return -1; |
| 134 | } |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 135 | ALOGV("api_jpeg_decode_init jpeg_ctx->args.mmapped_addr 0x%08x\n", |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 136 | jpeg_ctx->args.mmapped_addr); |
| 137 | #endif /* S5P_VMEM */ |
| 138 | |
| 139 | return jpeg_ctx->jpeg_fd; |
| 140 | } |
| 141 | |
| 142 | int api_jpeg_encode_init() |
| 143 | { |
| 144 | init_encode_param(); |
| 145 | jpeg_ctx->jpeg_fd = open(JPEG_DRIVER_NAME, O_RDWR); |
| 146 | |
| 147 | if (jpeg_ctx->jpeg_fd < 0) { |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 148 | ALOGE("JPEG driver open failed %d\n", jpeg_ctx->jpeg_fd); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 149 | return -1; |
| 150 | } |
| 151 | |
| 152 | #ifdef S5P_VMEM |
| 153 | mem_fp = s5p_vmem_open(); |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 154 | ALOGI("s5p_vmem_open\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 155 | #else |
| 156 | |
| 157 | jpeg_ctx->args.mmapped_addr = (char *) mmap(0, |
| 158 | JPEG_TOTAL_BUF_SIZE, |
| 159 | PROT_READ | PROT_WRITE, |
| 160 | MAP_SHARED, |
| 161 | jpeg_ctx->jpeg_fd, 0); |
| 162 | |
| 163 | if (jpeg_ctx->args.mmapped_addr == NULL) { |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 164 | ALOGE("JPEG mmap failed\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 165 | return -1; |
| 166 | } |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 167 | ALOGV("api_jpeg_encode_init jpeg_ctx->args.mmapped_addr 0x%08x\n", |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 168 | jpeg_ctx->args.mmapped_addr); |
| 169 | #endif /* S5P_VMEM */ |
| 170 | return jpeg_ctx->jpeg_fd; |
| 171 | } |
| 172 | |
| 173 | int api_jpeg_decode_deinit(int dev_fd) |
| 174 | { |
| 175 | if (jpeg_ctx->args.mmapped_addr != NULL) |
| 176 | munmap(jpeg_ctx->args.mmapped_addr, JPEG_TOTAL_BUF_SIZE); |
| 177 | |
| 178 | #ifdef S5P_VMEM |
| 179 | s5p_free_share(mem_fp, jpeg_ctx->args.in_cookie, jpeg_ctx->args.in_buf); |
| 180 | s5p_free_share(mem_fp, jpeg_ctx->args.out_cookie, jpeg_ctx->args.out_buf); |
| 181 | s5p_vmem_close(mem_fp); |
| 182 | #endif |
| 183 | |
| 184 | close(jpeg_ctx->jpeg_fd); |
| 185 | |
| 186 | if (jpeg_ctx->args.dec_param != NULL) |
| 187 | free(jpeg_ctx->args.dec_param); |
| 188 | |
| 189 | free(jpeg_ctx); |
| 190 | |
| 191 | return JPEG_OK; |
| 192 | } |
| 193 | |
| 194 | int api_jpeg_encode_deinit(int dev_fd) |
| 195 | { |
| 196 | if (jpeg_ctx->args.mmapped_addr != NULL) |
| 197 | munmap(jpeg_ctx->args.mmapped_addr, JPEG_TOTAL_BUF_SIZE); |
| 198 | |
| 199 | #ifdef S5P_VMEM |
| 200 | s5p_free_share(mem_fp, jpeg_ctx->args.in_cookie, jpeg_ctx->args.in_buf); |
| 201 | s5p_free_share(mem_fp, jpeg_ctx->args.out_cookie, jpeg_ctx->args.out_buf); |
| 202 | s5p_vmem_close(mem_fp); |
| 203 | #endif |
| 204 | close(jpeg_ctx->jpeg_fd); |
| 205 | |
| 206 | if (jpeg_ctx->args.enc_param != NULL) |
| 207 | free(jpeg_ctx->args.enc_param); |
| 208 | |
| 209 | free(jpeg_ctx); |
| 210 | |
| 211 | return JPEG_OK; |
| 212 | } |
| 213 | |
| 214 | void *api_jpeg_get_decode_in_buf(int dev_fd, unsigned int size) |
| 215 | { |
| 216 | if (size < 0 || size > MAX_JPEG_RES) { |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 217 | ALOGE("Invalid decode input buffer size\r\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 218 | return NULL; |
| 219 | } |
| 220 | #ifdef S5P_VMEM |
| 221 | jpeg_ctx->args.in_cookie = (unsigned int)ioctl(jpeg_ctx->jpeg_fd, |
| 222 | IOCTL_GET_DEC_IN_BUF, size); |
| 223 | jpeg_ctx->args.in_buf = s5p_malloc_share(mem_fp, |
| 224 | jpeg_ctx->args.in_cookie, |
| 225 | &jpeg_ctx->args.in_buf_size); |
| 226 | #else |
| 227 | jpeg_ctx->args.in_buf = (char *)ioctl(jpeg_ctx->jpeg_fd, |
| 228 | IOCTL_GET_DEC_IN_BUF, |
| 229 | jpeg_ctx->args.mmapped_addr); |
| 230 | #endif /* S5P_VMEM */ |
| 231 | return (void *)(jpeg_ctx->args.in_buf); |
| 232 | } |
| 233 | |
| 234 | void *api_jpeg_get_encode_in_buf(int dev_fd, unsigned int size) |
| 235 | { |
| 236 | #ifdef S5P_VMEM |
| 237 | jpeg_ctx->args.in_cookie = (unsigned int)ioctl(jpeg_ctx->jpeg_fd, |
| 238 | IOCTL_GET_ENC_IN_BUF, (size*3)); |
| 239 | jpeg_ctx->args.in_buf = s5p_malloc_share(mem_fp, |
| 240 | jpeg_ctx->args.in_cookie, |
| 241 | &jpeg_ctx->args.in_buf_size); |
| 242 | #else |
| 243 | jpeg_ctx->args.enc_param->size = size; |
| 244 | jpeg_ctx->args.in_buf = (char *)ioctl(jpeg_ctx->jpeg_fd, |
| 245 | IOCTL_GET_ENC_IN_BUF, |
| 246 | jpeg_ctx->args.mmapped_addr); |
| 247 | #endif |
| 248 | |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 249 | ALOGV("api_jpeg_get_encode_in_buf: 0x%x\n", |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 250 | jpeg_ctx->args.in_buf); |
| 251 | |
| 252 | return (void *)(jpeg_ctx->args.in_buf); |
| 253 | } |
| 254 | |
| 255 | void *api_jpeg_get_decode_out_buf(int dev_fd) |
| 256 | { |
| 257 | #ifdef S5P_VMEM |
| 258 | jpeg_ctx->args.out_cookie = (unsigned int)ioctl(jpeg_ctx->jpeg_fd, |
| 259 | IOCTL_GET_DEC_OUT_BUF, JPEG_FRAME_BUF_SIZE); |
| 260 | jpeg_ctx->args.out_buf = s5p_malloc_share(mem_fp, |
| 261 | jpeg_ctx->args.out_cookie, |
| 262 | &jpeg_ctx->args.out_buf_size); |
| 263 | #else |
| 264 | jpeg_ctx->args.out_buf = (char *)ioctl(jpeg_ctx->jpeg_fd, |
| 265 | IOCTL_GET_DEC_OUT_BUF, |
| 266 | jpeg_ctx->args.mmapped_addr); |
| 267 | #endif /* S5P_VMEM */ |
| 268 | /* |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 269 | ALOGV("api_jpeg_get_decode_out_buf: 0x%x\n", |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 270 | jpeg_ctx->args.out_buf); |
| 271 | */ |
| 272 | return (void *)(jpeg_ctx->args.out_buf); |
| 273 | } |
| 274 | |
| 275 | void *api_jpeg_get_encode_out_buf(int dev_fd) |
| 276 | { |
| 277 | #ifdef S5P_VMEM |
| 278 | jpeg_ctx->args.out_cookie = (unsigned int)ioctl(jpeg_ctx->jpeg_fd, |
| 279 | IOCTL_GET_ENC_OUT_BUF, JPEG_STREAM_BUF_SIZE); |
| 280 | jpeg_ctx->args.out_buf = s5p_malloc_share(mem_fp, |
| 281 | jpeg_ctx->args.out_cookie, |
| 282 | &jpeg_ctx->args.out_buf_size); |
| 283 | #else |
| 284 | jpeg_ctx->args.out_buf = (char *)ioctl(jpeg_ctx->jpeg_fd, |
| 285 | IOCTL_GET_ENC_OUT_BUF, |
| 286 | jpeg_ctx->args.mmapped_addr); |
| 287 | #endif /* S5P_VMEM */ |
| 288 | |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 289 | ALOGV("api_jpeg_get_encode_out_buf: 0x%x\n", |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 290 | jpeg_ctx->args.out_buf); |
| 291 | |
| 292 | return (void *)(jpeg_ctx->args.out_buf); |
| 293 | } |
| 294 | |
| 295 | void api_jpeg_set_decode_param(struct jpeg_dec_param *param) |
| 296 | { |
| 297 | memcpy(jpeg_ctx->args.dec_param, param, sizeof(struct jpeg_dec_param)); |
| 298 | ioctl(jpeg_ctx->jpeg_fd, IOCTL_SET_DEC_PARAM, jpeg_ctx->args.dec_param); |
| 299 | } |
| 300 | |
| 301 | void api_jpeg_set_encode_param(struct jpeg_enc_param *param) |
| 302 | { |
| 303 | memcpy(jpeg_ctx->args.enc_param, param, sizeof(struct jpeg_enc_param)); |
| 304 | ioctl(jpeg_ctx->jpeg_fd, IOCTL_SET_ENC_PARAM, jpeg_ctx->args.enc_param); |
| 305 | } |
| 306 | |
| 307 | enum jpeg_ret_type api_jpeg_decode_exe(int dev_fd, |
| 308 | struct jpeg_dec_param *dec_param) |
| 309 | { |
| 310 | struct jpeg_args *arg; |
| 311 | |
| 312 | arg = &(jpeg_ctx->args); |
| 313 | |
| 314 | ioctl(jpeg_ctx->jpeg_fd, IOCTL_JPEG_DEC_EXE, arg->dec_param); |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 315 | ALOGV("api_jpeg_decode_exe dec_param->out_fmt :%d \ |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 316 | dec_param->width : %d dec_param->height : %d\n", |
| 317 | arg->dec_param->out_fmt, |
| 318 | arg->dec_param->width, |
| 319 | arg->dec_param->height); |
| 320 | dec_param->width = arg->dec_param->width; |
| 321 | dec_param->height = arg->dec_param->height; |
| 322 | dec_param->size = get_yuv_size(arg->dec_param->out_fmt, |
| 323 | arg->dec_param->width, |
| 324 | arg->dec_param->height); |
| 325 | |
| 326 | return JPEG_DECODE_OK; |
| 327 | } |
| 328 | |
| 329 | enum jpeg_ret_type api_jpeg_encode_exe(int dev_fd, |
| 330 | struct jpeg_enc_param *enc_param) |
| 331 | { |
| 332 | struct jpeg_args *arg; |
| 333 | arg = &(jpeg_ctx->args); |
| 334 | |
| 335 | // check MCU validation width & height & sampling mode |
| 336 | if (check_input_size(jpeg_ctx->args.enc_param->width, |
| 337 | jpeg_ctx->args.enc_param->height) < 0) { |
Daniel Hillenbrand | 0fdadca | 2012-07-22 15:45:33 +0200 | [diff] [blame] | 338 | ALOGV("width/height doesn't match with MCU\r\n"); |
codeworkx | f1be2fe | 2012-03-24 17:38:29 +0100 | [diff] [blame] | 339 | return JPEG_FAIL; |
| 340 | } |
| 341 | |
| 342 | ioctl(jpeg_ctx->jpeg_fd, IOCTL_JPEG_ENC_EXE, arg->enc_param); |
| 343 | |
| 344 | enc_param->size = arg->enc_param->size; |
| 345 | |
| 346 | return JPEG_ENCODE_OK; |
| 347 | } |