QCamera3PostProc.cpp revision d5d5a90863708ac1cdbef25c41853b6f6f05d4e2
1/* Copyright (c) 2012-2013, The Linux Foundataion. 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#define LOG_TAG "QCamera3PostProc" 31 32#include <stdlib.h> 33#include <utils/Errors.h> 34 35#include "QCamera3PostProc.h" 36#include "QCamera3HWI.h" 37#include "QCamera3Channel.h" 38#include "QCamera3Stream.h" 39 40namespace qcamera { 41 42/*=========================================================================== 43 * FUNCTION : QCamera3PostProcessor 44 * 45 * DESCRIPTION: constructor of QCamera3PostProcessor. 46 * 47 * PARAMETERS : 48 * @cam_ctrl : ptr to HWI object 49 * 50 * RETURN : None 51 *==========================================================================*/ 52QCamera3PostProcessor::QCamera3PostProcessor(QCamera3PicChannel* ch_ctrl) 53 : m_parent(ch_ctrl), 54 mJpegCB(NULL), 55 mJpegUserData(NULL), 56 mJpegClientHandle(0), 57 mJpegSessionId(0), 58 m_pJpegExifObj(NULL), 59 m_bThumbnailNeeded(TRUE), 60 m_inputPPQ(releasePPInputData, this), 61 m_ongoingPPQ(releaseOngoingPPData, this), 62 m_inputJpegQ(releaseJpegData, this), 63 m_ongoingJpegQ(releaseJpegData, this), 64 m_inputRawQ(releasePPInputData, this) 65{ 66 memset(&mJpegHandle, 0, sizeof(mJpegHandle)); 67} 68 69/*=========================================================================== 70 * FUNCTION : ~QCamera3PostProcessor 71 * 72 * DESCRIPTION: deconstructor of QCamera3PostProcessor. 73 * 74 * PARAMETERS : None 75 * 76 * RETURN : None 77 *==========================================================================*/ 78QCamera3PostProcessor::~QCamera3PostProcessor() 79{ 80 if (m_pJpegExifObj != NULL) { 81 delete m_pJpegExifObj; 82 m_pJpegExifObj = NULL; 83 } 84} 85 86/*=========================================================================== 87 * FUNCTION : init 88 * 89 * DESCRIPTION: initialization of postprocessor 90 * 91 * PARAMETERS : 92 * @jpeg_cb : callback to handle jpeg event from mm-camera-interface 93 * @user_data : user data ptr for jpeg callback 94 * 95 * RETURN : int32_t type of status 96 * NO_ERROR -- success 97 * none-zero failure code 98 *==========================================================================*/ 99int32_t QCamera3PostProcessor::init(jpeg_encode_callback_t jpeg_cb, void *user_data) 100{ 101 mJpegCB = jpeg_cb; 102 mJpegUserData = user_data; 103 104 mJpegClientHandle = jpeg_open(&mJpegHandle); 105 if(!mJpegClientHandle) { 106 ALOGE("%s : jpeg_open did not work", __func__); 107 return UNKNOWN_ERROR; 108 } 109 110 m_dataProcTh.launch(dataProcessRoutine, this); 111 112 return NO_ERROR; 113} 114 115/*=========================================================================== 116 * FUNCTION : deinit 117 * 118 * DESCRIPTION: de-initialization of postprocessor 119 * 120 * PARAMETERS : None 121 * 122 * RETURN : int32_t type of status 123 * NO_ERROR -- success 124 * none-zero failure code 125 *==========================================================================*/ 126int32_t QCamera3PostProcessor::deinit() 127{ 128 m_dataProcTh.exit(); 129 130 if(mJpegClientHandle > 0) { 131 int rc = mJpegHandle.close(mJpegClientHandle); 132 ALOGD("%s: Jpeg closed, rc = %d, mJpegClientHandle = %x", 133 __func__, rc, mJpegClientHandle); 134 mJpegClientHandle = 0; 135 memset(&mJpegHandle, 0, sizeof(mJpegHandle)); 136 } 137 138 return NO_ERROR; 139} 140 141/*=========================================================================== 142 * FUNCTION : start 143 * 144 * DESCRIPTION: start postprocessor. Data process thread and data notify thread 145 * will be launched. 146 * 147 * PARAMETERS : 148 * @pSrcChannel : source channel obj ptr that possibly needs reprocess 149 * 150 * RETURN : int32_t type of status 151 * NO_ERROR -- success 152 * none-zero failure code 153 * 154 * NOTE : if any reprocess is needed, a reprocess channel/stream 155 * will be started. 156 *==========================================================================*/ 157int32_t QCamera3PostProcessor::start(QCamera3Memory* mMemory, int index) 158{ 159 int32_t rc = NO_ERROR; 160 mJpegMem = mMemory; 161 mJpegMemIndex = index; 162 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE); 163 164 return rc; 165} 166 167/*=========================================================================== 168 * FUNCTION : stop 169 * 170 * DESCRIPTION: stop postprocessor. Data process and notify thread will be stopped. 171 * 172 * PARAMETERS : None 173 * 174 * RETURN : int32_t type of status 175 * NO_ERROR -- success 176 * none-zero failure code 177 * 178 * NOTE : reprocess channel will be stopped and deleted if there is any 179 *==========================================================================*/ 180int32_t QCamera3PostProcessor::stop() 181{ 182 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE); 183 184 return NO_ERROR; 185} 186 187/*=========================================================================== 188 * FUNCTION : getJpegEncodingConfig 189 * 190 * DESCRIPTION: function to prepare encoding job information 191 * 192 * PARAMETERS : 193 * @encode_parm : param to be filled with encoding configuration 194 * 195 * RETURN : int32_t type of status 196 * NO_ERROR -- success 197 * none-zero failure code 198 *==========================================================================*/ 199int32_t QCamera3PostProcessor::getJpegEncodingConfig(mm_jpeg_encode_params_t& encode_parm, 200 QCamera3Stream *main_stream, 201 QCamera3Stream *thumb_stream) 202{ 203 ALOGV("%s : E", __func__); 204 int32_t ret = NO_ERROR; 205 206 encode_parm.jpeg_cb = mJpegCB; 207 encode_parm.userdata = mJpegUserData; 208 209 m_bThumbnailNeeded = TRUE; // need encode thumbnail by default 210 cam_dimension_t thumbnailSize; 211 memset(&thumbnailSize, 0, sizeof(cam_dimension_t)); 212 m_parent->getThumbnailSize(thumbnailSize); 213 if (thumbnailSize.width == 0 && thumbnailSize.height == 0) { 214 // (0,0) means no thumbnail 215 m_bThumbnailNeeded = FALSE; 216 } 217 encode_parm.encode_thumbnail = m_bThumbnailNeeded; 218 219 // get color format 220 cam_format_t img_fmt = CAM_FORMAT_YUV_420_NV12; //default value 221 main_stream->getFormat(img_fmt); 222 encode_parm.color_format = getColorfmtFromImgFmt(img_fmt); 223 224 // get jpeg quality 225 encode_parm.quality = m_parent->getJpegQuality(); 226 if (encode_parm.quality <= 0) { 227 encode_parm.quality = 85; 228 } 229 230 // get exif data 231 if (m_pJpegExifObj != NULL) { 232 delete m_pJpegExifObj; 233 m_pJpegExifObj = NULL; 234 } 235 m_pJpegExifObj = m_parent->getExifData(); 236 if (m_pJpegExifObj != NULL) { 237 encode_parm.exif_info.exif_data = m_pJpegExifObj->getEntries(); 238 encode_parm.exif_info.numOfEntries = m_pJpegExifObj->getNumOfEntries(); 239 } 240 241 cam_frame_len_offset_t main_offset; 242 memset(&main_offset, 0, sizeof(cam_frame_len_offset_t)); 243 main_stream->getFrameOffset(main_offset); 244 245 // src buf config 246 //Pass input main image buffer info to encoder. 247 QCamera3Memory *pStreamMem = main_stream->getStreamBufs(); 248 if (pStreamMem == NULL) { 249 ALOGE("%s: cannot get stream bufs from main stream", __func__); 250 ret = BAD_VALUE; 251 goto on_error; 252 } 253 encode_parm.num_src_bufs = pStreamMem->getCnt(); 254 for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) { 255 if (pStreamMem != NULL) { 256 encode_parm.src_main_buf[i].index = i; 257 encode_parm.src_main_buf[i].buf_size = pStreamMem->getSize(i); 258 encode_parm.src_main_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i); 259 encode_parm.src_main_buf[i].fd = pStreamMem->getFd(i); 260 encode_parm.src_main_buf[i].format = MM_JPEG_FMT_YUV; 261 encode_parm.src_main_buf[i].offset = main_offset; 262 } 263 } 264 265 //Pass input thumbnail buffer info to encoder. 266 //Note: In this version thumb_stream = main_stream 267 if (m_bThumbnailNeeded == TRUE) { 268 if (thumb_stream == NULL) { 269 thumb_stream = main_stream; 270 } 271 pStreamMem = thumb_stream->getStreamBufs(); 272 if (pStreamMem == NULL) { 273 ALOGE("%s: cannot get stream bufs from thumb stream", __func__); 274 ret = BAD_VALUE; 275 goto on_error; 276 } 277 cam_frame_len_offset_t thumb_offset; 278 memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t)); 279 thumb_stream->getFrameOffset(thumb_offset); 280 encode_parm.num_tmb_bufs = pStreamMem->getCnt(); 281 for (int i = 0; i < pStreamMem->getCnt(); i++) { 282 if (pStreamMem != NULL) { 283 encode_parm.src_thumb_buf[i].index = i; 284 encode_parm.src_thumb_buf[i].buf_size = pStreamMem->getSize(i); 285 encode_parm.src_thumb_buf[i].buf_vaddr = (uint8_t *)pStreamMem->getPtr(i); 286 encode_parm.src_thumb_buf[i].fd = pStreamMem->getFd(i); 287 encode_parm.src_thumb_buf[i].format = MM_JPEG_FMT_YUV; 288 encode_parm.src_thumb_buf[i].offset = thumb_offset; 289 } 290 } 291 } 292 293 //Pass output jpeg buffer info to encoder. 294 //mJpegMem is allocated by framework. 295 encode_parm.num_dst_bufs = 1; 296 encode_parm.dest_buf[0].index = 0; 297 encode_parm.dest_buf[0].buf_size = mJpegMem->getSize(mJpegMemIndex); 298 encode_parm.dest_buf[0].buf_vaddr = (uint8_t *)mJpegMem->getPtr(mJpegMemIndex); 299 encode_parm.dest_buf[0].fd = mJpegMem->getFd(mJpegMemIndex); 300 encode_parm.dest_buf[0].format = MM_JPEG_FMT_YUV; 301 encode_parm.dest_buf[0].offset = main_offset; 302 303 ALOGV("%s : X", __func__); 304 return NO_ERROR; 305 306on_error: 307 if (m_pJpegExifObj != NULL) { 308 delete m_pJpegExifObj; 309 m_pJpegExifObj = NULL; 310 } 311 ALOGV("%s : X with error %d", __func__, ret); 312 return ret; 313} 314 315/*=========================================================================== 316 * FUNCTION : processData 317 * 318 * DESCRIPTION: enqueue data into dataProc thread 319 * 320 * PARAMETERS : 321 * @frame : process frame received from mm-camera-interface 322 * 323 * RETURN : int32_t type of status 324 * NO_ERROR -- success 325 * none-zero failure code 326 * 327 * NOTE : depends on if offline reprocess is needed, received frame will 328 * be sent to either input queue of postprocess or jpeg encoding 329 *==========================================================================*/ 330int32_t QCamera3PostProcessor::processData(mm_camera_super_buf_t *frame) 331{ 332 ALOGD("%s: no need offline reprocess, sending to jpeg encoding", __func__); 333 qcamera_jpeg_data_t *jpeg_job = 334 (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); 335 if (jpeg_job == NULL) { 336 ALOGE("%s: No memory for jpeg job", __func__); 337 return NO_MEMORY; 338 } 339 340 memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); 341 jpeg_job->src_frame = frame; 342 343 // enqueu to jpeg input queue 344 m_inputJpegQ.enqueue((void *)jpeg_job); 345 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); 346 347 return NO_ERROR; 348} 349 350/*=========================================================================== 351 * FUNCTION : processRawData 352 * 353 * DESCRIPTION: enqueue raw data into dataProc thread 354 * 355 * PARAMETERS : 356 * @frame : process frame received from mm-camera-interface 357 * 358 * RETURN : int32_t type of status 359 * NO_ERROR -- success 360 * none-zero failure code 361 *==========================================================================*/ 362int32_t QCamera3PostProcessor::processRawData(mm_camera_super_buf_t *frame) 363{ 364 // enqueu to raw input queue 365 m_inputRawQ.enqueue((void *)frame); 366 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); 367 return NO_ERROR; 368} 369 370/*=========================================================================== 371 * FUNCTION : processPPData 372 * 373 * DESCRIPTION: process received frame after reprocess. 374 * 375 * PARAMETERS : 376 * @frame : received frame from reprocess channel. 377 * 378 * RETURN : int32_t type of status 379 * NO_ERROR -- success 380 * none-zero failure code 381 * 382 * NOTE : The frame after reprocess need to send to jpeg encoding. 383 *==========================================================================*/ 384int32_t QCamera3PostProcessor::processPPData(mm_camera_super_buf_t *frame) 385{ 386 qcamera_pp_data_t *job = (qcamera_pp_data_t *)m_ongoingPPQ.dequeue(); 387 388 if (job == NULL || job->src_frame == NULL) { 389 ALOGE("%s: Cannot find reprocess job", __func__); 390 return BAD_VALUE; 391 } 392 393 qcamera_jpeg_data_t *jpeg_job = 394 (qcamera_jpeg_data_t *)malloc(sizeof(qcamera_jpeg_data_t)); 395 if (jpeg_job == NULL) { 396 ALOGE("%s: No memory for jpeg job", __func__); 397 return NO_MEMORY; 398 } 399 400 memset(jpeg_job, 0, sizeof(qcamera_jpeg_data_t)); 401 jpeg_job->src_frame = frame; 402 jpeg_job->src_reproc_frame = job->src_frame; 403 404 // free pp job buf 405 free(job); 406 407 // enqueu reprocessed frame to jpeg input queue 408 m_inputJpegQ.enqueue((void *)jpeg_job); 409 410 // wait up data proc thread 411 m_dataProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); 412 413 return NO_ERROR; 414} 415 416/*=========================================================================== 417 * FUNCTION : findJpegJobByJobId 418 * 419 * DESCRIPTION: find a jpeg job from ongoing Jpeg queue by its job ID 420 * 421 * PARAMETERS : 422 * @jobId : job Id of the job 423 * 424 * RETURN : ptr to a jpeg job struct. NULL if not found. 425 * 426 * NOTE : Currently only one job is sending to mm-jpeg-interface for jpeg 427 * encoding. Therefore simply dequeue from the ongoing Jpeg Queue 428 * will serve the purpose to find the jpeg job. 429 *==========================================================================*/ 430qcamera_jpeg_data_t *QCamera3PostProcessor::findJpegJobByJobId(uint32_t jobId) 431{ 432 qcamera_jpeg_data_t * job = NULL; 433 if (jobId == 0) { 434 ALOGE("%s: not a valid jpeg jobId", __func__); 435 return NULL; 436 } 437 438 // currely only one jpeg job ongoing, so simply dequeue the head 439 job = (qcamera_jpeg_data_t *)m_ongoingJpegQ.dequeue(); 440 return job; 441} 442 443/*=========================================================================== 444 * FUNCTION : releasePPInputData 445 * 446 * DESCRIPTION: callback function to release post process input data node 447 * 448 * PARAMETERS : 449 * @data : ptr to post process input data 450 * @user_data : user data ptr (QCamera3Reprocessor) 451 * 452 * RETURN : None 453 *==========================================================================*/ 454void QCamera3PostProcessor::releasePPInputData(void *data, void *user_data) 455{ 456 QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data; 457 if (NULL != pme) { 458 pme->releaseSuperBuf((mm_camera_super_buf_t *)data); 459 } 460} 461 462/*=========================================================================== 463 * FUNCTION : releaseJpegData 464 * 465 * DESCRIPTION: callback function to release jpeg job node 466 * 467 * PARAMETERS : 468 * @data : ptr to ongoing jpeg job data 469 * @user_data : user data ptr (QCamera3Reprocessor) 470 * 471 * RETURN : None 472 *==========================================================================*/ 473void QCamera3PostProcessor::releaseJpegData(void *data, void *user_data) 474{ 475 QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data; 476 if (NULL != pme) { 477 pme->releaseJpegJobData((qcamera_jpeg_data_t *)data); 478 } 479} 480 481/*=========================================================================== 482 * FUNCTION : releaseOngoingPPData 483 * 484 * DESCRIPTION: callback function to release ongoing postprocess job node 485 * 486 * PARAMETERS : 487 * @data : ptr to onging postprocess job 488 * @user_data : user data ptr (QCamera3Reprocessor) 489 * 490 * RETURN : None 491 *==========================================================================*/ 492void QCamera3PostProcessor::releaseOngoingPPData(void *data, void *user_data) 493{ 494 QCamera3PostProcessor *pme = (QCamera3PostProcessor *)user_data; 495 if (NULL != pme) { 496 qcamera_pp_data_t *pp_job = (qcamera_pp_data_t *)data; 497 if (NULL != pp_job->src_frame) { 498 pme->releaseSuperBuf(pp_job->src_frame); 499 free(pp_job->src_frame); 500 pp_job->src_frame = NULL; 501 } 502 } 503} 504 505/*=========================================================================== 506 * FUNCTION : releaseSuperBuf 507 * 508 * DESCRIPTION: function to release a superbuf frame by returning back to kernel 509 * 510 * PARAMETERS : 511 * @super_buf : ptr to the superbuf frame 512 * 513 * RETURN : None 514 *==========================================================================*/ 515void QCamera3PostProcessor::releaseSuperBuf(mm_camera_super_buf_t *super_buf) 516{ 517 if (NULL != super_buf) { 518 if (m_parent != NULL) { 519 m_parent->bufDone(super_buf); 520 } 521 } 522} 523 524/*=========================================================================== 525 * FUNCTION : releaseJpegJobData 526 * 527 * DESCRIPTION: function to release internal resources in jpeg job struct 528 * 529 * PARAMETERS : 530 * @job : ptr to jpeg job struct 531 * 532 * RETURN : None 533 * 534 * NOTE : original source frame need to be queued back to kernel for 535 * future use. Output buf of jpeg job need to be released since 536 * it's allocated for each job. Exif object need to be deleted. 537 *==========================================================================*/ 538void QCamera3PostProcessor::releaseJpegJobData(qcamera_jpeg_data_t *job) 539{ 540 ALOGV("%s: E", __func__); 541 if (NULL != job) { 542 if (NULL != job->src_reproc_frame) { 543 releaseSuperBuf(job->src_reproc_frame); 544 free(job->src_reproc_frame); 545 job->src_reproc_frame = NULL; 546 } 547 548 if (NULL != job->src_frame) { 549 releaseSuperBuf(job->src_frame); 550 free(job->src_frame); 551 job->src_frame = NULL; 552 } 553 mJpegMem = NULL; 554 } 555 ALOGV("%s: X", __func__); 556} 557 558/*=========================================================================== 559 * FUNCTION : getColorfmtFromImgFmt 560 * 561 * DESCRIPTION: function to return jpeg color format based on its image format 562 * 563 * PARAMETERS : 564 * @img_fmt : image format 565 * 566 * RETURN : jpeg color format that can be understandable by omx lib 567 *==========================================================================*/ 568mm_jpeg_color_format QCamera3PostProcessor::getColorfmtFromImgFmt(cam_format_t img_fmt) 569{ 570 switch (img_fmt) { 571 case CAM_FORMAT_YUV_420_NV21: 572 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; 573 case CAM_FORMAT_YUV_420_NV21_ADRENO: 574 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; 575 case CAM_FORMAT_YUV_420_NV12: 576 return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2; 577 case CAM_FORMAT_YUV_420_YV12: 578 return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2; 579 case CAM_FORMAT_YUV_422_NV61: 580 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1; 581 case CAM_FORMAT_YUV_422_NV16: 582 return MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1; 583 default: 584 return MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2; 585 } 586} 587 588/*=========================================================================== 589 * FUNCTION : getJpegImgTypeFromImgFmt 590 * 591 * DESCRIPTION: function to return jpeg encode image type based on its image format 592 * 593 * PARAMETERS : 594 * @img_fmt : image format 595 * 596 * RETURN : return jpeg source image format (YUV or Bitstream) 597 *==========================================================================*/ 598mm_jpeg_format_t QCamera3PostProcessor::getJpegImgTypeFromImgFmt(cam_format_t img_fmt) 599{ 600 switch (img_fmt) { 601 case CAM_FORMAT_YUV_420_NV21: 602 case CAM_FORMAT_YUV_420_NV21_ADRENO: 603 case CAM_FORMAT_YUV_420_NV12: 604 case CAM_FORMAT_YUV_420_YV12: 605 case CAM_FORMAT_YUV_422_NV61: 606 case CAM_FORMAT_YUV_422_NV16: 607 return MM_JPEG_FMT_YUV; 608 default: 609 return MM_JPEG_FMT_YUV; 610 } 611} 612 613/*=========================================================================== 614 * FUNCTION : encodeData 615 * 616 * DESCRIPTION: function to prepare encoding job information and send to 617 * mm-jpeg-interface to do the encoding job 618 * 619 * PARAMETERS : 620 * @jpeg_job_data : ptr to a struct saving job related information 621 * @needNewSess : flag to indicate if a new jpeg encoding session need 622 * to be created. After creation, this flag will be toggled 623 * 624 * RETURN : int32_t type of status 625 * NO_ERROR -- success 626 * none-zero failure code 627 *==========================================================================*/ 628int32_t QCamera3PostProcessor::encodeData(qcamera_jpeg_data_t *jpeg_job_data, 629 uint8_t &needNewSess) 630{ 631 ALOGV("%s : E", __func__); 632 int32_t ret = NO_ERROR; 633 mm_jpeg_job_t jpg_job; 634 uint32_t jobId = 0; 635 QCamera3Stream *main_stream = NULL; 636 mm_camera_buf_def_t *main_frame = NULL; 637 QCamera3Stream *thumb_stream = NULL; 638 mm_camera_buf_def_t *thumb_frame = NULL; 639 mm_camera_super_buf_t *recvd_frame = jpeg_job_data->src_frame; 640 641 // find channel 642 QCamera3Channel *pChannel = m_parent; 643 // check reprocess channel if not found 644 if (pChannel == NULL) { 645 ALOGE("%s: No corresponding channel (ch_id = %d) exist, return here", 646 __func__, recvd_frame->ch_id); 647 return BAD_VALUE; 648 } 649 650 // find snapshot frame and thumnail frame 651 //Note: In this version we will receive only snapshot frame. 652 for (int i = 0; i < recvd_frame->num_bufs; i++) { 653 QCamera3Stream *pStream = 654 pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id); 655 if (pStream != NULL) { 656 if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) || 657 pStream->isTypeOf(CAM_STREAM_TYPE_OFFLINE_PROC)) { 658 main_stream = pStream; 659 main_frame = recvd_frame->bufs[i]; 660 } else if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) || 661 pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW)) { 662 thumb_stream = pStream; 663 thumb_frame = recvd_frame->bufs[i]; 664 } 665 } 666 } 667 668 if(NULL == main_frame){ 669 ALOGE("%s : Main frame is NULL", __func__); 670 return BAD_VALUE; 671 } 672 673 QCamera3Memory *memObj = (QCamera3Memory *)main_frame->mem_info; 674 if (NULL == memObj) { 675 ALOGE("%s : Memeory Obj of main frame is NULL", __func__); 676 return NO_MEMORY; 677 } 678 679 // clean and invalidate cache ops through mem obj of the frame 680 memObj->cleanInvalidateCache(main_frame->buf_idx); 681 682 if (thumb_frame != NULL) { 683 QCamera3Memory *thumb_memObj = (QCamera3Memory *)thumb_frame->mem_info; 684 if (NULL != thumb_memObj) { 685 // clean and invalidate cache ops through mem obj of the frame 686 thumb_memObj->cleanInvalidateCache(thumb_frame->buf_idx); 687 } 688 } 689 690 if (mJpegClientHandle <= 0) { 691 ALOGE("%s: Error: bug here, mJpegClientHandle is 0", __func__); 692 return UNKNOWN_ERROR; 693 } 694 695 ALOGD("%s: Need new session?:%d",__func__, needNewSess); 696 if (needNewSess) { 697 // create jpeg encoding session 698 mm_jpeg_encode_params_t encodeParam; 699 memset(&encodeParam, 0, sizeof(mm_jpeg_encode_params_t)); 700 701 getJpegEncodingConfig(encodeParam, main_stream, thumb_stream); 702 ALOGD("%s: #src bufs:%d # tmb bufs:%d #dst_bufs:%d", __func__, 703 encodeParam.num_src_bufs,encodeParam.num_tmb_bufs,encodeParam.num_dst_bufs); 704 ret = mJpegHandle.create_session(mJpegClientHandle, &encodeParam, &mJpegSessionId); 705 if (ret != NO_ERROR) { 706 ALOGE("%s: error creating a new jpeg encoding session", __func__); 707 return ret; 708 } 709 needNewSess = FALSE; 710 } 711 712 // Fill in new job 713 memset(&jpg_job, 0, sizeof(mm_jpeg_job_t)); 714 jpg_job.job_type = JPEG_JOB_TYPE_ENCODE; 715 jpg_job.encode_job.session_id = mJpegSessionId; 716 jpg_job.encode_job.src_index = main_frame->buf_idx; 717 jpg_job.encode_job.dst_index = 0; 718 719 cam_rect_t crop; 720 memset(&crop, 0, sizeof(cam_rect_t)); 721 //TBD_later - Zoom event removed in stream 722 //main_stream->getCropInfo(crop); 723 724 cam_dimension_t src_dim; 725 memset(&src_dim, 0, sizeof(cam_dimension_t)); 726 main_stream->getFrameDimension(src_dim); 727 728 // main dim 729 jpg_job.encode_job.main_dim.src_dim = src_dim; 730 jpg_job.encode_job.main_dim.dst_dim = src_dim; 731 jpg_job.encode_job.main_dim.crop = crop; 732 733 // thumbnail dim 734 ALOGD("%s: Thumbnail needed:%d",__func__, m_bThumbnailNeeded); 735 if (m_bThumbnailNeeded == TRUE) { 736 if (thumb_stream == NULL) { 737 // need jpeg thumbnail, but no postview/preview stream exists 738 // we use the main stream/frame to encode thumbnail 739 thumb_stream = main_stream; 740 thumb_frame = main_frame; 741 } 742 memset(&crop, 0, sizeof(cam_rect_t)); 743 //TBD_later - Zoom event removed in stream 744 //thumb_stream->getCropInfo(crop); 745 memset(&src_dim, 0, sizeof(cam_dimension_t)); 746 thumb_stream->getFrameDimension(src_dim); 747 jpg_job.encode_job.thumb_dim.src_dim = src_dim; 748 m_parent->getThumbnailSize(jpg_job.encode_job.thumb_dim.dst_dim); 749 jpg_job.encode_job.thumb_dim.crop = crop; 750 jpg_job.encode_job.thumb_index = thumb_frame->buf_idx; 751 } 752 753 // set rotation only when no online rotation or offline pp rotation is done before 754 755 if (!m_parent->needOnlineRotation()) { 756 jpg_job.encode_job.rotation = m_parent->getJpegRotation(); 757 } 758 ALOGV("%s: jpeg rotation is set to %d", __func__, jpg_job.encode_job.rotation); 759 760 // Find meta data frame. Meta data frame contains additional exif info 761 // which will be extracted and filled in by encoder. 762 //Note: In this version meta data will be null 763 //as we don't support bundling of snapshot and metadata streams. 764 765 mm_camera_buf_def_t *meta_frame = NULL; 766 for (int i = 0; i < jpeg_job_data->src_frame->num_bufs; i++) { 767 // look through input superbuf 768 if (jpeg_job_data->src_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) { 769 meta_frame = jpeg_job_data->src_frame->bufs[i]; 770 break; 771 } 772 } 773 if (meta_frame == NULL && jpeg_job_data->src_reproc_frame != NULL) { 774 // look through reprocess source superbuf 775 for (int i = 0; i < jpeg_job_data->src_reproc_frame->num_bufs; i++) { 776 if (jpeg_job_data->src_reproc_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_METADATA) { 777 meta_frame = jpeg_job_data->src_reproc_frame->bufs[i]; 778 break; 779 } 780 } 781 } 782 if (meta_frame != NULL) { 783 // fill in meta data frame ptr 784 jpg_job.encode_job.p_metadata = (cam_metadata_info_t *)meta_frame->buffer; 785 } 786 787 //Start jpeg encoding 788 ret = mJpegHandle.start_job(&jpg_job, &jobId); 789 if (ret == NO_ERROR) { 790 // remember job info 791 jpeg_job_data->jobId = jobId; 792 } 793 794 ALOGV("%s : X", __func__); 795 return ret; 796} 797 798/*=========================================================================== 799 * FUNCTION : dataProcessRoutine 800 * 801 * DESCRIPTION: data process routine that handles input data either from input 802 * Jpeg Queue to do jpeg encoding, or from input PP Queue to do 803 * reprocess. 804 * 805 * PARAMETERS : 806 * @data : user data ptr (QCamera3PostProcessor) 807 * 808 * RETURN : None 809 *==========================================================================*/ 810void *QCamera3PostProcessor::dataProcessRoutine(void *data) 811{ 812 int running = 1; 813 int ret; 814 uint8_t is_active = FALSE; 815 uint8_t needNewSess = TRUE; 816 ALOGV("%s: E", __func__); 817 QCamera3PostProcessor *pme = (QCamera3PostProcessor *)data; 818 QCameraCmdThread *cmdThread = &pme->m_dataProcTh; 819 820 do { 821 do { 822 ret = cam_sem_wait(&cmdThread->cmd_sem); 823 if (ret != 0 && errno != EINVAL) { 824 ALOGE("%s: cam_sem_wait error (%s)", 825 __func__, strerror(errno)); 826 return NULL; 827 } 828 } while (ret != 0); 829 830 // we got notified about new cmd avail in cmd queue 831 camera_cmd_type_t cmd = cmdThread->getCmd(); 832 switch (cmd) { 833 case CAMERA_CMD_TYPE_START_DATA_PROC: 834 ALOGD("%s: start data proc", __func__); 835 is_active = TRUE; 836 needNewSess = TRUE; 837 break; 838 case CAMERA_CMD_TYPE_STOP_DATA_PROC: 839 { 840 ALOGD("%s: stop data proc", __func__); 841 is_active = FALSE; 842 843 // cancel all ongoing jpeg jobs 844 qcamera_jpeg_data_t *jpeg_job = 845 (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(); 846 while (jpeg_job != NULL) { 847 pme->mJpegHandle.abort_job(jpeg_job->jobId); 848 849 pme->releaseJpegJobData(jpeg_job); 850 free(jpeg_job); 851 852 jpeg_job = (qcamera_jpeg_data_t *)pme->m_ongoingJpegQ.dequeue(); 853 } 854 855 // destroy jpeg encoding session 856 if ( 0 < pme->mJpegSessionId ) { 857 pme->mJpegHandle.destroy_session(pme->mJpegSessionId); 858 pme->mJpegSessionId = 0; 859 } 860 861 // free jpeg exif obj 862 if (pme->m_pJpegExifObj != NULL) { 863 delete pme->m_pJpegExifObj; 864 pme->m_pJpegExifObj = NULL; 865 } 866 needNewSess = TRUE; 867 868 // flush ongoing postproc Queue 869 pme->m_ongoingPPQ.flush(); 870 871 // flush input jpeg Queue 872 pme->m_inputJpegQ.flush(); 873 874 // flush input Postproc Queue 875 pme->m_inputPPQ.flush(); 876 877 // flush input raw Queue 878 pme->m_inputRawQ.flush(); 879 880 // signal cmd is completed 881 cam_sem_post(&cmdThread->sync_sem); 882 } 883 break; 884 case CAMERA_CMD_TYPE_DO_NEXT_JOB: 885 { 886 ALOGD("%s: Do next job, active is %d", __func__, is_active); 887 if (is_active == TRUE) { 888 // check if there is any ongoing jpeg jobs 889 if (pme->m_ongoingJpegQ.isEmpty()) { 890 // no ongoing jpeg job, we are fine to send jpeg encoding job 891 qcamera_jpeg_data_t *jpeg_job = 892 (qcamera_jpeg_data_t *)pme->m_inputJpegQ.dequeue(); 893 894 if (NULL != jpeg_job) { 895 //TBD_later - play shutter sound 896 //pme->m_parent->playShutter(); 897 898 // add into ongoing jpeg job Q 899 pme->m_ongoingJpegQ.enqueue((void *)jpeg_job); 900 ret = pme->encodeData(jpeg_job, needNewSess); 901 if (NO_ERROR != ret) { 902 // dequeue the last one 903 pme->m_ongoingJpegQ.dequeue(false); 904 905 pme->releaseJpegJobData(jpeg_job); 906 free(jpeg_job); 907 } 908 } 909 } 910 911 mm_camera_super_buf_t *pp_frame = 912 (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue(); 913 if (NULL != pp_frame) { 914 qcamera_pp_data_t *pp_job = 915 (qcamera_pp_data_t *)malloc(sizeof(qcamera_pp_data_t)); 916 if (pp_job != NULL) { 917 memset(pp_job, 0, sizeof(qcamera_pp_data_t)); 918 } else { 919 ALOGE("%s: no mem for qcamera_pp_data_t", __func__); 920 ret = -1; 921 } 922 923 if (0 != ret) { 924 // free pp_job 925 if (pp_job != NULL) { 926 free(pp_job); 927 } 928 // free frame 929 if (pp_frame != NULL) { 930 pme->releaseSuperBuf(pp_frame); 931 free(pp_frame); 932 } 933 } 934 } 935 } else { 936 // not active, simply return buf and do no op 937 mm_camera_super_buf_t *super_buf = 938 (mm_camera_super_buf_t *)pme->m_inputJpegQ.dequeue(); 939 if (NULL != super_buf) { 940 pme->releaseSuperBuf(super_buf); 941 free(super_buf); 942 } 943 super_buf = (mm_camera_super_buf_t *)pme->m_inputRawQ.dequeue(); 944 if (NULL != super_buf) { 945 pme->releaseSuperBuf(super_buf); 946 free(super_buf); 947 } 948 super_buf = (mm_camera_super_buf_t *)pme->m_inputPPQ.dequeue(); 949 if (NULL != super_buf) { 950 pme->releaseSuperBuf(super_buf); 951 free(super_buf); 952 } 953 } 954 } 955 break; 956 case CAMERA_CMD_TYPE_EXIT: 957 running = 0; 958 break; 959 default: 960 break; 961 } 962 } while (running); 963 ALOGV("%s: X", __func__); 964 return NULL; 965} 966 967/*=========================================================================== 968 * FUNCTION : getJpegPaddingReq 969 * 970 * DESCRIPTION: function to add an entry to exif data 971 * 972 * PARAMETERS : 973 * @padding_info : jpeg specific padding requirement 974 * 975 * RETURN : int32_t type of status 976 * NO_ERROR -- success 977 * none-zero failure code 978 *==========================================================================*/ 979int32_t QCamera3PostProcessor::getJpegPaddingReq(cam_padding_info_t &padding_info) 980{ 981 // TODO: hardcode for now, needs to query from mm-jpeg-interface 982 padding_info.width_padding = CAM_PAD_NONE; 983 padding_info.height_padding = CAM_PAD_TO_16; 984 padding_info.plane_padding = CAM_PAD_TO_WORD; 985 return NO_ERROR; 986} 987 988/*=========================================================================== 989 * FUNCTION : QCamera3Exif 990 * 991 * DESCRIPTION: constructor of QCamera3Exif 992 * 993 * PARAMETERS : None 994 * 995 * RETURN : None 996 *==========================================================================*/ 997QCamera3Exif::QCamera3Exif() 998 : m_nNumEntries(0) 999{ 1000 memset(m_Entries, 0, sizeof(m_Entries)); 1001} 1002 1003/*=========================================================================== 1004 * FUNCTION : ~QCamera3Exif 1005 * 1006 * DESCRIPTION: deconstructor of QCamera3Exif. Will release internal memory ptr. 1007 * 1008 * PARAMETERS : None 1009 * 1010 * RETURN : None 1011 *==========================================================================*/ 1012QCamera3Exif::~QCamera3Exif() 1013{ 1014 for (uint32_t i = 0; i < m_nNumEntries; i++) { 1015 switch (m_Entries[i].tag_entry.type) { 1016 case EXIF_BYTE: 1017 { 1018 if (m_Entries[i].tag_entry.count > 1 && 1019 m_Entries[i].tag_entry.data._bytes != NULL) { 1020 free(m_Entries[i].tag_entry.data._bytes); 1021 m_Entries[i].tag_entry.data._bytes = NULL; 1022 } 1023 } 1024 break; 1025 case EXIF_ASCII: 1026 { 1027 if (m_Entries[i].tag_entry.data._ascii != NULL) { 1028 free(m_Entries[i].tag_entry.data._ascii); 1029 m_Entries[i].tag_entry.data._ascii = NULL; 1030 } 1031 } 1032 break; 1033 case EXIF_SHORT: 1034 { 1035 if (m_Entries[i].tag_entry.count > 1 && 1036 m_Entries[i].tag_entry.data._shorts != NULL) { 1037 free(m_Entries[i].tag_entry.data._shorts); 1038 m_Entries[i].tag_entry.data._shorts = NULL; 1039 } 1040 } 1041 break; 1042 case EXIF_LONG: 1043 { 1044 if (m_Entries[i].tag_entry.count > 1 && 1045 m_Entries[i].tag_entry.data._longs != NULL) { 1046 free(m_Entries[i].tag_entry.data._longs); 1047 m_Entries[i].tag_entry.data._longs = NULL; 1048 } 1049 } 1050 break; 1051 case EXIF_RATIONAL: 1052 { 1053 if (m_Entries[i].tag_entry.count > 1 && 1054 m_Entries[i].tag_entry.data._rats != NULL) { 1055 free(m_Entries[i].tag_entry.data._rats); 1056 m_Entries[i].tag_entry.data._rats = NULL; 1057 } 1058 } 1059 break; 1060 case EXIF_UNDEFINED: 1061 { 1062 if (m_Entries[i].tag_entry.data._undefined != NULL) { 1063 free(m_Entries[i].tag_entry.data._undefined); 1064 m_Entries[i].tag_entry.data._undefined = NULL; 1065 } 1066 } 1067 break; 1068 case EXIF_SLONG: 1069 { 1070 if (m_Entries[i].tag_entry.count > 1 && 1071 m_Entries[i].tag_entry.data._slongs != NULL) { 1072 free(m_Entries[i].tag_entry.data._slongs); 1073 m_Entries[i].tag_entry.data._slongs = NULL; 1074 } 1075 } 1076 break; 1077 case EXIF_SRATIONAL: 1078 { 1079 if (m_Entries[i].tag_entry.count > 1 && 1080 m_Entries[i].tag_entry.data._srats != NULL) { 1081 free(m_Entries[i].tag_entry.data._srats); 1082 m_Entries[i].tag_entry.data._srats = NULL; 1083 } 1084 } 1085 break; 1086 default: 1087 ALOGE("%s: Error, Unknown type",__func__); 1088 break; 1089 } 1090 } 1091} 1092 1093/*=========================================================================== 1094 * FUNCTION : addEntry 1095 * 1096 * DESCRIPTION: function to add an entry to exif data 1097 * 1098 * PARAMETERS : 1099 * @tagid : exif tag ID 1100 * @type : data type 1101 * @count : number of data in uint of its type 1102 * @data : input data ptr 1103 * 1104 * RETURN : int32_t type of status 1105 * NO_ERROR -- success 1106 * none-zero failure code 1107 *==========================================================================*/ 1108int32_t QCamera3Exif::addEntry(exif_tag_id_t tagid, 1109 exif_tag_type_t type, 1110 uint32_t count, 1111 void *data) 1112{ 1113 int32_t rc = NO_ERROR; 1114 if(m_nNumEntries >= MAX_EXIF_TABLE_ENTRIES) { 1115 ALOGE("%s: Number of entries exceeded limit", __func__); 1116 return NO_MEMORY; 1117 } 1118 1119 m_Entries[m_nNumEntries].tag_id = tagid; 1120 m_Entries[m_nNumEntries].tag_entry.type = type; 1121 m_Entries[m_nNumEntries].tag_entry.count = count; 1122 m_Entries[m_nNumEntries].tag_entry.copy = 1; 1123 switch (type) { 1124 case EXIF_BYTE: 1125 { 1126 if (count > 1) { 1127 uint8_t *values = (uint8_t *)malloc(count); 1128 if (values == NULL) { 1129 ALOGE("%s: No memory for byte array", __func__); 1130 rc = NO_MEMORY; 1131 } else { 1132 memcpy(values, data, count); 1133 m_Entries[m_nNumEntries].tag_entry.data._bytes = values; 1134 } 1135 } else { 1136 m_Entries[m_nNumEntries].tag_entry.data._byte = 1137 *(uint8_t *)data; 1138 } 1139 } 1140 break; 1141 case EXIF_ASCII: 1142 { 1143 char *str = NULL; 1144 str = (char *)malloc(count + 1); 1145 if (str == NULL) { 1146 ALOGE("%s: No memory for ascii string", __func__); 1147 rc = NO_MEMORY; 1148 } else { 1149 memset(str, 0, count + 1); 1150 memcpy(str, data, count); 1151 m_Entries[m_nNumEntries].tag_entry.data._ascii = str; 1152 } 1153 } 1154 break; 1155 case EXIF_SHORT: 1156 { 1157 if (count > 1) { 1158 uint16_t *values = 1159 (uint16_t *)malloc(count * sizeof(uint16_t)); 1160 if (values == NULL) { 1161 ALOGE("%s: No memory for short array", __func__); 1162 rc = NO_MEMORY; 1163 } else { 1164 memcpy(values, data, count * sizeof(uint16_t)); 1165 m_Entries[m_nNumEntries].tag_entry.data._shorts =values; 1166 } 1167 } else { 1168 m_Entries[m_nNumEntries].tag_entry.data._short = 1169 *(uint16_t *)data; 1170 } 1171 } 1172 break; 1173 case EXIF_LONG: 1174 { 1175 if (count > 1) { 1176 uint32_t *values = 1177 (uint32_t *)malloc(count * sizeof(uint32_t)); 1178 if (values == NULL) { 1179 ALOGE("%s: No memory for long array", __func__); 1180 rc = NO_MEMORY; 1181 } else { 1182 memcpy(values, data, count * sizeof(uint32_t)); 1183 m_Entries[m_nNumEntries].tag_entry.data._longs = values; 1184 } 1185 } else { 1186 m_Entries[m_nNumEntries].tag_entry.data._long = 1187 *(uint32_t *)data; 1188 } 1189 } 1190 break; 1191 case EXIF_RATIONAL: 1192 { 1193 if (count > 1) { 1194 rat_t *values = (rat_t *)malloc(count * sizeof(rat_t)); 1195 if (values == NULL) { 1196 ALOGE("%s: No memory for rational array", __func__); 1197 rc = NO_MEMORY; 1198 } else { 1199 memcpy(values, data, count * sizeof(rat_t)); 1200 m_Entries[m_nNumEntries].tag_entry.data._rats = values; 1201 } 1202 } else { 1203 m_Entries[m_nNumEntries].tag_entry.data._rat = 1204 *(rat_t *)data; 1205 } 1206 } 1207 break; 1208 case EXIF_UNDEFINED: 1209 { 1210 uint8_t *values = (uint8_t *)malloc(count); 1211 if (values == NULL) { 1212 ALOGE("%s: No memory for undefined array", __func__); 1213 rc = NO_MEMORY; 1214 } else { 1215 memcpy(values, data, count); 1216 m_Entries[m_nNumEntries].tag_entry.data._undefined = values; 1217 } 1218 } 1219 break; 1220 case EXIF_SLONG: 1221 { 1222 if (count > 1) { 1223 int32_t *values = 1224 (int32_t *)malloc(count * sizeof(int32_t)); 1225 if (values == NULL) { 1226 ALOGE("%s: No memory for signed long array", __func__); 1227 rc = NO_MEMORY; 1228 } else { 1229 memcpy(values, data, count * sizeof(int32_t)); 1230 m_Entries[m_nNumEntries].tag_entry.data._slongs =values; 1231 } 1232 } else { 1233 m_Entries[m_nNumEntries].tag_entry.data._slong = 1234 *(int32_t *)data; 1235 } 1236 } 1237 break; 1238 case EXIF_SRATIONAL: 1239 { 1240 if (count > 1) { 1241 srat_t *values = (srat_t *)malloc(count * sizeof(srat_t)); 1242 if (values == NULL) { 1243 ALOGE("%s: No memory for sign rational array",__func__); 1244 rc = NO_MEMORY; 1245 } else { 1246 memcpy(values, data, count * sizeof(srat_t)); 1247 m_Entries[m_nNumEntries].tag_entry.data._srats = values; 1248 } 1249 } else { 1250 m_Entries[m_nNumEntries].tag_entry.data._srat = 1251 *(srat_t *)data; 1252 } 1253 } 1254 break; 1255 default: 1256 ALOGE("%s: Error, Unknown type",__func__); 1257 break; 1258 } 1259 1260 // Increase number of entries 1261 m_nNumEntries++; 1262 return rc; 1263} 1264 1265}; // namespace qcamera 1266