/*
* Copyright (C) 2013 Paul Kocialkowski
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG_TAG "exynos_jpeg"
#include
#include "exynos_camera.h"
#ifdef EXYNOS_JPEG_HW
int exynos_jpeg_start(struct exynos_camera *exynos_camera,
struct exynos_jpeg *jpeg)
{
struct jpeg_config config;
struct jpeg_buf *buffer_in;
struct jpeg_buf *buffer_out;
camera_memory_t *memory = NULL;
#ifdef EXYNOS_ION
int memory_ion_fd = -1;
#endif
int address;
int fd = -1;
int rc;
if (exynos_camera == NULL || jpeg == NULL)
return -EINVAL;
ALOGD("%s()", __func__);
if (jpeg->enabled) {
ALOGE("Jpeg was already started");
return -1;
}
buffer_in = &jpeg->buffer_in;
buffer_out = &jpeg->buffer_out;
#ifdef EXYNOS_ION
jpeg->memory_in_ion_fd = -1;
jpeg->memory_out_ion_fd = -1;
#endif
fd = jpeghal_enc_init();
if (fd < 0) {
ALOGE("%s: Unable to init jpeg encoder", __func__);
goto error;
}
jpeg->fd = fd;
memset(&config, 0, sizeof(config));
config.mode = JPEG_ENCODE;
config.width = jpeg->width;
config.height = jpeg->height;
config.num_planes = 1;
config.pix.enc_fmt.in_fmt = jpeg->format;
config.pix.enc_fmt.out_fmt = V4L2_PIX_FMT_JPEG_420;
if (jpeg->quality >= 90)
config.enc_qual = QUALITY_LEVEL_1;
else if (jpeg->quality >= 80)
config.enc_qual = QUALITY_LEVEL_2;
else if (jpeg->quality >= 70)
config.enc_qual = QUALITY_LEVEL_3;
else
config.enc_qual = QUALITY_LEVEL_4;
rc = jpeghal_enc_setconfig(fd, &config);
if (rc < 0) {
ALOGE("%s: Unable to set jpeg config", __func__);
goto error;
}
rc = jpeghal_s_ctrl(fd, V4L2_CID_CACHEABLE, 1);
if (rc < 0) {
ALOGE("%s: Unable to set cacheable control", __func__);
goto error;
}
memset(buffer_in, 0, sizeof(struct jpeg_buf));
buffer_in->memory = V4L2_MEMORY_MMAP;
buffer_in->num_planes = 1;
memset(buffer_out, 0, sizeof(struct jpeg_buf));
buffer_out->memory = V4L2_MEMORY_MMAP;
buffer_out->num_planes = 1;
rc = jpeghal_set_inbuf(fd, buffer_in);
if (rc < 0) {
#ifdef EXYNOS_ION
// Input
buffer_in->memory = V4L2_MEMORY_USERPTR;
buffer_in->length[0] = exynos_camera_buffer_length(jpeg->width, jpeg->height, jpeg->format);
memory_ion_fd = exynos_ion_alloc(exynos_camera, buffer_in->length[0]);
if (memory_ion_fd < 0) {
ALOGE("%s: Unable to alloc input ION memory", __func__);
goto error;
}
address = exynos_ion_phys(exynos_camera, memory_ion_fd);
if (EXYNOS_CAMERA_CALLBACK_DEFINED(request_memory)) {
memory = exynos_camera->callbacks.request_memory(memory_ion_fd, buffer_in->length[0], 1, exynos_camera->callbacks.user);
if (memory == NULL || memory->data == NULL || memory->data == MAP_FAILED) {
ALOGE("%s: Unable to request memory", __func__);
goto error;
}
} else {
ALOGE("%s: No memory request function!", __func__);
goto error;
}
jpeg->memory_in = memory;
jpeg->memory_in_pointer = memory->data;
jpeg->memory_in_ion_fd = memory_ion_fd;
buffer_in->start[0] = (void *) address;
rc = jpeghal_set_inbuf(fd, buffer_in);
if (rc < 0) {
ALOGE("%s: Unable to set input buffer", __func__);
goto error;
}
// Output
buffer_out->memory = V4L2_MEMORY_USERPTR;
buffer_out->length[0] = jpeg->width * jpeg->height * 4;
memory_ion_fd = exynos_ion_alloc(exynos_camera, buffer_out->length[0]);
if (memory_ion_fd < 0) {
ALOGE("%s: Unable to alloc output ION memory", __func__);
goto error;
}
address = exynos_ion_phys(exynos_camera, memory_ion_fd);
if (EXYNOS_CAMERA_CALLBACK_DEFINED(request_memory)) {
memory = exynos_camera->callbacks.request_memory(memory_ion_fd, buffer_out->length[0], 1, exynos_camera->callbacks.user);
if (memory == NULL || memory->data == NULL || memory->data == MAP_FAILED) {
ALOGE("%s: Unable to request memory", __func__);
goto error;
}
} else {
ALOGE("%s: No memory request function!", __func__);
goto error;
}
jpeg->memory_out = memory;
jpeg->memory_out_pointer = memory->data;
jpeg->memory_out_ion_fd = memory_ion_fd;
buffer_out->start[0] = (void *) address;
#else
ALOGE("%s: Unable to set input buffer", __func__);
goto error;
#endif
} else {
jpeg->memory_in_pointer = buffer_in->start[0];
jpeg->memory_out_pointer = buffer_out->start[0];
}
rc = jpeghal_set_outbuf(fd, buffer_out);
if (rc < 0) {
ALOGE("%s: Unable to set output buffer", __func__);
goto error;
}
jpeg->enabled = 1;
rc = 0;
goto complete;
error:
if (fd >= 0) {
// Avoid releasing unrequested mmap buffers
if (buffer_in->memory == 0)
buffer_in->memory = V4L2_MEMORY_USERPTR;
if (buffer_out->memory == 0)
buffer_out->memory = V4L2_MEMORY_USERPTR;
jpeghal_deinit(fd, buffer_in, buffer_out);
jpeg->fd = -1;
}
if (jpeg->memory_in != NULL && jpeg->memory_in->release != NULL) {
jpeg->memory_in->release(jpeg->memory_in);
jpeg->memory_in = NULL;
#ifdef EXYNOS_ION
if (jpeg->memory_in_ion_fd >= 0) {
exynos_ion_free(exynos_camera, jpeg->memory_in_ion_fd);
jpeg->memory_in_ion_fd = -1;
}
#endif
}
if (jpeg->memory_out != NULL && jpeg->memory_out->release != NULL) {
jpeg->memory_out->release(jpeg->memory_out);
jpeg->memory_out = NULL;
#ifdef EXYNOS_ION
if (jpeg->memory_out_ion_fd >= 0) {
exynos_ion_free(exynos_camera, jpeg->memory_out_ion_fd);
jpeg->memory_out_ion_fd = -1;
}
#endif
}
rc = -1;
complete:
return rc;
}
void exynos_jpeg_stop(struct exynos_camera *exynos_camera,
struct exynos_jpeg *jpeg)
{
struct jpeg_buf *buffer_in;
struct jpeg_buf *buffer_out;
int fd = -1;
int rc;
if (exynos_camera == NULL || jpeg == NULL)
return;
ALOGD("%s()", __func__);
if (!jpeg->enabled) {
ALOGE("Jpeg was already stopped");
return;
}
buffer_in = &jpeg->buffer_in;
buffer_out = &jpeg->buffer_out;
fd = jpeg->fd;
if (fd >= 0) {
jpeghal_deinit(fd, buffer_in, buffer_out);
jpeg->fd = -1;
}
if (jpeg->memory_in != NULL && jpeg->memory_in->release != NULL) {
jpeg->memory_in->release(jpeg->memory_in);
jpeg->memory_in = NULL;
#ifdef EXYNOS_ION
if (jpeg->memory_in_ion_fd >= 0) {
exynos_ion_free(exynos_camera, jpeg->memory_in_ion_fd);
jpeg->memory_in_ion_fd = -1;
}
#endif
}
if (jpeg->memory_out != NULL && jpeg->memory_out->release != NULL) {
jpeg->memory_out->release(jpeg->memory_out);
jpeg->memory_out = NULL;
#ifdef EXYNOS_ION
if (jpeg->memory_out_ion_fd >= 0) {
exynos_ion_free(exynos_camera, jpeg->memory_out_ion_fd);
jpeg->memory_out_ion_fd = -1;
}
#endif
}
jpeg->enabled = 0;
}
int exynos_jpeg(struct exynos_camera *exynos_camera, struct exynos_jpeg *jpeg)
{
struct jpeg_buf *buffer_in;
struct jpeg_buf *buffer_out;
int memory_size;
int fd = -1;
int rc;
if (exynos_camera == NULL || jpeg == NULL)
return -EINVAL;
ALOGD("%s()", __func__);
if (!jpeg->enabled) {
ALOGE("Jpeg was not started");
return -1;
}
buffer_in = &jpeg->buffer_in;
buffer_out = &jpeg->buffer_out;
fd = jpeg->fd;
if (fd < 0) {
ALOGE("%s: Invalid jpeg fd", __func__);
goto error;
}
#ifdef EXYNOS_ION
if (jpeg->memory_in != NULL && jpeg->memory_in_ion_fd >= 0) {
rc = exynos_ion_msync(exynos_camera, jpeg->memory_in_ion_fd, 0, buffer_in->length[0]);
if (rc < 0) {
ALOGE("%s: Unable to sync ION memory", __func__);
goto error;
}
}
#endif
rc = jpeghal_enc_exe(fd, buffer_in, buffer_out);
if (rc < 0) {
ALOGE("%s: Unable to encode jpeg", __func__);
goto error;
}
memory_size = jpeghal_g_ctrl(fd, V4L2_CID_CAM_JPEG_ENCODEDSIZE);
if (memory_size <= 0) {
ALOGE("%s: Unable to get jpeg size", __func__);
goto error;
}
jpeg->memory_out_size = memory_size;
#ifdef EXYNOS_ION
if (jpeg->memory_out != NULL && jpeg->memory_out_ion_fd >= 0) {
rc = exynos_ion_msync(exynos_camera, jpeg->memory_out_ion_fd, 0, memory_size);
if (rc < 0) {
ALOGE("%s: Unable to sync ION memory", __func__);
goto error;
}
}
#endif
rc = 0;
goto complete;
error:
if (fd >= 0) {
// Avoid releasing unrequested mmap buffers
if (buffer_in->memory == 0)
buffer_in->memory = V4L2_MEMORY_USERPTR;
if (buffer_out->memory == 0)
buffer_out->memory = V4L2_MEMORY_USERPTR;
jpeghal_deinit(fd, buffer_in, buffer_out);
jpeg->fd = -1;
}
if (jpeg->memory_in != NULL && jpeg->memory_in->release != NULL) {
jpeg->memory_in->release(jpeg->memory_in);
jpeg->memory_in = NULL;
#ifdef EXYNOS_ION
if (jpeg->memory_in_ion_fd >= 0) {
exynos_ion_free(exynos_camera, jpeg->memory_in_ion_fd);
jpeg->memory_in_ion_fd = -1;
}
#endif
}
if (jpeg->memory_out != NULL && jpeg->memory_out->release != NULL) {
jpeg->memory_out->release(jpeg->memory_out);
jpeg->memory_out = NULL;
#ifdef EXYNOS_ION
if (jpeg->memory_out_ion_fd >= 0) {
exynos_ion_free(exynos_camera, jpeg->memory_out_ion_fd);
jpeg->memory_out_ion_fd = -1;
}
#endif
}
rc = -1;
complete:
return rc;
}
#endif