diff --git a/Makefile b/Makefile index 8f41cbbf..63dd8681 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ prebuilt: \ prebuilt/armeabi-v7a/lib/android-26/minicap.so \ prebuilt/armeabi-v7a/lib/android-27/minicap.so \ prebuilt/armeabi-v7a/lib/android-28/minicap.so \ + prebuilt/armeabi-v7a/lib/android-29/minicap.so \ prebuilt/arm64-v8a/bin/minicap \ prebuilt/arm64-v8a/bin/minicap-nopie \ prebuilt/arm64-v8a/lib/android-21/minicap.so \ @@ -51,6 +52,7 @@ prebuilt: \ prebuilt/arm64-v8a/lib/android-26/minicap.so \ prebuilt/arm64-v8a/lib/android-27/minicap.so \ prebuilt/arm64-v8a/lib/android-28/minicap.so \ + prebuilt/arm64-v8a/lib/android-29/minicap.so \ prebuilt/x86/bin/minicap \ prebuilt/x86/bin/minicap-nopie \ prebuilt/x86/lib/android-14/minicap.so \ @@ -67,6 +69,7 @@ prebuilt: \ prebuilt/x86/lib/android-26/minicap.so \ prebuilt/x86/lib/android-27/minicap.so \ prebuilt/x86/lib/android-28/minicap.so \ + prebuilt/x86/lib/android-29/minicap.so \ prebuilt/x86_64/bin/minicap \ prebuilt/x86_64/bin/minicap-nopie \ prebuilt/x86_64/lib/android-21/minicap.so \ @@ -77,6 +80,7 @@ prebuilt: \ prebuilt/x86_64/lib/android-26/minicap.so \ prebuilt/x86_64/lib/android-27/minicap.so \ prebuilt/x86_64/lib/android-28/minicap.so \ + prebuilt/x86_64/lib/android-29/minicap.so \ prebuilt/%/bin/minicap: libs/%/minicap mkdir -p $(@D) diff --git a/jni/minicap-shared/aosp/Android.mk b/jni/minicap-shared/aosp/Android.mk index 9be0f59f..40a4981b 100644 --- a/jni/minicap-shared/aosp/Android.mk +++ b/jni/minicap-shared/aosp/Android.mk @@ -7,6 +7,8 @@ LOCAL_MODULE_TAGS := optional ifneq ($(OVERRIDE_PLATFORM_SDK_VERSION),) LOCAL_SRC_FILES += src/minicap_$(OVERRIDE_PLATFORM_SDK_VERSION).cpp +else ifeq ($(PLATFORM_SDK_VERSION),29) +LOCAL_SRC_FILES += src/minicap_29.cpp else ifeq ($(PLATFORM_SDK_VERSION),28) LOCAL_SRC_FILES += src/minicap_28.cpp else ifeq ($(PLATFORM_SDK_VERSION),27) diff --git a/jni/minicap-shared/aosp/Makefile b/jni/minicap-shared/aosp/Makefile index dc6b8e27..0dd853dc 100644 --- a/jni/minicap-shared/aosp/Makefile +++ b/jni/minicap-shared/aosp/Makefile @@ -48,6 +48,7 @@ all: \ libs/android-28/arm64-v8a/minicap.so \ libs/android-28/x86/minicap.so \ libs/android-28/x86_64/minicap.so \ + libs/android-29/arm64-v8a/minicap.so \ libs/android-9/armeabi-v7a/minicap.so: $(SOURCES) src/minicap_9.cpp mkdir -p $(@D) @@ -606,3 +607,12 @@ libs/android-28/mips64/minicap.so: $(SOURCES) src/minicap_28.cpp -v $(this_dir):/app \ -v $(this_dir)$(@D):/artifacts \ openstf/aosp:jdk8 /aosp.sh build aosp_mips64-eng minicap + +libs/android-29/arm64-v8a/minicap.so: $(SOURCES) src/minicap_29.cpp + mkdir -p $(@D) + docker run --rm \ + -a stdout -a stderr \ + -v /media/aosp/android-10.0.0_r2:/aosp \ + -v $(this_dir):/app \ + -v $(this_dir)$(@D):/artifacts \ + openstf/aosp:jdk8 /aosp.sh build aosp_arm64-eng minicap diff --git a/jni/minicap-shared/aosp/libs/android-29/arm64-v8a/minicap.so b/jni/minicap-shared/aosp/libs/android-29/arm64-v8a/minicap.so new file mode 100755 index 00000000..f242d0a9 Binary files /dev/null and b/jni/minicap-shared/aosp/libs/android-29/arm64-v8a/minicap.so differ diff --git a/jni/minicap-shared/aosp/libs/android-29/armeabi-v7a/minicap.so b/jni/minicap-shared/aosp/libs/android-29/armeabi-v7a/minicap.so new file mode 100755 index 00000000..38728b22 Binary files /dev/null and b/jni/minicap-shared/aosp/libs/android-29/armeabi-v7a/minicap.so differ diff --git a/jni/minicap-shared/aosp/libs/android-29/x86/minicap.so b/jni/minicap-shared/aosp/libs/android-29/x86/minicap.so new file mode 100755 index 00000000..f7f83828 Binary files /dev/null and b/jni/minicap-shared/aosp/libs/android-29/x86/minicap.so differ diff --git a/jni/minicap-shared/aosp/libs/android-29/x86_64/minicap.so b/jni/minicap-shared/aosp/libs/android-29/x86_64/minicap.so new file mode 100755 index 00000000..e34a95cb Binary files /dev/null and b/jni/minicap-shared/aosp/libs/android-29/x86_64/minicap.so differ diff --git a/jni/minicap-shared/aosp/src/minicap_29.cpp b/jni/minicap-shared/aosp/src/minicap_29.cpp new file mode 100644 index 00000000..01e39089 --- /dev/null +++ b/jni/minicap-shared/aosp/src/minicap_29.cpp @@ -0,0 +1,390 @@ +#include "Minicap.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "mcdebug.h" + +static const char* +error_name(int32_t err) { + switch (err) { + case android::NO_ERROR: // also android::OK + return "NO_ERROR"; + case android::UNKNOWN_ERROR: + return "UNKNOWN_ERROR"; + case android::NO_MEMORY: + return "NO_MEMORY"; + case android::INVALID_OPERATION: + return "INVALID_OPERATION"; + case android::BAD_VALUE: + return "BAD_VALUE"; + case android::BAD_TYPE: + return "BAD_TYPE"; + case android::NAME_NOT_FOUND: + return "NAME_NOT_FOUND"; + case android::PERMISSION_DENIED: + return "PERMISSION_DENIED"; + case android::NO_INIT: + return "NO_INIT"; + case android::ALREADY_EXISTS: + return "ALREADY_EXISTS"; + case android::DEAD_OBJECT: // also android::JPARKS_BROKE_IT + return "DEAD_OBJECT"; + case android::FAILED_TRANSACTION: + return "FAILED_TRANSACTION"; + case android::BAD_INDEX: + return "BAD_INDEX"; + case android::NOT_ENOUGH_DATA: + return "NOT_ENOUGH_DATA"; + case android::WOULD_BLOCK: + return "WOULD_BLOCK"; + case android::TIMED_OUT: + return "TIMED_OUT"; + case android::UNKNOWN_TRANSACTION: + return "UNKNOWN_TRANSACTION"; + case android::FDS_NOT_ALLOWED: + return "FDS_NOT_ALLOWED"; + default: + return "UNMAPPED_ERROR"; + } +} + +class FrameProxy: public android::ConsumerBase::FrameAvailableListener { +public: + FrameProxy(Minicap::FrameAvailableListener* listener): mUserListener(listener) { + } + + virtual void + onFrameAvailable(const android::BufferItem& /* item */) { + mUserListener->onFrameAvailable(); + } + +private: + Minicap::FrameAvailableListener* mUserListener; +}; + +class MinicapImpl: public Minicap +{ +public: + MinicapImpl(int32_t displayId) + : mDisplayId(displayId), + mRealWidth(0), + mRealHeight(0), + mDesiredWidth(0), + mDesiredHeight(0), + mDesiredOrientation(0), + mHaveBuffer(false), + mHaveRunningDisplay(false) { + } + + virtual + ~MinicapImpl() { + release(); + } + + virtual int + applyConfigChanges() { + if (mHaveRunningDisplay) { + destroyVirtualDisplay(); + } + + return createVirtualDisplay(); + } + + virtual int + consumePendingFrame(Minicap::Frame* frame) { + android::status_t err; + + if ((err = mConsumer->lockNextBuffer(&mBuffer)) != android::NO_ERROR) { + if (err == -EINTR) { + return err; + } + else { + MCERROR("Unable to lock next buffer %s (%d)", error_name(err), err); + return err; + } + } + + frame->data = mBuffer.data; + frame->format = convertFormat(mBuffer.format); + frame->width = mBuffer.width; + frame->height = mBuffer.height; + frame->stride = mBuffer.stride; + frame->bpp = android::bytesPerPixel(mBuffer.format); + frame->size = mBuffer.stride * mBuffer.height * frame->bpp; + + mHaveBuffer = true; + + return 0; + } + + virtual Minicap::CaptureMethod + getCaptureMethod() { + return METHOD_VIRTUAL_DISPLAY; + } + + virtual int32_t + getDisplayId() { + return mDisplayId; + } + + virtual void + release() { + destroyVirtualDisplay(); + } + + virtual void + releaseConsumedFrame(Minicap::Frame* /* frame */) { + if (mHaveBuffer) { + mConsumer->unlockBuffer(mBuffer); + mHaveBuffer = false; + } + } + + virtual int + setDesiredInfo(const Minicap::DisplayInfo& info) { + mDesiredWidth = info.width; + mDesiredHeight = info.height; + mDesiredOrientation = info.orientation; + return 0; + } + + virtual void + setFrameAvailableListener(Minicap::FrameAvailableListener* listener) { + mUserFrameAvailableListener = listener; + } + + virtual int + setRealInfo(const Minicap::DisplayInfo& info) { + mRealWidth = info.width; + mRealHeight = info.height; + return 0; + } + +private: + int32_t mDisplayId; + uint32_t mRealWidth; + uint32_t mRealHeight; + uint32_t mDesiredWidth; + uint32_t mDesiredHeight; + uint8_t mDesiredOrientation; + android::sp mBufferProducer; + android::sp mBufferConsumer; + android::sp mConsumer; + android::sp mVirtualDisplay; + android::sp mFrameProxy; + Minicap::FrameAvailableListener* mUserFrameAvailableListener; + bool mHaveBuffer; + bool mHaveRunningDisplay; + android::CpuConsumer::LockedBuffer mBuffer; + + int + createVirtualDisplay() { + uint32_t sourceWidth, sourceHeight; + uint32_t targetWidth, targetHeight; + android::status_t err; + + switch (mDesiredOrientation) { + case Minicap::ORIENTATION_90: + sourceWidth = mRealHeight; + sourceHeight = mRealWidth; + targetWidth = mDesiredHeight; + targetHeight = mDesiredWidth; + break; + case Minicap::ORIENTATION_270: + sourceWidth = mRealHeight; + sourceHeight = mRealWidth; + targetWidth = mDesiredHeight; + targetHeight = mDesiredWidth; + break; + case Minicap::ORIENTATION_180: + sourceWidth = mRealWidth; + sourceHeight = mRealHeight; + targetWidth = mDesiredWidth; + targetHeight = mDesiredHeight; + break; + case Minicap::ORIENTATION_0: + default: + sourceWidth = mRealWidth; + sourceHeight = mRealHeight; + targetWidth = mDesiredWidth; + targetHeight = mDesiredHeight; + break; + } + + // Set up virtual display size. + android::Rect layerStackRect(sourceWidth, sourceHeight); + android::Rect visibleRect(targetWidth, targetHeight); + + // Create a Surface for the virtual display to write to. + MCINFO("Creating SurfaceComposerClient"); + android::sp sc = new android::SurfaceComposerClient(); + + MCINFO("Performing SurfaceComposerClient init check"); + if ((err = sc->initCheck()) != android::NO_ERROR) { + MCERROR("Unable to initialize SurfaceComposerClient"); + return err; + } + + // This is now REQUIRED in O Developer Preview 1 or there's a segfault + // when the sp goes out of scope. + sc = NULL; + + // Create virtual display. + MCINFO("Creating virtual display"); + mVirtualDisplay = android::SurfaceComposerClient::createDisplay( + /* const String8& displayName */ android::String8("minicap"), + /* bool secure */ true + ); + + MCINFO("Creating buffer queue"); + android::BufferQueue::createBufferQueue(&mBufferProducer, &mBufferConsumer, false); + + MCINFO("Setting buffer options"); + mBufferConsumer->setDefaultBufferSize(targetWidth, targetHeight); + mBufferConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888); + + MCINFO("Creating CPU consumer"); + mConsumer = new android::CpuConsumer(mBufferConsumer, 3, false); + mConsumer->setName(android::String8("minicap")); + + MCINFO("Creating frame waiter"); + mFrameProxy = new FrameProxy(mUserFrameAvailableListener); + mConsumer->setFrameAvailableListener(mFrameProxy); + + MCINFO("Publishing virtual display"); + android::SurfaceComposerClient::Transaction t; + t.setDisplaySurface(mVirtualDisplay, mBufferProducer); + t.setDisplayProjection(mVirtualDisplay, + android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect); + t.setDisplayLayerStack(mVirtualDisplay, 0); // default stack + t.apply(); + + mHaveRunningDisplay = true; + + return 0; + } + + void + destroyVirtualDisplay() { + MCINFO("Destroying virtual display"); + android::SurfaceComposerClient::destroyDisplay(mVirtualDisplay); + + if (mHaveBuffer) { + mConsumer->unlockBuffer(mBuffer); + mHaveBuffer = false; + } + + mBufferProducer = NULL; + mBufferConsumer = NULL; + mConsumer = NULL; + mFrameProxy = NULL; + mVirtualDisplay = NULL; + + mHaveRunningDisplay = false; + } + + static Minicap::Format + convertFormat(android::PixelFormat format) { + switch (format) { + case android::PIXEL_FORMAT_NONE: + return FORMAT_NONE; + case android::PIXEL_FORMAT_CUSTOM: + return FORMAT_CUSTOM; + case android::PIXEL_FORMAT_TRANSLUCENT: + return FORMAT_TRANSLUCENT; + case android::PIXEL_FORMAT_TRANSPARENT: + return FORMAT_TRANSPARENT; + case android::PIXEL_FORMAT_OPAQUE: + return FORMAT_OPAQUE; + case android::PIXEL_FORMAT_RGBA_8888: + return FORMAT_RGBA_8888; + case android::PIXEL_FORMAT_RGBX_8888: + return FORMAT_RGBX_8888; + case android::PIXEL_FORMAT_RGB_888: + return FORMAT_RGB_888; + case android::PIXEL_FORMAT_RGB_565: + return FORMAT_RGB_565; + case android::PIXEL_FORMAT_BGRA_8888: + return FORMAT_BGRA_8888; + case android::PIXEL_FORMAT_RGBA_5551: + return FORMAT_RGBA_5551; + case android::PIXEL_FORMAT_RGBA_4444: + return FORMAT_RGBA_4444; + default: + return FORMAT_UNKNOWN; + } + } +}; + +int +minicap_try_get_display_info(int32_t displayId, Minicap::DisplayInfo* info) { + android::sp dpy = android::SurfaceComposerClient::getPhysicalDisplayToken(displayId); + if(!dpy) { + MCINFO("could not get display for id: %d, using internal display", displayId); + dpy = android::SurfaceComposerClient::getInternalDisplayToken(); + } + + android::Vector configs; + android::status_t err = android::SurfaceComposerClient::getDisplayConfigs(dpy, &configs); + + if (err != android::NO_ERROR) { + MCERROR("SurfaceComposerClient::getDisplayInfo() failed: %s (%d)\n", error_name(err), err); + return err; + } + + int activeConfig = android::SurfaceComposerClient::getActiveConfig(dpy); + if(static_cast(activeConfig) >= configs.size()) { + MCERROR("Active config %d not inside configs (size %zu)\n", activeConfig, configs.size()); + return android::BAD_VALUE; + } + android::DisplayInfo dinfo = configs[activeConfig]; + + info->width = dinfo.w; + info->height = dinfo.h; + info->orientation = dinfo.orientation; + info->fps = dinfo.fps; + info->density = dinfo.density; + info->xdpi = dinfo.xdpi; + info->ydpi = dinfo.ydpi; + info->secure = dinfo.secure; + info->size = sqrt(pow(dinfo.w / dinfo.xdpi, 2) + pow(dinfo.h / dinfo.ydpi, 2)); + + return 0; +} + +Minicap* +minicap_create(int32_t displayId) { + return new MinicapImpl(displayId); +} + +void +minicap_free(Minicap* mc) { + delete mc; +} + +void +minicap_start_thread_pool() { + android::ProcessState::self()->startThreadPool(); +} diff --git a/package.json b/package.json index 29483f05..75bfe7dd 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,26 @@ { "name": "minicap-prebuilt", - "version": "2.3.0", - "description": "Prebuilt binaries of minicap.", + "version": "2.3.2", + "description": "Orange prebuilt binaries of minicap for OpenSTF.", "keywords": [ "minicap" ], "bugs": { - "url": "https://github.com/openstf/minicap/issues" + "url": "https://github.com/Orange-OpenSource/minicap/issues" }, "license": "Apache-2.0", "author": { - "name": "The OpenSTF Project", - "email": "contact@openstf.io", - "url": "https://openstf.io" + "name": "Orange", + "url": "https://opensource.orange.com/" }, "repository": { "type": "git", - "url": "https://github.com/openstf/minicap.git" + "url": "https://github.com/Orange-OpenSource/minicap.git" }, "scripts": { "prepublish": "make" - } + }, + "files": [ + "prebuilt" + ] }