TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / android / camera / PreviewWindow.cpp
diff --git a/src/type3_AndroidCloud/anbox-master/android/camera/PreviewWindow.cpp b/src/type3_AndroidCloud/anbox-master/android/camera/PreviewWindow.cpp
new file mode 100644 (file)
index 0000000..4101ed9
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * 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 */