1/*
2** Copyright (c) 2011-2012 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 ALOG_NDEBUG 0
20#define ALOG_NIDEBUG 0
21#define LOG_TAG __FILE__
22#include <utils/Log.h>
23#include <utils/threads.h>
24
25#include "QCameraHWI.h"
26#include "QCameraStream.h"
27
28/* QCameraStream class implementation goes here*/
29/* following code implement the control logic of this class*/
30
31namespace android {
32
33StreamQueue::StreamQueue(){
34    mInitialized = false;
35}
36
37StreamQueue::~StreamQueue(){
38    flush();
39}
40
41void StreamQueue::init(){
42    Mutex::Autolock l(&mQueueLock);
43    mInitialized = true;
44    mQueueWait.signal();
45}
46
47void StreamQueue::deinit(){
48    Mutex::Autolock l(&mQueueLock);
49    mInitialized = false;
50    mQueueWait.signal();
51}
52
53bool StreamQueue::isInitialized(){
54   Mutex::Autolock l(&mQueueLock);
55   return mInitialized;
56}
57
58bool StreamQueue::enqueue(
59                 void * element){
60    Mutex::Autolock l(&mQueueLock);
61    if(mInitialized == false)
62        return false;
63
64    mContainer.add(element);
65    mQueueWait.signal();
66    return true;
67}
68
69bool StreamQueue::isEmpty(){
70    return (mInitialized && mContainer.isEmpty());
71}
72void* StreamQueue::dequeue(){
73
74    void *frame;
75    mQueueLock.lock();
76    while(mInitialized && mContainer.isEmpty()){
77        mQueueWait.wait(mQueueLock);
78    }
79
80    if(!mInitialized){
81        mQueueLock.unlock();
82        return NULL;
83    }
84
85    frame = mContainer.itemAt(0);
86    mContainer.removeAt(0);
87    mQueueLock.unlock();
88    return frame;
89}
90
91void StreamQueue::flush(){
92    Mutex::Autolock l(&mQueueLock);
93    mContainer.clear();
94}
95
96
97// ---------------------------------------------------------------------------
98// QCameraStream
99// ---------------------------------------------------------------------------
100
101void superbuf_cb_routine(mm_camera_super_buf_t *bufs,
102                       void *userdata)
103{
104    QCameraHardwareInterface *p_obj=(QCameraHardwareInterface*) userdata;
105    ALOGE("%s: E",__func__);
106
107    //Implement call to JPEG routine in Snapshot here
108     if(bufs->bufs[0]->stream_id == p_obj->mStreamSnapMain->mMmStreamId){
109         ALOGE("%s : jpeg callback for MM_CAMERA_SNAPSHOT_MAIN", __func__);
110         p_obj->mStreamSnapMain->receiveRawPicture(bufs);
111     }
112
113
114    for(int i=0;i<bufs->num_bufs;i++) {
115
116        p_obj->mCameraHandle->ops->qbuf(p_obj->mCameraHandle->camera_handle,
117                                       p_obj->mChannelId,
118                                       bufs->bufs[i]);
119
120    }
121
122
123}
124
125void stream_cb_routine(mm_camera_super_buf_t *bufs,
126                       void *userdata)
127{
128    ALOGE("%s E ", __func__);
129    QCameraStream *p_obj=(QCameraStream*) userdata;
130    ALOGE("DEBUG4:ExtMode:%d,streamid:%d",p_obj->mExtImgMode,bufs->bufs[0]->stream_id);
131    switch(p_obj->mExtImgMode) {
132    case MM_CAMERA_PREVIEW:
133        ALOGE("%s : callback for MM_CAMERA_PREVIEW", __func__);
134        ((QCameraStream_preview *)p_obj)->dataCallback(bufs);
135        break;
136    case MM_CAMERA_VIDEO:
137        ALOGE("%s : callback for MM_CAMERA_VIDEO", __func__);
138        ((QCameraStream_preview *)p_obj)->dataCallback(bufs);
139        break;
140    case MM_CAMERA_SNAPSHOT_MAIN:
141#if 0
142                if(p_obj->mHalCamCtrl->getHDRMode()) {
143                    ALOGE("%s: Skipping Q Buf for HDR mode",__func__);
144                    break;
145                }
146#endif
147
148                ALOGE("%s : callback for MM_CAMERA_SNAPSHOT_MAIN", __func__);
149                p_obj->p_mm_ops->ops->qbuf(p_obj->mCameraHandle,
150                                           p_obj->mChannelId,
151                                           bufs->bufs[0]);
152                break;
153         case MM_CAMERA_SNAPSHOT_THUMBNAIL:
154                break;
155         default:
156                break;
157
158    }
159    ALOGE("%s X ", __func__);
160}
161
162QCameraStream *QCameraStream::mStreamTable[STREAM_TABLE_SIZE];
163
164void QCameraStream::dataCallback(mm_camera_super_buf_t *bufs)
165{
166    if(mPendingCount!=0) {
167        ALOGD("Got frame request");
168        pthread_mutex_lock(&mFrameDeliveredMutex);
169        mPendingCount--;
170        ALOGD("Completed frame request");
171        pthread_cond_signal(&mFrameDeliveredCond);
172        pthread_mutex_unlock(&mFrameDeliveredMutex);
173        processPreviewFrame(bufs);
174    } else {
175        p_mm_ops->ops->qbuf(mCameraHandle,
176                mChannelId, bufs->bufs[0]);
177    }
178}
179
180void QCameraStream::onNewRequest()
181{
182    ALOGI("%s:E",__func__);
183    pthread_mutex_lock(&mFrameDeliveredMutex);
184    ALOGI("Sending Frame request");
185    mPendingCount++;
186    pthread_cond_wait(&mFrameDeliveredCond,&mFrameDeliveredMutex);
187    ALOGV("Got frame");
188    pthread_mutex_unlock(&mFrameDeliveredMutex);
189    ALOGV("%s:X",__func__);
190}
191
192int32_t QCameraStream::streamOn()
193{
194   status_t rc=NO_ERROR;
195   mm_camera_stream_config_t stream_config;
196   ALOGE("%s:streamid:%d",__func__,mMmStreamId);
197   Mutex::Autolock lock(mLock);
198   if(mActive){
199       ALOGE("%s: Stream:%d is already active",
200            __func__,mMmStreamId);
201       return rc;
202   }
203
204   if (mInit == true) {
205       /* this is the restart case */
206       memset(&stream_config, 0, sizeof(mm_camera_stream_config_t));
207       stream_config.fmt.fmt=(cam_format_t)mFormat;
208       stream_config.fmt.meta_header=MM_CAMEAR_META_DATA_TYPE_DEF;
209       stream_config.fmt.width=mWidth;
210       stream_config.fmt.height=mHeight;
211       stream_config.fmt.rotation = 0;
212       ALOGE("<DEBUG>::%s: Width :%d Height:%d Format:%d",__func__,mWidth,mHeight,mFormat);
213       stream_config.num_of_bufs=mNumBuffers;
214       stream_config.need_stream_on=true;
215       rc=p_mm_ops->ops->config_stream(mCameraHandle,
216                                 mChannelId,
217                                 mMmStreamId,
218                                 &stream_config);
219       ALOGE("%s: config_stream, rc = %d", __func__, rc);
220   }
221
222   rc = p_mm_ops->ops->start_streams(mCameraHandle,
223                              mChannelId,
224                              1,
225                              &mMmStreamId);
226   if(rc==NO_ERROR)
227       mActive = true;
228   return rc;
229}
230
231int32_t QCameraStream::streamOff(bool isAsyncCmd)
232{
233    status_t rc=NO_ERROR;
234    Mutex::Autolock lock(mLock);
235    if(!mActive) {
236        ALOGE("%s: Stream:%d is not active",
237              __func__,mMmStreamId);
238        return rc;
239    }
240
241    rc = p_mm_ops->ops->stop_streams(mCameraHandle,
242                              mChannelId,
243                              1,
244                              &mMmStreamId);
245
246    mActive=false;
247    return rc;
248
249}
250
251/* initialize a streaming channel*/
252status_t QCameraStream::initStream(mm_camera_img_mode imgmode,
253    cam_format_t format)
254{
255    int rc = MM_CAMERA_OK;
256    status_t ret = NO_ERROR;
257    mm_camera_op_mode_type_t op_mode=MM_CAMERA_OP_MODE_VIDEO;
258    cam_ctrl_dimension_t dim;
259    int i;
260    mm_camera_stream_config_t stream_config;
261
262    ALOGE("QCameraStream::initStream : E");
263
264    mFormat = format;
265    /*TODO: Convert between TEMPLATE to img_mode */
266    mExtImgMode = imgmode;
267    /***********Allocate Stream**************/
268
269    rc=p_mm_ops->ops->add_stream(mCameraHandle,
270                        mChannelId,
271                        stream_cb_routine,
272                        (void *)this,
273                        mExtImgMode,
274                        0/*sensor_idx*/);
275
276    if (rc < 0)
277       goto error1;
278
279    mMmStreamId=rc;
280    ALOGE("%s: mMmStreamId = %d\n", __func__, mMmStreamId);
281
282    memset(&stream_config, 0, sizeof(mm_camera_stream_config_t));
283    stream_config.fmt.fmt=format;
284    stream_config.fmt.meta_header=MM_CAMEAR_META_DATA_TYPE_DEF;
285    stream_config.fmt.width=mWidth;
286    stream_config.fmt.height=mHeight;
287    ALOGE("<DEBUG>::%s: Width :%d Height:%d Format:%d",__func__,mWidth,mHeight,format);
288    stream_config.num_of_bufs=mNumBuffers;
289    stream_config.need_stream_on=true;
290    rc=p_mm_ops->ops->config_stream(mCameraHandle,
291                              mChannelId,
292                              mMmStreamId,
293                              &stream_config);
294    if(MM_CAMERA_OK != rc)
295        goto error2;
296
297    goto end;
298
299
300error2:
301    ALOGE("%s: Error configuring stream",__func__);
302    p_mm_ops->ops->del_stream(mCameraHandle,mChannelId,
303                              mMmStreamId);
304
305error1:
306    return BAD_VALUE;
307end:
308    ALOGE("Setting mInit to true");
309    mInit=true;
310    return NO_ERROR;
311
312}
313
314status_t QCameraStream::deinitStream()
315{
316
317    int rc = MM_CAMERA_OK;
318
319    ALOGI("%s: E, Stream = %d\n", __func__, mMmStreamId);
320
321    rc= p_mm_ops->ops->del_stream(mCameraHandle,mChannelId,
322                              mMmStreamId);
323
324    ALOGI("%s: X, Stream = %d\n", __func__, mMmStreamId);
325    mInit=false;
326    return NO_ERROR;
327}
328
329status_t QCameraStream::setMode(int enable) {
330  ALOGE("%s :myMode %x ", __func__, myMode);
331  if (enable) {
332      myMode = (camera_mode_t)(myMode | CAMERA_ZSL_MODE);
333  } else {
334      myMode = (camera_mode_t)(myMode & ~CAMERA_ZSL_MODE);
335  }
336  return NO_ERROR;
337}
338
339status_t QCameraStream::setFormat()
340{
341    ALOGE("%s: E",__func__);
342
343    char mDeviceName[PROPERTY_VALUE_MAX];
344    property_get("ro.product.device",mDeviceName," ");
345
346    ALOGE("%s: X",__func__);
347    return NO_ERROR;
348}
349
350QCameraStream::QCameraStream (){
351    mInit = false;
352    mActive = false;
353    /* memset*/
354    memset(&mCrop, 0, sizeof(mm_camera_rect_t));
355}
356
357QCameraStream::QCameraStream(uint32_t CameraHandle,
358                       uint32_t ChannelId,
359                        uint32_t Width,
360                        uint32_t Height,
361                        mm_camera_vtbl_t *mm_ops,
362                        camera_mode_t mode)
363              :myMode(mode)
364{
365    mInit = false;
366    mActive = false;
367
368    mCameraHandle=CameraHandle;
369    mChannelId=ChannelId;
370    mWidth=Width;
371    mHeight=Height;
372    p_mm_ops=mm_ops;
373
374    /* memset*/
375    memset(&mCrop, 0, sizeof(mm_camera_rect_t));
376
377    mPendingCount=0;
378    pthread_mutex_init(&mFrameDeliveredMutex, NULL);
379    pthread_cond_init(&mFrameDeliveredCond, NULL);
380}
381
382QCameraStream::~QCameraStream () {;}
383
384int QCameraStream::allocateStreamId() {
385    int i = 0;
386    for (i = 0; i < STREAM_TABLE_SIZE; i++)
387        if (mStreamTable[i] == NULL) {
388            mStreamTable[i] = this;
389            break;
390        }
391    if (i == STREAM_TABLE_SIZE)
392        return INVALID_OPERATION;
393    ALOGE("%s: mStreamTable[%d] = %p\n", __func__, i, mStreamTable[i]);
394    return i;
395}
396
397int QCameraStream::deallocateStreamId(int id) {
398    if (id < 0 || id >= STREAM_TABLE_SIZE)
399        return BAD_VALUE;
400    mStreamTable[id] = NULL;
401    return OK;
402}
403
404QCameraStream *QCameraStream::getStreamAtId(int id) {
405    if (id < 0 || id >= STREAM_TABLE_SIZE)
406        return NULL;
407    else
408        return mStreamTable[id];
409}
410
411QCameraStream *QCameraStream::getStreamAtMmId(uint32_t mm_id) {
412    /*TODO: More efficient to do direct lookup. But it requires
413     *mm-camera-interface to expose a macro for handle-index mapping*/
414    for (int i = 0; i < STREAM_TABLE_SIZE; i++) {
415        ALOGE("%s: %d: ", __func__, i);
416        if (mStreamTable[i])
417            ALOGE("%s: mMmStreamId = %d", __func__, mStreamTable[i]->mMmStreamId);
418        if (mStreamTable[i] && (mStreamTable[i]->mMmStreamId == mm_id))
419            return mStreamTable[i];
420    }
421    ALOGE("%s: Cannot find stream with interface id %d", __func__, mm_id);
422    return NULL;
423}
424
425void QCameraStream::streamOffAll()
426{
427    for (int i = 0; i < STREAM_TABLE_SIZE; i++) {
428        if (mStreamTable[i]) {
429            if (mStreamTable[i]->mActive) {
430                ALOGI("%s: stream off stream[%d]", __func__, i);
431                mStreamTable[i]->streamOff(0);
432                ALOGI("%s: stream off stream[%d] done", __func__, i);
433            }
434            if (mStreamTable[i]->mInit) {
435                ALOGI("%s: deinit stream[%d]", __func__, i);
436                mStreamTable[i]->deinitStream();
437                ALOGI("%s: deinit stream[%d] done", __func__, i);
438            }
439        }
440    }
441}
442
443status_t QCameraStream::init() {
444    return NO_ERROR;
445}
446
447status_t QCameraStream::start() {
448    return NO_ERROR;
449}
450
451void QCameraStream::stop() {
452    return;
453}
454
455void QCameraStream::release() {
456    return;
457}
458
459void QCameraStream::setHALCameraControl(QCameraHardwareInterface* ctrl) {
460
461    /* provide a frame data user,
462    for the  queue monitor thread to call the busy queue is not empty*/
463    mHalCamCtrl = ctrl;
464}
465
466}; // namespace android
467