Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      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 /*
     18  * Contains implementation of a class PreviewWindow that encapsulates
     19  * functionality of a preview window set via set_preview_window camera HAL API.
     20  */
     21 
     22 #define LOG_NDEBUG 0
     23 #define LOG_TAG "EmulatedCamera_Preview"
     24 #include "PreviewWindow.h"
     25 #include <cutils/log.h>
     26 #include <hardware/camera.h>
     27 #include "EmulatedCameraDevice.h"
     28 #include "GrallocModule.h"
     29 
     30 namespace android {
     31 
     32 PreviewWindow::PreviewWindow()
     33     : mPreviewWindow(NULL),
     34       mLastPreviewed(0),
     35       mPreviewFrameWidth(0),
     36       mPreviewFrameHeight(0),
     37       mPreviewEnabled(false) {}
     38 
     39 PreviewWindow::~PreviewWindow() {}
     40 
     41 /****************************************************************************
     42  * Camera API
     43  ***************************************************************************/
     44 
     45 status_t PreviewWindow::setPreviewWindow(struct preview_stream_ops* window,
     46                                          int preview_fps) {
     47   ALOGV("%s: current: %p -> new: %p", __FUNCTION__, mPreviewWindow, window);
     48 
     49   status_t res = NO_ERROR;
     50   Mutex::Autolock locker(&mObjectLock);
     51 
     52   /* Reset preview info. */
     53   mPreviewFrameWidth = mPreviewFrameHeight = 0;
     54   mPreviewAfter = 0;
     55   mLastPreviewed = 0;
     56 
     57   if (window != NULL) {
     58     /* The CPU will write each frame to the preview window buffer.
     59      * Note that we delay setting preview window buffer geometry until
     60      * frames start to come in. */
     61     res = window->set_usage(window, GRALLOC_USAGE_SW_WRITE_OFTEN);
     62     if (res == NO_ERROR) {
     63       /* Set preview frequency. */
     64       mPreviewAfter = 1000000 / preview_fps;
     65     } else {
     66       window = NULL;
     67       res = -res;  // set_usage returns a negative errno.
     68       ALOGE("%s: Error setting preview window usage %d -> %s", __FUNCTION__,
     69             res, strerror(res));
     70     }
     71   }
     72   mPreviewWindow = window;
     73 
     74   return res;
     75 }
     76 
     77 status_t PreviewWindow::startPreview() {
     78   ALOGV("%s", __FUNCTION__);
     79 
     80   Mutex::Autolock locker(&mObjectLock);
     81   mPreviewEnabled = true;
     82 
     83   return NO_ERROR;
     84 }
     85 
     86 void PreviewWindow::stopPreview() {
     87   ALOGV("%s", __FUNCTION__);
     88 
     89   Mutex::Autolock locker(&mObjectLock);
     90   mPreviewEnabled = false;
     91 }
     92 
     93 /****************************************************************************
     94  * Public API
     95  ***************************************************************************/
     96 
     97 void PreviewWindow::onNextFrameAvailable(const void* /*frame*/,
     98                                          nsecs_t timestamp,
     99                                          EmulatedCameraDevice* camera_dev) {
    100   int res;
    101   Mutex::Autolock locker(&mObjectLock);
    102 
    103   if (!isPreviewEnabled() || mPreviewWindow == NULL || !isPreviewTime()) {
    104     return;
    105   }
    106 
    107   /* Make sure that preview window dimensions are OK with the camera device */
    108   if (adjustPreviewDimensions(camera_dev)) {
    109     /* Need to set / adjust buffer geometry for the preview window.
    110      * Note that in the emulator preview window uses only RGB for pixel
    111      * formats. */
    112     ALOGV("%s: Adjusting preview windows %p geometry to %dx%d", __FUNCTION__,
    113           mPreviewWindow, mPreviewFrameWidth, mPreviewFrameHeight);
    114     res = mPreviewWindow->set_buffers_geometry(
    115         mPreviewWindow, mPreviewFrameWidth, mPreviewFrameHeight,
    116         HAL_PIXEL_FORMAT_RGBA_8888);
    117     if (res != NO_ERROR) {
    118       ALOGE("%s: Error in set_buffers_geometry %d -> %s", __FUNCTION__, -res,
    119             strerror(-res));
    120       return;
    121     }
    122   }
    123 
    124   /*
    125    * Push new frame to the preview window.
    126    */
    127 
    128   /* Dequeue preview window buffer for the frame. */
    129   buffer_handle_t* buffer = NULL;
    130   int stride = 0;
    131   res = mPreviewWindow->dequeue_buffer(mPreviewWindow, &buffer, &stride);
    132   if (res != NO_ERROR || buffer == NULL) {
    133     ALOGE("%s: Unable to dequeue preview window buffer: %d -> %s", __FUNCTION__,
    134           -res, strerror(-res));
    135     return;
    136   }
    137 
    138   /* Let the preview window to lock the buffer. */
    139   res = mPreviewWindow->lock_buffer(mPreviewWindow, buffer);
    140   if (res != NO_ERROR) {
    141     ALOGE("%s: Unable to lock preview window buffer: %d -> %s", __FUNCTION__,
    142           -res, strerror(-res));
    143     mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
    144     return;
    145   }
    146 
    147   /* Now let the graphics framework to lock the buffer, and provide
    148    * us with the framebuffer data address. */
    149   void* img = NULL;
    150   res = GrallocModule::getInstance().lock(*buffer, GRALLOC_USAGE_SW_WRITE_OFTEN,
    151                                           0, 0, mPreviewFrameWidth,
    152                                           mPreviewFrameHeight, &img);
    153   if (res != NO_ERROR) {
    154     ALOGE("%s: gralloc.lock failure: %d -> %s", __FUNCTION__, res,
    155           strerror(res));
    156     mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
    157     return;
    158   }
    159 
    160   /* Frames come in in YV12/NV12/NV21 format. Since preview window doesn't
    161    * supports those formats, we need to obtain the frame in RGB565. */
    162   res = camera_dev->getCurrentPreviewFrame(img);
    163   if (res == NO_ERROR) {
    164     /* Show it. */
    165     mPreviewWindow->set_timestamp(mPreviewWindow, timestamp);
    166     mPreviewWindow->enqueue_buffer(mPreviewWindow, buffer);
    167   } else {
    168     ALOGE("%s: Unable to obtain preview frame: %d", __FUNCTION__, res);
    169     mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
    170   }
    171   GrallocModule::getInstance().unlock(*buffer);
    172 }
    173 
    174 /***************************************************************************
    175  * Private API
    176  **************************************************************************/
    177 
    178 bool PreviewWindow::adjustPreviewDimensions(EmulatedCameraDevice* camera_dev) {
    179   /* Match the cached frame dimensions against the actual ones. */
    180   if (mPreviewFrameWidth == camera_dev->getFrameWidth() &&
    181       mPreviewFrameHeight == camera_dev->getFrameHeight()) {
    182     /* They match. */
    183     return false;
    184   }
    185 
    186   /* They don't match: adjust the cache. */
    187   mPreviewFrameWidth = camera_dev->getFrameWidth();
    188   mPreviewFrameHeight = camera_dev->getFrameHeight();
    189 
    190   return true;
    191 }
    192 
    193 bool PreviewWindow::isPreviewTime() {
    194   timeval cur_time;
    195   gettimeofday(&cur_time, NULL);
    196   const uint64_t cur_mks = cur_time.tv_sec * 1000000LL + cur_time.tv_usec;
    197   if ((cur_mks - mLastPreviewed) >= mPreviewAfter) {
    198     mLastPreviewed = cur_mks;
    199     return true;
    200   }
    201   return false;
    202 }
    203 
    204 }; /* namespace android */
    205