| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * Contains implementation of a class PreviewWindow that encapsulates |
| * functionality of a preview window set via set_preview_window camera HAL API. |
| */ |
| |
| #define LOG_NDEBUG 0 |
| #define LOG_TAG "EmulatedCamera_Preview" |
| #include <cutils/log.h> |
| #include <ui/Rect.h> |
| #include <ui/GraphicBufferMapper.h> |
| #include "EmulatedCameraDevice.h" |
| #include "PreviewWindow.h" |
| |
| namespace android { |
| |
| PreviewWindow::PreviewWindow() |
| : mPreviewWindow(NULL), |
| mLastPreviewed(0), |
| mPreviewFrameWidth(0), |
| mPreviewFrameHeight(0), |
| mPreviewEnabled(false) |
| { |
| } |
| |
| PreviewWindow::~PreviewWindow() |
| { |
| } |
| |
| /**************************************************************************** |
| * Camera API |
| ***************************************************************************/ |
| |
| status_t PreviewWindow::setPreviewWindow(struct preview_stream_ops* window, |
| int preview_fps) |
| { |
| ALOGV("%s: current: %p -> new: %p", __FUNCTION__, mPreviewWindow, window); |
| |
| status_t res = NO_ERROR; |
| Mutex::Autolock locker(&mObjectLock); |
| |
| /* Reset preview info. */ |
| mPreviewFrameWidth = mPreviewFrameHeight = 0; |
| mPreviewAfter = 0; |
| mLastPreviewed = 0; |
| |
| if (window != NULL) { |
| /* The CPU will write each frame to the preview window buffer. |
| * Note that we delay setting preview window buffer geometry until |
| * frames start to come in. */ |
| res = window->set_usage(window, GRALLOC_USAGE_SW_WRITE_OFTEN); |
| if (res == NO_ERROR) { |
| /* Set preview frequency. */ |
| mPreviewAfter = 1000000 / preview_fps; |
| } else { |
| window = NULL; |
| res = -res; // set_usage returns a negative errno. |
| ALOGE("%s: Error setting preview window usage %d -> %s", |
| __FUNCTION__, res, strerror(res)); |
| } |
| } |
| mPreviewWindow = window; |
| |
| return res; |
| } |
| |
| status_t PreviewWindow::startPreview() |
| { |
| ALOGV("%s", __FUNCTION__); |
| |
| Mutex::Autolock locker(&mObjectLock); |
| mPreviewEnabled = true; |
| |
| return NO_ERROR; |
| } |
| |
| void PreviewWindow::stopPreview() |
| { |
| ALOGV("%s", __FUNCTION__); |
| |
| Mutex::Autolock locker(&mObjectLock); |
| mPreviewEnabled = false; |
| } |
| |
| /**************************************************************************** |
| * Public API |
| ***************************************************************************/ |
| |
| void PreviewWindow::onNextFrameAvailable(const void* frame, |
| nsecs_t timestamp, |
| EmulatedCameraDevice* camera_dev) |
| { |
| int res; |
| Mutex::Autolock locker(&mObjectLock); |
| |
| if (!isPreviewEnabled() || mPreviewWindow == NULL || !isPreviewTime()) { |
| return; |
| } |
| |
| /* Make sure that preview window dimensions are OK with the camera device */ |
| if (adjustPreviewDimensions(camera_dev)) { |
| /* Need to set / adjust buffer geometry for the preview window. |
| * Note that in the emulator preview window uses only RGB for pixel |
| * formats. */ |
| ALOGV("%s: Adjusting preview windows %p geometry to %dx%d", |
| __FUNCTION__, mPreviewWindow, mPreviewFrameWidth, |
| mPreviewFrameHeight); |
| res = mPreviewWindow->set_buffers_geometry(mPreviewWindow, |
| mPreviewFrameWidth, |
| mPreviewFrameHeight, |
| HAL_PIXEL_FORMAT_RGBA_8888); |
| if (res != NO_ERROR) { |
| ALOGE("%s: Error in set_buffers_geometry %d -> %s", |
| __FUNCTION__, -res, strerror(-res)); |
| return; |
| } |
| } |
| |
| /* |
| * Push new frame to the preview window. |
| */ |
| |
| /* Dequeue preview window buffer for the frame. */ |
| buffer_handle_t* buffer = NULL; |
| int stride = 0; |
| res = mPreviewWindow->dequeue_buffer(mPreviewWindow, &buffer, &stride); |
| if (res != NO_ERROR || buffer == NULL) { |
| ALOGE("%s: Unable to dequeue preview window buffer: %d -> %s", |
| __FUNCTION__, -res, strerror(-res)); |
| return; |
| } |
| |
| /* Let the preview window to lock the buffer. */ |
| res = mPreviewWindow->lock_buffer(mPreviewWindow, buffer); |
| if (res != NO_ERROR) { |
| ALOGE("%s: Unable to lock preview window buffer: %d -> %s", |
| __FUNCTION__, -res, strerror(-res)); |
| mPreviewWindow->cancel_buffer(mPreviewWindow, buffer); |
| return; |
| } |
| |
| /* Now let the graphics framework to lock the buffer, and provide |
| * us with the framebuffer data address. */ |
| void* img = NULL; |
| const Rect rect(mPreviewFrameWidth, mPreviewFrameHeight); |
| GraphicBufferMapper& grbuffer_mapper(GraphicBufferMapper::get()); |
| res = grbuffer_mapper.lock(*buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, rect, &img); |
| if (res != NO_ERROR) { |
| ALOGE("%s: grbuffer_mapper.lock failure: %d -> %s", |
| __FUNCTION__, res, strerror(res)); |
| mPreviewWindow->cancel_buffer(mPreviewWindow, buffer); |
| return; |
| } |
| |
| /* Frames come in in YV12/NV12/NV21 format. Since preview window doesn't |
| * supports those formats, we need to obtain the frame in RGB565. */ |
| res = camera_dev->getCurrentPreviewFrame(img); |
| if (res == NO_ERROR) { |
| /* Show it. */ |
| mPreviewWindow->set_timestamp(mPreviewWindow, timestamp); |
| mPreviewWindow->enqueue_buffer(mPreviewWindow, buffer); |
| } else { |
| ALOGE("%s: Unable to obtain preview frame: %d", __FUNCTION__, res); |
| mPreviewWindow->cancel_buffer(mPreviewWindow, buffer); |
| } |
| grbuffer_mapper.unlock(*buffer); |
| } |
| |
| /*************************************************************************** |
| * Private API |
| **************************************************************************/ |
| |
| bool PreviewWindow::adjustPreviewDimensions(EmulatedCameraDevice* camera_dev) |
| { |
| /* Match the cached frame dimensions against the actual ones. */ |
| if (mPreviewFrameWidth == camera_dev->getFrameWidth() && |
| mPreviewFrameHeight == camera_dev->getFrameHeight()) { |
| /* They match. */ |
| return false; |
| } |
| |
| /* They don't match: adjust the cache. */ |
| mPreviewFrameWidth = camera_dev->getFrameWidth(); |
| mPreviewFrameHeight = camera_dev->getFrameHeight(); |
| |
| return true; |
| } |
| |
| bool PreviewWindow::isPreviewTime() |
| { |
| timeval cur_time; |
| gettimeofday(&cur_time, NULL); |
| const uint64_t cur_mks = cur_time.tv_sec * 1000000LL + cur_time.tv_usec; |
| if ((cur_mks - mLastPreviewed) >= mPreviewAfter) { |
| mLastPreviewed = cur_mks; |
| return true; |
| } |
| return false; |
| } |
| |
| }; /* namespace android */ |