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