mm_qcamera_snapshot.c revision 6591d7fc4818d50ce096e781b14deda6903dbe57
1/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include "mm_qcamera_dbg.h"
31#include "mm_qcamera_app.h"
32
33/* This callback is received once the complete JPEG encoding is done */
34static void jpeg_encode_cb(jpeg_job_status_t status,
35                           uint32_t client_hdl,
36                           uint32_t jobId,
37                           mm_jpeg_output_t *p_buf,
38                           void *userData)
39{
40    int i = 0;
41    mm_camera_test_obj_t *pme = NULL;
42    CDBG("%s: BEGIN\n", __func__);
43
44    pme = (mm_camera_test_obj_t *)userData;
45    if (pme->jpeg_hdl != client_hdl ||
46        jobId != pme->current_job_id ||
47        !pme->current_job_frames) {
48        CDBG_ERROR("%s: NULL current job frames or not matching job ID (%d, %d)",
49                   __func__, jobId, pme->current_job_id);
50        return;
51    }
52
53    /* dump jpeg img */
54    CDBG_ERROR("%s: job %d, status=%d", __func__, jobId, status);
55    if (status == JPEG_JOB_STATUS_DONE && p_buf != NULL) {
56        mm_app_dump_jpeg_frame(p_buf->buf_vaddr, p_buf->buf_filled_len, "jpeg_dump", "jpg", jobId);
57    }
58
59    /* buf done current encoding frames */
60    pme->current_job_id = 0;
61    for (i = 0; i < pme->current_job_frames->num_bufs; i++) {
62        if (MM_CAMERA_OK != pme->cam->ops->qbuf(pme->current_job_frames->camera_handle,
63                                                pme->current_job_frames->ch_id,
64                                                pme->current_job_frames->bufs[i])) {
65            CDBG_ERROR("%s: Failed in Qbuf\n", __func__);
66        }
67    }
68    free(pme->current_job_frames);
69    pme->current_job_frames = NULL;
70
71    /* signal snapshot is done */
72    mm_camera_app_done();
73}
74
75int encodeData(mm_camera_test_obj_t *test_obj, mm_camera_super_buf_t* recvd_frame,
76               mm_camera_stream_t *m_stream)
77{
78    cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
79
80    int rc = -MM_CAMERA_E_GENERAL;
81    mm_jpeg_job_t job;
82
83    /* remember current frames being encoded */
84    test_obj->current_job_frames =
85        (mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t));
86    if (!test_obj->current_job_frames) {
87        CDBG_ERROR("%s: No memory for current_job_frames", __func__);
88        return rc;
89    }
90    *(test_obj->current_job_frames) = *recvd_frame;
91
92    memset(&job, 0, sizeof(job));
93    job.job_type = JPEG_JOB_TYPE_ENCODE;
94    job.encode_job.session_id = test_obj->current_jpeg_sess_id;
95
96    job.encode_job.rotation = 0;
97    if (cam_cap->position == CAM_POSITION_BACK) {
98        /* back camera, rotate 90 */
99        job.encode_job.rotation = 90;
100    }
101
102    /* fill in main src img encode param */
103    job.encode_job.main_dim.src_dim = m_stream->s_config.stream_info->dim;
104    job.encode_job.main_dim.dst_dim = m_stream->s_config.stream_info->dim;
105    job.encode_job.src_index = 0;
106
107    job.encode_job.thumb_dim.src_dim = m_stream->s_config.stream_info->dim;
108    job.encode_job.thumb_dim.dst_dim.width = DEFAULT_PREVIEW_WIDTH;
109    job.encode_job.thumb_dim.dst_dim.height = DEFAULT_PREVIEW_HEIGHT;
110
111    /* fill in sink img param */
112    job.encode_job.dst_index = 0;
113
114    rc = test_obj->jpeg_ops.start_job(&job, &test_obj->current_job_id);
115    if ( 0 != rc ) {
116        free(test_obj->current_job_frames);
117        test_obj->current_job_frames = NULL;
118    }
119
120    return rc;
121}
122
123int createEncodingSession(mm_camera_test_obj_t *test_obj,
124                          mm_camera_stream_t *m_stream,
125                          mm_camera_buf_def_t *m_frame)
126{
127    mm_jpeg_encode_params_t encode_param;
128
129    memset(&encode_param, 0, sizeof(mm_jpeg_encode_params_t));
130    encode_param.jpeg_cb = jpeg_encode_cb;
131    encode_param.userdata = (void*)test_obj;
132    encode_param.encode_thumbnail = 1;
133    encode_param.quality = 85;
134    encode_param.color_format = MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2;
135
136    /* fill in main src img encode param */
137    encode_param.num_src_bufs = 1;
138    encode_param.src_main_buf[0].index = 0;
139    encode_param.src_main_buf[0].buf_size = m_frame->frame_len;
140    encode_param.src_main_buf[0].buf_vaddr = (uint8_t *)m_frame->buffer;
141    encode_param.src_main_buf[0].fd = m_frame->fd;
142    encode_param.src_main_buf[0].format = MM_JPEG_FMT_YUV;
143    encode_param.src_main_buf[0].offset = m_stream->offset;
144
145    /* fill in sink img param */
146    encode_param.num_dst_bufs = 1;
147    encode_param.dest_buf[0].index = 0;
148    encode_param.dest_buf[0].buf_size = test_obj->jpeg_buf.buf.frame_len;
149    encode_param.dest_buf[0].buf_vaddr = (uint8_t *)test_obj->jpeg_buf.buf.buffer;
150    encode_param.dest_buf[0].fd = test_obj->jpeg_buf.buf.fd;
151    encode_param.dest_buf[0].format = MM_JPEG_FMT_YUV;
152
153    return test_obj->jpeg_ops.create_session(test_obj->jpeg_hdl,
154                                             &encode_param,
155                                             &test_obj->current_jpeg_sess_id);
156}
157
158static void mm_app_snapshot_notify_cb(mm_camera_super_buf_t *bufs,
159                                      void *user_data)
160{
161
162    int rc;
163    int i = 0;
164    mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data;
165    mm_camera_channel_t *channel = NULL;
166    mm_camera_stream_t *p_stream = NULL;
167    mm_camera_stream_t *m_stream = NULL;
168    mm_camera_buf_def_t *p_frame = NULL;
169    mm_camera_buf_def_t *m_frame = NULL;
170
171    CDBG("%s: BEGIN\n", __func__);
172
173    /* find channel */
174    for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) {
175        if (pme->channels[i].ch_id == bufs->ch_id) {
176            channel = &pme->channels[i];
177            break;
178        }
179    }
180    if (NULL == channel) {
181        CDBG_ERROR("%s: Wrong channel id (%d)", __func__, bufs->ch_id);
182        rc = -1;
183        goto error;
184    }
185
186    /* find snapshot stream */
187    for (i = 0; i < channel->num_streams; i++) {
188        if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_SNAPSHOT) {
189            m_stream = &channel->streams[i];
190            break;
191        }
192    }
193    if (NULL == m_stream) {
194        CDBG_ERROR("%s: cannot find snapshot stream", __func__);
195        rc = -1;
196        goto error;
197    }
198
199    /* find snapshot frame */
200    for (i = 0; i < bufs->num_bufs; i++) {
201        if (bufs->bufs[i]->stream_id == m_stream->s_id) {
202            m_frame = bufs->bufs[i];
203            break;
204        }
205    }
206    if (NULL == m_frame) {
207        CDBG_ERROR("%s: main frame is NULL", __func__);
208        rc = -1;
209        goto error;
210    }
211
212    mm_app_dump_frame(m_frame, "main", "yuv", m_frame->frame_idx);
213
214    /* find postview stream */
215    for (i = 0; i < channel->num_streams; i++) {
216        if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_POSTVIEW) {
217            p_stream = &channel->streams[i];
218            break;
219        }
220    }
221    if (NULL != p_stream) {
222        /* find preview frame */
223        for (i = 0; i < bufs->num_bufs; i++) {
224            if (bufs->bufs[i]->stream_id == p_stream->s_id) {
225                p_frame = bufs->bufs[i];
226                break;
227            }
228        }
229        if (NULL != p_frame) {
230            mm_app_dump_frame(p_frame, "postview", "yuv", p_frame->frame_idx);
231        }
232    }
233
234    mm_app_cache_ops((mm_camera_app_meminfo_t *)m_frame->mem_info,
235                     ION_IOC_CLEAN_INV_CACHES);
236
237    /* create a new jpeg encoding session */
238    rc = createEncodingSession(pme, m_stream, m_frame);
239    if (0 != rc) {
240        CDBG_ERROR("%s: error creating jpeg session", __func__);
241        goto error;
242    }
243
244    /* start jpeg encoding job */
245    rc = encodeData(pme, bufs, m_stream);
246
247error:
248    /* buf done rcvd frames in error case */
249    if ( 0 != rc ) {
250        for (i=0; i<bufs->num_bufs; i++) {
251            if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
252                                                    bufs->ch_id,
253                                                    bufs->bufs[i])) {
254                CDBG_ERROR("%s: Failed in Qbuf\n", __func__);
255            }
256            mm_app_cache_ops((mm_camera_app_meminfo_t *)bufs->bufs[i]->mem_info,
257                             ION_IOC_INV_CACHES);
258        }
259    }
260
261    CDBG("%s: END\n", __func__);
262}
263
264mm_camera_channel_t * mm_app_add_snapshot_channel(mm_camera_test_obj_t *test_obj)
265{
266    mm_camera_channel_t *channel = NULL;
267    mm_camera_stream_t *stream = NULL;
268
269    channel = mm_app_add_channel(test_obj,
270                                 MM_CHANNEL_TYPE_SNAPSHOT,
271                                 NULL,
272                                 NULL,
273                                 NULL);
274    if (NULL == channel) {
275        CDBG_ERROR("%s: add channel failed", __func__);
276        return NULL;
277    }
278
279    stream = mm_app_add_snapshot_stream(test_obj,
280                                        channel,
281                                        mm_app_snapshot_notify_cb,
282                                        (void *)test_obj,
283                                        1,
284                                        1);
285    if (NULL == stream) {
286        CDBG_ERROR("%s: add snapshot stream failed\n", __func__);
287        mm_app_del_channel(test_obj, channel);
288        return NULL;
289    }
290
291    return channel;
292}
293
294mm_camera_stream_t * mm_app_add_postview_stream(mm_camera_test_obj_t *test_obj,
295                                                mm_camera_channel_t *channel,
296                                                mm_camera_buf_notify_t stream_cb,
297                                                void *userdata,
298                                                uint8_t num_bufs,
299                                                uint8_t num_burst)
300{
301    int rc = MM_CAMERA_OK;
302    mm_camera_stream_t *stream = NULL;
303    cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
304
305    stream = mm_app_add_stream(test_obj, channel);
306    if (NULL == stream) {
307        CDBG_ERROR("%s: add stream failed\n", __func__);
308        return NULL;
309    }
310
311    stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
312    stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
313    stream->s_config.mem_vtbl.clean_invalidate_buf =
314      mm_app_stream_clean_invalidate_buf;
315    stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
316    stream->s_config.mem_vtbl.user_data = (void *)stream;
317    stream->s_config.stream_cb = stream_cb;
318    stream->s_config.userdata = userdata;
319    stream->num_of_bufs = num_bufs;
320
321    stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
322    memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
323    stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_POSTVIEW;
324    if (num_burst == 0) {
325        stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
326    } else {
327        stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_BURST;
328        stream->s_config.stream_info->num_of_burst = num_burst;
329    }
330    stream->s_config.stream_info->fmt = DEFAULT_PREVIEW_FORMAT;
331    stream->s_config.stream_info->dim.width = DEFAULT_PREVIEW_WIDTH;
332    stream->s_config.stream_info->dim.height = DEFAULT_PREVIEW_HEIGHT;
333    stream->s_config.padding_info = cam_cap->padding_info;
334
335    rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
336    if (MM_CAMERA_OK != rc) {
337        CDBG_ERROR("%s:config preview stream err=%d\n", __func__, rc);
338        return NULL;
339    }
340
341    return stream;
342}
343
344int mm_app_start_capture(mm_camera_test_obj_t *test_obj,
345                         uint8_t num_snapshots)
346{
347    int32_t rc = MM_CAMERA_OK;
348    mm_camera_channel_t *channel = NULL;
349    mm_camera_stream_t *s_main = NULL;
350    mm_camera_stream_t *s_postview = NULL;
351    mm_camera_channel_attr_t attr;
352
353    memset(&attr, 0, sizeof(mm_camera_channel_attr_t));
354    attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS;
355    attr.max_unmatched_frames = 3;
356    channel = mm_app_add_channel(test_obj,
357                                 MM_CHANNEL_TYPE_CAPTURE,
358                                 &attr,
359                                 mm_app_snapshot_notify_cb,
360                                 test_obj);
361    if (NULL == channel) {
362        CDBG_ERROR("%s: add channel failed", __func__);
363        return -MM_CAMERA_E_GENERAL;
364    }
365
366    s_postview = mm_app_add_postview_stream(test_obj,
367                                            channel,
368                                            NULL,
369                                            NULL,
370                                            num_snapshots,
371                                            num_snapshots);
372    if (NULL == s_postview) {
373        CDBG_ERROR("%s: add preview stream failed\n", __func__);
374        mm_app_del_channel(test_obj, channel);
375        return rc;
376    }
377
378    s_main = mm_app_add_snapshot_stream(test_obj,
379                                        channel,
380                                        NULL,
381                                        NULL,
382                                        num_snapshots,
383                                        num_snapshots);
384    if (NULL == s_main) {
385        CDBG_ERROR("%s: add main snapshot stream failed\n", __func__);
386        mm_app_del_stream(test_obj, channel, s_postview);
387        mm_app_del_channel(test_obj, channel);
388        return rc;
389    }
390
391    rc = mm_app_start_channel(test_obj, channel);
392    if (MM_CAMERA_OK != rc) {
393        CDBG_ERROR("%s:start zsl failed rc=%d\n", __func__, rc);
394        mm_app_del_stream(test_obj, channel, s_postview);
395        mm_app_del_stream(test_obj, channel, s_main);
396        mm_app_del_channel(test_obj, channel);
397        return rc;
398    }
399
400    return rc;
401}
402
403int mm_app_stop_capture(mm_camera_test_obj_t *test_obj)
404{
405    int rc = MM_CAMERA_OK;
406    mm_camera_channel_t *ch = NULL;
407
408    ch = mm_app_get_channel_by_type(test_obj, MM_CHANNEL_TYPE_CAPTURE);
409
410    rc = mm_app_stop_channel(test_obj, ch);
411    if (MM_CAMERA_OK != rc) {
412        CDBG_ERROR("%s:stop recording failed rc=%d\n", __func__, rc);
413    }
414
415    return rc;
416}
417