1 /*
2 Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 // System dependencies
31 #include <assert.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #define MMAN_H <SYSTEM_HEADER_PREFIX/mman.h>
35 #include MMAN_H
36 #include <cutils/properties.h>
37
38
39 // Camera dependencies
40 #include "mm_qcamera_app.h"
41 #include "mm_qcamera_dbg.h"
42 #include "mm_qcamera_app.h"
43 #include <assert.h>
44 #include <sys/mman.h>
45 #include <semaphore.h>
46
mm_app_metadata_notify_cb(mm_camera_super_buf_t * bufs,void * user_data)47 static void mm_app_metadata_notify_cb(mm_camera_super_buf_t *bufs,
48 void *user_data)
49 {
50 uint32_t i = 0;
51 mm_camera_channel_t *channel = NULL;
52 mm_camera_stream_t *p_stream = NULL;
53 mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data;
54 mm_camera_buf_def_t *frame;
55 metadata_buffer_t *pMetadata;
56
57 if (NULL == bufs || NULL == user_data) {
58 LOGE("bufs or user_data are not valid ");
59 return;
60 }
61 frame = bufs->bufs[0];
62
63 /* find channel */
64 for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) {
65 if (pme->channels[i].ch_id == bufs->ch_id) {
66 channel = &pme->channels[i];
67 break;
68 }
69 }
70
71 if (NULL == channel) {
72 LOGE("Channel object is NULL ");
73 return;
74 }
75
76 /* find preview stream */
77 for (i = 0; i < channel->num_streams; i++) {
78 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
79 p_stream = &channel->streams[i];
80 break;
81 }
82 }
83
84 if (NULL == p_stream) {
85 LOGE("cannot find metadata stream");
86 return;
87 }
88
89 /* find preview frame */
90 for (i = 0; i < bufs->num_bufs; i++) {
91 if (bufs->bufs[i]->stream_id == p_stream->s_id) {
92 frame = bufs->bufs[i];
93 break;
94 }
95 }
96
97 if (pme->metadata == NULL) {
98 /* The app will free the meta data, we don't need to bother here */
99 pme->metadata = malloc(sizeof(metadata_buffer_t));
100 if (NULL == pme->metadata) {
101 LOGE("Canot allocate metadata memory\n");
102 return;
103 }
104 }
105
106 memcpy(pme->metadata, frame->buffer, sizeof(metadata_buffer_t));
107
108 pMetadata = (metadata_buffer_t *)frame->buffer;
109
110 IF_META_AVAILABLE(uint32_t, flash_mode, CAM_INTF_META_FLASH_MODE, pMetadata) {
111 pme->mExifParams.sensor_params.flash_mode = (cam_flash_mode_t)*flash_mode;
112 }
113
114 IF_META_AVAILABLE(int32_t, flash_state, CAM_INTF_META_FLASH_STATE, pMetadata) {
115 pme->mExifParams.sensor_params.flash_state = (cam_flash_state_t) *flash_state;
116 }
117
118 IF_META_AVAILABLE(float, aperture_value, CAM_INTF_META_LENS_APERTURE, pMetadata) {
119 pme->mExifParams.sensor_params.aperture_value = *aperture_value;
120 }
121
122
123 IF_META_AVAILABLE(int32_t, wb_mode, CAM_INTF_PARM_WHITE_BALANCE, pMetadata) {
124 pme->mExifParams.cam_3a_params.wb_mode = (cam_wb_mode_type) *wb_mode;
125 }
126
127 IF_META_AVAILABLE(cam_sensor_params_t, sensor_params, CAM_INTF_META_SENSOR_INFO, pMetadata) {
128 pme->mExifParams.sensor_params = *sensor_params;
129 }
130
131 IF_META_AVAILABLE(cam_ae_exif_debug_t, ae_exif_debug_params,
132 CAM_INTF_META_EXIF_DEBUG_AE, pMetadata) {
133 if (pme->mExifParams.debug_params) {
134 pme->mExifParams.debug_params->ae_debug_params = *ae_exif_debug_params;
135 pme->mExifParams.debug_params->ae_debug_params_valid = TRUE;
136
137 }
138
139 }
140
141 IF_META_AVAILABLE(cam_awb_exif_debug_t, awb_exif_debug_params,
142 CAM_INTF_META_EXIF_DEBUG_AWB, pMetadata) {
143 if (pme->mExifParams.debug_params) {
144 pme->mExifParams.debug_params->awb_debug_params = *awb_exif_debug_params;
145 pme->mExifParams.debug_params->awb_debug_params_valid = TRUE;
146 LOGE("Storing AWB Metadata");
147 }
148 }
149
150 IF_META_AVAILABLE(cam_af_exif_debug_t, af_exif_debug_params,
151 CAM_INTF_META_EXIF_DEBUG_AF, pMetadata) {
152 if (pme->mExifParams.debug_params) {
153 pme->mExifParams.debug_params->af_debug_params = *af_exif_debug_params;
154 pme->mExifParams.debug_params->af_debug_params_valid = TRUE;
155 }
156 }
157
158 IF_META_AVAILABLE(cam_asd_exif_debug_t, asd_exif_debug_params,
159 CAM_INTF_META_EXIF_DEBUG_ASD, pMetadata) {
160 if (pme->mExifParams.debug_params) {
161 pme->mExifParams.debug_params->asd_debug_params = *asd_exif_debug_params;
162 pme->mExifParams.debug_params->asd_debug_params_valid = TRUE;
163 }
164 }
165
166 IF_META_AVAILABLE(cam_stats_buffer_exif_debug_t, stats_exif_debug_params,
167 CAM_INTF_META_EXIF_DEBUG_STATS, pMetadata) {
168 if (pme->mExifParams.debug_params) {
169 pme->mExifParams.debug_params->stats_debug_params = *stats_exif_debug_params;
170 pme->mExifParams.debug_params->stats_debug_params_valid = TRUE;
171 }
172 }
173
174 IF_META_AVAILABLE(cam_bestats_buffer_exif_debug_t, bestats_exif_debug_params,
175 CAM_INTF_META_EXIF_DEBUG_BESTATS, pMetadata) {
176 if (pme->mExifParams.debug_params) {
177 pme->mExifParams.debug_params->bestats_debug_params = *bestats_exif_debug_params;
178 pme->mExifParams.debug_params->bestats_debug_params_valid = TRUE;
179 }
180 }
181
182 IF_META_AVAILABLE(cam_bhist_buffer_exif_debug_t, bhist_exif_debug_params,
183 CAM_INTF_META_EXIF_DEBUG_BHIST, pMetadata) {
184 if (pme->mExifParams.debug_params) {
185 pme->mExifParams.debug_params->bhist_debug_params = *bhist_exif_debug_params;
186 pme->mExifParams.debug_params->bhist_debug_params_valid = TRUE;
187 }
188 }
189
190 IF_META_AVAILABLE(cam_q3a_tuning_info_t, q3a_tuning_exif_debug_params,
191 CAM_INTF_META_EXIF_DEBUG_3A_TUNING, pMetadata) {
192 if (pme->mExifParams.debug_params) {
193 pme->mExifParams.debug_params->q3a_tuning_debug_params = *q3a_tuning_exif_debug_params;
194 pme->mExifParams.debug_params->q3a_tuning_debug_params_valid = TRUE;
195 }
196 }
197 IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, pMetadata) {
198 if ((cam_af_state_t)(*afState) == CAM_AF_STATE_FOCUSED_LOCKED ||
199 (cam_af_state_t)(*afState) == CAM_AF_STATE_NOT_FOCUSED_LOCKED) {
200 LOGE("AutoFocus Done Call Back Received\n");
201 mm_camera_app_done();
202 } else if ((cam_af_state_t)(*afState) == CAM_AF_STATE_NOT_FOCUSED_LOCKED) {
203 LOGE("AutoFocus failed\n");
204 mm_camera_app_done();
205 }
206 }
207
208 if (pme->user_metadata_cb) {
209 LOGD("[DBG] user defined own metadata cb. calling it...");
210 pme->user_metadata_cb(frame);
211 }
212
213 if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
214 bufs->ch_id,
215 frame)) {
216 LOGE("Failed in Preview Qbuf\n");
217 }
218 mm_app_cache_ops((mm_camera_app_meminfo_t *)frame->mem_info,
219 ION_IOC_INV_CACHES);
220 }
221
mm_app_snapshot_notify_cb(mm_camera_super_buf_t * bufs,void * user_data)222 static void mm_app_snapshot_notify_cb(mm_camera_super_buf_t *bufs,
223 void *user_data)
224 {
225
226 int rc = 0;
227 uint32_t i = 0;
228 mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data;
229 mm_camera_channel_t *channel = NULL;
230 mm_camera_stream_t *p_stream = NULL;
231 mm_camera_stream_t *m_stream = NULL;
232 mm_camera_buf_def_t *p_frame = NULL;
233 mm_camera_buf_def_t *m_frame = NULL;
234
235 /* find channel */
236 for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) {
237 if (pme->channels[i].ch_id == bufs->ch_id) {
238 channel = &pme->channels[i];
239 break;
240 }
241 }
242 if (NULL == channel) {
243 LOGE("Wrong channel id (%d)", bufs->ch_id);
244 rc = -1;
245 goto error;
246 }
247
248 /* find snapshot stream */
249 for (i = 0; i < channel->num_streams; i++) {
250 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_SNAPSHOT) {
251 m_stream = &channel->streams[i];
252 break;
253 }
254 }
255 if (NULL == m_stream) {
256 LOGE("cannot find snapshot stream");
257 rc = -1;
258 goto error;
259 }
260
261 /* find snapshot frame */
262 for (i = 0; i < bufs->num_bufs; i++) {
263 if (bufs->bufs[i]->stream_id == m_stream->s_id) {
264 m_frame = bufs->bufs[i];
265 break;
266 }
267 }
268 if (NULL == m_frame) {
269 LOGE("main frame is NULL");
270 rc = -1;
271 goto error;
272 }
273
274 mm_app_dump_frame(m_frame, "main", "yuv", m_frame->frame_idx);
275
276 /* find postview stream */
277 for (i = 0; i < channel->num_streams; i++) {
278 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_POSTVIEW) {
279 p_stream = &channel->streams[i];
280 break;
281 }
282 }
283 if (NULL != p_stream) {
284 /* find preview frame */
285 for (i = 0; i < bufs->num_bufs; i++) {
286 if (bufs->bufs[i]->stream_id == p_stream->s_id) {
287 p_frame = bufs->bufs[i];
288 break;
289 }
290 }
291 if (NULL != p_frame) {
292 mm_app_dump_frame(p_frame, "postview", "yuv", p_frame->frame_idx);
293 }
294 }
295
296 mm_app_cache_ops((mm_camera_app_meminfo_t *)m_frame->mem_info,
297 ION_IOC_CLEAN_INV_CACHES);
298
299 pme->jpeg_buf.buf.buffer = (uint8_t *)malloc(m_frame->frame_len);
300 if ( NULL == pme->jpeg_buf.buf.buffer ) {
301 LOGE("error allocating jpeg output buffer");
302 goto error;
303 }
304
305 pme->jpeg_buf.buf.frame_len = m_frame->frame_len;
306 /* create a new jpeg encoding session */
307 rc = createEncodingSession(pme, m_stream, m_frame);
308 if (0 != rc) {
309 LOGE("error creating jpeg session");
310 free(pme->jpeg_buf.buf.buffer);
311 goto error;
312 }
313
314 /* start jpeg encoding job */
315 rc = encodeData(pme, bufs, m_stream);
316 if (0 != rc) {
317 LOGE("error creating jpeg session");
318 free(pme->jpeg_buf.buf.buffer);
319 goto error;
320 }
321
322 error:
323 /* buf done rcvd frames in error case */
324 if ( 0 != rc ) {
325 for (i=0; i<bufs->num_bufs; i++) {
326 if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
327 bufs->ch_id,
328 bufs->bufs[i])) {
329 LOGE("Failed in Qbuf\n");
330 }
331 mm_app_cache_ops((mm_camera_app_meminfo_t *)bufs->bufs[i]->mem_info,
332 ION_IOC_INV_CACHES);
333 }
334 }
335
336 LOGD(" END\n");
337 }
338
mm_app_preview_notify_cb(mm_camera_super_buf_t * bufs,void * user_data)339 static void mm_app_preview_notify_cb(mm_camera_super_buf_t *bufs,
340 void *user_data)
341 {
342 uint32_t i = 0;
343 char value[PROPERTY_VALUE_MAX];
344 mm_camera_channel_t *channel = NULL;
345 mm_camera_stream_t *p_stream = NULL;
346 mm_camera_buf_def_t *frame = NULL;
347 mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data;
348 property_get("persist.camera.dumpimg", value, "0");
349 uint32_t dump_preview = (uint32_t) atoi(value);
350
351 if (NULL == bufs || NULL == user_data) {
352 LOGE("bufs or user_data are not valid ");
353 return;
354 }
355
356 frame = bufs->bufs[0];
357
358 /* find channel */
359 for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) {
360 if (pme->channels[i].ch_id == bufs->ch_id) {
361 channel = &pme->channels[i];
362 break;
363 }
364 }
365 if (NULL == channel) {
366 LOGE("Channel object is NULL ");
367 return;
368 }
369 /* find preview stream */
370 for (i = 0; i < channel->num_streams; i++) {
371 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_PREVIEW) {
372 p_stream = &channel->streams[i];
373 break;
374 }
375 }
376
377 if (NULL == p_stream) {
378 LOGE("cannot find preview stream");
379 return;
380 }
381
382 /* find preview frame */
383 for (i = 0; i < bufs->num_bufs; i++) {
384 if (bufs->bufs[i]->stream_id == p_stream->s_id) {
385 frame = bufs->bufs[i];
386 break;
387 }
388 }
389
390 if ( 0 < pme->fb_fd ) {
391 mm_app_overlay_display(pme, frame->fd);
392 }
393
394 if (dump_preview & QCAMERA_DUMP_FRM_PREVIEW) {
395 char file_name[64];
396 snprintf(file_name, sizeof(file_name), "P_C%d", pme->cam->camera_handle);
397 mm_app_dump_frame(frame, file_name, "yuv", frame->frame_idx);
398 }
399
400 if (pme->user_preview_cb) {
401 LOGD("[DBG]user defined own preview cb. calling it...");
402 pme->user_preview_cb(frame);
403 }
404 if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
405 bufs->ch_id,
406 frame)) {
407 LOGE("Failed in Preview Qbuf\n");
408 }
409 mm_app_cache_ops((mm_camera_app_meminfo_t *)frame->mem_info,
410 ION_IOC_INV_CACHES);
411
412 LOGD(" END\n");
413 }
414
mm_app_zsl_notify_cb(mm_camera_super_buf_t * bufs,void * user_data)415 static void mm_app_zsl_notify_cb(mm_camera_super_buf_t *bufs,
416 void *user_data)
417 {
418 int rc = MM_CAMERA_OK;
419 uint32_t i = 0;
420 mm_camera_test_obj_t *pme = (mm_camera_test_obj_t *)user_data;
421 mm_camera_channel_t *channel = NULL;
422 mm_camera_stream_t *p_stream = NULL;
423 mm_camera_stream_t *m_stream = NULL;
424 mm_camera_stream_t *md_stream = NULL;
425 mm_camera_buf_def_t *p_frame = NULL;
426 mm_camera_buf_def_t *m_frame = NULL;
427 mm_camera_buf_def_t *md_frame = NULL;
428
429 LOGD(" BEGIN\n");
430
431 if (NULL == bufs || NULL == user_data) {
432 LOGE("bufs or user_data are not valid ");
433 return;
434 }
435
436 /* find channel */
437 for (i = 0; i < MM_CHANNEL_TYPE_MAX; i++) {
438 if (pme->channels[i].ch_id == bufs->ch_id) {
439 channel = &pme->channels[i];
440 break;
441 }
442 }
443 if (NULL == channel) {
444 LOGE("Wrong channel id (%d)", bufs->ch_id);
445 return;
446 }
447
448 /* find preview stream */
449 for (i = 0; i < channel->num_streams; i++) {
450 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_PREVIEW) {
451 p_stream = &channel->streams[i];
452 break;
453 }
454 }
455 if (NULL == p_stream) {
456 LOGE("cannot find preview stream");
457 return;
458 }
459
460 /* find snapshot stream */
461 for (i = 0; i < channel->num_streams; i++) {
462 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_SNAPSHOT) {
463 m_stream = &channel->streams[i];
464 break;
465 }
466 }
467 if (NULL == m_stream) {
468 LOGE("cannot find snapshot stream");
469 return;
470 }
471
472 /* find metadata stream */
473 for (i = 0; i < channel->num_streams; i++) {
474 if (channel->streams[i].s_config.stream_info->stream_type == CAM_STREAM_TYPE_METADATA) {
475 md_stream = &channel->streams[i];
476 break;
477 }
478 }
479 if (NULL == md_stream) {
480 LOGE("cannot find metadata stream");
481 }
482
483 /* find preview frame */
484 for (i = 0; i < bufs->num_bufs; i++) {
485 if (bufs->bufs[i]->stream_id == p_stream->s_id) {
486 p_frame = bufs->bufs[i];
487 break;
488 }
489 }
490
491 if(md_stream) {
492 /* find metadata frame */
493 for (i = 0; i < bufs->num_bufs; i++) {
494 if (bufs->bufs[i]->stream_id == md_stream->s_id) {
495 md_frame = bufs->bufs[i];
496 break;
497 }
498 }
499 if (!md_frame) {
500 LOGE("md_frame is null\n");
501 return;
502 }
503 if (!pme->metadata) {
504 /* App will free the metadata */
505 pme->metadata = malloc(sizeof(metadata_buffer_t));
506 if (!pme->metadata) {
507 ALOGE("not enough memory\n");
508 return;
509 }
510 }
511
512 memcpy(pme->metadata , md_frame->buffer, sizeof(metadata_buffer_t));
513 }
514 /* find snapshot frame */
515 for (i = 0; i < bufs->num_bufs; i++) {
516 if (bufs->bufs[i]->stream_id == m_stream->s_id) {
517 m_frame = bufs->bufs[i];
518 break;
519 }
520 }
521
522 if (!m_frame || !p_frame) {
523 LOGE("cannot find preview/snapshot frame");
524 return;
525 }
526
527 LOGD(" ZSL CB with fb_fd = %d, m_frame = %p, p_frame = %p \n",
528 pme->fb_fd,
529 m_frame,
530 p_frame);
531
532 if ( 0 < pme->fb_fd ) {
533 mm_app_overlay_display(pme, p_frame->fd);
534 }/* else {
535 mm_app_dump_frame(p_frame, "zsl_preview", "yuv", p_frame->frame_idx);
536 mm_app_dump_frame(m_frame, "zsl_main", "yuv", m_frame->frame_idx);
537 }*/
538
539 if ( pme->flip_mode ) {
540 int32_t prmFlip = pme->flip_mode;
541 if (md_frame) {
542 metadata_buffer_t* md_data = (metadata_buffer_t*)(md_frame->buffer);
543 ADD_SET_PARAM_ENTRY_TO_BATCH(md_data, CAM_INTF_PARM_FLIP, prmFlip);
544 }
545 }
546
547 if ( pme->enable_reproc && ( NULL != pme->reproc_stream ) ) {
548
549
550 if (NULL != md_frame) {
551 rc = mm_app_do_reprocess(pme,
552 m_frame,
553 md_frame->buf_idx,
554 bufs,
555 md_stream);
556
557 if (MM_CAMERA_OK != rc ) {
558 LOGE("reprocess failed rc = %d", rc);
559 }
560 } else {
561 LOGE("md_frame is null\n");
562 }
563
564 return;
565 }
566
567 if ( pme->encodeJpeg ) {
568 pme->jpeg_buf.buf.buffer = (uint8_t *)malloc(m_frame->frame_len);
569 if ( NULL == pme->jpeg_buf.buf.buffer ) {
570 LOGE("error allocating jpeg output buffer");
571 goto exit;
572 }
573
574 pme->jpeg_buf.buf.frame_len = m_frame->frame_len;
575 /* create a new jpeg encoding session */
576 rc = createEncodingSession(pme, m_stream, m_frame);
577 if (0 != rc) {
578 LOGE("error creating jpeg session");
579 free(pme->jpeg_buf.buf.buffer);
580 goto exit;
581 }
582
583 /* start jpeg encoding job */
584 rc = encodeData(pme, bufs, m_stream);
585 pme->encodeJpeg = 0;
586 } else {
587 if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
588 bufs->ch_id,
589 m_frame)) {
590 LOGE("Failed in main Qbuf\n");
591 }
592 mm_app_cache_ops((mm_camera_app_meminfo_t *)m_frame->mem_info,
593 ION_IOC_INV_CACHES);
594 }
595
596 exit:
597
598 if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
599 bufs->ch_id,
600 p_frame)) {
601 LOGE("Failed in preview Qbuf\n");
602 }
603 mm_app_cache_ops((mm_camera_app_meminfo_t *)p_frame->mem_info,
604 ION_IOC_INV_CACHES);
605
606 if(md_frame) {
607 if (MM_CAMERA_OK != pme->cam->ops->qbuf(bufs->camera_handle,
608 bufs->ch_id,
609 md_frame)) {
610 LOGE("Failed in metadata Qbuf\n");
611 }
612 mm_app_cache_ops((mm_camera_app_meminfo_t *)md_frame->mem_info,
613 ION_IOC_INV_CACHES);
614 }
615
616 LOGD(" END\n");
617 }
618
mm_app_add_metadata_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)619 mm_camera_stream_t * mm_app_add_metadata_stream(mm_camera_test_obj_t *test_obj,
620 mm_camera_channel_t *channel,
621 mm_camera_buf_notify_t stream_cb,
622 void *userdata,
623 uint8_t num_bufs)
624 {
625 int rc = MM_CAMERA_OK;
626 mm_camera_stream_t *stream = NULL;
627 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
628 stream = mm_app_add_stream(test_obj, channel);
629 if (NULL == stream) {
630 LOGE("add stream failed\n");
631 return NULL;
632 }
633
634 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
635 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
636 stream->s_config.mem_vtbl.clean_invalidate_buf =
637 mm_app_stream_clean_invalidate_buf;
638 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
639 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
640 stream->s_config.mem_vtbl.user_data = (void *)stream;
641 stream->s_config.stream_cb = stream_cb;
642 stream->s_config.stream_cb_sync = NULL;
643 stream->s_config.userdata = userdata;
644 stream->num_of_bufs = num_bufs;
645
646 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
647 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
648 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_METADATA;
649 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
650 stream->s_config.stream_info->fmt = DEFAULT_PREVIEW_FORMAT;
651 stream->s_config.stream_info->dim.width = sizeof(metadata_buffer_t);
652 stream->s_config.stream_info->dim.height = 1;
653 stream->s_config.stream_info->num_bufs = num_bufs;
654 stream->s_config.padding_info = cam_cap->padding_info;
655
656 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
657 if (MM_CAMERA_OK != rc) {
658 LOGE("config preview stream err=%d\n", rc);
659 return NULL;
660 }
661
662 return stream;
663 }
664
mm_app_get_analysis_stream_dim(const mm_camera_test_obj_t * test_obj,const cam_dimension_t * preview_dim)665 cam_dimension_t mm_app_get_analysis_stream_dim(
666 const mm_camera_test_obj_t *test_obj,
667 const cam_dimension_t* preview_dim)
668 {
669 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
670 cam_dimension_t max_analysis_dim =
671 cam_cap->analysis_info[CAM_ANALYSIS_INFO_FD_STILL].analysis_max_res;
672 cam_dimension_t analysis_dim = {0, 0};
673
674 if (preview_dim->width > max_analysis_dim.width ||
675 preview_dim->height > max_analysis_dim.height) {
676 double max_ratio, requested_ratio;
677
678 max_ratio = (double)max_analysis_dim.width / (double)max_analysis_dim.height;
679 requested_ratio = (double)preview_dim->width / (double)preview_dim->height;
680
681 if (max_ratio < requested_ratio) {
682 analysis_dim.width = max_analysis_dim.width;
683 analysis_dim.height = (int32_t)((double)max_analysis_dim.width / requested_ratio);
684 } else {
685 analysis_dim.height = max_analysis_dim.height;
686 analysis_dim.width = (int32_t)((double)max_analysis_dim.height * requested_ratio);
687 }
688 analysis_dim.width &= ~0x1;
689 analysis_dim.height &= ~0x1;
690 } else {
691 analysis_dim = *preview_dim;
692 }
693
694 LOGI("analysis stream dim (%d x %d)\n", analysis_dim.width, analysis_dim.height);
695 return analysis_dim;
696 }
697
mm_app_add_analysis_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)698 mm_camera_stream_t * mm_app_add_analysis_stream(mm_camera_test_obj_t *test_obj,
699 mm_camera_channel_t *channel,
700 mm_camera_buf_notify_t stream_cb,
701 void *userdata,
702 uint8_t num_bufs)
703 {
704 int rc = MM_CAMERA_OK;
705 mm_camera_stream_t *stream = NULL;
706 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
707 cam_dimension_t preview_dim = {0, 0};
708 cam_dimension_t analysis_dim = {0, 0};
709
710 if ((test_obj->preview_resolution.user_input_display_width == 0) ||
711 ( test_obj->preview_resolution.user_input_display_height == 0)) {
712 preview_dim.width = DEFAULT_PREVIEW_WIDTH;
713 preview_dim.height = DEFAULT_PREVIEW_HEIGHT;
714 } else {
715 preview_dim.width = test_obj->preview_resolution.user_input_display_width;
716 preview_dim.height = test_obj->preview_resolution.user_input_display_height;
717 }
718
719 analysis_dim = mm_app_get_analysis_stream_dim(test_obj, &preview_dim);
720 LOGI("analysis stream dimesion: %d x %d\n",
721 analysis_dim.width, analysis_dim.height);
722 if (analysis_dim.width == 0 || analysis_dim.height == 0) {
723 /* FD or PAAF might not be enabled , use preview dim */
724 return NULL;
725 }
726
727 stream = mm_app_add_stream(test_obj, channel);
728 if (NULL == stream) {
729 LOGE("add stream failed\n");
730 return NULL;
731 }
732
733 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
734 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
735 stream->s_config.mem_vtbl.clean_invalidate_buf =
736 mm_app_stream_clean_invalidate_buf;
737 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
738 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
739 stream->s_config.mem_vtbl.user_data = (void *)stream;
740 stream->s_config.stream_cb = stream_cb;
741 stream->s_config.userdata = userdata;
742 stream->num_of_bufs = num_bufs;
743
744 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
745 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
746 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_ANALYSIS;
747 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
748 stream->s_config.stream_info->fmt = DEFAULT_PREVIEW_FORMAT;
749 stream->s_config.stream_info->dim = analysis_dim;
750 stream->s_config.padding_info =
751 cam_cap->analysis_info[CAM_ANALYSIS_INFO_FD_STILL].analysis_padding_info;
752 stream->s_config.stream_info->num_bufs = num_bufs;
753
754 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
755 if (MM_CAMERA_OK != rc) {
756 LOGE("config preview stream err=%d\n", rc);
757 return NULL;
758 }
759
760 return stream;
761 }
mm_app_add_ZSL_preview_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)762 mm_camera_stream_t * mm_app_add_ZSL_preview_stream(mm_camera_test_obj_t *test_obj,
763 mm_camera_channel_t *channel,
764 mm_camera_buf_notify_t stream_cb,
765 void *userdata,
766 uint8_t num_bufs)
767 {
768 int rc = MM_CAMERA_OK;
769 mm_camera_stream_t *stream = NULL;
770 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
771 cam_dimension_t preview_dim = {0, 0};
772 cam_dimension_t analysis_dim = {0, 0};
773
774 if ((test_obj->preview_resolution.user_input_display_width == 0) ||
775 ( test_obj->preview_resolution.user_input_display_height == 0)) {
776 preview_dim.width = DEFAULT_PREVIEW_WIDTH;
777 preview_dim.height = DEFAULT_PREVIEW_HEIGHT;
778 } else {
779 preview_dim.width = test_obj->preview_resolution.user_input_display_width;
780 preview_dim.height = test_obj->preview_resolution.user_input_display_height;
781 }
782 LOGI("preview dimesion: %d x %d\n", preview_dim.width, preview_dim.height);
783
784 analysis_dim = mm_app_get_analysis_stream_dim(test_obj, &preview_dim);
785 LOGI("analysis stream dimesion: %d x %d\n",
786 analysis_dim.width, analysis_dim.height);
787
788 uint32_t analysis_pp_mask = cam_cap->qcom_supported_feature_mask &
789 (CAM_QCOM_FEATURE_SHARPNESS |
790 CAM_QCOM_FEATURE_EFFECT |
791 CAM_QCOM_FEATURE_DENOISE2D);
792 LOGI("analysis stream pp mask:%x\n", analysis_pp_mask);
793
794 stream = mm_app_add_stream(test_obj, channel);
795 if (NULL == stream) {
796 LOGE("add stream failed\n");
797 return NULL;
798 }
799 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
800 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
801 stream->s_config.mem_vtbl.clean_invalidate_buf =
802 mm_app_stream_clean_invalidate_buf;
803 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
804 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
805 stream->s_config.mem_vtbl.user_data = (void *)stream;
806 stream->s_config.stream_cb = stream_cb;
807 stream->s_config.stream_cb_sync = NULL;
808 stream->s_config.userdata = userdata;
809 stream->num_of_bufs = num_bufs;
810
811 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
812 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
813 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_PREVIEW;
814 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
815 stream->s_config.stream_info->fmt = DEFAULT_PREVIEW_FORMAT;
816
817 stream->s_config.stream_info->dim.width = preview_dim.width;
818 stream->s_config.stream_info->dim.height = preview_dim.height;
819 stream->s_config.stream_info->num_bufs = num_bufs;
820 stream->s_config.padding_info = cam_cap->padding_info;
821
822 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
823 if (MM_CAMERA_OK != rc) {
824 LOGE("config preview stream err=%d\n", rc);
825 return NULL;
826 }
827
828 return stream;
829 }
830
831
mm_app_add_preview_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)832 mm_camera_stream_t * mm_app_add_preview_stream(mm_camera_test_obj_t *test_obj,
833 mm_camera_channel_t *channel,
834 mm_camera_buf_notify_t stream_cb,
835 void *userdata,
836 uint8_t num_bufs)
837 {
838 int rc = MM_CAMERA_OK;
839 mm_camera_stream_t *stream = NULL;
840 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
841 cam_dimension_t preview_dim = {0, 0};
842 cam_dimension_t analysis_dim = {0, 0};
843
844 if ((test_obj->preview_resolution.user_input_display_width == 0) ||
845 ( test_obj->preview_resolution.user_input_display_height == 0)) {
846 preview_dim.width = DEFAULT_PREVIEW_WIDTH;
847 preview_dim.height = DEFAULT_PREVIEW_HEIGHT;
848 } else {
849 preview_dim.width = test_obj->preview_resolution.user_input_display_width;
850 preview_dim.height = test_obj->preview_resolution.user_input_display_height;
851 }
852 LOGI("preview dimesion: %d x %d\n", preview_dim.width, preview_dim.height);
853
854 analysis_dim = mm_app_get_analysis_stream_dim(test_obj, &preview_dim);
855 LOGI("analysis stream dimesion: %d x %d\n",
856 analysis_dim.width, analysis_dim.height);
857
858 uint32_t analysis_pp_mask = cam_cap->qcom_supported_feature_mask &
859 (CAM_QCOM_FEATURE_SHARPNESS |
860 CAM_QCOM_FEATURE_EFFECT |
861 CAM_QCOM_FEATURE_DENOISE2D);
862 LOGI("analysis stream pp mask:%x\n", analysis_pp_mask);
863
864 cam_stream_size_info_t abc ;
865 memset (&abc , 0, sizeof (cam_stream_size_info_t));
866
867 if (analysis_dim.width != 0 && analysis_dim.height != 0) {
868 abc.num_streams = 2;
869 } else {
870 abc.num_streams = 1;
871 }
872 abc.postprocess_mask[0] = 2178;
873 abc.stream_sizes[0].width = preview_dim.width;
874 abc.stream_sizes[0].height = preview_dim.height;
875 abc.type[0] = CAM_STREAM_TYPE_PREVIEW;
876
877 if (analysis_dim.width != 0 && analysis_dim.height != 0) {
878 abc.postprocess_mask[1] = analysis_pp_mask;
879 abc.stream_sizes[1].width = analysis_dim.width;
880 abc.stream_sizes[1].height = analysis_dim.height;
881 abc.type[1] = CAM_STREAM_TYPE_ANALYSIS;
882 }
883
884 abc.buffer_info.min_buffers = 10;
885 abc.buffer_info.max_buffers = 10;
886 abc.is_type[0] = IS_TYPE_NONE;
887
888 rc = setmetainfoCommand(test_obj, &abc);
889 if (rc != MM_CAMERA_OK) {
890 LOGE("meta info command failed\n");
891 }
892
893 stream = mm_app_add_stream(test_obj, channel);
894 if (NULL == stream) {
895 LOGE("add stream failed\n");
896 return NULL;
897 }
898 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
899 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
900 stream->s_config.mem_vtbl.clean_invalidate_buf =
901 mm_app_stream_clean_invalidate_buf;
902 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
903 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
904 stream->s_config.mem_vtbl.user_data = (void *)stream;
905 stream->s_config.stream_cb = stream_cb;
906 stream->s_config.stream_cb_sync = NULL;
907 stream->s_config.userdata = userdata;
908 stream->num_of_bufs = num_bufs;
909
910 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
911 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
912 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_PREVIEW;
913 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
914 stream->s_config.stream_info->fmt = DEFAULT_PREVIEW_FORMAT;
915
916 if (test_obj->enable_EZTune) {
917 stream->s_config.stream_info->pp_config.feature_mask = CAM_QCOM_FEATURE_EZTUNE;
918 }
919
920 stream->s_config.stream_info->dim.width = preview_dim.width;
921 stream->s_config.stream_info->dim.height = preview_dim.height;
922 stream->s_config.stream_info->num_bufs = num_bufs;
923 stream->s_config.padding_info = cam_cap->padding_info;
924
925 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
926 if (MM_CAMERA_OK != rc) {
927 LOGE("config preview stream err=%d\n", rc);
928 return NULL;
929 }
930
931 return stream;
932 }
933
mm_app_add_raw_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)934 mm_camera_stream_t * mm_app_add_raw_stream(mm_camera_test_obj_t *test_obj,
935 mm_camera_channel_t *channel,
936 mm_camera_buf_notify_t stream_cb,
937 void *userdata,
938 uint8_t num_bufs,
939 uint8_t num_burst)
940 {
941 int rc = MM_CAMERA_OK;
942 mm_camera_stream_t *stream = NULL;
943 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
944
945 cam_stream_size_info_t abc ;
946 memset (&abc , 0, sizeof (cam_stream_size_info_t));
947
948 abc.num_streams = 1;
949 abc.postprocess_mask[0] = 0;
950
951 if ( test_obj->buffer_width == 0 || test_obj->buffer_height == 0 ) {
952 abc.stream_sizes[0].width = DEFAULT_SNAPSHOT_WIDTH;
953 abc.stream_sizes[0].height = DEFAULT_SNAPSHOT_HEIGHT;
954 } else {
955 abc.stream_sizes[0].width = (int32_t)test_obj->buffer_width;
956 abc.stream_sizes[0].height = (int32_t)test_obj->buffer_height;
957 }
958 abc.type[0] = CAM_STREAM_TYPE_RAW;
959
960 abc.buffer_info.min_buffers = num_bufs;
961 abc.buffer_info.max_buffers = num_bufs;
962 abc.is_type[0] = IS_TYPE_NONE;
963
964 rc = setmetainfoCommand(test_obj, &abc);
965 if (rc != MM_CAMERA_OK) {
966 LOGE("meta info command failed\n");
967 }
968
969 stream = mm_app_add_stream(test_obj, channel);
970 if (NULL == stream) {
971 LOGE("add stream failed\n");
972 return NULL;
973 }
974
975 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
976 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
977 stream->s_config.mem_vtbl.clean_invalidate_buf =
978 mm_app_stream_clean_invalidate_buf;
979 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
980 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
981 stream->s_config.mem_vtbl.user_data = (void *)stream;
982 stream->s_config.stream_cb = stream_cb;
983 stream->s_config.stream_cb_sync = NULL;
984 stream->s_config.userdata = userdata;
985 stream->num_of_bufs = num_bufs;
986
987 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
988 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
989 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_RAW;
990 if (num_burst == 0) {
991 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
992 } else {
993 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_BURST;
994 stream->s_config.stream_info->num_of_burst = num_burst;
995 }
996 stream->s_config.stream_info->fmt = test_obj->buffer_format;
997 if ( test_obj->buffer_width == 0 || test_obj->buffer_height == 0 ) {
998 stream->s_config.stream_info->dim.width = DEFAULT_SNAPSHOT_WIDTH;
999 stream->s_config.stream_info->dim.height = DEFAULT_SNAPSHOT_HEIGHT;
1000 } else {
1001 stream->s_config.stream_info->dim.width = (int32_t)test_obj->buffer_width;
1002 stream->s_config.stream_info->dim.height = (int32_t)test_obj->buffer_height;
1003 }
1004 stream->s_config.stream_info->num_bufs = num_bufs;
1005 stream->s_config.padding_info = cam_cap->padding_info;
1006
1007 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
1008 if (MM_CAMERA_OK != rc) {
1009 LOGE("config preview stream err=%d\n", rc);
1010 return NULL;
1011 }
1012
1013 return stream;
1014 }
1015
mm_app_add_ZSL_snapshot_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)1016 mm_camera_stream_t * mm_app_add_ZSL_snapshot_stream(mm_camera_test_obj_t *test_obj,
1017 mm_camera_channel_t *channel,
1018 mm_camera_buf_notify_t stream_cb,
1019 void *userdata,
1020 uint8_t num_bufs,
1021 uint8_t num_burst)
1022 {
1023 int rc = MM_CAMERA_OK;
1024 mm_camera_stream_t *stream = NULL;
1025 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
1026 cam_stream_size_info_t abc_snap ;
1027 memset (&abc_snap , 0, sizeof (cam_stream_size_info_t));
1028
1029 abc_snap.num_streams = 2;
1030 abc_snap.postprocess_mask[1] = 2178;
1031 abc_snap.stream_sizes[1].width = DEFAULT_PREVIEW_WIDTH;
1032 abc_snap.stream_sizes[1].height = DEFAULT_PREVIEW_HEIGHT;
1033 abc_snap.type[1] = CAM_STREAM_TYPE_PREVIEW;
1034
1035 abc_snap.postprocess_mask[0] = 0;
1036 if ( test_obj->buffer_width == 0 || test_obj->buffer_height == 0 ) {
1037 abc_snap.stream_sizes[0].width = DEFAULT_SNAPSHOT_WIDTH;
1038 abc_snap.stream_sizes[0].height = DEFAULT_SNAPSHOT_HEIGHT;
1039 } else {
1040 abc_snap.stream_sizes[0].width = test_obj->buffer_width;
1041 abc_snap.stream_sizes[0].height = test_obj->buffer_height;
1042 }
1043 abc_snap.type[0] = CAM_STREAM_TYPE_SNAPSHOT;
1044
1045 abc_snap.buffer_info.min_buffers = 7;
1046 abc_snap.buffer_info.max_buffers = 7;
1047 abc_snap.is_type[0] = IS_TYPE_NONE;
1048
1049 rc = setmetainfoCommand(test_obj, &abc_snap);
1050 if (rc != MM_CAMERA_OK) {
1051 LOGE("meta info command snapshot failed\n");
1052 }
1053
1054 stream = mm_app_add_stream(test_obj, channel);
1055 if (NULL == stream) {
1056 LOGE("add stream failed\n");
1057 return NULL;
1058 }
1059
1060 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
1061 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
1062 stream->s_config.mem_vtbl.clean_invalidate_buf =
1063 mm_app_stream_clean_invalidate_buf;
1064 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
1065 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
1066 stream->s_config.mem_vtbl.user_data = (void *)stream;
1067 stream->s_config.stream_cb = stream_cb;
1068 stream->s_config.stream_cb_sync = NULL;
1069 stream->s_config.userdata = userdata;
1070 stream->num_of_bufs = num_bufs;
1071
1072 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
1073 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
1074 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_SNAPSHOT;
1075 if (num_burst == 0) {
1076 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
1077 } else {
1078 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_BURST;
1079 stream->s_config.stream_info->num_of_burst = num_burst;
1080 }
1081 stream->s_config.stream_info->fmt = DEFAULT_SNAPSHOT_FORMAT;
1082 if ( test_obj->buffer_width == 0 || test_obj->buffer_height == 0 ) {
1083 stream->s_config.stream_info->dim.width = DEFAULT_SNAPSHOT_WIDTH;
1084 stream->s_config.stream_info->dim.height = DEFAULT_SNAPSHOT_HEIGHT;
1085 } else {
1086 stream->s_config.stream_info->dim.width = test_obj->buffer_width;
1087 stream->s_config.stream_info->dim.height = test_obj->buffer_height;
1088 }
1089 stream->s_config.stream_info->num_bufs = num_bufs;
1090 stream->s_config.padding_info = cam_cap->padding_info;
1091 /* Make offset as zero as CPP will not be used */
1092 stream->s_config.padding_info.offset_info.offset_x = 0;
1093 stream->s_config.padding_info.offset_info.offset_y = 0;
1094
1095 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
1096 if (MM_CAMERA_OK != rc) {
1097 LOGE("config preview stream err=%d\n", rc);
1098 return NULL;
1099 }
1100
1101 return stream;
1102 }
1103
1104
mm_app_add_snapshot_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)1105 mm_camera_stream_t * mm_app_add_snapshot_stream(mm_camera_test_obj_t *test_obj,
1106 mm_camera_channel_t *channel,
1107 mm_camera_buf_notify_t stream_cb,
1108 void *userdata,
1109 uint8_t num_bufs,
1110 uint8_t num_burst)
1111 {
1112 int rc = MM_CAMERA_OK;
1113 mm_camera_stream_t *stream = NULL;
1114 cam_capability_t *cam_cap = (cam_capability_t *)(test_obj->cap_buf.buf.buffer);
1115 cam_stream_size_info_t abc_snap ;
1116 memset (&abc_snap , 0, sizeof (cam_stream_size_info_t));
1117
1118 abc_snap.num_streams = 2;
1119 abc_snap.postprocess_mask[1] = 2178;
1120 abc_snap.stream_sizes[1].width = DEFAULT_PREVIEW_WIDTH;
1121 abc_snap.stream_sizes[1].height = DEFAULT_PREVIEW_HEIGHT;
1122 abc_snap.type[1] = CAM_STREAM_TYPE_POSTVIEW;
1123
1124 abc_snap.postprocess_mask[0] = 0;
1125 if ( test_obj->buffer_width == 0 || test_obj->buffer_height == 0 ) {
1126 abc_snap.stream_sizes[0].width = DEFAULT_SNAPSHOT_WIDTH;
1127 abc_snap.stream_sizes[0].height = DEFAULT_SNAPSHOT_HEIGHT;
1128 } else {
1129 abc_snap.stream_sizes[0].width = test_obj->buffer_width;
1130 abc_snap.stream_sizes[0].height = test_obj->buffer_height;
1131 }
1132 abc_snap.type[0] = CAM_STREAM_TYPE_SNAPSHOT;
1133
1134 abc_snap.buffer_info.min_buffers = 7;
1135 abc_snap.buffer_info.max_buffers = 7;
1136 abc_snap.is_type[0] = IS_TYPE_NONE;
1137
1138 rc = setmetainfoCommand(test_obj, &abc_snap);
1139 if (rc != MM_CAMERA_OK) {
1140 LOGE("meta info command snapshot failed\n");
1141 }
1142
1143 stream = mm_app_add_stream(test_obj, channel);
1144 if (NULL == stream) {
1145 LOGE("add stream failed\n");
1146 return NULL;
1147 }
1148
1149 stream->s_config.mem_vtbl.get_bufs = mm_app_stream_initbuf;
1150 stream->s_config.mem_vtbl.put_bufs = mm_app_stream_deinitbuf;
1151 stream->s_config.mem_vtbl.clean_invalidate_buf =
1152 mm_app_stream_clean_invalidate_buf;
1153 stream->s_config.mem_vtbl.invalidate_buf = mm_app_stream_invalidate_buf;
1154 stream->s_config.mem_vtbl.clean_buf = mm_app_stream_clean_buf;
1155 stream->s_config.mem_vtbl.user_data = (void *)stream;
1156 stream->s_config.stream_cb = stream_cb;
1157 stream->s_config.stream_cb_sync = NULL;
1158 stream->s_config.userdata = userdata;
1159 stream->num_of_bufs = num_bufs;
1160
1161 stream->s_config.stream_info = (cam_stream_info_t *)stream->s_info_buf.buf.buffer;
1162 memset(stream->s_config.stream_info, 0, sizeof(cam_stream_info_t));
1163 stream->s_config.stream_info->stream_type = CAM_STREAM_TYPE_SNAPSHOT;
1164 if (num_burst == 0) {
1165 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
1166 } else {
1167 stream->s_config.stream_info->streaming_mode = CAM_STREAMING_MODE_BURST;
1168 stream->s_config.stream_info->num_of_burst = num_burst;
1169 }
1170 stream->s_config.stream_info->fmt = DEFAULT_SNAPSHOT_FORMAT;
1171 if ( test_obj->buffer_width == 0 || test_obj->buffer_height == 0 ) {
1172 stream->s_config.stream_info->dim.width = DEFAULT_SNAPSHOT_WIDTH;
1173 stream->s_config.stream_info->dim.height = DEFAULT_SNAPSHOT_HEIGHT;
1174 } else {
1175 stream->s_config.stream_info->dim.width = test_obj->buffer_width;
1176 stream->s_config.stream_info->dim.height = test_obj->buffer_height;
1177 }
1178 stream->s_config.stream_info->num_bufs = num_bufs;
1179 stream->s_config.padding_info = cam_cap->padding_info;
1180 /* Make offset as zero as CPP will not be used */
1181 stream->s_config.padding_info.offset_info.offset_x = 0;
1182 stream->s_config.padding_info.offset_info.offset_y = 0;
1183
1184 rc = mm_app_config_stream(test_obj, channel, stream, &stream->s_config);
1185 if (MM_CAMERA_OK != rc) {
1186 LOGE("config preview stream err=%d\n", rc);
1187 return NULL;
1188 }
1189
1190 return stream;
1191 }
1192
mm_app_add_preview_channel(mm_camera_test_obj_t * test_obj)1193 mm_camera_channel_t * mm_app_add_preview_channel(mm_camera_test_obj_t *test_obj)
1194 {
1195 mm_camera_channel_t *channel = NULL;
1196 mm_camera_stream_t *stream = NULL;
1197
1198 channel = mm_app_add_channel(test_obj,
1199 MM_CHANNEL_TYPE_PREVIEW,
1200 NULL,
1201 NULL,
1202 NULL);
1203 if (NULL == channel) {
1204 LOGE("add channel failed");
1205 return NULL;
1206 }
1207
1208 stream = mm_app_add_preview_stream(test_obj,
1209 channel,
1210 mm_app_preview_notify_cb,
1211 (void *)test_obj,
1212 PREVIEW_BUF_NUM);
1213 if (NULL == stream) {
1214 LOGE("add stream failed\n");
1215 mm_app_del_channel(test_obj, channel);
1216 return NULL;
1217 }
1218
1219 return channel;
1220 }
1221
mm_app_stop_and_del_channel(mm_camera_test_obj_t * test_obj,mm_camera_channel_t * channel)1222 int mm_app_stop_and_del_channel(mm_camera_test_obj_t *test_obj,
1223 mm_camera_channel_t *channel)
1224 {
1225 int rc = MM_CAMERA_OK;
1226 mm_camera_stream_t *stream = NULL;
1227 uint8_t i;
1228 cam_stream_size_info_t abc ;
1229 memset (&abc , 0, sizeof (cam_stream_size_info_t));
1230
1231 rc = mm_app_stop_channel(test_obj, channel);
1232 if (MM_CAMERA_OK != rc) {
1233 LOGE("Stop Preview failed rc=%d\n", rc);
1234 }
1235
1236 if (channel->num_streams <= MAX_STREAM_NUM_IN_BUNDLE) {
1237 for (i = 0; i < channel->num_streams; i++) {
1238 stream = &channel->streams[i];
1239 rc = mm_app_del_stream(test_obj, channel, stream);
1240 if (MM_CAMERA_OK != rc) {
1241 LOGE("del stream(%d) failed rc=%d\n", i, rc);
1242 }
1243 }
1244 } else {
1245 LOGE("num_streams = %d. Should not be more than %d\n",
1246 channel->num_streams, MAX_STREAM_NUM_IN_BUNDLE);
1247 }
1248
1249 rc = setmetainfoCommand(test_obj, &abc);
1250 if (rc != MM_CAMERA_OK) {
1251 LOGE("meta info command failed\n");
1252 }
1253
1254 rc = mm_app_del_channel(test_obj, channel);
1255 if (MM_CAMERA_OK != rc) {
1256 LOGE("delete channel failed rc=%d\n", rc);
1257 }
1258
1259 return rc;
1260 }
1261
mm_app_start_preview(mm_camera_test_obj_t * test_obj)1262 int mm_app_start_preview(mm_camera_test_obj_t *test_obj)
1263 {
1264 int rc = MM_CAMERA_OK;
1265 mm_camera_channel_t *channel = NULL;
1266 mm_camera_stream_t *stream = NULL;
1267 mm_camera_stream_t *s_metadata = NULL;
1268 mm_camera_stream_t *s_analysis = NULL;
1269 uint8_t i;
1270
1271 channel = mm_app_add_preview_channel(test_obj);
1272 if (NULL == channel) {
1273 LOGE("add channel failed");
1274 return -MM_CAMERA_E_GENERAL;
1275 }
1276
1277 s_metadata = mm_app_add_metadata_stream(test_obj,
1278 channel,
1279 mm_app_metadata_notify_cb,
1280 (void *)test_obj,
1281 PREVIEW_BUF_NUM);
1282 if (NULL == s_metadata) {
1283 LOGE("add metadata stream failed\n");
1284 mm_app_del_channel(test_obj, channel);
1285 return rc;
1286 }
1287
1288 s_analysis = mm_app_add_analysis_stream(test_obj,
1289 channel,
1290 NULL,
1291 (void *)test_obj,
1292 PREVIEW_BUF_NUM);
1293 if (NULL == s_analysis) {
1294 LOGE("Analysis Stream could not be added\n");
1295 }
1296
1297 rc = mm_app_start_channel(test_obj, channel);
1298 if (MM_CAMERA_OK != rc) {
1299 LOGE("start preview failed rc=%d\n", rc);
1300 if (channel->num_streams <= MAX_STREAM_NUM_IN_BUNDLE) {
1301 for (i = 0; i < channel->num_streams; i++) {
1302 stream = &channel->streams[i];
1303 mm_app_del_stream(test_obj, channel, stream);
1304 }
1305 }
1306 mm_app_del_channel(test_obj, channel);
1307 return rc;
1308 }
1309
1310 return rc;
1311 }
1312
mm_app_stop_preview(mm_camera_test_obj_t * test_obj)1313 int mm_app_stop_preview(mm_camera_test_obj_t *test_obj)
1314 {
1315 int rc = MM_CAMERA_OK;
1316 mm_camera_channel_t *channel =
1317 mm_app_get_channel_by_type(test_obj, MM_CHANNEL_TYPE_PREVIEW);
1318
1319 rc = mm_app_stop_and_del_channel(test_obj, channel);
1320 if (MM_CAMERA_OK != rc) {
1321 LOGE("Stop Preview failed rc=%d\n", rc);
1322 }
1323
1324 return rc;
1325 }
1326
mm_app_start_preview_zsl(mm_camera_test_obj_t * test_obj)1327 int mm_app_start_preview_zsl(mm_camera_test_obj_t *test_obj)
1328 {
1329 int32_t rc = MM_CAMERA_OK;
1330 mm_camera_channel_t *channel = NULL;
1331 mm_camera_stream_t *s_preview = NULL;
1332 mm_camera_stream_t *s_metadata = NULL;
1333 mm_camera_stream_t *s_main = NULL;
1334 mm_camera_channel_attr_t attr;
1335 memset(&attr, 0, sizeof(mm_camera_channel_attr_t));
1336 attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS;
1337 attr.look_back = 2;
1338 attr.post_frame_skip = 0;
1339 attr.water_mark = 2;
1340 attr.max_unmatched_frames = 3;
1341 channel = mm_app_add_channel(test_obj,
1342 MM_CHANNEL_TYPE_ZSL,
1343 &attr,
1344 mm_app_zsl_notify_cb,
1345 test_obj);
1346 if (NULL == channel) {
1347 LOGE("add channel failed");
1348 return -MM_CAMERA_E_GENERAL;
1349 }
1350
1351
1352 s_main = mm_app_add_ZSL_snapshot_stream(test_obj,
1353 channel,
1354 mm_app_snapshot_notify_cb,
1355 (void *)test_obj,
1356 PREVIEW_BUF_NUM,
1357 0);
1358 if (NULL == s_main) {
1359 LOGE("add main snapshot stream failed\n");
1360 mm_app_del_channel(test_obj, channel);
1361 return rc;
1362 }
1363 s_preview = mm_app_add_ZSL_preview_stream(test_obj,
1364 channel,
1365 mm_app_preview_notify_cb,
1366 (void *)test_obj,
1367 PREVIEW_BUF_NUM);
1368 if (NULL == s_preview) {
1369 LOGE("add preview stream failed\n");
1370 mm_app_del_channel(test_obj, channel);
1371 return rc;
1372 }
1373
1374
1375 s_metadata = mm_app_add_metadata_stream(test_obj,
1376 channel,
1377 mm_app_metadata_notify_cb,
1378 (void *)test_obj,
1379 PREVIEW_BUF_NUM);
1380 if (NULL == s_metadata) {
1381 LOGE("add metadata stream failed\n");
1382 mm_app_del_channel(test_obj, channel);
1383 return rc;
1384 }
1385
1386 rc = mm_app_start_channel(test_obj, channel);
1387 if (MM_CAMERA_OK != rc) {
1388 LOGE("start zsl failed rc=%d\n", rc);
1389 mm_app_del_stream(test_obj, channel, s_preview);
1390 mm_app_del_stream(test_obj, channel, s_metadata);
1391 mm_app_del_stream(test_obj, channel, s_main);
1392 mm_app_del_channel(test_obj, channel);
1393 return rc;
1394 }
1395
1396 if ( test_obj->enable_reproc ) {
1397 if ( NULL == mm_app_add_reprocess_channel(test_obj, s_main) ) {
1398 LOGE("Reprocess channel failed to initialize \n");
1399 mm_app_del_stream(test_obj, channel, s_preview);
1400 #ifdef USE_METADATA_STREAM
1401 mm_app_del_stream(test_obj, channel, s_metadata);
1402 #endif
1403 mm_app_del_stream(test_obj, channel, s_main);
1404 mm_app_del_channel(test_obj, channel);
1405 return rc;
1406 }
1407 rc = mm_app_start_reprocess(test_obj);
1408 if (MM_CAMERA_OK != rc) {
1409 LOGE("reprocess start failed rc=%d\n", rc);
1410 mm_app_del_stream(test_obj, channel, s_preview);
1411 #ifdef USE_METADATA_STREAM
1412 mm_app_del_stream(test_obj, channel, s_metadata);
1413 #endif
1414 mm_app_del_stream(test_obj, channel, s_main);
1415 mm_app_del_channel(test_obj, channel);
1416 return rc;
1417 }
1418 }
1419
1420 return rc;
1421 }
1422
mm_app_stop_preview_zsl(mm_camera_test_obj_t * test_obj)1423 int mm_app_stop_preview_zsl(mm_camera_test_obj_t *test_obj)
1424 {
1425 int rc = MM_CAMERA_OK;
1426
1427 mm_camera_channel_t *channel =
1428 mm_app_get_channel_by_type(test_obj, MM_CHANNEL_TYPE_ZSL);
1429
1430 rc = mm_app_stop_and_del_channel(test_obj, channel);
1431 if (MM_CAMERA_OK != rc) {
1432 LOGE("Stop Preview failed rc=%d\n", rc);
1433 }
1434
1435 if ( test_obj->enable_reproc ) {
1436 rc |= mm_app_stop_reprocess(test_obj);
1437 }
1438
1439 return rc;
1440 }
1441
mm_app_initialize_fb(mm_camera_test_obj_t * test_obj)1442 int mm_app_initialize_fb(mm_camera_test_obj_t *test_obj)
1443 {
1444 int rc = MM_CAMERA_OK;
1445 int brightness_fd;
1446 const char brightness_level[] = BACKLIGHT_LEVEL;
1447 void *fb_base = NULL;
1448
1449 assert( ( NULL != test_obj ) && ( 0 == test_obj->fb_fd ) );
1450
1451 test_obj->fb_fd = open(FB_PATH, O_RDWR);
1452 if ( 0 > test_obj->fb_fd ) {
1453 LOGE("FB device open failed rc=%d, %s\n",
1454 -errno,
1455 strerror(errno));
1456 rc = -errno;
1457 goto FAIL;
1458 }
1459
1460 rc = ioctl(test_obj->fb_fd, FBIOGET_VSCREENINFO, &test_obj->vinfo);
1461 if ( MM_CAMERA_OK != rc ) {
1462 LOGE("Can not retrieve screen info rc=%d, %s\n",
1463 -errno,
1464 strerror(errno));
1465 rc = -errno;
1466 goto FAIL;
1467 }
1468
1469 if ( ( 0 == test_obj->vinfo.yres_virtual ) ||
1470 ( 0 == test_obj->vinfo.yres ) ||
1471 ( test_obj->vinfo.yres > test_obj->vinfo.yres_virtual ) ) {
1472 LOGE("Invalid FB virtual yres: %d, yres: %d\n",
1473 test_obj->vinfo.yres_virtual,
1474 test_obj->vinfo.yres);
1475 rc = MM_CAMERA_E_GENERAL;
1476 goto FAIL;
1477 }
1478
1479 if ( ( 0 == test_obj->vinfo.xres_virtual ) ||
1480 ( 0 == test_obj->vinfo.xres ) ||
1481 ( test_obj->vinfo.xres > test_obj->vinfo.xres_virtual ) ) {
1482 LOGE("Invalid FB virtual xres: %d, xres: %d\n",
1483 test_obj->vinfo.xres_virtual,
1484 test_obj->vinfo.xres);
1485 rc = MM_CAMERA_E_GENERAL;
1486 goto FAIL;
1487 }
1488
1489 brightness_fd = open(BACKLIGHT_CONTROL, O_RDWR);
1490 if ( brightness_fd >= 0 ) {
1491 write(brightness_fd, brightness_level, strlen(brightness_level));
1492 close(brightness_fd);
1493 }
1494
1495 test_obj->slice_size = test_obj->vinfo.xres * ( test_obj->vinfo.yres - 1 ) * DEFAULT_OV_FORMAT_BPP;
1496 memset(&test_obj->data_overlay, 0, sizeof(struct mdp_overlay));
1497 test_obj->data_overlay.src.width = test_obj->buffer_width;
1498 test_obj->data_overlay.src.height = test_obj->buffer_height;
1499 test_obj->data_overlay.src_rect.w = test_obj->buffer_width;
1500 test_obj->data_overlay.src_rect.h = test_obj->buffer_height;
1501 test_obj->data_overlay.dst_rect.w = test_obj->buffer_width;
1502 test_obj->data_overlay.dst_rect.h = test_obj->buffer_height;
1503 test_obj->data_overlay.src.format = DEFAULT_OV_FORMAT;
1504 test_obj->data_overlay.src_rect.x = 0;
1505 test_obj->data_overlay.src_rect.y = 0;
1506 test_obj->data_overlay.dst_rect.x = 0;
1507 test_obj->data_overlay.dst_rect.y = 0;
1508 test_obj->data_overlay.z_order = 2;
1509 test_obj->data_overlay.alpha = 0x80;
1510 test_obj->data_overlay.transp_mask = 0xffe0;
1511 test_obj->data_overlay.flags = MDP_FLIP_LR | MDP_FLIP_UD;
1512
1513 // Map and clear FB portion
1514 fb_base = mmap(0,
1515 test_obj->slice_size,
1516 PROT_WRITE,
1517 MAP_SHARED,
1518 test_obj->fb_fd,
1519 0);
1520 if ( MAP_FAILED == fb_base ) {
1521 LOGE("( Error while memory mapping frame buffer %s",
1522 strerror(errno));
1523 rc = -errno;
1524 goto FAIL;
1525 }
1526
1527 memset(fb_base, 0, test_obj->slice_size);
1528
1529 if (ioctl(test_obj->fb_fd, FBIOPAN_DISPLAY, &test_obj->vinfo) < 0) {
1530 LOGE("FBIOPAN_DISPLAY failed!");
1531 rc = -errno;
1532 goto FAIL;
1533 }
1534
1535 munmap(fb_base, test_obj->slice_size);
1536 test_obj->data_overlay.id = (uint32_t)MSMFB_NEW_REQUEST;
1537 rc = ioctl(test_obj->fb_fd, MSMFB_OVERLAY_SET, &test_obj->data_overlay);
1538 if (rc < 0) {
1539 LOGE("MSMFB_OVERLAY_SET failed! err=%d\n",
1540 test_obj->data_overlay.id);
1541 return MM_CAMERA_E_GENERAL;
1542 }
1543 LOGE("Overlay set with overlay id: %d", test_obj->data_overlay.id);
1544
1545 return rc;
1546
1547 FAIL:
1548
1549 if ( 0 < test_obj->fb_fd ) {
1550 close(test_obj->fb_fd);
1551 }
1552
1553 return rc;
1554 }
1555
mm_app_close_fb(mm_camera_test_obj_t * test_obj)1556 int mm_app_close_fb(mm_camera_test_obj_t *test_obj)
1557 {
1558 int rc = MM_CAMERA_OK;
1559
1560 assert( ( NULL != test_obj ) && ( 0 < test_obj->fb_fd ) );
1561
1562 if (ioctl(test_obj->fb_fd, MSMFB_OVERLAY_UNSET, &test_obj->data_overlay.id)) {
1563 LOGE("\nERROR! MSMFB_OVERLAY_UNSET failed! (Line %d)\n");
1564 }
1565
1566 if (ioctl(test_obj->fb_fd, FBIOPAN_DISPLAY, &test_obj->vinfo) < 0) {
1567 LOGE("ERROR: FBIOPAN_DISPLAY failed! line=%d\n");
1568 }
1569
1570 close(test_obj->fb_fd);
1571 test_obj->fb_fd = -1;
1572
1573 return rc;
1574 }
1575
memset16(void * pDst,uint16_t value,int count)1576 void memset16(void *pDst, uint16_t value, int count)
1577 {
1578 uint16_t *ptr = pDst;
1579 while (count--)
1580 *ptr++ = value;
1581 }
1582
mm_app_overlay_display(mm_camera_test_obj_t * test_obj,int bufferFd)1583 int mm_app_overlay_display(mm_camera_test_obj_t *test_obj, int bufferFd)
1584 {
1585 int rc = MM_CAMERA_OK;
1586 struct msmfb_overlay_data ovdata;
1587
1588
1589 memset(&ovdata, 0, sizeof(struct msmfb_overlay_data));
1590 ovdata.id = test_obj->data_overlay.id;
1591 ovdata.data.memory_id = bufferFd;
1592
1593 if (ioctl(test_obj->fb_fd, MSMFB_OVERLAY_PLAY, &ovdata)) {
1594 LOGE("MSMFB_OVERLAY_PLAY failed!");
1595 return MM_CAMERA_E_GENERAL;
1596 }
1597
1598 if (ioctl(test_obj->fb_fd, FBIOPAN_DISPLAY, &test_obj->vinfo) < 0) {
1599 LOGE("FBIOPAN_DISPLAY failed!");
1600 return MM_CAMERA_E_GENERAL;
1601 }
1602
1603 return rc;
1604 }
1605