blob: 4101ed965db7423a9944d200595b33195cf1e63b
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 |