1 /*
2 ** Copyright (c) 2011-2012 The Linux Foundation. All rights reserved.
3 **
4 ** Not a Contribution, Apache license notifications and license are retained
5 ** for attribution purposes only.
6 **
7 ** Licensed under the Apache License, Version 2.0 (the "License");
8 ** you may not use this file except in compliance with the License.
9 ** You may obtain a copy of the License at
10 **
11 **     http://www.apache.org/licenses/LICENSE-2.0
12 **
13 ** Unless required by applicable law or agreed to in writing, software
14 ** distributed under the License is distributed on an "AS IS" BASIS,
15 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 ** See the License for the specific language governing permissions and
17 ** limitations under the License.
18 */
19 
20 /*#error uncomment this for compiler test!*/
21 
22 //#define ALOG_NDEBUG 0
23 #define ALOG_NIDEBUG 0
24 #define LOG_TAG "QCameraHWI_Record"
25 #include <utils/Log.h>
26 #include <utils/threads.h>
27 #include <cutils/properties.h>
28 #include <fcntl.h>
29 #include <sys/mman.h>
30 
31 #include "QCameraStream.h"
32 
33 
34 #define LIKELY(exp)   __builtin_expect(!!(exp), 1)
35 #define UNLIKELY(exp) __builtin_expect(!!(exp), 0)
36 
37 /* QCameraStream_record class implementation goes here*/
38 /* following code implement the video streaming capture & encoding logic of this class*/
39 // ---------------------------------------------------------------------------
40 // QCameraStream_record createInstance()
41 // ---------------------------------------------------------------------------
42 namespace android {
43 
44 
45 // ---------------------------------------------------------------------------
46 // QCameraStream_record Constructor
47 // ---------------------------------------------------------------------------
QCameraStream_record(uint32_t CameraHandle,uint32_t ChannelId,uint32_t Width,uint32_t Height,uint32_t Format,uint8_t NumBuffers,mm_camera_vtbl_t * mm_ops,mm_camera_img_mode imgmode,camera_mode_t mode,QCameraHardwareInterface * camCtrl)48 QCameraStream_record::QCameraStream_record(uint32_t CameraHandle,
49                                            uint32_t ChannelId,
50                                            uint32_t Width,
51                                            uint32_t Height,
52                                            uint32_t Format,
53                                            uint8_t NumBuffers,
54                                            mm_camera_vtbl_t *mm_ops,
55                                            mm_camera_img_mode imgmode,
56                                            camera_mode_t mode,
57                                            QCameraHardwareInterface* camCtrl)
58 //  : QCameraStream(cameraId,mode),
59   :QCameraStream(CameraHandle,
60                  ChannelId,
61                  Width,
62                  Height,
63                  Format,
64                  NumBuffers,
65                  mm_ops,
66                  imgmode,
67                  mode,
68                  camCtrl),
69                  mDebugFps(false)
70 {
71   char value[PROPERTY_VALUE_MAX];
72   ALOGV("%s: BEGIN", __func__);
73 
74   property_get("persist.debug.sf.showfps", value, "0");
75   mDebugFps = atoi(value);
76 
77   ALOGV("%s: END", __func__);
78 }
79 
80 // ---------------------------------------------------------------------------
81 // QCameraStream_record Destructor
82 // ---------------------------------------------------------------------------
~QCameraStream_record()83 QCameraStream_record::~QCameraStream_record() {
84     ALOGV("%s: BEGIN", __func__);
85     release();
86     ALOGV("%s: END", __func__);
87 }
88 
putBuf(uint8_t num_bufs,mm_camera_buf_def_t * bufs)89 int QCameraStream_record::putBuf(uint8_t num_bufs, mm_camera_buf_def_t *bufs)
90 {
91     for(int cnt = 0; cnt < mHalCamCtrl->mRecordingMemory.buffer_count; cnt++) {
92         if (mHalCamCtrl->mStoreMetaDataInFrame) {
93             struct encoder_media_buffer_type * packet =
94                 (struct encoder_media_buffer_type  *)mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->data;
95             native_handle_delete(const_cast<native_handle_t *>(packet->meta_handle));
96             mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->release(
97                mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]);
98         }
99         mHalCamCtrl->mRecordingMemory.camera_memory[cnt]->release(
100            mHalCamCtrl->mRecordingMemory.camera_memory[cnt]);
101 
102 #ifdef USE_ION
103         mHalCamCtrl->deallocate_ion_memory(&mHalCamCtrl->mRecordingMemory.mem_info[cnt]);
104 #endif
105     }
106     memset(&mHalCamCtrl->mRecordingMemory, 0, sizeof(mHalCamCtrl->mRecordingMemory));
107     return NO_ERROR;
108 }
109 
110 // ---------------------------------------------------------------------------
111 // QCameraStream_record
112 // ---------------------------------------------------------------------------
release()113 void QCameraStream_record::release()
114 {
115     ALOGV("%s: BEGIN", __func__);
116     streamOff(0);
117     deinitStream();
118     ALOGV("%s: END", __func__);
119 }
120 
processRecordFrame(mm_camera_super_buf_t * frame)121 status_t QCameraStream_record::processRecordFrame(mm_camera_super_buf_t *frame)
122 {
123     ALOGV("%s : BEGIN",__func__);
124     int video_buf_idx = frame->bufs[0]->buf_idx;
125 
126     if(!mActive) {
127       ALOGE("Recording Stopped. Returning callback");
128       return NO_ERROR;
129     }
130 
131     if (UNLIKELY(mDebugFps)) {
132         debugShowVideoFPS();
133     }
134     ALOGE("DEBUG4:%d",frame->bufs[0]->stream_id);
135     ALOGE("<DEBUG4>: Timestamp: %ld %ld",frame->bufs[0]->ts.tv_sec,frame->bufs[0]->ts.tv_nsec);
136     mHalCamCtrl->dumpFrameToFile(frame->bufs[0], HAL_DUMP_FRM_VIDEO);
137     camera_data_timestamp_callback rcb = mHalCamCtrl->mDataCbTimestamp;
138     void *rdata = mHalCamCtrl->mCallbackCookie;
139 	  nsecs_t timeStamp = nsecs_t(frame->bufs[0]->ts.tv_sec)*1000000000LL + \
140                       frame->bufs[0]->ts.tv_nsec;
141 
142     ALOGE("Send Video frame to services/encoder TimeStamp : %lld",timeStamp);
143     mRecordedFrames[video_buf_idx] = *frame;
144 
145     mHalCamCtrl->cache_ops(&mHalCamCtrl->mRecordingMemory.mem_info[video_buf_idx],
146                            (void *)mHalCamCtrl->mRecordingMemory.camera_memory[video_buf_idx]->data,
147                            ION_IOC_CLEAN_CACHES);
148 
149     if (mHalCamCtrl->mStoreMetaDataInFrame) {
150         if((rcb != NULL) && (mHalCamCtrl->mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
151             ALOGE("Calling video callback:%d", video_buf_idx);
152             rcb(timeStamp, CAMERA_MSG_VIDEO_FRAME,
153                 mHalCamCtrl->mRecordingMemory.metadata_memory[video_buf_idx],
154                 0, mHalCamCtrl->mCallbackCookie);
155         }
156     } else {
157         if((rcb != NULL) && (mHalCamCtrl->mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) {
158             ALOGE("Calling video callback2");
159             rcb(timeStamp, CAMERA_MSG_VIDEO_FRAME,
160                 mHalCamCtrl->mRecordingMemory.camera_memory[video_buf_idx],
161                 0, mHalCamCtrl->mCallbackCookie);
162         }
163     }
164 
165     ALOGV("%s : END",__func__);
166     return NO_ERROR;
167 }
168 
169 //Record Related Functions
initStream(uint8_t no_cb_needed,uint8_t stream_on)170 status_t QCameraStream_record::initStream(uint8_t no_cb_needed, uint8_t stream_on)
171 {
172     status_t ret = NO_ERROR;
173 
174     ALOGI(" %s : E ", __FUNCTION__);
175     mNumBuffers = VIDEO_BUFFER_COUNT;
176     if(mHalCamCtrl->isLowPowerCamcorder()) {
177         ALOGE("%s: lower power camcorder selected", __func__);
178         mNumBuffers = VIDEO_BUFFER_COUNT_LOW_POWER_CAMCORDER;
179     }
180     ret = QCameraStream::initStream(no_cb_needed, stream_on);
181 end:
182     ALOGI(" %s : X ", __FUNCTION__);
183     return ret;
184 }
185 
getBuf(mm_camera_frame_len_offset * frame_offset_info,uint8_t num_bufs,uint8_t * initial_reg_flag,mm_camera_buf_def_t * bufs)186 status_t QCameraStream_record::getBuf(mm_camera_frame_len_offset *frame_offset_info,
187                                       uint8_t num_bufs,
188                                       uint8_t *initial_reg_flag,
189                                       mm_camera_buf_def_t  *bufs)
190 {
191     ALOGE("%s : BEGIN",__func__);
192 
193     if (num_bufs > mNumBuffers) {
194         mNumBuffers = num_bufs;
195     }
196     if ((mNumBuffers == 0) || (mNumBuffers > MM_CAMERA_MAX_NUM_FRAMES)) {
197         ALOGE("%s: Invalid number of buffers (=%d) requested!",
198              __func__, mNumBuffers);
199         return BAD_VALUE;
200     }
201 
202     memset(mRecordBuf, 0, sizeof(mRecordBuf));
203     memcpy(&mFrameOffsetInfo, frame_offset_info, sizeof(mFrameOffsetInfo));
204     if (mHalCamCtrl->initHeapMem(&mHalCamCtrl->mRecordingMemory,
205                                  mNumBuffers,
206                                  mFrameOffsetInfo.frame_len,
207                                  MSM_PMEM_VIDEO,
208                                  &mFrameOffsetInfo,
209                                  mRecordBuf) < 0) {
210         ALOGE("%s: Error getting heap mem for recording", __func__);
211         return NO_MEMORY;
212     }
213 
214     if (mHalCamCtrl->mStoreMetaDataInFrame) {
215         for (int cnt = 0; cnt < mNumBuffers; cnt++) {
216             mHalCamCtrl->mRecordingMemory.metadata_memory[cnt] =
217                 mHalCamCtrl->mGetMemory(-1,
218                                         sizeof(struct encoder_media_buffer_type),
219                                         1,
220                                         (void *)this);
221             struct encoder_media_buffer_type * packet =
222                 (struct encoder_media_buffer_type *)mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->data;
223             packet->meta_handle = native_handle_create(1, 2); //1 fd, 1 offset and 1 size
224             packet->buffer_type = kMetadataBufferTypeCameraSource;
225             native_handle_t * nh = const_cast<native_handle_t *>(packet->meta_handle);
226             nh->data[0] = mHalCamCtrl->mRecordingMemory.mem_info[cnt].fd;
227             nh->data[1] = 0;
228             nh->data[2] = mHalCamCtrl->mRecordingMemory.mem_info[cnt].size;
229         }
230     }
231 
232     for(int i = 0; i < num_bufs; i++) {
233         bufs[i] = mRecordBuf[i];
234         initial_reg_flag[i] = true;
235     }
236 
237     ALOGE("%s : END",__func__);
238     return NO_ERROR;
239 }
240 
releaseRecordingFrame(const void * opaque)241 void QCameraStream_record::releaseRecordingFrame(const void *opaque)
242 {
243     ALOGV("%s : BEGIN, opaque = 0x%p",__func__, opaque);
244     if(!mActive)
245     {
246         ALOGE("%s : Recording already stopped!!! Leak???",__func__);
247         return;
248     }
249     for(int cnt = 0; cnt < mHalCamCtrl->mRecordingMemory.buffer_count; cnt++) {
250       if (mHalCamCtrl->mStoreMetaDataInFrame) {
251         if(mHalCamCtrl->mRecordingMemory.metadata_memory[cnt] &&
252                 mHalCamCtrl->mRecordingMemory.metadata_memory[cnt]->data == opaque) {
253             /* found the match */
254             ALOGE("Releasing video frames:%d",cnt);
255             if(MM_CAMERA_OK != p_mm_ops->ops->qbuf(mCameraHandle, mChannelId, mRecordedFrames[cnt].bufs[0]))
256                 ALOGE("%s : Buf Done Failed",__func__);
257             mHalCamCtrl->cache_ops(&mHalCamCtrl->mRecordingMemory.mem_info[cnt],
258                                    (void *)mRecordedFrames[cnt].bufs[0]->buffer,
259                                    ION_IOC_INV_CACHES);
260             ALOGV("%s : END",__func__);
261             return;
262         }
263       } else {
264         if(mHalCamCtrl->mRecordingMemory.camera_memory[cnt] &&
265                 mHalCamCtrl->mRecordingMemory.camera_memory[cnt]->data == opaque) {
266             /* found the match */
267             ALOGE("Releasing video frames2");
268             if(MM_CAMERA_OK != p_mm_ops->ops->qbuf(mCameraHandle, mChannelId, mRecordedFrames[cnt].bufs[0]))
269                 ALOGE("%s : Buf Done Failed",__func__);
270             mHalCamCtrl->cache_ops(&mHalCamCtrl->mRecordingMemory.mem_info[cnt],
271                                    (void *)mRecordedFrames[cnt].bufs[0]->buffer,
272                                    ION_IOC_INV_CACHES);
273             ALOGV("%s : END",__func__);
274             return;
275         }
276       }
277     }
278 	ALOGE("%s: cannot find the matched frame with opaue = 0x%p", __func__, opaque);
279 }
280 
debugShowVideoFPS() const281 void QCameraStream_record::debugShowVideoFPS() const
282 {
283   static int mFrameCount;
284   static int mLastFrameCount = 0;
285   static nsecs_t mLastFpsTime = 0;
286   static float mFps = 0;
287   mFrameCount++;
288   nsecs_t now = systemTime();
289   nsecs_t diff = now - mLastFpsTime;
290   if (diff > ms2ns(250)) {
291     mFps =  ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
292     ALOGI("Video Frames Per Second: %.4f", mFps);
293     mLastFpsTime = now;
294     mLastFrameCount = mFrameCount;
295   }
296 }
297 
298 }//namespace android
299 
300