1/*
2** Copyright (c) 2011 Code Aurora Forum. 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// ---------------------------------------------------------------------------
39namespace android {
40
41
42QCameraStream* 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// ---------------------------------------------------------------------------
54void 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// ---------------------------------------------------------------------------
68QCameraStream_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// ---------------------------------------------------------------------------
86QCameraStream_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// ---------------------------------------------------------------------------
103static 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// ---------------------------------------------------------------------------
120status_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
151status_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
200error:
201  releaseEncodeBuffer();
202  LOGV("%s: END", __func__);
203  return ret;
204}
205
206void 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// ---------------------------------------------------------------------------
241void 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// ---------------------------------------------------------------------------
293void 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
319status_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
381status_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
521void 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
553void 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
571sp<IMemoryHeap> QCameraStream_record::getHeap() const
572{
573  return mRecordHeap != NULL ? mRecordHeap->mHeap : NULL;
574}
575
576#endif
577status_t  QCameraStream_record::takeLiveSnapshot(){
578	return true;
579}
580
581}//namespace android
582
583