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