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