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 
PreviewWindow()32 PreviewWindow::PreviewWindow()
33     : mPreviewWindow(NULL),
34       mLastPreviewed(0),
35       mPreviewFrameWidth(0),
36       mPreviewFrameHeight(0),
37       mPreviewEnabled(false)
38 {
39 }
40 
~PreviewWindow()41 PreviewWindow::~PreviewWindow()
42 {
43 }
44 
45 /****************************************************************************
46  * Camera API
47  ***************************************************************************/
48 
setPreviewWindow(struct preview_stream_ops * window,int preview_fps)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 
startPreview()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 
stopPreview()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 
onNextFrameAvailable(const void * frame,nsecs_t timestamp,EmulatedCameraDevice * camera_dev)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 
adjustPreviewDimensions(EmulatedCameraDevice * camera_dev)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 
isPreviewTime()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