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