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 LOG_NIDEBUG 0
20//#define LOG_NDEBUG 0
21
22#define LOG_TAG "QCameraHWI"
23#include <utils/Log.h>
24#include <utils/threads.h>
25#include <cutils/properties.h>
26#include <fcntl.h>
27#include <sys/mman.h>
28
29#include "QCameraHAL.h"
30#include "QCameraHWI.h"
31
32/* QCameraHardwareInterface class implementation goes here*/
33/* following code implement the contol logic of this class*/
34
35namespace android {
36
37extern void stream_cb_routine(mm_camera_super_buf_t *bufs,
38                       void *userdata);
39extern void superbuf_cb_routine(mm_camera_super_buf_t *bufs,
40                       void *userdata);
41
42
43/*Command Thread startup function*/
44
45void *command_thread(void *obj)
46{
47    QCameraHardwareInterface *pme = (QCameraHardwareInterface *)obj;
48    ALOGD("%s: E", __func__);
49    if (pme != NULL) {
50        pme->runCommandThread(obj);
51    }
52    else ALOGW("not starting command thread: the object went away!");
53    ALOGD("%s: X", __func__);
54    return NULL;
55}
56
57int QCameraHardwareInterface::tryRestartStreams(
58    camera_metadata_entry_t& streams)
59{
60    int rc = 0;
61    bool needRestart = false;
62    bool needRecordingHint = false;
63
64    for (uint32_t i = 0; i < streams.count; i++) {
65        int streamId = streams.data.u8[i];
66        QCameraStream *stream = QCameraStream::getStreamAtId(streamId);
67        if (!stream->mInit) {
68            needRestart = true;
69            if (stream->mFormat == CAMERA_YUV_420_NV12)
70                needRecordingHint = true;
71        }
72    }
73
74    if (!needRestart)
75        goto end;
76
77    QCameraStream::streamOffAll();
78
79    if (needRecordingHint) {
80        uint32_t recordingHint = 1;
81        rc = mCameraHandle->ops->set_parm(mCameraHandle->camera_handle,
82            MM_CAMERA_PARM_RECORDING_HINT, &recordingHint);
83        if (rc < 0) {
84            ALOGE("set_parm MM_CAMERA_PARM_RECORDING_HINT returns %d", rc);
85            return rc;
86        }
87    }
88
89end:
90    for (uint32_t i = 0; i < streams.count; i++) {
91        int streamId = streams.data.u8[i];
92        QCameraStream *stream = QCameraStream::getStreamAtId(streamId);
93        if (!stream->mInit) {
94            rc = stream->prepareStream();
95            if (rc < 0) {
96                ALOGE("prepareStream for stream %d failed %d", streamId, rc);
97                return rc;
98            }
99        }
100    }
101    for (uint32_t i = 0; i < streams.count; i++) {
102        int streamId = streams.data.u8[i];
103        QCameraStream *stream = QCameraStream::getStreamAtId(streamId);
104
105        if (!stream->mActive) {
106            rc = stream->streamOn();
107            if (rc < 0) {
108                ALOGE("streamOn for stream %d failed %d", streamId, rc);
109                return rc;
110            }
111        }
112    }
113    return rc;
114}
115
116void QCameraHardwareInterface::runCommandThread(void *data)
117{
118
119    /**
120     * This function implements the main service routine for the incoming
121     * frame requests, this thread routine is started everytime we get a
122     * notify_request_queue_not_empty trigger, this thread makes the
123     * assumption that once it receives a NULL on a dequest_request call
124     * there will be a fresh notify_request_queue_not_empty call that is
125     * invoked thereby launching a new instance of this thread. Therefore,
126     * once we get a NULL on a dequeue request we simply let this thread die
127     */
128    int res;
129    camera_metadata_t *request=NULL;
130    mPendingRequests=0;
131
132    while(mRequestQueueSrc) {
133        ALOGV("%s:Dequeue request using mRequestQueueSrc:%p",__func__,mRequestQueueSrc);
134        mRequestQueueSrc->dequeue_request(mRequestQueueSrc,&request);
135        if(request==NULL) {
136            ALOGE("%s:No more requests available from src command \
137                    thread dying",__func__);
138            return;
139        }
140        mPendingRequests++;
141
142        /* Set the metadata values */
143
144        /* Wait for the SOF for the new metadata values to be applied */
145
146        /* Check the streams that need to be active in the stream request */
147        sort_camera_metadata(request);
148
149        camera_metadata_entry_t streams;
150        res = find_camera_metadata_entry(request,
151                ANDROID_REQUEST_OUTPUT_STREAMS,
152                &streams);
153        if (res != NO_ERROR) {
154            ALOGE("%s: error reading output stream tag", __FUNCTION__);
155            return;
156        }
157
158        res = tryRestartStreams(streams);
159        if (res != NO_ERROR) {
160            ALOGE("error tryRestartStreams %d", res);
161            return;
162        }
163
164        /* 3rd pass: Turn on all streams requested */
165        for (uint32_t i = 0; i < streams.count; i++) {
166            int streamId = streams.data.u8[i];
167            QCameraStream *stream = QCameraStream::getStreamAtId(streamId);
168
169            /* Increment the frame pending count in each stream class */
170
171            /* Assuming we will have the stream obj in had at this point may be
172             * may be multiple objs in which case we loop through array of streams */
173            stream->onNewRequest();
174        }
175        ALOGV("%s:Freeing request using mRequestQueueSrc:%p",__func__,mRequestQueueSrc);
176        /* Free the request buffer */
177        mRequestQueueSrc->free_request(mRequestQueueSrc,request);
178        mPendingRequests--;
179        ALOGV("%s:Completed request",__func__);
180    }
181
182    QCameraStream::streamOffAll();
183}
184
185/*Mem Hooks*/
186int32_t get_buffer_hook(uint32_t camera_handle,
187                        uint32_t ch_id, uint32_t stream_id,
188                        void *user_data,
189                        mm_camera_frame_len_offset *frame_offset_info,
190                        uint8_t num_bufs,
191                        uint8_t *initial_reg_flag,
192                        mm_camera_buf_def_t  *bufs)
193{
194    QCameraHardwareInterface *pme=(QCameraHardwareInterface *)user_data;
195    return pme->getBuf(camera_handle, ch_id, stream_id,
196                user_data, frame_offset_info,
197                num_bufs,initial_reg_flag,
198                bufs);
199
200}
201
202int32_t put_buffer_hook(uint32_t camera_handle,
203                        uint32_t ch_id, uint32_t stream_id,
204                        void *user_data, uint8_t num_bufs,
205                        mm_camera_buf_def_t *bufs)
206{
207    QCameraHardwareInterface *pme=(QCameraHardwareInterface *)user_data;
208    return pme->putBuf(camera_handle, ch_id, stream_id,
209                user_data, num_bufs, bufs);
210
211}
212
213int QCameraHardwareInterface::getBuf(uint32_t camera_handle,
214                        uint32_t ch_id, uint32_t mm_stream_id,
215                        void *user_data,
216                        mm_camera_frame_len_offset *frame_offset_info,
217                        uint8_t num_bufs,
218                        uint8_t *initial_reg_flag,
219                        mm_camera_buf_def_t  *bufs)
220{
221    status_t ret=NO_ERROR;
222    ALOGE("%s: E, stream_id = %d\n", __func__, mm_stream_id);
223    QCameraStream_preview *stream = (QCameraStream_preview *)
224                        QCameraStream::getStreamAtMmId(mm_stream_id);
225
226    ALOGE("%s: len:%d, y_off:%d, cbcr:%d num buffers: %d planes:%d streamid:%d",
227        __func__,
228        frame_offset_info->frame_len,
229	frame_offset_info->mp[0].len,
230	frame_offset_info->mp[1].len,
231        num_bufs,frame_offset_info->num_planes,
232        mm_stream_id);
233    /*************Preiew Stream*****************/
234    ALOGE("Interface requesting Preview Buffers");
235    stream->mFrameOffsetInfo=*frame_offset_info;
236    if(NO_ERROR!=stream->initBuffers()){
237        return BAD_VALUE;
238    }
239    ALOGE("Debug : %s : initDisplayBuffers",__func__);
240    for(int i=0;i<num_bufs;i++) {
241        bufs[i] = stream->mDisplayBuf[i];
242        initial_reg_flag[i] =
243            (stream->mPreviewMemory.local_flag[i] == BUFFER_OWNED);
244        ALOGE("initial_reg_flag[%d]:%d",i,initial_reg_flag[i]);
245    }
246    return 0;
247}
248
249int QCameraHardwareInterface::putBuf(uint32_t camera_handle,
250                        uint32_t ch_id, uint32_t mm_stream_id,
251                        void *user_data, uint8_t num_bufs,
252                        mm_camera_buf_def_t *bufs)
253{
254    ALOGE("%s:E, stream_id = %d",__func__, mm_stream_id);
255    QCameraStream_preview *stream = (QCameraStream_preview *)
256                        QCameraStream::getStreamAtMmId(mm_stream_id);
257    stream->deinitBuffers();
258    return 0;
259}
260
261
262QCameraHardwareInterface::
263QCameraHardwareInterface(int cameraId, int mode)
264                  : mCameraId(cameraId)
265{
266
267    cam_ctrl_dimension_t mDimension;
268
269    /* Open camera stack! */
270    memset(&mMemHooks, 0, sizeof(mm_camear_mem_vtbl_t));
271    mMemHooks.user_data=this;
272    mMemHooks.get_buf=get_buffer_hook;
273    mMemHooks.put_buf=put_buffer_hook;
274
275    mCameraHandle=camera_open(mCameraId, &mMemHooks);
276    ALOGV("Cam open returned %p",mCameraHandle);
277    if(mCameraHandle == NULL) {
278        ALOGE("startCamera: cam_ops_open failed: id = %d", mCameraId);
279        return;
280    }
281    mCameraHandle->ops->sync(mCameraHandle->camera_handle);
282
283    mChannelId=mCameraHandle->ops->ch_acquire(mCameraHandle->camera_handle);
284    if(mChannelId<=0)
285    {
286        ALOGE("%s:Channel aquire failed",__func__);
287        mCameraHandle->ops->camera_close(mCameraHandle->camera_handle);
288        return;
289    }
290
291    /* Initialize # of frame requests the HAL is handling to zero*/
292    mPendingRequests=0;
293}
294
295QCameraHardwareInterface::~QCameraHardwareInterface()
296{
297    mCameraHandle->ops->camera_close(mCameraHandle->camera_handle);
298}
299
300void QCameraHardwareInterface::release()
301{
302}
303
304bool QCameraHardwareInterface::isCameraReady()
305{
306    return true;
307}
308
309int QCameraHardwareInterface::set_request_queue_src_ops(
310    const camera2_request_queue_src_ops_t *request_src_ops)
311{
312    ALOGE("%s:E mRequestQueueSrc:%p",__func__,request_src_ops);
313    mRequestQueueSrc = request_src_ops;
314    ALOGE("%s:X",__func__);
315    return 0;
316}
317
318int QCameraHardwareInterface::notify_request_queue_not_empty()
319{
320
321    pthread_attr_t attr;
322    if(pthread_attr_init(&attr)!=0) {
323        ALOGE("%s:pthread_attr_init failed",__func__);
324        return BAD_VALUE;
325    }
326    if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)!=0){
327        ALOGE("%s:pthread_attr_setdetachstate failed",__func__);
328        return BAD_VALUE;
329    }
330    if(pthread_create(&mCommandThread,&attr,
331                   command_thread, (void *)this)!=0) {
332        ALOGE("%s:pthread_create failed to launch command_thread",__func__);
333        return BAD_VALUE;
334    }
335
336    return NO_ERROR;
337}
338
339int QCameraHardwareInterface::set_frame_queue_dst_ops(
340    const camera2_frame_queue_dst_ops_t *frame_dst_ops)
341{
342    mFrameQueueDst = frame_dst_ops;
343    return OK;
344}
345
346int QCameraHardwareInterface::get_in_progress_count()
347{
348    return mPendingRequests;
349}
350
351int QCameraHardwareInterface::construct_default_request(
352    int request_template, camera_metadata_t **request)
353{
354    status_t ret;
355    ALOGD("%s:E:request_template:%d ",__func__,request_template);
356
357    if (request == NULL)
358        return BAD_VALUE;
359    if (request_template < 0 || request_template >= CAMERA2_TEMPLATE_COUNT)
360        return BAD_VALUE;
361
362    ret = constructDefaultRequest(request_template, request, true);
363    if (ret != OK) {
364        ALOGE("%s: Unable to allocate default request: %s (%d)",
365            __FUNCTION__, strerror(-ret), ret);
366        return ret;
367    }
368    ret = constructDefaultRequest(request_template, request, false);
369    if (ret != OK) {
370        ALOGE("%s: Unable to fill in default request: %s (%d)",
371            __FUNCTION__, strerror(-ret), ret);
372        return ret;
373    }
374
375    ALOGE("Setting OP MODE to MM_CAMERA_OP_MODE_VIDEO");
376    mm_camera_op_mode_type_t op_mode=MM_CAMERA_OP_MODE_VIDEO;
377    ret = mCameraHandle->ops->set_parm(
378                         mCameraHandle->camera_handle,
379                         MM_CAMERA_PARM_OP_MODE,
380                         &op_mode);
381    ALOGE("OP Mode Set");
382
383    return ret;
384}
385
386int QCameraHardwareInterface::allocate_stream(
387    uint32_t width,
388    uint32_t height, int format,
389    const camera2_stream_ops_t *stream_ops,
390    uint32_t *stream_id,
391    uint32_t *format_actual,
392    uint32_t *usage,
393    uint32_t *max_buffers)
394{
395    int ret = OK;
396    QCameraStream *stream = NULL;
397    camera_mode_t myMode = (camera_mode_t)(CAMERA_MODE_2D|CAMERA_NONZSL_MODE);
398    ALOGE("%s : BEGIN",__func__);
399
400    ALOGE("Mymode Preview = %d",myMode);
401    stream = QCameraStream_preview::createInstance(
402                        mCameraHandle->camera_handle,
403                        mChannelId,
404                        width,
405                        height,
406                        format,
407                        mCameraHandle,
408                        myMode);
409    ALOGE("%s: createInstance done", __func__);
410    if (!stream) {
411        ALOGE("%s: error - can't creat preview stream!", __func__);
412        return BAD_VALUE;
413    }
414
415    stream->setPreviewWindow(stream_ops);
416    *stream_id = stream->getStreamId();
417    *max_buffers= stream->getMaxBuffers();
418    ALOGE("%s: stream_id = %d\n", __func__, *stream_id);
419    *usage = GRALLOC_USAGE_HW_CAMERA_WRITE | CAMERA_GRALLOC_HEAP_ID
420        | CAMERA_GRALLOC_FALLBACK_HEAP_ID;
421    /* Set to an arbitrary format SUPPORTED by gralloc */
422    //*format_actual = HAL_PIXEL_FORMAT_YCbCr_422_SP;
423    *format_actual = HAL_PIXEL_FORMAT_YCrCb_420_SP;
424    /*TODO: For hardware encoder, add CAMERA_GRALLOC_CACHING_ID */
425    stream->setHALCameraControl(this);
426
427    ALOGV("%s : END",__func__);
428    return ret;
429}
430
431int QCameraHardwareInterface::register_stream_buffers(
432    uint32_t stream_id, int num_buffers,
433    buffer_handle_t *buffers)
434{
435    struct private_handle_t *private_handle =
436                        (struct private_handle_t *)buffers[0];
437    QCameraStream_preview *stream = (QCameraStream_preview *)
438                        QCameraStream::getStreamAtId(stream_id);
439
440    if(!stream) {
441        ALOGE("%s: Request for unknown stream",__func__);
442        return BAD_VALUE;
443    }
444
445    if(NO_ERROR!=stream->registerStreamBuffers(num_buffers, buffers)) {
446        ALOGE("%s:registerStreamBuffers failed",__func__);
447        return BAD_VALUE;
448    }
449
450    return NO_ERROR;
451}
452
453int QCameraHardwareInterface::release_stream(uint32_t stream_id)
454{
455    QCameraStream *stream = QCameraStream::getStreamAtId(stream_id);
456
457    QCameraStream_preview::deleteInstance(stream);
458
459    return OK;
460}
461
462int QCameraHardwareInterface::allocate_reprocess_stream(
463    uint32_t width,
464    uint32_t height,
465    uint32_t format,
466    const camera2_stream_in_ops_t *reprocess_stream_ops,
467    uint32_t *stream_id,
468    uint32_t *consumer_usage,
469    uint32_t *max_buffers)
470{
471    return INVALID_OPERATION;
472}
473
474int QCameraHardwareInterface::release_reprocess_stream(uint32_t stream_id)
475{
476    return INVALID_OPERATION;
477}
478
479int QCameraHardwareInterface::get_metadata_vendor_tag_ops(vendor_tag_query_ops_t **ops)
480{
481    *ops = NULL;
482    return OK;
483}
484
485int QCameraHardwareInterface::set_notify_callback(camera2_notify_callback notify_cb,
486            void *user)
487{
488    mNotifyCb = notify_cb;
489    mNotifyUserPtr = user;
490    return OK;
491}
492}; // namespace android
493