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