/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ // Camera dependencies #include "mm_qcamera_app.h" #include "mm_qcamera_dbg.h" /* This callback is received once the complete JPEG encoding is done */ static void jpeg_encode_cb(jpeg_job_status_t status, uint32_t client_hdl, uint32_t jobId, mm_jpeg_output_t *p_buf, void *userData) { uint32_t i = 0; mm_camera_test_obj_t *pme = NULL; LOGD(" BEGIN\n"); pme = (mm_camera_test_obj_t *)userData; if (pme->jpeg_hdl != client_hdl || jobId != pme->current_job_id || !pme->current_job_frames) { LOGE(" NULL current job frames or not matching job ID (%d, %d)", jobId, pme->current_job_id); return; } /* dump jpeg img */ LOGE(" job %d, status=%d", jobId, status); if (status == JPEG_JOB_STATUS_DONE && p_buf != NULL) { mm_app_dump_jpeg_frame(p_buf->buf_vaddr, p_buf->buf_filled_len, "jpeg", "jpg", jobId); } /* buf done current encoding frames */ pme->current_job_id = 0; for (i = 0; i < pme->current_job_frames->num_bufs; i++) { if (MM_CAMERA_OK != pme->cam->ops->qbuf(pme->current_job_frames->camera_handle, pme->current_job_frames->ch_id, pme->current_job_frames->bufs[i])) { LOGE(" Failed in Qbuf\n"); } mm_app_cache_ops((mm_camera_app_meminfo_t *) pme->current_job_frames->bufs[i]->mem_info, ION_IOC_INV_CACHES); } free(pme->jpeg_buf.buf.buffer); free(pme->current_job_frames); pme->current_job_frames = NULL; /* signal snapshot is done */ mm_camera_app_done(); } int encodeData(mm_camera_test_obj_t *test_obj, mm_camera_super_buf_t* recvd_frame, mm_camera_stream_t *m_stream) { cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer); int rc = -MM_CAMERA_E_GENERAL; mm_jpeg_job_t job; /* remember current frames being encoded */ test_obj->current_job_frames = (mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t)); if (!test_obj->current_job_frames) { LOGE(" No memory for current_job_frames"); return rc; } *(test_obj->current_job_frames) = *recvd_frame; memset(&job, 0, sizeof(job)); job.job_type = JPEG_JOB_TYPE_ENCODE; job.encode_job.session_id = test_obj->current_jpeg_sess_id; // TODO: Rotation should be set according to // sensor&device orientation job.encode_job.rotation = 0; if (cam_cap->position == CAM_POSITION_BACK) { job.encode_job.rotation = 270; } /* fill in main src img encode param */ job.encode_job.main_dim.src_dim = m_stream->s_config.stream_info->dim; job.encode_job.main_dim.dst_dim = m_stream->s_config.stream_info->dim; job.encode_job.src_index = 0; job.encode_job.thumb_dim.src_dim = m_stream->s_config.stream_info->dim; job.encode_job.thumb_dim.dst_dim.width = DEFAULT_PREVIEW_WIDTH; job.encode_job.thumb_dim.dst_dim.height = DEFAULT_PREVIEW_HEIGHT; /* fill in sink img param */ job.encode_job.dst_index = 0; if (test_obj->metadata != NULL) { job.encode_job.p_metadata = test_obj->metadata; } else { LOGE(" Metadata null, not set for jpeg encoding"); } rc = test_obj->jpeg_ops.start_job(&job, &test_obj->current_job_id); if ( 0 != rc ) { free(test_obj->current_job_frames); test_obj->current_job_frames = NULL; } return rc; } int createEncodingSession(mm_camera_test_obj_t *test_obj, mm_camera_stream_t *m_stream, mm_camera_buf_def_t *m_frame) { mm_jpeg_encode_params_t encode_param; memset(&encode_param, 0, sizeof(mm_jpeg_encode_params_t)); encode_param.jpeg_cb = jpeg_encode_cb; encode_param.userdata = (void*)test_obj; encode_param.encode_thumbnail = 0; encode_param.quality = 85; encode_param.color_format = MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; encode_param.thumb_color_format = MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; /* fill in main src img encode param */ encode_param.num_src_bufs = 1; encode_param.src_main_buf[0].index = 0; encode_param.src_main_buf[0].buf_size = m_frame->frame_len; encode_param.src_main_buf[0].buf_vaddr = (uint8_t *)m_frame->buffer; encode_param.src_main_buf[0].fd = m_frame->fd; encode_param.src_main_buf[0].format = MM_JPEG_FMT_YUV; encode_param.src_main_buf[0].offset = m_stream->offset; /* fill in sink img param */ encode_param.num_dst_bufs = 1; encode_param.dest_buf[0].index = 0; encode_param.dest_buf[0].buf_size = test_obj->jpeg_buf.buf.frame_len; encode_param.dest_buf[0].buf_vaddr = (uint8_t *)test_obj->jpeg_buf.buf.buffer; encode_param.dest_buf[0].fd = test_obj->jpeg_buf.buf.fd; encode_param.dest_buf[0].format = MM_JPEG_FMT_YUV; /* main dimension */ encode_param.main_dim.src_dim = m_stream->s_config.stream_info->dim; encode_param.main_dim.dst_dim = m_stream->s_config.stream_info->dim; return test_obj->jpeg_ops.create_session(test_obj->jpeg_hdl, &encode_param, &test_obj->current_jpeg_sess_id); } /** mm_app_snapshot_metadata_notify_cb * @bufs: Pointer to super buffer * @user_data: Pointer to user data * * **/ __unused static void mm_app_snapshot_metadata_notify_cb(mm_camera_super_buf_t *bufs, void *user_data) { uint32_t i = 0; mm_camera_channel_t *channel = NULL; mm_camera_stream_t *p_stream = NULL; mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data; mm_camera_buf_def_t *frame; metadata_buffer_t *pMetadata; if (NULL == bufs || NULL == user_data) { LOGE(" bufs or user_data are not valid "); return; } frame = bufs->bufs[0]; /* find channel */ for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) { if (pme->channels[i].ch_id == bufs->ch_id) { channel = &pme->channels[i]; break; } } if (NULL == channel) { LOGE(" Channel object is null"); return; } /* find meta stream */ for (i = 0; i < channel->num_streams; i++) { if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_METADATA) { p_stream = &channel->streams[i]; break; } } if (NULL == p_stream) { LOGE(" cannot find metadata stream"); return; } /* find meta frame */ for (i = 0; i < bufs->num_bufs; i++) { if (bufs->bufs[i]->stream_id == p_stream->s_id) { frame = bufs->bufs[i]; break; } } if (!pme->metadata) { /* The app will free the metadata, we don't need to bother here */ pme->metadata = malloc(sizeof(metadata_buffer_t)); if (NULL == pme->metadata) { LOGE(" malloc failed"); return; } } memcpy(pme->metadata , frame->buffer, sizeof(metadata_buffer_t)); pMetadata = (metadata_buffer_t *)frame->buffer; IF_META_AVAILABLE(cam_auto_focus_data_t, focus_data, CAM_INTF_META_AUTOFOCUS_DATA, pMetadata) { if (focus_data->focus_state == CAM_AF_STATE_FOCUSED_LOCKED) { LOGE(" AutoFocus Done Call Back Received\n"); mm_camera_app_done(); } else if (focus_data->focus_state == CAM_AF_STATE_NOT_FOCUSED_LOCKED) { LOGE(" AutoFocus failed\n"); mm_camera_app_done(); } } if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle, bufs->ch_id, frame)) { LOGE(" Failed in Preview Qbuf\n"); } mm_app_cache_ops((mm_camera_app_meminfo_t *)frame->mem_info, ION_IOC_INV_CACHES); } static void mm_app_snapshot_notify_cb_raw(mm_camera_super_buf_t *bufs, void *user_data) { int rc; uint32_t i = 0; mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data; mm_camera_channel_t *channel = NULL; mm_camera_stream_t *m_stream = NULL; mm_camera_buf_def_t *m_frame = NULL; LOGD(" BEGIN\n"); /* find channel */ for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) { if (pme->channels[i].ch_id == bufs->ch_id) { channel = &pme->channels[i]; break; } } if (NULL == channel) { LOGE(" Wrong channel id (%d)", bufs->ch_id); rc = -1; goto EXIT; } /* find snapshot stream */ for (i = 0; i < channel->num_streams; i++) { if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_RAW) { m_stream = &channel->streams[i]; break; } } if (NULL == m_stream) { LOGE(" cannot find snapshot stream"); rc = -1; goto EXIT; } /* find snapshot frame */ for (i = 0; i < bufs->num_bufs; i++) { if (bufs->bufs[i]->stream_id == m_stream->s_id) { m_frame = bufs->bufs[i]; break; } } if (NULL == m_frame) { LOGE(" main frame is NULL"); rc = -1; goto EXIT; } mm_app_dump_frame(m_frame, "main", "raw", m_frame->frame_idx); EXIT: for (i=0; i<bufs->num_bufs; i++) { if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle, bufs->ch_id, bufs->bufs[i])) { LOGE(" Failed in Qbuf\n"); } } mm_camera_app_done(); LOGD(" END\n"); } static void mm_app_snapshot_notify_cb(mm_camera_super_buf_t *bufs, void *user_data) { int rc = 0; uint32_t i = 0; mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data; mm_camera_channel_t *channel = NULL; mm_camera_stream_t *p_stream = NULL; mm_camera_stream_t *m_stream = NULL; mm_camera_buf_def_t *p_frame = NULL; mm_camera_buf_def_t *m_frame = NULL; /* find channel */ for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) { if (pme->channels[i].ch_id == bufs->ch_id) { channel = &pme->channels[i]; break; } } if (NULL == channel) { LOGE(" Wrong channel id (%d)", bufs->ch_id); rc = -1; goto error; } /* find snapshot stream */ for (i = 0; i < channel->num_streams; i++) { if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_SNAPSHOT) { m_stream = &channel->streams[i]; break; } } if (NULL == m_stream) { LOGE(" cannot find snapshot stream"); rc = -1; goto error; } /* find snapshot frame */ for (i = 0; i < bufs->num_bufs; i++) { if (bufs->bufs[i]->stream_id == m_stream->s_id) { m_frame = bufs->bufs[i]; break; } } if (NULL == m_frame) { LOGE(" main frame is NULL"); rc = -1; goto error; } mm_app_dump_frame(m_frame, "main", "yuv", m_frame->frame_idx); /* find postview stream */ for (i = 0; i < channel->num_streams; i++) { if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_POSTVIEW) { p_stream = &channel->streams[i]; break; } } if (NULL != p_stream) { /* find preview frame */ for (i = 0; i < bufs->num_bufs; i++) { if (bufs->bufs[i]->stream_id == p_stream->s_id) { p_frame = bufs->bufs[i]; break; } } if (NULL != p_frame) { mm_app_dump_frame(p_frame, "postview", "yuv", p_frame->frame_idx); } } mm_app_cache_ops((mm_camera_app_meminfo_t *)m_frame->mem_info, ION_IOC_CLEAN_INV_CACHES); pme->jpeg_buf.buf.buffer = (uint8_t *)malloc(m_frame->frame_len); if ( NULL == pme->jpeg_buf.buf.buffer ) { LOGE(" error allocating jpeg output buffer"); goto error; } pme->jpeg_buf.buf.frame_len = m_frame->frame_len; /* create a new jpeg encoding session */ rc = createEncodingSession(pme, m_stream, m_frame); if (0 != rc) { LOGE(" error creating jpeg session"); free(pme->jpeg_buf.buf.buffer); goto error; } /* start jpeg encoding job */ rc = encodeData(pme, bufs, m_stream); if (0 != rc) { LOGE(" error creating jpeg session"); free(pme->jpeg_buf.buf.buffer); goto error; } error: /* buf done rcvd frames in error case */ if ( 0 != rc ) { for (i=0; i<bufs->num_bufs; i++) { if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle, bufs->ch_id, bufs->bufs[i])) { LOGE(" Failed in Qbuf\n"); } mm_app_cache_ops((mm_camera_app_meminfo_t *)bufs->bufs[i]->mem_info, ION_IOC_INV_CACHES); } } LOGD(" END\n"); } mm_camera_channel_t * mm_app_add_snapshot_channel(mm_camera_test_obj_t *test_obj) { mm_camera_channel_t *channel = NULL; mm_camera_stream_t *stream = NULL; channel = mm_app_add_channel(test_obj, MM_CHANNEL_TYPE_SNAPSHOT, NULL, NULL, NULL); if (NULL == channel) { LOGE(" add channel failed"); return NULL; } stream = mm_app_add_snapshot_stream(test_obj, channel, mm_app_snapshot_notify_cb, (void *)test_obj, 1, 1); if (NULL == stream) { LOGE(" add snapshot stream failed\n"); mm_app_del_channel(test_obj, channel); return NULL; } return channel; } mm_camera_stream_t * mm_app_add_postview_stream(mm_camera_test_obj_t *test_obj, mm_camera_channel_t *channel, mm_camera_buf_notify_t stream_cb, void *userdata, uint8_t num_bufs, uint8_t num_burst) { int rc = MM_CAMERA_OK; mm_camera_stream_t *stream = NULL; cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer); stream = mm_app_add_stream(test_obj, channel); if (NULL == stream) { LOGE(" add stream failed\n"); return NULL; } stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf; stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf; stream->s_config.mem_vtbl.clean_invalidate_buf = mm_app_stream_clean_invalidate_buf; stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf; stream->s_config.mem_vtbl.user_data = (void *)stream; stream->s_config.stream_cb = stream_cb; stream->s_config.stream_cb_sync = NULL; stream->s_config.userdata = userdata; stream->num_of_bufs = num_bufs; stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer; memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t)); stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_POSTVIEW; if (num_burst == 0) { stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; } else { stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_BURST; stream->s_config.stream_info->num_of_burst = num_burst; } stream->s_config.stream_info->fmt = DEFAULT_PREVIEW_FORMAT; stream->s_config.stream_info->dim.width = DEFAULT_PREVIEW_WIDTH; stream->s_config.stream_info->dim.height = DEFAULT_PREVIEW_HEIGHT; stream->s_config.padding_info = cam_cap->padding_info; rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config); if (MM_CAMERA_OK != rc) { LOGE("config postview stream err=%d\n", rc); return NULL; } return stream; } int mm_app_start_capture_raw(mm_camera_test_obj_t *test_obj, uint8_t num_snapshots) { int32_t rc = MM_CAMERA_OK; mm_camera_channel_t *channel = NULL; mm_camera_stream_t *s_main = NULL; mm_camera_channel_attr_t attr; memset(&attr, 0, sizeof(mm_camera_channel_attr_t)); attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_BURST; attr.max_unmatched_frames = 3; channel = mm_app_add_channel(test_obj, MM_CHANNEL_TYPE_CAPTURE, &attr, mm_app_snapshot_notify_cb_raw, test_obj); if (NULL == channel) { LOGE(" add channel failed"); return -MM_CAMERA_E_GENERAL; } test_obj->buffer_format = DEFAULT_RAW_FORMAT; s_main = mm_app_add_raw_stream(test_obj, channel, mm_app_snapshot_notify_cb_raw, test_obj, num_snapshots, num_snapshots); if (NULL == s_main) { LOGE(" add main snapshot stream failed\n"); mm_app_del_channel(test_obj, channel); return rc; } rc = mm_app_start_channel(test_obj, channel); if (MM_CAMERA_OK != rc) { LOGE("start zsl failed rc=%d\n", rc); mm_app_del_stream(test_obj, channel, s_main); mm_app_del_channel(test_obj, channel); return rc; } return rc; } int mm_app_stop_capture_raw(mm_camera_test_obj_t *test_obj) { int rc = MM_CAMERA_OK; mm_camera_channel_t *ch = NULL; int i; cam_stream_size_info_t abc ; memset (&abc , 0, sizeof (cam_stream_size_info_t)); ch = mm_app_get_channel_by_type(test_obj, MM_CHANNEL_TYPE_CAPTURE); rc = mm_app_stop_channel(test_obj, ch); if (MM_CAMERA_OK != rc) { LOGE("stop recording failed rc=%d\n", rc); } for ( i = 0 ; i < ch->num_streams ; i++ ) { mm_app_del_stream(test_obj, ch, &ch->streams[i]); } rc = setmetainfoCommand(test_obj, &abc); if (rc != MM_CAMERA_OK) { LOGE(" meta info command failed\n"); } mm_app_del_channel(test_obj, ch); return rc; } int mm_app_start_capture(mm_camera_test_obj_t *test_obj, uint8_t num_snapshots) { int32_t rc = MM_CAMERA_OK; mm_camera_channel_t *channel = NULL; mm_camera_stream_t *s_main = NULL; mm_camera_stream_t *s_post = NULL; mm_camera_channel_attr_t attr; memset(&attr, 0, sizeof(mm_camera_channel_attr_t)); attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS; attr.max_unmatched_frames = 3; channel = mm_app_add_channel(test_obj, MM_CHANNEL_TYPE_CAPTURE, &attr, mm_app_snapshot_notify_cb, test_obj); if (NULL == channel) { LOGE(" add channel failed"); return -MM_CAMERA_E_GENERAL; } s_main = mm_app_add_snapshot_stream(test_obj, channel, mm_app_snapshot_notify_cb, (void *)test_obj, CAPTURE_BUF_NUM, num_snapshots); if (NULL == s_main) { LOGE(" add main snapshot stream failed\n"); mm_app_del_channel(test_obj, channel); return rc; } s_post = mm_app_add_postview_stream(test_obj, channel, NULL, NULL, CAPTURE_BUF_NUM, num_snapshots); if (NULL == s_main) { LOGE(" add main postview stream failed\n"); mm_app_del_channel(test_obj, channel); return rc; } rc = mm_app_start_channel(test_obj, channel); if (MM_CAMERA_OK != rc) { LOGE("start zsl failed rc=%d\n", rc); mm_app_del_stream(test_obj, channel, s_main); mm_app_del_channel(test_obj, channel); return rc; } return rc; } int mm_app_stop_capture(mm_camera_test_obj_t *test_obj) { int rc = MM_CAMERA_OK; mm_camera_channel_t *ch = NULL; ch = mm_app_get_channel_by_type(test_obj, MM_CHANNEL_TYPE_CAPTURE); rc = mm_app_stop_and_del_channel(test_obj, ch); if (MM_CAMERA_OK != rc) { LOGE("stop capture channel failed rc=%d\n", rc); } return rc; } int mm_app_take_picture(mm_camera_test_obj_t *test_obj, uint8_t is_burst_mode) { LOGH("\nEnter %s!!\n"); int rc = MM_CAMERA_OK; uint8_t num_snapshot = 1; int num_rcvd_snapshot = 0; if (is_burst_mode) num_snapshot = 6; //stop preview before starting capture. rc = mm_app_stop_preview(test_obj); if (rc != MM_CAMERA_OK) { LOGE(" stop preview failed before capture!!, err=%d\n", rc); return rc; } rc = mm_app_start_capture(test_obj, num_snapshot); if (rc != MM_CAMERA_OK) { LOGE(" mm_app_start_capture(), err=%d\n", rc); return rc; } while (num_rcvd_snapshot < num_snapshot) { LOGH("\nWaiting mm_camera_app_wait !!\n"); mm_camera_app_wait(); num_rcvd_snapshot++; } rc = mm_app_stop_capture(test_obj); if (rc != MM_CAMERA_OK) { LOGE(" mm_app_stop_capture(), err=%d\n", rc); return rc; } //start preview after capture. rc = mm_app_start_preview(test_obj); if (rc != MM_CAMERA_OK) { LOGE(" start preview failed after capture!!, err=%d\n",rc); } return rc; }