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