From 6e4f410a95ce328a6bb9113ed1597c66f3f77177 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Tue, 7 Jul 2015 12:48:39 +0200 Subject: Remove eAndroid specific modules Change-Id: Ied9d920dfa6d12093b40d32d5f3a61c1c23b137d Reviewed-by: Gatis Paeglis --- .exclude | 1 - src/doppelganger/appops.cpp | 50 - src/doppelganger/appops.h | 29 - src/doppelganger/doppelganger.pro | 22 - src/doppelganger/main.cpp | 36 - src/doppelganger/permissioncontroller.cpp | 38 - src/doppelganger/permissioncontroller.h | 35 - src/doppelganger/powermanager.cpp | 88 -- src/doppelganger/powermanager.h | 62 - src/doppelganger/schedulingpolicyservice.cpp | 88 -- src/doppelganger/schedulingpolicyservice.h | 44 - src/imports/nativemedia/BufferQueue.cpp | 1061 ----------------- src/imports/nativemedia/BufferQueue.h | 490 -------- src/imports/nativemedia/SurfaceTexture.cpp | 23 - src/imports/nativemedia/SurfaceTexture.h | 23 - src/imports/nativemedia/SurfaceTexture_4_0.cpp | 1236 -------------------- src/imports/nativemedia/SurfaceTexture_4_0.h | 517 -------- src/imports/nativemedia/SurfaceTexture_4_1.cpp | 866 -------------- src/imports/nativemedia/SurfaceTexture_4_1.h | 420 ------- src/imports/nativemedia/main.cpp | 73 -- src/imports/nativemedia/nativemedia.pro | 21 - src/imports/nativemedia/omx.cpp | 666 ----------- src/imports/nativemedia/omxmodule.cpp | 37 - src/imports/nativemedia/omxnode.cpp | 204 ---- src/imports/nativemedia/omxnode.h | 129 -- src/imports/nativemedia/omxplayer.h | 42 - src/imports/nativemedia/qmldir | 2 - src/imports/nativemedia/test.qml | 53 - src/plugins/plugins.pro | 3 - src/plugins/sensors/eandroid/eandroid.pro | 30 - .../sensors/eandroid/eandroidaccelerometer.cpp | 38 - .../sensors/eandroid/eandroidaccelerometer.h | 38 - .../eandroid/eandroidambientlightsensor.cpp | 47 - .../sensors/eandroid/eandroidambientlightsensor.h | 38 - .../sensors/eandroid/eandroidbasesensor.cpp | 59 - src/plugins/sensors/eandroid/eandroidbasesensor.h | 40 - src/plugins/sensors/eandroid/eandroidgyroscope.cpp | 40 - src/plugins/sensors/eandroid/eandroidgyroscope.h | 38 - src/plugins/sensors/eandroid/eandroidlight.cpp | 36 - src/plugins/sensors/eandroid/eandroidlight.h | 38 - .../sensors/eandroid/eandroidmagnetometer.cpp | 57 - .../sensors/eandroid/eandroidmagnetometer.h | 38 - .../sensors/eandroid/eandroidrotationsensor.cpp | 42 - .../sensors/eandroid/eandroidrotationsensor.h | 38 - .../sensors/eandroid/eandroidsensordevice.cpp | 212 ---- .../sensors/eandroid/eandroidsensordevice.h | 99 -- src/plugins/sensors/eandroid/main.cpp | 142 --- src/plugins/sensors/eandroid/plugin.json | 1 - src/plugins/sensors/sensors.pro | 3 - src/qconnectivity/main.cpp | 476 -------- src/qconnectivity/qconnectivity.pro | 13 - src/qt_hw_init/main.cpp | 30 - src/qt_hw_init/qt_hw_init.pro | 8 - src/src.pro | 4 - 54 files changed, 7964 deletions(-) delete mode 100644 .exclude delete mode 100644 src/doppelganger/appops.cpp delete mode 100644 src/doppelganger/appops.h delete mode 100644 src/doppelganger/doppelganger.pro delete mode 100644 src/doppelganger/main.cpp delete mode 100644 src/doppelganger/permissioncontroller.cpp delete mode 100644 src/doppelganger/permissioncontroller.h delete mode 100644 src/doppelganger/powermanager.cpp delete mode 100644 src/doppelganger/powermanager.h delete mode 100644 src/doppelganger/schedulingpolicyservice.cpp delete mode 100644 src/doppelganger/schedulingpolicyservice.h delete mode 100644 src/imports/nativemedia/BufferQueue.cpp delete mode 100644 src/imports/nativemedia/BufferQueue.h delete mode 100644 src/imports/nativemedia/SurfaceTexture.cpp delete mode 100644 src/imports/nativemedia/SurfaceTexture.h delete mode 100644 src/imports/nativemedia/SurfaceTexture_4_0.cpp delete mode 100644 src/imports/nativemedia/SurfaceTexture_4_0.h delete mode 100644 src/imports/nativemedia/SurfaceTexture_4_1.cpp delete mode 100644 src/imports/nativemedia/SurfaceTexture_4_1.h delete mode 100644 src/imports/nativemedia/main.cpp delete mode 100644 src/imports/nativemedia/nativemedia.pro delete mode 100644 src/imports/nativemedia/omx.cpp delete mode 100644 src/imports/nativemedia/omxmodule.cpp delete mode 100644 src/imports/nativemedia/omxnode.cpp delete mode 100644 src/imports/nativemedia/omxnode.h delete mode 100644 src/imports/nativemedia/omxplayer.h delete mode 100644 src/imports/nativemedia/qmldir delete mode 100644 src/imports/nativemedia/test.qml delete mode 100644 src/plugins/plugins.pro delete mode 100644 src/plugins/sensors/eandroid/eandroid.pro delete mode 100644 src/plugins/sensors/eandroid/eandroidaccelerometer.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidaccelerometer.h delete mode 100644 src/plugins/sensors/eandroid/eandroidambientlightsensor.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidambientlightsensor.h delete mode 100644 src/plugins/sensors/eandroid/eandroidbasesensor.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidbasesensor.h delete mode 100644 src/plugins/sensors/eandroid/eandroidgyroscope.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidgyroscope.h delete mode 100644 src/plugins/sensors/eandroid/eandroidlight.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidlight.h delete mode 100644 src/plugins/sensors/eandroid/eandroidmagnetometer.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidmagnetometer.h delete mode 100644 src/plugins/sensors/eandroid/eandroidrotationsensor.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidrotationsensor.h delete mode 100644 src/plugins/sensors/eandroid/eandroidsensordevice.cpp delete mode 100644 src/plugins/sensors/eandroid/eandroidsensordevice.h delete mode 100644 src/plugins/sensors/eandroid/main.cpp delete mode 100644 src/plugins/sensors/eandroid/plugin.json delete mode 100644 src/plugins/sensors/sensors.pro delete mode 100644 src/qconnectivity/main.cpp delete mode 100644 src/qconnectivity/qconnectivity.pro delete mode 100644 src/qt_hw_init/main.cpp delete mode 100644 src/qt_hw_init/qt_hw_init.pro diff --git a/.exclude b/.exclude deleted file mode 100644 index 34ed1e1..0000000 --- a/.exclude +++ /dev/null @@ -1 +0,0 @@ -src/imports/nativemedia diff --git a/src/doppelganger/appops.cpp b/src/doppelganger/appops.cpp deleted file mode 100644 index adeddcc..0000000 --- a/src/doppelganger/appops.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://qt.digia.com/ -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://qt.digia.com/ -** -****************************************************************************/ - -#include "appops.h" - -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 4) -#include -#include - -class AppOpsPrivate : public android::BnAppOpsCallback -{ -public: - virtual void opChanged(int32_t, const android::String16&) - { - - } - - virtual android::status_t onTransact(uint32_t, - const android::Parcel&, - android::Parcel*, - uint32_t flags = 0) - { - (void)flags; - return android::OK; - } -}; -#endif - -void AppOps::instantiate() -{ -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 4) - android::defaultServiceManager()->addService(android::String16("appops"), new AppOpsPrivate); -#endif -} diff --git a/src/doppelganger/appops.h b/src/doppelganger/appops.h deleted file mode 100644 index 5e765a6..0000000 --- a/src/doppelganger/appops.h +++ /dev/null @@ -1,29 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://qt.digia.com/ -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://qt.digia.com/ -** -****************************************************************************/ - -#ifndef APPOPS_H -#define APPOPS_H - -class AppOps -{ -public: - static void instantiate(); -}; - -#endif // APPOPS_H diff --git a/src/doppelganger/doppelganger.pro b/src/doppelganger/doppelganger.pro deleted file mode 100644 index fa91169..0000000 --- a/src/doppelganger/doppelganger.pro +++ /dev/null @@ -1,22 +0,0 @@ -QT -= core gui - -TARGET = doppelganger - -LIBS += -lutils -lbinder -lcutils \ - -L$${ANDROID_PRODUCT_OUT}/obj/STATIC_LIBRARIES/libscheduling_policy_intermediates -lscheduling_policy -lpowermanager - -TEMPLATE = app - -SOURCES += main.cpp \ - permissioncontroller.cpp \ - schedulingpolicyservice.cpp \ - powermanager.cpp \ - appops.cpp - -HEADERS += \ - permissioncontroller.h \ - schedulingpolicyservice.h \ - powermanager.h \ - appops.h - -load(qt_tool) diff --git a/src/doppelganger/main.cpp b/src/doppelganger/main.cpp deleted file mode 100644 index 3e86a66..0000000 --- a/src/doppelganger/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include - -#include "permissioncontroller.h" -#include "schedulingpolicyservice.h" -#include "powermanager.h" -#include "appops.h" - -using namespace android; - -int main(int, char *[]) -{ - sp proc(ProcessState::self()); - SchedulingPolicyService::instantiate(); - PermissionController::instantiate(); - PowerManager::instantiate(); - AppOps::instantiate(); - IPCThreadState::self()->joinThreadPool(); -} diff --git a/src/doppelganger/permissioncontroller.cpp b/src/doppelganger/permissioncontroller.cpp deleted file mode 100644 index 9538b1a..0000000 --- a/src/doppelganger/permissioncontroller.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "permissioncontroller.h" - -#include - -using namespace android; - -PermissionController::PermissionController() -{ -} - -void PermissionController::instantiate() -{ - defaultServiceManager()->addService(String16("permission"), new PermissionController); -} - -bool PermissionController::checkPermission(const String16 &, int32_t, int32_t) -{ - // just bypass any permission - return true; -} diff --git a/src/doppelganger/permissioncontroller.h b/src/doppelganger/permissioncontroller.h deleted file mode 100644 index 211a346..0000000 --- a/src/doppelganger/permissioncontroller.h +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef PERMISSIONCONTROLLER_H -#define PERMISSIONCONTROLLER_H - -#include - -class PermissionController : public android::BnPermissionController -{ -public: - static void instantiate(); - - bool checkPermission(const android::String16 &permission, int32_t pid, int32_t uid); - -private: - PermissionController(); -}; - -#endif // PERMISSIONCONTROLLER_H diff --git a/src/doppelganger/powermanager.cpp b/src/doppelganger/powermanager.cpp deleted file mode 100644 index 7f0da97..0000000 --- a/src/doppelganger/powermanager.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ - -#include "powermanager.h" - -#include - -using namespace android; - -enum { - ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION, - ACQUIRE_WAKE_LOCK_UID = IBinder::FIRST_CALL_TRANSACTION + 1, - RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 2, - UPDATE_WAKE_LOCK_UIDS = IBinder::FIRST_CALL_TRANSACTION + 3, -}; - -void PowerManager::instantiate() -{ - defaultServiceManager()->addService(String16("power"), new PowerManager()); -} - -status_t PowerManager::onTransact(uint32_t code, - const Parcel &, - Parcel *, - uint32_t) -{ - switch (code) { - case ACQUIRE_WAKE_LOCK: - case ACQUIRE_WAKE_LOCK_UID: - case RELEASE_WAKE_LOCK: - case UPDATE_WAKE_LOCK_UIDS: - return NO_ERROR; - default: - break; - } -} - -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 4) -status_t PowerManager::acquireWakeLock(int, - const sp &, - const String16 &, - const String16 &) -{ - return OK; -} - -status_t PowerManager::acquireWakeLockWithUid(int, - const sp &, - const String16 &, - const String16 &, - int) -{ - return OK; -} - -status_t PowerManager::updateWakeLockUids(const sp &, - int, - const int *) -{ - return OK; -} -#else // < 4.4 -status_t PowerManager::acquireWakeLock(int, const sp &, const String16 &) -{ - return OK; -} -#endif - -status_t PowerManager::releaseWakeLock(const sp &, int) -{ - return OK; -} diff --git a/src/doppelganger/powermanager.h b/src/doppelganger/powermanager.h deleted file mode 100644 index 23f2695..0000000 --- a/src/doppelganger/powermanager.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ - -#ifndef POWERMANAGER_H -#define POWERMANAGER_H - -#include - -namespace android { - -typedef BnInterface BnPowerManagerService; - -} // namespace android - -class PowerManager : public android::BnPowerManagerService -{ -public: - static void instantiate(); - android::status_t onTransact(uint32_t code, - const android::Parcel &data, - android::Parcel *reply, - uint32_t flags); - -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 4) - virtual android::status_t acquireWakeLock(int flags, - const android::sp& lock, - const android::String16& tag, - const android::String16& packageName); - virtual android::status_t acquireWakeLockWithUid(int flags, - const android::sp& lock, - const android::String16& tag, - const android::String16& packageName, - int uid); - virtual android::status_t updateWakeLockUids(const android::sp& lock, - int len, - const int *uids); -#else // < 4.4 - virtual android::status_t acquireWakeLock(int flags, - const android::sp& lock, - const android::String16& tag); -#endif - - virtual android::status_t releaseWakeLock(const android::sp& lock, int flags); -}; - -#endif // POWERMANAGER_H diff --git a/src/doppelganger/schedulingpolicyservice.cpp b/src/doppelganger/schedulingpolicyservice.cpp deleted file mode 100644 index 7113e6a..0000000 --- a/src/doppelganger/schedulingpolicyservice.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "schedulingpolicyservice.h" - -#include -#include -#include -#include - -using namespace android; - -enum { - REQUEST_PRIORITY_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION -}; - -#define PRIORITY_MIN 1 -#define PRIORITY_MAX 3 - -SchedulingPolicyService::SchedulingPolicyService() -{ -} - -void SchedulingPolicyService::instantiate() -{ - defaultServiceManager()->addService(String16("scheduling_policy"), new SchedulingPolicyService); -} - -status_t SchedulingPolicyService::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) -{ - switch (code) { - case REQUEST_PRIORITY_TRANSACTION: { - CHECK_INTERFACE(ISchedulingPolicyService, data, reply); - int32_t pid = data.readInt32(); - int32_t tid = data.readInt32(); - int32_t prio = data.readInt32(); - int res = requestPriority_helper(pid, tid, prio); - reply->writeNoException(); - reply->writeInt32(res); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 3 -int SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t prio) -#else -int SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t prio, bool) -#endif -{ - return requestPriority_helper(pid, tid, prio); -} - -int SchedulingPolicyService::requestPriority_helper(int32_t pid, int32_t tid, int32_t prio) -{ - if (prio < PRIORITY_MIN || prio > PRIORITY_MAX) - return PERMISSION_DENIED; - - int res = set_sched_policy(tid, IPCThreadState::self()->getCallingPid() == pid ? SP_AUDIO_SYS - : SP_AUDIO_APP); - if (res != NO_ERROR) - return PERMISSION_DENIED; - - struct sched_param param; - param.sched_priority = prio; - res = sched_setscheduler(tid, SCHED_FIFO, ¶m); - if (res) - return PERMISSION_DENIED; - - return OK; -} diff --git a/src/doppelganger/schedulingpolicyservice.h b/src/doppelganger/schedulingpolicyservice.h deleted file mode 100644 index 2dc1e42..0000000 --- a/src/doppelganger/schedulingpolicyservice.h +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef SCHEDULINGPOLICYSERVICE_H -#define SCHEDULINGPOLICYSERVICE_H - -#include -#include - -class SchedulingPolicyService : public android::BnSchedulingPolicyService -{ -public: - static void instantiate(); - - android::status_t onTransact(uint32_t code, const android::Parcel &data, - android::Parcel *reply, uint32_t flags); - -#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 3 - int requestPriority(int32_t pid, int32_t tid, int32_t prio); -#else - int requestPriority(int32_t pid, int32_t tid, int32_t prio, bool); -#endif - -private: - SchedulingPolicyService(); - int requestPriority_helper(int32_t pid, int32_t tid, int32_t prio); -}; - -#endif // SCHEDULINGPOLICYSERVICE_H diff --git a/src/imports/nativemedia/BufferQueue.cpp b/src/imports/nativemedia/BufferQueue.cpp deleted file mode 100644 index 1dbd498..0000000 --- a/src/imports/nativemedia/BufferQueue.cpp +++ /dev/null @@ -1,1061 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 1) - -#define LOG_TAG "BufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include -#include - -#include -#include -#include - -#include -#include -#include - -// This compile option causes SurfaceTexture to return the buffer that is currently -// attached to the GL texture from dequeueBuffer when no other buffers are -// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do -// implicit cross-process synchronization to prevent the buffer from being -// written to before the buffer has (a) been detached from the GL texture and -// (b) all GL reads from the buffer have completed. - -// During refactoring, do not support dequeuing the current buffer -#undef ALLOW_DEQUEUE_CURRENT_BUFFER - -#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER -#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true -#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled" -#else -#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false -#endif - -// Macros for including the BufferQueue name in log messages -#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) - -#define ATRACE_BUFFER_INDEX(index) \ - if (ATRACE_ENABLED()) { \ - char ___traceBuf[1024]; \ - snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(), \ - (index)); \ - android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ - } - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -static const char* scalingModeName(int scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) : - mDefaultWidth(1), - mDefaultHeight(1), - mPixelFormat(PIXEL_FORMAT_RGBA_8888), - mMinUndequeuedBuffers(bufferCount), - mMinAsyncBufferSlots(bufferCount + 1), - mMinSyncBufferSlots(bufferCount), - mBufferCount(mMinAsyncBufferSlots), - mClientBufferCount(0), - mServerBufferCount(mMinAsyncBufferSlots), - mSynchronousMode(false), - mAllowSynchronousMode(allowSynchronousMode), - mConnectedApi(NO_CONNECTED_API), - mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false), - mDefaultBufferFormat(0), - mConsumerUsageBits(0), - mTransformHint(0) -{ - // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - ST_LOGV("BufferQueue"); -#if 0 - sp composer(ComposerService::getComposerService()); - mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); - if (mGraphicBufferAlloc == 0) { - ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()"); - } -#endif -} - -BufferQueue::~BufferQueue() { - ST_LOGV("~BufferQueue"); -} - -status_t BufferQueue::setBufferCountServerLocked(int bufferCount) { - if (bufferCount > NUM_BUFFER_SLOTS) - return BAD_VALUE; - - // special-case, nothing to do - if (bufferCount == mBufferCount) - return OK; - - if (!mClientBufferCount && - bufferCount >= mBufferCount) { - // easy, we just have more buffers - mBufferCount = bufferCount; - mServerBufferCount = bufferCount; - mDequeueCondition.broadcast(); - } else { - // we're here because we're either - // - reducing the number of available buffers - // - or there is a client-buffer-count in effect - - // less than 2 buffers is never allowed - if (bufferCount < 2) - return BAD_VALUE; - - // when there is non client-buffer-count in effect, the client is not - // allowed to dequeue more than one buffer at a time, - // so the next time they dequeue a buffer, we know that they don't - // own one. the actual resizing will happen during the next - // dequeueBuffer. - - mServerBufferCount = bufferCount; - mDequeueCondition.broadcast(); - } - return OK; -} - -bool BufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - -void BufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock lock(mMutex); - mDefaultBufferFormat = defaultFormat; - return OK; -} - -status_t BufferQueue::setConsumerUsageBits(uint32_t usage) { - Mutex::Autolock lock(mMutex); - mConsumerUsageBits = usage; - return OK; -} - -status_t BufferQueue::setTransformHint(uint32_t hint) { - Mutex::Autolock lock(mMutex); - mTransformHint = hint; - return OK; -} - -status_t BufferQueue::setBufferCount(int bufferCount) { - ST_LOGV("setBufferCount: count=%d", bufferCount); - - sp listener; - { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (bufferCount > NUM_BUFFER_SLOTS) { - ST_LOGE("setBufferCount: bufferCount larger than slots available"); - return BAD_VALUE; - } - - // Error out if the user has dequeued buffers - for (int i=0 ; i= minBufferSlots) ? - mServerBufferCount : minBufferSlots; - return setBufferCountServerLocked(bufferCount); - } - - if (bufferCount < minBufferSlots) { - ST_LOGE("setBufferCount: requested buffer count (%d) is less than " - "minimum (%d)", bufferCount, minBufferSlots); - return BAD_VALUE; - } - - // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. - freeAllBuffersLocked(); - mBufferCount = bufferCount; - mClientBufferCount = bufferCount; - mBufferHasBeenQueued = false; - mQueue.clear(); - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } // scope for lock - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return OK; -} - -int BufferQueue::query(int what, int* outValue) -{ - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("query: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mPixelFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mSynchronousMode ? - (mMinUndequeuedBuffers-1) : mMinUndequeuedBuffers; - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mQueue.size() >= 2); - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - -status_t BufferQueue::requestBuffer(int slot, sp* buf) { - ATRACE_CALL(); - ST_LOGV("requestBuffer: slot=%d", slot); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (slot < 0 || mBufferCount <= slot) { - ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", - mBufferCount, slot); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, - uint32_t format, uint32_t usage) { - ATRACE_CALL(); - ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); - - if ((w && !h) || (!w && h)) { - ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); - return BAD_VALUE; - } - - status_t returnFlags(OK); - EGLDisplay dpy = EGL_NO_DISPLAY; - EGLSyncKHR fence = EGL_NO_SYNC_KHR; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (format == 0) { - format = mDefaultBufferFormat; - } - // turn on usage bits the consumer requested - usage |= mConsumerUsageBits; - - int found = -1; - int foundSync = -1; - int dequeuedCount = 0; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - // We need to wait for the FIFO to drain if the number of buffer - // needs to change. - // - // The condition "number of buffers needs to change" is true if - // - the client doesn't care about how many buffers there are - // - AND the actual number of buffer is different from what was - // set in the last setBufferCountServer() - // - OR - - // setBufferCountServer() was set to a value incompatible with - // the synchronization mode (for instance because the sync mode - // changed since) - // - // As long as this condition is true AND the FIFO is not empty, we - // wait on mDequeueCondition. - - const int minBufferCountNeeded = mSynchronousMode ? - mMinSyncBufferSlots : mMinAsyncBufferSlots; - - const bool numberOfBuffersNeedsToChange = !mClientBufferCount && - ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded)); - - if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { - // wait for the FIFO to drain - mDequeueCondition.wait(mMutex); - // NOTE: we continue here because we need to reevaluate our - // whole state (eg: we could be abandoned or disconnected) - continue; - } - - if (numberOfBuffersNeedsToChange) { - // here we're guaranteed that mQueue is empty - freeAllBuffersLocked(); - mBufferCount = mServerBufferCount; - if (mBufferCount < minBufferCountNeeded) - mBufferCount = minBufferCountNeeded; - mBufferHasBeenQueued = false; - returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; - } - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - foundSync = INVALID_BUFFER_SLOT; - dequeuedCount = 0; - for (int i = 0; i < mBufferCount; i++) { - const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; - } - - // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) - // but dequeuing the current buffer is disabled. - if (false) { - // This functionality has been temporarily removed so - // BufferQueue and SurfaceTexture can be refactored into - // separate objects - } else { - if (state == BufferSlot::FREE) { - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - bool isOlder = mSlots[i].mFrameNumber < - mSlots[found].mFrameNumber; - if (found < 0 || isOlder) { - foundSync = i; - found = i; - } - } - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mClientBufferCount && dequeuedCount) { - ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the - // mMinUndequeuedBuffers check below. - if (mBufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int avail = mBufferCount - (dequeuedCount+1); - if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) { - ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded " - "(dequeued=%d)", - mMinUndequeuedBuffers-int(mSynchronousMode), - dequeuedCount); - return -EBUSY; - } - } - - // if no buffer is found, wait for a buffer to be released - tryAgain = found == INVALID_BUFFER_SLOT; - if (tryAgain) { - mDequeueCondition.wait(mMutex); - } - } - - - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ST_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - const int buf = found; - *outBuf = found; - - ATRACE_BUFFER_INDEX(buf); - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - const bool updateFormat = (format != 0); - if (!updateFormat) { - // keep the current (or default) format - format = mPixelFormat; - } - - // buffer is now in DEQUEUED (but can also be current at the same time, - // if we're in synchronous mode) - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - status_t error; - sp graphicBuffer = new GraphicBuffer(w, h, format, usage); - if (graphicBuffer == 0) { - ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " - "failed"); - return error; - } - if (updateFormat) { - mPixelFormat = format; - } - - mSlots[buf].mAcquireCalled = false; - mSlots[buf].mGraphicBuffer = graphicBuffer; - mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = EGL_NO_SYNC_KHR; - mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - - returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; - } - - dpy = mSlots[buf].mEglDisplay; - fence = mSlots[buf].mFence; - mSlots[buf].mFence = EGL_NO_SYNC_KHR; - } // end lock scope - - if (fence != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); - // If something goes wrong, log the error, but return the buffer without - // synchronizing access to it. It's too late at this point to abort the - // dequeue operation. - if (result == EGL_FALSE) { - ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError()); - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ST_LOGE("dequeueBuffer: timeout waiting for fence"); - } - eglDestroySyncKHR(dpy, fence); - } - - ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, - mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t BufferQueue::setSynchronousMode(bool enabled) { - ATRACE_CALL(); - ST_LOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - status_t err = OK; - if (!mAllowSynchronousMode && enabled) - return err; - - if (!enabled) { - // going to asynchronous mode, drain the queue - err = drainQueueLocked(); - if (err != NO_ERROR) - return err; - } - - if (mSynchronousMode != enabled) { - // - if we're going to asynchronous mode, the queue is guaranteed to be - // empty here - // - if the client set the number of buffers, we're guaranteed that - // we have at least 3 (because we don't allow less) - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return err; -} - -status_t BufferQueue::queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output) { - ATRACE_CALL(); - ATRACE_BUFFER_INDEX(buf); - - Rect crop; - uint32_t transform; - int scalingMode; - int64_t timestamp; - - input.deflate(×tamp, &crop, &scalingMode, &transform); - - ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " - "scale=%s", - buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - sp listener; - - { // scope for the lock - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (buf < 0 || buf >= mBufferCount) { - ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", - mBufferCount, buf); - return -EINVAL; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("queueBuffer: slot %d is not owned by the client " - "(state=%d)", buf, mSlots[buf].mBufferState); - return -EINVAL; - } else if (!mSlots[buf].mRequestBufferCalled) { - ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", buf); - return -EINVAL; - } - - const sp& graphicBuffer(mSlots[buf].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedCrop; - crop.intersect(bufferRect, &croppedCrop); - if (croppedCrop != crop) { - ST_LOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", buf); - return -EINVAL; - } - - if (mSynchronousMode) { - // In synchronous mode we queue all buffers in a FIFO. - mQueue.push_back(buf); - - // Synchronous mode always signals that an additional frame should - // be consumed. - listener = mConsumerListener; - } else { - // In asynchronous mode we only keep the most recent buffer. - if (mQueue.empty()) { - mQueue.push_back(buf); - - // Asynchronous mode only signals that a frame should be - // consumed if no previous frame was pending. If a frame were - // pending then the consumer would have already been notified. - listener = mConsumerListener; - } else { - Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; - // and we record the new buffer index in the queued list - *front = buf; - } - } - - mSlots[buf].mTimestamp = timestamp; - mSlots[buf].mCrop = crop; - mSlots[buf].mTransform = transform; - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode); - scalingMode = mSlots[buf].mScalingMode; - break; - } - - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mSlots[buf].mScalingMode = scalingMode; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - - mBufferHasBeenQueued = true; - mDequeueCondition.broadcast(); - - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - - ATRACE_INT(mConsumerName.string(), mQueue.size()); - } // scope for the lock - - // call back without lock held - if (listener != 0) { - listener->onFrameAvailable(); - } - return OK; -} - -void BufferQueue::cancelBuffer(int buf) { - ATRACE_CALL(); - ST_LOGV("cancelBuffer: slot=%d", buf); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGW("cancelBuffer: BufferQueue has been abandoned!"); - return; - } - - if (buf < 0 || buf >= mBufferCount) { - ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", - mBufferCount, buf); - return; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - buf, mSlots[buf].mBufferState); - return; - } - mSlots[buf].mBufferState = BufferSlot::FREE; - mSlots[buf].mFrameNumber = 0; - mDequeueCondition.broadcast(); -} - -status_t BufferQueue::connect(int api, QueueBufferOutput* output) { - ATRACE_CALL(); - ST_LOGV("connect: api=%d", api); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("connect: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mConsumerListener == NULL) { - ST_LOGE("connect: BufferQueue has no consumer!"); - return NO_INIT; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi != NO_CONNECTED_API) { - ST_LOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } else { - mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - } - break; - default: - err = -EINVAL; - break; - } - - mBufferHasBeenQueued = false; - - return err; -} - -status_t BufferQueue::disconnect(int api) { - ATRACE_CALL(); - ST_LOGV("disconnect: api=%d", api); - - int err = NO_ERROR; - sp listener; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // it is not really an error to disconnect after the surface - // has been abandoned, it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - drainQueueAndFreeBuffersLocked(); - mConnectedApi = NO_CONNECTED_API; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } else { - ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } - break; - default: - ST_LOGE("disconnect: unknown API %d", api); - err = -EINVAL; - break; - } - } - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return err; -} - -void BufferQueue::dump(String8& result) const -{ - char buffer[1024]; - BufferQueue::dump(result, "", buffer, 1024); -} - -void BufferQueue::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } - - snprintf(buffer, SIZE, - "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "mPixelFormat=%d, FIFO(%d)={%s}\n", - prefix, mBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mPixelFormat, fifoSize, fifo.string()); - result.append(buffer); - - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - for (int i=0 ; i":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp, - scalingModeName(slot.mScalingMode) - ); - result.append(buffer); - - const sp& buf(slot.mGraphicBuffer); - if (buf != NULL) { - snprintf(buffer, SIZE, - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - result.append(buffer); - } - result.append("\n"); - } -} - -void BufferQueue::freeBufferLocked(int i) { - mSlots[i].mGraphicBuffer = 0; - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - mSlots[i].mNeedsCleanupOnRelease = true; - } - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - - // destroy fence as BufferQueue now takes ownership - if (mSlots[i].mFence != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence); - mSlots[i].mFence = EGL_NO_SYNC_KHR; - } -} - -void BufferQueue::freeAllBuffersLocked() { - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } -} - -status_t BufferQueue::acquireBuffer(BufferItem *buffer) { - ATRACE_CALL(); - Mutex::Autolock _l(mMutex); - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = *front; - - ATRACE_BUFFER_INDEX(buf); - - if (mSlots[buf].mAcquireCalled) { - buffer->mGraphicBuffer = NULL; - } else { - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - } - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mTimestamp = mSlots[buf].mTimestamp; - buffer->mBuf = buf; - mSlots[buf].mAcquireCalled = true; - - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mQueue.erase(front); - mDequeueCondition.broadcast(); - - ATRACE_INT(mConsumerName.string(), mQueue.size()); - } else { - return NO_BUFFER_AVAILABLE; - } - - return OK; -} - -status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, - EGLSyncKHR fence) { - ATRACE_CALL(); - ATRACE_BUFFER_INDEX(buf); - - Mutex::Autolock _l(mMutex); - - if (buf == INVALID_BUFFER_SLOT) { - return -EINVAL; - } - - mSlots[buf].mEglDisplay = display; - mSlots[buf].mFence = fence; - - // The buffer can now only be released if its in the acquired state - if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mBufferState = BufferSlot::FREE; - } else if (mSlots[buf].mNeedsCleanupOnRelease) { - ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); - mSlots[buf].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); - return -EINVAL; - } - - mDequeueCondition.broadcast(); - return OK; -} - -status_t BufferQueue::consumerConnect(const sp& consumerListener) { - ST_LOGV("consumerConnect"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("consumerConnect: BufferQueue has been abandoned!"); - return NO_INIT; - } - - mConsumerListener = consumerListener; - - return OK; -} - -status_t BufferQueue::consumerDisconnect() { - ST_LOGV("consumerDisconnect"); - Mutex::Autolock lock(mMutex); - - if (mConsumerListener == NULL) { - ST_LOGE("consumerDisconnect: No consumer is connected!"); - return -EINVAL; - } - - mAbandoned = true; - mConsumerListener = NULL; - mQueue.clear(); - freeAllBuffersLocked(); - mDequeueCondition.broadcast(); - return OK; -} - -status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) { - ST_LOGV("getReleasedBuffers"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("getReleasedBuffers: BufferQueue has been abandoned!"); - return NO_INIT; - } - - uint32_t mask = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (!mSlots[i].mAcquireCalled) { - mask |= 1 << i; - } - } - *slotMask = mask; - - ST_LOGV("getReleasedBuffers: returning mask %#x", mask); - return NO_ERROR; -} - -status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return OK; -} - -status_t BufferQueue::setBufferCountServer(int bufferCount) { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - return setBufferCountServerLocked(bufferCount); -} - -void BufferQueue::freeAllBuffersExceptHeadLocked() { - int head = -1; - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - head = *front; - } - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (i != head) { - freeBufferLocked(i); - } - } -} - -status_t BufferQueue::drainQueueLocked() { - while (mSynchronousMode && !mQueue.isEmpty()) { - mDequeueCondition.wait(mMutex); - if (mAbandoned) { - ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!"); - return NO_INIT; - } - if (mConnectedApi == NO_CONNECTED_API) { - ST_LOGE("drainQueueLocked: BufferQueue is not connected!"); - return NO_INIT; - } - } - return NO_ERROR; -} - -status_t BufferQueue::drainQueueAndFreeBuffersLocked() { - status_t err = drainQueueLocked(); - if (err == NO_ERROR) { - if (mSynchronousMode) { - freeAllBuffersLocked(); - } else { - freeAllBuffersExceptHeadLocked(); - } - } - return err; -} - -BufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp& consumerListener): - mConsumerListener(consumerListener) {} - -BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -void BufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} - -void BufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -}; // namespace android - -#endif diff --git a/src/imports/nativemedia/BufferQueue.h b/src/imports/nativemedia/BufferQueue.h deleted file mode 100644 index 1c80d0c..0000000 --- a/src/imports/nativemedia/BufferQueue.h +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -#ifndef ANDROID_GUI_BUFFERQUEUE_H -#define ANDROID_GUI_BUFFERQUEUE_H - -#include -#include - -#include -#include - -#include - -#include -#include -#include - -namespace android { -// ---------------------------------------------------------------------------- - -class BufferQueue : public BnSurfaceTexture { -public: - enum { MIN_UNDEQUEUED_BUFFERS = 2 }; - enum { NUM_BUFFER_SLOTS = 32 }; - enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; - enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE }; - - // ConsumerListener is the interface through which the BufferQueue notifies - // the consumer of events that the consumer may wish to react to. Because - // the consumer will generally have a mutex that is locked during calls from - // teh consumer to the BufferQueue, these calls from the BufferQueue to the - // consumer *MUST* be called only when the BufferQueue mutex is NOT locked. - struct ConsumerListener : public virtual RefBase { - // onFrameAvailable is called from queueBuffer each time an additional - // frame becomes available for consumption. This means that frames that - // are queued while in asynchronous mode only trigger the callback if no - // previous frames are pending. Frames queued while in synchronous mode - // always trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - - // onBuffersReleased is called to notify the buffer consumer that the - // BufferQueue has released its references to one or more GraphicBuffers - // contained in its slots. The buffer consumer should then call - // BufferQueue::getReleasedBuffers to retrieve the list of buffers - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onBuffersReleased() = 0; - }; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // BufferQueue object and the consumer object. The reason this can't be a weak - // reference in the BufferQueue class is because we're planning to expose the - // consumer side of a BufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public BufferQueue::ConsumerListener { - public: - - ProxyConsumerListener(const wp& consumerListener); - virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - private: - - // mConsumerListener is a weak reference to the ConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp mConsumerListener; - }; - - - // BufferQueue manages a pool of gralloc memory slots to be used - // by producers and consumers. - // allowSynchronousMode specifies whether or not synchronous mode can be - // enabled. - // bufferCount sets the minimum number of undequeued buffers for this queue - BufferQueue( bool allowSynchronousMode = true, int bufferCount = MIN_UNDEQUEUED_BUFFERS); - virtual ~BufferQueue(); - - virtual int query(int what, int* value); - - // setBufferCount updates the number of available buffer slots. After - // calling this all buffer slots are both unallocated and owned by the - // BufferQueue object (i.e. they are not owned by the client). - virtual status_t setBufferCount(int bufferCount); - - virtual status_t requestBuffer(int slot, sp* buf); - - // dequeueBuffer gets the next buffer slot index for the client to use. If a - // buffer slot is available then that slot index is written to the location - // pointed to by the buf argument and a status of OK is returned. If no - // slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. - virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); - - // queueBuffer returns a filled buffer to the BufferQueue. In addition, a - // timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are client-dependent and should be documented by the - // client. - virtual status_t queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output); - - virtual void cancelBuffer(int buf); - - // setSynchronousMode set whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be retired in order. - // The default mode is asynchronous. - virtual status_t setSynchronousMode(bool enabled); - - // connect attempts to connect a producer client API to the BufferQueue. - // This must be called before any other ISurfaceTexture methods are called - // except for getAllocator. - // - // This method will fail if the connect was previously called on the - // BufferQueue and no corresponding disconnect call was made. - virtual status_t connect(int api, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer client API from the - // BufferQueue. Calling this method will cause any subsequent calls to other - // ISurfaceTexture methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the BufferQueue is not currently - // connected to the specified client API. - virtual status_t disconnect(int api); - - // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - - // public facing structure for BufferSlot - struct BufferItem { - - BufferItem() - : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { - mCrop.makeInvalid(); - } - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer - int mBuf; - }; - - // The following public functions is the consumer facing interface - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the BufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - status_t acquireBuffer(BufferItem *buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue pending a fence sync. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence); - - // consumerConnect connects a consumer to the BufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // BufferQueue is placed into the "abandoned" state, causing most - // interactions with the BufferQueue by the producer to fail. - status_t consumerConnect(const sp& consumer); - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed and the BufferQueue is placed in the "abandoned" - // state, causing most interactions with the BufferQueue by the producer to - // fail. - status_t consumerDisconnect(); - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots the have been released by the BufferQueue - // but have not yet been released by the consumer. - status_t getReleasedBuffers(uint32_t* slotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setBufferCountServer set the buffer count. If the client has requested - // a buffer count using setBufferCount, the server-buffer count will - // take effect once the client sets the count back to zero. - status_t setBufferCountServer(int bufferCount); - - // isSynchronousMode returns whether the SurfaceTexture is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // setConsumerName sets the name used in logging - void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer - status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used - status_t setTransformHint(uint32_t hint); - -private: - // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage) - // for the given slot. - void freeBufferLocked(int index); - - // freeAllBuffersLocked frees the resources (both GraphicBuffer and - // EGLImage) for all slots. - void freeAllBuffersLocked(); - - // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer - // and EGLImage) for all slots except the head of mQueue - void freeAllBuffersExceptHeadLocked(); - - // drainQueueLocked drains the buffer queue if we're in synchronous mode - // returns immediately otherwise. It returns NO_INIT if the BufferQueue - // became abandoned or disconnected during this call. - status_t drainQueueLocked(); - - // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in - // synchronous mode and free all buffers. In asynchronous mode, all buffers - // are freed except the current buffer. - status_t drainQueueAndFreeBuffersLocked(); - - status_t setBufferCountServerLocked(int bufferCount); - - struct BufferSlot { - - BufferSlot() - : mEglDisplay(EGL_NO_DISPLAY), - mBufferState(BufferSlot::FREE), - mRequestBufferCalled(false), - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mFence(EGL_NO_SYNC_KHR), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false) { - mCrop.makeInvalid(); - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mEglDisplay is the EGLDisplay used to create mEglImage. - EGLDisplay mEglDisplay; - - // BufferState represents the different states in which a buffer slot - // can be. - enum BufferState { - // FREE indicates that the buffer is not currently being used and - // will not be used in the future until it gets dequeued and - // subsequently queued by the client. - // aka "owned by BufferQueue, ready to be dequeued" - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // client, but has not yet been queued or canceled. The buffer is - // considered 'owned' by the client, and the server should not use - // it for anything. - // - // Note that when in synchronous-mode (mSynchronousMode == true), - // the buffer that's currently attached to the texture may be - // dequeued by the client. That means that the current buffer can - // be in either the DEQUEUED or QUEUED state. In asynchronous mode, - // however, the current buffer is always in the QUEUED state. - // aka "owned by producer, ready to be queued" - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been queued by the client, - // and has not since been made available for the client to dequeue. - // Attaching the buffer to the texture does NOT transition the - // buffer away from the QUEUED state. However, in Synchronous mode - // the current buffer may be dequeued by the client under some - // circumstances. See the note about the current buffer in the - // documentation for DEQUEUED. - // aka "owned by BufferQueue, ready to be acquired" - QUEUED = 2, - - // aka "owned by consumer, ready to be released" - ACQUIRED = 3 - }; - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the client did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching client bugs. - bool mRequestBufferCalled; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based - // on a compile-time option) set to a new sync object in updateTexImage. - EGLSyncKHR mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by consumer - bool mNeedsCleanupOnRelease; - }; - - // mSlots is the array of buffer slots that must be mirrored on the client - // side. This allows buffer ownership to be transferred between the client - // and server without sending a GraphicBuffer over binder. The entire array - // is initialized to NULL at construction time, and buffers are allocated - // for a slot when requestBuffer is called with that slot's index. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in requestBuffers() if a width and height of zero is specified. - uint32_t mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in requestBuffers() if a width and height of zero is specified. - uint32_t mDefaultHeight; - - // mPixelFormat holds the pixel format of allocated buffers. It is used - // in requestBuffers() if a format of zero is specified. - uint32_t mPixelFormat; - - // mMinUndequeuedBuffers is a constraint on the number of buffers - // not dequeued at any time - int mMinUndequeuedBuffers; - - // mMinAsyncBufferSlots is a constraint on the minimum mBufferCount - // when this BufferQueue is in asynchronous mode - int mMinAsyncBufferSlots; - - // mMinSyncBufferSlots is a constraint on the minimum mBufferCount - // when this BufferQueue is in synchronous mode - int mMinSyncBufferSlots; - - // mBufferCount is the number of buffer slots that the client and server - // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed - // by calling setBufferCount or setBufferCountServer - int mBufferCount; - - // mClientBufferCount is the number of buffer slots requested by the client. - // The default is zero, which means the client doesn't care how many buffers - // there is. - int mClientBufferCount; - - // mServerBufferCount buffer count requested by the server-side - int mServerBufferCount; - - // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to - // allocate new GraphicBuffer objects. - sp mGraphicBufferAlloc; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially set - // to NULL and is written by consumerConnect and consumerDisconnect. - sp mConsumerListener; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - // mAllowSynchronousMode whether we allow synchronous mode or not - const bool mAllowSynchronousMode; - - // mConnectedApi indicates the API that is currently connected to this - // BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets updated - // by the connect and disconnect methods. - int mConnectedApi; - - // mDequeueCondition condition used for dequeueBuffer in synchronous mode - mutable Condition mDequeueCondition; - - // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector Fifo; - Fifo mQueue; - - // mAbandoned indicates that the BufferQueue will no longer be used to - // consume images buffers pushed to it using the ISurfaceTexture interface. - // It is initialized to false, and set to true in the abandon method. A - // BufferQueue that has been abandoned will return the NO_INIT error from - // all ISurfaceTexture methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the BufferQueue in log messages. - // It is set by the setName method. - String8 mConsumerName; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of BufferQueue objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mFrameCounter is the free running counter, incremented for every buffer queued - // with the surface Texture. - uint64_t mFrameCounter; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is reset - // by changing the buffer count. - bool mBufferHasBeenQueued; - - // mDefaultBufferFormat can be set so it will override - // the buffer format when it isn't specified in dequeueBuffer - uint32_t mDefaultBufferFormat; - - // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers - uint32_t mConsumerUsageBits; - - // mTransformHint is used to optimize for screen rotations - uint32_t mTransformHint; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/src/imports/nativemedia/SurfaceTexture.cpp b/src/imports/nativemedia/SurfaceTexture.cpp deleted file mode 100644 index 05207ad..0000000 --- a/src/imports/nativemedia/SurfaceTexture.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 1) -#include "SurfaceTexture_4_1.cpp" -#else -#include "SurfaceTexture_4_0.cpp" -#endif diff --git a/src/imports/nativemedia/SurfaceTexture.h b/src/imports/nativemedia/SurfaceTexture.h deleted file mode 100644 index 552d465..0000000 --- a/src/imports/nativemedia/SurfaceTexture.h +++ /dev/null @@ -1,23 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#if Q_ANDROID_VERSION_MAJOR > 4 || (Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR >= 1) -#include "SurfaceTexture_4_1.h" -#else -#include "SurfaceTexture_4_0.h" -#endif diff --git a/src/imports/nativemedia/SurfaceTexture_4_0.cpp b/src/imports/nativemedia/SurfaceTexture_4_0.cpp deleted file mode 100644 index 1ec08a7..0000000 --- a/src/imports/nativemedia/SurfaceTexture_4_0.cpp +++ /dev/null @@ -1,1236 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "SurfaceTexture" -//#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -#include - -// This compile option causes SurfaceTexture to return the buffer that is currently -// attached to the GL texture from dequeueBuffer when no other buffers are -// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do -// implicit cross-process synchronization to prevent the buffer from being -// written to before the buffer has (a) been detached from the GL texture and -// (b) all GL reads from the buffer have completed. -#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER -#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true -#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled" -#else -#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false -#endif - -// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension -// to synchronize access to the buffers. It will cause dequeueBuffer to stall, -// waiting for the GL reads for the buffer being dequeued to complete before -// allowing the buffer to be dequeued. -#ifdef USE_FENCE_SYNC -#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER -#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible" -#endif -#endif - -// Macros for including the SurfaceTexture name in log messages -#if 0 -#define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) LOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) LOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) LOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) LOGE("[%s] "x, mName.string(), ##__VA_ARGS__) -#else -#define ST_LOGV(x, ...) LOGV("[V/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) LOGD("[D/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) qDebug("[I/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) qDebug("[W/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) qDebug("[E/%s] "x, mName.string(), ##__VA_ARGS__) -#endif - -namespace android { - -// Transform matrices -static float mtxIdentity[16] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; -static float mtxFlipH[16] = { - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxFlipV[16] = { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; -static float mtxRot90[16] = { - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxRot180[16] = { - -1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 1, 1, 0, 1, -}; -static float mtxRot270[16] = { - 0, -1, 0, 0, - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; - -static void mtxMul(float out[16], const float a[16], const float b[16]); - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, - GLenum texTarget, bool useFenceSync) : - mDefaultWidth(1), - mDefaultHeight(1), - mPixelFormat(PIXEL_FORMAT_RGBA_8888), - mBufferCount(MIN_ASYNC_BUFFER_SLOTS), - mClientBufferCount(0), - mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), - mCurrentTexture(INVALID_BUFFER_SLOT), - mCurrentTransform(0), - mCurrentTimestamp(0), - mNextTransform(0), - mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTexName(tex), - mSynchronousMode(false), - mAllowSynchronousMode(allowSynchronousMode), - mConnectedApi(NO_CONNECTED_API), - mAbandoned(false), -#ifdef USE_FENCE_SYNC - mUseFenceSync(useFenceSync), -#else - mUseFenceSync(false), -#endif - mTexTarget(texTarget), - mFrameCounter(0) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - ST_LOGV("SurfaceTexture"); -// sp composer(ComposerService::getComposerService()); -// mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); - mNextCrop.makeInvalid(); - memcpy(mCurrentTransformMatrix, mtxIdentity, - sizeof(mCurrentTransformMatrix)); -} - -SurfaceTexture::~SurfaceTexture() { - ST_LOGV("~SurfaceTexture"); - freeAllBuffersLocked(); -} - -status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) { - if (bufferCount > NUM_BUFFER_SLOTS) - return BAD_VALUE; - - // special-case, nothing to do - if (bufferCount == mBufferCount) - return OK; - - if (!mClientBufferCount && - bufferCount >= mBufferCount) { - // easy, we just have more buffers - mBufferCount = bufferCount; - mServerBufferCount = bufferCount; - mDequeueCondition.signal(); - } else { - // we're here because we're either - // - reducing the number of available buffers - // - or there is a client-buffer-count in effect - - // less than 2 buffers is never allowed - if (bufferCount < 2) - return BAD_VALUE; - - // when there is non client-buffer-count in effect, the client is not - // allowed to dequeue more than one buffer at a time, - // so the next time they dequeue a buffer, we know that they don't - // own one. the actual resizing will happen during the next - // dequeueBuffer. - - mServerBufferCount = bufferCount; - } - return OK; -} - -status_t SurfaceTexture::setBufferCountServer(int bufferCount) { - Mutex::Autolock lock(mMutex); - return setBufferCountServerLocked(bufferCount); -} - -status_t SurfaceTexture::setBufferCount(int bufferCount) { - ST_LOGV("setBufferCount: count=%d", bufferCount); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (bufferCount > NUM_BUFFER_SLOTS) { - ST_LOGE("setBufferCount: bufferCount larger than slots available"); - return BAD_VALUE; - } - - // Error out if the user has dequeued buffers - for (int i=0 ; i= minBufferSlots) ? - mServerBufferCount : minBufferSlots; - return setBufferCountServerLocked(bufferCount); - } - - if (bufferCount < minBufferSlots) { - ST_LOGE("setBufferCount: requested buffer count (%d) is less than " - "minimum (%d)", bufferCount, minBufferSlots); - return BAD_VALUE; - } - - // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. - freeAllBuffersLocked(); - mBufferCount = bufferCount; - mClientBufferCount = bufferCount; - mCurrentTexture = INVALID_BUFFER_SLOT; - mQueue.clear(); - mDequeueCondition.signal(); - return OK; -} - -status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return OK; -} - -status_t SurfaceTexture::requestBuffer(int slot, sp* buf) { - ST_LOGV("requestBuffer: slot=%d", slot); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (slot < 0 || mBufferCount <= slot) { - ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", - mBufferCount, slot); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, - uint32_t format, uint32_t usage) { - ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); - - if ((w && !h) || (!w && h)) { - ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); - return BAD_VALUE; - } - - status_t returnFlags(OK); - EGLDisplay dpy = EGL_NO_DISPLAY; - EGLSyncKHR fence = EGL_NO_SYNC_KHR; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - int found = -1; - int foundSync = -1; - int dequeuedCount = 0; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - // We need to wait for the FIFO to drain if the number of buffer - // needs to change. - // - // The condition "number of buffers needs to change" is true if - // - the client doesn't care about how many buffers there are - // - AND the actual number of buffer is different from what was - // set in the last setBufferCountServer() - // - OR - - // setBufferCountServer() was set to a value incompatible with - // the synchronization mode (for instance because the sync mode - // changed since) - // - // As long as this condition is true AND the FIFO is not empty, we - // wait on mDequeueCondition. - - const int minBufferCountNeeded = mSynchronousMode ? - MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; - - const bool numberOfBuffersNeedsToChange = !mClientBufferCount && - ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded)); - - if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { - // wait for the FIFO to drain - mDequeueCondition.wait(mMutex); - // NOTE: we continue here because we need to reevaluate our - // whole state (eg: we could be abandoned or disconnected) - continue; - } - - if (numberOfBuffersNeedsToChange) { - // here we're guaranteed that mQueue is empty - freeAllBuffersLocked(); - mBufferCount = mServerBufferCount; - if (mBufferCount < minBufferCountNeeded) - mBufferCount = minBufferCountNeeded; - mCurrentTexture = INVALID_BUFFER_SLOT; - returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; - } - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - foundSync = INVALID_BUFFER_SLOT; - dequeuedCount = 0; - for (int i = 0; i < mBufferCount; i++) { - const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; - } - - // if buffer is FREE it CANNOT be current - LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i), - "dequeueBuffer: buffer %d is both FREE and current!", - i); - - if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) { - if (state == BufferSlot::FREE || i == mCurrentTexture) { - foundSync = i; - if (i != mCurrentTexture) { - found = i; - break; - } - } - } else { - if (state == BufferSlot::FREE) { - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - bool isOlder = mSlots[i].mFrameNumber < - mSlots[found].mFrameNumber; - if (found < 0 || isOlder) { - foundSync = i; - found = i; - } - } - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mClientBufferCount && dequeuedCount) { - ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the - // MIN_UNDEQUEUED_BUFFERS check below. - bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; - if (bufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int avail = mBufferCount - (dequeuedCount+1); - if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { - ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " - "(dequeued=%d)", - MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), - dequeuedCount); - return -EBUSY; - } - } - - // we're in synchronous mode and didn't find a buffer, we need to - // wait for some buffers to be consumed - tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); - if (tryAgain) { - mDequeueCondition.wait(mMutex); - } - } - - if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { - // foundSync guaranteed to be != INVALID_BUFFER_SLOT - found = foundSync; - } - - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ST_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - const int buf = found; - *outBuf = found; - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - const bool updateFormat = (format != 0); - if (!updateFormat) { - // keep the current (or default) format - format = mPixelFormat; - } - - // buffer is now in DEQUEUED (but can also be current at the same time, - // if we're in synchronous mode) - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - status_t error; - sp graphicBuffer( - new GraphicBuffer(w, h, format, usage)); -// mGraphicBufferAlloc->createGraphicBuffer( -// w, h, format, usage, &error)); - if (graphicBuffer == 0) { - ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " - "failed"); - return error; - } - if (updateFormat) { - mPixelFormat = format; - } - mSlots[buf].mGraphicBuffer = graphicBuffer; - mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = EGL_NO_SYNC_KHR; - if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mSlots[buf].mEglDisplay, - mSlots[buf].mEglImage); - mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; - mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - } - if (mCurrentTexture == buf) { - // The current texture no longer references the buffer in this slot - // since we just allocated a new buffer. - mCurrentTexture = INVALID_BUFFER_SLOT; - } - returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; - } - - dpy = mSlots[buf].mEglDisplay; - fence = mSlots[buf].mFence; - mSlots[buf].mFence = EGL_NO_SYNC_KHR; - } - - if (fence != EGL_NO_SYNC_KHR) { - EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); - // If something goes wrong, log the error, but return the buffer without - // synchronizing access to it. It's too late at this point to abort the - // dequeue operation. - if (result == EGL_FALSE) { - LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError()); - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - LOGE("dequeueBuffer: timeout waiting for fence"); - } - eglDestroySyncKHR(dpy, fence); - } - - ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, - mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t SurfaceTexture::setSynchronousMode(bool enabled) { - ST_LOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - status_t err = OK; - if (!mAllowSynchronousMode && enabled) - return err; - - if (!enabled) { - // going to asynchronous mode, drain the queue - err = drainQueueLocked(); - if (err != NO_ERROR) - return err; - } - - if (mSynchronousMode != enabled) { - // - if we're going to asynchronous mode, the queue is guaranteed to be - // empty here - // - if the client set the number of buffers, we're guaranteed that - // we have at least 3 (because we don't allow less) - mSynchronousMode = enabled; - mDequeueCondition.signal(); - } - return err; -} - -status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp, - uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { - ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp); - - sp listener; - - { // scope for the lock - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (buf < 0 || buf >= mBufferCount) { - ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", - mBufferCount, buf); - return -EINVAL; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("queueBuffer: slot %d is not owned by the client " - "(state=%d)", buf, mSlots[buf].mBufferState); - return -EINVAL; - } else if (buf == mCurrentTexture) { - ST_LOGE("queueBuffer: slot %d is current!", buf); - return -EINVAL; - } else if (!mSlots[buf].mRequestBufferCalled) { - ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", buf); - return -EINVAL; - } - - if (mSynchronousMode) { - // In synchronous mode we queue all buffers in a FIFO. - mQueue.push_back(buf); - - // Synchronous mode always signals that an additional frame should - // be consumed. - listener = mFrameAvailableListener; - } else { - // In asynchronous mode we only keep the most recent buffer. - if (mQueue.empty()) { - mQueue.push_back(buf); - - // Asynchronous mode only signals that a frame should be - // consumed if no previous frame was pending. If a frame were - // pending then the consumer would have already been notified. - listener = mFrameAvailableListener; - } else { - Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; - // and we record the new buffer index in the queued list - *front = buf; - } - } - - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mSlots[buf].mCrop = mNextCrop; - mSlots[buf].mTransform = mNextTransform; - mSlots[buf].mScalingMode = mNextScalingMode; - mSlots[buf].mTimestamp = timestamp; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - - mDequeueCondition.signal(); - - *outWidth = mDefaultWidth; - *outHeight = mDefaultHeight; - *outTransform = 0; - } // scope for the lock - - // call back without lock held - if (listener != 0) { - listener->onFrameAvailable(); - } - return OK; -} - -void SurfaceTexture::cancelBuffer(int buf) { - ST_LOGV("cancelBuffer: slot=%d", buf); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGW("cancelBuffer: SurfaceTexture has been abandoned!"); - return; - } - - if (buf < 0 || buf >= mBufferCount) { - ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", - mBufferCount, buf); - return; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - buf, mSlots[buf].mBufferState); - return; - } - mSlots[buf].mBufferState = BufferSlot::FREE; - mSlots[buf].mFrameNumber = 0; - mDequeueCondition.signal(); -} - -status_t SurfaceTexture::setCrop(const Rect& crop) { - ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right, - crop.bottom); - - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("setCrop: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - mNextCrop = crop; - return OK; -} - -status_t SurfaceTexture::setTransform(uint32_t transform) { - ST_LOGV("setTransform: xform=%#x", transform); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("setTransform: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - mNextTransform = transform; - return OK; -} - -status_t SurfaceTexture::connect(int api, - uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { - ST_LOGV("connect: api=%d", api); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("connect: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi != NO_CONNECTED_API) { - ST_LOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } else { - mConnectedApi = api; - *outWidth = mDefaultWidth; - *outHeight = mDefaultHeight; - *outTransform = 0; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - -status_t SurfaceTexture::disconnect(int api) { - ST_LOGV("disconnect: api=%d", api); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // it is not really an error to disconnect after the surface - // has been abandoned, it should just be a no-op. - return NO_ERROR; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - drainQueueAndFreeBuffersLocked(); - mConnectedApi = NO_CONNECTED_API; - mNextCrop.makeInvalid(); - mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mNextTransform = 0; - mDequeueCondition.signal(); - } else { - ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } - break; - default: - ST_LOGE("disconnect: unknown API %d", api); - err = -EINVAL; - break; - } - return err; -} - -status_t SurfaceTexture::setScalingMode(int mode) { - ST_LOGV("setScalingMode: mode=%d", mode); - - switch (mode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - break; - default: - ST_LOGE("unknown scaling mode: %d", mode); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mNextScalingMode = mode; - return OK; -} - -status_t SurfaceTexture::updateTexImage() { - ST_LOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - qDebug("calling updateTexImage() on an abandoned SurfaceTexture"); - return NO_INIT; - } - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = *front; - - // Update the GL texture object. - EGLImageKHR image = mSlots[buf].mEglImage; - EGLDisplay dpy = eglGetCurrentDisplay(); - if (image == EGL_NO_IMAGE_KHR) { - if (mSlots[buf].mGraphicBuffer == 0) { - qDebug("buffer at slot %d is null", buf); - return BAD_VALUE; - } - image = createImage(dpy, mSlots[buf].mGraphicBuffer); - mSlots[buf].mEglImage = image; - mSlots[buf].mEglDisplay = dpy; - if (image == EGL_NO_IMAGE_KHR) { - // NOTE: if dpy was invalid, createImage() is guaranteed to - // fail. so we'd end up here. - qDebug("EGL_NO_IMAGE_KHR: %p", dpy); - return -EINVAL; - } - } - - GLint error; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGW("updateTexImage: clearing GL error: %#04x", error); - } - - glBindTexture(mTexTarget, mTexName); - glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); - - bool failed = false; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("error binding external texture image %p (slot %d): %#04x", - image, buf, error); - failed = true; - } - if (failed) { - return -EINVAL; - } - - if (mCurrentTexture != INVALID_BUFFER_SLOT) { - if (mUseFenceSync) { - EGLSyncKHR fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, - NULL); - if (fence == EGL_NO_SYNC_KHR) { - ST_LOGE("updateTexImage: error creating fence: %#x", - eglGetError()); - return -EINVAL; - } - glFlush(); - mSlots[mCurrentTexture].mFence = fence; - } - } - - ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", - mCurrentTexture, - mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, - buf, mSlots[buf].mGraphicBuffer->handle); - - if (mCurrentTexture != INVALID_BUFFER_SLOT) { - // The current buffer becomes FREE if it was still in the queued - // state. If it has already been given to the client - // (synchronous mode), then it stays in DEQUEUED state. - if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) { - mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE; - } - } - - // Update the SurfaceTexture state. - mCurrentTexture = buf; - mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; - mCurrentCrop = mSlots[buf].mCrop; - mCurrentTransform = mSlots[buf].mTransform; - mCurrentScalingMode = mSlots[buf].mScalingMode; - mCurrentTimestamp = mSlots[buf].mTimestamp; - computeCurrentTransformMatrix(); - - // Now that we've passed the point at which failures can happen, - // it's safe to remove the buffer from the front of the queue. - mQueue.erase(front); - mDequeueCondition.signal(); - } else { - // We always bind the texture even if we don't update its contents. - glBindTexture(mTexTarget, mTexName); - } - - return OK; -} - -bool SurfaceTexture::isExternalFormat(uint32_t format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - -GLenum SurfaceTexture::getCurrentTextureTarget() const { - return mTexTarget; -} - -void SurfaceTexture::getTransformMatrix(float mtx[16]) { - Mutex::Autolock lock(mMutex); - memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); -} - -void SurfaceTexture::computeCurrentTransformMatrix() { - ST_LOGV("computeCurrentTransformMatrix"); - - float xform[16]; - for (int i = 0; i < 16; i++) { - xform[i] = mtxIdentity[i]; - } - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - float result[16]; - mtxMul(result, xform, mtxFlipH); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } - } - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - float result[16]; - mtxMul(result, xform, mtxFlipV); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } - } - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float result[16]; - mtxMul(result, xform, mtxRot90); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } - } - - sp& buf(mSlots[mCurrentTexture].mGraphicBuffer); - float tx, ty, sx, sy; - if (!mCurrentCrop.isEmpty()) { - // In order to prevent bilinear sampling at the of the crop rectangle we - // may need to shrink it by 2 texels in each direction. Normally this - // would just need to take 1/2 a texel off each end, but because the - // chroma channels will likely be subsampled we need to chop off a whole - // texel. This will cause artifacts if someone does nearest sampling - // with 1:1 pixel:texel ratio, but it's impossible to simultaneously - // accomodate the bilinear and nearest sampling uses. - // - // If nearest sampling turns out to be a desirable usage of these - // textures then we could add the ability to switch a SurfaceTexture to - // nearest-mode. Preferably, however, the image producers (video - // decoder, camera, etc.) would simply not use a crop rectangle (or at - // least not tell the framework about it) so that the GPU can do the - // correct edge behavior. - int xshrink = 0, yshrink = 0; - if (mCurrentCrop.left > 0) { - tx = float(mCurrentCrop.left + 1) / float(buf->getWidth()); - xshrink++; - } else { - tx = 0.0f; - } - if (mCurrentCrop.right < int32_t(buf->getWidth())) { - xshrink++; - } - if (mCurrentCrop.bottom < int32_t(buf->getHeight())) { - ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) / - float(buf->getHeight()); - yshrink++; - } else { - ty = 0.0f; - } - if (mCurrentCrop.top > 0) { - yshrink++; - } - sx = float(mCurrentCrop.width() - xshrink) / float(buf->getWidth()); - sy = float(mCurrentCrop.height() - yshrink) / float(buf->getHeight()); - } else { - tx = 0.0f; - ty = 0.0f; - sx = 1.0f; - sy = 1.0f; - } - float crop[16] = { - sx, 0, 0, 0, - 0, sy, 0, 0, - 0, 0, 1, 0, - tx, ty, 0, 1, - }; - - float mtxBeforeFlipV[16]; - mtxMul(mtxBeforeFlipV, crop, xform); - - // SurfaceFlinger expects the top of its window textures to be at a Y - // coordinate of 0, so SurfaceTexture must behave the same way. We don't - // want to expose this to applications, however, so we must add an - // additional vertical flip to the transform after all the other transforms. - mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV); -} - -nsecs_t SurfaceTexture::getTimestamp() { - ST_LOGV("getTimestamp"); - Mutex::Autolock lock(mMutex); - return mCurrentTimestamp; -} - -void SurfaceTexture::setFrameAvailableListener( - const sp& listener) { - ST_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void SurfaceTexture::freeBufferLocked(int i) { - mSlots[i].mGraphicBuffer = 0; - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage); - mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; - mSlots[i].mEglDisplay = EGL_NO_DISPLAY; - } -} - -void SurfaceTexture::freeAllBuffersLocked() { - LOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mCurrentTexture = INVALID_BUFFER_SLOT; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } -} - -void SurfaceTexture::freeAllBuffersExceptHeadLocked() { - LOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersExceptCurrentLocked called but mQueue is not empty"); - int head = -1; - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - head = *front; - } - mCurrentTexture = INVALID_BUFFER_SLOT; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (i != head) { - freeBufferLocked(i); - } - } -} - -status_t SurfaceTexture::drainQueueLocked() { - while (mSynchronousMode && !mQueue.isEmpty()) { - mDequeueCondition.wait(mMutex); - if (mAbandoned) { - ST_LOGE("drainQueueLocked: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - if (mConnectedApi == NO_CONNECTED_API) { - ST_LOGE("drainQueueLocked: SurfaceTexture is not connected!"); - return NO_INIT; - } - } - return NO_ERROR; -} - -status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() { - status_t err = drainQueueLocked(); - if (err == NO_ERROR) { - if (mSynchronousMode) { - freeAllBuffersLocked(); - } else { - freeAllBuffersExceptHeadLocked(); - } - } - return err; -} - -EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, - const sp& graphicBuffer) { - EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); - EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE, - }; - EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); - if (image == EGL_NO_IMAGE_KHR) { - EGLint error = eglGetError(); - ST_LOGE("error creating EGLImage: %#x", error); - } - return image; -} - -sp SurfaceTexture::getCurrentBuffer() const { - Mutex::Autolock lock(mMutex); - return mCurrentTextureBuf; -} - -Rect SurfaceTexture::getCurrentCrop() const { - Mutex::Autolock lock(mMutex); - return mCurrentCrop; -} - -uint32_t SurfaceTexture::getCurrentTransform() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransform; -} - -uint32_t SurfaceTexture::getCurrentScalingMode() const { - Mutex::Autolock lock(mMutex); - return mCurrentScalingMode; -} - -bool SurfaceTexture::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - -int SurfaceTexture::query(int what, int* outValue) -{ - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("query: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mPixelFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mSynchronousMode ? - (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS; - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - -void SurfaceTexture::abandon() { - Mutex::Autolock lock(mMutex); - mQueue.clear(); - mAbandoned = true; - mCurrentTextureBuf.clear(); - freeAllBuffersLocked(); - mDequeueCondition.signal(); -} - -void SurfaceTexture::setName(const String8& name) { - mName = name; -} - -void SurfaceTexture::dump(String8& result) const -{ - char buffer[1024]; - dump(result, "", buffer, 1024); -} - -void SurfaceTexture::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, - "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "mPixelFormat=%d, mTexName=%d\n", - prefix, mBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mPixelFormat, mTexName); - result.append(buffer); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } - - snprintf(buffer, SIZE, - "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n" - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n" - , - prefix, mCurrentCrop.left, - mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform, mCurrentTexture, - prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, - mNextCrop.bottom, mNextTransform, fifoSize, fifo.string() - ); - result.append(buffer); - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - default: return "Unknown"; - } - } - } stateName; - - for (int i=0 ; i":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp - ); - result.append(buffer); - - const sp& buf(slot.mGraphicBuffer); - if (buf != NULL) { - snprintf(buffer, SIZE, - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - result.append(buffer); - } - result.append("\n"); - } -} - -static void mtxMul(float out[16], const float a[16], const float b[16]) { - out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; - out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; - out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; - out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; - - out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; - out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; - out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; - out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; - - out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; - out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; - out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; - out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; - - out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; - out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; - out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; - out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; -} - -}; // namespace android diff --git a/src/imports/nativemedia/SurfaceTexture_4_0.h b/src/imports/nativemedia/SurfaceTexture_4_0.h deleted file mode 100644 index 53cc852..0000000 --- a/src/imports/nativemedia/SurfaceTexture_4_0.h +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_GUI_SURFACETEXTURE_H -#define ANDROID_GUI_SURFACETEXTURE_H - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture" - -namespace android { -// ---------------------------------------------------------------------------- - -class IGraphicBufferAlloc; -class String8; - -class SurfaceTexture : public BnSurfaceTexture { -public: - enum { MIN_UNDEQUEUED_BUFFERS = 2 }; - enum { - MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1, - MIN_SYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS - }; - enum { NUM_BUFFER_SLOTS = 32 }; - enum { NO_CONNECTED_API = 0 }; - - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called from queueBuffer() each time an - // additional frame becomes available for consumption. This means that - // frames that are queued while in asynchronous mode only trigger the - // callback if no previous frames are pending. Frames queued while in - // synchronous mode always trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the - // name of the OpenGL ES texture to which images are to be streamed. This - // texture name cannot be changed once the SurfaceTexture is created. - // allowSynchronousMode specifies whether or not synchronous mode can be - // enabled. texTarget specifies the OpenGL ES texture target to which the - // texture will be bound in updateTexImage. useFenceSync specifies whether - // fences should be used to synchronize access to buffers if that behavior - // is enabled at compile-time. - SurfaceTexture(GLuint tex, bool allowSynchronousMode = true, - GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true); - - virtual ~SurfaceTexture(); - - // setBufferCount updates the number of available buffer slots. After - // calling this all buffer slots are both unallocated and owned by the - // SurfaceTexture object (i.e. they are not owned by the client). - virtual status_t setBufferCount(int bufferCount); - - virtual status_t requestBuffer(int slot, sp* buf); - - // dequeueBuffer gets the next buffer slot index for the client to use. If a - // buffer slot is available then that slot index is written to the location - // pointed to by the buf argument and a status of OK is returned. If no - // slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. - virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); - - // queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a - // timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are client-dependent and should be documented by the - // client. - virtual status_t queueBuffer(int buf, int64_t timestamp, - uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform); - virtual void cancelBuffer(int buf); - virtual status_t setCrop(const Rect& reg); - virtual status_t setTransform(uint32_t transform); - virtual status_t setScalingMode(int mode); - - virtual int query(int what, int* value); - - // setSynchronousMode set whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be retired in order. - // The default mode is asynchronous. - virtual status_t setSynchronousMode(bool enabled); - - // connect attempts to connect a client API to the SurfaceTexture. This - // must be called before any other ISurfaceTexture methods are called except - // for getAllocator. - // - // This method will fail if the connect was previously called on the - // SurfaceTexture and no corresponding disconnect call was made. - virtual status_t connect(int api, - uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform); - - // disconnect attempts to disconnect a client API from the SurfaceTexture. - // Calling this method will cause any subsequent calls to other - // ISurfaceTexture methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the SurfaceTexture is not currently - // connected to the specified client API. - virtual status_t disconnect(int api); - - // updateTexImage sets the image contents of the target texture to that of - // the most recently queued buffer. - // - // This call may only be made while the OpenGL ES context to which the - // target texture belongs is bound to the calling thread. - status_t updateTexImage(); - - // setBufferCountServer set the buffer count. If the client has requested - // a buffer count using setBufferCount, the server-buffer count will - // take effect once the client sets the count back to zero. - status_t setBufferCountServer(int bufferCount); - - // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix - // associated with the texture image set by the most recent call to - // updateTexImage. - // - // This transform matrix maps 2D homogeneous texture coordinates of the form - // (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture - // coordinate that should be used to sample that location from the texture. - // Sampling the texture outside of the range of this transform is undefined. - // - // This transform is necessary to compensate for transforms that the stream - // content producer may implicitly apply to the content. By forcing users of - // a SurfaceTexture to apply this transform we avoid performing an extra - // copy of the data that would be needed to hide the transform from the - // user. - // - // The matrix is stored in column-major order so that it may be passed - // directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv - // functions. - void getTransformMatrix(float mtx[16]); - - // getTimestamp retrieves the timestamp associated with the texture image - // set by the most recent call to updateTexImage. - // - // The timestamp is in nanoseconds, and is monotonically increasing. Its - // other semantics (zero point, etc) are source-dependent and should be - // documented by the source. - int64_t getTimestamp(); - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const sp& listener); - - // getAllocator retrieves the binder object that must be referenced as long - // as the GraphicBuffers dequeued from this SurfaceTexture are referenced. - // Holding this binder reference prevents SurfaceFlinger from freeing the - // buffers before the client is done with them. - sp getAllocator(); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - // A call to setDefaultBufferSize() may trigger requestBuffers() to - // be called from the client. - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. - status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // getCurrentBuffer returns the buffer associated with the current image. - sp getCurrentBuffer() const; - - // getCurrentTextureTarget returns the texture target of the current - // texture as returned by updateTexImage(). - GLenum getCurrentTextureTarget() const; - - // getCurrentCrop returns the cropping rectangle of the current buffer - Rect getCurrentCrop() const; - - // getCurrentTransform returns the transform of the current buffer - uint32_t getCurrentTransform() const; - - // getCurrentScalingMode returns the scaling mode of the current buffer - uint32_t getCurrentScalingMode() const; - - // isSynchronousMode returns whether the SurfaceTexture is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // abandon frees all the buffers and puts the SurfaceTexture into the - // 'abandoned' state. Once put in this state the SurfaceTexture can never - // leave it. When in the 'abandoned' state, all methods of the - // ISurfaceTexture interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the SurfaceTexture, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client or - // by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the SurfaceTexture that will be used to identify it in - // log messages. - void setName(const String8& name); - - // dump our state in a String - void dump(String8& result) const; - void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - -protected: - - // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage) - // for the given slot. - void freeBufferLocked(int index); - - // freeAllBuffersLocked frees the resources (both GraphicBuffer and - // EGLImage) for all slots. - void freeAllBuffersLocked(); - - // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer - // and EGLImage) for all slots except the head of mQueue - void freeAllBuffersExceptHeadLocked(); - - // drainQueueLocked drains the buffer queue if we're in synchronous mode - // returns immediately otherwise. return NO_INIT if SurfaceTexture - // became abandoned or disconnected during this call. - status_t drainQueueLocked(); - - // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in - // synchronous mode and free all buffers. In asynchronous mode, all buffers - // are freed except the current buffer. - status_t drainQueueAndFreeBuffersLocked(); - - static bool isExternalFormat(uint32_t format); - -private: - - // createImage creates a new EGLImage from a GraphicBuffer. - EGLImageKHR createImage(EGLDisplay dpy, - const sp& graphicBuffer); - - status_t setBufferCountServerLocked(int bufferCount); - - // computeCurrentTransformMatrix computes the transform matrix for the - // current texture. It uses mCurrentTransform and the current GraphicBuffer - // to compute this matrix and stores it in mCurrentTransformMatrix. - void computeCurrentTransformMatrix(); - - enum { INVALID_BUFFER_SLOT = -1 }; - - struct BufferSlot { - - BufferSlot() - : mEglImage(EGL_NO_IMAGE_KHR), - mEglDisplay(EGL_NO_DISPLAY), - mBufferState(BufferSlot::FREE), - mRequestBufferCalled(false), - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mFence(EGL_NO_SYNC_KHR) { - mCrop.makeInvalid(); - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mEglImage is the EGLImage created from mGraphicBuffer. - EGLImageKHR mEglImage; - - // mEglDisplay is the EGLDisplay used to create mEglImage. - EGLDisplay mEglDisplay; - - // BufferState represents the different states in which a buffer slot - // can be. - enum BufferState { - // FREE indicates that the buffer is not currently being used and - // will not be used in the future until it gets dequeued and - // subsequently queued by the client. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // client, but has not yet been queued or canceled. The buffer is - // considered 'owned' by the client, and the server should not use - // it for anything. - // - // Note that when in synchronous-mode (mSynchronousMode == true), - // the buffer that's currently attached to the texture may be - // dequeued by the client. That means that the current buffer can - // be in either the DEQUEUED or QUEUED state. In asynchronous mode, - // however, the current buffer is always in the QUEUED state. - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been queued by the client, - // and has not since been made available for the client to dequeue. - // Attaching the buffer to the texture does NOT transition the - // buffer away from the QUEUED state. However, in Synchronous mode - // the current buffer may be dequeued by the client under some - // circumstances. See the note about the current buffer in the - // documentation for DEQUEUED. - QUEUED = 2, - }; - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the client did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching client bugs. - bool mRequestBufferCalled; - - // mCrop is the current crop rectangle for this buffer slot. This gets - // set to mNextCrop each time queueBuffer gets called for this buffer. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. This - // gets set to mNextTransform each time queueBuffer gets called for this - // slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. This - // gets set to mNextScalingMode each time queueBuffer gets called for - // this slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based - // on a compile-time option) set to a new sync object in updateTexImage. - EGLSyncKHR mFence; - }; - - // mSlots is the array of buffer slots that must be mirrored on the client - // side. This allows buffer ownership to be transferred between the client - // and server without sending a GraphicBuffer over binder. The entire array - // is initialized to NULL at construction time, and buffers are allocated - // for a slot when requestBuffer is called with that slot's index. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in requestBuffers() if a width and height of zero is specified. - uint32_t mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in requestBuffers() if a width and height of zero is specified. - uint32_t mDefaultHeight; - - // mPixelFormat holds the pixel format of allocated buffers. It is used - // in requestBuffers() if a format of zero is specified. - uint32_t mPixelFormat; - - // mBufferCount is the number of buffer slots that the client and server - // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed - // by calling setBufferCount or setBufferCountServer - int mBufferCount; - - // mClientBufferCount is the number of buffer slots requested by the client. - // The default is zero, which means the client doesn't care how many buffers - // there is. - int mClientBufferCount; - - // mServerBufferCount buffer count requested by the server-side - int mServerBufferCount; - - // mCurrentTexture is the buffer slot index of the buffer that is currently - // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, - // indicating that no buffer slot is currently bound to the texture. Note, - // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - // that no buffer is bound to the texture. A call to setBufferCount will - // reset mCurrentTexture to INVALID_BUFFER_SLOT. - int mCurrentTexture; - - // mCurrentTextureBuf is the graphic buffer of the current texture. It's - // possible that this buffer is not associated with any buffer slot, so we - // must track it separately in order to support the getCurrentBuffer method. - sp mCurrentTextureBuf; - - // mCurrentCrop is the crop rectangle that applies to the current texture. - // It gets set each time updateTexImage is called. - Rect mCurrentCrop; - - // mCurrentTransform is the transform identifier for the current texture. It - // gets set each time updateTexImage is called. - uint32_t mCurrentTransform; - - // mCurrentScalingMode is the scaling mode for the current texture. It gets - // set to each time updateTexImage is called. - uint32_t mCurrentScalingMode; - - // mCurrentTransformMatrix is the transform matrix for the current texture. - // It gets computed by computeTransformMatrix each time updateTexImage is - // called. - float mCurrentTransformMatrix[16]; - - // mCurrentTimestamp is the timestamp for the current texture. It - // gets set each time updateTexImage is called. - int64_t mCurrentTimestamp; - - // mNextCrop is the crop rectangle that will be used for the next buffer - // that gets queued. It is set by calling setCrop. - Rect mNextCrop; - - // mNextTransform is the transform identifier that will be used for the next - // buffer that gets queued. It is set by calling setTransform. - uint32_t mNextTransform; - - // mNextScalingMode is the scaling mode that will be used for the next - // buffers that get queued. It is set by calling setScalingMode. - int mNextScalingMode; - - // mTexName is the name of the OpenGL texture to which streamed images will - // be bound when updateTexImage is called. It is set at construction time - // changed with a call to setTexName. - const GLuint mTexName; - - // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to - // allocate new GraphicBuffer objects. - //sp mGraphicBufferAlloc; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - sp mFrameAvailableListener; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - // mAllowSynchronousMode whether we allow synchronous mode or not - const bool mAllowSynchronousMode; - - // mConnectedApi indicates the API that is currently connected to this - // SurfaceTexture. It defaults to NO_CONNECTED_API (= 0), and gets updated - // by the connect and disconnect methods. - int mConnectedApi; - - // mDequeueCondition condition used for dequeueBuffer in synchronous mode - mutable Condition mDequeueCondition; - - // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector Fifo; - Fifo mQueue; - - // mAbandoned indicates that the SurfaceTexture will no longer be used to - // consume images buffers pushed to it using the ISurfaceTexture interface. - // It is initialized to false, and set to true in the abandon method. A - // SurfaceTexture that has been abandoned will return the NO_INIT error from - // all ISurfaceTexture methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the SurfaceTexture in log messages. - // It is set by the setName method. - String8 mName; - - // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync - // extension should be used to prevent buffers from being dequeued before - // it's safe for them to be written. It gets set at construction time and - // never changes. - const bool mUseFenceSync; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of SurfaceTexture objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mTexTarget is the GL texture target with which the GL texture object is - // associated. It is set in the constructor and never changed. It is - // almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android - // Browser. In that case it is set to GL_TEXTURE_2D to allow - // glCopyTexSubImage to read from the texture. This is a hack to work - // around a GL driver limitation on the number of FBO attachments, which the - // browser's tile cache exceeds. - const GLenum mTexTarget; - - // mFrameCounter is the free running counter, incremented for every buffer queued - // with the surface Texture. - uint64_t mFrameCounter; - - -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_SURFACETEXTURE_H diff --git a/src/imports/nativemedia/SurfaceTexture_4_1.cpp b/src/imports/nativemedia/SurfaceTexture_4_1.cpp deleted file mode 100644 index 9f8fd84..0000000 --- a/src/imports/nativemedia/SurfaceTexture_4_1.cpp +++ /dev/null @@ -1,866 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "SurfaceTexture" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension -// to synchronize access to the buffers. It will cause dequeueBuffer to stall, -// waiting for the GL reads for the buffer being dequeued to complete before -// allowing the buffer to be dequeued. -#ifdef USE_FENCE_SYNC -#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER -#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible" -#endif -#endif - -// Macros for including the SurfaceTexture name in log messages -#define ST_LOGV(x, ...) qDebug("[V/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) qDebug("[D/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) qDebug("[I/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) qDebug("[W/%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) qDebug("[E/%s] "x, mName.string(), ##__VA_ARGS__) - -namespace android { - -// Transform matrices -static float mtxIdentity[16] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; -static float mtxFlipH[16] = { - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxFlipV[16] = { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; -static float mtxRot90[16] = { - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxRot180[16] = { - -1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 1, 1, 0, 1, -}; -static float mtxRot270[16] = { - 0, -1, 0, 0, - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; - -static void mtxMul(float out[16], const float a[16], const float b[16]); - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, - GLenum texTarget, bool useFenceSync, const sp &bufferQueue) : - mCurrentTransform(0), - mCurrentTimestamp(0), - mFilteringEnabled(true), - mTexName(tex), -#ifdef USE_FENCE_SYNC - mUseFenceSync(useFenceSync), -#else - mUseFenceSync(false), -#endif - mTexTarget(texTarget), - mEglDisplay(EGL_NO_DISPLAY), - mEglContext(EGL_NO_CONTEXT), - mAbandoned(false), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), - mAttached(true) -{ - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - ST_LOGV("SurfaceTexture"); - if (bufferQueue == 0) { - ST_LOGV("Creating a new BufferQueue"); - mBufferQueue = new BufferQueue(allowSynchronousMode); - } - else { - mBufferQueue = bufferQueue; - } - - memcpy(mCurrentTransformMatrix, mtxIdentity, - sizeof(mCurrentTransformMatrix)); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp listener; - sp proxy; - listener = static_cast(this); - proxy = new BufferQueue::ProxyConsumerListener(listener); - - status_t err = mBufferQueue->consumerConnect(proxy); - if (err != NO_ERROR) { - ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)", - strerror(-err), err); - } else { - mBufferQueue->setConsumerName(mName); - mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); - } -} - -SurfaceTexture::~SurfaceTexture() { - ST_LOGV("~SurfaceTexture"); - - abandon(); -} - -status_t SurfaceTexture::setBufferCountServer(int bufferCount) { - Mutex::Autolock lock(mMutex); - return mBufferQueue->setBufferCountServer(bufferCount); -} - - -status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return mBufferQueue->setDefaultBufferSize(w, h); -} - -status_t SurfaceTexture::updateTexImage() { - return SurfaceTexture::updateTexImage(NULL); -} - -status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { - ATRACE_CALL(); - ST_LOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - status_t err = NO_ERROR; - - if (mAbandoned) { - ST_LOGE("updateTexImage: SurfaceTexture is abandoned!"); - return NO_INIT; - } - - if (!mAttached) { - ST_LOGE("updateTexImage: SurfaceTexture is not attached to an OpenGL " - "ES context"); - return INVALID_OPERATION; - } - - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) || - dpy == EGL_NO_DISPLAY) { - ST_LOGE("updateTexImage: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) || - ctx == EGL_NO_CONTEXT) { - ST_LOGE("updateTexImage: invalid current EGLContext"); - return INVALID_OPERATION; - } - - mEglDisplay = dpy; - mEglContext = ctx; - - BufferQueue::BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - err = mBufferQueue->acquireBuffer(&item); - if (err == NO_ERROR) { - int buf = item.mBuf; - // This buffer was newly allocated, so we need to clean up on our side - if (item.mGraphicBuffer != NULL) { - mEGLSlots[buf].mGraphicBuffer = 0; - if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage); - mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; - } - mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer; - } - - // we call the rejecter here, in case the caller has a reason to - // not accept this buffer. this is used by SurfaceFlinger to - // reject buffers which have the wrong size - if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) { - mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence); - mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR; - glBindTexture(mTexTarget, mTexName); - return NO_ERROR; - } - - // Update the GL texture object. We may have to do this even when - // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when - // detaching from a context but the buffer has not been re-allocated. - EGLImageKHR image = mEGLSlots[buf].mEglImage; - if (image == EGL_NO_IMAGE_KHR) { - if (mEGLSlots[buf].mGraphicBuffer == NULL) { - ST_LOGE("updateTexImage: buffer at slot %d is null", buf); - err = BAD_VALUE; - } else { - image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer); - mEGLSlots[buf].mEglImage = image; - if (image == EGL_NO_IMAGE_KHR) { - // NOTE: if dpy was invalid, createImage() is guaranteed to - // fail. so we'd end up here. - err = UNKNOWN_ERROR; - } - } - } - - if (err == NO_ERROR) { - GLint error; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGW("updateTexImage: clearing GL error: %#04x", error); - } - - glBindTexture(mTexTarget, mTexName); - glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); - - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("updateTexImage: error binding external texture image %p " - "(slot %d): %#04x", image, buf, error); - err = UNKNOWN_ERROR; - } - - if (err == NO_ERROR) { - err = syncForReleaseLocked(dpy); - } - } - - if (err != NO_ERROR) { - // Release the buffer we just acquired. It's not safe to - // release the old buffer, so instead we just drop the new frame. - mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence); - mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR; - return err; - } - - ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", - mCurrentTexture, - mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, - buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0); - - // release old buffer - if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy, - mEGLSlots[mCurrentTexture].mFence); - - mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR; - if (status == BufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(mCurrentTexture); - } else if (status != NO_ERROR) { - ST_LOGE("updateTexImage: released invalid buffer"); - err = status; - } - } - - // Update the SurfaceTexture state. - mCurrentTexture = buf; - mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer; - mCurrentCrop = item.mCrop; - mCurrentTransform = item.mTransform; - mCurrentScalingMode = item.mScalingMode; - mCurrentTimestamp = item.mTimestamp; - computeCurrentTransformMatrix(); - } else { - if (err < 0) { - ALOGE("updateTexImage failed on acquire %d", err); - } - // We always bind the texture even if we don't update its contents. - glBindTexture(mTexTarget, mTexName); - return OK; - } - - return err; -} - -status_t SurfaceTexture::detachFromContext() { - ATRACE_CALL(); - ST_LOGV("detachFromContext"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("detachFromContext: abandoned SurfaceTexture"); - return NO_INIT; - } - - if (!mAttached) { - ST_LOGE("detachFromContext: SurfaceTexture is not attached to a " - "context"); - return INVALID_OPERATION; - } - - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { - ST_LOGE("detachFromContext: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { - ST_LOGE("detachFromContext: invalid current EGLContext"); - return INVALID_OPERATION; - } - - if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) { - status_t err = syncForReleaseLocked(dpy); - if (err != OK) { - return err; - } - - glDeleteTextures(1, &mTexName); - } - - // Because we're giving up the EGLDisplay we need to free all the EGLImages - // that are associated with it. They'll be recreated when the - // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a - // new EGLDisplay). - for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - EGLImageKHR img = mEGLSlots[i].mEglImage; - if (img != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mEglDisplay, img); - mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR; - } - } - - mEglDisplay = EGL_NO_DISPLAY; - mEglContext = EGL_NO_CONTEXT; - mAttached = false; - - return OK; -} - -status_t SurfaceTexture::attachToContext(GLuint tex) { - ATRACE_CALL(); - ST_LOGV("attachToContext"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("attachToContext: abandoned SurfaceTexture"); - return NO_INIT; - } - - if (mAttached) { - ST_LOGE("attachToContext: SurfaceTexture is already attached to a " - "context"); - return INVALID_OPERATION; - } - - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if (dpy == EGL_NO_DISPLAY) { - ST_LOGE("attachToContext: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if (ctx == EGL_NO_CONTEXT) { - ST_LOGE("attachToContext: invalid current EGLContext"); - return INVALID_OPERATION; - } - - // We need to bind the texture regardless of whether there's a current - // buffer. - glBindTexture(mTexTarget, tex); - - if (mCurrentTextureBuf != NULL) { - // The EGLImageKHR that was associated with the slot was destroyed when - // the SurfaceTexture was detached from the old context, so we need to - // recreate it here. - EGLImageKHR image = createImage(dpy, mCurrentTextureBuf); - if (image == EGL_NO_IMAGE_KHR) { - return UNKNOWN_ERROR; - } - - // Attach the current buffer to the GL texture. - glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); - - GLint error; - status_t err = OK; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("attachToContext: error binding external texture image %p " - "(slot %d): %#04x", image, mCurrentTexture, error); - err = UNKNOWN_ERROR; - } - - // We destroy the EGLImageKHR here because the current buffer may no - // longer be associated with one of the buffer slots, so we have - // nowhere to to store it. If the buffer is still associated with a - // slot then another EGLImageKHR will be created next time that buffer - // gets acquired in updateTexImage. - eglDestroyImageKHR(dpy, image); - - if (err != OK) { - return err; - } - } - - mEglDisplay = dpy; - mEglContext = ctx; - mTexName = tex; - mAttached = true; - - return OK; -} - -status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { - ST_LOGV("syncForReleaseLocked"); - - if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - EGLSyncKHR fence = mEGLSlots[mCurrentTexture].mFence; - if (fence != EGL_NO_SYNC_KHR) { - // There is already a fence for the current slot. We need to wait - // on that before replacing it with another fence to ensure that all - // outstanding buffer accesses have completed before the producer - // accesses it. - EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); - if (result == EGL_FALSE) { - ST_LOGE("syncForReleaseLocked: error waiting for previous " - "fence: %#x", eglGetError()); - return UNKNOWN_ERROR; - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ST_LOGE("syncForReleaseLocked: timeout waiting for previous " - "fence"); - return TIMED_OUT; - } - eglDestroySyncKHR(dpy, fence); - } - - // Create a fence for the outstanding accesses in the current OpenGL ES - // context. - fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); - if (fence == EGL_NO_SYNC_KHR) { - ST_LOGE("syncForReleaseLocked: error creating fence: %#x", - eglGetError()); - return UNKNOWN_ERROR; - } - glFlush(); - mEGLSlots[mCurrentTexture].mFence = fence; - } - - return OK; -} - -bool SurfaceTexture::isExternalFormat(uint32_t format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - -GLenum SurfaceTexture::getCurrentTextureTarget() const { - return mTexTarget; -} - -void SurfaceTexture::getTransformMatrix(float mtx[16]) { - Mutex::Autolock lock(mMutex); - memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); -} - -void SurfaceTexture::setFilteringEnabled(bool enabled) { - Mutex::Autolock lock(mMutex); - bool needsRecompute = mFilteringEnabled != enabled; - mFilteringEnabled = enabled; - if (needsRecompute) { - computeCurrentTransformMatrix(); - } -} - -void SurfaceTexture::computeCurrentTransformMatrix() { - ST_LOGV("computeCurrentTransformMatrix"); - - float xform[16]; - for (int i = 0; i < 16; i++) { - xform[i] = mtxIdentity[i]; - } - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - float result[16]; - mtxMul(result, xform, mtxFlipH); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } - } - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - float result[16]; - mtxMul(result, xform, mtxFlipV); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } - } - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float result[16]; - mtxMul(result, xform, mtxRot90); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } - } - - sp& buf(mCurrentTextureBuf); - Rect cropRect = mCurrentCrop; - float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; - float bufferWidth = buf->getWidth(); - float bufferHeight = buf->getHeight(); - if (!cropRect.isEmpty()) { - float shrinkAmount = 0.0f; - if (mFilteringEnabled) { - // In order to prevent bilinear sampling beyond the edge of the - // crop rectangle we may need to shrink it by 2 texels in each - // dimension. Normally this would just need to take 1/2 a texel - // off each end, but because the chroma channels of YUV420 images - // are subsampled we may need to shrink the crop region by a whole - // texel on each side. - switch (buf->getPixelFormat()) { - case PIXEL_FORMAT_RGBA_8888: - case PIXEL_FORMAT_RGBX_8888: - case PIXEL_FORMAT_RGB_888: - case PIXEL_FORMAT_RGB_565: - case PIXEL_FORMAT_BGRA_8888: - case PIXEL_FORMAT_RGBA_5551: - case PIXEL_FORMAT_RGBA_4444: - // We know there's no subsampling of any channels, so we - // only need to shrink by a half a pixel. - shrinkAmount = 0.5; - - default: - // If we don't recognize the format, we must assume the - // worst case (that we care about), which is YUV420. - shrinkAmount = 1.0; - } - } - - // Only shrink the dimensions that are not the size of the buffer. - if (cropRect.width() < bufferWidth) { - tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; - sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / - bufferWidth; - } - if (cropRect.height() < bufferHeight) { - ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / - bufferHeight; - sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / - bufferHeight; - } - } - float crop[16] = { - sx, 0, 0, 0, - 0, sy, 0, 0, - 0, 0, 1, 0, - tx, ty, 0, 1, - }; - - float mtxBeforeFlipV[16]; - mtxMul(mtxBeforeFlipV, crop, xform); - - // SurfaceFlinger expects the top of its window textures to be at a Y - // coordinate of 0, so SurfaceTexture must behave the same way. We don't - // want to expose this to applications, however, so we must add an - // additional vertical flip to the transform after all the other transforms. - mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV); -} - -nsecs_t SurfaceTexture::getTimestamp() { - ST_LOGV("getTimestamp"); - Mutex::Autolock lock(mMutex); - return mCurrentTimestamp; -} - -void SurfaceTexture::setFrameAvailableListener( - const sp& listener) { - ST_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, - const sp& graphicBuffer) { - EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); - EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE, - }; - EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); - if (image == EGL_NO_IMAGE_KHR) { - EGLint error = eglGetError(); - ST_LOGE("error creating EGLImage: %#x", error); - } - return image; -} - -sp SurfaceTexture::getCurrentBuffer() const { - Mutex::Autolock lock(mMutex); - return mCurrentTextureBuf; -} - -Rect SurfaceTexture::getCurrentCrop() const { - Mutex::Autolock lock(mMutex); - - Rect outCrop = mCurrentCrop; - if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - int32_t newWidth = mCurrentCrop.width(); - int32_t newHeight = mCurrentCrop.height(); - - if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { - newWidth = newHeight * mDefaultWidth / mDefaultHeight; - ST_LOGV("too wide: newWidth = %d", newWidth); - } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { - newHeight = newWidth * mDefaultHeight / mDefaultWidth; - ST_LOGV("too tall: newHeight = %d", newHeight); - } - - // The crop is too wide - if (newWidth < mCurrentCrop.width()) { - int32_t dw = (newWidth - mCurrentCrop.width())/2; - outCrop.left -=dw; - outCrop.right += dw; - // The crop is too tall - } else if (newHeight < mCurrentCrop.height()) { - int32_t dh = (newHeight - mCurrentCrop.height())/2; - outCrop.top -= dh; - outCrop.bottom += dh; - } - - ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", - outCrop.left, outCrop.top, - outCrop.right,outCrop.bottom); - } - - return outCrop; -} - -uint32_t SurfaceTexture::getCurrentTransform() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransform; -} - -uint32_t SurfaceTexture::getCurrentScalingMode() const { - Mutex::Autolock lock(mMutex); - return mCurrentScalingMode; -} - -bool SurfaceTexture::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue->isSynchronousMode(); -} - -void SurfaceTexture::freeBufferLocked(int slotIndex) { - ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mEGLSlots[slotIndex].mGraphicBuffer = 0; - if (slotIndex == mCurrentTexture) { - mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; - } - EGLImageKHR img = mEGLSlots[slotIndex].mEglImage; - if (img != EGL_NO_IMAGE_KHR) { - ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img); - eglDestroyImageKHR(mEglDisplay, img); - } - mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR; -} - -void SurfaceTexture::abandon() { - ST_LOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - mAbandoned = true; - mCurrentTextureBuf.clear(); - - // destroy all egl buffers - for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - - // disconnect from the BufferQueue - mBufferQueue->consumerDisconnect(); - mBufferQueue.clear(); - } -} - -void SurfaceTexture::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mBufferQueue->setConsumerName(name); -} - -status_t SurfaceTexture::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock lock(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); -} - -status_t SurfaceTexture::setConsumerUsageBits(uint32_t usage) { - Mutex::Autolock lock(mMutex); - usage |= DEFAULT_USAGE_FLAGS; - return mBufferQueue->setConsumerUsageBits(usage); -} - -status_t SurfaceTexture::setTransformHint(uint32_t hint) { - Mutex::Autolock lock(mMutex); - return mBufferQueue->setTransformHint(hint); -} - -// Used for refactoring BufferQueue from SurfaceTexture -// Should not be in final interface once users of SurfaceTexture are clean up. -status_t SurfaceTexture::setSynchronousMode(bool enabled) { - Mutex::Autolock lock(mMutex); - return mBufferQueue->setSynchronousMode(enabled); -} - -// Used for refactoring, should not be in final interface -sp SurfaceTexture::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue; -} - -void SurfaceTexture::onFrameAvailable() { - ST_LOGV("onFrameAvailable"); - - sp listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener; - } - - if (listener != NULL) { - ST_LOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void SurfaceTexture::onBuffersReleased() { - ST_LOGV("onBuffersReleased"); - - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint32_t mask = 0; - mBufferQueue->getReleasedBuffers(&mask); - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } -} - -void SurfaceTexture::dump(String8& result) const -{ - char buffer[1024]; - dump(result, "", buffer, 1024); -} - -void SurfaceTexture::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, "%smTexName=%d, mAbandoned=%d\n", prefix, mTexName, - int(mAbandoned)); - result.append(buffer); - - snprintf(buffer, SIZE, - "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n", - prefix, mCurrentCrop.left, - mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform, mCurrentTexture - ); - result.append(buffer); - - if (!mAbandoned) { - mBufferQueue->dump(result, prefix, buffer, SIZE); - } -} - -static void mtxMul(float out[16], const float a[16], const float b[16]) { - out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; - out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; - out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; - out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; - - out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; - out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; - out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; - out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; - - out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; - out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; - out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; - out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; - - out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; - out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; - out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; - out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; -} - -}; // namespace android diff --git a/src/imports/nativemedia/SurfaceTexture_4_1.h b/src/imports/nativemedia/SurfaceTexture_4_1.h deleted file mode 100644 index 33aac7f..0000000 --- a/src/imports/nativemedia/SurfaceTexture_4_1.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_GUI_SURFACETEXTURE_H -#define ANDROID_GUI_SURFACETEXTURE_H - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture" - -namespace android { -// ---------------------------------------------------------------------------- - - -class String8; - -class SurfaceTexture : public virtual RefBase, - protected BufferQueue::ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the - // name of the OpenGL ES texture to which images are to be streamed. - // allowSynchronousMode specifies whether or not synchronous mode can be - // enabled. texTarget specifies the OpenGL ES texture target to which the - // texture will be bound in updateTexImage. useFenceSync specifies whether - // fences should be used to synchronize access to buffers if that behavior - // is enabled at compile-time. A custom bufferQueue can be specified - // if behavior for queue/dequeue/connect etc needs to be customized. - // Otherwise a default BufferQueue will be created and used. - // - // For legacy reasons, the SurfaceTexture is created in a state where it is - // considered attached to an OpenGL ES context for the purposes of the - // attachToContext and detachFromContext methods. However, despite being - // considered "attached" to a context, the specific OpenGL ES context - // doesn't get latched until the first call to updateTexImage. After that - // point, all calls to updateTexImage must be made with the same OpenGL ES - // context current. - // - // A SurfaceTexture may be detached from one OpenGL ES context and then - // attached to a different context using the detachFromContext and - // attachToContext methods, respectively. The intention of these methods is - // purely to allow a SurfaceTexture to be transferred from one consumer - // context to another. If such a transfer is not needed there is no - // requirement that either of these methods be called. - SurfaceTexture(GLuint tex, bool allowSynchronousMode = true, - GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true, - const sp &bufferQueue = 0); - - virtual ~SurfaceTexture(); - - // updateTexImage sets the image contents of the target texture to that of - // the most recently queued buffer. - // - // This call may only be made while the OpenGL ES context to which the - // target texture belongs is bound to the calling thread. - status_t updateTexImage(); - - // setBufferCountServer set the buffer count. If the client has requested - // a buffer count using setBufferCount, the server-buffer count will - // take effect once the client sets the count back to zero. - status_t setBufferCountServer(int bufferCount); - - // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix - // associated with the texture image set by the most recent call to - // updateTexImage. - // - // This transform matrix maps 2D homogeneous texture coordinates of the form - // (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture - // coordinate that should be used to sample that location from the texture. - // Sampling the texture outside of the range of this transform is undefined. - // - // This transform is necessary to compensate for transforms that the stream - // content producer may implicitly apply to the content. By forcing users of - // a SurfaceTexture to apply this transform we avoid performing an extra - // copy of the data that would be needed to hide the transform from the - // user. - // - // The matrix is stored in column-major order so that it may be passed - // directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv - // functions. - void getTransformMatrix(float mtx[16]); - - // getTimestamp retrieves the timestamp associated with the texture image - // set by the most recent call to updateTexImage. - // - // The timestamp is in nanoseconds, and is monotonically increasing. Its - // other semantics (zero point, etc) are source-dependent and should be - // documented by the source. - int64_t getTimestamp(); - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const sp& listener); - - // getAllocator retrieves the binder object that must be referenced as long - // as the GraphicBuffers dequeued from this SurfaceTexture are referenced. - // Holding this binder reference prevents SurfaceFlinger from freeing the - // buffers before the client is done with them. - sp getAllocator(); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - // A call to setDefaultBufferSize() may trigger requestBuffers() to - // be called from the client. - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. - status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // setFilteringEnabled sets whether the transform matrix should be computed - // for use with bilinear filtering. - void setFilteringEnabled(bool enabled); - - // getCurrentBuffer returns the buffer associated with the current image. - sp getCurrentBuffer() const; - - // getCurrentTextureTarget returns the texture target of the current - // texture as returned by updateTexImage(). - GLenum getCurrentTextureTarget() const; - - // getCurrentCrop returns the cropping rectangle of the current buffer. - Rect getCurrentCrop() const; - - // getCurrentTransform returns the transform of the current buffer. - uint32_t getCurrentTransform() const; - - // getCurrentScalingMode returns the scaling mode of the current buffer. - uint32_t getCurrentScalingMode() const; - - // isSynchronousMode returns whether the SurfaceTexture is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // abandon frees all the buffers and puts the SurfaceTexture into the - // 'abandoned' state. Once put in this state the SurfaceTexture can never - // leave it. When in the 'abandoned' state, all methods of the - // ISurfaceTexture interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the SurfaceTexture, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client or - // by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the SurfaceTexture that will be used to identify it in - // log messages. - void setName(const String8& name); - - // These functions call the corresponding BufferQueue implementation - // so the refactoring can proceed smoothly - status_t setDefaultBufferFormat(uint32_t defaultFormat); - status_t setConsumerUsageBits(uint32_t usage); - status_t setTransformHint(uint32_t hint); - virtual status_t setSynchronousMode(bool enabled); - - // getBufferQueue returns the BufferQueue object to which this - // SurfaceTexture is connected. - sp getBufferQueue() const; - - // detachFromContext detaches the SurfaceTexture from the calling thread's - // current OpenGL ES context. This context must be the same as the context - // that was current for previous calls to updateTexImage. - // - // Detaching a SurfaceTexture from an OpenGL ES context will result in the - // deletion of the OpenGL ES texture object into which the images were being - // streamed. After a SurfaceTexture has been detached from the OpenGL ES - // context calls to updateTexImage will fail returning INVALID_OPERATION - // until the SurfaceTexture is attached to a new OpenGL ES context using the - // attachToContext method. - status_t detachFromContext(); - - // attachToContext attaches a SurfaceTexture that is currently in the - // 'detached' state to the current OpenGL ES context. A SurfaceTexture is - // in the 'detached' state iff detachFromContext has successfully been - // called and no calls to attachToContext have succeeded since the last - // detachFromContext call. Calls to attachToContext made on a - // SurfaceTexture that is not in the 'detached' state will result in an - // INVALID_OPERATION error. - // - // The tex argument specifies the OpenGL ES texture object name in the - // new context into which the image contents will be streamed. A successful - // call to attachToContext will result in this texture object being bound to - // the texture target and populated with the image contents that were - // current at the time of the last call to detachFromContext. - status_t attachToContext(GLuint tex); - - // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - -protected: - - // Implementation of the BufferQueue::ConsumerListener interface. These - // calls are used to notify the SurfaceTexture of asynchronous events in the - // BufferQueue. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - static bool isExternalFormat(uint32_t format); - -private: - // this version of updateTexImage() takes a functor used to reject or not - // the newly acquired buffer. - // this API is TEMPORARY and intended to be used by SurfaceFlinger only, - // which is why class Layer is made a friend of SurfaceTexture below. - class BufferRejecter { - friend class SurfaceTexture; - virtual bool reject(const sp& buf, - const BufferQueue::BufferItem& item) = 0; - protected: - virtual ~BufferRejecter() { } - }; - friend class Layer; - status_t updateTexImage(BufferRejecter* rejecter); - - // createImage creates a new EGLImage from a GraphicBuffer. - EGLImageKHR createImage(EGLDisplay dpy, - const sp& graphicBuffer); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot and destroy the EGLImage in that slot. Otherwise it has no effect. - // - // This method must be called with mMutex locked. - void freeBufferLocked(int slotIndex); - - // computeCurrentTransformMatrix computes the transform matrix for the - // current texture. It uses mCurrentTransform and the current GraphicBuffer - // to compute this matrix and stores it in mCurrentTransformMatrix. - void computeCurrentTransformMatrix(); - - // syncForReleaseLocked performs the synchronization needed to release the - // current slot from an OpenGL ES context. If needed it will set the - // current slot's fence to guard against a producer accessing the buffer - // before the outstanding accesses have completed. - status_t syncForReleaseLocked(EGLDisplay dpy); - - // The default consumer usage flags that SurfaceTexture always sets on its - // BufferQueue instance; these will be OR:d with any additional flags passed - // from the SurfaceTexture user. In particular, SurfaceTexture will always - // consume buffers as hardware textures. - static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; - - // mCurrentTextureBuf is the graphic buffer of the current texture. It's - // possible that this buffer is not associated with any buffer slot, so we - // must track it separately in order to support the getCurrentBuffer method. - sp mCurrentTextureBuf; - - // mCurrentCrop is the crop rectangle that applies to the current texture. - // It gets set each time updateTexImage is called. - Rect mCurrentCrop; - - // mCurrentTransform is the transform identifier for the current texture. It - // gets set each time updateTexImage is called. - uint32_t mCurrentTransform; - - // mCurrentScalingMode is the scaling mode for the current texture. It gets - // set to each time updateTexImage is called. - uint32_t mCurrentScalingMode; - - // mCurrentTransformMatrix is the transform matrix for the current texture. - // It gets computed by computeTransformMatrix each time updateTexImage is - // called. - float mCurrentTransformMatrix[16]; - - // mCurrentTimestamp is the timestamp for the current texture. It - // gets set each time updateTexImage is called. - int64_t mCurrentTimestamp; - - uint32_t mDefaultWidth, mDefaultHeight; - - // mFilteringEnabled indicates whether the transform matrix is computed for - // use with bilinear filtering. It defaults to true and is changed by - // setFilteringEnabled(). - bool mFilteringEnabled; - - // mTexName is the name of the OpenGL texture to which streamed images will - // be bound when updateTexImage is called. It is set at construction time - // and can be changed with a call to attachToContext. - GLuint mTexName; - - // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync - // extension should be used to prevent buffers from being dequeued before - // it's safe for them to be written. It gets set at construction time and - // never changes. - const bool mUseFenceSync; - - // mTexTarget is the GL texture target with which the GL texture object is - // associated. It is set in the constructor and never changed. It is - // almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android - // Browser. In that case it is set to GL_TEXTURE_2D to allow - // glCopyTexSubImage to read from the texture. This is a hack to work - // around a GL driver limitation on the number of FBO attachments, which the - // browser's tile cache exceeds. - const GLenum mTexTarget; - - // EGLSlot contains the information and object references that - // SurfaceTexture maintains about a BufferQueue buffer slot. - struct EGLSlot { - EGLSlot() - : mEglImage(EGL_NO_IMAGE_KHR), - mFence(EGL_NO_SYNC_KHR) { - } - - sp mGraphicBuffer; - - // mEglImage is the EGLImage created from mGraphicBuffer. - EGLImageKHR mEglImage; - - // mFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based - // on a compile-time option) set to a new sync object in updateTexImage. - EGLSyncKHR mFence; - }; - - // mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently - // associated. It is intialized to EGL_NO_DISPLAY and gets set to the - // current display when updateTexImage is called for the first time and when - // attachToContext is called. - EGLDisplay mEglDisplay; - - // mEglContext is the OpenGL ES context with which this SurfaceTexture is - // currently associated. It is initialized to EGL_NO_CONTEXT and gets set - // to the current GL context when updateTexImage is called for the first - // time and when attachToContext is called. - EGLContext mEglContext; - - // mEGLSlots stores the buffers that have been allocated by the BufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of BufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - EGLSlot mEGLSlots[BufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the BufferQueue will no longer be used to - // consume images buffers pushed to it using the ISurfaceTexture interface. - // It is initialized to false, and set to true in the abandon method. A - // BufferQueue that has been abandoned will return the NO_INIT error from - // all ISurfaceTexture methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the SurfaceTexture in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - sp mFrameAvailableListener; - - // mCurrentTexture is the buffer slot index of the buffer that is currently - // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, - // indicating that no buffer slot is currently bound to the texture. Note, - // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - // that no buffer is bound to the texture. A call to setBufferCount will - // reset mCurrentTexture to INVALID_BUFFER_SLOT. - int mCurrentTexture; - - // The SurfaceTexture has-a BufferQueue and is responsible for creating this object - // if none is supplied - sp mBufferQueue; - - // mAttached indicates whether the SurfaceTexture is currently attached to - // an OpenGL ES context. For legacy reasons, this is initialized to true, - // indicating that the SurfaceTexture is considered to be attached to - // whatever context is current at the time of the first updateTexImage call. - // It is set to false by detachFromContext, and then set to true again by - // attachToContext. - bool mAttached; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of SurfaceTexture objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_SURFACETEXTURE_H diff --git a/src/imports/nativemedia/main.cpp b/src/imports/nativemedia/main.cpp deleted file mode 100644 index b14b3d0..0000000 --- a/src/imports/nativemedia/main.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include - -void initializeOMX(); -void render(QOpenGLContext *context, QWindow *surface); - -class Renderer : public QObject -{ - Q_OBJECT -public: - Renderer(QWindow *surface) - : surface(surface) - { - context = new QOpenGLContext; - - context->create(); - context->makeCurrent(surface); - - initializeOMX(); - qDebug() << "OMX initialized"; - } - -public slots: - void render() { - ::render(context, surface); - } - -public: - QWindow *surface; - QOpenGLContext *context; -} *renderer; - -void triggerRender() -{ - QTimer::singleShot(0, renderer, SLOT(render())); -} - -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QScreen *screen = QGuiApplication::primaryScreen(); - - qDebug() << "Screen geometry:" << screen->geometry(); - - QWindow window; - window.setSurfaceType(QWindow::OpenGLSurface); - window.setGeometry(screen->geometry()); - window.show(); - - renderer = new Renderer(&window); - - return app.exec(); -} - -#include "main.moc" diff --git a/src/imports/nativemedia/nativemedia.pro b/src/imports/nativemedia/nativemedia.pro deleted file mode 100644 index 027608d..0000000 --- a/src/imports/nativemedia/nativemedia.pro +++ /dev/null @@ -1,21 +0,0 @@ -###################################################################### -# Automatically generated by qmake (3.0) Thu Mar 7 13:00:32 2013 -###################################################################### - -CXX_MODULE = qml -TARGET = android_omx -TARGETPATH = QtAndroidOmx -IMPORT_VERSION = 1.0 - -INCLUDEPATH += $$ANDROID_BUILD_TOP/development/ndk/platforms/android-14/include/ - -LIBS += -lOpenMAXAL -lui -lgui -lutils -lcutils -lbinder - -QT += qml quick - -# Input -HEADERS += omxnode.h omxplayer.h -SOURCES += omx.cpp SurfaceTexture.cpp BufferQueue.cpp omxnode.cpp omxmodule.cpp - -load(qml_plugin) - diff --git a/src/imports/nativemedia/omx.cpp b/src/imports/nativemedia/omx.cpp deleted file mode 100644 index b2ad4bc..0000000 --- a/src/imports/nativemedia/omx.cpp +++ /dev/null @@ -1,666 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include -#include - -#include -#include - -#include "omxplayer.h" - -#include - -#include - -// number of required interfaces for the MediaPlayer creation -#define NB_MAXAL_INTERFACES 3 // XAAndroidBufferQueueItf, XAStreamInformationItf and XAPlayItf - -// number of buffers in our buffer queue, an arbitrary number -#define NB_BUFFERS 8 - -// we're streaming MPEG-2 transport stream data, operate on transport stream block size -#define MPEG2_TS_PACKET_SIZE 188 - -// number of MPEG-2 transport stream blocks per buffer, an arbitrary number -#define PACKETS_PER_BUFFER 10 - -// determines how much memory we're dedicating to memory caching -#define BUFFER_SIZE (PACKETS_PER_BUFFER*MPEG2_TS_PACKET_SIZE) - -using namespace android; - -// constant to identify a buffer context which is the end of the stream to decode -static const int kEosBufferCntxt = 1980; // a magic value we can compare against - -OmxPlayer::~OmxPlayer() -{ -} - -struct OmxContext : public OmxPlayer { - // engine interfaces - XAObjectItf engineObject; - XAEngineItf engineEngine; - - // output mix interfaces - XAObjectItf outputMixObject; - - // streaming media player interfaces - XAObjectItf playerObj; - XAPlayItf playerPlayItf; - XAAndroidBufferQueueItf playerBQItf; - XAStreamInformationItf playerStreamInfoItf; - XAVolumeItf playerVolItf; - - // where we cache in memory the data to play - // note this memory is re-used by the buffer queue callback - char dataCache[BUFFER_SIZE * NB_BUFFERS]; - - // handle of the file to play - FILE *file; - - // has the app reached the end of the file - bool reachedEof; - - // For mutual exclusion between callback thread and application thread(s). - // The mutex protects reachedEof, discontinuity, - // The condition is signalled when a discontinuity is acknowledged. - - pthread_mutex_t mutex; - pthread_cond_t cond; - - sp surfaceTexture; - sp surfaceTextureClient; - - int currentFrame; - GLuint textureId; - - // for render, useful for debugging - QOpenGLShaderProgram *program; - - int vertexLocation; - int texCoordLocation; - int textureLocation; - - OmxContext() - : engineObject(0) - , engineEngine(0) - , outputMixObject(0) - , playerObj(0) - , playerPlayItf(0) - , playerBQItf(0) - , playerStreamInfoItf(0) - , playerVolItf(0) - , file(0) - , reachedEof(false) - , mutex(PTHREAD_MUTEX_INITIALIZER) - , cond(PTHREAD_COND_INITIALIZER) - , currentFrame(-1) - , textureId(0) - , program(0) - , vertexLocation(0) - , texCoordLocation(0) - , textureLocation(0) - { - } - - ~OmxContext(); - - void updateTexture() - { - if (surfaceTexture.get()) - surfaceTexture->updateTexImage(); - } - - bool hasFrame() - { - return currentFrame >= 0; - } - - void setPaused(bool paused); - - bool initialize(const QByteArray &filename); - bool enqueueInitialBuffers(bool discontinuity); - - XAresult AndroidBufferQueueCallback( - XAAndroidBufferQueueItf caller, - void *pCallbackContext, - void *pBufferContext, - void *pBufferData, - XAuint32 dataSize, - XAuint32 dataUsed, - const XAAndroidBufferItem *pItems, - XAuint32 itemsLength); - - void StreamChangeCallback(XAStreamInformationItf caller, - XAuint32 eventId, - XAuint32 streamIndex, - void * pEventData, - void * pContext ); - - void render(QOpenGLContext *context, QWindow *surface); -}; - -static XAresult AndroidBufferQueueCallback( - XAAndroidBufferQueueItf caller, - void *pCallbackContext, /* input */ - void *pBufferContext, /* input */ - void *pBufferData, /* input */ - XAuint32 dataSize, /* input */ - XAuint32 dataUsed, /* input */ - const XAAndroidBufferItem *pItems,/* input */ - XAuint32 itemsLength /* input */) -{ - return static_cast(pCallbackContext)->AndroidBufferQueueCallback( - caller, pCallbackContext, pBufferContext, pBufferData, dataSize, dataUsed, pItems, itemsLength); -} - -// AndroidBufferQueueItf callback to supply MPEG-2 TS packets to the media player -XAresult OmxContext::AndroidBufferQueueCallback( - XAAndroidBufferQueueItf caller, - void *pCallbackContext, /* input */ - void *pBufferContext, /* input */ - void *pBufferData, /* input */ - XAuint32 dataSize, /* input */ - XAuint32 dataUsed, /* input */ - const XAAndroidBufferItem *pItems,/* input */ - XAuint32 itemsLength /* input */) -{ - XAresult res; - int ok; - - // note there is never any contention on this mutex unless a discontinuity request is active - ok = pthread_mutex_lock(&mutex); - assert(0 == ok); - -#if 0 - // was a discontinuity requested? - if (discontinuity) { - // Note: can't rewind after EOS, which we send when reaching EOF - // (don't send EOS if you plan to play more content through the same player) - if (!reachedEof) { - // clear the buffer queue - res = (*playerBQItf)->Clear(playerBQItf); - assert(XA_RESULT_SUCCESS == res); - // rewind the data source so we are guaranteed to be at an appropriate point - rewind(file); - // Enqueue the initial buffers, with a discontinuity indicator on first buffer - (void) enqueueInitialBuffers(JNI_TRUE); - } - // acknowledge the discontinuity request - discontinuity = JNI_FALSE; - ok = pthread_cond_signal(&cond); - assert(0 == ok); - goto exit; - } -#endif - - if ((pBufferData == NULL) && (pBufferContext != NULL)) { - const int processedCommand = *(int *)pBufferContext; - if (kEosBufferCntxt == processedCommand) { - qDebug("EOS was processed\n"); - // our buffer with the EOS message has been consumed - assert(0 == dataSize); - goto exit; - } - } - - // pBufferData is a pointer to a buffer that we previously Enqueued - assert((dataSize > 0) && ((dataSize % MPEG2_TS_PACKET_SIZE) == 0)); - assert(dataCache <= (char *) pBufferData && (char *) pBufferData < - &dataCache[BUFFER_SIZE * NB_BUFFERS]); - assert(0 == (((char *) pBufferData - dataCache) % BUFFER_SIZE)); - - // don't bother trying to read more data once we've hit EOF - if (reachedEof) { - goto exit; - } - - size_t nbRead; - // note we do call fread from multiple threads, but never concurrently - size_t bytesRead; - bytesRead = fread(pBufferData, 1, BUFFER_SIZE, file); - if (bytesRead > 0) { - if ((bytesRead % MPEG2_TS_PACKET_SIZE) != 0) { - qDebug("Dropping last packet because it is not whole"); - } - size_t packetsRead = bytesRead / MPEG2_TS_PACKET_SIZE; - size_t bufferSize = packetsRead * MPEG2_TS_PACKET_SIZE; - res = (*caller)->Enqueue(caller, NULL /*pBufferContext*/, - pBufferData /*pData*/, - bufferSize /*dataLength*/, - NULL /*pMsg*/, - 0 /*msgLength*/); - assert(XA_RESULT_SUCCESS == res); - } else { - // EOF or I/O error, signal EOS - XAAndroidBufferItem msgEos[1]; - msgEos[0].itemKey = XA_ANDROID_ITEMKEY_EOS; - msgEos[0].itemSize = 0; - // EOS message has no parameters, so the total size of the message is the size of the key - // plus the size if itemSize, both XAuint32 - res = (*caller)->Enqueue(caller, (void *)&kEosBufferCntxt /*pBufferContext*/, - NULL /*pData*/, 0 /*dataLength*/, - msgEos /*pMsg*/, - sizeof(XAuint32)*2 /*msgLength*/); - assert(XA_RESULT_SUCCESS == res); - reachedEof = true; - } - -exit: - ok = pthread_mutex_unlock(&mutex); - assert(0 == ok); - return XA_RESULT_SUCCESS; -} - -// callback invoked whenever there is new or changed stream information -static void StreamChangeCallback(XAStreamInformationItf caller, - XAuint32 eventId, - XAuint32 streamIndex, - void * pEventData, - void * pContext ) -{ - static_cast(pContext)->StreamChangeCallback( - caller, eventId, streamIndex, pEventData, pContext); -} - -// callback invoked whenever there is new or changed stream information -void OmxContext::StreamChangeCallback(XAStreamInformationItf caller, - XAuint32 eventId, - XAuint32 streamIndex, - void * pEventData, - void * pContext ) -{ - qDebug("StreamChangeCallback called for stream %u", streamIndex); - - switch (eventId) { - case XA_STREAMCBEVENT_PROPERTYCHANGE: { - /** From spec 1.0.1: - "This event indicates that stream property change has occurred. - The streamIndex parameter identifies the stream with the property change. - The pEventData parameter for this event is not used and shall be ignored." - */ - - XAresult res; - XAuint32 domain; - res = (*caller)->QueryStreamType(caller, streamIndex, &domain); - assert(XA_RESULT_SUCCESS == res); - switch (domain) { - case XA_DOMAINTYPE_VIDEO: { - XAVideoStreamInformation videoInfo; - res = (*caller)->QueryStreamInformation(caller, streamIndex, &videoInfo); - assert(XA_RESULT_SUCCESS == res); - qDebug("Found video size %u x %u, codec ID=%u, frameRate=%u, bitRate=%u, duration=%u ms", - videoInfo.width, videoInfo.height, videoInfo.codecId, videoInfo.frameRate, - videoInfo.bitRate, videoInfo.duration); - emit videoSize(videoInfo.width, videoInfo.height); - } break; - default: - fprintf(stderr, "Unexpected domain %u\n", domain); - break; - } - } break; - default: - fprintf(stderr, "Unexpected stream event ID %u\n", eventId); - break; - } -} - -// Enqueue the initial buffers, and optionally signal a discontinuity in the first buffer -bool OmxContext::enqueueInitialBuffers(bool discontinuity) -{ - - /* Fill our cache. - * We want to read whole packets (integral multiples of MPEG2_TS_PACKET_SIZE). - * fread returns units of "elements" not bytes, so we ask for 1-byte elements - * and then check that the number of elements is a multiple of the packet size. - */ - size_t bytesRead; - bytesRead = fread(dataCache, 1, BUFFER_SIZE * NB_BUFFERS, file); - if (bytesRead <= 0) { - // could be premature EOF or I/O error - return false; - } - if ((bytesRead % MPEG2_TS_PACKET_SIZE) != 0) { - qDebug("Dropping last packet because it is not whole"); - } - size_t packetsRead = bytesRead / MPEG2_TS_PACKET_SIZE; - qDebug("Initially queueing %u packets", packetsRead); - - /* Enqueue the content of our cache before starting to play, - we don't want to starve the player */ - size_t i; - for (i = 0; i < NB_BUFFERS && packetsRead > 0; i++) { - // compute size of this buffer - size_t packetsThisBuffer = packetsRead; - if (packetsThisBuffer > PACKETS_PER_BUFFER) { - packetsThisBuffer = PACKETS_PER_BUFFER; - } - size_t bufferSize = packetsThisBuffer * MPEG2_TS_PACKET_SIZE; - XAresult res; - if (discontinuity) { - // signal discontinuity - XAAndroidBufferItem items[1]; - items[0].itemKey = XA_ANDROID_ITEMKEY_DISCONTINUITY; - items[0].itemSize = 0; - // DISCONTINUITY message has no parameters, - // so the total size of the message is the size of the key - // plus the size if itemSize, both XAuint32 - res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, - dataCache + i*BUFFER_SIZE, bufferSize, items /*pMsg*/, - sizeof(XAuint32)*2 /*msgLength*/); - //discontinuity = false; - } else { - res = (*playerBQItf)->Enqueue(playerBQItf, NULL /*pBufferContext*/, - dataCache + i*BUFFER_SIZE, bufferSize, NULL, 0); - } - assert(XA_RESULT_SUCCESS == res); - packetsRead -= packetsThisBuffer; - } - - return true; -} - -class FrameCallback : public SurfaceTexture::FrameAvailableListener -{ -public: - FrameCallback(OmxContext *ctx) - : context(ctx) - { - } - - void onFrameAvailable() - { - emit context->frameAvailable(); - ++context->currentFrame; - } - -private: - OmxContext *context; -}; - -OmxPlayer *OmxPlayer::create() -{ - return new OmxContext; -} - -bool OmxContext::initialize(const QByteArray &filename) -{ - file = fopen(filename.data(), "rb"); - if (!file) { - qWarning("Failed to open %s", filename.data()); - return false; - } - - XAresult res; - - qDebug() << "Creating engine object"; - - // create engine - res = xaCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); - assert(XA_RESULT_SUCCESS == res); - - qDebug() << "Creating engine object succeeded?" << (res == XA_RESULT_SUCCESS); - - // realize the engine - res = (*engineObject)->Realize(engineObject, XA_BOOLEAN_FALSE); - assert(XA_RESULT_SUCCESS == res); - - qDebug() << "Realizing engine object succeeded?" << (res == XA_RESULT_SUCCESS); - - // get the engine interface, which is needed in order to create other objects - res = (*engineObject)->GetInterface(engineObject, XA_IID_ENGINE, &engineEngine); - assert(XA_RESULT_SUCCESS == res); - - qDebug() << "Getting engine interface succeeded?" << (res == XA_RESULT_SUCCESS); - - // create output mix - res = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); - assert(XA_RESULT_SUCCESS == res); - - qDebug() << "Creating output mix succeeded?" << (res == XA_RESULT_SUCCESS); - - // realize the output mix - res = (*outputMixObject)->Realize(outputMixObject, XA_BOOLEAN_FALSE); - assert(XA_RESULT_SUCCESS == res); - - qDebug() << "Realizing output mix succeeded?" << (res == XA_RESULT_SUCCESS); - - // configure data source - XADataLocator_AndroidBufferQueue loc_abq = { XA_DATALOCATOR_ANDROIDBUFFERQUEUE, NB_BUFFERS }; - XADataFormat_MIME format_mime = { - XA_DATAFORMAT_MIME, XA_ANDROID_MIME_MP2TS, XA_CONTAINERTYPE_MPEG_TS }; - XADataSource dataSrc = {&loc_abq, &format_mime}; - - // configure audio sink - XADataLocator_OutputMix loc_outmix = { XA_DATALOCATOR_OUTPUTMIX, outputMixObject }; - XADataSink audioSnk = { &loc_outmix, 0 }; - - qDebug() << "Creating SurfaceTexture"; - - glGenTextures(1, &textureId); - surfaceTexture = new android::SurfaceTexture(textureId); - - qDebug() << "Creating SurfaceTextureClient"; - - android::sp surfaceTextureClient = new android::SurfaceTextureClient(surfaceTexture); - - sp listener = new FrameCallback(this); - - surfaceTexture->setFrameAvailableListener(listener); - - // configure image video sink - XADataLocator_NativeDisplay loc_nd = { - XA_DATALOCATOR_NATIVEDISPLAY, // locatorType - // the video sink must be an ANativeWindow created from a Surface or SurfaceTexture - static_cast(surfaceTextureClient.get()), // hWindow - // must be 0 - 0 // hDisplay - }; - XADataSink imageVideoSink = {&loc_nd, 0}; - - // declare interfaces to use - XAboolean required[NB_MAXAL_INTERFACES] - = {XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE, XA_BOOLEAN_TRUE}; - XAInterfaceID iidArray[NB_MAXAL_INTERFACES] - = {XA_IID_PLAY, XA_IID_ANDROIDBUFFERQUEUESOURCE, - XA_IID_STREAMINFORMATION}; - - - qDebug() << "Creating media player for engine" << engineEngine; - - // create media player - res = (*engineEngine)->CreateMediaPlayer(engineEngine, &playerObj, &dataSrc, - 0, &audioSnk, &imageVideoSink, 0, 0, - NB_MAXAL_INTERFACES /*XAuint32 numInterfaces*/, - iidArray /*const XAInterfaceID *pInterfaceIds*/, - required /*const XAboolean *pInterfaceRequired*/); - - qDebug() << "CreateMediaPlayer succeeded?" << (res == XA_RESULT_SUCCESS); - - // realize the player - res = (*playerObj)->Realize(playerObj, XA_BOOLEAN_FALSE); - - qDebug() << "Realize media player succeeded?" << (res == XA_RESULT_SUCCESS); - - // get the play interface - res = (*playerObj)->GetInterface(playerObj, XA_IID_PLAY, &playerPlayItf); - - qDebug() << "Get play interface succeeded?" << (res == XA_RESULT_SUCCESS); - - // get the stream information interface (for video size) - res = (*playerObj)->GetInterface(playerObj, XA_IID_STREAMINFORMATION, &playerStreamInfoItf); - - qDebug() << "Get stream information interface succeeded?" << (res == XA_RESULT_SUCCESS); - - // get the volume interface - res = (*playerObj)->GetInterface(playerObj, XA_IID_VOLUME, &playerVolItf); - - qDebug() << "Get volume interface succeeded?" << (res == XA_RESULT_SUCCESS); - - // get the Android buffer queue interface - res = (*playerObj)->GetInterface(playerObj, XA_IID_ANDROIDBUFFERQUEUESOURCE, &playerBQItf); - - qDebug() << "Get buffer queue interface succeeded?" << (res == XA_RESULT_SUCCESS); - - // specify which events we want to be notified of - res = (*playerBQItf)->SetCallbackEventsMask(playerBQItf, XA_ANDROIDBUFFERQUEUEEVENT_PROCESSED); - - qDebug() << "Setting callback events mask succeeded?" << (res == XA_RESULT_SUCCESS); - - // register the callback from which OpenMAX AL can retrieve the data to play - res = (*playerBQItf)->RegisterCallback(playerBQItf, ::AndroidBufferQueueCallback, this); - - qDebug() << "Registering buffer queue callback succeeded?" << (res == XA_RESULT_SUCCESS); - - // we want to be notified of the video size once it's found, so we register a callback for that - res = (*playerStreamInfoItf)->RegisterStreamChangeCallback(playerStreamInfoItf, - ::StreamChangeCallback, this); - - qDebug() << "Registering stream change callback succeeded?" << (res == XA_RESULT_SUCCESS); - - // enqueue the initial buffers - if (!enqueueInitialBuffers(false)) - return false; - - qDebug() << "Enqueued initial buffers"; - - // prepare the player - res = (*playerPlayItf)->SetPlayState(playerPlayItf, XA_PLAYSTATE_PAUSED); - - qDebug() << "Preparing player (setting play state paused) succeeded?" << (res == XA_RESULT_SUCCESS); - - // set the volume - res = (*playerVolItf)->SetVolumeLevel(playerVolItf, 0); - - qDebug() << "Setting volume level succeeded?" << (res == XA_RESULT_SUCCESS); - - return true; -} - -OmxContext::~OmxContext() -{ - if (!file) - return; - - // destroy streaming media player object, and invalidate all associated interfaces - if (playerObj != NULL) { - (*playerObj)->Destroy(playerObj); - playerObj = NULL; - playerPlayItf = NULL; - playerBQItf = NULL; - playerStreamInfoItf = NULL; - playerVolItf = NULL; - } - - // destroy output mix object, and invalidate all associated interfaces - if (outputMixObject != NULL) { - (*outputMixObject)->Destroy(outputMixObject); - outputMixObject = NULL; - } - - // destroy engine object, and invalidate all associated interfaces - if (engineObject != NULL) { - (*engineObject)->Destroy(engineObject); - engineObject = NULL; - engineEngine = NULL; - } -} - -void OmxContext::setPaused(bool paused) -{ - XAresult res; - - // make sure the streaming media player was created - if (NULL != playerPlayItf) { - // set the player's state - res = (*playerPlayItf)->SetPlayState(playerPlayItf, paused ? - XA_PLAYSTATE_PAUSED : XA_PLAYSTATE_PLAYING); - } -} - -void OmxContext::render(QOpenGLContext *context, QWindow *surface) -{ - context->makeCurrent(surface); - - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - - if (currentFrame >= 0) { - surfaceTexture->updateTexImage(); - - if (!program) { - qDebug() << "Received first video frame, starting to render"; - - program = new QOpenGLShaderProgram; - - program->addShaderFromSourceCode(QOpenGLShader::Vertex, - "attribute highp vec4 vertex;\n" - "attribute highp vec2 texCoord;\n" - "varying highp vec2 coord;\n" - "void main(void)\n" - "{\n" - " coord = texCoord;\n" - " gl_Position = vertex;\n" - "}"); - program->addShaderFromSourceCode(QOpenGLShader::Fragment, - "#extension GL_OES_EGL_image_external : require\n" - "uniform samplerExternalOES tex;\n" - "varying highp vec2 coord;\n" - "void main(void)\n" - "{\n" - " gl_FragColor = texture2D(tex, coord);\n" - "}"); - - program->link(); - - vertexLocation = program->attributeLocation("vertex"); - texCoordLocation = program->attributeLocation("texCoord"); - textureLocation = program->uniformLocation("tex"); - - qDebug() << "attribute locations" << vertexLocation << texCoordLocation; - qDebug() << "uniform location" << textureLocation; - } - - program->bind(); - - static GLfloat const triangleVertices[] = { - -1, -3, - 3, 1, - -1, 1 - }; - - static GLfloat const triangleTexCoords[] = { - 0, 2, - 2, 0, - 0, 0 - }; - - program->enableAttributeArray(vertexLocation); - program->setAttributeArray(vertexLocation, triangleVertices, 2); - program->enableAttributeArray(texCoordLocation); - program->setAttributeArray(texCoordLocation, triangleTexCoords, 2); - - glDrawArrays(GL_TRIANGLES, 0, 3); - - program->disableAttributeArray(vertexLocation); - program->disableAttributeArray(texCoordLocation); - } - - context->swapBuffers(surface); -} diff --git a/src/imports/nativemedia/omxmodule.cpp b/src/imports/nativemedia/omxmodule.cpp deleted file mode 100644 index 2daa154..0000000 --- a/src/imports/nativemedia/omxmodule.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "omxnode.h" -#include - -class QAndroidOmxModule : public QQmlExtensionPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") - -public: - virtual void registerTypes(const char *uri) - { - Q_ASSERT(QLatin1String(uri) == QLatin1String("QtAndroidOmx")); - - qmlRegisterType(uri, 1, 0, "OmxItem"); - } -}; - -#include "omxmodule.moc" - diff --git a/src/imports/nativemedia/omxnode.cpp b/src/imports/nativemedia/omxnode.cpp deleted file mode 100644 index 27ec1da..0000000 --- a/src/imports/nativemedia/omxnode.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "omxnode.h" - -#include -#include -#include - -#include - -static const char omx_texture_material_vertex[] = - "uniform highp mat4 qt_Matrix; \n" - "attribute highp vec4 qt_VertexPosition; \n" - "attribute highp vec2 qt_VertexTexCoord; \n" - "varying highp vec2 qt_TexCoord; \n" - "void main() { \n" - " qt_TexCoord = qt_VertexTexCoord; \n" - " gl_Position = qt_Matrix * qt_VertexPosition; \n" - "}"; - - -static const char omx_texture_material_fragment[] = - "#extension GL_OES_EGL_image_external : require \n" - "varying highp vec2 qt_TexCoord; \n" - "uniform samplerExternalOES qt_Texture; \n" - "uniform lowp float qt_Opacity; \n" - "void main() { \n" - " gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * qt_Opacity; \n" - "}"; - -QList OmxTextureMaterial::attributes() const -{ - QList attributeList; - attributeList << "qt_VertexPosition"; - attributeList << "qt_VertexTexCoord"; - return attributeList; -} - -void OmxTextureMaterial::updateState(const OmxTextureState *newState, const OmxTextureState *oldState) -{ - Q_UNUSED(oldState); - newState->player->updateTexture(); -} - -const char *OmxTextureMaterial::vertexShader() const -{ - return omx_texture_material_vertex; -} - -const char *OmxTextureMaterial::fragmentShader() const -{ - return omx_texture_material_fragment; -} - -OmxNode::OmxNode(OmxPlayer *player) - : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) - , m_player(player) - , m_initialized(false) -{ - m_textureMaterial = OmxTextureMaterial::createMaterial(); - m_textureMaterial->state()->player = player; - - setGeometry(&m_geometry); - setMaterial(m_textureMaterial); - - setFlag(UsePreprocess, true); -} - -OmxNode::~OmxNode() -{ - delete m_textureMaterial; -} - -void OmxNode::preprocess() -{ -} - -void OmxNode::setRect(const QRectF &rect) -{ - if (m_rect == rect) - return; - - printf("OmxNode::setRect(%f %f %f %f)\n", rect.x(), rect.y(), rect.width(), rect.height()); - m_rect = rect; - - QRectF sourceRect(0, 0, 1, 1); - QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_rect, sourceRect); -} - -OmxItem::OmxItem() - : m_player(OmxPlayer::create()) - , m_hasFrame(false) - , m_initialized(false) - , m_paused(false) - , m_sourceWidth(0) - , m_sourceHeight(0) -{ - connect(m_player, SIGNAL(frameAvailable()), this, SLOT(triggerRender())); - connect(m_player, SIGNAL(videoSize(int, int)), this, SLOT(videoSize(int, int))); - - setFlag(ItemHasContents, true); -} - -void OmxItem::itemChange(ItemChange change, const ItemChangeData &) -{ - if (change == ItemSceneChange) { - QQuickWindow *win = window(); - if (!win) - return; - - // Connect the beforeRendering signal to our paint function. - // Since this call is executed on the rendering thread it must be - // a Qt::DirectConnection - connect(win, SIGNAL(beforeRendering()), this, SLOT(beforeRendering()), Qt::DirectConnection); - } -} - - -OmxItem::~OmxItem() -{ - delete m_player; -} - -void OmxItem::triggerRender() -{ - m_hasFrame = true; - update(); -} - -void OmxItem::videoSize(int w, int h) -{ - m_sourceWidth = w; - m_sourceHeight = h; - - emit sourceWidthChanged(); - emit sourceHeightChanged(); -} - -void OmxItem::setSource(const QString &source) -{ - if (m_initialized || source == m_source) - return; - - m_source = source; - emit sourceChanged(); - update(); -} - -void OmxItem::beforeRendering() -{ - if (m_initialized || m_source.isNull()) - return; - - m_initialized = m_player->initialize(m_source.toLocal8Bit()); - - GLuint tid; - glGenTextures(1, &tid); - - // start playing if not paused - if (m_initialized && !paused()) - m_player->setPaused(false); -} - -QSGNode *OmxItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) -{ - if (!m_hasFrame) - return 0; - - OmxNode *node; - if (oldNode) - node = static_cast(oldNode); - else - node = new OmxNode(m_player); - - node->setRect(boundingRect()); - node->markDirty(QSGNode::DirtyMaterial); - - return node; -} - -void OmxItem::setPaused(bool p) -{ - if (p == m_paused) - return; - m_player->setPaused(p); - m_paused = p; - emit pausedChanged(); -} diff --git a/src/imports/nativemedia/omxnode.h b/src/imports/nativemedia/omxnode.h deleted file mode 100644 index e658378..0000000 --- a/src/imports/nativemedia/omxnode.h +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef OMXNODE_H -#define OMXNODE_H - -#include - -#include -#include - -#include "SurfaceTexture.h" - -#include "omxplayer.h" - -class QSGTexture; - -struct OmxTextureState { - OmxPlayer *player; -}; - -class OmxNode : public QSGGeometryNode -{ -public: - OmxNode(OmxPlayer *player); - ~OmxNode(); - - void preprocess(); - - void setRect(const QRectF &rect); - inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } - - bool isTextureUpdated() const { return m_textureUpdated; } - void setTextureUpdated(bool textureUpdated) { m_textureUpdated = textureUpdated; } - -private: - bool m_textureUpdated; - - QSGGeometry m_geometry; - QSGSimpleMaterial *m_textureMaterial; - - QRectF m_rect; - OmxPlayer *m_player; - bool m_initialized; -}; - -class OmxTextureMaterial : public QSGSimpleMaterialShader -{ - QSG_DECLARE_SIMPLE_SHADER(OmxTextureMaterial, OmxTextureState) -public: - QList attributes() const; - - void updateState(const OmxTextureState *newState, const OmxTextureState *oldState); - -protected: - const char *vertexShader() const; - const char *fragmentShader() const; -}; - -class OmxItem : public QQuickItem -{ - Q_OBJECT - Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged FINAL) - Q_PROPERTY(int sourceWidth READ sourceWidth NOTIFY sourceWidthChanged FINAL) - Q_PROPERTY(int sourceHeight READ sourceHeight NOTIFY sourceHeightChanged FINAL) - Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged FINAL) -public: - OmxItem(); - virtual ~OmxItem(); - - QString source() { - return m_source; - } - - int sourceWidth() { - return m_sourceWidth; - } - - int sourceHeight() { - return m_sourceHeight; - } - - bool paused() { return m_paused; } - void setPaused(bool p); - - void setSource(const QString &source); - -signals: - void sourceChanged(); - void sourceWidthChanged(); - void sourceHeightChanged(); - void pausedChanged(); - -protected: - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - void itemChange(ItemChange change, const ItemChangeData &); - -private slots: - void triggerRender(); - void videoSize(int w, int h); - void beforeRendering(); - -private: - OmxPlayer *m_player; - bool m_hasFrame; - bool m_initialized; - bool m_paused; - QString m_source; - int m_sourceWidth; - int m_sourceHeight; -}; - -#endif // OMXNODE_H - diff --git a/src/imports/nativemedia/omxplayer.h b/src/imports/nativemedia/omxplayer.h deleted file mode 100644 index 05bb224..0000000 --- a/src/imports/nativemedia/omxplayer.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef OMXPLAYER_H -#define OMXPLAYER_H - -#include - -class OmxPlayer : public QObject -{ - Q_OBJECT -public: - virtual ~OmxPlayer() = 0; - - virtual void updateTexture() = 0; - virtual bool initialize(const QByteArray &filename) = 0; - virtual bool hasFrame() = 0; - virtual void setPaused(bool paused) = 0; - - static OmxPlayer *create(); - -signals: - void frameAvailable(); - void videoSize(int w, int h); -}; - -#endif diff --git a/src/imports/nativemedia/qmldir b/src/imports/nativemedia/qmldir deleted file mode 100644 index 6c14ce6..0000000 --- a/src/imports/nativemedia/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module QtAndroidOmx -plugin android_omx diff --git a/src/imports/nativemedia/test.qml b/src/imports/nativemedia/test.qml deleted file mode 100644 index 01a1bfd..0000000 --- a/src/imports/nativemedia/test.qml +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -import QtQuick 2.0 -import QtAndroidOmx 1.0 - -Rectangle { - id: root - color: "white" - - Column { - width: parent.width - anchors.verticalCenter: parent.verticalCenter - - OmxItem { - id: omx - - width: root.width * 0.5 - height: width / aspect - - anchors.horizontalCenter: parent.horizontalCenter - anchors.margins: 40 - source: "NativeMedia.ts" - - property real aspect: sourceWidth / (sourceHeight > 0 ? sourceHeight : 1) - - MouseArea { - anchors.fill: parent - onClicked: parent.paused = !parent.paused - } - } - - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: "Video size: " + omx.sourceWidth + "x" + omx.sourceHeight - } - } -} diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro deleted file mode 100644 index cb74ee6..0000000 --- a/src/plugins/plugins.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += sensors - diff --git a/src/plugins/sensors/eandroid/eandroid.pro b/src/plugins/sensors/eandroid/eandroid.pro deleted file mode 100644 index 3b15f74..0000000 --- a/src/plugins/sensors/eandroid/eandroid.pro +++ /dev/null @@ -1,30 +0,0 @@ -TARGET = qtsensors_eandroid -QT = core sensors - -PLUGIN_TYPE = sensors -load(qt_plugin) - -LIBS += -lhardware - -HEADERS += \ - eandroidambientlightsensor.h \ - eandroidsensordevice.h \ - eandroidbasesensor.h \ - eandroidaccelerometer.h \ - eandroidlight.h \ - eandroidgyroscope.h \ - eandroidmagnetometer.h \ - eandroidrotationsensor.h - -SOURCES += \ - main.cpp \ - eandroidambientlightsensor.cpp \ - eandroidsensordevice.cpp \ - eandroidbasesensor.cpp \ - eandroidaccelerometer.cpp \ - eandroidlight.cpp \ - eandroidgyroscope.cpp \ - eandroidmagnetometer.cpp \ - eandroidrotationsensor.cpp - -OTHER_FILES = plugin.json diff --git a/src/plugins/sensors/eandroid/eandroidaccelerometer.cpp b/src/plugins/sensors/eandroid/eandroidaccelerometer.cpp deleted file mode 100644 index 0d4fa62..0000000 --- a/src/plugins/sensors/eandroid/eandroidaccelerometer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include - -EAndroidAccelerometer::EAndroidAccelerometer(int type, QSensor *sensor) - : EAndroidBaseSensor(type, sensor) -{ - setReading(&m_reading); -} - -EAndroidAccelerometer::~EAndroidAccelerometer() -{ -} - -void EAndroidAccelerometer::processEvent(sensors_event_t &event) -{ - m_reading.setTimestamp(event.timestamp / 1000); - m_reading.setX(event.data[0]); - m_reading.setY(event.data[1]); - m_reading.setZ(event.data[2]); - newReadingAvailable(); -} diff --git a/src/plugins/sensors/eandroid/eandroidaccelerometer.h b/src/plugins/sensors/eandroid/eandroidaccelerometer.h deleted file mode 100644 index 0062c2c..0000000 --- a/src/plugins/sensors/eandroid/eandroidaccelerometer.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDACCELEROMETER_H -#define EANDROIDACCELEROMETER_H - -#include - -#include - -class EAndroidAccelerometer : public EAndroidBaseSensor -{ - Q_OBJECT -public: - EAndroidAccelerometer(int type, QSensor *sensor); - ~EAndroidAccelerometer(); - void processEvent(sensors_event_t &event); - -private: - QAccelerometerReading m_reading; -}; - -#endif // EANDROIDACCELEROMETER_H diff --git a/src/plugins/sensors/eandroid/eandroidambientlightsensor.cpp b/src/plugins/sensors/eandroid/eandroidambientlightsensor.cpp deleted file mode 100644 index 10e4bc3..0000000 --- a/src/plugins/sensors/eandroid/eandroidambientlightsensor.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "eandroidambientlightsensor.h" - -EAndroidAmbientLightSensor::EAndroidAmbientLightSensor(int type, QSensor *sensor) - : EAndroidBaseSensor(type, sensor) -{ - setReading(&m_reading); -} - -EAndroidAmbientLightSensor::~EAndroidAmbientLightSensor() -{ -} - -void EAndroidAmbientLightSensor::processEvent(sensors_event_t &event) -{ - const int lightLevelLux = event.light; - - if (lightLevelLux < 10) - m_reading.setLightLevel(QAmbientLightReading::Dark); - else if (lightLevelLux < 80) - m_reading.setLightLevel(QAmbientLightReading::Twilight); - else if (lightLevelLux < 400) - m_reading.setLightLevel(QAmbientLightReading::Light); - else if (lightLevelLux < 2500) - m_reading.setLightLevel(QAmbientLightReading::Bright); - else - m_reading.setLightLevel(QAmbientLightReading::Sunny); - - newReadingAvailable(); -} diff --git a/src/plugins/sensors/eandroid/eandroidambientlightsensor.h b/src/plugins/sensors/eandroid/eandroidambientlightsensor.h deleted file mode 100644 index dba24ea..0000000 --- a/src/plugins/sensors/eandroid/eandroidambientlightsensor.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDAMBIENTLIGHTSENSOR_H -#define EANDROIDAMBIENTLIGHTSENSOR_H - -#include - -#include - -class EAndroidAmbientLightSensor : public EAndroidBaseSensor -{ - Q_OBJECT -public: - EAndroidAmbientLightSensor(int type, QSensor *sensor); - ~EAndroidAmbientLightSensor(); - void processEvent(sensors_event_t &event); - -private: - QAmbientLightReading m_reading; -}; - -#endif // EANDROIDAMBIENTLIGHTSENSOR_H diff --git a/src/plugins/sensors/eandroid/eandroidbasesensor.cpp b/src/plugins/sensors/eandroid/eandroidbasesensor.cpp deleted file mode 100644 index 49ec5e4..0000000 --- a/src/plugins/sensors/eandroid/eandroidbasesensor.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include -#include - -EAndroidBaseSensor::EAndroidBaseSensor(int sensorType, QSensor *sensor) - : QSensorBackend(sensor) -{ - m_type = sensorType; - m_isStarted = false; - EAndroidSensorDevice *device = EAndroidSensorDevice::instance(); - setDescription(device->description(sensorType)); -#if 0 // #### TODO - QTBUG-33293 - qint32 maxRate = device->maxDataRate(sensorType); // convert to Hz - addDataRate(1, 70); - addOutputRange(1,55,6); -#endif -} - -EAndroidBaseSensor::~EAndroidBaseSensor() -{ - if (m_isStarted) - stop(); -} - -void EAndroidBaseSensor::start() -{ - EAndroidSensorDevice::instance()->registerListener(m_type, this, sensor()->dataRate()); - m_isStarted = true; -} - -void EAndroidBaseSensor::stop() -{ - if (m_isStarted) { - m_isStarted = false; - EAndroidSensorDevice::instance()->unregisterListener(m_type, this); - } -} - -void EAndroidBaseSensor::processEvent(sensors_event_t &event) -{ - Q_UNUSED(event) -} diff --git a/src/plugins/sensors/eandroid/eandroidbasesensor.h b/src/plugins/sensors/eandroid/eandroidbasesensor.h deleted file mode 100644 index 16afebf..0000000 --- a/src/plugins/sensors/eandroid/eandroidbasesensor.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDBASESENSOR_H -#define EANDROIDBASESENSOR_H - -#include -#include - -class EAndroidBaseSensor : public QSensorBackend -{ - Q_OBJECT -public: - EAndroidBaseSensor(int sensorType, QSensor *sensor); - virtual ~EAndroidBaseSensor(); - virtual void start(); - virtual void stop(); - virtual void processEvent(sensors_event_t &event); - -private: - int m_type; - bool m_isStarted; -}; - -#endif // EANDROIDBASESENSOR_H diff --git a/src/plugins/sensors/eandroid/eandroidgyroscope.cpp b/src/plugins/sensors/eandroid/eandroidgyroscope.cpp deleted file mode 100644 index 783933f..0000000 --- a/src/plugins/sensors/eandroid/eandroidgyroscope.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "eandroidgyroscope.h" -#include - -EAndroidGyroscope::EAndroidGyroscope(int type, QSensor *sensor) - : EAndroidBaseSensor(type, sensor) -{ - setReading(&m_reading); -} - -EAndroidGyroscope::~EAndroidGyroscope() -{ -} - -void EAndroidGyroscope::processEvent(sensors_event_t &event) -{ - m_reading.setTimestamp(event.timestamp / 1000); - m_reading.setX(event.gyro.x *180/M_PI); - m_reading.setY(event.gyro.y *180/M_PI); - m_reading.setZ(event.gyro.z *180/M_PI); - newReadingAvailable(); -} - diff --git a/src/plugins/sensors/eandroid/eandroidgyroscope.h b/src/plugins/sensors/eandroid/eandroidgyroscope.h deleted file mode 100644 index 96a8005..0000000 --- a/src/plugins/sensors/eandroid/eandroidgyroscope.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDGYROSCOPE_H -#define EANDROIDGYROSCOPE_H - -#include - -#include - -class EAndroidGyroscope : public EAndroidBaseSensor -{ - Q_OBJECT -public: - EAndroidGyroscope(int type, QSensor *sensor); - ~EAndroidGyroscope(); - void processEvent(sensors_event_t &event); - -private: - QGyroscopeReading m_reading; -}; - -#endif // EANDROIDGYROSCOPE_H diff --git a/src/plugins/sensors/eandroid/eandroidlight.cpp b/src/plugins/sensors/eandroid/eandroidlight.cpp deleted file mode 100644 index a7e9243..0000000 --- a/src/plugins/sensors/eandroid/eandroidlight.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include - -EAndroidLight::EAndroidLight(int type, QSensor *sensor) - : EAndroidBaseSensor(type, sensor) -{ - setReading(&m_reading); -} - -EAndroidLight::~EAndroidLight() -{ -} - -void EAndroidLight::processEvent(sensors_event_t &event) -{ - m_reading.setTimestamp(event.timestamp / 1000); - m_reading.setLux(event.light); - newReadingAvailable(); -} diff --git a/src/plugins/sensors/eandroid/eandroidlight.h b/src/plugins/sensors/eandroid/eandroidlight.h deleted file mode 100644 index 75ce1ac..0000000 --- a/src/plugins/sensors/eandroid/eandroidlight.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDLIGHT_H -#define EANDROIDLIGHT_H - -#include - -#include - -class EAndroidLight : public EAndroidBaseSensor -{ - Q_OBJECT -public: - EAndroidLight(int type, QSensor *sensor); - ~EAndroidLight(); - void processEvent(sensors_event_t &ev); - -private: - QLightReading m_reading; -}; - -#endif // EANDROIDLIGHT_H diff --git a/src/plugins/sensors/eandroid/eandroidmagnetometer.cpp b/src/plugins/sensors/eandroid/eandroidmagnetometer.cpp deleted file mode 100644 index 73597b2..0000000 --- a/src/plugins/sensors/eandroid/eandroidmagnetometer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "eandroidmagnetometer.h" - -EAndroidMagnetometer::EAndroidMagnetometer(int type, QSensor *sensor) - : EAndroidBaseSensor(type, sensor) -{ - setReading(&m_reading); -} - -EAndroidMagnetometer::~EAndroidMagnetometer() -{ -} - -void EAndroidMagnetometer::processEvent(sensors_event_t &event) -{ - m_reading.setTimestamp(event.timestamp / 1000); - // convect micro-Tesla to tesla - m_reading.setX(event.magnetic.x / 1e6); - m_reading.setY(event.magnetic.y / 1e6); - m_reading.setZ(event.magnetic.z / 1e6); - - switch (event.magnetic.status) { - case SENSOR_STATUS_UNRELIABLE: - m_reading.setCalibrationLevel(0.0); - break; - case SENSOR_STATUS_ACCURACY_LOW: - m_reading.setCalibrationLevel(0.3); - break; - case SENSOR_STATUS_ACCURACY_MEDIUM: - m_reading.setCalibrationLevel(0.6); - break; - case SENSOR_STATUS_ACCURACY_HIGH: - m_reading.setCalibrationLevel(1.0); - break; - default: - break; - } - - newReadingAvailable(); -} diff --git a/src/plugins/sensors/eandroid/eandroidmagnetometer.h b/src/plugins/sensors/eandroid/eandroidmagnetometer.h deleted file mode 100644 index 92838b5..0000000 --- a/src/plugins/sensors/eandroid/eandroidmagnetometer.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDMAGNETOMETER_H -#define EANDROIDMAGNETOMETER_H - -#include - -#include - -class EAndroidMagnetometer : public EAndroidBaseSensor -{ - Q_OBJECT -public: - EAndroidMagnetometer(int type, QSensor *sensor); - ~EAndroidMagnetometer(); - void processEvent(sensors_event_t &event); - -private: - QMagnetometerReading m_reading; -}; - -#endif // EANDROIDMAGNETOMETER_H diff --git a/src/plugins/sensors/eandroid/eandroidrotationsensor.cpp b/src/plugins/sensors/eandroid/eandroidrotationsensor.cpp deleted file mode 100644 index ee0ab7a..0000000 --- a/src/plugins/sensors/eandroid/eandroidrotationsensor.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "eandroidrotationsensor.h" -#include - -EAndroidRotationSensor::EAndroidRotationSensor(int type, QSensor *sensor) - : EAndroidBaseSensor(type, sensor) -{ - setReading(&m_reading); -} - -EAndroidRotationSensor::~EAndroidRotationSensor() -{ -} - -void EAndroidRotationSensor::processEvent(sensors_event_t &event) -{ - m_reading.setTimestamp(event.timestamp / 1000); - - float rz = -event.data[0] * 180 / M_PI; - float rx = -event.data[1] * 180 / M_PI; - float ry = event.data[2] * 180 / M_PI; - - m_reading.setFromEuler(rx, ry, rz); - newReadingAvailable(); -} diff --git a/src/plugins/sensors/eandroid/eandroidrotationsensor.h b/src/plugins/sensors/eandroid/eandroidrotationsensor.h deleted file mode 100644 index 79ac239..0000000 --- a/src/plugins/sensors/eandroid/eandroidrotationsensor.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDROTATIONSENSOR_H -#define EANDROIDROTATIONSENSOR_H - -#include - -#include - -class EAndroidRotationSensor : public EAndroidBaseSensor -{ - Q_OBJECT -public: - EAndroidRotationSensor(int type, QSensor *sensor); - ~EAndroidRotationSensor(); - void processEvent(sensors_event_t &event); - -private: - QRotationReading m_reading; -}; - -#endif // EANDROIDROTATIONSENSOR_H diff --git a/src/plugins/sensors/eandroid/eandroidsensordevice.cpp b/src/plugins/sensors/eandroid/eandroidsensordevice.cpp deleted file mode 100644 index 9b9e03e..0000000 --- a/src/plugins/sensors/eandroid/eandroidsensordevice.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include - -EventReaderThread::EventReaderThread(EAndroidSensorDevice *device) : - m_device(device) -{ -} - -SensorEventArray* EventReaderThread::lock() -{ - m_mutex.lock(); - return &m_events; -} - -void EventReaderThread::run() -{ - static const size_t numEvents = 16; - sensors_event_t buffer[numEvents]; - int err = 0; - int n; - do { - n = m_device->m_sensorDevice->poll(m_device->m_sensorDevice, buffer, numEvents); - if (n < 0) { - qWarning("poll() failed (%s)\n", strerror(-err)); - break; - } - m_mutex.lock(); - for (int i = 0 ; i < n ; i++) { - sensors_event_t& event = buffer[i]; - if (event.version != sizeof(sensors_event_t)) { - qWarning("incorrect event version (version=%d, expected=%d", - event.version, sizeof(sensors_event_t)); - break; - } - m_events.append(event); - } - m_mutex.unlock(); - eventPending(); - } while (true); -} - -EAndroidSensorDevice::EAndroidSensorDevice() - : m_eventThread(0), - m_sensorModule(0), - m_sensorDevice(0), - m_availableSensorsList(0), - m_initSuccess(true) -{ - m_initSuccess = initSensorDevice(); - if (m_initSuccess) { - m_eventThread = new EventReaderThread(this); - connect(m_eventThread, SIGNAL(eventPending()), this, - SLOT(processSensorEvents()), Qt::QueuedConnection); - } else { - qWarning("Failed to initialize sensor module. Possibly a missing sensor driver?"); - } -} - -EAndroidSensorDevice* EAndroidSensorDevice::m_instance = 0; -EAndroidSensorDevice* EAndroidSensorDevice::instance() -{ - if (!m_instance) - m_instance = new EAndroidSensorDevice(); - return m_instance; -} - -void EAndroidSensorDevice::registerListener(int type, EAndroidBaseSensor *sensor, int dataRateHz) -{ - bool startReaderThread = m_listenersHash.isEmpty(); - bool enableSensor = m_listenersHash[type].isEmpty(); - m_listenersHash[type].push_back(sensor); - if (startReaderThread) - m_eventThread->start(); - if (enableSensor) { - setActive(type, true); - setDelay(type, dataRateHz); - } -} - -void EAndroidSensorDevice::unregisterListener(int type, EAndroidBaseSensor *sensor) -{ - m_listenersHash[type].removeOne(sensor); - bool disableSensor = m_listenersHash[type].isEmpty(); - if (disableSensor) - m_listenersHash.remove(type); - bool stopReaderThread = m_listenersHash.isEmpty(); - if (stopReaderThread) - m_eventThread->quit(); - if (disableSensor) - setActive(type, false); -} - -int EAndroidSensorDevice::indexForType(int type) const -{ - for (int i = 0; i < m_availableSensors; ++i) - if (m_availableSensorsList[i].type == type) - return i; - qWarning() << "invalid sensor type: " << type; - return -1; -} - -void EAndroidSensorDevice::setActive(int type, bool enable) -{ - for (int i = 0; i < m_availableSensors; i++) { - if (m_availableSensorsList[i].type == type) { - int err = m_sensorDevice->activate(m_sensorDevice, - m_availableSensorsList[i].handle, enable); - if (err != 0) - qWarning("activate() for '%s'failed (%s)\n", - m_availableSensorsList[i].name, strerror(-err)); - } - } -} - -void EAndroidSensorDevice::setDelay(int type, int dataRateHz) const -{ - qint64 ns; - // convert microseconds to nanoseconds - qint32 maxRateNs = maxDataRate(type) * 1000; - if (dataRateHz == 0) { - // if dataRateHz is not set, then we use maxRateNs - ns = maxRateNs; - } else { - // convert Hz to nanoseconds - ns = 1000000000LL / dataRateHz; - if (ns > maxRateNs) - ns = maxRateNs; - } - int index = indexForType(type); - if (index != -1) - m_sensorDevice->setDelay(m_sensorDevice, - m_availableSensorsList[index].handle, ns); - -} - -qint32 EAndroidSensorDevice::maxDataRate(int type) const -{ - // minDelay - minimum delay allowed between events in microseconds - int index = indexForType(type); - if (index != -1) - return m_availableSensorsList[index].minDelay; - return 0; -} - -QString EAndroidSensorDevice::description(int type) const -{ - int index = indexForType(type); - if (index != -1) { - QString desc; - desc.append(m_availableSensorsList[index].name); - desc.append(QString(" (Vendor:%1) ").arg(m_availableSensorsList[index].vendor)); - return desc; - } - return QString(); -} - -int EAndroidSensorDevice::availableSensors(sensor_t const** list) const -{ - if (m_initSuccess) - return m_sensorModule->get_sensors_list(m_sensorModule, list); - return 0; -} - -bool EAndroidSensorDevice::initSensorDevice() -{ - int err = 0; - err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, - (hw_module_t const**)&m_sensorModule); - if (err != 0 || !m_sensorModule) { - qWarning("hw_get_module() failed (%s)\n", strerror(-err)); - return false; - } - - err = sensors_open(&m_sensorModule->common, &m_sensorDevice); - if (err != 0 || !m_sensorDevice) { - qWarning("sensors_open() failed (%s)\n", strerror(-err)); - return false; - } - - m_availableSensors = m_sensorModule->get_sensors_list(m_sensorModule, - &m_availableSensorsList); - return true; -} - -void EAndroidSensorDevice::processSensorEvents() const -{ - SensorEventArray *eventqueue = m_eventThread->lock(); - for (int i = 0; i < eventqueue->size(); i++) { - sensors_event_t event = eventqueue->at(i); - foreach (EAndroidBaseSensor *sensorListener, m_listenersHash[event.type]) - sensorListener->processEvent(event); - } - eventqueue->clear(); - m_eventThread->unlock(); -} diff --git a/src/plugins/sensors/eandroid/eandroidsensordevice.h b/src/plugins/sensors/eandroid/eandroidsensordevice.h deleted file mode 100644 index db4e0f4..0000000 --- a/src/plugins/sensors/eandroid/eandroidsensordevice.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#ifndef EANDROIDSENSORDEVICE_H -#define EANDROIDSENSORDEVICE_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -typedef QVarLengthArray SensorEventArray; -typedef QHash > ListenersHash; - -class EAndroidSensorDevice; - -class EventReaderThread : public QThread -{ - Q_OBJECT -public: - EventReaderThread(EAndroidSensorDevice *manager); - void run(); - SensorEventArray* lock(); - inline void unlock() { m_mutex.unlock(); } - -signals: - void eventPending(); - -private: - EAndroidSensorDevice *m_device; - SensorEventArray m_events; - QMutex m_mutex; -}; - -class EAndroidSensorDevice : public QObject -{ - Q_OBJECT -public: - static EAndroidSensorDevice* instance(); - - void registerListener(int type, EAndroidBaseSensor *sensor, int dataRateHz); - void unregisterListener(int type, EAndroidBaseSensor *sensor); - int availableSensors(sensor_t const** list) const; - qint32 maxDataRate(int type) const; - QString description(int type) const; - -protected: - bool initSensorDevice(); - int indexForType(int type) const; - void setActive(int type, bool enable); - void setDelay(int type, int dataRateHz) const; - -public slots: - void processSensorEvents() const; - -private: - static EAndroidSensorDevice* m_instance; - EAndroidSensorDevice(); - EAndroidSensorDevice(const EAndroidSensorDevice &); - EAndroidSensorDevice& operator=(const EAndroidSensorDevice &); - - friend class EventReaderThread; - EventReaderThread *m_eventThread; - - sensors_module_t* m_sensorModule; - sensors_poll_device_t* m_sensorDevice; - sensor_t const* m_availableSensorsList; - int m_availableSensors; - bool m_initSuccess; - - ListenersHash m_listenersHash; -}; - -#endif // EANDROIDSENSORDEVICE_H diff --git a/src/plugins/sensors/eandroid/main.cpp b/src/plugins/sensors/eandroid/main.cpp deleted file mode 100644 index 8b62a18..0000000 --- a/src/plugins/sensors/eandroid/main.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtSensors module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://www.qt.io/licensing. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include - -#include - -class EAndroidSensorPlugin : public QObject, public QSensorPluginInterface, public QSensorBackendFactory -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "com.qt-project.Qt.QSensorPluginInterface/1.0" FILE "plugin.json") - Q_INTERFACES(QSensorPluginInterface) -public: - void registerSensors() - { -#define REGISTER_BACKEND(type, id) \ - QSensorManager::registerBackend(type, id, this); \ - - sensor_t const* sensors; - QByteArray id; - int count = EAndroidSensorDevice::instance()->availableSensors(&sensors); - for (int i = 0; i < count; i++) { - id = QByteArray::number(sensors[i].type); - switch (sensors[i].type) { - case SENSOR_TYPE_ACCELEROMETER: - REGISTER_BACKEND(QAccelerometer::type, id) - break; - case SENSOR_TYPE_MAGNETIC_FIELD: - REGISTER_BACKEND(QMagnetometer::type, id) - break; - case SENSOR_TYPE_ORIENTATION: - break; - case SENSOR_TYPE_GYROSCOPE: - REGISTER_BACKEND(QGyroscope::type, id) - break; - case SENSOR_TYPE_LIGHT: - REGISTER_BACKEND(QLightSensor::type, id); - REGISTER_BACKEND(QAmbientLightSensor::type, id); - break; - case SENSOR_TYPE_PRESSURE: - break; - case SENSOR_TYPE_TEMPERATURE: - break; - case SENSOR_TYPE_PROXIMITY: - break; - case SENSOR_TYPE_GRAVITY: - break; - case SENSOR_TYPE_LINEAR_ACCELERATION: - break; - case SENSOR_TYPE_ROTATION_VECTOR: - REGISTER_BACKEND(QRotationSensor::type, id); - break; - case SENSOR_TYPE_RELATIVE_HUMIDITY: - break; - case SENSOR_TYPE_AMBIENT_TEMPERATURE: - break; - } - } -#undef REGISTER_BACKEND - } - - QSensorBackend *createBackend(QSensor *sensor) - { - int sensorType = sensor->identifier().toInt(); - switch (sensorType) { - case SENSOR_TYPE_ACCELEROMETER: - return new EAndroidAccelerometer(sensorType, sensor); - case SENSOR_TYPE_MAGNETIC_FIELD: - return new EAndroidMagnetometer(sensorType, sensor); - case SENSOR_TYPE_ORIENTATION: - break; - case SENSOR_TYPE_GYROSCOPE: - return new EAndroidGyroscope(sensorType, sensor); - case SENSOR_TYPE_LIGHT: - if (sensor->type() == QAmbientLightSensor::type) - return new EAndroidAmbientLightSensor(sensorType, sensor); - else if (sensor->type() == QLightSensor::type) - return new EAndroidLight(sensorType, sensor); - case SENSOR_TYPE_PRESSURE: - break; - case SENSOR_TYPE_TEMPERATURE: - break; - case SENSOR_TYPE_PROXIMITY: - break; - case SENSOR_TYPE_GRAVITY: - break; - case SENSOR_TYPE_LINEAR_ACCELERATION: - break; - case SENSOR_TYPE_ROTATION_VECTOR: - return new EAndroidRotationSensor(sensorType, sensor); - case SENSOR_TYPE_RELATIVE_HUMIDITY: - break; - case SENSOR_TYPE_AMBIENT_TEMPERATURE: - break; - default: - break; - } - return 0; - } -}; - -#include "main.moc" diff --git a/src/plugins/sensors/eandroid/plugin.json b/src/plugins/sensors/eandroid/plugin.json deleted file mode 100644 index 8a55b3a..0000000 --- a/src/plugins/sensors/eandroid/plugin.json +++ /dev/null @@ -1 +0,0 @@ -{ "Keys": [ "notused" ] } diff --git a/src/plugins/sensors/sensors.pro b/src/plugins/sensors/sensors.pro deleted file mode 100644 index d02cc99..0000000 --- a/src/plugins/sensors/sensors.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -android: SUBDIRS += eandroid - diff --git a/src/qconnectivity/main.cpp b/src/qconnectivity/main.cpp deleted file mode 100644 index d25c42e..0000000 --- a/src/qconnectivity/main.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include -#include -#include - -#include -#include -#include -#include -#include - -Q_LOGGING_CATEGORY(B2QT_QCONNECTIVITY, "qt.b2qt.qconnectivity") - -// Code values come from android/system/netd/ResponseCode.h -const int InterfaceChange = 600; -const char UNIQUE_HOSTNAME[] = "net.hostname"; -// sanity check a renewal time, lower value than -// this might indicate a badly configured DHCP server -const int MIN_RENEWAL_TIME_SECS = 300; // 5 min - -#define ETH_INTERFACE_HW "eth0" -#define ETH_INTERFACE_EMULATOR "eth1" - -#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 3 -// this function is defined in android/system/core/libnetutils/dhcp_utils.c -extern "C" { -int dhcp_do_request_renew(const char *ifname, - char *ipaddr, - char *gateway, - uint32_t *prefixLength, - char *dns1, - char *dns2, - char *server, - uint32_t *lease, - char *vendorInfo); -} -#endif - -static int q_dhcp_do_request(bool renew, - const char *ifname, - char *ipaddr, - char *gateway, - uint32_t *prefixLength, - char *dns1, - char *dns2, - char *server, - uint32_t *lease, - char *vendorInfo, - char *domain) -{ -#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 3 - if (!renew) - return dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns1, dns2, server, lease, vendorInfo); - return dhcp_do_request_renew(ifname, ipaddr, gateway, prefixLength, dns1, dns2, server, lease, vendorInfo); -#else - char *dns[3] = {dns1, dns2, 0}; - char mtu[PROPERTY_VALUE_MAX]; -#if Q_ANDROID_VERSION_MAJOR == 4 && Q_ANDROID_VERSION_MINOR < 4 - if (!renew) - return dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo); - return dhcp_do_request_renew(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo); -#else - if (!renew) - return dhcp_do_request(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo, domain, mtu); - return dhcp_do_request_renew(ifname, ipaddr, gateway, prefixLength, dns, server, lease, vendorInfo, domain, mtu); -#endif -#endif -} - - -class LeaseTimer; -class QConnectivityDaemon : public QObject -{ - Q_OBJECT -public: - QConnectivityDaemon(); - -protected: - void setHostnamePropery(const char *interface) const; - void sendCommand(const char *command) const; - void handleInterfaceChange(const QList &message); - bool startDhcp(bool renew, const char *interface); - void stopDhcp(const char *interface); - bool ethernetSupported() const; - bool isEmulator() const; - -protected slots: - void initNetdConnection(); - void handleNetdEvent(); - void handleRequest(); - void handleNewConnection(); - void sendReply(QLocalSocket *requester, const QByteArray &reply) const; - void updateLease(); - void handleError(QLocalSocket::LocalSocketError /*socketError*/) const; - -private: - friend class LeaseTimer; - QLocalSocket *m_netdSocket; - // currently used to listen for requests from Qt Wifi library, - // in future can be used also for Bluetooth and etc. - QLocalServer *m_serverSocket; - bool m_linkUp; - LeaseTimer *m_leaseTimer; - bool m_isEmulator; - QByteArray m_ethInterface; - // android initializes services in a separate threads, therefore it is - // not guaranteed that the netd socket will be ready at the time when qconnectivity - // is starting up - we try to reconnect again after 2 second intervals. This - // variable holds the maximum attempt count (chosen arbitrarily). - int m_attemptCount; -}; - -class LeaseTimer : public QTimer -{ - Q_OBJECT -public: - LeaseTimer(QConnectivityDaemon *daemon) : m_daemon(daemon) {} - - void setInterface(const QByteArray &interface) - { - if (m_ifc.isEmpty()) { - m_ifc = interface; - } else { - // for example when user switches from eth0 to wlan0, we - // stop DHCP on the previous interface - if (m_ifc != interface) { - m_daemon->stopDhcp(m_ifc.constData()); - m_ifc = interface; - } - } - } - - QByteArray interface() const { return m_ifc; } - -private: - QConnectivityDaemon *m_daemon; - QByteArray m_ifc; -}; - -QConnectivityDaemon::QConnectivityDaemon() - : m_netdSocket(0), - m_serverSocket(0), - m_linkUp(false), - m_leaseTimer(0), - m_isEmulator(isEmulator()), - m_attemptCount(50) -{ - QLoggingCategory::setFilterRules(QStringLiteral("qt.b2qt.qconnectivity=true")); - qCDebug(B2QT_QCONNECTIVITY) << "starting QConnectivityDaemon..."; - - if (!m_isEmulator) { - m_ethInterface = ETH_INTERFACE_HW; - m_leaseTimer = new LeaseTimer(this); - m_leaseTimer->setSingleShot(true); - connect(m_leaseTimer, SIGNAL(timeout()), this, SLOT(updateLease())); - - int serverFd = socket_local_server("qconnectivity", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); - if (serverFd != -1) { - m_serverSocket = new QLocalServer(this); - if (m_serverSocket->listen(serverFd)) - connect(m_serverSocket, SIGNAL(newConnection()), this, SLOT(handleNewConnection())); - else - qCWarning(B2QT_QCONNECTIVITY) << "not able to listen on the server socket..."; - } else { - qCWarning(B2QT_QCONNECTIVITY) << "failed to open qconnectivity server socket"; - } - } else { - m_ethInterface = ETH_INTERFACE_EMULATOR; - } - initNetdConnection(); -} - -bool QConnectivityDaemon::isEmulator() const -{ - bool isEmulator = false; - QFile conf("/system/bin/appcontroller.conf"); - if (conf.open(QIODevice::ReadOnly)) { - QByteArray content = conf.readAll(); - isEmulator = content.contains("platform=emulator"); - conf.close(); - } else { - qCWarning(B2QT_QCONNECTIVITY) << "Failed to read appcontroller.conf"; - } - return isEmulator; -} - -void QConnectivityDaemon::initNetdConnection() -{ - int netdFd = socket_local_client("netd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); - if (netdFd != -1) { - qCDebug(B2QT_QCONNECTIVITY) << "connected to netd socket"; - m_netdSocket = new QLocalSocket(this); - m_netdSocket->setSocketDescriptor(netdFd); - connect(m_netdSocket, SIGNAL(readyRead()), this, SLOT(handleNetdEvent())); - connect(m_netdSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), - this, SLOT(handleError(QLocalSocket::LocalSocketError))); - } else { - if (--m_attemptCount != 0) - QTimer::singleShot(200, this, SLOT(initNetdConnection())); - else - qCWarning(B2QT_QCONNECTIVITY) << "failed to connect to netd socket!"; - return; - } - if (ethernetSupported()) { - // down-up sequence generates "linkstate" events, which we can use to setup - // our daemon on initial startup (device boot) or on daemon restarts - sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" down").constData()); - sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" up").constData()); - } - // disable firewall - this setting seems to be enabled only when using "Always-on VPN" - // mode on Android phones, see setLockdownTracker() in ConnectivityService.java - sendCommand("0 firewall disable"); -} - -void QConnectivityDaemon::setHostnamePropery(const char *interface) const -{ - // Setup our unique device name (used as a host name argument for dhcpcd call in - // dhcp_do_request). On Android device name is set in ConnectivityService.java and - // the id is generated with the help of SecureRandom.java class. We will use Mac - // address as a unique hostname. - char prop_value[PROPERTY_VALUE_MAX]; - property_get(UNIQUE_HOSTNAME, prop_value, NULL); - if ((prop_value[0] == '\0')) { - char hwaddr[6]; - memset(hwaddr, 0, sizeof(hwaddr)); - ifc_init(); - if (ifc_get_hwaddr(interface, (void *)hwaddr) == 0) { - QByteArray macAddress(hwaddr, sizeof(hwaddr)); - property_set(UNIQUE_HOSTNAME, macAddress.toHex().prepend("b2qt-").constData()); - } else { - qCWarning(B2QT_QCONNECTIVITY) << "failed to get MAC address"; - } - ifc_close(); - } -} - -void QConnectivityDaemon::sendCommand(const char *command) const -{ - if (!m_netdSocket) { - qCDebug(B2QT_QCONNECTIVITY) << "netd socket is not ready!"; - return; - } - qCDebug(B2QT_QCONNECTIVITY) << "sending command - " << command; - // netd expects "\0" terminated commands... - m_netdSocket->write(command, qstrlen(command) + 1); - m_netdSocket->flush(); -} - -void QConnectivityDaemon::handleInterfaceChange(const QList &message) -{ - // Format: "Code Iface linkstate " - if (message.size() < 5) - return; - - if (message.at(2) == "linkstate" && message.at(3) == m_ethInterface) { - if (message.at(4) == "up") { - // ethernet cable has been plugged in - if (!m_linkUp) { - m_linkUp = true; - startDhcp(false, m_ethInterface); - } - } else { - // .. plugged out - if (m_linkUp) { - m_linkUp = false; - stopDhcp(m_ethInterface); - } - } - } -} - -bool QConnectivityDaemon::startDhcp(bool renew, const char *interface) -{ - qCDebug(B2QT_QCONNECTIVITY) << "startDhcp [ renew" << renew << "] " - << "interface: " << interface; - setHostnamePropery(interface); - - int result = 0; - char ipaddr[PROPERTY_VALUE_MAX]; - quint32 prefixLength = 0; - char gateway[PROPERTY_VALUE_MAX]; - char dns1[PROPERTY_VALUE_MAX]; - char dns2[PROPERTY_VALUE_MAX]; - char server[PROPERTY_VALUE_MAX]; - quint32 lease = 0; - char vendorInfo[PROPERTY_VALUE_MAX]; - char domain[PROPERTY_VALUE_MAX] = {0}; - - if (renew) { - result = q_dhcp_do_request(true, interface, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease, vendorInfo, domain); - } else { - // stop any existing DHCP daemon before starting new - dhcp_stop(interface); - // this uses "ctl.start.*" mechanism to start "dhcpcd" daemon as defined by - // the device init.rc. Android starts dhcpcd with argument -B which means that - // we are responsible for renewing a lease before it expires - ifc_clear_addresses(interface); - result = q_dhcp_do_request(false, interface, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease, vendorInfo, domain); - } - - bool success = (result == 0) ? true : false; - if (success) { - qCDebug(B2QT_QCONNECTIVITY) << "\nipaddr: " << ipaddr << "\nprefixLength: " << prefixLength - << "\ngateway: " << gateway << "\ndns1: " << dns1 << "\ndns2: " << dns2; - - if (!renew) { - in_addr _ipaddr, _gateway, _dns1, _dns2; - inet_aton(ipaddr, &_ipaddr); - inet_aton(gateway, &_gateway); - inet_aton(dns1, &_dns1); - inet_aton(dns2, &_dns2); - - ifc_configure(interface, _ipaddr.s_addr, prefixLength, - _gateway.s_addr, _dns1.s_addr, _dns2.s_addr); - - // set DNS servers and domain for interface - see NetworkManagementService.java - QByteArray dnsForInterface("0 resolver setifdns "); - dnsForInterface.append(interface).append(" "); - if (domain[0]) - dnsForInterface.append(domain); - else - dnsForInterface.append(" "); - dnsForInterface.append(" "); - dnsForInterface.append(dns1).append(" ").append(dns2); - sendCommand(dnsForInterface.constData()); - - // set default interface for DNS - see NetworkManagementService.java - sendCommand(QByteArray("0 resolver setdefaultif ").append(interface).constData()); - - property_set("net.dns1", dns1); - property_set("net.dns2", dns2); - } - - if (!m_isEmulator && lease >= 0) { - if (lease < MIN_RENEWAL_TIME_SECS) { - qCWarning(B2QT_QCONNECTIVITY) << "DHCP server proposes lease time " << lease - << "seconds. We will use" << MIN_RENEWAL_TIME_SECS << " seconds instead."; - lease = MIN_RENEWAL_TIME_SECS; - } - // update lease when 48% of lease time has elapsed - if (m_leaseTimer->isActive()) - m_leaseTimer->stop(); - m_leaseTimer->setInterface(interface); - m_leaseTimer->start(lease * 480); - } - } else { - qCWarning(B2QT_QCONNECTIVITY, "DHCP request failed - %s", dhcp_get_errmsg()); - if (renew) { - // If it fails to renew a lease (faulty server, proxy?) we re-connect. - // Some users might prefer to use expired lease over having interrupt - // in network connection - if (qEnvironmentVariableIsSet("QT_USE_EXPIRED_LEASE")) - return true; - qCDebug(B2QT_QCONNECTIVITY) << "attempting to re-connect..."; - stopDhcp(interface); - startDhcp(false, interface); - } - } - return success; -} - -void QConnectivityDaemon::stopDhcp(const char *interface) -{ - qCDebug(B2QT_QCONNECTIVITY) << "stopDhcp: " << interface; - ifc_clear_addresses(interface); - dhcp_stop(interface); - if (!m_isEmulator && m_leaseTimer->isActive()) - m_leaseTimer->stop(); -} - -bool QConnectivityDaemon::ethernetSupported() const -{ - // standard linux kernel path - return QDir().exists(QString("/sys/class/net/").append(m_ethInterface)); -} - -void QConnectivityDaemon::handleNetdEvent() -{ - QByteArray data = m_netdSocket->readAll(); - qCDebug(B2QT_QCONNECTIVITY) << "netd event: " << data; - if (data.endsWith('\0')) - data.chop(1); - - QList message = data.split(' '); - int code = message.at(0).toInt(); - switch (code) { - case InterfaceChange: - handleInterfaceChange(message); - break; - default: - break; - } -} - -void QConnectivityDaemon::handleRequest() -{ - // Format: "interface " - QLocalSocket *requester = qobject_cast(QObject::sender()); - if (requester->canReadLine()) { - QByteArray request = requester->readLine(requester->bytesAvailable()); - - qCDebug(B2QT_QCONNECTIVITY) << "received a request: " << request; - QList cmd = request.split(' '); - if (cmd.size() < 2) - return; - - QByteArray interface = cmd.at(0); - if (cmd.at(1) == "connect") { - QByteArray reply; - if (startDhcp(false, interface.constData())) - reply = "success"; - else - reply = "failed"; - sendReply(requester, reply); - } else { - stopDhcp(interface.constData()); - } - } -} - -void QConnectivityDaemon::handleNewConnection() -{ - QLocalSocket *requester = m_serverSocket->nextPendingConnection(); - connect(requester, SIGNAL(readyRead()), this, SLOT(handleRequest())); - connect(requester, SIGNAL(disconnected()), requester, SLOT(deleteLater())); -} - -void QConnectivityDaemon::sendReply(QLocalSocket *requester, const QByteArray &reply) const -{ - QByteArray r = reply; - r.append("\n"); - requester->write(r.constData(), r.length()); - requester->flush(); - requester->disconnectFromServer(); -} - -void QConnectivityDaemon::updateLease() -{ - qCDebug(B2QT_QCONNECTIVITY) << "updating lease"; - startDhcp(true, m_leaseTimer->interface().constData()); -} - -void QConnectivityDaemon::handleError(QLocalSocket::LocalSocketError /*socketError*/) const -{ - qCWarning(B2QT_QCONNECTIVITY) << "QLocalSocket::LocalSocketError"; -} - -int main(int argc, char *argv[]) -{ - QCoreApplication a(argc, argv); - - QConnectivityDaemon connectivityDaemon; - - return a.exec(); -} - -#include "main.moc" diff --git a/src/qconnectivity/qconnectivity.pro b/src/qconnectivity/qconnectivity.pro deleted file mode 100644 index df3b366..0000000 --- a/src/qconnectivity/qconnectivity.pro +++ /dev/null @@ -1,13 +0,0 @@ -QT += core network -QT -= gui - -TARGET = qconnectivity -CONFIG += console -CONFIG -= app_bundle - -TEMPLATE = app - -LIBS += -lcutils -lnetutils -SOURCES += main.cpp - -load(qt_tool) diff --git a/src/qt_hw_init/main.cpp b/src/qt_hw_init/main.cpp deleted file mode 100644 index 15cc807..0000000 --- a/src/qt_hw_init/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc -** All rights reserved. -** For any questions to Digia, please use the contact form at -** http://www.qt.io -** -** This file is part of Qt Enterprise Embedded. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. -** -** If you have questions regarding the use of this file, please use -** the contact form at http://www.qt.io -** -****************************************************************************/ -#include "b2qtdevice.h" - -int main(int, char *[]) -{ - B2QtDevice device; - - device.initAudio(); - - device.setDisplayBrightness(255); - - return 0; -} diff --git a/src/qt_hw_init/qt_hw_init.pro b/src/qt_hw_init/qt_hw_init.pro deleted file mode 100644 index 4784926..0000000 --- a/src/qt_hw_init/qt_hw_init.pro +++ /dev/null @@ -1,8 +0,0 @@ -TEMPLATE = app -TARGET = qt_hw_init -QT -= gui -QT += b2qtutils - -SOURCES += main.cpp - -load(qt_tool) diff --git a/src/src.pro b/src/src.pro index a0e42dd..7ddc9ca 100644 --- a/src/src.pro +++ b/src/src.pro @@ -5,8 +5,4 @@ SUBDIRS += \ wifi \ imports \ doc \ - plugins \ b2qt-update-util - - -android: SUBDIRS += doppelganger qt_hw_init qconnectivity -- cgit v1.2.3