summaryrefslogtreecommitdiff
path: root/v3/PreviewWindow.cpp (plain)
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
30namespace android {
31
32PreviewWindow::PreviewWindow()
33 : mPreviewWindow(NULL),
34 mLastPreviewed(0),
35 mPreviewFrameWidth(0),
36 mPreviewFrameHeight(0),
37 mPreviewEnabled(false)
38{
39}
40
41PreviewWindow::~PreviewWindow()
42{
43}
44
45/****************************************************************************
46 * Camera API
47 ***************************************************************************/
48
49status_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
82status_t PreviewWindow::startPreview()
83{
84 ALOGV("%s", __FUNCTION__);
85
86 Mutex::Autolock locker(&mObjectLock);
87 mPreviewEnabled = true;
88
89 return NO_ERROR;
90}
91
92void PreviewWindow::stopPreview()
93{
94 ALOGV("%s", __FUNCTION__);
95
96 Mutex::Autolock locker(&mObjectLock);
97 mPreviewEnabled = false;
98}
99
100/****************************************************************************
101 * Public API
102 ***************************************************************************/
103
104void 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
188bool 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
204bool 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