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 <log/log.h>
26 #include <hardware/camera.h>
27 #include "EmulatedCameraDevice.h"
28 #include "GrallocModule.h"
29
30 namespace android {
31
PreviewWindow()32 PreviewWindow::PreviewWindow()
33 : mPreviewWindow(NULL),
34 mLastPreviewed(0),
35 mPreviewFrameWidth(0),
36 mPreviewFrameHeight(0),
37 mPreviewEnabled(false) {}
38
~PreviewWindow()39 PreviewWindow::~PreviewWindow() {}
40
41 /****************************************************************************
42 * Camera API
43 ***************************************************************************/
44
setPreviewWindow(struct preview_stream_ops * window,int preview_fps)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
startPreview()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
stopPreview()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
onNextFrameAvailable(const void *,nsecs_t timestamp,EmulatedCameraDevice * camera_dev)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
adjustPreviewDimensions(EmulatedCameraDevice * camera_dev)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
isPreviewTime()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