/* * 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 "EmulatedCameraDevice.h" #include "PreviewWindow.h" #include "GrallocModule.h" namespace android { PreviewWindow::PreviewWindow() : mPreviewWindow(NULL), 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; 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) { 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(nsecs_t timestamp, EmulatedCameraDevice* camera_dev) { int res; Mutex::Autolock locker(&mObjectLock); if (!isPreviewEnabled() || mPreviewWindow == NULL) { 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; res = GrallocModule::getInstance().lock( *buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, 0, 0, mPreviewFrameWidth, mPreviewFrameHeight, &img); if (res != NO_ERROR) { ALOGE("%s: gralloc.lock failure: %d -> %s", __FUNCTION__, res, strerror(res)); mPreviewWindow->cancel_buffer(mPreviewWindow, buffer); return; } int64_t frame_timestamp = 0L; /* 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, &frame_timestamp); if (res == NO_ERROR) { /* Show it. */ mPreviewWindow->set_timestamp(mPreviewWindow, frame_timestamp != 0L ? frame_timestamp : timestamp); mPreviewWindow->enqueue_buffer(mPreviewWindow, buffer); } else { ALOGE("%s: Unable to obtain preview frame: %d", __FUNCTION__, res); mPreviewWindow->cancel_buffer(mPreviewWindow, buffer); } GrallocModule::getInstance().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; } }; /* namespace android */