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// ---------------------------------------------------------------------------
42namespace android {
43
44
45// ---------------------------------------------------------------------------
46// QCameraStream_record Constructor
47// ---------------------------------------------------------------------------
48QCameraStream_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// ---------------------------------------------------------------------------
83QCameraStream_record::~QCameraStream_record() {
84    ALOGV("%s: BEGIN", __func__);
85    release();
86    ALOGV("%s: END", __func__);
87}
88
89int 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// ---------------------------------------------------------------------------
113void QCameraStream_record::release()
114{
115    ALOGV("%s: BEGIN", __func__);
116    streamOff(0);
117    deinitStream();
118    ALOGV("%s: END", __func__);
119}
120
121status_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
170status_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);
181end:
182    ALOGI(" %s : X ", __FUNCTION__);
183    return ret;
184}
185
186status_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
241void 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
281void 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