Home | History | Annotate | Download | only in camera
      1 /*
      2 ** Copyright (c) 2011 The Linux Foundation. All rights reserved.
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 /*#error uncomment this for compiler test!*/
     18 
     19 //#define ALOG_NDEBUG 0
     20 #define ALOG_NIDEBUG 0
     21 #define LOG_TAG "QCameraHWI_Record"
     22 #include <utils/Log.h>
     23 #include <utils/threads.h>
     24 #include <cutils/properties.h>
     25 #include <fcntl.h>
     26 #include <sys/mman.h>
     27 
     28 #include "QCameraStream.h"
     29 
     30 #define LIKELY(exp)   __builtin_expect(!!(exp), 1)
     31 #define UNLIKELY(exp) __builtin_expect(!!(exp), 0)
     32 
     33 /* QCameraStream_record class implementation goes here*/
     34 /* following code implement the video streaming capture & encoding logic of this class*/
     35 // ---------------------------------------------------------------------------
     36 // QCameraStream_record createInstance()
     37 // ---------------------------------------------------------------------------
     38 namespace android {
     39 
     40 
     41 QCameraStream* QCameraStream_record::createInstance(int cameraId,
     42                                       camera_mode_t mode)
     43 {
     44   ALOGV("%s: BEGIN", __func__);
     45   QCameraStream* pme = new QCameraStream_record(cameraId, mode);
     46   ALOGV("%s: END", __func__);
     47   return pme;
     48 }
     49 
     50 // ---------------------------------------------------------------------------
     51 // QCameraStream_record deleteInstance()
     52 // ---------------------------------------------------------------------------
     53 void QCameraStream_record::deleteInstance(QCameraStream *ptr)
     54 {
     55   ALOGV("%s: BEGIN", __func__);
     56   if (ptr){
     57     ptr->release();
     58     delete ptr;
     59     ptr = NULL;
     60   }
     61   ALOGV("%s: END", __func__);
     62 }
     63 
     64 // ---------------------------------------------------------------------------
     65 // QCameraStream_record Constructor
     66 // ---------------------------------------------------------------------------
     67 QCameraStream_record::QCameraStream_record(int cameraId,
     68                                            camera_mode_t mode)
     69   :QCameraStream(cameraId,mode),
     70   mDebugFps(false)
     71 {
     72   mHalCamCtrl = NULL;
     73   char value[PROPERTY_VALUE_MAX];
     74   ALOGV("%s: BEGIN", __func__);
     75 
     76   property_get("persist.debug.sf.showfps", value, "0");
     77   mDebugFps = atoi(value);
     78 
     79   ALOGV("%s: END", __func__);
     80 }
     81 
     82 // ---------------------------------------------------------------------------
     83 // QCameraStream_record Destructor
     84 // ---------------------------------------------------------------------------
     85 QCameraStream_record::~QCameraStream_record() {
     86   ALOGV("%s: BEGIN", __func__);
     87   if(mActive) {
     88     stop();
     89   }
     90   if(mInit) {
     91     release();
     92   }
     93   mInit = false;
     94   mActive = false;
     95   ALOGV("%s: END", __func__);
     96 
     97 }
     98 
     99 // ---------------------------------------------------------------------------
    100 // QCameraStream_record Callback from mm_camera
    101 // ---------------------------------------------------------------------------
    102 static void record_notify_cb(mm_camera_ch_data_buf_t *bufs_new,
    103                               void *user_data)
    104 {
    105   QCameraStream_record *pme = (QCameraStream_record *)user_data;
    106   mm_camera_ch_data_buf_t *bufs_used = 0;
    107   ALOGV("%s: BEGIN", __func__);
    108 
    109   /*
    110   * Call Function Process Video Data
    111   */
    112   pme->processRecordFrame(bufs_new);
    113   ALOGV("%s: END", __func__);
    114 }
    115 
    116 // ---------------------------------------------------------------------------
    117 // QCameraStream_record
    118 // ---------------------------------------------------------------------------
    119 status_t QCameraStream_record::init()
    120 {
    121   status_t ret = NO_ERROR;
    122   ALOGV("%s: BEGIN", __func__);
    123 
    124   /*
    125   *  Acquiring Video Channel
    126   */
    127   ret = QCameraStream::initChannel (mCameraId, MM_CAMERA_CH_VIDEO_MASK);
    128   if (NO_ERROR!=ret) {
    129     ALOGE("%s ERROR: Can't init native cammera preview ch\n",__func__);
    130     return ret;
    131   }
    132 
    133   /*
    134   * Register the Callback with camera
    135   */
    136   (void) cam_evt_register_buf_notify(mCameraId, MM_CAMERA_CH_VIDEO,
    137                                             record_notify_cb,
    138                                             MM_CAMERA_REG_BUF_CB_INFINITE,
    139                                             0,
    140                                             this);
    141 
    142   mInit = true;
    143   ALOGV("%s: END", __func__);
    144   return ret;
    145 }
    146 // ---------------------------------------------------------------------------
    147 // QCameraStream_record
    148 // ---------------------------------------------------------------------------
    149 
    150 status_t QCameraStream_record::start()
    151 {
    152   status_t ret = NO_ERROR;
    153   ALOGV("%s: BEGIN", __func__);
    154 
    155   Mutex::Autolock lock(mStopCallbackLock);
    156   if(!mInit) {
    157     ALOGE("%s ERROR: Record buffer not registered",__func__);
    158     return BAD_VALUE;
    159   }
    160 
    161   setFormat(MM_CAMERA_CH_VIDEO_MASK , (cam_format_t)0);
    162   //mRecordFreeQueueLock.lock();
    163   //mRecordFreeQueue.clear();
    164   //mRecordFreeQueueLock.unlock();
    165   /*
    166   *  Allocating Encoder Frame Buffers
    167   */
    168   ret = initEncodeBuffers();
    169   if (NO_ERROR!=ret) {
    170     ALOGE("%s ERROR: Buffer Allocation Failed\n",__func__);
    171     goto error;
    172   }
    173 
    174   ret = cam_config_prepare_buf(mCameraId, &mRecordBuf);
    175   if(ret != MM_CAMERA_OK) {
    176     ALOGE("%s ERROR: Reg Record buf err=%d\n", __func__, ret);
    177     ret = BAD_VALUE;
    178     goto error;
    179   }else{
    180     ret = NO_ERROR;
    181   }
    182 
    183   /*
    184   * Start Video Streaming
    185   */
    186   ret = cam_ops_action(mCameraId, true, MM_CAMERA_OPS_VIDEO, 0);
    187   if (MM_CAMERA_OK != ret) {
    188     ALOGE ("%s ERROR: Video streaming start err=%d\n", __func__, ret);
    189     ret = BAD_VALUE;
    190     goto error;
    191   }else{
    192     ALOGV("%s : Video streaming Started",__func__);
    193     ret = NO_ERROR;
    194   }
    195   mActive = true;
    196   ALOGV("%s: END", __func__);
    197   return ret;
    198 
    199 error:
    200   releaseEncodeBuffer();
    201   ALOGV("%s: END", __func__);
    202   return ret;
    203 }
    204 
    205 void QCameraStream_record::releaseEncodeBuffer() {
    206   for(int cnt = 0; cnt < mHalCamCtrl->mRecordingMemory.buffer_count; cnt++) {
    207     if (NO_ERROR !=
    208       mHalCamCtrl->sendUnMappingBuf(MSM_V4L2_EXT_CAPTURE_MODE_VIDEO, cnt,
    209       mCameraId, CAM_SOCK_MSG_TYPE_FD_UNMAPPING))
    210       ALOGE("%s: Unmapping Video Data Failed", __func__);
    211 
    212     if (mHalCamCtrl->mStoreMetaDataInFrame) {
    213       struct encoder_media_buffer_type * packet =
    214           (struct encoder_media_buffer_type  *)
    215           mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->data;
    216       native_handle_delete(const_cast<native_handle_t *>(packet->meta_handle));
    217       mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->release(
    218         mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]);
    219 
    220     }
    221     mHalCamCtrl->mRecordingMemory.camera_memory[cnt]->release(
    222       mHalCamCtrl->mRecordingMemory.camera_memory[cnt]);
    223     close(mHalCamCtrl->mRecordingMemory.fd[cnt]);
    224     mHalCamCtrl->mRecordingMemory.fd[cnt] = -1;
    225 
    226 #ifdef USE_ION
    227     mHalCamCtrl->deallocate_ion_memory(&mHalCamCtrl->mRecordingMemory, cnt);
    228 #endif
    229   }
    230   memset(&mHalCamCtrl->mRecordingMemory, 0, sizeof(mHalCamCtrl->mRecordingMemory));
    231   //mNumRecordFrames = 0;
    232   delete[] recordframes;
    233   if (mRecordBuf.video.video.buf.mp)
    234     delete[] mRecordBuf.video.video.buf.mp;
    235 }
    236 
    237 // ---------------------------------------------------------------------------
    238 // QCameraStream_record
    239 // ---------------------------------------------------------------------------
    240 void QCameraStream_record::stop()
    241 {
    242   status_t ret = NO_ERROR;
    243   ALOGV("%s: BEGIN", __func__);
    244 
    245   if(!mActive) {
    246     ALOGE("%s : Record stream not started",__func__);
    247     return;
    248   }
    249   mActive =  false;
    250   Mutex::Autolock lock(mStopCallbackLock);
    251 #if 0 //mzhu, when stop recording, all frame will be dirty. no need to queue frame back to kernel any more
    252   mRecordFreeQueueLock.lock();
    253   while(!mRecordFreeQueue.isEmpty()) {
    254     ALOGV("%s : Pre-releasing of Encoder buffers!\n", __FUNCTION__);
    255     mm_camera_ch_data_buf_t releasedBuf = mRecordFreeQueue.itemAt(0);
    256     mRecordFreeQueue.removeAt(0);
    257     mRecordFreeQueueLock.unlock();
    258     ALOGV("%s (%d): releasedBuf.idx = %d\n", __FUNCTION__, __LINE__,
    259                                               releasedBuf.video.video.idx);
    260     if(MM_CAMERA_OK != cam_evt_buf_done(mCameraId,&releasedBuf))
    261         ALOGE("%s : Buf Done Failed",__func__);
    262   }
    263   mRecordFreeQueueLock.unlock();
    264 #if 0
    265   while (!mRecordFreeQueue.isEmpty()) {
    266         ALOGE("%s : Waiting for Encoder to release all buffer!\n", __FUNCTION__);
    267   }
    268 #endif
    269 #endif // mzhu
    270   /* unregister the notify fn from the mmmm_camera_t object
    271    *  call stop() in parent class to stop the monitor thread */
    272 
    273   ret = cam_ops_action(mCameraId, false, MM_CAMERA_OPS_VIDEO, 0);
    274   if (MM_CAMERA_OK != ret) {
    275     ALOGE ("%s ERROR: Video streaming Stop err=%d\n", __func__, ret);
    276   }
    277 
    278   ret = cam_config_unprepare_buf(mCameraId, MM_CAMERA_CH_VIDEO);
    279   if(ret != MM_CAMERA_OK){
    280     ALOGE("%s ERROR: Ureg video buf \n", __func__);
    281   }
    282 
    283   releaseEncodeBuffer();
    284 
    285   mActive = false;
    286   ALOGV("%s: END", __func__);
    287 
    288 }
    289 // ---------------------------------------------------------------------------
    290 // QCameraStream_record
    291 // ---------------------------------------------------------------------------
    292 void QCameraStream_record::release()
    293 {
    294   status_t ret = NO_ERROR;
    295   ALOGV("%s: BEGIN", __func__);
    296 
    297   if(mActive) {
    298     stop();
    299   }
    300   if(!mInit) {
    301     ALOGE("%s : Record stream not initialized",__func__);
    302     return;
    303   }
    304 
    305   ret= QCameraStream::deinitChannel(mCameraId, MM_CAMERA_CH_VIDEO);
    306   if(ret != MM_CAMERA_OK) {
    307     ALOGE("%s:Deinit Video channel failed=%d\n", __func__, ret);
    308   }
    309   (void)cam_evt_register_buf_notify(mCameraId, MM_CAMERA_CH_VIDEO,
    310                                             NULL,
    311                                             (mm_camera_register_buf_cb_type_t)NULL,
    312                                             NULL,
    313                                             NULL);
    314   mInit = false;
    315   ALOGV("%s: END", __func__);
    316 }
    317 
    318 status_t QCameraStream_record::processRecordFrame(void *data)
    319 {
    320     ALOGV("%s : BEGIN",__func__);
    321     mm_camera_ch_data_buf_t* frame = (mm_camera_ch_data_buf_t*) data;
    322 
    323     Mutex::Autolock lock(mStopCallbackLock);
    324     if(!mActive) {
    325       ALOGE("Recording Stopped. Returning callback");
    326       return NO_ERROR;
    327     }
    328 
    329     if (UNLIKELY(mDebugFps)) {
    330         debugShowVideoFPS();
    331     }
    332 
    333     mHalCamCtrl->dumpFrameToFile(frame->video.video.frame, HAL_DUMP_FRM_VIDEO);
    334     mHalCamCtrl->mCallbackLock.lock();
    335     camera_data_timestamp_callback rcb = mHalCamCtrl->mDataCbTimestamp;
    336     void *rdata = mHalCamCtrl->mCallbackCookie;
    337     mHalCamCtrl->mCallbackLock.unlock();
    338 
    339 	nsecs_t timeStamp = nsecs_t(frame->video.video.frame->ts.tv_sec)*1000000000LL + \
    340                       frame->video.video.frame->ts.tv_nsec;
    341 
    342   ALOGV("Send Video frame to services/encoder TimeStamp : %lld",timeStamp);
    343   mRecordedFrames[frame->video.video.idx] = *frame;
    344 
    345 #ifdef USE_ION
    346   struct ion_flush_data cache_inv_data;
    347   int ion_fd;
    348   ion_fd = frame->video.video.frame->ion_dev_fd;
    349   cache_inv_data.vaddr = (void *)frame->video.video.frame->buffer;
    350   cache_inv_data.fd = frame->video.video.frame->fd;
    351   cache_inv_data.handle = frame->video.video.frame->fd_data.handle;
    352   cache_inv_data.length = frame->video.video.frame->ion_alloc.len;
    353 
    354   if (mHalCamCtrl->cache_ops(ion_fd, &cache_inv_data, ION_IOC_CLEAN_CACHES) < 0)
    355     ALOGE("%s: Cache clean for Video buffer %p fd = %d failed", __func__,
    356       cache_inv_data.vaddr, cache_inv_data.fd);
    357 #endif
    358 
    359   if (mHalCamCtrl->mStoreMetaDataInFrame) {
    360     mStopCallbackLock.unlock();
    361     if(mActive && (rcb != NULL) && (mHalCamCtrl->mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
    362       rcb(timeStamp, CAMERA_MSG_VIDEO_FRAME,
    363               mHalCamCtrl->mRecordingMemory.metadata_memory[frame->video.video.idx],
    364               0, mHalCamCtrl->mCallbackCookie);
    365     }
    366   } else {
    367     mStopCallbackLock.unlock();
    368     if(mActive && (rcb != NULL) && (mHalCamCtrl->mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
    369       rcb(timeStamp, CAMERA_MSG_VIDEO_FRAME,
    370               mHalCamCtrl->mRecordingMemory.camera_memory[frame->video.video.idx],
    371               0, mHalCamCtrl->mCallbackCookie);
    372     }
    373   }
    374 
    375   ALOGV("%s : END",__func__);
    376   return NO_ERROR;
    377 }
    378 
    379 //Record Related Functions
    380 status_t QCameraStream_record::initEncodeBuffers()
    381 {
    382   ALOGV("%s : BEGIN",__func__);
    383   status_t ret = NO_ERROR;
    384   const char *pmem_region;
    385   uint32_t frame_len;
    386   uint8_t num_planes;
    387   uint32_t planes[VIDEO_MAX_PLANES];
    388   //cam_ctrl_dimension_t dim;
    389   int width = 0;  /* width of channel  */
    390   int height = 0; /* height of channel */
    391   int buf_cnt;
    392   pmem_region = "/dev/pmem_adsp";
    393 
    394 
    395   memset(&mHalCamCtrl->mRecordingMemory, 0, sizeof(mHalCamCtrl->mRecordingMemory));
    396   memset(&dim, 0, sizeof(cam_ctrl_dimension_t));
    397   ret = cam_config_get_parm(mCameraId, MM_CAMERA_PARM_DIMENSION, &dim);
    398   if (MM_CAMERA_OK != ret) {
    399     ALOGE("%s: ERROR - can't get camera dimension!", __func__);
    400     return BAD_VALUE;
    401   }
    402   else {
    403     width =  dim.video_width;
    404     height = dim.video_height;
    405   }
    406   num_planes = 2;
    407   planes[0] = dim.video_frame_offset.mp[0].len;
    408   planes[1] = dim.video_frame_offset.mp[1].len;
    409   frame_len = dim.video_frame_offset.frame_len;
    410 
    411   buf_cnt = VIDEO_BUFFER_COUNT;
    412   if(mHalCamCtrl->isLowPowerCamcorder()) {
    413     ALOGV("%s: lower power camcorder selected", __func__);
    414     buf_cnt = VIDEO_BUFFER_COUNT_LOW_POWER_CAMCORDER;
    415   }
    416     recordframes = new msm_frame[buf_cnt];
    417     memset(recordframes,0,sizeof(struct msm_frame) * buf_cnt);
    418 
    419 		mRecordBuf.video.video.buf.mp = new mm_camera_mp_buf_t[buf_cnt *
    420                                   sizeof(mm_camera_mp_buf_t)];
    421 		if (!mRecordBuf.video.video.buf.mp) {
    422 			ALOGE("%s Error allocating memory for mplanar struct ", __func__);
    423 			return BAD_VALUE;
    424 		}
    425 		memset(mRecordBuf.video.video.buf.mp, 0,
    426 					 buf_cnt * sizeof(mm_camera_mp_buf_t));
    427 
    428     memset(&mHalCamCtrl->mRecordingMemory, 0, sizeof(mHalCamCtrl->mRecordingMemory));
    429     for (int i=0; i<MM_CAMERA_MAX_NUM_FRAMES;i++) {
    430         mHalCamCtrl->mRecordingMemory.main_ion_fd[i] = -1;
    431         mHalCamCtrl->mRecordingMemory.fd[i] = -1;
    432     }
    433 
    434     mHalCamCtrl->mRecordingMemory.buffer_count = buf_cnt;
    435 
    436 		mHalCamCtrl->mRecordingMemory.size = frame_len;
    437 		mHalCamCtrl->mRecordingMemory.cbcr_offset = planes[0];
    438 
    439     for (int cnt = 0; cnt < mHalCamCtrl->mRecordingMemory.buffer_count; cnt++) {
    440 #ifdef USE_ION
    441       if(mHalCamCtrl->allocate_ion_memory(&mHalCamCtrl->mRecordingMemory, cnt,
    442         ((0x1 << CAMERA_ION_HEAP_ID) | (0x1 << CAMERA_ION_FALLBACK_HEAP_ID))) < 0) {
    443         ALOGE("%s ION alloc failed\n", __func__);
    444         return UNKNOWN_ERROR;
    445       }
    446 #else
    447 		  mHalCamCtrl->mRecordingMemory.fd[cnt] = open("/dev/pmem_adsp", O_RDWR|O_SYNC);
    448 		  if(mHalCamCtrl->mRecordingMemory.fd[cnt] <= 0) {
    449 			  ALOGE("%s: no pmem for frame %d", __func__, cnt);
    450 			  return UNKNOWN_ERROR;
    451 		  }
    452 #endif
    453 		  mHalCamCtrl->mRecordingMemory.camera_memory[cnt] =
    454 		    mHalCamCtrl->mGetMemory(mHalCamCtrl->mRecordingMemory.fd[cnt],
    455 		    mHalCamCtrl->mRecordingMemory.size, 1, (void *)this);
    456 
    457       if (mHalCamCtrl->mStoreMetaDataInFrame) {
    458         mHalCamCtrl->mRecordingMemory.metadata_memory[cnt] =
    459           mHalCamCtrl->mGetMemory(-1,
    460           sizeof(struct encoder_media_buffer_type), 1, (void *)this);
    461         struct encoder_media_buffer_type * packet =
    462           (struct encoder_media_buffer_type  *)
    463           mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->data;
    464         packet->meta_handle = native_handle_create(1, 2); //1 fd, 1 offset and 1 size
    465         packet->buffer_type = kMetadataBufferTypeCameraSource;
    466         native_handle_t * nh = const_cast<native_handle_t *>(packet->meta_handle);
    467         nh->data[0] = mHalCamCtrl->mRecordingMemory.fd[cnt];
    468         nh->data[1] = 0;
    469         nh->data[2] = mHalCamCtrl->mRecordingMemory.size;
    470       }
    471     	recordframes[cnt].fd = mHalCamCtrl->mRecordingMemory.fd[cnt];
    472     	recordframes[cnt].buffer = (uint32_t)mHalCamCtrl->mRecordingMemory.camera_memory[cnt]->data;
    473 	    recordframes[cnt].y_off = 0;
    474 	    recordframes[cnt].cbcr_off = mHalCamCtrl->mRecordingMemory.cbcr_offset;
    475 	    recordframes[cnt].path = OUTPUT_TYPE_V;
    476       recordframes[cnt].fd_data = mHalCamCtrl->mRecordingMemory.ion_info_fd[cnt];
    477       recordframes[cnt].ion_alloc = mHalCamCtrl->mRecordingMemory.alloc[cnt];
    478       recordframes[cnt].ion_dev_fd = mHalCamCtrl->mRecordingMemory.main_ion_fd[cnt];
    479 
    480       if (NO_ERROR !=
    481         mHalCamCtrl->sendMappingBuf(MSM_V4L2_EXT_CAPTURE_MODE_VIDEO, cnt,
    482         recordframes[cnt].fd, mHalCamCtrl->mRecordingMemory.size, mCameraId,
    483         CAM_SOCK_MSG_TYPE_FD_MAPPING))
    484         ALOGE("%s: sending mapping data Msg Failed", __func__);
    485 
    486       ALOGV("initRecord :  record heap , video buffers  buffer=%lu fd=%d y_off=%d cbcr_off=%d\n",
    487 		    (unsigned long)recordframes[cnt].buffer, recordframes[cnt].fd, recordframes[cnt].y_off,
    488 		    recordframes[cnt].cbcr_off);
    489 	    //mNumRecordFrames++;
    490 
    491 			mRecordBuf.video.video.buf.mp[cnt].frame = recordframes[cnt];
    492       mRecordBuf.video.video.buf.mp[cnt].frame_offset = 0;
    493       mRecordBuf.video.video.buf.mp[cnt].num_planes = num_planes;
    494       /* Plane 0 needs to be set seperately. Set other planes
    495        * in a loop. */
    496       mRecordBuf.video.video.buf.mp[cnt].planes[0].reserved[0] =
    497         mRecordBuf.video.video.buf.mp[cnt].frame_offset;
    498       mRecordBuf.video.video.buf.mp[cnt].planes[0].length = planes[0];
    499       mRecordBuf.video.video.buf.mp[cnt].planes[0].m.userptr =
    500         recordframes[cnt].fd;
    501       for (int j = 1; j < num_planes; j++) {
    502         mRecordBuf.video.video.buf.mp[cnt].planes[j].length = planes[j];
    503         mRecordBuf.video.video.buf.mp[cnt].planes[j].m.userptr =
    504           recordframes[cnt].fd;
    505         mRecordBuf.video.video.buf.mp[cnt].planes[j].reserved[0] =
    506           mRecordBuf.video.video.buf.mp[cnt].planes[j-1].reserved[0] +
    507           mRecordBuf.video.video.buf.mp[cnt].planes[j-1].length;
    508       }
    509     }
    510 
    511     //memset(&mRecordBuf, 0, sizeof(mRecordBuf));
    512     mRecordBuf.ch_type = MM_CAMERA_CH_VIDEO;
    513     mRecordBuf.video.video.num = mHalCamCtrl->mRecordingMemory.buffer_count;//kRecordBufferCount;
    514     //mRecordBuf.video.video.frame_offset = &record_offset[0];
    515     //mRecordBuf.video.video.frame = &recordframes[0];
    516     ALOGV("%s : END",__func__);
    517     return NO_ERROR;
    518 }
    519 
    520 void QCameraStream_record::releaseRecordingFrame(const void *opaque)
    521 {
    522     ALOGV("%s : BEGIN, opaque = 0x%p",__func__, opaque);
    523     if(!mActive)
    524     {
    525         ALOGE("%s : Recording already stopped!!! Leak???",__func__);
    526         return;
    527     }
    528     for(int cnt = 0; cnt < mHalCamCtrl->mRecordingMemory.buffer_count; cnt++) {
    529       if (mHalCamCtrl->mStoreMetaDataInFrame) {
    530         if(mHalCamCtrl->mRecordingMemory.metadata_memory[cnt] &&
    531                 mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->data == opaque) {
    532             /* found the match */
    533             if(MM_CAMERA_OK != cam_evt_buf_done(mCameraId, &mRecordedFrames[cnt]))
    534                 ALOGE("%s : Buf Done Failed",__func__);
    535             ALOGV("%s : END",__func__);
    536             return;
    537         }
    538       } else {
    539         if(mHalCamCtrl->mRecordingMemory.camera_memory[cnt] &&
    540                 mHalCamCtrl->mRecordingMemory.camera_memory[cnt]->data == opaque) {
    541             /* found the match */
    542             if(MM_CAMERA_OK != cam_evt_buf_done(mCameraId, &mRecordedFrames[cnt]))
    543                 ALOGE("%s : Buf Done Failed",__func__);
    544             ALOGV("%s : END",__func__);
    545             return;
    546         }
    547       }
    548     }
    549 	ALOGE("%s: cannot find the matched frame with opaue = 0x%p", __func__, opaque);
    550 }
    551 
    552 void QCameraStream_record::debugShowVideoFPS() const
    553 {
    554   static int mFrameCount;
    555   static int mLastFrameCount = 0;
    556   static nsecs_t mLastFpsTime = 0;
    557   static float mFps = 0;
    558   mFrameCount++;
    559   nsecs_t now = systemTime();
    560   nsecs_t diff = now - mLastFpsTime;
    561   if (diff > ms2ns(250)) {
    562     mFps =  ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
    563     ALOGV("Video Frames Per Second: %.4f", mFps);
    564     mLastFpsTime = now;
    565     mLastFrameCount = mFrameCount;
    566   }
    567 }
    568 
    569 #if 0
    570 sp<IMemoryHeap> QCameraStream_record::getHeap() const
    571 {
    572   return mRecordHeap != NULL ? mRecordHeap->mHeap : NULL;
    573 }
    574 
    575 #endif
    576 status_t  QCameraStream_record::takeLiveSnapshot(){
    577 	return true;
    578 }
    579 
    580 }//namespace android
    581 
    582