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