diff --git a/app/build.gradle b/app/build.gradle index fac1a5d598..06a710a4d4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -328,8 +328,6 @@ dependencies { implementation rootProject.ext.dependencies.android_start_up implementation rootProject.ext.dependencies.lancetx_runtime implementation rootProject.ext.dependencies.mogocustommap - implementation project(':libraries:map-usbcamera') - implementation project(':core:function-impl:mogo-core-function-startup') implementation project(':core:function-impl:mogo-core-function-devatools') implementation project(':core:function-impl:mogo-core-function-datacenter') diff --git a/libraries/map-usbcamera/.gitignore b/libraries/map-usbcamera/.gitignore deleted file mode 100644 index 42afabfd2a..0000000000 --- a/libraries/map-usbcamera/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/libraries/map-usbcamera/build.gradle b/libraries/map-usbcamera/build.gradle deleted file mode 100644 index 2616caa0ec..0000000000 --- a/libraries/map-usbcamera/build.gradle +++ /dev/null @@ -1,73 +0,0 @@ -plugins { - id 'com.android.library' - id 'kotlin-android' - id 'kotlin-android-extensions' - id 'kotlin-kapt' - id 'com.alibaba.arouter' -} - -android { - compileSdkVersion rootProject.ext.android.compileSdkVersion - // buildToolsVersion rootProject.ext.android.buildToolsVersion - defaultConfig { - minSdkVersion rootProject.ext.android.minSdkVersion - targetSdkVersion rootProject.ext.android.targetSdkVersion - versionCode Integer.valueOf(VERSION_CODE) - versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION") - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles 'consumer-rules.pro' - - //ARouter apt 参数 - kapt { - useBuildCache = false - arguments { - arg("AROUTER_MODULE_NAME", project.getName()) - } - } - - ndk { - abiFilters "armeabi-v7a", "arm64-v8a" - } - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - compileOptions { - sourceCompatibility 1.8 - targetCompatibility 1.8 - } - - - repositories { - flatDir { - dirs 'libs' - } - } - sourceSets{ - main{ - jniLibs.srcDir(['libs']) - } - } -} - -dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - - implementation rootProject.ext.dependencies.androidxconstraintlayout - implementation rootProject.ext.dependencies.arouter - kapt rootProject.ext.dependencies.aroutercompiler - - if (Boolean.valueOf(USE_MAVEN_PACKAGE)) { - - } else { - - } -} - -apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString() \ No newline at end of file diff --git a/libraries/map-usbcamera/consumer-rules.pro b/libraries/map-usbcamera/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libraries/map-usbcamera/gradle.properties b/libraries/map-usbcamera/gradle.properties deleted file mode 100644 index 86f5eb86de..0000000000 --- a/libraries/map-usbcamera/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -GROUP=com.mogo.camera -POM_ARTIFACT_ID=map-usbcamera -VERSION_CODE=1 \ No newline at end of file diff --git a/libraries/map-usbcamera/libs/common-4.1.1.aar b/libraries/map-usbcamera/libs/common-4.1.1.aar deleted file mode 100644 index 9d78514565..0000000000 Binary files a/libraries/map-usbcamera/libs/common-4.1.1.aar and /dev/null differ diff --git a/libraries/map-usbcamera/proguard-rules.pro b/libraries/map-usbcamera/proguard-rules.pro deleted file mode 100644 index 481bb43481..0000000000 --- a/libraries/map-usbcamera/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/libraries/map-usbcamera/src/main/AndroidManifest.xml b/libraries/map-usbcamera/src/main/AndroidManifest.xml deleted file mode 100644 index 70e75d7b52..0000000000 --- a/libraries/map-usbcamera/src/main/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/libraries/map-usbcamera/src/main/assets/zk/SIMYOU.ttf b/libraries/map-usbcamera/src/main/assets/zk/SIMYOU.ttf deleted file mode 100644 index 933b9d369f..0000000000 Binary files a/libraries/map-usbcamera/src/main/assets/zk/SIMYOU.ttf and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/USBCameraHelper.java b/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/USBCameraHelper.java deleted file mode 100644 index e61d6478d0..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/USBCameraHelper.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.mogo.usbcamera; - -import com.serenegiant.usb.USBMonitor; - -/** - * @author donghongyu - * USB摄像头方案,获取权限、获取YUV数据 - */ -public class USBCameraHelper { - private static USBCameraHelper mCameraHelper; - /** - * USB Manager - */ - private USBMonitor mUSBMonitor; - - private USBCameraHelper() { - } - - public static USBCameraHelper getInstance() { - if (mCameraHelper == null) { - mCameraHelper = new USBCameraHelper(); - } - return mCameraHelper; - } - - - - public void registerUSB() { - if (mUSBMonitor != null) { - mUSBMonitor.register(); - } - } - - public void unregisterUSB() { - if (mUSBMonitor != null) { - mUSBMonitor.unregister(); - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/UVCCameraHelper.java b/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/UVCCameraHelper.java deleted file mode 100644 index 4a14cd62f3..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/UVCCameraHelper.java +++ /dev/null @@ -1,373 +0,0 @@ -package com.mogo.usbcamera; - -import android.app.Activity; -import android.graphics.SurfaceTexture; -import android.hardware.usb.UsbDevice; -import android.os.Environment; - -import com.serenegiant.usb.DeviceFilter; -import com.serenegiant.usb.Size; -import com.serenegiant.usb.USBMonitor; -import com.serenegiant.usb.UVCCamera; -import com.serenegiant.usb.common.AbstractUVCCameraHandler; -import com.serenegiant.usb.common.UVCCameraHandler; -import com.serenegiant.usb.encoder.RecordParams; -import com.serenegiant.usb.widget.CameraViewInterface; - -import org.easydarwin.sw.TxtOverlay; - -import java.io.File; -import java.util.List; -import java.util.Objects; - -/** - * UVCCamera Helper class - */ -public class UVCCameraHelper { - public static final String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() - + File.separator; - public static final String SUFFIX_JPEG = ".jpg"; - public static final String SUFFIX_MP4 = ".mp4"; - private static final String TAG = "UVCCameraHelper"; - private int previewWidth = 640; - private int previewHeight = 480; - public static final int FRAME_FORMAT_YUYV = UVCCamera.FRAME_FORMAT_YUYV; - // Default using MJPEG - // if your device is connected,but have no images - // please try to change it to FRAME_FORMAT_YUYV - public static final int FRAME_FORMAT_MJPEG = UVCCamera.FRAME_FORMAT_MJPEG; - public static final int MODE_BRIGHTNESS = UVCCamera.PU_BRIGHTNESS; - public static final int MODE_CONTRAST = UVCCamera.PU_CONTRAST; - private int mFrameFormat = FRAME_FORMAT_MJPEG; - - private static UVCCameraHelper mCameraHelper; - // USB Manager - private USBMonitor mUSBMonitor; - // Camera Handler - private UVCCameraHandler mCameraHandler; - private USBMonitor.UsbControlBlock mCtrlBlock; - - private Activity mActivity; - private CameraViewInterface mCamView; - - private UVCCameraHelper() { - } - - public static UVCCameraHelper getInstance() { - if (mCameraHelper == null) { - mCameraHelper = new UVCCameraHelper(); - } - return mCameraHelper; - } - - public void closeCamera() { - if (mCameraHandler != null) { - mCameraHandler.close(); - } - } - - public interface OnMyDevConnectListener { - void onAttachDev(UsbDevice device); - - void onDettachDev(UsbDevice device); - - void onConnectDev(UsbDevice device, boolean isConnected); - - void onDisConnectDev(UsbDevice device); - - void onCancelDev(UsbDevice device); - - } - - public void initUSBMonitor(Activity activity, CameraViewInterface cameraView, final OnMyDevConnectListener listener) { - this.mActivity = activity; - this.mCamView = cameraView; - - mUSBMonitor = new USBMonitor(activity.getApplicationContext(), new USBMonitor.OnDeviceConnectListener() { - - // called by checking usb device - // do request device permission - @Override - public void onAttach(UsbDevice device) { - if (listener != null) { - listener.onAttachDev(device); - } - } - - // called by taking out usb device - // do close camera - @Override - public void onDettach(UsbDevice device) { - if (listener != null) { - listener.onDettachDev(device); - } - } - - // called by connect to usb camera - // do open camera,start previewing - @Override - public void onConnect(final UsbDevice device, USBMonitor.UsbControlBlock ctrlBlock, boolean createNew) { - mCtrlBlock = ctrlBlock; - openCamera(ctrlBlock); - new Thread(() -> { - // wait for camera created - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // start previewing - startPreview(mCamView); - }).start(); - if (listener != null) { - listener.onConnectDev(device, true); - } - } - - // called by disconnect to usb camera - // do nothing - @Override - public void onDisconnect(UsbDevice device, USBMonitor.UsbControlBlock ctrlBlock) { - if (listener != null) { - listener.onDisConnectDev(device); - } - } - - @Override - public void onCancel(UsbDevice device) { - if (listener != null) { - listener.onCancelDev(device); - } - } - }); - - createUVCCamera(); - } - - public void createUVCCamera() { - if (mCamView == null) { - throw new NullPointerException("CameraViewInterface cannot be null!"); - } - - // release resources for initializing camera handler - if (mCameraHandler != null) { - mCameraHandler.release(); - mCameraHandler = null; - } - // initialize camera handler - mCamView.setAspectRatio(previewWidth / (float) previewHeight); - mCameraHandler = UVCCameraHandler.createHandler(mActivity, mCamView, 2, - previewWidth, previewHeight, mFrameFormat); - } - - public void updateResolution(int width, int height) { - if (previewWidth == width && previewHeight == height) { - return; - } - this.previewWidth = width; - this.previewHeight = height; - if (mCameraHandler != null) { - mCameraHandler.release(); - mCameraHandler = null; - } - mCamView.setAspectRatio(previewWidth / (float) previewHeight); - mCameraHandler = UVCCameraHandler.createHandler(mActivity, mCamView, 2, - previewWidth, previewHeight, mFrameFormat); - openCamera(mCtrlBlock); - new Thread(new Runnable() { - @Override - public void run() { - // wait for camera created - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // start previewing - startPreview(mCamView); - } - }).start(); - } - - public void registerUSB() { - if (mUSBMonitor != null) { - mUSBMonitor.register(); - } - } - - public void unregisterUSB() { - if (mUSBMonitor != null) { - mUSBMonitor.unregister(); - } - } - - public boolean checkSupportFlag(final int flag) { - return mCameraHandler != null && mCameraHandler.checkSupportFlag(flag); - } - - public int getModelValue(final int flag) { - return mCameraHandler != null ? mCameraHandler.getValue(flag) : 0; - } - - public int setModelValue(final int flag, final int value) { - return mCameraHandler != null ? mCameraHandler.setValue(flag, value) : 0; - } - - public int resetModelValue(final int flag) { - return mCameraHandler != null ? mCameraHandler.resetValue(flag) : 0; - } - - public void requestPermission(int index) { - List devList = getUsbDeviceList(); - if (devList == null || devList.size() == 0) { - return; - } - int count = devList.size(); - if (index >= count) { - new IllegalArgumentException("index illegal,should be < devList.size()"); - } - if (mUSBMonitor != null) { - mUSBMonitor.requestPermission(getUsbDeviceList().get(index)); - } - } - - public int getUsbDeviceCount() { - List devList = getUsbDeviceList(); - if (devList == null || devList.size() == 0) { - return 0; - } - return devList.size(); - } - - public List getUsbDeviceList() { - List deviceFilters = DeviceFilter - .getDeviceFilters(mActivity.getApplicationContext(), R.xml.device_filter); - if (mUSBMonitor == null || deviceFilters == null) { - // throw new NullPointerException("mUSBMonitor ="+mUSBMonitor+"deviceFilters=;"+deviceFilters); - return null; - } - // matching all of filter devices - return mUSBMonitor.getDeviceList(deviceFilters); - } - - public void capturePicture(String savePath, AbstractUVCCameraHandler.OnCaptureListener listener) { - if (mCameraHandler != null && mCameraHandler.isOpened()) { - File file = new File(savePath); - if (!Objects.requireNonNull(file.getParentFile()).exists()) { - file.getParentFile().mkdirs(); - } - mCameraHandler.captureStill(savePath, listener); - } - } - - public void startPusher(AbstractUVCCameraHandler.OnEncodeResultListener listener) { - if (mCameraHandler != null && !isPushing()) { - mCameraHandler.startRecording(null, listener); - } - } - - public void startPusher(RecordParams params, AbstractUVCCameraHandler.OnEncodeResultListener listener) { - if (mCameraHandler != null && !isPushing()) { - if (params.isSupportOverlay()) { - TxtOverlay.install(mActivity.getApplicationContext()); - } - mCameraHandler.startRecording(params, listener); - } - } - - public void stopPusher() { - if (mCameraHandler != null && isPushing()) { - mCameraHandler.stopRecording(); - } - } - - public boolean isPushing() { - if (mCameraHandler != null) { - return mCameraHandler.isRecording(); - } - return false; - } - - public boolean isCameraOpened() { - if (mCameraHandler != null) { - return mCameraHandler.isOpened(); - } - return false; - } - - public void release() { - if (mCameraHandler != null) { - mCameraHandler.release(); - mCameraHandler = null; - } - if (mUSBMonitor != null) { - mUSBMonitor.destroy(); - mUSBMonitor = null; - } - } - - public USBMonitor getUSBMonitor() { - return mUSBMonitor; - } - - public void setOnPreviewFrameListener(AbstractUVCCameraHandler.OnPreViewResultListener listener) { - if (mCameraHandler != null) { - mCameraHandler.setOnPreViewResultListener(listener); - } - } - - private void openCamera(USBMonitor.UsbControlBlock ctrlBlock) { - if (mCameraHandler != null) { - mCameraHandler.open(ctrlBlock); - } - } - - public void startPreview(CameraViewInterface cameraView) { - SurfaceTexture st = cameraView.getSurfaceTexture(); - if (mCameraHandler != null) { - mCameraHandler.startPreview(st); - } - } - - public void stopPreview() { - if (mCameraHandler != null) { - mCameraHandler.stopPreview(); - } - } - - public void startCameraFoucs() { - if (mCameraHandler != null) { - mCameraHandler.startCameraFoucs(); - } - } - - public List getSupportedPreviewSizes() { - if (mCameraHandler == null) { - return null; - } - return mCameraHandler.getSupportedPreviewSizes(); - } - - public void setDefaultPreviewSize(int defaultWidth, int defaultHeight) { - if (mUSBMonitor != null) { - throw new IllegalStateException("setDefaultPreviewSize should be call before initMonitor"); - } - this.previewWidth = defaultWidth; - this.previewHeight = defaultHeight; - } - - public void setDefaultFrameFormat(int format) { - if (mUSBMonitor != null) { - throw new IllegalStateException("setDefaultFrameFormat should be call before initMonitor"); - } - this.mFrameFormat = format; - } - - public int getPreviewWidth() { - return previewWidth; - } - - public int getPreviewHeight() { - return previewHeight; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/utils/FileUtils.java b/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/utils/FileUtils.java deleted file mode 100644 index 09a2e2037c..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/mogo/usbcamera/utils/FileUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.mogo.usbcamera.utils; - -import android.os.Environment; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * - * Created by jiangdongguo on 2017/10/18. - */ -public class FileUtils { - - private static BufferedOutputStream outputStream; - public static String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator; - - public static void createfile(String path){ - File file = new File(path); - if(file.exists()){ - file.delete(); - } - try { - outputStream = new BufferedOutputStream(new FileOutputStream(file)); - } catch (Exception e){ - e.printStackTrace(); - } - } - - public static void releaseFile(){ - try { - if(outputStream != null) { - outputStream.flush(); - outputStream.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void putFileStream(byte[] data,int offset,int length){ - if(outputStream != null) { - try { - outputStream.write(data,offset,length); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public static void putFileStream(byte[] data){ - if(outputStream != null) { - try { - outputStream.write(data); - } catch (IOException e) { - e.printStackTrace(); - } - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/DialogFragmentEx.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/DialogFragmentEx.java deleted file mode 100644 index d1a390497c..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/DialogFragmentEx.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.serenegiant.dialog; - -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; - -public abstract class DialogFragmentEx extends DialogFragment { - protected static final String ARGS_KEY_REQUEST_CODE = "requestCode"; - protected static final String ARGS_KEY_ID_TITLE = "title"; - protected static final String ARGS_KEY_ID_MESSAGE = "message"; - protected static final String ARGS_KEY_TAG = "tag"; - - @Override - public void onSaveInstanceState(@NonNull final Bundle outState) { - super.onSaveInstanceState(outState); - final Bundle args = getArguments(); - if (args != null) { - outState.putAll(args); - } - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/MessageDialogFragment.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/MessageDialogFragment.java deleted file mode 100644 index bfdf3595f1..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/MessageDialogFragment.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.serenegiant.dialog; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.app.Fragment; -import android.content.DialogInterface; -import android.os.Bundle; -import android.util.Log; - -import com.serenegiant.utils.BuildCheck; - -/** - * パーミッション要求前に説明用のダイアログを表示するためのDialogFragment - */ -@SuppressWarnings("deprecation") -@Deprecated -public class MessageDialogFragment extends DialogFragment { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = MessageDialogFragment.class.getSimpleName(); - - public static interface MessageDialogListener { - public void onMessageDialogResult(final MessageDialogFragment dialog, final int requestCode, final String[] permissions, final boolean result); - } - - public static MessageDialogFragment showDialog(final Activity parent, final int requestCode, final int id_title, final int id_message, final String[] permissions) { - final MessageDialogFragment dialog = newInstance(requestCode, id_title, id_message, permissions); - dialog.show(parent.getFragmentManager(), TAG); - return dialog; - } - - public static MessageDialogFragment showDialog(final Fragment parent, final int requestCode, final int id_title, final int id_message, final String[] permissions) { - final MessageDialogFragment dialog = newInstance(requestCode, id_title, id_message, permissions); - dialog.setTargetFragment(parent, parent.getId()); - dialog.show(parent.getFragmentManager(), TAG); - return dialog; - } - - public static MessageDialogFragment newInstance(final int requestCode, final int id_title, final int id_message, final String[] permissions) { - final MessageDialogFragment fragment = new MessageDialogFragment(); - final Bundle args = new Bundle(); - // ここでパラメータをセットする - args.putInt("requestCode", requestCode); - args.putInt("title", id_title); - args.putInt("message", id_message); - args.putStringArray("permissions", permissions != null ? permissions : new String[]{}); - fragment.setArguments(args); - return fragment; - } - - private MessageDialogListener mDialogListener; - - public MessageDialogFragment() { - super(); - // デフォルトコンストラクタが必要 - } - - @SuppressLint("NewApi") - @Override - public void onAttach(final Activity activity) { - super.onAttach(activity); - // コールバックインターフェースを取得 - if (activity instanceof MessageDialogListener) { - mDialogListener = (MessageDialogListener)activity; - } - if (mDialogListener == null) { - final Fragment fragment = getTargetFragment(); - if (fragment instanceof MessageDialogListener) { - mDialogListener = (MessageDialogListener)fragment; - } - } - if (mDialogListener == null) { - if (BuildCheck.isAndroid4_2()) { - final Fragment target = getParentFragment(); - if (target instanceof MessageDialogListener) { - mDialogListener = (MessageDialogListener)target; - } - } - } - if (mDialogListener == null) { -// Log.w(TAG, "caller activity/fragment must implement PermissionDetailDialogFragmentListener"); - throw new ClassCastException(activity.toString()); - } - } - -// @Override -// public void onCreate(final Bundle savedInstanceState) { -// super.onCreate(savedInstanceState); -// final Bundle args = savedInstanceState != null ? savedInstanceState : getArguments(); -// } - - @Override - public Dialog onCreateDialog(final Bundle savedInstanceState) { - final Bundle args = savedInstanceState != null ? savedInstanceState : getArguments(); - final int requestCode = getArguments().getInt("requestCode"); - final int id_title = getArguments().getInt("title"); - final int id_message = getArguments().getInt("message"); - final String[] permissions = args.getStringArray("permissions"); - - - return new AlertDialog.Builder(getActivity()) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(id_title) - .setMessage(id_message) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int whichButton) { - // 本当はここでパーミッション要求をしたいだけどこのダイアログがdismissしてしまって結果を受け取れないので - // 呼び出し側へ返してそこでパーミッション要求する。なのでこのダイアログは単にメッセージを表示するだけ - try { - mDialogListener.onMessageDialogResult(MessageDialogFragment.this, requestCode, permissions, true); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - ) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, int whichButton) { - try { - mDialogListener.onMessageDialogResult(MessageDialogFragment.this, requestCode, permissions, false); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - ) - .create(); - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/MessageDialogFragmentV4.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/MessageDialogFragmentV4.java deleted file mode 100644 index b55b276159..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/dialog/MessageDialogFragmentV4.java +++ /dev/null @@ -1,213 +0,0 @@ -package com.serenegiant.dialog; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; - -import com.serenegiant.utils.BuildCheck; - -public class MessageDialogFragmentV4 extends DialogFragmentEx { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = MessageDialogFragmentV4.class.getSimpleName(); - - private static final String ARGS_KEY_PERMISSIONS = "permissions"; - - /** - * ダイアログの表示結果を受け取るためのコールバックリスナー - */ - public static interface MessageDialogListener { - public void onMessageDialogResult( - @NonNull final MessageDialogFragmentV4 dialog, final int requestCode, - @NonNull final String[] permissions, final boolean result); - } - - /** - * ダイアログ表示のためのヘルパーメソッド - * @param parent - * @param requestCode - * @param id_title - * @param id_message - * @param permissions - * @return - * @throws IllegalStateException - */ - public static MessageDialogFragmentV4 showDialog( - @NonNull final FragmentActivity parent, final int requestCode, - @StringRes final int id_title, @StringRes final int id_message, - @NonNull final String[] permissions) throws IllegalStateException { - - final MessageDialogFragmentV4 dialog - = newInstance(requestCode, id_title, id_message, permissions); - dialog.show(parent.getSupportFragmentManager(), TAG); - return dialog; - } - - /** - * ダイアログ表示のためのヘルパーメソッド - * @param parent - * @param requestCode - * @param id_title - * @param id_message - * @param permissions - * @return - * @throws IllegalStateException - */ - public static MessageDialogFragmentV4 showDialog( - @NonNull final Fragment parent, final int requestCode, - @StringRes final int id_title, @StringRes final int id_message, - @NonNull final String[] permissions) throws IllegalStateException { - - final MessageDialogFragmentV4 dialog - = newInstance(requestCode, id_title, id_message, permissions); - dialog.setTargetFragment(parent, parent.getId()); - dialog.show(parent.requireFragmentManager(), TAG); - return dialog; - } - - /** - * ダイアログ生成のためのヘルパーメソッド - * ダイアログ自体を直接生成せずにこのメソッドを呼び出すこと - * @param requestCode - * @param id_title - * @param id_message - * @param permissions - * @return - */ - public static MessageDialogFragmentV4 newInstance( - final int requestCode, - @StringRes final int id_title, @StringRes final int id_message, - @NonNull final String[] permissions) { - - final MessageDialogFragmentV4 fragment = new MessageDialogFragmentV4(); - final Bundle args = new Bundle(); - // ここでパラメータをセットする - args.putInt(ARGS_KEY_REQUEST_CODE, requestCode); - args.putInt(ARGS_KEY_ID_TITLE, id_title); - args.putInt(ARGS_KEY_ID_MESSAGE, id_message); - args.putStringArray(ARGS_KEY_PERMISSIONS, permissions); - fragment.setArguments(args); - return fragment; - } - - private MessageDialogListener mDialogListener; - - /** - * コンストラクタ, 直接生成せずに#newInstanceを使うこと - */ - public MessageDialogFragmentV4() { - super(); - // デフォルトコンストラクタが必要 - } - - @Override - public void onAttach(final Context context) { - super.onAttach(context); - // コールバックインターフェースを取得 - if (context instanceof MessageDialogListener) { - mDialogListener = (MessageDialogListener)context; - } - if (mDialogListener == null) { - final Fragment fragment = getTargetFragment(); - if (fragment instanceof MessageDialogListener) { - mDialogListener = (MessageDialogListener)fragment; - } - } - if (mDialogListener == null) { - if (BuildCheck.isAndroid4_2()) { - final Fragment target = getParentFragment(); - if (target instanceof MessageDialogListener) { - mDialogListener = (MessageDialogListener)target; - } - } - } - if (mDialogListener == null) { -// Log.w(TAG, "caller activity/fragment must implement PermissionDetailDialogFragmentListener"); - throw new ClassCastException(context.toString()); - } - } - -// @Override -// public void onCreate(final Bundle savedInstanceState) { -// super.onCreate(savedInstanceState); -// final Bundle args = savedInstanceState != null ? savedInstanceState : getArguments(); -// } - - @NonNull - @Override - public Dialog onCreateDialog(final Bundle savedInstanceState) { - final Bundle args = savedInstanceState != null ? savedInstanceState : requireArguments(); - final int id_title = args.getInt(ARGS_KEY_ID_TITLE); - final int id_message = args.getInt(ARGS_KEY_ID_MESSAGE); - - final Activity activity = requireActivity(); - return new AlertDialog.Builder(activity) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(id_title) - .setMessage(id_message) - .setPositiveButton(android.R.string.ok, mOnClickListener) - .setNegativeButton(android.R.string.cancel, mOnClickListener) - .create(); - } - - private final DialogInterface.OnClickListener mOnClickListener - = new DialogInterface.OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int which) { - // 本当はここでパーミッション要求をしたいだけどこのダイアログがdismissしてしまって結果を受け取れないので - // 呼び出し側へ返してそこでパーミッション要求する。なのでこのダイアログは単にメッセージを表示するだけ - callOnMessageDialogResult(which == DialogInterface.BUTTON_POSITIVE); - } - }; - - @Override - public void onCancel(final DialogInterface dialog) { - super.onCancel(dialog); - callOnMessageDialogResult(false); - } - - /** - * コールバックリスナー呼び出しのためのヘルパーメソッド - * @param result - */ - private void callOnMessageDialogResult(final boolean result) - throws IllegalStateException { - - final Bundle args = requireArguments(); - final int requestCode = args.getInt(ARGS_KEY_REQUEST_CODE); - final String[] permissions = args.getStringArray(ARGS_KEY_PERMISSIONS); - try { - mDialogListener.onMessageDialogResult( - MessageDialogFragmentV4.this, - requestCode, permissions, result); - } catch (final Exception e) { - Log.w(TAG, e); - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/AbstractRendererHolder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/AbstractRendererHolder.java deleted file mode 100644 index 570dc75eb4..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/AbstractRendererHolder.java +++ /dev/null @@ -1,1524 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import static com.serenegiant.glutils.ShaderConst.GL_TEXTURE_EXTERNAL_OES; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.opengl.GLES20; -import android.opengl.GLES30; -import android.opengl.Matrix; -import android.os.Build; -import android.util.Log; -import android.util.SparseArray; -import android.view.Surface; -import android.view.SurfaceHolder; - -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.serenegiant.utils.BuildCheck; - -import java.io.BufferedOutputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -public abstract class AbstractRendererHolder implements IRendererHolder { - private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = AbstractRendererHolder.class.getSimpleName(); - private static final String RENDERER_THREAD_NAME = "RendererHolder"; - private static final String CAPTURE_THREAD_NAME = "CaptureTask"; - - protected static final int REQUEST_DRAW = 1; - protected static final int REQUEST_UPDATE_SIZE = 2; - protected static final int REQUEST_ADD_SURFACE = 3; - protected static final int REQUEST_REMOVE_SURFACE = 4; - protected static final int REQUEST_REMOVE_SURFACE_ALL = 12; - protected static final int REQUEST_RECREATE_MASTER_SURFACE = 5; - protected static final int REQUEST_MIRROR = 6; - protected static final int REQUEST_ROTATE = 7; - protected static final int REQUEST_CLEAR = 8; - protected static final int REQUEST_CLEAR_ALL = 9; - protected static final int REQUEST_SET_MVP = 10; - - protected final Object mSync = new Object(); - @Nullable - private final RenderHolderCallback mCallback; - private volatile boolean isRunning; - - private OutputStream mCaptureStream; - @StillCaptureFormat - private int mCaptureFormat; - @IntRange(from = 1L,to = 99L) - private int mCaptureCompression = DEFAULT_CAPTURE_COMPRESSION; - protected final RendererTask mRendererTask; - - protected AbstractRendererHolder(final int width, final int height, - @Nullable final RenderHolderCallback callback) { - - this(width, height, - 3, null, EglTask.EGL_FLAG_RECORDABLE, - callback); - } - - protected AbstractRendererHolder(final int width, final int height, - final int maxClientVersion, final EGLBase.IContext sharedContext, final int flags, - @Nullable final RenderHolderCallback callback) { - - mCallback = callback; - mRendererTask = createRendererTask(width, height, - maxClientVersion, sharedContext, flags); - new Thread(mRendererTask, RENDERER_THREAD_NAME).start(); - if (!mRendererTask.waitReady()) { - // 初期化に失敗した時 - throw new RuntimeException("failed to start renderer thread"); - } - startCaptureTask(); - } - -//-------------------------------------------------------------------------------- -// IRendererHolderの実装 - @Override - public boolean isRunning() { - return isRunning; - } - - /** - * 関係するすべてのリソースを開放する。再利用できない - */ - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "release:"); - mRendererTask.release(); - synchronized (mSync) { - isRunning = false; - mSync.notifyAll(); - } -// if (DEBUG) Log.v(TAG, "release:finished"); - } - - @Nullable - public EGLBase.IContext getContext() { - return mRendererTask.getContext(); - } - - /** - * マスター用の映像を受け取るためのSurfaceを取得 - * @return - */ - @Override - public Surface getSurface() { - return mRendererTask.getSurface(); - } - - /** - * マスター用の映像を受け取るためのSurfaceTextureを取得 - * @return - */ - @Override - public SurfaceTexture getSurfaceTexture() { - return mRendererTask.getSurfaceTexture(); - } - - /** - * マスター用の映像を受け取るためのマスターをチェックして無効なら再生成要求する - */ - @Override - public void reset() { - mRendererTask.checkMasterSurface(); - } - - /** - * マスター映像サイズをサイズ変更要求 - * @param width - * @param height - */ - @Override - public void resize(final int width, final int height) - throws IllegalStateException { - - mRendererTask.resize(width, height); - } - - /** - * ミラーモードをセット - * @param mirror - */ - @Override - public void setMirror(@MirrorMode final int mirror) { - mRendererTask.mirror(mirror % MIRROR_NUM); - } - - /** - * 現在のミラーモードを取得 - * @return - */ - @Override - @MirrorMode - public int getMirror() { - return mRendererTask.mirror(); - } - - /** - * 分配描画用のSurfaceを追加 - * このメソッドは指定したSurfaceが追加されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id 普通はSurface#hashCodeを使う - * @param surface - * @param isRecordable - */ - @Override - public void addSurface(final int id, - final Object surface, final boolean isRecordable) - throws IllegalStateException, IllegalArgumentException { - -// if (DEBUG) Log.v(TAG, "addSurface:id=" + id + ",surface=" + surface); - mRendererTask.addSurface(id, surface); - } - - /** - * 分配描画用のSurfaceを追加 - * このメソッドは指定したSurfaceが追加されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id 普通はSurface#hashCodeを使う - * @param surface - * @param isRecordable - * @param maxFps - */ - @Override - public void addSurface(final int id, - final Object surface, final boolean isRecordable, final int maxFps) - throws IllegalStateException, IllegalArgumentException { - -// if (DEBUG) Log.v(TAG, "addSurface:id=" + id + ",surface=" + surface); - mRendererTask.addSurface(id, surface, maxFps); - } - - /** - * 分配描画用のSurfaceを削除要求する。 - * このメソッドは指定したSurfaceが削除されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id - */ - @Override - public void removeSurface(final int id) { -// if (DEBUG) Log.v(TAG, "removeSurface:id=" + id); - mRendererTask.removeSurface(id); - } - - /** - * 分配描画用のSurfaceを全て削除要求する - * このメソッドはSurfaceが削除されるか - * interruptされるまでカレントスレッドをブロックする。 - */ - @Override - public void removeSurfaceAll() { -// if (DEBUG) Log.v(TAG, "removeSurfaceAll:id=" + id); - mRendererTask.removeSurfaceAll(); - } - - /** - * 分配描画用のSurfaceを指定した色で塗りつぶす - * @param id - * @param color - */ - @Override - public void clearSurface(final int id, final int color) { - mRendererTask.clearSurface(id, color); - } - - /** - * 分配描画用のSurfaceを指定した色で塗りつぶす - * @param color - */ - public void clearSurfaceAll(final int color) { - mRendererTask.clearSurfaceAll(color); - } - - public void setMvpMatrix(final int id, - final int offset, @NonNull final float[] matrix) { - mRendererTask.setMvpMatrix(id, offset, matrix); - } - - /** - * 分配描画用のSurfaceへの描画が有効かどうかを取得 - * @param id - * @return - */ - @Override - public boolean isEnabled(final int id) { - return mRendererTask.isEnabled(id); - } - - /** - * 分配描画用のSurfaceへの描画の有効・無効を切替 - * @param id - * @param enable - */ - @Override - public void setEnabled(final int id, final boolean enable) { - mRendererTask.setEnabled(id, enable); - } - - /** - * 強制的に現在の最新のフレームを描画要求する - * 分配描画用Surface全てが更新されるので注意 - */ - @Override - public void requestFrame() { - mRendererTask.removeRequest(REQUEST_DRAW); - mRendererTask.offer(REQUEST_DRAW); - } - - /** - * 追加されている分配描画用のSurfaceの数を取得 - * @return - */ - @Override - public int getCount() { - return mRendererTask.getCount(); - } - - /** - * 静止画を撮影する - * 撮影完了を待機しない - * @param path - */ - @Deprecated - @Override - public void captureStillAsync(@NonNull final String path) - throws FileNotFoundException, IllegalStateException { - - if (DEBUG) Log.v(TAG, "captureStillAsync:" + path); - - captureStill(new BufferedOutputStream(new FileOutputStream(path)), - getCaptureFormat(path), DEFAULT_CAPTURE_COMPRESSION, false); - } - - /** - * 静止画を撮影する - * 撮影完了を待機しない - * @param path - * @param captureCompression - */ - @Deprecated - @Override - public void captureStillAsync(@NonNull final String path, - @IntRange(from = 1L,to = 99L) final int captureCompression) - throws FileNotFoundException, IllegalStateException { - - if (DEBUG) Log.v(TAG, "captureStillAsync:" + path - + ",captureCompression=" + captureCompression); - - captureStill(new BufferedOutputStream(new FileOutputStream(path)), - getCaptureFormat(path), captureCompression, false); - } - - /** - * 静止画を撮影する - * 撮影完了を待機する - * @param path - */ - @Override - public void captureStill(@NonNull final String path) - throws FileNotFoundException, IllegalStateException { - - if (DEBUG) Log.v(TAG, "captureStill:" + path); - - captureStill(new BufferedOutputStream(new FileOutputStream(path)), - getCaptureFormat(path), DEFAULT_CAPTURE_COMPRESSION, true); - } - - /** - * 静止画を撮影する - * 撮影完了を待機する - * @param path - */ - @Override - public void captureStill(@NonNull final String path, - @IntRange(from = 1L,to = 99L)final int captureCompression) - throws FileNotFoundException, IllegalStateException { - - if (DEBUG) Log.v(TAG, "captureStill:" + path - + ",captureCompression=" + captureCompression); - captureStill(new BufferedOutputStream(new FileOutputStream(path)), - getCaptureFormat(path), captureCompression, true); - } - - /** - * 静止画を撮影する - * 撮影完了を待機する - * @param out - * @param captureFormat - * @param captureCompression - */ - @Override - public void captureStill(@NonNull final OutputStream out, - @StillCaptureFormat final int captureFormat, - @IntRange(from = 1L,to = 99L) final int captureCompression) - throws IllegalStateException { - - captureStill(out, captureFormat, captureCompression, true); - } - - /** - * 実際の静止画撮影要求メソッド - * @param out - * @param captureFormat - * @param captureCompression - * @param needWait 撮影完了を待機するを待機するかどうか - */ - private void captureStill(@NonNull final OutputStream out, - @StillCaptureFormat final int captureFormat, - @IntRange(from = 1L,to = 99L) final int captureCompression, - final boolean needWait) throws IllegalStateException { - - synchronized (mSync) { - if (!isRunning) { - throw new IllegalStateException("already released?"); - } - if (mCaptureStream != null) { - throw new IllegalStateException("already run still capturing now"); - } - mCaptureStream = out; - mCaptureFormat = captureFormat; - mCaptureCompression = captureCompression; - mSync.notifyAll(); - if (needWait) { - // 撮影完了街をする場合 - for ( ; isRunning && (mCaptureStream != null) ; ) { - try { - if (DEBUG) Log.v(TAG, "静止画撮影待ち"); - mSync.wait(1000); - } catch (final InterruptedException e) { - // ignore - } - } - } - } - if (DEBUG) Log.v(TAG, "captureStill:終了"); - } - - /** - * パス文字列の拡張子を調べて静止画圧縮フォーマットを取得する。 - * jpeg(jpg)/png/webpのいずれでもなければIllegalArgumentExceptionを投げる - * @param path - * @return - * @throws IllegalArgumentException - */ - @StillCaptureFormat - private static int getCaptureFormat(@NonNull final String path) - throws IllegalArgumentException { - - int result; - final String _path = path.toLowerCase(); - if (path.endsWith(".jpg") || path.endsWith(".jpeg")) { - result = OUTPUT_FORMAT_JPEG; - } else if (path.endsWith(".png")) { - result = OUTPUT_FORMAT_PNG; - } else if (path.endsWith(".webp")) { - result = OUTPUT_FORMAT_WEBP; - } else { - throw new IllegalArgumentException("unknown compress format(extension)"); - } - return result; - } - - /** - * 静止画圧縮フォーマットをBitmap.CompressFormatに変換する - * @param captureFormat - * @return - */ - private static Bitmap.CompressFormat getCaptureFormat( - @StillCaptureFormat final int captureFormat) { - - Bitmap.CompressFormat result; - switch (captureFormat) { - case OUTPUT_FORMAT_JPEG: - result = Bitmap.CompressFormat.JPEG; - break; - case OUTPUT_FORMAT_PNG: - result = Bitmap.CompressFormat.PNG; - break; - case OUTPUT_FORMAT_WEBP: - result = Bitmap.CompressFormat.WEBP; - break; - default: - result = Bitmap.CompressFormat.JPEG; - break; - } - return result; - } -//-------------------------------------------------------------------------------- - @NonNull - protected abstract RendererTask createRendererTask(final int width, final int height, - final int maxClientVersion, final EGLBase.IContext sharedContext, final int flags); - - protected void startCaptureTask() { - new Thread(mCaptureTask, CAPTURE_THREAD_NAME).start(); - synchronized (mSync) { - if (!isRunning) { - try { - mSync.wait(); - } catch (final InterruptedException e) { - // ignore - } - } - } - } - - protected void notifyCapture() { -// if (DEBUG) Log.v(TAG, "notifyCapture:"); - synchronized (mCaptureTask) { - // キャプチャタスクに映像が更新されたことを通知 - mCaptureTask.notify(); - } - } - -//-------------------------------------------------------------------------------- - protected void callOnCreate(Surface surface) { - if (mCallback != null) { - try { - mCallback.onCreate(surface); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - - protected void callOnFrameAvailable() { - if (mCallback != null) { - try { - mCallback.onFrameAvailable(); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - - protected void callOnDestroy() { - if (mCallback != null) { - try { - mCallback.onDestroy(); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - -//-------------------------------------------------------------------------------- - protected abstract static class BaseRendererTask extends EglTask { - private final SparseArray mClients - = new SparseArray(); - private final AbstractRendererHolder mParent; - private int mVideoWidth, mVideoHeight; - final float[] mTexMatrix = new float[16]; - int mTexId; - private SurfaceTexture mMasterTexture; - private Surface mMasterSurface; - @MirrorMode - private int mMirror = MIRROR_NORMAL; - private int mRotation = 0; - private volatile boolean mIsFirstFrameRendered; - - public BaseRendererTask(@NonNull final AbstractRendererHolder parent, - final int width, final int height) { - - this(parent, width, height, - 3, null, EglTask.EGL_FLAG_RECORDABLE); - } - - public BaseRendererTask(@NonNull final AbstractRendererHolder parent, - final int width, final int height, - final int maxClientVersion, - final EGLBase.IContext sharedContext, final int flags) { - - super(maxClientVersion, sharedContext, flags); - mParent = parent; - mVideoWidth = width > 0 ? width : 640; - mVideoHeight = height > 0 ? height : 480; - } - /** - * ワーカースレッド開始時の処理(ここはワーカースレッド上) - */ - @Override - protected final void onStart() { -// if (DEBUG) Log.v(TAG, "onStart:"); - handleReCreateMasterSurface(); - internalOnStart(); - synchronized (mParent.mSync) { - mParent.isRunning = true; - mParent.mSync.notifyAll(); - } -// if (DEBUG) Log.v(TAG, "onStart:finished"); - } - - /** - * ワーカースレッド終了時の処理(ここはまだワーカースレッド上) - */ - @Override - protected void onStop() { -// if (DEBUG) Log.v(TAG, "onStop"); - synchronized (mParent.mSync) { - mParent.isRunning = false; - mParent.mSync.notifyAll(); - } - makeCurrent(); - internalOnStop(); - handleReleaseMasterSurface(); - handleRemoveAll(); -// if (DEBUG) Log.v(TAG, "onStop:finished"); - } - - @Override - protected boolean onError(final Exception e) { -// if (DEBUG) Log.w(TAG, e); - return false; - } - - protected abstract void internalOnStart(); - protected abstract void internalOnStop(); - - @Override - protected Object processRequest(final int request, - final int arg1, final int arg2, final Object obj) { - - switch (request) { - case REQUEST_DRAW: - handleDraw(); - break; - case REQUEST_UPDATE_SIZE: - handleResize(arg1, arg2); - break; - case REQUEST_ADD_SURFACE: - handleAddSurface(arg1, obj, arg2); - break; - case REQUEST_REMOVE_SURFACE: - handleRemoveSurface(arg1); - break; - case REQUEST_REMOVE_SURFACE_ALL: - handleRemoveAll(); - break; - case REQUEST_RECREATE_MASTER_SURFACE: - handleReCreateMasterSurface(); - break; - case REQUEST_MIRROR: - handleMirror(arg1); - break; - case REQUEST_ROTATE: - handleRotate(arg1, arg2); - break; - case REQUEST_CLEAR: - handleClear(arg1, arg2); - break; - case REQUEST_CLEAR_ALL: - handleClearAll(arg1); - break; - case REQUEST_SET_MVP: - handleSetMvp(arg1, arg2, obj); - break; - } - return null; - } - - /** - * マスター映像取得用のSurfaceを取得 - * @return - */ - public Surface getSurface() { -// if (DEBUG) Log.v(TAG, "getSurface:" + mMasterSurface); - checkMasterSurface(); - return mMasterSurface; - } - - /** - * マスター映像受け取り用のSurfaceTextureを取得 - * @return - */ - public SurfaceTexture getSurfaceTexture() { -// if (DEBUG) Log.v(TAG, "getSurfaceTexture:" + mMasterTexture); - checkMasterSurface(); - return mMasterTexture; - } - - /** - * 分配描画用のSurfaceを追加 - * このメソッドは指定したSurfaceが追加されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id - * @param surface - */ - public void addSurface(final int id, final Object surface) - throws IllegalStateException, IllegalArgumentException { - - addSurface(id, surface, -1); - } - - /** - * 分配描画用のSurfaceを追加 - * このメソッドは指定したSurfaceが追加されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id - * @param surface - */ - public void addSurface(final int id, - final Object surface, final int maxFps) - throws IllegalStateException, IllegalArgumentException { - - checkFinished(); - if (!((surface instanceof SurfaceTexture) - || (surface instanceof Surface) - || (surface instanceof SurfaceHolder))) { - - throw new IllegalArgumentException( - "Surface should be one of Surface, SurfaceTexture or SurfaceHolder"); - } - synchronized (mClients) { - if (mClients.get(id) == null) { - for ( ; isRunning() ; ) { - if (offer(REQUEST_ADD_SURFACE, id, maxFps, surface)) { - try { - mClients.wait(); - } catch (final InterruptedException e) { - // ignore - } - break; - } else { - // キューに追加できなかった時は待機する - try { - mClients.wait(5); - } catch (final InterruptedException e) { - break; - } - } - } - } - } - } - - /** - * 分配描画用のSurfaceを削除 - * このメソッドは指定したSurfaceが削除されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id - */ - public void removeSurface(final int id) { - synchronized (mClients) { - if (mClients.get(id) != null) { - for ( ; isRunning() ; ) { - if (offer(REQUEST_REMOVE_SURFACE, id)) { - try { - mClients.wait(); - } catch (final InterruptedException e) { - // ignore - } - break; - } else { - // キューに追加できなかった時は待機する - try { - mClients.wait(5); - } catch (final InterruptedException e) { - break; - } - } - } - } - } - } - - /** - * 分配描画用のSurfaceを全て削除する - * このメソッドはSurfaceが削除されるか - * interruptされるまでカレントスレッドをブロックする。 - */ - public void removeSurfaceAll() { - synchronized (mClients) { - for ( ; isRunning() ; ) { - if (offer(REQUEST_REMOVE_SURFACE_ALL)) { - try { - mClients.wait(); - } catch (final InterruptedException e) { - // ignore - } - break; - } else { - // キューに追加できなかった時は待機する - try { - mClients.wait(5); - } catch (final InterruptedException e) { - break; - } - } - } - } - } - - /** - * 指定したIDの分配描画用のSurfaceを指定した色で塗りつぶす - * @param id - * @param color - */ - public void clearSurface(final int id, final int color) { - checkFinished(); - offer(REQUEST_CLEAR, id, color); - } - - public void clearSurfaceAll(final int color) { - checkFinished(); - offer(REQUEST_CLEAR_ALL, color); - } - - public void setMvpMatrix(final int id, - final int offset, @NonNull final float[] matrix) { - checkFinished(); - offer(REQUEST_SET_MVP, id, offset, matrix); - } - - public boolean isEnabled(final int id) { - synchronized (mClients) { - final RendererSurfaceRec rec = mClients.get(id); - return rec != null && rec.isEnabled(); - } - } - - public void setEnabled(final int id, final boolean enable) { - synchronized (mClients) { - final RendererSurfaceRec rec = mClients.get(id); - if (rec != null) { - rec.setEnabled(enable); - } - } - } - - /** - * 分配描画用のSurfaceの数を取得 - * @return - */ - public int getCount() { - synchronized (mClients) { - return mClients.size(); - } - } - - /** - * リサイズ - * @param width - * @param height - */ - public void resize(final int width, final int height) - throws IllegalStateException { - - checkFinished(); - if ( ((width > 0) && (height > 0)) - && ((mVideoWidth != width) || (mVideoHeight != height)) ) { - - offer(REQUEST_UPDATE_SIZE, width, height); - } - } - - protected int width() { - return mVideoWidth; - } - - protected int height() { - return mVideoHeight; - } - - public void mirror(final int mirror) { - checkFinished(); - if (mMirror != mirror) { - offer(REQUEST_MIRROR, mirror); - } - } - - @MirrorMode - public int mirror() { - return mMirror; - } - - /** - * 分配描画用のマスターSurfaceが有効かどうかをチェックして無効なら再生成する - */ - public void checkMasterSurface() { - checkFinished(); - if ((mMasterSurface == null) || (!mMasterSurface.isValid())) { - Log.d(TAG, "checkMasterSurface:invalid master surface"); - offerAndWait(REQUEST_RECREATE_MASTER_SURFACE, 0, 0, null); - } - } - - protected void checkFinished() throws IllegalStateException { - if (isFinished()) { - throw new IllegalStateException("already finished"); - } - } - - protected AbstractRendererHolder getParent() { - return mParent; - } - -//================================================================================ -// ワーカースレッド上での処理 -//================================================================================ - /** - * 実際の描画処理 - */ - protected void handleDraw() { - if ((mMasterSurface == null) || (!mMasterSurface.isValid())) { - Log.e(TAG, "checkMasterSurface:invalid master surface"); - offer(REQUEST_RECREATE_MASTER_SURFACE); - return; - } - if (mIsFirstFrameRendered) { - try { - makeCurrent(); - handleUpdateTexture(); - } catch (final Exception e) { - Log.e(TAG, "draw:thread id =" + Thread.currentThread().getId(), e); - offer(REQUEST_RECREATE_MASTER_SURFACE); - return; - } - mParent.notifyCapture(); - preprocess(); - handleDrawClients(); - mParent.callOnFrameAvailable(); - } - makeCurrent(); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - GLES20.glFlush(); - } - - protected void handleUpdateTexture() { - mMasterTexture.updateTexImage(); - mMasterTexture.getTransformMatrix(mTexMatrix); - } - - protected abstract void preprocess(); - - /** - * 各Surfaceへ描画する - */ - protected void handleDrawClients() { - synchronized (mClients) { - final int n = mClients.size(); - RendererSurfaceRec client; - for (int i = n - 1; i >= 0; i--) { - client = mClients.valueAt(i); - if ((client != null) && client.canDraw()) { - try { - onDrawClient(client, mTexId, mTexMatrix); - } catch (final Exception e) { - // removeSurfaceが呼ばれなかったかremoveSurfaceを呼ぶ前に破棄されてしまった - mClients.removeAt(i); - client.release(); - } - } - } - } - } - - /** - * Surface1つの描画処理 - * @param client - * @param texId - * @param texMatrix - */ - protected abstract void onDrawClient( - @NonNull final RendererSurfaceRec client, - final int texId, final float[] texMatrix); - - /** - * 指定したIDの分配描画先Surfaceを追加する - * @param id - * @param surface - */ - protected void handleAddSurface(final int id, - final Object surface, final int maxFps) { - -// if (DEBUG) Log.v(TAG, "handleAddSurface:id=" + id); - checkSurface(); - synchronized (mClients) { - RendererSurfaceRec client = mClients.get(id); - if (client == null) { - try { - client = RendererSurfaceRec.newInstance(getEgl(), surface, maxFps); - setMirror(client, mMirror); - mClients.append(id, client); - } catch (final Exception e) { - Log.w(TAG, "invalid surface: surface=" + surface, e); - } - } else { - Log.w(TAG, "surface is already added: id=" + id); - } - mClients.notifyAll(); - } - } - - /** - * 指定したIDの分配描画先Surfaceを破棄する - * @param id - */ - protected void handleRemoveSurface(final int id) { - // if (DEBUG) Log.v(TAG, "handleRemoveSurface:id=" + id); - synchronized (mClients) { - final RendererSurfaceRec client = mClients.get(id); - if (client != null) { - mClients.remove(id); - if (client.isValid()) { - client.clear(0); // XXX 黒で塗りつぶし, 色指定できるようにする? - } - client.release(); - } - checkSurface(); - mClients.notifyAll(); - } - } - - /** - * 念の為に分配描画先のSurfaceを全て破棄する - */ - protected void handleRemoveAll() { - // if (DEBUG) Log.v(TAG, "handleRemoveAll:"); - synchronized (mClients) { - final int n = mClients.size(); - RendererSurfaceRec client; - for (int i = 0; i < n; i++) { - client = mClients.valueAt(i); - if (client != null) { - if (client.isValid()) { - client.clear(0); // XXX 黒で塗りつぶし, 色指定できるようにする? - } - client.release(); - } - } - mClients.clear(); - mClients.notifyAll(); - } - // if (DEBUG) Log.v(TAG, "handleRemoveAll:finished"); - } - - /** - * 分配描画先のSurfaceが有効かどうかをチェックして無効なものは削除する - */ - protected void checkSurface() { - // if (DEBUG) Log.v(TAG, "checkSurface"); - synchronized (mClients) { - final int n = mClients.size(); - for (int i = 0; i < n; i++) { - final RendererSurfaceRec client = mClients.valueAt(i); - if ((client != null) && !client.isValid()) { - final int id = mClients.keyAt(i); - // if (DEBUG) Log.i(TAG, "checkSurface:found invalid surface:id=" + id); - mClients.valueAt(i).release(); - mClients.remove(id); - } - } - } - // if (DEBUG) Log.v(TAG, "checkSurface:finished"); - } - - /** - * 指定したIDの分配描画用Surfaceを指定した色で塗りつぶす - * @param id - * @param color - */ - protected void handleClear(final int id, final int color) { - synchronized (mClients) { - final RendererSurfaceRec client = mClients.get(id); - if ((client != null) && client.isValid()) { - client.clear(color); - } - } - } - - /** - * 分配描画用Surface全てを指定した色で塗りつぶす - * @param color - */ - protected void handleClearAll(final int color) { - synchronized (mClients) { - final int n = mClients.size(); - for (int i = 0; i < n; i++) { - final RendererSurfaceRec client = mClients.valueAt(i); - if ((client != null) && client.isValid()) { - client.clear(color); - } - } - } - } - - /** - * モデルビュー変換行列を適用する - * @param id - * @param offset - * @param mvp - */ - protected void handleSetMvp(final int id, - final int offset, final Object mvp) { - - if ((mvp instanceof float[]) && (((float[]) mvp).length >= 16 + offset)) { - final float[] array = (float[])mvp; - synchronized (mClients) { - final RendererSurfaceRec client = mClients.get(id); - if ((client != null) && client.isValid()) { - System.arraycopy(array, offset, client.mMvpMatrix, 0, 16); - } - } - } - } - - /** - * マスターSurfaceを再生成する - */ - @SuppressLint("NewApi") - protected void handleReCreateMasterSurface() { - makeCurrent(); - handleReleaseMasterSurface(); - makeCurrent(); - mTexId = GLHelper.initTex(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_NEAREST); - mMasterTexture = new SurfaceTexture(mTexId); - mMasterSurface = new Surface(mMasterTexture); - if (BuildCheck.isAndroid4_1()) { - mMasterTexture.setDefaultBufferSize(mVideoWidth, mVideoHeight); - } - mMasterTexture.setOnFrameAvailableListener(mOnFrameAvailableListener); - mParent.callOnCreate(mMasterSurface); - } - - /** - * マスターSurfaceを破棄する - */ - protected void handleReleaseMasterSurface() { - if (mMasterSurface != null) { - try { - mMasterSurface.release(); - } catch (final Exception e) { - Log.w(TAG, e); - } - mMasterSurface = null; - mParent.callOnDestroy(); - } - if (mMasterTexture != null) { - try { - mMasterTexture.release(); - } catch (final Exception e) { - Log.w(TAG, e); - } - mMasterTexture = null; - } - if (mTexId != 0) { - GLHelper.deleteTex(mTexId); - mTexId = 0; - } - } - - /** - * マスター映像サイズをリサイズ - * @param width - * @param height - */ - @SuppressLint("NewApi") - protected void handleResize(final int width, final int height) { -// if (DEBUG) Log.v(TAG, String.format("handleResize:(%d,%d)", width, height)); - mVideoWidth = width; - mVideoHeight = height; - if (BuildCheck.isAndroid4_1()) { - mMasterTexture.setDefaultBufferSize(mVideoWidth, mVideoHeight); - } - } - - /** - * ミラーモードをセット - * @param mirror - */ - protected void handleMirror(final int mirror) { - mMirror = mirror; - synchronized (mClients) { - final int n = mClients.size(); - for (int i = 0; i < n; i++) { - final RendererSurfaceRec client = mClients.valueAt(i); - if (client != null) { - setMirror(client, mirror); - } - } - } - } - - /** - * handleMirrorの下請け - * @param client - * @param mirror - */ - protected void setMirror(final RendererSurfaceRec client, final int mirror) { - RendererHolder.setMirror(client.mMvpMatrix, mirror); - } - - protected void handleRotate(final int id, final int degree) { - // FIXME 未実装 - } - - /** - * TextureSurfaceで映像を受け取った際のコールバックリスナー - */ - protected final SurfaceTexture.OnFrameAvailableListener - mOnFrameAvailableListener = new SurfaceTexture.OnFrameAvailableListener() { - - @Override - public void onFrameAvailable(final SurfaceTexture surfaceTexture) { - removeRequest(REQUEST_DRAW); - mIsFirstFrameRendered = true; - offer(REQUEST_DRAW); - } - }; - - } - - /** - * ワーカースレッド上でOpenGL|ESを用いてマスター映像を分配描画するためのインナークラス - */ - protected abstract static class RendererTask extends BaseRendererTask { - - protected GLDrawer2D mDrawer; - - public RendererTask(@NonNull final AbstractRendererHolder parent, - final int width, final int height) { - - super(parent, width, height); - } - - public RendererTask(@NonNull final AbstractRendererHolder parent, - final int width, final int height, - final int maxClientVersion, - final EGLBase.IContext sharedContext, final int flags) { - - super(parent, width, height, maxClientVersion, sharedContext, flags); - } - - @Override - protected void internalOnStart() { - mDrawer = new GLDrawer2D(true); - } - - @Override - protected void internalOnStop() { - if (mDrawer != null) { - mDrawer.release(); - mDrawer = null; - } - } - - @Override - protected void preprocess() { - } - - @Override - protected void onDrawClient(@NonNull final RendererSurfaceRec client, - final int texId, final float[] texMatrix) { - - client.draw(mDrawer, texId, texMatrix); - } - } - -//-------------------------------------------------------------------------------- - - protected void setupCaptureDrawer(final GLDrawer2D drawer) { - } - - /** - * 静止画を非同期でキャプチャするためのRunnable - */ - private final Runnable mCaptureTask = new Runnable() { - EGLBase eglBase; - EGLBase.IEglSurface captureSurface; - GLDrawer2D drawer; - final float[] mMvpMatrix = new float[16]; - - @Override - public void run() { -// if (DEBUG) Log.v(TAG, "captureTask start"); - synchronized (mSync) { - // 描画スレッドが実行されるまで待機 - for (; !isRunning && !mRendererTask.isFinished(); ) { - try { - mSync.wait(1000); - } catch (final InterruptedException e) { - break; - } - } - } - if (isRunning) { - init(); - try { - if ((eglBase.getGlVersion() > 2) && (BuildCheck.isAndroid4_3())) { - captureLoopGLES3(); - } else { - captureLoopGLES2(); - } - } catch (final Exception e) { - Log.w(TAG, e); - } finally { - // release resources - release(); - } - } -// if (DEBUG) Log.v(TAG, "captureTask finished"); - } - - private final void init() { - eglBase = EGLBase.createFrom(3, - mRendererTask.getContext(), false, 0, false); - captureSurface = eglBase.createOffscreen( - mRendererTask.width(), mRendererTask.height()); - Matrix.setIdentityM(mMvpMatrix, 0); - drawer = new GLDrawer2D(true); - setupCaptureDrawer(drawer); - } - - private final void captureLoopGLES2() { - int width = -1, height = -1; - ByteBuffer buf = null; - int captureCompression = DEFAULT_CAPTURE_COMPRESSION; -// if (DEBUG) Log.v(TAG, "captureTask loop"); - for (; isRunning ;) { - synchronized (mSync) { - if (mCaptureStream == null) { - try { - mSync.wait(); - } catch (final InterruptedException e) { - break; - } - if (mCaptureStream != null) { -// if (DEBUG) Log.i(TAG, "静止画撮影要求を受け取った"); - captureCompression = mCaptureCompression; - if ((captureCompression <= 0) || (captureCompression >= 100)) { - captureCompression = 90; - } - } else { - // 起床されたけどmCaptureStreamがnullだった - continue; - } - } - if (DEBUG) Log.v(TAG, "#captureLoopGLES2:start capture"); - if ((buf == null) - || (width != mRendererTask.width()) - || (height != mRendererTask.height())) { - - width = mRendererTask.width(); - height = mRendererTask.height(); - buf = ByteBuffer.allocateDirect(width * height * 4); - buf.order(ByteOrder.LITTLE_ENDIAN); - if (captureSurface != null) { - captureSurface.release(); - captureSurface = null; - } - captureSurface = eglBase.createOffscreen(width, height); - } - if (isRunning && (width > 0) && (height > 0)) { - setMirror(mMvpMatrix, mRendererTask.mirror()); - mMvpMatrix[5] *= -1.0f; // flip up-side down - drawer.setMvpMatrix(mMvpMatrix, 0); - captureSurface.makeCurrent(); - drawer.draw(mRendererTask.mTexId, mRendererTask.mTexMatrix, 0); - captureSurface.swap(); - buf.clear(); - GLES20.glReadPixels(0, 0, width, height, - GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); -// if (DEBUG) Log.v(TAG, "save pixels to file:" + captureFile); - final Bitmap.CompressFormat compressFormat - = getCaptureFormat(mCaptureFormat); - try { - try { - final Bitmap bmp = Bitmap.createBitmap( - width, height, Bitmap.Config.ARGB_8888); - buf.clear(); - bmp.copyPixelsFromBuffer(buf); - bmp.compress(compressFormat, captureCompression, mCaptureStream); - bmp.recycle(); - mCaptureStream.flush(); - } finally { - mCaptureStream.close(); - } - } catch (final IOException e) { - Log.w(TAG, "failed to save file", e); - } - } else if (isRunning) { - Log.w(TAG, "#captureLoopGLES3:unexpectedly width/height is zero"); - } - if (DEBUG) Log.i(TAG, "#captureLoopGLES2:静止画撮影終了"); - mCaptureStream = null; - mSync.notifyAll(); - } // end of synchronized (mSync) - } // end of for (; isRunning ;) - synchronized (mSync) { - mSync.notifyAll(); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) - private final void captureLoopGLES3() { - int width = -1, height = -1; - ByteBuffer buf = null; - int captureCompression = 90; -// if (DEBUG) Log.v(TAG, "captureTask loop"); - for (; isRunning ;) { - synchronized (mSync) { - if (mCaptureStream == null) { - try { - mSync.wait(); - } catch (final InterruptedException e) { - break; - } - if (mCaptureStream != null) { -// if (DEBUG) Log.i(TAG, "静止画撮影要求を受け取った"); - captureCompression = mCaptureCompression; - if ((captureCompression <= 0) || (captureCompression >= 100)) { - captureCompression = 90; - } - } else { - // 起床されたけどmCaptureStreamがnullだった - continue; - } - } - if (DEBUG) Log.v(TAG, "#captureLoopGLES3:start capture"); - if ((buf == null) - || (width != mRendererTask.width()) - || (height != mRendererTask.height())) { - - width = mRendererTask.width(); - height = mRendererTask.height(); - buf = ByteBuffer.allocateDirect(width * height * 4); - buf.order(ByteOrder.LITTLE_ENDIAN); - if (captureSurface != null) { - captureSurface.release(); - captureSurface = null; - } - captureSurface = eglBase.createOffscreen(width, height); - } - if (isRunning && (width > 0) && (height > 0)) { - setMirror(mMvpMatrix, mRendererTask.mirror()); - mMvpMatrix[5] *= -1.0f; // flip up-side down - drawer.setMvpMatrix(mMvpMatrix, 0); - captureSurface.makeCurrent(); - drawer.draw(mRendererTask.mTexId, mRendererTask.mTexMatrix, 0); - captureSurface.swap(); - buf.clear(); - // FIXME これはGL|ES3のPBOとglMapBufferRange/glUnmapBufferを使うように変更する - GLES30.glReadPixels(0, 0, width, height, - GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, buf); -// if (DEBUG) Log.v(TAG, "save pixels to file:" + captureFile); - final Bitmap.CompressFormat compressFormat - = getCaptureFormat(mCaptureFormat); - try { - try { - final Bitmap bmp = Bitmap.createBitmap( - width, height, Bitmap.Config.ARGB_8888); - buf.clear(); - bmp.copyPixelsFromBuffer(buf); - bmp.compress(compressFormat, captureCompression, mCaptureStream); - bmp.recycle(); - mCaptureStream.flush(); - } finally { - mCaptureStream.close(); - } - } catch (final IOException e) { - Log.w(TAG, "failed to save file", e); - } - } else if (isRunning) { - Log.w(TAG, "#captureLoopGLES3:unexpectedly width/height is zero"); - } - if (DEBUG) Log.i(TAG, "#captureLoopGLES3:静止画撮影終了"); - mCaptureStream = null; - mSync.notifyAll(); - } // end of synchronized (mSync) - } // end of for (; isRunning ;) - synchronized (mSync) { - mSync.notifyAll(); - } - } - - private final void release() { - if (captureSurface != null) { - captureSurface.makeCurrent(); - captureSurface.release(); - captureSurface = null; - } - if (drawer != null) { - drawer.release(); - drawer = null; - } - if (eglBase != null) { - eglBase.release(); - eglBase = null; - } - } - }; - -//================================================================================ - protected static void setMirror(final float[] mvp, final int mirror) { - switch (mirror) { - case MIRROR_NORMAL: - mvp[0] = Math.abs(mvp[0]); - mvp[5] = Math.abs(mvp[5]); - break; - case MIRROR_HORIZONTAL: - mvp[0] = -Math.abs(mvp[0]); // flip left-right - mvp[5] = Math.abs(mvp[5]); - break; - case MIRROR_VERTICAL: - mvp[0] = Math.abs(mvp[0]); - mvp[5] = -Math.abs(mvp[5]); // flip up-side down - break; - case MIRROR_BOTH: - mvp[0] = -Math.abs(mvp[0]); // flip left-right - mvp[5] = -Math.abs(mvp[5]); // flip up-side down - break; - } - } - - /** - * 現在のモデルビュー変換行列をxy平面で指定した角度回転させる - * @param mvp - * @param degrees - */ - protected static void rotate(final float[] mvp, final int degrees) { - if ((degrees % 180) != 0) { - Matrix.rotateM(mvp, 0, degrees, 0.0f, 0.0f, 1.0f); - } - } - - /** - * モデルビュー変換行列にxy平面で指定した角度回転させた回転行列をセットする - * @param mvp - * @param degrees - */ - protected static void setRotation(final float[] mvp, final int degrees) { - Matrix.setIdentityM(mvp, 0); - if ((degrees % 180) != 0) { - Matrix.rotateM(mvp, 0, degrees, 0.0f, 0.0f, 1.0f); - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/DumbRenderer.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/DumbRenderer.java deleted file mode 100644 index 2f4f5db2f0..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/DumbRenderer.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.SurfaceTexture; -import android.util.Log; -import android.view.Surface; - -import androidx.annotation.NonNull; - -/** - * OpenGL|ESでのSurfaceへの描画処理をDelegaterを介して行うためのIRenderer - */ -public class DumbRenderer implements IRenderer { -// private static final boolean DEBUG = BuildConfig.DEBUG && false; - private static final String TAG = DumbRenderer.class.getSimpleName(); - - public interface RendererDelegater { - public void onStart(final EGLBase eglBase); - public void onStop(final EGLBase eglBase); - public void onSetSurface(final EGLBase eglBase, final Object surface); - public void onResize(final EGLBase eglBase, final int width, final int height); - /** - * 描画実行 - * @param eglBase - * @param args #requestRenderの引数 - */ - public void onDraw(final EGLBase eglBase, final Object... args); - public void onMirror(final EGLBase eglBase, final int mirror); - } - - /** レンダリングスレッドの排他制御用オブジェクト */ - private final Object mSync = new Object(); - private RendererTask mRendererTask; - @MirrorMode - private int mMirror = MIRROR_NORMAL; - - public DumbRenderer(final EGLBase.IContext sharedContext, - final int flags, final RendererDelegater delegater) { - - this(3, sharedContext, flags, delegater); - } - - public DumbRenderer(final int maxClientVersion, - final EGLBase.IContext sharedContext, - final int flags, final RendererDelegater delegater) { - - mRendererTask = new RendererTask(maxClientVersion, sharedContext, flags, delegater); - new Thread(mRendererTask, TAG).start(); - if (!mRendererTask.waitReady()) { - // 初期化に失敗した時 - throw new RuntimeException("failed to start renderer thread"); - } - } - - @Override - public void release() { - synchronized (mSync) { - if (mRendererTask != null) { - // 描画タスクを開放 - mRendererTask.release(); - mRendererTask = null; - } - } - } - - @Override - public void setSurface(final Surface surface) { - synchronized (mSync) { - if (mRendererTask != null) { - mRendererTask.offer(REQUEST_SET_SURFACE, surface); - } - } - } - - @Override - public void setSurface(final SurfaceTexture surface) { - synchronized (mSync) { - if (mRendererTask != null) { - mRendererTask.offer(REQUEST_SET_SURFACE, surface); - } - } - } - - @Override - public void setMirror(@MirrorMode final int mirror) { - synchronized (mSync) { - if (mMirror != mirror) { - mMirror = mirror; - if (mRendererTask != null) { - mRendererTask.offer(REQUEST_MIRROR, mirror % 4); - } - } - } - } - - @Override - @MirrorMode - public int getMirror() { - return mMirror; - } - - @Override - public void resize(final int width, final int height) { - synchronized (mSync) { - if (mRendererTask != null) { - mRendererTask.offer(REQUEST_RESIZE, width, height); - } - } - } - - @Override - public void requestRender(final Object... args) { - synchronized (mSync) { - if (mRendererTask != null) { - mRendererTask.offer(REQUEST_DRAW, args); - } - } - } - - private static final int REQUEST_SET_SURFACE = 1; - private static final int REQUEST_DRAW = 2; - private static final int REQUEST_RESIZE = 3; - private static final int REQUEST_MIRROR = 4; - - private static class RendererTask extends EglTask { - private final RendererDelegater mDelegater; - /** 最後にレンダリングしたフレームサイズ, 0ならまで一度も描画されていない */ - private int frameWidth, frameHeight, frameRotation; - /** 描画先Surfaceのサイズ */ - private int surfaceWidth, surfaceHeight; - /** 映像を左右反転させるかどうか */ - private boolean mirror; - - public RendererTask(final EGLBase.IContext sharedContext, - final int flags, @NonNull final RendererDelegater delegater) { - - this(3, sharedContext, flags, delegater); - } - - public RendererTask(final int maxClientVersion, - final EGLBase.IContext sharedContext, - final int flags, @NonNull final RendererDelegater delegater) { - - super(maxClientVersion, sharedContext, flags); - mDelegater = delegater; - } - - @Override - protected void onStart() { - makeCurrent(); - try { - mDelegater.onStart(getEgl()); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - - @Override - protected void onStop() { - makeCurrent(); - try { - mDelegater.onStop(getEgl()); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - - @Override - protected Object processRequest(final int request, - final int arg1, final int arg2, final Object obj) throws TaskBreak { - - switch (request) { - case REQUEST_SET_SURFACE: - handleSetSurface(obj); - break; - case REQUEST_DRAW: - handleDraw(obj); - break; - case REQUEST_RESIZE: - handleResize(arg1, arg2); - break; - case REQUEST_MIRROR: - handleMirror(arg1); - break; - } - return null; - } - - private void handleSetSurface(final Object surface) { - makeCurrent(); - try { - mDelegater.onSetSurface(getEgl(), surface); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - - private void handleResize(final int width, final int height) { - if ((surfaceWidth != width) || (surfaceHeight != height)) { - surfaceWidth = width; - surfaceHeight = height; - makeCurrent(); - try { - mDelegater.onResize(getEgl(), width, height); - } catch (final Exception e) { - Log.w(TAG, e); - } - handleDraw(); - } - } - - private void handleDraw(final Object... args) { - makeCurrent(); - try { - mDelegater.onDraw(getEgl(), args); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - - private void handleMirror(final int mirror) { - makeCurrent(); - try { - mDelegater.onMirror(getEgl(), mirror); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase.java deleted file mode 100644 index 1a5b9fe61e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.os.Build; - -/** - * EGLレンダリングコンテキストを生成&使用するためのヘルパークラス - */ -public abstract class EGLBase { - public static final Object EGL_LOCK = new Object(); - - public static final int EGL_RECORDABLE_ANDROID = 0x3142; - public static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - public static final int EGL_OPENGL_ES2_BIT = 4; - public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; -// public static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; - - /** - * EGL生成のヘルパーメソッド, 環境に応じてEGLBase10またはEGLBase14を生成する - * maxClientVersion=3, ステンシルバッファなし - * @param sharedContext - * @param withDepthBuffer - * @param isRecordable - * @return - */ - public static EGLBase createFrom(final IContext sharedContext, - final boolean withDepthBuffer, final boolean isRecordable) { - - return createFrom(3, sharedContext, withDepthBuffer, 0, isRecordable); - } - - /** - * EGL生成のヘルパーメソッド, 環境に応じてEGLBase10またはEGLBase14を生成する - * maxClientVersion=3 - * @param sharedContext - * @param withDepthBuffer - * @param stencilBits - * @param isRecordable - * @return - */ - public static EGLBase createFrom(final IContext sharedContext, - final boolean withDepthBuffer, final int stencilBits, final boolean isRecordable) { - - return createFrom(3, sharedContext, - withDepthBuffer, stencilBits, isRecordable); - } - - /** - * EGL生成のヘルパーメソッド, 環境に応じてEGLBase10またはEGLBase14を生成する - * @param maxClientVersion - * @param sharedContext - * @param withDepthBuffer trueなら16ビットのデプスバッファ有り, falseならデプスバッファなし - * @param stencilBits 0以下ならステンシルバッファなし - * @param isRecordable - * @return - */ - public static EGLBase createFrom(final int maxClientVersion, - final IContext sharedContext, final boolean withDepthBuffer, - final int stencilBits, final boolean isRecordable) { - - if (isEGL14Supported() && ((sharedContext == null) - || (sharedContext instanceof EGLBase14.Context))) { - - return new EGLBase14(maxClientVersion, - (EGLBase14.Context)sharedContext, - withDepthBuffer, stencilBits, isRecordable); - } else { - return new EGLBase10(maxClientVersion, - (EGLBase10.Context)sharedContext, - withDepthBuffer, stencilBits, isRecordable); - } - } - - /** - * EGLレンダリングコンテキストのホルダークラス - */ - public static abstract class IContext { - public abstract long getNativeHandle(); - public abstract Object getEGLContext(); - } - - /** - * EGLコンフィグのホルダークラス - */ - public static abstract class IConfig { - } - - /** - * EGLレンダリングコンテキストに紐付ける描画オブジェクト - */ - public interface IEglSurface { - public void makeCurrent(); - public void swap(); - - public IContext getContext(); - /** - * swap with presentation time[ns] - * only works well now when using EGLBase14 - * @param presentationTimeNs - */ - public void swap(final long presentationTimeNs); - public void release(); - public boolean isValid(); - } - - public static boolean isEGL14Supported() { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2); - } - - /** - * 関連するリソースを破棄する - */ - public abstract void release(); - /** - * GLESに文字列を問い合わせる - * @param what - * @return - */ - public abstract String queryString(final int what); - /** - * GLESバージョンを取得する - * @return 1, 2または3 - */ - public abstract int getGlVersion(); - /** - * EGLレンダリングコンテキストを取得する - * このEGLBaseインスタンスを使って生成したEglSurfaceをmakeCurrentした状態で - * eglGetCurrentContextを呼び出すのと一緒 - * @return - */ - public abstract IContext getContext(); - - /** - * EGLコンフィグを取得する - * @return - */ - public abstract IConfig getConfig(); - - /** - * 指定したSurfaceからEglSurfaceを生成する - * 生成したEglSurfaceをmakeCurrentした状態で戻る - * @param nativeWindow Surface/SurfaceTexture/SurfaceHolder - * @return - */ - public abstract IEglSurface createFromSurface(final Object nativeWindow); - /** - * 指定した大きさのオフスクリーンEglSurfaceを生成する - * 生成したEglSurfaceをmakeCurrentした状態で戻る - * @param width PBufferオフスクリーンのサイズ(0以下はだめ) - * @param height - * @return - */ - public abstract IEglSurface createOffscreen(final int width, final int height); - /** - * EGLレンダリングコンテキストとスレッドの紐付けを解除する - */ - public abstract void makeDefault(); - - /** - * eglWaitGLとeglWaitNativeを呼ぶ - * - * eglWaitGL: コマンドキュー内のコマンドをすべて転送する, GLES20.glFinish()と同様の効果 - * eglWaitNative: GPU側の描画処理が終了するまで実行をブロックする - */ - public abstract void sync(); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase10.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase10.java deleted file mode 100644 index c5ae0e2dd8..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase10.java +++ /dev/null @@ -1,724 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; -import android.opengl.GLES10; -import android.opengl.GLES20; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.serenegiant.utils.BuildCheck; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.egl.EGLSurface; - -/** - * EGLレンダリングコンテキストを生成&使用するためのヘルパークラス - */ -/*package*/ class EGLBase10 extends EGLBase { -// private static final boolean DEBUG = false; // FIXME set false on release - private static final String TAG = "EGLBase10"; - - private EGL10 mEgl = null; - private EGLDisplay mEglDisplay = null; - private Config mEglConfig = null; - private int mGlVersion = 2; - - private static final Context EGL_NO_CONTEXT = new Context(EGL10.EGL_NO_CONTEXT); - @NonNull private Context mContext = EGL_NO_CONTEXT; - - /** - * EGLレンダリングコンテキストのホルダークラス - */ - public static class Context extends IContext { - public final EGLContext eglContext; - - private Context(final EGLContext context) { - eglContext = context; - } - - @Override - public long getNativeHandle() { - return 0L; - } - - @Override - public Object getEGLContext() { - return eglContext; - } - } - - public static class Config extends IConfig { - public final EGLConfig eglConfig; - - private Config(final EGLConfig eglConfig) { - this.eglConfig = eglConfig; - } - } - - /** - * Android4.1.2だとSurfaceを使えない。 - * SurfaceTexture/SurfaceHolderの場合は内部でSurfaceを生成して使っているにもかかわらず。 - * SurfaceHolderはインターフェースなのでSurfaceHolderを継承したダミークラスを生成して食わす - */ - public static class MySurfaceHolder implements SurfaceHolder { - private final Surface surface; - - public MySurfaceHolder(final Surface surface) { - this.surface = surface; - } - @Override - public Surface getSurface() { - return surface; - } - // ここより下はどないでもええ - @Override - public void addCallback(final Callback callback) { - } - @Override - public void removeCallback(final Callback callback) { - } - @Override - public boolean isCreating() { - return false; - } - @Override - public void setType(final int type) { - } - @Override - public void setFixedSize(final int width, final int height) { - } - @Override - public void setSizeFromLayout() { - } - @Override - public void setFormat(final int format) { - } - @Override - public void setKeepScreenOn(final boolean screenOn) { - } - @Override - public Canvas lockCanvas() { - return null; - } - @Override - public Canvas lockCanvas(final Rect dirty) { - return null; - } - @Override - public void unlockCanvasAndPost(final Canvas canvas) { - } - @Override - public Rect getSurfaceFrame() { - return null; - } - } - - /** - * EGLレンダリングコンテキストに紐付ける描画オブジェクト - */ - public static class EglSurface implements IEglSurface { - private final EGLBase10 mEglBase; - private EGLSurface mEglSurface = EGL10.EGL_NO_SURFACE; - - /** - * Surface(Surface/SurfaceTexture/SurfaceHolder)に関係付けられたEglSurface - * @param eglBase - * @param surface - */ - private EglSurface(final EGLBase10 eglBase, final Object surface) - throws IllegalArgumentException { - -// if (DEBUG) Log.v(TAG, "EglSurface:"); - mEglBase = eglBase; - if ((surface instanceof Surface) && !BuildCheck.isAndroid4_2()) { - // Android4.1.2だとSurfaceを使えない。 - // SurfaceTexture/SurfaceHolderの場合は内部で - // Surfaceを生成して使っているにもかかわらず。 - // SurfaceHolderはインターフェースなのでSurfaceHolderを - // 継承したダミークラスを生成して食わす - mEglSurface = mEglBase.createWindowSurface( - new MySurfaceHolder((Surface) surface)); - } else if ((surface instanceof Surface) - || (surface instanceof SurfaceHolder) - || (surface instanceof SurfaceTexture) - || (surface instanceof SurfaceView)) { - mEglSurface = mEglBase.createWindowSurface(surface); - } else { - throw new IllegalArgumentException("unsupported surface"); - } - } - - /** - * 指定した大きさを持つオフスクリーンEglSurface(PBuffer) - * @param eglBase - * @param width - * @param height - */ - private EglSurface(final EGLBase10 eglBase, final int width, final int height) { -// if (DEBUG) Log.v(TAG, "EglSurface:"); - mEglBase = eglBase; - if ((width <= 0) || (height <= 0)) { - mEglSurface = mEglBase.createOffscreenSurface(1, 1); - } else { - mEglSurface = mEglBase.createOffscreenSurface(width, height); - } - } - - /** - * 指定したEGLSurfaceをカレントの描画Surfaceに設定する - * Surface全面に描画できるようにViewportも変更するので必要であればswapの後に変更すること - */ - @Override - public void makeCurrent() { - mEglBase.makeCurrent(mEglSurface); - if (mEglBase.getGlVersion() >= 2) { - GLES20.glViewport(0, 0, - mEglBase.getSurfaceWidth(mEglSurface), mEglBase.getSurfaceHeight(mEglSurface)); - } else { - GLES10.glViewport(0, 0, - mEglBase.getSurfaceWidth(mEglSurface), mEglBase.getSurfaceHeight(mEglSurface)); - } - } - - /** - * 描画を終了してダブルバッファを切り替える - */ - @Override - public void swap() { - mEglBase.swap(mEglSurface); - } - - @Override - public void swap(final long presentationTimeNs) { - mEglBase.swap(mEglSurface, presentationTimeNs); - } - - @Override - public IContext getContext() { - return mEglBase.getContext(); - } - - public void setPresentationTime(final long presentationTimeNs) { -// EGLExt.eglPresentationTimeANDROID(mEglBase.mEglDisplay, -// mEglSurface, presentationTimeNs); - } - - /** - * EGLSurfaceが有効かどうかを取得 - * @return - */ - @Override - public boolean isValid() { - return (mEglSurface != null) - && (mEglSurface != EGL10.EGL_NO_SURFACE) - && (mEglBase.getSurfaceWidth(mEglSurface) > 0) - && (mEglBase.getSurfaceHeight(mEglSurface) > 0); - } - - /** - * 破棄処理 - */ - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "EglSurface:release:"); - mEglBase.makeDefault(); - mEglBase.destroyWindowSurface(mEglSurface); - mEglSurface = EGL10.EGL_NO_SURFACE; - } - } - - /** - * コンストラクタ - * @param maxClientVersion - * @param sharedContext 共有コンテキストを使用する場合に指定 - * @param withDepthBuffer - * @param isRecordable true MediaCodec等の録画用Surfaceを使用する場合に、 - * EGL_RECORDABLE_ANDROIDフラグ付きでコンフィグする - */ - public EGLBase10(final int maxClientVersion, - final Context sharedContext, final boolean withDepthBuffer, - final int stencilBits, final boolean isRecordable) { - -// if (DEBUG) Log.v(TAG, "Constructor:"); - init(maxClientVersion, sharedContext, withDepthBuffer, stencilBits, isRecordable); - } - - /** - * 関連するリソースを破棄する - */ - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "release:"); - destroyContext(); - mContext = EGL_NO_CONTEXT; - if (mEgl == null) return; - mEgl.eglMakeCurrent(mEglDisplay, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); -// mEgl.eglReleaseThread(); // XXX これを入れるとハングアップする機種がある - mEgl.eglTerminate(mEglDisplay); - mEglDisplay = null; - mEglConfig = null; - mEgl = null; - } - - /** - * 指定したSurfaceからEglSurfaceを生成する - * 生成したEglSurfaceをmakeCurrentした状態で戻る - * @param nativeWindow Surface/SurfaceTexture/SurfaceHolder - * @return - */ - @Override - public EglSurface createFromSurface(final Object nativeWindow) { -// if (DEBUG) Log.v(TAG, "createFromSurface:"); - final EglSurface eglSurface = new EglSurface(this, nativeWindow); - eglSurface.makeCurrent(); - return eglSurface; - } - - /** - * 指定した大きさのオフスクリーンEglSurfaceを生成する - * 生成したEglSurfaceをmakeCurrentした状態で戻る - * @param width PBufferオフスクリーンのサイズ(0以下はだめ) - * @param height - * @return - */ - @Override - public EglSurface createOffscreen(final int width, final int height) { -// if (DEBUG) Log.v(TAG, "createOffscreen:"); - final EglSurface eglSurface = new EglSurface(this, width, height); - eglSurface.makeCurrent(); - return eglSurface; - } - - /** - * EGLレンダリングコンテキストを取得する - * このEGLBaseインスタンスを使って生成したEglSurfaceをmakeCurrentした状態で - * eglGetCurrentContextを呼び出すのと一緒 - * @return - */ - @Override - public Context getContext() { - return mContext; - } - - /** - * EGLコンフィグを取得する - * @return - */ - @Override - public Config getConfig() { - return mEglConfig; - } - - /** - * EGLレンダリングコンテキストとスレッドの紐付けを解除する - */ - @Override - public void makeDefault() { -// if (DEBUG) Log.v(TAG, "makeDefault:"); - if (!mEgl.eglMakeCurrent(mEglDisplay, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) { - - Log.w(TAG, "makeDefault:eglMakeCurrent:err=" + mEgl.eglGetError()); - } - } - - /** - * eglWaitGLとeglWaitNativeを呼ぶ - * - * eglWaitGL: コマンドキュー内のコマンドをすべて転送する, GLES20.glFinish()と同様の効果 - * eglWaitNative: GPU側の描画処理が終了するまで実行をブロックする - */ - @Override - public void sync() { - mEgl.eglWaitGL(); // GLES20.glFinish()と同様の効果 - mEgl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, null); - } - - /** - * GLESに文字列を問い合わせる - * @param what - * @return - */ - @Override - public String queryString(final int what) { - return mEgl.eglQueryString(mEglDisplay, what); - } - - /** - * GLESバージョンを取得する - * @return 1, 2または3 - */ - @Override - public int getGlVersion() { - return mGlVersion; - } - - /** - * 初期化の下請け - * @param maxClientVersion - * @param sharedContext - * @param withDepthBuffer - * @param isRecordable - */ - private final void init(final int maxClientVersion, - @Nullable Context sharedContext, - final boolean withDepthBuffer, final int stencilBits, final boolean isRecordable) { - -// if (DEBUG) Log.v(TAG, "init:"); - sharedContext = (sharedContext != null) ? sharedContext : EGL_NO_CONTEXT; - if (mEgl == null) { - mEgl = (EGL10)EGLContext.getEGL(); - mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { - throw new RuntimeException("eglGetDisplay failed"); - } - // EGLのバージョンを取得 - final int[] version = new int[2]; - if (!mEgl.eglInitialize(mEglDisplay, version)) { - mEglDisplay = null; - throw new RuntimeException("eglInitialize failed"); - } - } - EGLConfig config; - if (maxClientVersion >= 3) { - // GLES3で取得できるかどうか試してみる - config = getConfig(3, withDepthBuffer, stencilBits, isRecordable); - if (config != null) { - final EGLContext context = createContext(sharedContext, config, 3); - if ((mEgl.eglGetError()) == EGL10.EGL_SUCCESS) { - // ここは例外生成したくないのでcheckEglErrorの代わりに自前でチェック - //Log.d(TAG, "Got GLES 3 config"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 3; - } - } - } - // GLES3で取得できなかった時はGLES2を試みる - if ((maxClientVersion >= 2) - && ((mContext == null) || (mContext.eglContext == EGL10.EGL_NO_CONTEXT))) { - - config = getConfig(2, withDepthBuffer, stencilBits, isRecordable); - if (config == null) { - throw new RuntimeException("chooseConfig failed"); - } - try { - // create EGL rendering context - final EGLContext context = createContext(sharedContext, config, 2); - checkEglError("eglCreateContext"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 2; - } catch (final Exception e) { - if (isRecordable) { - config = getConfig(2, withDepthBuffer, stencilBits, false); - if (config == null) { - throw new RuntimeException("chooseConfig failed"); - } - // create EGL rendering context - final EGLContext context = createContext(sharedContext, config, 2); - checkEglError("eglCreateContext"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 2; - } - } - } - if ((mContext == null) || (mContext.eglContext == EGL10.EGL_NO_CONTEXT)) { - config = getConfig(1, withDepthBuffer, stencilBits, isRecordable); - if (config == null) { - throw new RuntimeException("chooseConfig failed"); - } - // create EGL rendering context - final EGLContext context = createContext(sharedContext, config, 1); - checkEglError("eglCreateContext"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 1; - } - // confirm whether the EGL rendering context is successfully created - final int[] values = new int[1]; - mEgl.eglQueryContext(mEglDisplay, - mContext.eglContext, EGL_CONTEXT_CLIENT_VERSION, values); - Log.d(TAG, "EGLContext created, client version " + values[0]); - makeDefault(); - } - - /** - * change context to draw this window surface - * @return - */ - private final boolean makeCurrent(final EGLSurface surface) { -// if (DEBUG) Log.v(TAG, "makeCurrent:"); -/* if (mEglDisplay == null) { - if (DEBUG) Log.d(TAG, "makeCurrent:eglDisplay not initialized"); - } */ - if (surface == null || surface == EGL10.EGL_NO_SURFACE) { - final int error = mEgl.eglGetError(); - if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { - Log.e(TAG, "makeCurrent:EGL_BAD_NATIVE_WINDOW"); - } - return false; - } - // attach EGL rendering context to specific EGL window surface - if (!mEgl.eglMakeCurrent(mEglDisplay, surface, surface, mContext.eglContext)) { - Log.w("TAG", "eglMakeCurrent" + mEgl.eglGetError()); - return false; - } - return true; - } - - private final int swap(final EGLSurface surface) { -// if (DEBUG) Log.v(TAG, "swap:"); - if (!mEgl.eglSwapBuffers(mEglDisplay, surface)) { - final int err = mEgl.eglGetError(); -// if (DEBUG) Log.w(TAG, "swap:err=" + err); - return err; - } - return EGL10.EGL_SUCCESS; - } - - /** - * swap rendering buffer with presentation time[ns] - * presentationTimeNs is ignored on this method - * @param surface - * @param ignored - * @return - */ - private final int swap(final EGLSurface surface, final long ignored) { -// if (DEBUG) Log.v(TAG, "swap:"); -// EGLExt.eglPresentationTimeANDROID(mEglDisplay, surface, presentationTimeNs); - if (!mEgl.eglSwapBuffers(mEglDisplay, surface)) { - final int err = mEgl.eglGetError(); -// if (DEBUG) Log.w(TAG, "swap:err=" + err); - return err; - } - return EGL10.EGL_SUCCESS; - } - - private final EGLContext createContext( - @NonNull final Context sharedContext, - final EGLConfig config, final int version) { - -// if (DEBUG) Log.v(TAG, "createContext:"); - - final int[] attrib_list = { - EGL_CONTEXT_CLIENT_VERSION, version, - EGL10.EGL_NONE - }; - final EGLContext context = mEgl.eglCreateContext( - mEglDisplay, config, sharedContext.eglContext, attrib_list); -// checkEglError("eglCreateContext"); - return context; - } - - private final void destroyContext() { -// if (DEBUG) Log.v(TAG, "destroyContext:"); - - if (!mEgl.eglDestroyContext(mEglDisplay, mContext.eglContext)) { - Log.e("destroyContext", "display:" + mEglDisplay - + " context: " + mContext.eglContext); - Log.e(TAG, "eglDestroyContext:" + mEgl.eglGetError()); - } - mContext = EGL_NO_CONTEXT; - } - - private final int getSurfaceWidth(final EGLSurface surface) { - final int[] value = new int[1]; - final boolean ret = mEgl.eglQuerySurface(mEglDisplay, - surface, EGL10.EGL_WIDTH, value); - if (!ret) value[0] = 0; - return value[0]; - } - - private final int getSurfaceHeight(final EGLSurface surface) { - final int[] value = new int[1]; - final boolean ret = mEgl.eglQuerySurface(mEglDisplay, - surface, EGL10.EGL_HEIGHT, value); - if (!ret) value[0] = 0; - return value[0]; - } - - /** - * nativeWindow should be one of the SurfaceView, Surface, SurfaceHolder and SurfaceTexture - * @param nativeWindow - * @return - */ - private final EGLSurface createWindowSurface(final Object nativeWindow) { -// if (DEBUG) Log.v(TAG, "createWindowSurface:nativeWindow=" + nativeWindow); - - final int[] surfaceAttribs = { - EGL10.EGL_NONE - }; - EGLSurface result = null; - try { - result = mEgl.eglCreateWindowSurface(mEglDisplay, - mEglConfig.eglConfig, nativeWindow, surfaceAttribs); - if (result == null || result == EGL10.EGL_NO_SURFACE) { - final int error = mEgl.eglGetError(); - if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { - Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); - } - throw new RuntimeException("createWindowSurface failed error=" + error); - } - makeCurrent(result); - // 画面サイズ・フォーマットの取得 - } catch (final Exception e) { - Log.e(TAG, "eglCreateWindowSurface", e); - throw new IllegalArgumentException(e); - } - return result; - } - - /** - * Creates an EGL surface associated with an offscreen buffer. - */ - private final EGLSurface createOffscreenSurface(final int width, final int height) { -// if (DEBUG) Log.v(TAG, "createOffscreenSurface:"); - final int[] surfaceAttribs = { - EGL10.EGL_WIDTH, width, - EGL10.EGL_HEIGHT, height, - EGL10.EGL_NONE - }; - mEgl.eglWaitGL(); - EGLSurface result = null; - try { - result = mEgl.eglCreatePbufferSurface(mEglDisplay, - mEglConfig.eglConfig, surfaceAttribs); - checkEglError("eglCreatePbufferSurface"); - if (result == null) { - throw new RuntimeException("surface was null"); - } - } catch (final IllegalArgumentException e) { - Log.e(TAG, "createOffscreenSurface", e); - } catch (final RuntimeException e) { - Log.e(TAG, "createOffscreenSurface", e); - } - return result; - } - - private final void destroyWindowSurface(EGLSurface surface) { -// if (DEBUG) Log.v(TAG, "destroySurface:"); - - if (surface != EGL10.EGL_NO_SURFACE) { - mEgl.eglMakeCurrent(mEglDisplay, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - mEgl.eglDestroySurface(mEglDisplay, surface); - } - surface = EGL10.EGL_NO_SURFACE; -// if (DEBUG) Log.v(TAG, "destroySurface:finished"); - } - - private final void checkEglError(final String msg) { - int error; - if ((error = mEgl.eglGetError()) != EGL10.EGL_SUCCESS) { - throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error)); - } - } - - private final EGLConfig getConfig(final int version, - final boolean hasDepthBuffer, final int stencilBits, final boolean isRecordable) { - - int renderableType = EGL_OPENGL_ES2_BIT; - if (version >= 3) { - renderableType |= EGL_OPENGL_ES3_BIT_KHR; - } -// final int swapBehavior = dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; - final int[] attribList = { - EGL10.EGL_RENDERABLE_TYPE, renderableType, - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_ALPHA_SIZE, 8, -// EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT | swapBehavior, - EGL10.EGL_NONE, EGL10.EGL_NONE, //EGL10.EGL_STENCIL_SIZE, 8, - // this flag need to recording of MediaCodec - EGL10.EGL_NONE, EGL10.EGL_NONE, // EGL_RECORDABLE_ANDROID, 1, - EGL10.EGL_NONE, EGL10.EGL_NONE, // with_depth_buffer ? EGL10.EGL_DEPTH_SIZE : EGL10.EGL_NONE, - // with_depth_buffer ? 16 : 0, - EGL10.EGL_NONE - }; - int offset = 10; - if (stencilBits > 0) { // ステンシルバッファ(常時未使用) - attribList[offset++] = EGL10.EGL_STENCIL_SIZE; - attribList[offset++] = 8; - } - if (hasDepthBuffer) { // デプスバッファ - attribList[offset++] = EGL10.EGL_DEPTH_SIZE; - attribList[offset++] = 16; - } - if (isRecordable && BuildCheck.isAndroid4_3()) { - // MediaCodecの入力用Surfaceの場合 - // A-1000F(Android4.1.2)はこのフラグをつけるとうまく動かない - attribList[offset++] = EGL_RECORDABLE_ANDROID; - attribList[offset++] = 1; - } - for (int i = attribList.length - 1; i >= offset; i--) { - attribList[i] = EGL10.EGL_NONE; - } - EGLConfig config = internalGetConfig(attribList); - if ((config == null) && (version == 2)) { - if (isRecordable) { - // EGL_RECORDABLE_ANDROIDをつけると失敗する機種もあるので取り除く - final int n = attribList.length; - for (int i = 10; i < n - 1; i += 2) { - if (attribList[i] == EGL_RECORDABLE_ANDROID) { - for (int j = i; j < n; j++) { - attribList[j] = EGL10.EGL_NONE; - } - break; - } - } - config = internalGetConfig(attribList); - } - } - if (config == null) { - Log.w(TAG, "try to fallback to RGB565"); - attribList[3] = 5; - attribList[5] = 6; - attribList[7] = 5; - config = internalGetConfig(attribList); - } - return config; - } - - private EGLConfig internalGetConfig(final int[] attribList) { - final EGLConfig[] configs = new EGLConfig[1]; - final int[] numConfigs = new int[1]; - if (!mEgl.eglChooseConfig(mEglDisplay, - attribList, configs, configs.length, numConfigs)) { - - return null; - } - return configs[0]; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase14.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase14.java deleted file mode 100644 index fb119a4641..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EGLBase14.java +++ /dev/null @@ -1,631 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.graphics.SurfaceTexture; -import android.opengl.EGL14; -import android.opengl.EGLConfig; -import android.opengl.EGLContext; -import android.opengl.EGLDisplay; -import android.opengl.EGLExt; -import android.opengl.EGLSurface; -import android.opengl.GLES10; -import android.opengl.GLES20; -import android.os.Build; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -import androidx.annotation.NonNull; - -import com.serenegiant.utils.BuildCheck; - -/** - * EGLレンダリングコンテキストを生成&使用するためのヘルパークラス - */ -@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) -/*package*/ class EGLBase14 extends EGLBase { // API >= 17 -// private static final boolean DEBUG = false; // TODO set false on release - private static final String TAG = "EGLBase14"; - - private static final Context EGL_NO_CONTEXT = new Context(EGL14.EGL_NO_CONTEXT); - - private Config mEglConfig = null; - @NonNull private Context mContext = EGL_NO_CONTEXT; -// private EGLContext mEglContext = EGL14.EGL_NO_CONTEXT; - private EGLDisplay mEglDisplay = EGL14.EGL_NO_DISPLAY; - private EGLContext mDefaultContext = EGL14.EGL_NO_CONTEXT; - private int mGlVersion = 2; - - /** - * EGLレンダリングコンテキストのホルダークラス - */ - public static class Context extends IContext { - public final EGLContext eglContext; - - private Context(final EGLContext context) { - eglContext = context; - } - - @Override - @SuppressLint("NewApi") - public long getNativeHandle() { - return eglContext != null ? - (BuildCheck.isLollipop() - ? eglContext.getNativeHandle() : eglContext.getHandle()) : 0L; - } - - @Override - public Object getEGLContext() { - return eglContext; - } - } - - public static class Config extends IConfig { - public final EGLConfig eglConfig; - - private Config(final EGLConfig eglConfig) { - this.eglConfig = eglConfig; - } - } - - /** - * EGLレンダリングコンテキストに紐付ける描画オブジェクト - */ - public static class EglSurface implements IEglSurface { - private final EGLBase14 mEglBase; - private EGLSurface mEglSurface = EGL14.EGL_NO_SURFACE; - - private EglSurface(final EGLBase14 eglBase, final Object surface) - throws IllegalArgumentException { - -// if (DEBUG) Log.v(TAG, "EglSurface:"); - mEglBase = eglBase; - if ((surface instanceof Surface) - || (surface instanceof SurfaceHolder) - || (surface instanceof SurfaceTexture) - || (surface instanceof SurfaceView)) { - mEglSurface = mEglBase.createWindowSurface(surface); - } else { - throw new IllegalArgumentException("unsupported surface"); - } - } - - /** - * 指定した大きさを持つオフスクリーンEglSurface(PBuffer) - * @param eglBase - * @param width - * @param height - */ - private EglSurface(final EGLBase14 eglBase, - final int width, final int height) { - -// if (DEBUG) Log.v(TAG, "EglSurface:"); - mEglBase = eglBase; - if ((width <= 0) || (height <= 0)) { - mEglSurface = mEglBase.createOffscreenSurface(1, 1); - } else { - mEglSurface = mEglBase.createOffscreenSurface(width, height); - } - } - - @Override - public void makeCurrent() { - mEglBase.makeCurrent(mEglSurface); - if (mEglBase.getGlVersion() >= 2) { - GLES20.glViewport(0, 0, - mEglBase.getSurfaceWidth(mEglSurface), - mEglBase.getSurfaceHeight(mEglSurface)); - } else { - GLES10.glViewport(0, 0, - mEglBase.getSurfaceWidth(mEglSurface), - mEglBase.getSurfaceHeight(mEglSurface)); - } - } - - @Override - public void swap() { - mEglBase.swap(mEglSurface); - } - - @Override - public void swap(final long presentationTimeNs) { - mEglBase.swap(mEglSurface, presentationTimeNs); - } - - public void setPresentationTime(final long presentationTimeNs) { - EGLExt.eglPresentationTimeANDROID(mEglBase.mEglDisplay, - mEglSurface, presentationTimeNs); - } - - @Override - public IContext getContext() { - return mEglBase.getContext(); - } - - @Override - public boolean isValid() { - return (mEglSurface != null) - && (mEglSurface != EGL14.EGL_NO_SURFACE) - && (mEglBase.getSurfaceWidth(mEglSurface) > 0) - && (mEglBase.getSurfaceHeight(mEglSurface) > 0); - } - - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "EglSurface:release:"); - mEglBase.makeDefault(); - mEglBase.destroyWindowSurface(mEglSurface); - mEglSurface = EGL14.EGL_NO_SURFACE; - } - } - - /** - * コンストラクタ - * @param maxClientVersion - * @param sharedContext - * @param withDepthBuffer - * @param isRecordable - */ - public EGLBase14(final int maxClientVersion, - final Context sharedContext, final boolean withDepthBuffer, - final int stencilBits, final boolean isRecordable) { - -// if (DEBUG) Log.v(TAG, "Constructor:"); - init(maxClientVersion, sharedContext, withDepthBuffer, stencilBits, isRecordable); - } - - /** - * 関連するリソースを破棄する - */ - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "release:"); - if (mEglDisplay != EGL14.EGL_NO_DISPLAY) { - destroyContext(); - EGL14.eglTerminate(mEglDisplay); - EGL14.eglReleaseThread(); - } - mEglDisplay = EGL14.EGL_NO_DISPLAY; - mContext = EGL_NO_CONTEXT; - } - - /** - * 指定したSurfaceからEglSurfaceを生成する - * 生成したEglSurfaceをmakeCurrentした状態で戻る - * @param nativeWindow Surface/SurfaceTexture/SurfaceHolder - * @return - */ - @Override - public EglSurface createFromSurface(final Object nativeWindow) { -// if (DEBUG) Log.v(TAG, "createFromSurface:"); - final EglSurface eglSurface = new EglSurface(this, nativeWindow); - eglSurface.makeCurrent(); - return eglSurface; - } - - /** - * 指定した大きさのオフスクリーンEglSurfaceを生成する - * 生成したEglSurfaceをmakeCurrentした状態で戻る - * @param width PBufferオフスクリーンのサイズ(0以下はだめ) - * @param height - * @return - */ - @Override - public EglSurface createOffscreen(final int width, final int height) { -// if (DEBUG) Log.v(TAG, "createOffscreen:"); - final EglSurface eglSurface = new EglSurface(this, width, height); - eglSurface.makeCurrent(); - return eglSurface; - } - - /** - * GLESに文字列を問い合わせる - * @param what - * @return - */ - public String queryString(final int what) { - return EGL14.eglQueryString(mEglDisplay, what); - } - - /** - * GLESバージョンを取得する - * @return 1, 2または3 - */ - @Override - public int getGlVersion() { - return mGlVersion; - } - - /** - * EGLレンダリングコンテキストを取得する - * このEGLBaseインスタンスを使って生成したEglSurfaceをmakeCurrentした状態で - * eglGetCurrentContextを呼び出すのと一緒 - * @return - */ - @Override - public Context getContext() { - return mContext; - } - - /** - * EGLコンフィグを取得する - * @return - */ - @Override - public Config getConfig() { - return mEglConfig; - } - - /** - * EGLレンダリングコンテキストとスレッドの紐付けを解除する - */ - @Override - public void makeDefault() { -// if (DEBUG) Log.v(TAG, "makeDefault:"); - if (!EGL14.eglMakeCurrent(mEglDisplay, - EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) { - - Log.w("TAG", "makeDefault" + EGL14.eglGetError()); - } - } - - /** - * eglWaitGLとeglWaitNativeを呼ぶ - * - * eglWaitGL: コマンドキュー内のコマンドをすべて転送する, GLES20.glFinish()と同様の効果 - * eglWaitNative: GPU側の描画処理が終了するまで実行をブロックする - */ - @Override - public void sync() { - EGL14.eglWaitGL(); // GLES20.glFinish()と同様の効果 - EGL14.eglWaitNative(EGL14.EGL_CORE_NATIVE_ENGINE); - } - - private void init(final int maxClientVersion, Context sharedContext, - final boolean withDepthBuffer, final int stencilBits, final boolean isRecordable) { - -// if (DEBUG) Log.v(TAG, "init:"); - if (mEglDisplay != EGL14.EGL_NO_DISPLAY) { - throw new RuntimeException("EGL already set up"); - } - - mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); - if (mEglDisplay == EGL14.EGL_NO_DISPLAY) { - throw new RuntimeException("eglGetDisplay failed"); - } - // EGLのバージョンを取得 - final int[] version = new int[2]; - if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) { - mEglDisplay = null; - throw new RuntimeException("eglInitialize failed"); - } - - sharedContext = (sharedContext != null) ? sharedContext : EGL_NO_CONTEXT; - - EGLConfig config; - if (maxClientVersion >= 3) { - // GLES3で取得できるかどうか試してみる - config = getConfig(3, withDepthBuffer, stencilBits, isRecordable); - if (config != null) { - final EGLContext context = createContext(sharedContext, config, 3); - if (EGL14.eglGetError() == EGL14.EGL_SUCCESS) { - // ここは例外生成したくないのでcheckEglErrorの代わりに自前でチェック - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 3; - } - } - } - // GLES3で取得できなかった時はGLES2を試みる - if ((maxClientVersion >= 2) - && ((mContext == null) || (mContext.eglContext == EGL14.EGL_NO_CONTEXT))) { - - config = getConfig(2, withDepthBuffer, stencilBits, isRecordable); - if (config == null) { - throw new RuntimeException("chooseConfig failed"); - } - try { - // create EGL rendering context - final EGLContext context = createContext(sharedContext, config, 2); - checkEglError("eglCreateContext"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 2; - } catch (final Exception e) { - if (isRecordable) { - config = getConfig(2, withDepthBuffer, stencilBits, false); - if (config == null) { - throw new RuntimeException("chooseConfig failed"); - } - // create EGL rendering context - final EGLContext context = createContext(sharedContext, config, 2); - checkEglError("eglCreateContext"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 2; - } - } - } - if ((mContext == null) || (mContext.eglContext == EGL14.EGL_NO_CONTEXT)) { - config = getConfig(1, withDepthBuffer, stencilBits, isRecordable); - if (config == null) { - throw new RuntimeException("chooseConfig failed"); - } - // create EGL rendering context - final EGLContext context = createContext(sharedContext, config, 1); - checkEglError("eglCreateContext"); - mEglConfig = new Config(config); - mContext = new Context(context); - mGlVersion = 1; - } - // confirm whether the EGL rendering context is successfully created - final int[] values = new int[1]; - EGL14.eglQueryContext(mEglDisplay, - mContext.eglContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, values, 0); - Log.d(TAG, "EGLContext created, client version " + values[0]); - makeDefault(); // makeCurrent(EGL14.EGL_NO_SURFACE); - } - - /** - * change context to draw this window surface - * @return - */ - private boolean makeCurrent(final EGLSurface surface) { -// if (DEBUG) Log.v(TAG, "makeCurrent:"); -/* if (mEglDisplay == null) { - if (DEBUG) Log.d(TAG, "makeCurrent:eglDisplay not initialized"); - } */ - if (surface == null || surface == EGL14.EGL_NO_SURFACE) { - final int error = EGL14.eglGetError(); - if (error == EGL14.EGL_BAD_NATIVE_WINDOW) { - Log.e(TAG, "makeCurrent:returned EGL_BAD_NATIVE_WINDOW."); - } - return false; - } - // attach EGL rendering context to specific EGL window surface - if (!EGL14.eglMakeCurrent(mEglDisplay, surface, surface, mContext.eglContext)) { - Log.w("TAG", "eglMakeCurrent" + EGL14.eglGetError()); - return false; - } - return true; - } - - private int swap(final EGLSurface surface) { -// if (DEBUG) Log.v(TAG, "swap:"); - if (!EGL14.eglSwapBuffers(mEglDisplay, surface)) { - final int err = EGL14.eglGetError(); -// if (DEBUG) Log.w(TAG, "swap:err=" + err); - return err; - } - return EGL14.EGL_SUCCESS; - } - - private int swap(final EGLSurface surface, final long presentationTimeNs) { -// if (DEBUG) Log.v(TAG, "swap:"); - EGLExt.eglPresentationTimeANDROID(mEglDisplay, surface, presentationTimeNs); - if (!EGL14.eglSwapBuffers(mEglDisplay, surface)) { - final int err = EGL14.eglGetError(); -// if (DEBUG) Log.w(TAG, "swap:err=" + err); - return err; - } - return EGL14.EGL_SUCCESS; - } - - private EGLContext createContext(final Context sharedContext, - final EGLConfig config, final int version) { - -// if (DEBUG) Log.v(TAG, "createContext:"); - - final int[] attrib_list = { - EGL14.EGL_CONTEXT_CLIENT_VERSION, version, - EGL14.EGL_NONE - }; - final EGLContext context = EGL14.eglCreateContext(mEglDisplay, - config, sharedContext.eglContext, attrib_list, 0); -// checkEglError("eglCreateContext"); - return context; - } - - private void destroyContext() { -// if (DEBUG) Log.v(TAG, "destroyContext:"); - - if (!EGL14.eglDestroyContext(mEglDisplay, mContext.eglContext)) { - Log.e("destroyContext", "display:" + mEglDisplay - + " context: " + mContext.eglContext); - Log.e(TAG, "eglDestroyContext:" + EGL14.eglGetError()); - } - mContext = EGL_NO_CONTEXT; - if (mDefaultContext != EGL14.EGL_NO_CONTEXT) { - if (!EGL14.eglDestroyContext(mEglDisplay, mDefaultContext)) { - Log.e("destroyContext", "display:" + mEglDisplay - + " context: " + mDefaultContext); - Log.e(TAG, "eglDestroyContext:" + EGL14.eglGetError()); - } - mDefaultContext = EGL14.EGL_NO_CONTEXT; - } - } - - private final int[] mSurfaceDimension = new int[2]; - private final int getSurfaceWidth(final EGLSurface surface) { - final boolean ret = EGL14.eglQuerySurface(mEglDisplay, - surface, EGL14.EGL_WIDTH, mSurfaceDimension, 0); - if (!ret) mSurfaceDimension[0] = 0; - return mSurfaceDimension[0]; - } - - private final int getSurfaceHeight(final EGLSurface surface) { - final boolean ret = EGL14.eglQuerySurface(mEglDisplay, - surface, EGL14.EGL_HEIGHT, mSurfaceDimension, 1); - if (!ret) mSurfaceDimension[1] = 0; - return mSurfaceDimension[1]; - } - - /** - * nativeWindow should be one of the Surface, SurfaceHolder and SurfaceTexture - * @param nativeWindow - * @return - */ - private final EGLSurface createWindowSurface(final Object nativeWindow) { -// if (DEBUG) Log.v(TAG, "createWindowSurface:nativeWindow=" + nativeWindow); - - final int[] surfaceAttribs = { - EGL14.EGL_NONE - }; - EGLSurface result = null; - try { - result = EGL14.eglCreateWindowSurface(mEglDisplay, - mEglConfig.eglConfig, nativeWindow, surfaceAttribs, 0); - if (result == null || result == EGL14.EGL_NO_SURFACE) { - final int error = EGL14.eglGetError(); - if (error == EGL14.EGL_BAD_NATIVE_WINDOW) { - Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); - } - throw new RuntimeException("createWindowSurface failed error=" + error); - } - makeCurrent(result); - // 画面サイズ・フォーマットの取得 - } catch (final Exception e) { - Log.e(TAG, "eglCreateWindowSurface", e); - throw new IllegalArgumentException(e); - } - return result; - } - - /** - * Creates an EGL surface associated with an offscreen buffer. - */ - private final EGLSurface createOffscreenSurface(final int width, final int height) { -// if (DEBUG) Log.v(TAG, "createOffscreenSurface:"); - final int[] surfaceAttribs = { - EGL14.EGL_WIDTH, width, - EGL14.EGL_HEIGHT, height, - EGL14.EGL_NONE - }; - EGLSurface result = null; - try { - result = EGL14.eglCreatePbufferSurface(mEglDisplay, - mEglConfig.eglConfig, surfaceAttribs, 0); - checkEglError("eglCreatePbufferSurface"); - if (result == null) { - throw new RuntimeException("surface was null"); - } - } catch (final IllegalArgumentException e) { - Log.e(TAG, "createOffscreenSurface", e); - } catch (final RuntimeException e) { - Log.e(TAG, "createOffscreenSurface", e); - } - return result; - } - - private void destroyWindowSurface(EGLSurface surface) { -// if (DEBUG) Log.v(TAG, "destroySurface:"); - - if (surface != EGL14.EGL_NO_SURFACE) { - EGL14.eglMakeCurrent(mEglDisplay, - EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); - EGL14.eglDestroySurface(mEglDisplay, surface); - } - surface = EGL14.EGL_NO_SURFACE; -// if (DEBUG) Log.v(TAG, "destroySurface:finished"); - } - - private void checkEglError(final String msg) { - int error; - if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) { - throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error)); - } - } - - private EGLConfig getConfig(final int version, - final boolean hasDepthBuffer, final int stencilBits, final boolean isRecordable) { - - int renderableType = EGL_OPENGL_ES2_BIT; - if (version >= 3) { - renderableType |= EGL_OPENGL_ES3_BIT_KHR; - } - final int[] attribList = { - EGL14.EGL_RENDERABLE_TYPE, renderableType, - EGL14.EGL_RED_SIZE, 8, - EGL14.EGL_GREEN_SIZE, 8, - EGL14.EGL_BLUE_SIZE, 8, - EGL14.EGL_ALPHA_SIZE, 8, -// EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT | swapBehavior, - EGL14.EGL_NONE, EGL14.EGL_NONE, //EGL14.EGL_STENCIL_SIZE, 8, - // this flag need to recording of MediaCodec - EGL14.EGL_NONE, EGL14.EGL_NONE, //EGL_RECORDABLE_ANDROID, 1, - EGL14.EGL_NONE, EGL14.EGL_NONE, // with_depth_buffer ? EGL14.EGL_DEPTH_SIZE : EGL14.EGL_NONE, - // with_depth_buffer ? 16 : 0, - EGL14.EGL_NONE - }; - int offset = 10; - if (stencilBits > 0) { // ステンシルバッファ(常時未使用) - attribList[offset++] = EGL14.EGL_STENCIL_SIZE; - attribList[offset++] = stencilBits; - } - if (hasDepthBuffer) { // デプスバッファ - attribList[offset++] = EGL14.EGL_DEPTH_SIZE; - attribList[offset++] = 16; - } - if (isRecordable && BuildCheck.isAndroid4_3()) {// MediaCodecの入力用Surfaceの場合 - attribList[offset++] = EGL_RECORDABLE_ANDROID; - attribList[offset++] = 1; - } - for (int i = attribList.length - 1; i >= offset; i--) { - attribList[i] = EGL14.EGL_NONE; - } - EGLConfig config = internalGetConfig(attribList); - if ((config == null) && (version == 2)) { - if (isRecordable) { - // EGL_RECORDABLE_ANDROIDをつけると失敗する機種もあるので取り除く - final int n = attribList.length; - for (int i = 10; i < n - 1; i += 2) { - if (attribList[i] == EGL_RECORDABLE_ANDROID) { - for (int j = i; j < n; j++) { - attribList[j] = EGL14.EGL_NONE; - } - break; - } - } - config = internalGetConfig(attribList); - } - } - if (config == null) { - Log.w(TAG, "try to fallback to RGB565"); - attribList[3] = 5; - attribList[5] = 6; - attribList[7] = 5; - config = internalGetConfig(attribList); - } - return config; - } - - private EGLConfig internalGetConfig(final int[] attribList) { - final EGLConfig[] configs = new EGLConfig[1]; - final int[] numConfigs = new int[1]; - if (!EGL14.eglChooseConfig(mEglDisplay, - attribList, 0, configs, 0, configs.length, numConfigs, 0)) { - return null; - } - return configs[0]; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EffectRendererHolder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EffectRendererHolder.java deleted file mode 100644 index 5b72592870..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EffectRendererHolder.java +++ /dev/null @@ -1,548 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_SIMPLE_OES; -import static com.serenegiant.glutils.ShaderConst.FUNC_HSV2RGB; -import static com.serenegiant.glutils.ShaderConst.FUNC_RGB2HSV; -import static com.serenegiant.glutils.ShaderConst.HEADER_OES; -import static com.serenegiant.glutils.ShaderConst.SAMPLER_OES; -import static com.serenegiant.glutils.ShaderConst.SHADER_VERSION; - -import android.annotation.SuppressLint; -import android.opengl.GLES20; -import android.util.Log; -import android.util.SparseArray; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -/** - * GL_TEXTURE_EXTERNAL_OESテクスチャを受け取ってSurfaceへ分配描画するクラス - * RendererHolderにフラグメントシェーダーでのフィルター処理を追加 - * ...カラーマトリックスを掛けるほうがいいかなぁ - * ...色はuniform変数で渡す方がいいかも - */ -public class EffectRendererHolder extends AbstractRendererHolder { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = EffectRendererHolder.class.getSimpleName(); - - private static final int MAX_PARAM_NUM = 18; - - public static final int EFFECT_NON = 0; - public static final int EFFECT_GRAY = 1; - public static final int EFFECT_GRAY_REVERSE = 2; - public static final int EFFECT_BIN = 3; - public static final int EFFECT_BIN_YELLOW = 4; - public static final int EFFECT_BIN_GREEN = 5; - public static final int EFFECT_BIN_REVERSE = 6; - public static final int EFFECT_BIN_REVERSE_YELLOW = 7; - public static final int EFFECT_BIN_REVERSE_GREEN = 8; - /** - * 赤色黄色を強調 - * setParamsはfloat[12] { - * 0.17f, 0.85f, // 赤色&黄色の色相下側閾値, 上側閾値 - * 0.50f, 1.0f, // 強調する彩度下限, 上限 - * 0.40f, 1.0f, // 強調する明度下限, 上限 - * 1.0f, 1.0f, 5.0f, // 強調時のファクター(H, S, Vの順) 明度(x5.0) = 1.0 - * 1.0f, 0.5f, 0.8f, // 通常時のファクター(H, S, Vの順) 彩度(x0.5)と明度(x0.8)を少し落とす - * } - */ - public static final int EFFECT_EMPHASIZE_RED_YELLOW = 9; - /** - * 赤色黄色と白を強調 - * setParamsはfloat[12] { - * 0.17f, 0.85f, // 赤色&黄色の色相下側閾値, 上側閾値 - * 0.50f, 1.0f, // 強調する彩度下限, 上限 - * 0.40f, 1.0f, // 強調する明度下限, 上限 - * 1.0f, 1.0f, 5.0f, // 強調時のファクター(H, S, Vの順) 明度(x5.0) = 1.0 - * 1.0f, 0.5f, 0.8f, // 通常時のファクター(H, S, Vの順) 彩度(x0.5)と明度(x0.8)を少し落とす - * 白のパラメータは今はなし - */ - public static final int EFFECT_EMPHASIZE_RED_YELLOW_WHITE = 10; - /** - * 黄色と白を強調 - * setParamsはfloat[12] { - * 0.17f, 0.85f, // 赤色&黄色の色相下側閾値, 上側閾値 FIXME 未調整 - * 0.50f, 1.0f, // 強調する彩度下限, 上限 - * 0.40f, 1.0f, // 強調する明度下限, 上限 - * 1.0f, 1.0f, 5.0f, // 強調時のファクター(H, S, Vの順) 明度(x5.0) = 1.0 - * 1.0f, 0.5f, 0.8f, // 通常時のファクター(H, S, Vの順) 彩度(x0.5)と明度(x0.8)を少し落とす - * 白のパラメータは今はなし - */ - public static final int EFFECT_EMPHASIZE_YELLOW_WHITE = 11; - /** 内蔵映像効果の数 */ - public static final int EFFECT_NUM = 12; - - /** - * グレースケール変換のためのフラグメントシェーダーのベース文字列 - * header(HEADER_OESかHEADER_2D)とサンプラーの種類文字列(SAMPLER_OESかSAMPLER_2D)を渡すこと - */ - private static final String FRAGMENT_SHADER_GRAY_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "const vec3 conv = vec3(0.3, 0.59, 0.11);\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = dot(tc.rgb, conv);\n" + - " vec3 cl3 = vec3(color, color, color);\n" + - " gl_FragColor = vec4(cl3, 1.0);\n" + - "}\n"; - - private static final String FRAGMENT_SHADER_GRAY_OES - = String.format(FRAGMENT_SHADER_GRAY_BASE, HEADER_OES, SAMPLER_OES); - - /** - * 白黒反転したグレースケール変換のためのフラグメントシェーダーのベース文字列 - * header(HEADER_OESかHEADER_2D)とサンプラーの種類文字列(SAMPLER_OESかSAMPLER_2D)を渡すこと - */ - private static final String FRAGMENT_SHADER_GRAY_REVERSE_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "const vec3 conv = vec3(0.3, 0.59, 0.11);\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = dot(tc.rgb, conv);\n" + - " vec3 cl3 = vec3(color, color, color);\n" + - " gl_FragColor = vec4(clamp(vec3(1.0, 1.0, 1.0) - cl3, 0.0, 1.0), 1.0);\n" + - "}\n"; - - private static final String FRAGMENT_SHADER_GRAY_REVERSE_OES - = String.format(FRAGMENT_SHADER_GRAY_REVERSE_BASE, HEADER_OES, SAMPLER_OES); - - /** - * 2値化のためのフラグメントシェーダーのベース文字列 - * header(HEADER_OESかHEADER_2D)とサンプラーの種類文字列(SAMPLER_OESかSAMPLER_2D)、 - * 変換後の明るい部分用の色を指定するための文字列(R, G, Bの順)を渡すこと - */ - private static final String FRAGMENT_SHADER_BIN_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "const vec3 conv = vec3(0.3, 0.59, 0.11);\n" + - "const vec3 cl = vec3(%s);\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = dot(tc.rgb, conv);\n" + - " vec3 bin = step(0.3, vec3(color, color, color));\n" + - " gl_FragColor = vec4(cl * bin, 1.0);\n" + - "}\n"; - - private static final String FRAGMENT_SHADER_BIN_OES - = String.format(FRAGMENT_SHADER_BIN_BASE, HEADER_OES, SAMPLER_OES, "1.0, 1.0, 1.0"); - - private static final String FRAGMENT_SHADER_BIN_YELLOW_OES - = String.format(FRAGMENT_SHADER_BIN_BASE, HEADER_OES, SAMPLER_OES, "1.0, 1.0, 0.0"); - - private static final String FRAGMENT_SHADER_BIN_GREEN_OES - = String.format(FRAGMENT_SHADER_BIN_BASE, HEADER_OES, SAMPLER_OES, "0.0, 1.0, 0.0"); - - /** - * 反転した2値化のためのフラグメントシェーダーのベース文字列 - * header(HEADER_OESかHEADER_2D)とサンプラーの種類文字列(SAMPLER_OESかSAMPLER_2D)、 - * 変換後の明るい部分用の色を指定するための文字列(R, G, Bの順)を渡すこと - */ - private static final String FRAGMENT_SHADER_BIN_REVERSE_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "const vec3 conv = vec3(0.3, 0.59, 0.11);\n" + - "const vec3 cl = vec3(%s);\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = dot(tc.rgb, conv);\n" + - " vec3 bin = step(0.3, vec3(color, color, color));\n" + - " gl_FragColor = vec4(cl * (vec3(1.0, 1.0, 1.0) - bin), 1.0);\n" + - "}\n"; - - private static final String FRAGMENT_SHADER_BIN_REVERSE_OES - = String.format(FRAGMENT_SHADER_BIN_REVERSE_BASE, HEADER_OES, SAMPLER_OES, "1.0, 1.0, 1.0"); - - private static final String FRAGMENT_SHADER_BIN_REVERSE_YELLOW_OES - = String.format(FRAGMENT_SHADER_BIN_REVERSE_BASE, HEADER_OES, SAMPLER_OES, "1.0, 1.0, 0.0"); - - private static final String FRAGMENT_SHADER_BIN_REVERSE_GREEN_OES - = String.format(FRAGMENT_SHADER_BIN_REVERSE_BASE, HEADER_OES, SAMPLER_OES, "0.0, 1.0, 0.0"); - - /** - * 赤と黄色を強調するためのフラグメントシェーダーのベース文字列 - */ - private static final String FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "uniform float uParams[" + MAX_PARAM_NUM + "];\n" + - FUNC_RGB2HSV + - FUNC_HSV2RGB + - "void main() {\n" + - " vec3 hsv = rgb2hsv(texture2D(sTexture, vTextureCoord).rgb);\n" + // RGBをHSVに変換 - " if ( ((hsv.g >= uParams[2]) && (hsv.g <= uParams[3]))\n" + // s - " && ((hsv.b >= uParams[4]) && (hsv.b <= uParams[5]))\n" + // v - " && ((hsv.r <= uParams[0]) || (hsv.r >= uParams[1])) ) {\n" + // h - " hsv = hsv * vec3(uParams[6], uParams[7], uParams[8]);\n" + // 赤色と黄色の範囲 - " } else {\n" + - " hsv = hsv * vec3(uParams[9], uParams[10], uParams[11]);\n" + // それ以外なら - " }\n" + - " gl_FragColor = vec4(hsv2rgb(clamp(hsv, 0.0, 1.0)), 1.0);\n" + // HSVをRGBに戻す - "}\n"; - - private static final String FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_OES - = String.format(FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_BASE, HEADER_OES, SAMPLER_OES); - - /** - * 赤と黄色と白色を強調するためのフラグメントシェーダーのベース文字列 - */ - private static final String FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_WHITE_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "uniform float uParams[" + MAX_PARAM_NUM + "];\n" + - FUNC_RGB2HSV + - FUNC_HSV2RGB + - "void main() {\n" + - " vec3 hsv = rgb2hsv(texture2D(sTexture, vTextureCoord).rgb);\n" + // RGBをHSVに変換 - " if ( ((hsv.g >= uParams[2]) && (hsv.g <= uParams[3]))\n" + // s - " && ((hsv.b >= uParams[4]) && (hsv.b <= uParams[5]))\n" + // v - " && ((hsv.r <= uParams[0]) || (hsv.r >= uParams[1])) ) {\n" + // h - " hsv = hsv * vec3(uParams[6], uParams[7], uParams[8]);\n" + // 赤色と黄色の範囲 - " } else if ((hsv.g < uParams[12]) && (hsv.b < uParams[13])) {\n" + // 彩度が一定以下, 明度が一定以下なら - " hsv = hsv * vec3(1.0, 0.0, 2.0);\n" + // 色相そのまま, 彩度0, 明度x2 - " } else {\n" + - " hsv = hsv * vec3(uParams[9], uParams[10], uParams[11]);\n" + // それ以外なら - " }\n" + - " gl_FragColor = vec4(hsv2rgb(clamp(hsv, 0.0, 1.0)), 1.0);\n" + // HSVをRGBに戻す - "}\n"; - - private static final String FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_WHITE_OES - = String.format(FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_WHITE_BASE, HEADER_OES, SAMPLER_OES); - - /** - * 黄色と白を強調するためのフラグメントシェーダーのベース文字列 - * 今はFRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_WHITE_BASEと同じ(違うパラメータ渡せば良いだけなので) - */ - private static final String FRAGMENT_SHADER_EMPHASIZE_YELLOW_WHITE_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "uniform float uParams[" + MAX_PARAM_NUM + "];\n" + - FUNC_RGB2HSV + - FUNC_HSV2RGB + - "void main() {\n" + - " vec3 rgb = texture2D(sTexture, vTextureCoord).rgb;\n" + // RGB - " vec3 hsv = rgb2hsv(rgb);\n" + // RGBをHSVに変換 - " if ( ((hsv.r >= uParams[0]) && (hsv.r <= uParams[1]))\n" + // h - " && ((hsv.g >= uParams[2]) && (hsv.g <= uParams[3]))\n" + // s - " && ((hsv.b >= uParams[4]) && (hsv.b <= uParams[5])) ) {\n" + // v - " hsv = hsv * vec3(uParams[6], uParams[7], uParams[8]);\n" + // 黄色の範囲 - " } else if ((hsv.g < uParams[12]) && (hsv.b > uParams[13])) {\n" + // 彩度が一定以下, 明度が一定以上なら - " hsv = hsv * vec3(1.0, 0.0, 2.0);\n" + // 色相そのまま, 彩度0, 明度x2 - " } else {\n" + - " hsv = hsv * vec3(uParams[9], uParams[10], uParams[11]);\n" + // それ以外なら - " }\n" + - " gl_FragColor = vec4(hsv2rgb(clamp(hsv, 0.0, 1.0)), 1.0);\n" + // HSVをRGBに戻す - "}\n"; - - private static final String FRAGMENT_SHADER_EMPHASIZE_YELLOW_WHITE_OES - = String.format(FRAGMENT_SHADER_EMPHASIZE_YELLOW_WHITE_BASE, HEADER_OES, SAMPLER_OES); - - public EffectRendererHolder(final int width, final int height, - @Nullable final RenderHolderCallback callback) { - - this(width, height, - 3, null, EglTask.EGL_FLAG_RECORDABLE, - callback); - } - - public EffectRendererHolder(final int width, final int height, - final int maxClientVersion, final EGLBase.IContext sharedContext, final int flags, - @Nullable final RenderHolderCallback callback) { - - super(width, height, - maxClientVersion, sharedContext, flags, - callback); - } - - @Override - @NonNull - protected RendererTask createRendererTask(final int width, final int height, - final int maxClientVersion, final EGLBase.IContext sharedContext, final int flags) { - return new MyRendererTask(this, width, height, - maxClientVersion, sharedContext, flags); - } - -//================================================================================ -// クラス固有publicメソッド -//================================================================================ - - /** - * 映像効果をセット - * 継承して独自の映像効果を追加する時はEFFECT_NUMよりも大きい値を使うこと - * @param effect - */ - public void changeEffect(final int effect) { - ((MyRendererTask)mRendererTask).changeEffect(effect); - } - - /** - * 現在の映像効果番号を取得 - * @return - */ - public int getCurrentEffect() { - return ((MyRendererTask)mRendererTask).mEffect; - } - - /** - * 現在選択中の映像フィルタにパラメータ配列をセット - * 現在対応しているのは色強調用の映像効果のみ(n=12以上必要) - * @param params - */ - public void setParams(@NonNull final float[] params) { - ((MyRendererTask)mRendererTask).setParams(-1, params); - } - - /** - * 指定した映像フィルタにパラメータ配列をセット - * 現在対応しているのは色強調用の映像効果のみ(n=12以上必要) - * @param effect EFFECT_NONより大きいこと - * @param params - * @throws IllegalArgumentException effectが範囲外ならIllegalArgumentException生成 - */ - public void setParams(final int effect, @NonNull final float[] params) - throws IllegalArgumentException { - - if (effect > EFFECT_NON) { - ((MyRendererTask)mRendererTask).setParams(effect, params); - } else { - throw new IllegalArgumentException("invalid effect number:" + effect); - } - } - - /** - * 内蔵映像効果以外のeffectを指定したときの処理 - * 描画用のワーカースレッド上で呼び出される - * このクラスでは無変換のフラグメントシェーダーを適用する - * @param effect - * @param drawer GLDrawer2Dインスタンス - */ - protected void handleDefaultEffect(final int effect, - @NonNull final IDrawer2dES2 drawer) { - - if (drawer instanceof GLDrawer2D) { - ((GLDrawer2D) drawer).resetShader(); - } - } - -//================================================================================ -// 実装 -//================================================================================ - private static final int REQUEST_CHANGE_EFFECT = 100; - private static final int REQUEST_SET_PARAMS = 101; - - /** - * ワーカースレッド上でOpenGL|ESを用いてマスター映像を分配描画するためのインナークラス - */ - protected static final class MyRendererTask extends RendererTask { - - private final SparseArray mParams = new SparseArray(); - private int muParamsLoc; - private float[] mCurrentParams; - private int mEffect; - - public MyRendererTask(final EffectRendererHolder parent, - final int width, final int height) { - - super(parent, width, height); - } - - public MyRendererTask(@NonNull final AbstractRendererHolder parent, - final int width, final int height, - final int maxClientVersion, - final EGLBase.IContext sharedContext, final int flags) { - - super(parent, width, height, maxClientVersion, sharedContext, flags); - } - - /** - * ワーカースレッド開始時の処理(ここはワーカースレッド上) - */ - @SuppressLint("NewApi") - @Override - protected void internalOnStart() { -// if (DEBUG) Log.v(TAG, "onStart:"); - super.internalOnStart(); - mParams.clear(); - mParams.put(EFFECT_EMPHASIZE_RED_YELLOW, new float[] { - 0.17f, 0.85f, // 赤色&黄色の色相下側閾値, 上側閾値 - 0.50f, 1.0f, // 強調する彩度下限, 上限 - 0.40f, 1.0f, // 強調する明度下限, 上限 - 1.0f, 1.0f, 5.0f, // 強調時のファクター(H, S, Vの順) 明度(x5.0) = 1.0 - 1.0f, 1.0f, 1.0f, // 通常時のファクター(H, S, Vの順) - }); - mParams.put(EFFECT_EMPHASIZE_RED_YELLOW_WHITE, new float[] { - 0.17f, 0.85f, // 赤色&黄色の色相下側閾値, 上側閾値 - 0.50f, 1.0f, // 強調する彩度下限, 上限 - 0.40f, 1.0f, // 強調する明度下限, 上限 - 1.0f, 1.0f, 5.0f, // 強調時のファクター(H, S, Vの順) 明度(x5.0) = 1.0 - 1.0f, 1.0f, 1.0f, // 通常時のファクター(H, S, Vの順) - }); - mParams.put(EFFECT_EMPHASIZE_YELLOW_WHITE, new float[] { - 0.10f, 0.19f, // 黄色の色相h下側閾値, 上側閾値 - 0.30f, 1.00f, // 強調する彩度s下限, 上限 - 0.30f, 1.00f, // 強調する明度v下限, 上限 - 1.00f, 1.00f, 5.00f, // 強調時のファクター(H, S, Vの順) 明度(x5.0) = 1.0 - 1.00f, 0.80f, 0.80f, // 通常時のファクター(H, S, Vの順) 彩度(x0.8)と明度(x0.8)を少し落とす - 0.15f, 0.40f, // 白強調時の彩度上限, 白強調時の明度下限 - 0, 0, 0, 0, // ダミー - }); - mEffect = EFFECT_NON; - handleChangeEffect(EFFECT_NON); -// if (DEBUG) Log.v(TAG, "onStart:finished"); - } - - @Override - protected Object processRequest(final int request, - final int arg1, final int arg2, final Object obj) { - - Object result = null; - switch (request) { - case REQUEST_CHANGE_EFFECT: - handleChangeEffect(arg1); - break; - case REQUEST_SET_PARAMS: - handleSetParam(arg1, (float[])obj); - break; - default: - result = super.processRequest(request, arg1, arg2, obj); - break; - } - return result; - } - - public void changeEffect(final int effect) { - checkFinished(); - if (mEffect != effect) { - offer(REQUEST_CHANGE_EFFECT, effect); - } - } - - public void setParams(final int effect, @NonNull final float[] params) { - checkFinished(); - offer(REQUEST_SET_PARAMS, effect, 0, params); - } - -//================================================================================ -// ワーカースレッド上での処理 -//================================================================================ - /** - * 映像効果を変更 - * @param effect - */ - protected void handleChangeEffect(final int effect) { - mEffect = effect; - switch (effect) { - case EFFECT_NON: - mDrawer.updateShader(FRAGMENT_SHADER_SIMPLE_OES); - break; - case EFFECT_GRAY: - mDrawer.updateShader(FRAGMENT_SHADER_GRAY_OES); - break; - case EFFECT_GRAY_REVERSE: - mDrawer.updateShader(FRAGMENT_SHADER_GRAY_REVERSE_OES); - break; - case EFFECT_BIN: - mDrawer.updateShader(FRAGMENT_SHADER_BIN_OES); - break; - case EFFECT_BIN_YELLOW: - mDrawer.updateShader(FRAGMENT_SHADER_BIN_YELLOW_OES); - break; - case EFFECT_BIN_GREEN: - mDrawer.updateShader(FRAGMENT_SHADER_BIN_GREEN_OES); - break; - case EFFECT_BIN_REVERSE: - mDrawer.updateShader(FRAGMENT_SHADER_BIN_REVERSE_OES); - break; - case EFFECT_BIN_REVERSE_YELLOW: - mDrawer.updateShader(FRAGMENT_SHADER_BIN_REVERSE_YELLOW_OES); - break; - case EFFECT_BIN_REVERSE_GREEN: - mDrawer.updateShader(FRAGMENT_SHADER_BIN_REVERSE_GREEN_OES); - break; - case EFFECT_EMPHASIZE_RED_YELLOW: - mDrawer.updateShader(FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_OES); - break; - case EFFECT_EMPHASIZE_RED_YELLOW_WHITE: - mDrawer.updateShader(FRAGMENT_SHADER_EMPHASIZE_RED_YELLOW_WHITE_OES); - break; - case EFFECT_EMPHASIZE_YELLOW_WHITE: - mDrawer.updateShader(FRAGMENT_SHADER_EMPHASIZE_YELLOW_WHITE_OES); - break; - default: - try { - ((EffectRendererHolder)getParent()) - .handleDefaultEffect(effect, mDrawer); - } catch (final Exception e) { - mDrawer.resetShader(); - Log.w(TAG, e); - } - break; - } - muParamsLoc = mDrawer.glGetUniformLocation("uParams"); - mCurrentParams = mParams.get(effect); - updateParams(); - } - - /** - * 映像効果用のパラメーターをセット - * @param effect - * @param params - */ - private void handleSetParam(final int effect, @NonNull final float[] params) { - if ((effect < EFFECT_NON) || (mEffect == effect)) { - mCurrentParams = params; - mParams.put(mEffect, params); - updateParams(); - } else { - mParams.put(effect, params); - } - } - - /** - * 映像効果用のパラメータをGPUへ適用 - */ - private void updateParams() { - final int n = Math.min(mCurrentParams != null - ? mCurrentParams.length : 0, MAX_PARAM_NUM); - if ((muParamsLoc >= 0) && (n > 0)) { - mDrawer.glUseProgram(); - GLES20.glUniform1fv(muParamsLoc, n, mCurrentParams, 0); - } - } - - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EglTask.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EglTask.java deleted file mode 100644 index 1f36e6348d..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/EglTask.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import androidx.annotation.Nullable; - -import com.serenegiant.utils.MessageTask; - -public abstract class EglTask extends MessageTask { -// private static final boolean DEBUG = false; -// private static final String TAG = "EglTask"; - - public static final int EGL_FLAG_DEPTH_BUFFER = 0x01; - public static final int EGL_FLAG_RECORDABLE = 0x02; - public static final int EGL_FLAG_STENCIL_1BIT = 0x04; -// public static final int EGL_FLAG_STENCIL_2BIT = 0x08; -// public static final int EGL_FLAG_STENCIL_4BIT = 0x10; - public static final int EGL_FLAG_STENCIL_8BIT = 0x20; - - private EGLBase mEgl = null; - private EGLBase.IEglSurface mEglHolder; - - public EglTask(final EGLBase.IContext sharedContext, final int flags) { -// if (DEBUG) Log.i(TAG, "shared_context=" + shared_context); - init(flags, 3, sharedContext); - } - - public EglTask(final int maxClientVersion, - final EGLBase.IContext sharedContext, final int flags) { - -// if (DEBUG) Log.i(TAG, "shared_context=" + shared_context); - init(flags, maxClientVersion, sharedContext); - } - - /** - * @param flags - * @param maxClientVersion - * @param sharedContext - */ - @Override - protected void onInit(final int flags, - final int maxClientVersion, final Object sharedContext) { - - if ((sharedContext == null) - || (sharedContext instanceof EGLBase.IContext)) { - - final int stencilBits - = (flags & EGL_FLAG_STENCIL_1BIT) == EGL_FLAG_STENCIL_1BIT ? 1 - : ((flags & EGL_FLAG_STENCIL_8BIT) == EGL_FLAG_STENCIL_8BIT ? 8 : 0); - mEgl = EGLBase.createFrom(maxClientVersion, (EGLBase.IContext)sharedContext, - (flags & EGL_FLAG_DEPTH_BUFFER) == EGL_FLAG_DEPTH_BUFFER, - stencilBits, - (flags & EGL_FLAG_RECORDABLE) == EGL_FLAG_RECORDABLE); - } - if (mEgl == null) { - callOnError(new RuntimeException("failed to create EglCore")); - releaseSelf(); - } else { - mEglHolder = mEgl.createOffscreen(1, 1); - mEglHolder.makeCurrent(); - } - } - - @Override - protected Request takeRequest() throws InterruptedException { - final Request result = super.takeRequest(); - mEglHolder.makeCurrent(); - return result; - } - - @Override - protected void onBeforeStop() { - mEglHolder.makeCurrent(); - } - - @Override - protected void onRelease() { - mEglHolder.release(); - mEgl.release(); - } - - protected EGLBase getEgl() { - return mEgl; - } - - protected EGLBase.IContext getEGLContext() { - return mEgl.getContext(); - } - - protected EGLBase.IConfig getConfig() { - return mEgl.getConfig(); - } - - @Nullable - protected EGLBase.IContext getContext() { - return mEgl != null ? mEgl.getContext() : null; - } - - protected void makeCurrent() { - mEglHolder.makeCurrent(); - } - - protected boolean isGLES3() { - return (mEgl != null) && (mEgl.getGlVersion() > 2); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLDrawer2D.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLDrawer2D.java deleted file mode 100644 index 1d73f13a7d..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLDrawer2D.java +++ /dev/null @@ -1,307 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_SIMPLE; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_SIMPLE_OES; -import static com.serenegiant.glutils.ShaderConst.GL_TEXTURE_2D; -import static com.serenegiant.glutils.ShaderConst.GL_TEXTURE_EXTERNAL_OES; -import static com.serenegiant.glutils.ShaderConst.VERTEX_SHADER; - -import android.opengl.GLES20; -import android.opengl.Matrix; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -/** - * 描画領域全面にテクスチャを2D描画するためのヘルパークラス - */ -public class GLDrawer2D implements IDrawer2dES2 { -// private static final boolean DEBUG = false; // FIXME set false on release -// private static final String TAG = "GLDrawer2D"; - - private static final float[] VERTICES = { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f }; - private static final float[] TEXCOORD = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; - private static final int FLOAT_SZ = Float.SIZE / 8; - - private final int VERTEX_NUM; - private final int VERTEX_SZ; - private final FloatBuffer pVertex; - private final FloatBuffer pTexCoord; - private final int mTexTarget; - private int hProgram; - int maPositionLoc; - int maTextureCoordLoc; - int muMVPMatrixLoc; - int muTexMatrixLoc; - private final float[] mMvpMatrix = new float[16]; - - /** - * コンストラクタ - * GLコンテキスト/EGLレンダリングコンテキストが有効な状態で呼ばないとダメ - * @param isOES 外部テクスチャ(GL_TEXTURE_EXTERNAL_OES)を使う場合はtrue。 - * 通常の2Dテキスチャならfalse - */ - public GLDrawer2D(final boolean isOES) { - this(VERTICES, TEXCOORD, isOES); - } - - /** - * コンストラクタ - * GLコンテキスト/EGLレンダリングコンテキストが有効な状態で呼ばないとダメ - * @param vertices 頂点座標, floatを8個 = (x,y) x 4ペア - * @param texcoord テクスチャ座標, floatを8個 = (s,t) x 4ペア - * @param isOES 外部テクスチャ(GL_TEXTURE_EXTERNAL_OES)を使う場合はtrue。 - * 通常の2Dテキスチャならfalse - */ - public GLDrawer2D(final float[] vertices, - final float[] texcoord, final boolean isOES) { - - VERTEX_NUM = Math.min( - vertices != null ? vertices.length : 0, - texcoord != null ? texcoord.length : 0) / 2; - VERTEX_SZ = VERTEX_NUM * 2; - - mTexTarget = isOES ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; - pVertex = ByteBuffer.allocateDirect(VERTEX_SZ * FLOAT_SZ) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - pVertex.put(vertices); - pVertex.flip(); - pTexCoord = ByteBuffer.allocateDirect(VERTEX_SZ * FLOAT_SZ) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - pTexCoord.put(texcoord); - pTexCoord.flip(); - - if (isOES) { - hProgram = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_SIMPLE_OES); - } else { - hProgram = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_SIMPLE); - } - // モデルビュー変換行列を初期化 - Matrix.setIdentityM(mMvpMatrix, 0); - init(); - } - - /** - * 破棄処理。GLコンテキスト/EGLレンダリングコンテキスト内で呼び出さないとダメ - */ - @Override - public void release() { - if (hProgram >= 0) { - GLES20.glDeleteProgram(hProgram); - } - hProgram = -1; - } - - /** - * 外部テクスチャを使うかどうか - * @return - */ - public boolean isOES() { - return mTexTarget == GL_TEXTURE_EXTERNAL_OES; - } - - /** - * モデルビュー変換行列を取得(内部配列を直接返すので変更時は要注意) - * @return - */ - @Override - public float[] getMvpMatrix() { - return mMvpMatrix; - } - - /** - * モデルビュー変換行列に行列を割り当てる - * @param matrix 領域チェックしていないのでoffsetから16個以上必須 - * @param offset - * @return - */ - @Override - public IDrawer2D setMvpMatrix(final float[] matrix, final int offset) { - System.arraycopy(matrix, offset, mMvpMatrix, 0, 16); - return this; - } - - /** - * モデルビュー変換行列のコピーを取得 - * @param matrix 領域チェックしていないのでoffsetから16個以上必須 - * @param offset - */ - @Override - public void getMvpMatrix(final float[] matrix, final int offset) { - System.arraycopy(mMvpMatrix, 0, matrix, offset, 16); - } - - /** - * 指定したテクスチャを指定したテクスチャ変換行列を使って描画領域全面に描画するためのヘルパーメソッド - * このクラスインスタンスのモデルビュー変換行列が設定されていればそれも適用された状態で描画する - * @param texId texture ID - * @param tex_matrix テクスチャ変換行列、nullならば以前に適用したものが再利用される。 - * 領域チェックしていないのでoffsetから16個以上確保しておくこと - */ - @Override - public synchronized void draw(final int texId, - final float[] tex_matrix, final int offset) { - -// if (DEBUG) Log.v(TAG, "draw"); - if (hProgram < 0) return; - GLES20.glUseProgram(hProgram); - if (tex_matrix != null) { - // テクスチャ変換行列が指定されている時 - GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, tex_matrix, offset); - } - // モデルビュー変換行列をセット - GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mMvpMatrix, 0); - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(mTexTarget, texId); - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_NUM); - GLES20.glBindTexture(mTexTarget, 0); - GLES20.glUseProgram(0); - } - - /** - * Textureオブジェクトを描画するためのヘルパーメソッド - * Textureオブジェクトで管理しているテクスチャ名とテクスチャ座標変換行列を使って描画する - * @param texture - */ - @Override - public void draw(final ITexture texture) { - draw(texture.getTexture(), texture.getTexMatrix(), 0); - } - - /** - * TextureOffscreenオブジェクトを描画するためのヘルパーメソッド - * @param offscreen - */ - @Override - public void draw(final TextureOffscreen offscreen) { - draw(offscreen.getTexture(), offscreen.getTexMatrix(), 0); - } - - /** - * テクスチャ名生成のヘルパーメソッド - * GLHelper#initTexを呼び出すだけ - * @return texture ID - */ - public int initTex() { - return GLHelper.initTex(mTexTarget, GLES20.GL_NEAREST); - } - - /** - * テクスチャ名破棄のヘルパーメソッド - * GLHelper.deleteTexを呼び出すだけ - * @param hTex - */ - public void deleteTex(final int hTex) { - GLHelper.deleteTex(hTex); - } - - /** - * 頂点シェーダー・フラグメントシェーダーを変更する - * GLコンテキスト/EGLレンダリングコンテキスト内で呼び出さないとダメ - * glUseProgramが呼ばれた状態で返る - * @param vs 頂点シェーダー文字列 - * @param fs フラグメントシェーダー文字列 - */ - public synchronized void updateShader(final String vs, final String fs) { - release(); - hProgram = GLHelper.loadShader(vs, fs); - init(); - } - - /** - * フラグメントシェーダーを変更する - * GLコンテキスト/EGLレンダリングコンテキスト内で呼び出さないとダメ - * glUseProgramが呼ばれた状態で返る - * @param fs フラグメントシェーダー文字列 - */ - public void updateShader(final String fs) { - updateShader(VERTEX_SHADER, fs); - } - - /** - * 頂点シェーダー・フラグメントシェーダーをデフォルトに戻す - */ - public void resetShader() { - release(); - if (isOES()) { - hProgram = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_SIMPLE_OES); - } else { - hProgram = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_SIMPLE); - } - init(); - } - - /** - * アトリビュート変数のロケーションを取得 - * glUseProgramが呼ばれた状態で返る - * @param name - * @return - */ - @Override - public int glGetAttribLocation(final String name) { - GLES20.glUseProgram(hProgram); - return GLES20.glGetAttribLocation(hProgram, name); - } - - /** - * ユニフォーム変数のロケーションを取得 - * glUseProgramが呼ばれた状態で返る - * @param name - * @return - */ - @Override - public int glGetUniformLocation(final String name) { - GLES20.glUseProgram(hProgram); - return GLES20.glGetUniformLocation(hProgram, name); - } - - /** - * glUseProgramが呼ばれた状態で返る - */ - @Override - public void glUseProgram() { - GLES20.glUseProgram(hProgram); - } - - /** - * シェーダープログラム変更時の初期化処理 - * glUseProgramが呼ばれた状態で返る - */ - private void init() { - GLES20.glUseProgram(hProgram); - maPositionLoc = GLES20.glGetAttribLocation(hProgram, "aPosition"); - maTextureCoordLoc = GLES20.glGetAttribLocation(hProgram, "aTextureCoord"); - muMVPMatrixLoc = GLES20.glGetUniformLocation(hProgram, "uMVPMatrix"); - muTexMatrixLoc = GLES20.glGetUniformLocation(hProgram, "uTexMatrix"); - // - GLES20.glUniformMatrix4fv(muMVPMatrixLoc, - 1, false, mMvpMatrix, 0); - GLES20.glUniformMatrix4fv(muTexMatrixLoc, - 1, false, mMvpMatrix, 0); - GLES20.glVertexAttribPointer(maPositionLoc, - 2, GLES20.GL_FLOAT, false, VERTEX_SZ, pVertex); - GLES20.glVertexAttribPointer(maTextureCoordLoc, - 2, GLES20.GL_FLOAT, false, VERTEX_SZ, pTexCoord); - GLES20.glEnableVertexAttribArray(maPositionLoc); - GLES20.glEnableVertexAttribArray(maTextureCoordLoc); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLHelper.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLHelper.java deleted file mode 100644 index c4c8adfd72..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLHelper.java +++ /dev/null @@ -1,417 +0,0 @@ -package com.serenegiant.glutils; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.opengl.GLES20; -import android.opengl.GLES30; -import android.opengl.GLUtils; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.serenegiant.utils.AssetsHelper; -import com.serenegiant.utils.BuildCheck; - -import java.io.IOException; - -/** - * OpenGL|ES2/3用のヘルパークラス - */ -public final class GLHelper { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = "GLHelper"; - - /** - * OpenGL|ESのエラーをチェックしてlogCatに出力する - * @param op - */ - public static void checkGlError(final String op) { - final int error = GLES20.glGetError(); - if (error != GLES20.GL_NO_ERROR) { - final String msg = op + ": glError 0x" + Integer.toHexString(error); - Log.e(TAG, msg); - new Throwable(msg).printStackTrace(); -// if (DEBUG) { -// throw new RuntimeException(msg); -// } - } - } - - /** - * テクスチャ名を生成, テクスチャユニットはGL_TEXTURE0, クランプ方法はGL_CLAMP_TO_EDGE - * @param texTarget - * @param filter_param テクスチャの補完方法を指定, min/mag共に同じ値になる, GL_LINEARとかGL_NEAREST - * @return - */ - public static int initTex(final int texTarget, final int filter_param) { - return initTex(texTarget, GLES20.GL_TEXTURE0, - filter_param, filter_param, GLES20.GL_CLAMP_TO_EDGE); - } - - /** - * テクスチャ名を生成(GL_TEXTURE0のみ) - * @param texTarget - * @param texUnit テクスチャユニット, GL_TEXTURE0...GL_TEXTURE31 - * @param min_filter テクスチャの補間方法を指定, GL_LINEARとかGL_NEAREST - * @param mag_filter テクスチャの補間方法を指定, GL_LINEARとかGL_NEAREST - * @param wrap テクスチャのクランプ方法, GL_CLAMP_TO_EDGE - * @return - */ - public static int initTex(final int texTarget, final int texUnit, - final int min_filter, final int mag_filter, final int wrap) { - -// if (DEBUG) Log.v(TAG, "initTex:target=" + texTarget); - final int[] tex = new int[1]; - GLES20.glActiveTexture(texUnit); - GLES20.glGenTextures(1, tex, 0); - GLES20.glBindTexture(texTarget, tex[0]); - GLES20.glTexParameteri(texTarget, GLES20.GL_TEXTURE_WRAP_S, wrap); - GLES20.glTexParameteri(texTarget, GLES20.GL_TEXTURE_WRAP_T, wrap); - GLES20.glTexParameteri(texTarget, GLES20.GL_TEXTURE_MIN_FILTER, min_filter); - GLES20.glTexParameteri(texTarget, GLES20.GL_TEXTURE_MAG_FILTER, mag_filter); - return tex[0]; - } - - /** - * テクスチャ名配列を生成(前から順にGL_TEXTURE0, GL_TEXTURE1, ...) - * @param n 生成するテキスチャ名の数, 最大で32個(GL_MAX_TEXTURE_IMAGE_UNITS以下) - * @param texTarget - * @param filter_param - * @return - */ - public static int[] initTexes(final int n, - final int texTarget, final int filter_param) { - - return initTexes(new int[n], texTarget, - filter_param, filter_param, GLES20.GL_CLAMP_TO_EDGE); - } - - /** - * テクスチャ名配列を生成(前から順にGL_TEXTURE0, GL_TEXTURE1, ...) - * @param texIds テクスチャ名配列, 最大で32個(GL_MAX_TEXTURE_IMAGE_UNITS以下) - * @param texTarget - * @param filter_param - * @return - */ - public static int[] initTexes(@NonNull final int[] texIds, - final int texTarget, final int filter_param) { - - return initTexes(texIds, texTarget, - filter_param, filter_param, GLES20.GL_CLAMP_TO_EDGE); - } - - /** - * テクスチャ名配列を生成(前から順にGL_TEXTURE0, GL_TEXTURE1, ...) - * @param n 生成するテキスチャ名の数, 最大32 - * @param texTarget - * @param min_filter - * @param mag_filter - * @param wrap - * @return - */ - public static int[] initTexes(final int n, - final int texTarget, final int min_filter, final int mag_filter, final int wrap) { - - return initTexes(new int[n], texTarget, min_filter, mag_filter, wrap); - } - - /** - * テクスチャ名配列を生成(前から順にGL_TEXTURE0, GL_TEXTURE1, ...) - * @param texIds テクスチャ名配列, 最大で32個(GL_MAX_TEXTURE_IMAGE_UNITS以下) - * @param texTarget - * @param min_filter - * @param mag_filter - * @param wrap - * @return - */ - public static int[] initTexes(@NonNull final int[] texIds, - final int texTarget, final int min_filter, final int mag_filter, final int wrap) { - - int[] textureUnits = new int[1]; - GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, textureUnits, 0); - Log.v(TAG, "GL_MAX_TEXTURE_IMAGE_UNITS=" + textureUnits[0]); - final int n = texIds.length > textureUnits[0] - ? textureUnits[0] : texIds.length; - for (int i = 0; i < n; i++) { - texIds[i] = GLHelper.initTex(texTarget, ShaderConst.TEX_NUMBERS[i], - min_filter, mag_filter, wrap); - } - return texIds; - } - - /** - * テクスチャ名配列を生成(こっちは全部同じテクスチャユニット) - * @param n 最大で32個(GL_MAX_TEXTURE_IMAGE_UNITS以下) - * @param texTarget - * @param texUnit - * @param min_filter - * @param mag_filter - * @param wrap - * @return - */ - public static int[] initTexes(final int n, - final int texTarget, final int texUnit, - final int min_filter, final int mag_filter, final int wrap) { - - return initTexes(new int[n], texTarget, texUnit, - min_filter, mag_filter, wrap); - } - - /** - * テクスチャ名配列を生成(こっちは全部同じテクスチャユニット) - * @param texIds 最大で32個(GL_MAX_TEXTURE_IMAGE_UNITS以下) - * @param texTarget - * @param texUnit - * @param filter_param - * @return - */ - public static int[] initTexes(@NonNull final int[] texIds, - final int texTarget, final int texUnit, final int filter_param) { - - return initTexes(texIds, texTarget, texUnit, - filter_param, filter_param, GLES20.GL_CLAMP_TO_EDGE); - } - - /** - * テクスチャ名配列を生成(こっちは全部同じテクスチャユニット) - * @param texIds - * @param texTarget - * @param texUnit - * @param min_filter - * @param mag_filter - * @param wrap - * @return - */ - public static int[] initTexes(@NonNull final int[] texIds, - final int texTarget, final int texUnit, - final int min_filter, final int mag_filter, final int wrap) { - - int[] textureUnits = new int[1]; - GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, textureUnits, 0); - final int n = texIds.length > textureUnits[0] - ? textureUnits[0] : texIds.length; - for (int i = 0; i < n; i++) { - texIds[i] = GLHelper.initTex(texTarget, texUnit, - min_filter, mag_filter, wrap); - } - return texIds; - } - - /** - * delete specific texture - */ - public static void deleteTex(final int hTex) { -// if (DEBUG) Log.v(TAG, "deleteTex:"); - final int[] tex = new int[] {hTex}; - GLES20.glDeleteTextures(1, tex, 0); - } - - /** - * delete specific texture - */ - public static void deleteTex(@NonNull final int[] tex) { -// if (DEBUG) Log.v(TAG, "deleteTex:"); - GLES20.glDeleteTextures(tex.length, tex, 0); - } - - public static int loadTextureFromResource(final Context context, final int resId) { - return loadTextureFromResource(context, resId, null); - } - - @SuppressLint("NewApi") - @SuppressWarnings("deprecation") - public static int loadTextureFromResource(final Context context, final int resId, final Resources.Theme theme) { - // Create an empty, mutable bitmap - final Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888); - // get a canvas to paint over the bitmap - final Canvas canvas = new Canvas(bitmap); - canvas.drawARGB(0,0,255,0); - - // get a background image from resources - // note the image format must match the bitmap format - final Drawable background; - if (BuildCheck.isAndroid5()) { - background = context.getResources().getDrawable(resId, theme); - } else { - background = context.getResources().getDrawable(resId); - } - background.setBounds(0, 0, 256, 256); - background.draw(canvas); // draw the background to our bitmap - - final int[] textures = new int[1]; - - //Generate one texture pointer... - GLES20.glGenTextures(1, textures, 0); - //...and bind it to our array - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); - - //Create Nearest Filtered Texture - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - - //Different possible texture parameters, e.g. GLES20.GL_CLAMP_TO_EDGE - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); - - //Use the Android GLUtils to specify a two-dimensional texture image from our bitmap - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); - //Clean up - bitmap.recycle(); - - return textures[0]; - } - - public static int createTextureWithTextContent (final String text) { - // Create an empty, mutable bitmap - final Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888); - // get a canvas to paint over the bitmap - final Canvas canvas = new Canvas(bitmap); - canvas.drawARGB(0,0,255,0); - - // Draw the text - final Paint textPaint = new Paint(); - textPaint.setTextSize(32); - textPaint.setAntiAlias(true); - textPaint.setARGB(0xff, 0xff, 0xff, 0xff); - // draw the text centered - canvas.drawText(text, 16, 112, textPaint); - - final int texture = initTex(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE0, GLES20.GL_NEAREST, GLES20.GL_LINEAR, GLES20.GL_REPEAT); - - // Alpha blending - // GLES20.glEnable(GLES20.GL_BLEND); - // GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); - - // Use the Android GLUtils to specify a two-dimensional texture image from our bitmap - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); - // Clean up - bitmap.recycle(); - - return texture; - } - - /** - * load, compile and link shader from Assets files - * @param context - * @param vss_asset source file name in Assets of vertex shader - * @param fss_asset source file name in Assets of fragment shader - * @return - */ - public static int loadShader(@NonNull final Context context, - final String vss_asset, final String fss_asset) { - - int program = 0; - try { - final String vss = AssetsHelper.loadString(context.getAssets(), vss_asset); - final String fss = AssetsHelper.loadString(context.getAssets(), vss_asset); - program = loadShader(vss, fss); - } catch (IOException e) { - } - return program; - } - - /** - * load, compile and link shader - * @param vss source of vertex shader - * @param fss source of fragment shader - * @return - */ - public static int loadShader(final String vss, final String fss) { -// if (DEBUG) Log.v(TAG, "loadShader:"); - final int[] compiled = new int[1]; - // 頂点シェーダーをコンパイル - final int vs = loadShader(GLES20.GL_VERTEX_SHADER, vss); - if (vs == 0) { - return 0; - } - // フラグメントシェーダーをコンパイル - int fs = loadShader(GLES20.GL_FRAGMENT_SHADER, fss); - if (fs == 0) { - return 0; - } - // リンク - final int program = GLES20.glCreateProgram(); - checkGlError("glCreateProgram"); - if (program == 0) { - Log.e(TAG, "Could not create program"); - } - GLES20.glAttachShader(program, vs); - checkGlError("glAttachShader"); - GLES20.glAttachShader(program, fs); - checkGlError("glAttachShader"); - GLES20.glLinkProgram(program); - final int[] linkStatus = new int[1]; - GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); - if (linkStatus[0] != GLES20.GL_TRUE) { - Log.e(TAG, "Could not link program: "); - Log.e(TAG, GLES20.glGetProgramInfoLog(program)); - GLES20.glDeleteProgram(program); - return 0; - } - return program; - } - - /** - * Compiles the provided shader source. - * - * @return A handle to the shader, or 0 on failure. - */ - public static int loadShader(final int shaderType, final String source) { - int shader = GLES20.glCreateShader(shaderType); - checkGlError("glCreateShader type=" + shaderType); - GLES20.glShaderSource(shader, source); - GLES20.glCompileShader(shader); - final int[] compiled = new int[1]; - GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); - if (compiled[0] == 0) { - Log.e(TAG, "Could not compile shader " + shaderType + ":"); - Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader)); - GLES20.glDeleteShader(shader); - shader = 0; - } - return shader; - } - - /** - * Checks to see if the location we obtained is valid. GLES returns -1 if a label - * could not be found, but does not set the GL error. - *

- * Throws a RuntimeException if the location is invalid. - */ - public static void checkLocation(final int location, final String label) { - if (location < 0) { - throw new RuntimeException("Unable to locate '" + label + "' in program"); - } - } - - /** - * Writes GL version info to the log. - */ - @SuppressLint("InlinedApi") - public static void logVersionInfo() { - Log.i(TAG, "vendor : " + GLES20.glGetString(GLES20.GL_VENDOR)); - Log.i(TAG, "renderer: " + GLES20.glGetString(GLES20.GL_RENDERER)); - Log.i(TAG, "version : " + GLES20.glGetString(GLES20.GL_VERSION)); - - if (BuildCheck.isAndroid4_3()) { - final int[] values = new int[1]; - GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, values, 0); - final int majorVersion = values[0]; - GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, values, 0); - final int minorVersion = values[0]; - if (GLES30.glGetError() == GLES30.GL_NO_ERROR) { - Log.i(TAG, "version: " + majorVersion + "." + minorVersion); - } - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLMasterContext.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLMasterContext.java deleted file mode 100644 index eb1616f031..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLMasterContext.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.serenegiant.glutils; - -/** - * Created by saki on 2018/02/10. - * 共有コンテキストのマスターをを保持するためだけのクラス - * Applicationクラス等でシングルトンとして使う - */ -public class GLMasterContext { - private static final String TAG = GLMasterContext.class.getSimpleName(); - - private MasterTask mMasterTask; - - public GLMasterContext(final int maxClientVersion, final int flags) { - mMasterTask = new MasterTask(maxClientVersion, flags); - new Thread(mMasterTask, TAG).start(); - mMasterTask.waitReady(); - } - - @Override - protected void finalize() throws Throwable { - try { - release(); - } finally { - super.finalize(); - } - } - - public synchronized void release() { - if (mMasterTask != null) { - mMasterTask.release(); - mMasterTask = null; - } - } - - public synchronized EGLBase.IContext getContext() - throws IllegalStateException { - if (mMasterTask != null) { - return mMasterTask.getContext(); - } else { - throw new IllegalStateException("already released"); - } - } - - private static class MasterTask extends EglTask { - public MasterTask(final int maxClientVersion, final int flags) { - super(maxClientVersion, null, flags); - } - - @Override - protected void onStart() { - // do nothing - } - - @Override - protected void onStop() { - // do nothing - } - - @Override - protected Object processRequest(final int request, - final int arg1, final int arg2, final Object obj) throws TaskBreak { - // do nothing - return null; - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLTexture.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLTexture.java deleted file mode 100644 index 9f08ad3abc..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/GLTexture.java +++ /dev/null @@ -1,234 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.opengl.GLES20; -import android.opengl.GLUtils; -import android.opengl.Matrix; -import android.text.TextUtils; - -import java.io.IOException; - -/** - * OpenGL|ESのテクスチャ操作用のヘルパークラス - */ -public class GLTexture implements ITexture { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること -// private static final String TAG = "GLTexture"; - - /* package */final int mTextureTarget; - /* package */final int mTextureUnit ; - /* package */int mTextureId; - /* package */final float[] mTexMatrix = new float[16]; // テクスチャ変換行列 - /* package */int mTexWidth, mTexHeight; - /* package */int mImageWidth, mImageHeight; - - /** - * コンストラクタ - * テクスチャユニットが常時GL_TEXTURE0なので複数のテクスチャを同時に使えない - * @param width テクスチャサイズ - * @param height テクスチャサイズ - * @param filter_param テクスチャの補間方法を指定 GL_LINEARとかGL_NEAREST - */ - public GLTexture(final int width, final int height, final int filter_param) { - this(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE0, width, height, filter_param); - } - - /** - * コンストラクタ - * @param texTarget GL_TEXTURE_EXTERNAL_OESはだめ - * @param texUnit - * @param width テクスチャサイズ - * @param height テクスチャサイズ - * @param filter_param テクスチャの補間方法を指定 GL_LINEARとかGL_NEAREST - */ - public GLTexture(final int texTarget, final int texUnit, - final int width, final int height, final int filter_param) { -// if (DEBUG) Log.v(TAG, String.format("コンストラクタ(%d,%d)", width, height)); - mTextureTarget = texTarget; - mTextureUnit = texUnit; - // テクスチャに使うビットマップは縦横サイズが2の乗数でないとダメ。 - // 更に、ミップマップするなら正方形でないとダメ - // 指定したwidth/heightと同じか大きい2の乗数にする - int w = 32; - for (; w < width; w <<= 1); - int h = 32; - for (; h < height; h <<= 1); - if (mTexWidth != w || mTexHeight != h) { - mTexWidth = w; - mTexHeight = h; - } -// if (DEBUG) Log.v(TAG, String.format("texSize(%d,%d)", mTexWidth, mTexHeight)); - mTextureId = GLHelper.initTex(mTextureTarget, filter_param); - // テクスチャのメモリ領域を確保する - GLES20.glTexImage2D(mTextureTarget, - 0, // ミップマップレベル0(ミップマップしない) - GLES20.GL_RGBA, // 内部フォーマット - mTexWidth, mTexHeight, // サイズ - 0, // 境界幅 - GLES20.GL_RGBA, // 引き渡すデータのフォーマット - GLES20.GL_UNSIGNED_BYTE, // データの型 - null); // ピクセルデータ無し - // テクスチャ変換行列を初期化 - Matrix.setIdentityM(mTexMatrix, 0); - mTexMatrix[0] = width / (float)mTexWidth; - mTexMatrix[5] = height / (float)mTexHeight; -// if (DEBUG) Log.v(TAG, "GLTexture:id=" + mTextureId); - } - - @Override - protected void finalize() throws Throwable { - try { - release(); // GLコンテキスト内じゃない可能性があるのであまり良くないけど - } finally { - super.finalize(); - } - } - - /** - * テクスチャを破棄 - * GLコンテキスト/EGLレンダリングコンテキスト内で呼び出すこと - */ - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "release:"); - if (mTextureId > 0) { - GLHelper.deleteTex(mTextureId); - mTextureId = 0; - } - } - - /** - * このインスタンスで管理しているテクスチャを有効にする(バインドする) - */ - @Override - public void bind() { -// if (DEBUG) Log.v(TAG, "bind:"); - GLES20.glActiveTexture(mTextureUnit); // テクスチャユニットを選択 - GLES20.glBindTexture(mTextureTarget, mTextureId); - } - - /** - * このインスタンスで管理しているテクスチャを無効にする(アンバインドする) - */ - @Override - public void unbind() { -// if (DEBUG) Log.v(TAG, "unbind:"); - GLES20.glActiveTexture(mTextureUnit); // テクスチャユニットを選択 - GLES20.glBindTexture(mTextureTarget, 0); - } - - /** - * テクスチャターゲットを取得(GL_TEXTURE_2D) - * @return - */ - @Override - public int getTexTarget() { return mTextureTarget; } - /** - * テクスチャ名を取得 - * @return - */ - @Override - public int getTexture() { return mTextureId; } - /** - * テクスチャ座標変換行列を取得(内部配列をそのまま返すので変更時は要注意) - * @return - */ - @Override - public float[] getTexMatrix() { return mTexMatrix; } - /** - * テクスチャ座標変換行列のコピーを取得 - * @param matrix 領域チェックしていないのでoffset位置から16個以上確保しておくこと - * @param offset - */ - @Override - public void getTexMatrix(final float[] matrix, final int offset) { - System.arraycopy(mTexMatrix, 0, matrix, offset, mTexMatrix.length); - } - /** - * テクスチャ幅を取得 - * @return - */ - @Override - public int getTexWidth() { return mTexWidth; } - /** - * テクスチャ高さを取得 - * @return - */ - @Override - public int getTexHeight() { return mTexHeight; } - - /** - * 指定したファイルから画像をテクスチャに読み込む - * ファイルが存在しないか読み込めなければIOException/NullPointerExceptionを生成 - * @param filePath - */ - @Override - public void loadTexture(final String filePath) throws NullPointerException, IOException { -// if (DEBUG) Log.v(TAG, "loadTexture:path=" + filePath); - if (TextUtils.isEmpty(filePath)) - throw new NullPointerException("image file path should not be a null"); - final BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; // Bitmapを生成せずにサイズ等の情報だけを取得する - BitmapFactory.decodeFile(filePath, options); - // テキスチャサイズ内に指定したイメージが収まるためのサブサンプリングを値を求める - final int imageWidth = options.outWidth; - final int imageHeight = options.outHeight; - int inSampleSize = 1; // サブサンプリングサイズ - if ((imageHeight > mTexHeight) || (imageWidth > mTexWidth)) { - if (imageWidth > imageHeight) { - inSampleSize = (int)Math.ceil(imageHeight / (float)mTexHeight); - } else { - inSampleSize = (int)Math.ceil(imageWidth / (float)mTexWidth); - } - } -// if (DEBUG) Log.v(TAG, String.format("image(%d,%d),tex(%d,%d),inSampleSize=%d", -// imageWidth, imageHeight, mTexWidth, mTexHeight, inSampleSize)); - // 実際の読み込み処理 - options.inSampleSize = inSampleSize; - options.inJustDecodeBounds = false; - loadTexture(BitmapFactory.decodeFile(filePath, options)); - } - - /** - * 指定したビットマップをテクスチャに読み込む - * @param bitmap - */ - public void loadTexture(final Bitmap bitmap) throws NullPointerException { - mImageWidth = bitmap.getWidth(); // 読み込んだイメージのサイズを取得 - mImageHeight = bitmap.getHeight(); - Bitmap texture = Bitmap.createBitmap(mTexWidth, mTexHeight, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(texture); - canvas.drawBitmap(bitmap, 0, 0, null); - bitmap.recycle(); - // テクスチャ座標変換行列を設定(読み込んだイメージサイズがテクスチャサイズにフィットするようにスケール変換) - Matrix.setIdentityM(mTexMatrix, 0); - mTexMatrix[0] = mImageWidth / (float)mTexWidth; - mTexMatrix[5] = mImageHeight / (float)mTexHeight; -// if (DEBUG) Log.v(TAG, String.format("image(%d,%d),scale(%f,%f)", -// mImageWidth, mImageHeight, mMvpMatrix[0], mMvpMatrix[5])); - bind(); - GLUtils.texImage2D(mTextureTarget, 0, texture, 0); - unbind(); - texture.recycle(); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IDrawer2D.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IDrawer2D.java deleted file mode 100644 index d7c4ce816e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IDrawer2D.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -public interface IDrawer2D { - public void release(); - public float[] getMvpMatrix(); - public IDrawer2D setMvpMatrix(final float[] matrix, final int offset); - public void getMvpMatrix(final float[] matrix, final int offset); - public void draw(final int texId, final float[] tex_matrix, final int offset); - public void draw(final ITexture texture); - public void draw(final TextureOffscreen offscreen); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IDrawer2dES2.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IDrawer2dES2.java deleted file mode 100644 index 9548cb941f..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IDrawer2dES2.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -public interface IDrawer2dES2 extends IDrawer2D { - public int glGetAttribLocation(final String name); - public int glGetUniformLocation(final String name); - public void glUseProgram(); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRenderer.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRenderer.java deleted file mode 100644 index b13e45d389..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRenderer.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.SurfaceTexture; -import android.view.Surface; - -public interface IRenderer extends IRendererCommon { - - /** - * 関係するすべてのリソースを開放する。再利用できない - */ - public void release(); - - /** - * 描画先のSurfaceをセット - * @param surface - */ - public void setSurface(final Surface surface); - - /** - * 描画先のSurfaceをセット - * @param surface - */ - public void setSurface(final SurfaceTexture surface); - - /** - * Surfaceサイズを変更 - * @param width - * @param height - */ - public void resize(final int width, final int height); - - /** - * 描画要求 - * @param args - */ - public void requestRender(final Object... args); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRendererCommon.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRendererCommon.java deleted file mode 100644 index f7e080595e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRendererCommon.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import androidx.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public interface IRendererCommon { - public static final int MIRROR_NORMAL = 0; - public static final int MIRROR_HORIZONTAL = 1; - public static final int MIRROR_VERTICAL = 2; - public static final int MIRROR_BOTH = 3; - public static final int MIRROR_NUM = 4; - - @IntDef({MIRROR_NORMAL, MIRROR_HORIZONTAL, MIRROR_VERTICAL, MIRROR_BOTH}) - @Retention(RetentionPolicy.SOURCE) - public @interface MirrorMode {} - - /** - * 映像を上下左右反転させるかどうかをセット - * @param mirror 0:通常, 1:左右反転, 2:上下反転, 3:上下左右反転 - */ - public void setMirror(@MirrorMode final int mirror); - - /** - * 映像を上下左右反転させるかどうかを取得 - * @return 0:通常, 1:左右反転, 2:上下反転, 3:上下左右反転 - */ - public @MirrorMode int getMirror(); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRendererHolder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRendererHolder.java deleted file mode 100644 index 9120cde2f5..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/IRendererHolder.java +++ /dev/null @@ -1,223 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.SurfaceTexture; -import android.view.Surface; - -import androidx.annotation.IntDef; -import androidx.annotation.IntRange; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.FileNotFoundException; -import java.io.OutputStream; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 分配描画インターフェース - */ -public interface IRendererHolder extends IRendererCommon { - public static final int DEFAULT_CAPTURE_COMPRESSION = 80; - - public static final int OUTPUT_FORMAT_JPEG = 0; // Bitmap.CompressFormat.JPEG - public static final int OUTPUT_FORMAT_PNG = 1; // Bitmap.CompressFormat.PNG - public static final int OUTPUT_FORMAT_WEBP = 2; // Bitmap.CompressFormat.WEBP - - @IntDef({OUTPUT_FORMAT_JPEG, OUTPUT_FORMAT_PNG, OUTPUT_FORMAT_WEBP}) - @Retention(RetentionPolicy.SOURCE) - public @interface StillCaptureFormat {} - - /** - * 実行中かどうか - * @return - */ - public boolean isRunning(); - /** - * 関係するすべてのリソースを開放する。再利用できない - */ - public void release(); - - @Nullable - public EGLBase.IContext getContext(); - - /** - * マスター用の映像を受け取るためのSurfaceを取得 - * @return - */ - public Surface getSurface(); - - /** - * マスター用の映像を受け取るためのSurfaceTextureを取得 - * @return - */ - public SurfaceTexture getSurfaceTexture(); - - /** - * マスター用の映像を受け取るためのマスターをチェックして無効なら再生成要求する - */ - public void reset(); - - /** - * マスター映像サイズをサイズ変更要求 - * @param width - * @param height - */ - public void resize(final int width, final int height) - throws IllegalStateException; - - /** - * 分配描画用のSurfaceを追加 - * このメソッドは指定したSurfaceが追加されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id 普通は#hashCodeを使う - * @param surface, should be one of Surface, SurfaceTexture or SurfaceHolder - * @param isRecordable - */ - public void addSurface(final int id, final Object surface, - final boolean isRecordable) - throws IllegalStateException, IllegalArgumentException; - - /** - * 分配描画用のSurfaceを追加 - * このメソッドは指定したSurfaceが追加されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id 普通は#hashCodeを使う - * @param surface, should be one of Surface, SurfaceTexture or SurfaceHolder - * @param isRecordable - * @param maxFps 0以下なら制限しない - */ - public void addSurface(final int id, final Object surface, - final boolean isRecordable, final int maxFps) - throws IllegalStateException, IllegalArgumentException; - - /** - * 分配描画用のSurfaceを削除 - * このメソッドは指定したSurfaceが削除されるか - * interruptされるまでカレントスレッドをブロックする。 - * @param id - */ - public void removeSurface(final int id); - - /** - * 分配描画用のSurfaceを全て削除 - * このメソッドはSurfaceが削除されるか - * interruptされるまでカレントスレッドをブロックする。 - */ - public void removeSurfaceAll(); - - /** - * 分配描画用のSurfaceを指定した色で塗りつぶす - * @param id - * @param color - */ - public void clearSurface(final int id, final int color); - - /** - * 分配描画用のSurfaceを指定した色で塗りつぶす - * @param color - */ - public void clearSurfaceAll(final int color); - - /** - * モデルビュー変換行列をセット - * @param id - * @param offset - * @param matrix offset以降に16要素以上 - */ - public void setMvpMatrix(final int id, - final int offset, @NonNull final float[] matrix); - - /** - * 分配描画用のSurfaceへの描画が有効かどうかを取得 - * @param id - * @return - */ - public boolean isEnabled(final int id); - - /** - * 分配描画用のSurfaceへの描画の有効・無効を切替 - * @param id - * @param enable - */ - public void setEnabled(final int id, final boolean enable); - - /** - * 強制的に現在の最新のフレームを描画要求する - * 分配描画用Surface全てが更新されるので注意 - */ - public void requestFrame(); - - /** - * 追加されている分配描画用のSurfaceの数を取得 - * @return - */ - public int getCount(); - - /** - * 静止画を撮影する - * 撮影完了を待機しない - * @param path - */ - @Deprecated - public void captureStillAsync(@NonNull final String path) - throws FileNotFoundException, IllegalStateException; - - /** - * 静止画を撮影する - * 撮影完了を待機しない - * @param path - * @param captureCompression JPEGの圧縮率, pngの時は無視 - */ - @Deprecated - public void captureStillAsync(@NonNull final String path, - @IntRange(from = 1L,to = 99L) final int captureCompression) - throws FileNotFoundException, IllegalStateException; - - /** - * 静止画を撮影する - * 撮影完了を待機する - * @param path - */ - public void captureStill(@NonNull final String path) - throws FileNotFoundException, IllegalStateException; - - /** - * 静止画を撮影する - * 撮影完了を待機する - * @param path - * @param captureCompression JPEGの圧縮率, pngの時は無視 - */ - public void captureStill(@NonNull final String path, - @IntRange(from = 1L,to = 99L) final int captureCompression) - throws FileNotFoundException, IllegalStateException; - - /** - * 静止画を撮影する - * 撮影完了を待機する - * @param out - * @param stillCaptureFormat - * @param captureCompression - */ - public void captureStill(@NonNull final OutputStream out, - @StillCaptureFormat final int stillCaptureFormat, - @IntRange(from = 1L,to = 99L) final int captureCompression) - throws IllegalStateException; -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/ITexture.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/ITexture.java deleted file mode 100644 index 354b955245..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/ITexture.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.Bitmap; - -import java.io.IOException; - -public interface ITexture { - void release(); - - void bind(); - void unbind(); - - int getTexTarget(); - int getTexture(); - - float[] getTexMatrix(); - void getTexMatrix(float[] matrix, int offset); - - int getTexWidth(); - int getTexHeight(); - - void loadTexture(String filePath) throws NullPointerException, IOException; - void loadTexture(Bitmap bitmap) throws NullPointerException; -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RenderHandler.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RenderHandler.java deleted file mode 100644 index c88e9fb27e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RenderHandler.java +++ /dev/null @@ -1,266 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.SurfaceTexture; -import android.opengl.GLES20; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; - -/** - * Draw shared texture on specific whole Surface using OpenGL|ES - * this will deprecate soon because I don't use this now - */ -@Deprecated -public final class RenderHandler extends Handler { -// private static final boolean DEBUG = false; // FIXME set false on release - private static final String TAG = "RenderHandler"; - - private static final int MSG_RENDER_SET_GLCONTEXT = 1; - private static final int MSG_RENDER_DRAW = 2; - private static final int MSG_CHECK_VALID = 3; - private static final int MSG_RENDER_QUIT = 9; - - private int mTexId = -1; - private final RenderThread mThread; - - public static RenderHandler createHandler() { -// if (DEBUG) Log.v(TAG, "createHandler:"); - return createHandler("RenderThread"); - } - - public static final RenderHandler createHandler(final String name) { -// if (DEBUG) Log.v(TAG, "createHandler:name=" + name); - final RenderThread thread = new RenderThread(name); - thread.start(); - return thread.getHandler(); - } - - public final void setEglContext(final EGLBase.IContext sharedContext, - final int tex_id, final Object surface, final boolean isRecordable) { -// if (DEBUG) Log.i(TAG, "RenderHandler:setEglContext:"); - if (!(surface instanceof Surface) - && !(surface instanceof SurfaceTexture) - && !(surface instanceof SurfaceHolder)) - throw new RuntimeException("unsupported window type:" + surface); - mTexId = tex_id; - sendMessage(obtainMessage(MSG_RENDER_SET_GLCONTEXT, - isRecordable ? 1 : 0, 0, new ContextParams(sharedContext, surface))); - } - - public final void draw() { - sendMessage(obtainMessage(MSG_RENDER_DRAW, mTexId, 0, null)); - } - - public final void draw(final int tex_id) { - sendMessage(obtainMessage(MSG_RENDER_DRAW, tex_id, 0, null)); - } - - public final void draw(final float[] tex_matrix) { - sendMessage(obtainMessage(MSG_RENDER_DRAW, mTexId, 0, tex_matrix)); - } - - public final void draw(final int tex_id, final float[] tex_matrix) { - sendMessage(obtainMessage(MSG_RENDER_DRAW, tex_id, 0, tex_matrix)); - } - - public boolean isValid() { - synchronized (mThread.mSync) { - sendEmptyMessage(MSG_CHECK_VALID); - try { - mThread.mSync.wait(); - } catch (final InterruptedException e) { - } - return mThread.mSurface != null && mThread.mSurface.isValid(); - } - } - - public final void release() { -// if (DEBUG) Log.i(TAG, "release:"); - removeMessages(MSG_RENDER_SET_GLCONTEXT); - removeMessages(MSG_RENDER_DRAW); - sendEmptyMessage(MSG_RENDER_QUIT); - } - - @Override - public final void handleMessage(final Message msg) { - switch (msg.what) { - case MSG_RENDER_SET_GLCONTEXT: - final ContextParams params = (ContextParams)msg.obj; - mThread.handleSetEglContext(params.sharedContext, params.surface, msg.arg1 != 0); - break; - case MSG_RENDER_DRAW: - mThread.handleDraw(msg.arg1, (float[])msg.obj); - break; - case MSG_CHECK_VALID: - synchronized (mThread.mSync) { - mThread.mSync.notify(); - } - break; - case MSG_RENDER_QUIT: - Looper.myLooper().quit(); - break; - default: - super.handleMessage(msg); - } - } - -//******************************************************************************** -//******************************************************************************** - private RenderHandler(final RenderThread thread) { -// if (DEBUG) Log.i(TAG, "RenderHandler:"); - mThread = thread; - } - - private static final class ContextParams { - final EGLBase.IContext sharedContext; - final Object surface; - public ContextParams(final EGLBase.IContext sharedContext, final Object surface) { - this.sharedContext = sharedContext; - this.surface = surface; - } - } - - /** - * Thread to execute render methods - * You can also use HandlerThread insted of this and create Handler from its Looper. - */ - private static final class RenderThread extends Thread { - private static final String TAG_THREAD = "RenderThread"; - private final Object mSync = new Object(); - private RenderHandler mHandler; - private EGLBase mEgl; - private EGLBase.IEglSurface mTargetSurface; - private Surface mSurface; - private GLDrawer2D mDrawer; - - public RenderThread(final String name) { - super(name); - } - - public final RenderHandler getHandler() { - synchronized (mSync) { - // create rendering thread - try { - mSync.wait(); - } catch (final InterruptedException e) { - } - } - return mHandler; - } - - /** - * Set shared context and Surface - * @param shardContext - * @param surface - */ - public final void handleSetEglContext(final EGLBase.IContext shardContext, - final Object surface, final boolean isRecordable) { -// if (DEBUG) Log.i(TAG_THREAD, "setEglContext:"); - release(); - synchronized (mSync) { - mSurface = surface instanceof Surface ? (Surface)surface - : (surface instanceof SurfaceTexture - ? new Surface((SurfaceTexture)surface) : null); - } - mEgl = EGLBase.createFrom(3, shardContext, false, 0, isRecordable); - try { - mTargetSurface = mEgl.createFromSurface(surface); - mDrawer = new GLDrawer2D(isRecordable); - } catch (final Exception e) { - Log.w(TAG, e); - if (mTargetSurface != null) { - mTargetSurface.release(); - mTargetSurface = null; - } - if (mDrawer != null) { - mDrawer.release(); - mDrawer = null; - } - } - } - - /** - * drawing - * @param tex_id - * @param tex_matrix - */ - public void handleDraw(final int tex_id, final float[] tex_matrix) { -// if (DEBUG) Log.i(TAG_THREAD, "draw"); - if (tex_id >= 0 && mTargetSurface != null) { - mTargetSurface.makeCurrent(); - mDrawer.draw(tex_id, tex_matrix, 0); - mTargetSurface.swap(); - } - } - - @Override - public final void run() { -// if (DEBUG) Log.v(TAG_THREAD, "started"); - Looper.prepare(); - synchronized (mSync) { - mHandler = new RenderHandler(this); - mSync.notify(); - } - Looper.loop(); -// if (DEBUG) Log.v(TAG_THREAD, "finishing"); - release(); - synchronized (mSync) { - mHandler = null; - } -// if (DEBUG) Log.v(TAG_THREAD, "finished"); - } - - private final void release() { -// if (DEBUG) Log.v(TAG_THREAD, "release:"); - if (mDrawer != null) { - mDrawer.release(); - mDrawer = null; - } - synchronized (mSync) { - mSurface = null; - } - if (mTargetSurface != null) { - clear(); - mTargetSurface.release(); - mTargetSurface = null; - } - if (mEgl != null) { - mEgl.release(); - mEgl = null; - } - } - - /** - * Fill black on specific Surface - */ - private final void clear() { -// if (DEBUG) Log.v(TAG_THREAD, "clear:"); - mTargetSurface.makeCurrent(); - GLES20.glClearColor(0, 0, 0, 1); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - mTargetSurface.swap(); - } - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RenderHolderCallback.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RenderHolderCallback.java deleted file mode 100644 index 44477966aa..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RenderHolderCallback.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.view.Surface; - -/** - * RenderHolderのコールバックリスナー - */ -public interface RenderHolderCallback { - public void onCreate(Surface surface); - public void onFrameAvailable(); - public void onDestroy(); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererHolder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererHolder.java deleted file mode 100644 index 043f5e4302..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererHolder.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -/** - * Hold shared texture that has camera frame and draw them to registered surface if needs
- */ -public class RendererHolder extends AbstractRendererHolder { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = RendererHolder.class.getSimpleName(); - - public RendererHolder(final int width, final int height, - @Nullable final RenderHolderCallback callback) { - - this(width, height, - 3, null, EglTask.EGL_FLAG_RECORDABLE, - callback); - } - - public RendererHolder(final int width, final int height, - final int maxClientVersion, final EGLBase.IContext sharedContext, final int flags, - @Nullable final RenderHolderCallback callback) { - - super(width, height, - maxClientVersion, sharedContext, flags, - callback); - } - - @NonNull - protected RendererTask createRendererTask(final int width, final int height, - final int maxClientVersion, final EGLBase.IContext sharedContext, final int flags) { - - return new MyRendererTask(this, width, height, - maxClientVersion, sharedContext, flags); - } - -//================================================================================ -// 実装 -//================================================================================ - /** - * ワーカースレッド上でOpenGL|ESを用いてマスター映像を分配描画するためのインナークラス - */ - protected static final class MyRendererTask extends RendererTask { - - public MyRendererTask(final RendererHolder parent, - final int width, final int height) { - - super(parent, width, height); - } - - public MyRendererTask(@NonNull final AbstractRendererHolder parent, - final int width, final int height, - final int maxClientVersion, - final EGLBase.IContext sharedContext, final int flags) { - - super(parent, width, height, maxClientVersion, sharedContext, flags); - } - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererOnFrameAvailableListener.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererOnFrameAvailableListener.java deleted file mode 100644 index 0d9064f484..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererOnFrameAvailableListener.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -public interface RendererOnFrameAvailableListener { - void onFrameAvailable(long presentationTimeUs); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererSurfaceRec.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererSurfaceRec.java deleted file mode 100644 index a59125d4d9..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/RendererSurfaceRec.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.opengl.GLES20; -import android.opengl.Matrix; - -import com.serenegiant.utils.Time; - -/** - * 同じ内容のクラスだったからEffectRendererHolder/RendererHolderのインナークラスを外に出した - */ -class RendererSurfaceRec { - - /** - * ファクトリーメソッド - * @param egl - * @param surface - * @param maxFps 0以下なら最大描画フレームレート制限なし, あまり正確じゃない - * @return - */ - static RendererSurfaceRec newInstance(final EGLBase egl, - final Object surface, final int maxFps) { - - return (maxFps > 0) - ? new RendererSurfaceRecHasWait(egl, surface, maxFps) - : new RendererSurfaceRec(egl, surface); // no limitation of maxFps - } - - /** 元々の分配描画用Surface */ - private Object mSurface; - /** 分配描画用Surfaceを元に生成したOpenGL|ESで描画する為のEglSurface */ - private EGLBase.IEglSurface mTargetSurface; - final float[] mMvpMatrix = new float[16]; - protected volatile boolean mEnable = true; - - /** - * コンストラクタ, ファクトリーメソッドの使用を強制するためprivate - * @param egl - * @param surface - */ - private RendererSurfaceRec(final EGLBase egl, final Object surface) { - mSurface = surface; - mTargetSurface = egl.createFromSurface(surface); - Matrix.setIdentityM(mMvpMatrix, 0); - } - - /** - * 生成したEglSurfaceを破棄する - */ - public void release() { - if (mTargetSurface != null) { - mTargetSurface.release(); - mTargetSurface = null; - } - mSurface = null; - } - - /** - * Surfaceが有効かどうかを取得する - * @return - */ - public boolean isValid() { - return (mTargetSurface != null) && mTargetSurface.isValid(); - } - - private void check() throws IllegalStateException { - if (mTargetSurface == null) { - throw new IllegalStateException("already released"); - } - } - - /** - * Surfaceへの描画が有効かどうかを取得する - * @return - */ - public boolean isEnabled() { - return mEnable; - } - - /** - * Surfaceへの描画を一時的に有効/無効にする - * @param enable - */ - public void setEnabled(final boolean enable) { - mEnable = enable; - } - - public boolean canDraw() { - return mEnable; - } - - public void draw(final GLDrawer2D drawer, final int textId, final float[] texMatrix) { - if (mTargetSurface != null) { - mTargetSurface.makeCurrent(); - // 本来は映像が全面に描画されるので#glClearでクリアする必要はないけど - // ハングアップする機種があるのでクリアしとく - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - drawer.setMvpMatrix(mMvpMatrix, 0); - drawer.draw(textId, texMatrix, 0); - mTargetSurface.swap(); - } - } - - /** - * 指定した色で全面を塗りつぶす - * @param color - */ - public void clear(final int color) { - if (mTargetSurface != null) { - mTargetSurface.makeCurrent(); - GLES20.glClearColor( - ((color & 0x00ff0000) >>> 16) / 255.0f, // R - ((color & 0x0000ff00) >>> 8) / 255.0f, // G - ((color & 0x000000ff)) / 255.0f, // B - ((color & 0xff000000) >>> 24) / 255.0f // A - ); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - mTargetSurface.swap(); - } - } - - /** - * #drawの代わりにOpenGL|ES2を使って自前で描画する場合は - * #makeCurrentでレンダリングコンテキストを切り替えてから - * 描画後#swapを呼ぶ - */ - public void makeCurrent() throws IllegalStateException { - check(); - mTargetSurface.makeCurrent(); - } - - /** - * #drawの代わりにOpenGL|ES2を使って自前で描画する場合は - * #makeCurrentでレンダリングコンテキストを切り替えてから - * 描画後#swapを呼ぶ - */ - public void swap() throws IllegalStateException { - check(); - mTargetSurface.swap(); - } - - private static class RendererSurfaceRecHasWait extends RendererSurfaceRec { - private long mNextDraw; - private final long mIntervalsNs; - - /** - * コンストラクタ, ファクトリーメソッドの使用を強制するためprivate - * @param egl - * @param surface - * @param maxFps 正数 - */ - private RendererSurfaceRecHasWait(final EGLBase egl, - final Object surface, final int maxFps) { - - super(egl, surface); - mIntervalsNs = 1000000000L / maxFps; - mNextDraw = Time.nanoTime() + mIntervalsNs; - } - - @Override - public boolean canDraw() { - return mEnable && (Time.nanoTime() - mNextDraw > 0); - } - - @Override - public void draw(final GLDrawer2D drawer, - final int textId, final float[] texMatrix) { - - mNextDraw = Time.nanoTime() + mIntervalsNs; - super.draw(drawer, textId, texMatrix); - } - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/ShaderConst.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/ShaderConst.java deleted file mode 100644 index 99b05961a8..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/ShaderConst.java +++ /dev/null @@ -1,421 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.opengl.GLES20; - -/** - * Created by saki on 16/08/26. - * フラグメントシェーダーとかの文字列定数達を集める - */ -public class ShaderConst { - public static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65; - public static final int GL_TEXTURE_2D = 0x0DE1; - - public static final String SHADER_VERSION = "#version 100\n"; - - public static final String HEADER_2D = ""; - public static final String SAMPLER_2D = "sampler2D"; - - public static final String HEADER_OES = "#extension GL_OES_EGL_image_external : require\n"; - public static final String SAMPLER_OES = "samplerExternalOES"; - - public static final int KERNEL_SIZE3x3 = 9; - public static final int KERNEL_SIZE5x5 = 25; - - public static final int NO_TEXTURE = -1; - - public static final int[] TEX_NUMBERS = { - GLES20.GL_TEXTURE0, GLES20.GL_TEXTURE1, - GLES20.GL_TEXTURE2, GLES20.GL_TEXTURE3, - GLES20.GL_TEXTURE4, GLES20.GL_TEXTURE5, - GLES20.GL_TEXTURE6, GLES20.GL_TEXTURE7, - GLES20.GL_TEXTURE8, GLES20.GL_TEXTURE9, - GLES20.GL_TEXTURE10, GLES20.GL_TEXTURE11, - GLES20.GL_TEXTURE12, GLES20.GL_TEXTURE13, - GLES20.GL_TEXTURE14, GLES20.GL_TEXTURE15, - GLES20.GL_TEXTURE16, GLES20.GL_TEXTURE17, - GLES20.GL_TEXTURE18, GLES20.GL_TEXTURE19, - GLES20.GL_TEXTURE20, GLES20.GL_TEXTURE21, - GLES20.GL_TEXTURE22, GLES20.GL_TEXTURE23, - GLES20.GL_TEXTURE24, GLES20.GL_TEXTURE25, - GLES20.GL_TEXTURE26, GLES20.GL_TEXTURE27, - GLES20.GL_TEXTURE28, GLES20.GL_TEXTURE29, - GLES20.GL_TEXTURE30, GLES20.GL_TEXTURE31, - }; - -// 関数文字列定義 - /** - * RGBをHSVに変換 - * {R[0.0-1.0], G[0.0-1.0], B([0.0-1.0]} => {H[0.0-1.0], S[0.0-1.0], V[0.0-1.0]} - */ - public static final String FUNC_RGB2HSV - = "vec3 rgb2hsv(vec3 c) {\n" + - "vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n" + - "vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n" + - "vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n" + - "float d = q.x - min(q.w, q.y);\n" + - "float e = 1.0e-10;\n" + - "return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n" + - "}\n"; - /** - * HSVをRGBに変換 - * {H[0.0-1.0], S[0.0-1.0], V[0.0-1.0]} => {R[0.0-1.0], G[0.0-1.0], B([0.0-1.0]} - */ - public static final String FUNC_HSV2RGB - = "vec3 hsv2rgb(vec3 c) {\n" + - "vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n" + - "vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n" + - "return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n" + - "}\n"; - - /** - * RGBの輝度を取得 - * 変換係数との内積を計算するだけ - * 係数は(0.2125, 0.7154, 0.0721) - */ - public static final String FUNC_GET_INTENSITY - = "const highp vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n" + - "highp float getIntensity(vec3 c) {\n" + - "return dot(c.rgb, luminanceWeighting);\n" + - "}\n"; - -// 頂点シェーダー - /** - * モデルビュー変換行列とテクスチャ変換行列適用するだけの頂点シェーダー - */ - public static final String VERTEX_SHADER = SHADER_VERSION + - "uniform mat4 uMVPMatrix;\n" + // モデルビュー変換行列 - "uniform mat4 uTexMatrix;\n" + // テクスチャ変換行列 - "attribute highp vec4 aPosition;\n" + // 頂点座標 - "attribute highp vec4 aTextureCoord;\n" + // テクスチャ情報 - "varying highp vec2 vTextureCoord;\n" + // フラグメントシェーダーへ引き渡すテクスチャ座標 - "void main() {\n" + - " gl_Position = uMVPMatrix * aPosition;\n" + - " vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" + - "}\n"; - -// フラグメントシェーダー - public static final String FRAGMENT_SHADER_SIMPLE_OES - = SHADER_VERSION - + HEADER_OES - + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" - + "varying highp vec2 vTextureCoord;\n" - + "void main() {\n" - + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" - + "}"; - - public static final String FRAGMENT_SHADER_SIMPLE - = SHADER_VERSION - + HEADER_2D - + "precision mediump float;\n" - + "uniform sampler2D sTexture;\n" - + "varying highp vec2 vTextureCoord;\n" - + "void main() {\n" - + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" - + "}"; - -// - // Simple fragment shader for use with "normal" 2D textures. - private static final String FRAGMENT_SHADER_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "void main() {\n" + - " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + - "}\n"; - public static final String FRAGMENT_SHADER_2D - = String.format(FRAGMENT_SHADER_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT - = String.format(FRAGMENT_SHADER_BASE, HEADER_OES, SAMPLER_OES); - - // Fragment shader that converts color to black & white with a simple transformation. - private static final String FRAGMENT_SHADER_BW_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11;\n" + - " gl_FragColor = vec4(color, color, color, 1.0);\n" + - "}\n"; - public static final String FRAGMENT_SHADER_BW - = String.format(FRAGMENT_SHADER_BW_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT_BW - = String.format(FRAGMENT_SHADER_BW_BASE, HEADER_OES, SAMPLER_OES); - - // Fragment shader that attempts to produce a high contrast image - private static final String FRAGMENT_SHADER_NIGHT_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = ((tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11) - 0.5 * 1.5) + 0.8;\n" + - " gl_FragColor = vec4(color, color + 0.15, color, 1.0);\n" + - "}\n"; - public static final String FRAGMENT_SHADER_NIGHT - = String.format(FRAGMENT_SHADER_NIGHT_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT_NIGHT - = String.format(FRAGMENT_SHADER_NIGHT_BASE, HEADER_OES, SAMPLER_OES); - - // Fragment shader that applies a Chroma Key effect, making green pixels transparent - private static final String FRAGMENT_SHADER_CHROMA_KEY_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "void main() {\n" + - " vec4 tc = texture2D(sTexture, vTextureCoord);\n" + - " float color = ((tc.r * 0.3 + tc.g * 0.59 + tc.b * 0.11) - 0.5 * 1.5) + 0.8;\n" + - " if(tc.g > 0.6 && tc.b < 0.6 && tc.r < 0.6){ \n" + - " gl_FragColor = vec4(0, 0, 0, 0.0);\n" + - " }else{ \n" + - " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + - " }\n" + - "}\n"; - public static final String FRAGMENT_SHADER_CHROMA_KEY - = String.format(FRAGMENT_SHADER_CHROMA_KEY_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT_CHROMA_KEY - = String.format(FRAGMENT_SHADER_CHROMA_KEY_BASE, HEADER_OES, SAMPLER_OES); - - private static final String FRAGMENT_SHADER_SQUEEZE_BASE = SHADER_VERSION + - "%s" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " float r = length(normCoord); // to polar coords \n" + - " float phi = atan(normCoord.y + uPosition.y, normCoord.x + uPosition.x); // to polar coords \n"+ - " r = pow(r, 1.0/1.8) * 0.8;\n"+ // Squeeze it - " normCoord.x = r * cos(phi); \n" + - " normCoord.y = r * sin(phi); \n" + - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - public static final String FRAGMENT_SHADER_SQUEEZE - = String.format(FRAGMENT_SHADER_SQUEEZE_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT_SQUEEZE - = String.format(FRAGMENT_SHADER_SQUEEZE_BASE, HEADER_OES, SAMPLER_OES); - - public static final String FRAGMENT_SHADER_EXT_TWIRL = - "#version 100\n" + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " float r = length(normCoord); // to polar coords \n" + - " float phi = atan(normCoord.y + uPosition.y, normCoord.x + uPosition.x); // to polar coords \n"+ - " phi = phi + (1.0 - smoothstep(-0.5, 0.5, r)) * 4.0;\n"+ // Twirl it - " normCoord.x = r * cos(phi); \n" + - " normCoord.y = r * sin(phi); \n" + - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_EXT_TUNNEL = SHADER_VERSION + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " float r = length(normCoord); // to polar coords \n" + - " float phi = atan(normCoord.y + uPosition.y, normCoord.x + uPosition.x); // to polar coords \n"+ - " if (r > 0.5) r = 0.5;\n"+ // Tunnel - " normCoord.x = r * cos(phi); \n" + - " normCoord.y = r * sin(phi); \n" + - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_EXT_BULGE = SHADER_VERSION + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " float r = length(normCoord); // to polar coords \n" + - " float phi = atan(normCoord.y + uPosition.y, normCoord.x + uPosition.x); // to polar coords \n"+ - " r = r * smoothstep(-0.1, 0.5, r);\n"+ // Bulge - " normCoord.x = r * cos(phi); \n" + - " normCoord.y = r * sin(phi); \n" + - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_EXT_DENT = SHADER_VERSION + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " float r = length(normCoord); // to polar coords \n" + - " float phi = atan(normCoord.y + uPosition.y, normCoord.x + uPosition.x); // to polar coords \n"+ - " r = 2.0 * r - r * smoothstep(0.0, 0.7, r);\n"+ // Dent - " normCoord.x = r * cos(phi); \n" + - " normCoord.y = r * sin(phi); \n" + - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_EXT_FISHEYE = SHADER_VERSION + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " float r = length(normCoord); // to polar coords \n" + - " float phi = atan(normCoord.y + uPosition.y, normCoord.x + uPosition.x); // to polar coords \n"+ - " r = r * r / sqrt(2.0);\n"+ // Fisheye - " normCoord.x = r * cos(phi); \n" + - " normCoord.y = r * sin(phi); \n" + - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_EXT_STRETCH = SHADER_VERSION + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " vec2 s = sign(normCoord + uPosition);\n"+ - " normCoord = abs(normCoord);\n"+ - " normCoord = 0.5 * normCoord + 0.5 * smoothstep(0.25, 0.5, normCoord) * normCoord;\n"+ - " normCoord = s * normCoord;\n"+ - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_EXT_MIRROR = SHADER_VERSION + - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform samplerExternalOES sTexture;\n" + - "uniform vec2 uPosition;\n" + - "void main() {\n" + - " vec2 texCoord = vTextureCoord.xy;\n" + - " vec2 normCoord = 2.0 * texCoord - 1.0;\n"+ - " normCoord.x = normCoord.x * sign(normCoord.x + uPosition.x);\n"+ - " texCoord = normCoord / 2.0 + 0.5;\n"+ - " gl_FragColor = texture2D(sTexture, texCoord);\n"+ - "}\n"; - - public static final String FRAGMENT_SHADER_SOBEL_BASE = SHADER_VERSION + - "%s" + - "#define KERNEL_SIZE3x3 " + KERNEL_SIZE3x3 + "\n" + - "precision highp float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "uniform float uKernel[18];\n" + - "uniform vec2 uTexOffset[KERNEL_SIZE3x3];\n" + - "uniform float uColorAdjust;\n" + - "void main() {\n" + - " vec3 t0 = texture2D(sTexture, vTextureCoord + uTexOffset[0]).rgb;\n" + - " vec3 t1 = texture2D(sTexture, vTextureCoord + uTexOffset[1]).rgb;\n" + - " vec3 t2 = texture2D(sTexture, vTextureCoord + uTexOffset[2]).rgb;\n" + - " vec3 t3 = texture2D(sTexture, vTextureCoord + uTexOffset[3]).rgb;\n" + - " vec3 t4 = texture2D(sTexture, vTextureCoord + uTexOffset[4]).rgb;\n" + - " vec3 t5 = texture2D(sTexture, vTextureCoord + uTexOffset[5]).rgb;\n" + - " vec3 t6 = texture2D(sTexture, vTextureCoord + uTexOffset[6]).rgb;\n" + - " vec3 t7 = texture2D(sTexture, vTextureCoord + uTexOffset[7]).rgb;\n" + - " vec3 t8 = texture2D(sTexture, vTextureCoord + uTexOffset[8]).rgb;\n" + - " vec3 sumH = t0 * uKernel[0] + t1 * uKernel[1] + t2 * uKernel[2]\n" + - " + t3 * uKernel[3] + t4 * uKernel[4] + t5 * uKernel[5]\n" + - " + t6 * uKernel[6] + t7 * uKernel[7] + t8 * uKernel[8];\n" + -// " vec3 sumV = t0 * uKernel[ 9] + t1 * uKernel[10] + t2 * uKernel[11]\n" + -// " + t3 * uKernel[12] + t4 * uKernel[13] + t5 * uKernel[14]\n" + -// " + t6 * uKernel[15] + t7 * uKernel[16] + t8 * uKernel[17];\n" + -// " float mag = length(abs(sumH) + abs(sumV));\n" + - " float mag = length(sumH);\n" + - " gl_FragColor = vec4(vec3(mag), 1.0);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_SOBEL - = String.format(FRAGMENT_SHADER_SOBEL_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT_SOBEL - = String.format(FRAGMENT_SHADER_SOBEL_BASE, HEADER_OES, SAMPLER_OES); - - public static final float[] KERNEL_NULL = { 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f}; - public static final float[] KERNEL_SOBEL_H = { 1f, 0f, -1f, 2f, 0f, -2f, 1f, 0f, -1f, }; // ソーベル(1次微分) - public static final float[] KERNEL_SOBEL_V = { 1f, 2f, 1f, 0f, 0f, 0f, -1f, -2f, -1f, }; - public static final float[] KERNEL_SOBEL2_H = { 3f, 0f, -3f, 10f, 0f, -10f, 3f, 0f, -3f, }; - public static final float[] KERNEL_SOBEL2_V = { 3f, 10f, 3f, 0f, 0f, 0f, -3f, -10f, -3f, }; - public static final float[] KERNEL_SHARPNESS = { 0f, -1f, 0f, -1f, 5f, -1f, 0f, -1f, 0f,}; // シャープネス - public static final float[] KERNEL_EDGE_DETECT = { -1f, -1f, -1f, -1f, 8f, -1f, -1f, -1f, -1f, }; // エッジ検出 - public static final float[] KERNEL_EMBOSS = { 2f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f }; // エンボス, オフセット0.5f - public static final float[] KERNEL_SMOOTH = { 1/9f, 1/9f, 1/9f, 1/9f, 1/9f, 1/9f, 1/9f, 1/9f, 1/9f, }; // 移動平均 - public static final float[] KERNEL_GAUSSIAN = { 1/16f, 2/16f, 1/16f, 2/16f, 4/16f, 2/16f, 1/16f, 2/16f, 1/16f, }; // ガウシアン(ノイズ除去/) - public static final float[] KERNEL_BRIGHTEN = { 1f, 1f, 1f, 1f, 2f, 1f, 1f, 1f, 1f, }; - public static final float[] KERNEL_LAPLACIAN = { 1f, 1f, 1f, 1f, -8f, 1f, 1f, 1f, 1f, }; // ラプラシアン(2次微分) - - private static final String FRAGMENT_SHADER_FILT3x3_BASE = SHADER_VERSION + - "%s" + - "#define KERNEL_SIZE3x3 " + KERNEL_SIZE3x3 + "\n" + - "precision highp float;\n" + - "varying vec2 vTextureCoord;\n" + - "uniform %s sTexture;\n" + - "uniform float uKernel[18];\n" + - "uniform vec2 uTexOffset[KERNEL_SIZE3x3];\n" + - "uniform float uColorAdjust;\n" + - "void main() {\n" + - " vec4 sum = vec4(0.0);\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[0]) * uKernel[0];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[1]) * uKernel[1];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[2]) * uKernel[2];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[3]) * uKernel[3];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[4]) * uKernel[4];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[5]) * uKernel[5];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[6]) * uKernel[6];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[7]) * uKernel[7];\n" + - " sum += texture2D(sTexture, vTextureCoord + uTexOffset[8]) * uKernel[8];\n" + - " gl_FragColor = sum + uColorAdjust;\n" + - "}\n"; - public static final String FRAGMENT_SHADER_FILT3x3 - = String.format(FRAGMENT_SHADER_FILT3x3_BASE, HEADER_2D, SAMPLER_2D); - public static final String FRAGMENT_SHADER_EXT_FILT3x3 - = String.format(FRAGMENT_SHADER_FILT3x3_BASE, HEADER_OES, SAMPLER_OES); - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/StaticTextureSource.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/StaticTextureSource.java deleted file mode 100644 index bb833b966e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/StaticTextureSource.java +++ /dev/null @@ -1,553 +0,0 @@ -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -package com.serenegiant.glutils; - -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.opengl.GLES20; -import android.util.Log; -import android.util.SparseArray; -import android.view.Surface; -import android.view.SurfaceHolder; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -/** - * MediaCodecのデコーダーでデコードした動画や - * カメラからの映像の代わりに静止画をSurfaceへ - * 出力するためのクラス - */ -public class StaticTextureSource { - private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = StaticTextureSource.class.getSimpleName(); - - private final Object mSync = new Object(); - private RendererTask mRendererTask; - private volatile boolean isRunning; - - /** - * フレームレート指定付きコンストラクタ - * @param fps - */ - public StaticTextureSource(final float fps) { - this(null, fps); - } - - /** - * ソースの静止画を指定したコンストラクタ, フレームレートは10fps固定 - * @param bitmap - */ - public StaticTextureSource(@Nullable final Bitmap bitmap) { - this(bitmap, 10.0f); - } - - /** - * ソースの静止画とフレームレートを指定可能なコンストラクタ - * @param bitmap - * @param fps - */ - public StaticTextureSource(@Nullable final Bitmap bitmap, final float fps) { - final int width = bitmap != null ? bitmap.getWidth() : 1; - final int height = bitmap != null ? bitmap.getHeight() : 1; - mRendererTask = new RendererTask(this, width, height, fps); - new Thread(mRendererTask, TAG).start(); - if (!mRendererTask.waitReady()) { - // 初期化に失敗した時 - throw new RuntimeException("failed to start renderer thread"); - } - setBitmap(bitmap); - } - - /** - * 実行中かどうか - * @return - */ - public boolean isRunning() { - return isRunning; - } - - /** - * 関係するすべてのリソースを開放する。再利用できない - */ - public void release() { - if (DEBUG) Log.v(TAG, "release:"); - isRunning = false; - synchronized (mSync) { - mSync.notifyAll(); - } - if (mRendererTask != null) { - mRendererTask.release(); - } - synchronized (mSync) { - mRendererTask = null; - mSync.notifyAll(); - } - if (DEBUG) Log.v(TAG, "release:finished"); - } - - /** - * 分配描画用のSurfaceを追加 - * @param id 普通はSurface#hashCodeを使う - * @param surface - * @param isRecordable - */ - public void addSurface(final int id, final Object surface, - final boolean isRecordable) { - - if (DEBUG) Log.v(TAG, "addSurface:id=" + id + ",surface=" + surface); - synchronized (mSync) { - mRendererTask.addSurface(id, surface); - } - } - - /** - * 分配描画用のSurfaceを追加 - * @param id - * @param surface - * @param isRecordable - * @param maxFps コンストラクタで指定した値より大きくしても速く描画されるわけではない - */ - public void addSurface(final int id, final Object surface, - final boolean isRecordable, final int maxFps) { - - if (DEBUG) Log.v(TAG, "addSurface:id=" + id + ",surface=" + surface); - synchronized (mSync) { - mRendererTask.addSurface(id, surface, maxFps); - } - } - - /** - * 分配描画用のSurfaceを削除 - * @param id - */ - public void removeSurface(final int id) { - if (DEBUG) Log.v(TAG, "removeSurface:id=" + id); - synchronized (mSync) { - mRendererTask.removeSurface(id); - } - } - - /** - * 強制的に現在の最新のフレームを描画要求する - * 分配描画用Surface全てが更新されるので注意 - */ - public void requestFrame() { - synchronized (mSync) { - mRendererTask.removeRequest(REQUEST_DRAW); - mRendererTask.offer(REQUEST_DRAW); - mSync.notify(); - } - } - - /** - * 追加されている分配描画用のSurfaceの数を取得 - * @return - */ - public int getCount() { - return mRendererTask.getCount(); - } - - /** - * ソース静止画を指定 - * 既にセットされていれば古いほうが破棄される - * @param bitmap nullなら何もしない - */ - public void setBitmap(final Bitmap bitmap) { - if (DEBUG) Log.v(TAG, "setBitmap:bitmap=" + bitmap); - if (bitmap != null) { - synchronized (mSync) { - mRendererTask.setBitmap(bitmap); - } - } - } - - /** - * ソース静止画の幅を取得 - * @return 既にreleaseされていれば0 - */ - public int getWidth() { - synchronized (mSync) { - return mRendererTask != null ? mRendererTask.mVideoWidth : 0; - } - } - - /** - * ソース静止画の高さを取得 - * @return 既にreleaseされていれば0 - */ - public int getHeight() { - synchronized (mSync) { - return mRendererTask != null ? mRendererTask.mVideoHeight : 0; - } - } - - private static final int REQUEST_DRAW = 1; - private static final int REQUEST_ADD_SURFACE = 3; - private static final int REQUEST_REMOVE_SURFACE = 4; - private static final int REQUEST_SET_BITMAP = 7; - - private static class RendererTask extends EglTask { - private final Object mClientSync = new Object(); - private final SparseArray mClients - = new SparseArray(); - private final StaticTextureSource mParent; - private final long mIntervalsNs; - private GLDrawer2D mDrawer; - private int mVideoWidth, mVideoHeight; - private TextureOffscreen mImageSource; - - public RendererTask(final StaticTextureSource parent, - final int width, final int height, final float fps) { - - super(3, null, 0); - mParent = parent; - mVideoWidth = width; - mVideoHeight = height; - mIntervalsNs = fps <= 0 ? 100000000L : (long)(1000000000L / fps); - } - - /** - * ワーカースレッド開始時の処理(ここはワーカースレッド上) - */ - @Override - protected void onStart() { - if (DEBUG) Log.v(TAG, "onStart:"); - mDrawer = new GLDrawer2D(false); // GL_TEXTURE_EXTERNAL_OESを使わない - synchronized (mParent.mSync) { - mParent.isRunning = true; - mParent.mSync.notifyAll(); - } - new Thread(mParent.mOnFrameTask, TAG).start(); - if (DEBUG) Log.v(TAG, "onStart:finished"); - } - - /** - * ワーカースレッド終了時の処理(ここはまだワーカースレッド上) - */ - @Override - protected void onStop() { - if (DEBUG) Log.v(TAG, "onStop"); - synchronized (mParent.mSync) { - mParent.isRunning = false; - mParent.mSync.notifyAll(); - } - makeCurrent(); - if (mDrawer != null) { - mDrawer.release(); - mDrawer = null; - } - if (mImageSource != null) { - mImageSource.release(); - mImageSource = null; - } - handleRemoveAll(); - if (DEBUG) Log.v(TAG, "onStop:finished"); - } - - @Override - protected boolean onError(final Exception e) { - if (DEBUG) Log.w(TAG, e); - return false; - } - - @Override - protected Object processRequest(final int request, - final int arg1, final int arg2, final Object obj) { - - switch (request) { - case REQUEST_DRAW: - handleDraw(); - break; - case REQUEST_ADD_SURFACE: - handleAddSurface(arg1, obj, arg2); - break; - case REQUEST_REMOVE_SURFACE: - handleRemoveSurface(arg1); - break; - case REQUEST_SET_BITMAP: - handleSetBitmap((Bitmap)obj); - break; - } - return null; - } - - /** - * 分配描画用のSurfaceを追加 - * @param id - * @param surface - */ - public void addSurface(final int id, final Object surface) { - addSurface(id, surface, -1); - } - - /** - * 分配描画用のSurfaceを追加 - * @param id - * @param surface - */ - public void addSurface(final int id, final Object surface, final int maxFps) { - checkFinished(); - if (!((surface instanceof SurfaceTexture) - || (surface instanceof Surface) - || (surface instanceof SurfaceHolder))) { - - throw new IllegalArgumentException( - "Surface should be one of Surface, SurfaceTexture or SurfaceHolder"); - } - synchronized (mClientSync) { - if (mClients.get(id) == null) { - for ( ; ; ) { - if (offer(REQUEST_ADD_SURFACE, id, maxFps, surface)) { - try { - mClientSync.wait(); - } catch (final InterruptedException e) { - // ignore - } - break; - } else { - try { - mClientSync.wait(10); - } catch (InterruptedException e) { - break; - } - } - } - } - } - } - - /** - * 分配描画用のSurfaceを削除 - * @param id - */ - public void removeSurface(final int id) { - synchronized (mClientSync) { - if (mClients.get(id) != null) { - for ( ; ; ) { - if (offer(REQUEST_REMOVE_SURFACE, id)) { - try { - mClientSync.wait(); - } catch (final InterruptedException e) { - // ignore - } - break; - } else { - try { - mClientSync.wait(10); - } catch (InterruptedException e) { - break; - } - } - } - } - } - } - - /** - * ソース静止画をセット - * @param bitmap - */ - public void setBitmap(@NonNull final Bitmap bitmap) { - offer(REQUEST_SET_BITMAP, bitmap); - } - - /** - * 分配描画用のSurfaceの数を取得 - * @return - */ - public int getCount() { - synchronized (mClientSync) { - return mClients.size(); - } - } - - private void checkFinished() { - if (isFinished()) { - throw new RuntimeException("already finished"); - } - } - -//================================================================================ -// ワーカースレッド上での処理 -//================================================================================ - /** - * 実際の描画処理 - */ - private void handleDraw() { -// if (DEBUG) Log.v(TAG, "handleDraw:"); - makeCurrent(); - // 各Surfaceへ描画する - if (mImageSource != null) { - final int texId = mImageSource.getTexture(); - synchronized (mClientSync) { - final int n = mClients.size(); - RendererSurfaceRec client; - for (int i = n - 1; i >= 0; i--) { - client = mClients.valueAt(i); - if ((client != null) && client.canDraw()) { - try { - client.draw(mDrawer, texId, null); // client.draw(mDrawer, mTexId, mTexMatrix); - GLHelper.checkGlError("handleSetBitmap"); - } catch (final Exception e) { - // removeSurfaceが呼ばれなかったかremoveSurfaceを呼ぶ前に破棄されてしまった - mClients.removeAt(i); - client.release(); - } - } - } - } - } else { - Log.w(TAG, "mImageSource is not ready"); - } - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - GLES20.glFlush(); -// if (DEBUG) Log.v(TAG, "handleDraw:finish"); - } - - /** - * 指定したIDの分配描画先Surfaceを追加する - * @param id - * @param surface - */ - private void handleAddSurface(final int id, final Object surface, final int maxFps) { - if (DEBUG) Log.v(TAG, "handleAddSurface:id=" + id); - checkSurface(); - synchronized (mClientSync) { - RendererSurfaceRec client = mClients.get(id); - if (client == null) { - try { - client = RendererSurfaceRec.newInstance(getEgl(), surface, maxFps); - mClients.append(id, client); - } catch (final Exception e) { - Log.w(TAG, "invalid surface: surface=" + surface, e); - } - } else { - Log.w(TAG, "surface is already added: id=" + id); - } - mClientSync.notifyAll(); - } - } - - /** - * 指定したIDの分配描画先Surfaceを破棄する - * @param id - */ - private void handleRemoveSurface(final int id) { - if (DEBUG) Log.v(TAG, "handleRemoveSurface:id=" + id); - synchronized (mClientSync) { - final RendererSurfaceRec client = mClients.get(id); - if (client != null) { - mClients.remove(id); - client.release(); - } - checkSurface(); - mClientSync.notifyAll(); - } - } - - /** - * 念の為に分配描画先のSurfaceを全て破棄する - */ - private void handleRemoveAll() { - if (DEBUG) Log.v(TAG, "handleRemoveAll:"); - synchronized (mClientSync) { - final int n = mClients.size(); - RendererSurfaceRec client; - for (int i = 0; i < n; i++) { - client = mClients.valueAt(i); - if (client != null) { - makeCurrent(); - client.release(); - } - } - mClients.clear(); - } - if (DEBUG) Log.v(TAG, "handleRemoveAll:finished"); - } - - /** - * 分配描画先のSurfaceが有効かどうかをチェックして無効なものは削除する - */ - private void checkSurface() { - if (DEBUG) Log.v(TAG, "checkSurface"); - synchronized (mClientSync) { - final int n = mClients.size(); - for (int i = 0; i < n; i++) { - final RendererSurfaceRec client = mClients.valueAt(i); - if ((client != null) && !client.isValid()) { - final int id = mClients.keyAt(i); - if (DEBUG) Log.i(TAG, "checkSurface:found invalid surface:id=" + id); - mClients.valueAt(i).release(); - mClients.remove(id); - } - } - } - if (DEBUG) Log.v(TAG, "checkSurface:finished"); - } - - /** - * ソース静止画をセット - * @param bitmap - */ - private void handleSetBitmap(final Bitmap bitmap) { - if (DEBUG) Log.v(TAG, "handleSetBitmap:bitmap=" + bitmap); - final int width = bitmap.getWidth(); - final int height = bitmap.getHeight(); - if (mImageSource == null) { - mImageSource = new TextureOffscreen(width, height, false); - GLHelper.checkGlError("handleSetBitmap"); - mImageSource.loadBitmap(bitmap); - } else { - mImageSource.loadBitmap(bitmap); - } - mVideoWidth = width; - mVideoHeight = height; - } - - } - - /** - * 一定時間おきに描画要求を送るためのRunnable - */ - private Runnable mOnFrameTask = new Runnable() { - @Override - public void run() { - final long ms = mRendererTask.mIntervalsNs / 1000000L; - final int ns = (int)(mRendererTask.mIntervalsNs % 1000000L); - for (; isRunning; ) { - if (mRendererTask == null) break; - synchronized (mSync) { - try { - mSync.wait(ms, ns); - if (mRendererTask.mImageSource != null) { - mRendererTask.removeRequest(REQUEST_DRAW); - mRendererTask.offer(REQUEST_DRAW); - mSync.notify(); - } - } catch (Exception e) { - Log.w(TAG, e); - } - } - } - } - }; - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/Texture2dProgram.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/Texture2dProgram.java deleted file mode 100644 index e66fc4ae88..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/Texture2dProgram.java +++ /dev/null @@ -1,535 +0,0 @@ -package com.serenegiant.glutils; -/* - * Copyright 2014 Google Inc. All rights reserved. - * Modified 2014-2018 t_saki@serenegiant.com - * - * 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. - */ - -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_2D; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_BULGE; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_BW; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_CHROMA_KEY; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_DENT; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_FILT3x3; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_FISHEYE; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_MIRROR; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_NIGHT; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_SQUEEZE; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_STRETCH; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_TUNNEL; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_EXT_TWIRL; -import static com.serenegiant.glutils.ShaderConst.FRAGMENT_SHADER_FILT3x3; -import static com.serenegiant.glutils.ShaderConst.GL_TEXTURE_EXTERNAL_OES; -import static com.serenegiant.glutils.ShaderConst.KERNEL_NULL; -import static com.serenegiant.glutils.ShaderConst.KERNEL_SIZE3x3; -import static com.serenegiant.glutils.ShaderConst.VERTEX_SHADER; - -import android.opengl.GLES11Ext; -import android.opengl.GLES20; -import android.util.Log; -import android.view.MotionEvent; - -import java.nio.FloatBuffer; - -/** - * GL program and supporting functions for textured 2D shapes. - */ -public class Texture2dProgram { - private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = "Texture2dProgram"; - - public enum ProgramType { - // ここはGL_TEXTURE_2D - TEXTURE_2D, -// TEXTURE_SOBEL, // フラグメントシェーダーがうまく走らなくて止まってしまう -// TEXTURE_SOBEL2, // フラグメントシェーダーがうまく走らなくて止まってしまう - TEXTURE_FILT3x3, - TEXTURE_CUSTOM, - // ここから下はGL_TEXTURE_EXTERNAL_OES - TEXTURE_EXT, - TEXTURE_EXT_BW, - TEXTURE_EXT_NIGHT, - TEXTURE_EXT_CHROMA_KEY, - TEXTURE_EXT_SQUEEZE, - TEXTURE_EXT_TWIRL, - TEXTURE_EXT_TUNNEL, - TEXTURE_EXT_BULGE, - TEXTURE_EXT_DENT, - TEXTURE_EXT_FISHEYE, - TEXTURE_EXT_STRETCH, - TEXTURE_EXT_MIRROR, -// TEXTURE_EXT_SOBEL, // フラグメントシェーダーがうまく走らなくて止まってしまう -// TEXTURE_EXT_SOBEL2, // フラグメントシェーダーがうまく走らなくて止まってしまう - TEXTURE_EXT_FILT3x3, - } - - private final Object mSync = new Object(); - private final ProgramType mProgramType; - - private float mTexWidth; - private float mTexHeight; - - // Handles to the GL program and various components of it. - private int mProgramHandle; - private final int muMVPMatrixLoc; // モデルビュー変換行列 - private final int muTexMatrixLoc; // テクスチャ行列 - private final int maPositionLoc; // - private final int maTextureCoordLoc;// - private int muKernelLoc; // カーネル行列(float配列) - private int muTexOffsetLoc; // テクスチャオフセット(カーネル行列用) - private int muColorAdjustLoc; // 色調整 - private int muTouchPositionLoc; - private int muFlagsLoc; - - private int mTextureTarget; - - protected boolean mHasKernel2; - /** Inputs for convolution filter based shaders */ - private final float[] mKernel = new float[KERNEL_SIZE3x3 * 2]; - /** Summed touch event delta */ - private final float[] mSummedTouchPosition = new float[2]; - /** Raw location of last touch event */ - private final float[] mLastTouchPosition = new float[2]; - private float[] mTexOffset; - private float mColorAdjust; - private final int[] mFlags = new int[4]; - - public Texture2dProgram(final int target, final String fss) { - this(ProgramType.TEXTURE_CUSTOM, target, VERTEX_SHADER, fss); - } - - public Texture2dProgram(final int target, final String vss, final String fss) { - this(ProgramType.TEXTURE_CUSTOM, target, vss, fss); - } - - public Texture2dProgram(final ProgramType programType) { - this(programType, 0, null, null); - } - - /** - * Prepares the program in the current EGL context. - */ - protected Texture2dProgram(final ProgramType programType, - final int target, final String vss, final String fss) { - - mProgramType = programType; - - float[] kernel = null, kernel2 = null; - switch (programType) { - case TEXTURE_2D: - mTextureTarget = GLES20.GL_TEXTURE_2D; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_2D); - break; -// case TEXTURE_SOBEL: -// mTextureTarget = GLES20.GL_TEXTURE_2D; -// mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_SOBEL); -// kernel = KERNEL_SOBEL_H; -// kernel2 = KERNEL_SOBEL_V; -// break; -// case TEXTURE_SOBEL2: -// mTextureTarget = GLES20.GL_TEXTURE_2D; -// mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_SOBEL); -// kernel = KERNEL_SOBEL2_H; -// kernel2 = KERNEL_SOBEL2_V; -// break; - case TEXTURE_FILT3x3: - mTextureTarget = GLES20.GL_TEXTURE_2D; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_FILT3x3); - break; - case TEXTURE_EXT: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT); - break; - case TEXTURE_EXT_BW: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_BW); - break; - case TEXTURE_EXT_NIGHT: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_NIGHT); - break; - case TEXTURE_EXT_CHROMA_KEY: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_CHROMA_KEY); - break; - case TEXTURE_EXT_SQUEEZE: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_SQUEEZE); - break; - case TEXTURE_EXT_TWIRL: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_TWIRL); - break; - case TEXTURE_EXT_TUNNEL: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_TUNNEL); - break; - case TEXTURE_EXT_BULGE: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_BULGE); - break; - case TEXTURE_EXT_FISHEYE: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_FISHEYE); - break; - case TEXTURE_EXT_DENT: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_DENT); - break; - case TEXTURE_EXT_MIRROR: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_MIRROR); - break; - case TEXTURE_EXT_STRETCH: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_STRETCH); - break; -// case TEXTURE_EXT_SOBEL: -// mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES; -// mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_SOBEL); -// kernel = KERNEL_SOBEL_H; -// kernel2 = KERNEL_SOBEL_V; -// break; -// case TEXTURE_EXT_SOBEL2: -// mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES; -// mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_SOBEL); -// kernel = KERNEL_SOBEL2_H; -// kernel2 = KERNEL_SOBEL2_V; -// break; - case TEXTURE_EXT_FILT3x3: - mTextureTarget = GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = GLHelper.loadShader(VERTEX_SHADER, FRAGMENT_SHADER_EXT_FILT3x3); - break; - case TEXTURE_CUSTOM: - switch (target) { - case GLES20.GL_TEXTURE_2D: - case GLES11Ext.GL_TEXTURE_EXTERNAL_OES: - break; - default: - throw new IllegalArgumentException( - "target should be GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES"); - } - mTextureTarget = target; - mProgramHandle = GLHelper.loadShader(vss, fss); - break; - default: - throw new RuntimeException("Unhandled type " + programType); - } - if (mProgramHandle == 0) { - throw new RuntimeException("Unable to create program"); - } - if (DEBUG) Log.d(TAG, "Created program " + mProgramHandle + " (" + programType + ")"); - - // get locations of attributes and uniforms - maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition"); - GLHelper.checkLocation(maPositionLoc, "aPosition"); - maTextureCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord"); - GLHelper.checkLocation(maTextureCoordLoc, "aTextureCoord"); - muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix"); - GLHelper.checkLocation(muMVPMatrixLoc, "uMVPMatrix"); - muTexMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexMatrix"); -// GLHelper.checkLocation(muTexMatrixLoc, "uTexMatrix"); - initLocation(kernel, kernel2); - - } - - /** - * Releases the program. - */ - public void release() { - if (DEBUG) Log.d(TAG, "deleting program " + mProgramHandle); - GLES20.glDeleteProgram(mProgramHandle); - mProgramHandle = -1; - } - - /** - * Returns the program type. - */ - public ProgramType getProgramType() { - return mProgramType; - } - - public int getProgramHandle() { - return mProgramHandle; - } - - /** - * Creates a texture object suitable for use with this program. - *

- * On exit, the texture will be bound. - */ - public int createTextureObject() { - final int[] textures = new int[1]; - GLES20.glGenTextures(1, textures, 0); - GLHelper.checkGlError("glGenTextures"); - - final int texId = textures[0]; - GLES20.glBindTexture(mTextureTarget, texId); - GLHelper.checkGlError("glBindTexture " + texId); - - GLES20.glTexParameterf(mTextureTarget, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); - GLES20.glTexParameterf(mTextureTarget, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(mTextureTarget, - GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(mTextureTarget, - GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - GLHelper.checkGlError("glTexParameter"); - - return texId; - } - - /** - * Configures the effect offset - * - * This only has an effect for programs that - * use positional effects like SQUEEZE and MIRROR - */ - public void handleTouchEvent(final MotionEvent ev){ - synchronized (mSync) { - if (ev.getAction() == MotionEvent.ACTION_MOVE){ - // A finger is dragging about - if (mTexHeight != 0 && mTexWidth != 0){ - mSummedTouchPosition[0] - += (2 * (ev.getX() - mLastTouchPosition[0])) / mTexWidth; - mSummedTouchPosition[1] - += (2 * (ev.getY() - mLastTouchPosition[1])) / -mTexHeight; - mLastTouchPosition[0] = ev.getX(); - mLastTouchPosition[1] = ev.getY(); - } - } else if (ev.getAction() == MotionEvent.ACTION_DOWN){ - // The primary finger has landed - mLastTouchPosition[0] = ev.getX(); - mLastTouchPosition[1] = ev.getY(); - } - } - } - - /** - * Configures the convolution filter values. - * This only has an effect for programs that use the - * FRAGMENT_SHADER_EXT_FILT3x3 Fragment shader. - * - * @param values Normalized filter values; must be KERNEL_SIZE3x3 elements. - */ - public void setKernel(final float[] values, final float colorAdj) { - if (values.length < KERNEL_SIZE3x3) { - throw new IllegalArgumentException( - "Kernel size is " + values.length + " vs. " + KERNEL_SIZE3x3); - } - System.arraycopy(values, 0, mKernel, 0, KERNEL_SIZE3x3); - mColorAdjust = colorAdj; - } - - public void setKernel2(final float[] values) { - synchronized (mSync) { - mHasKernel2 = values != null && (values.length == KERNEL_SIZE3x3); - if (mHasKernel2) { - System.arraycopy(values, 0, mKernel, KERNEL_SIZE3x3, KERNEL_SIZE3x3); - } - } - } - - public void setColorAdjust(final float adjust) { - synchronized (mSync) { - mColorAdjust = adjust; - } - } - - /** - * Sets the size of the texture. This is used to find adjacent texels when filtering. - */ - public void setTexSize(final int width, final int height) { - mTexHeight = height; - mTexWidth = width; - final float rw = 1.0f / width; - final float rh = 1.0f / height; - - // Don't need to create a new array here, but it's syntactically convenient. - synchronized (mSync) { - mTexOffset = new float[] { - -rw, -rh, 0f, -rh, rw, -rh, - -rw, 0f, 0f, 0f, rw, 0f, - -rw, rh, 0f, rh, rw, rh - }; - } - } - - public void setFlags(final int[] flags) { - final int n = Math.min(4, flags != null ? flags.length : 0); - if (n > 0) { - synchronized (mSync) { - System.arraycopy(flags, 0, mFlags, 0, n); - } - } - } - - public void setFlag(final int index, final int value) { - if ((index >= 0) && (index < mFlags.length)) { - synchronized (mSync) { - mFlags[index] = value; - } - } - } - - /** - * Issues the draw call. Does the full setup on every call. - * - * @param mvpMatrix The 4x4 projection matrix. - * @param mvpMatrixOffset offset of mvpMatrix - * @param vertexBuffer Buffer with vertex position data. - * @param firstVertex Index of first vertex to use in vertexBuffer. - * @param vertexCount Number of vertices in vertexBuffer. - * @param coordsPerVertex The number of coordinates per vertex (e.g. x,y is 2). - * @param vertexStride Width, in bytes, of the position data for each vertex (often - * vertexCount * sizeof(float)). - * @param texMatrix A 4x4 transformation matrix for texture coords. - * @param texMatrixOffset offset of texMatrix - * @param texBuffer Buffer with vertex texture data. - * @param texStride Width, in bytes, of the texture data for each vertex. - */ - public void draw(final float[] mvpMatrix, final int mvpMatrixOffset, - final FloatBuffer vertexBuffer, final int firstVertex, - final int vertexCount, final int coordsPerVertex, final int vertexStride, - final float[] texMatrix, final int texMatrixOffset, - final FloatBuffer texBuffer, final int textureId, final int texStride) { - - GLHelper.checkGlError("draw start"); - - // シェーダープログラムを選択 - GLES20.glUseProgram(mProgramHandle); - GLHelper.checkGlError("glUseProgram"); - - // テクスチャを選択 - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(mTextureTarget, textureId); - GLHelper.checkGlError("glBindTexture"); - - synchronized (mSync) { - // モデルビュー変換行列をセット - GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, mvpMatrixOffset); - GLHelper.checkGlError("glUniformMatrix4fv"); - - // テクスチャ変換行列をセット - if (muTexMatrixLoc >= 0) { - GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, texMatrixOffset); - GLHelper.checkGlError("glUniformMatrix4fv"); - } - - // 頂点座標バッファを有効にする("aPosition" vertex attribute) - GLES20.glEnableVertexAttribArray(maPositionLoc); - GLHelper.checkGlError("glEnableVertexAttribArray"); - GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex, - GLES20.GL_FLOAT, false, vertexStride, vertexBuffer); - GLHelper.checkGlError("glVertexAttribPointer"); - - // テクスチャ座標バッファを有効にする("aTextureCoord" vertex attribute) - GLES20.glEnableVertexAttribArray(maTextureCoordLoc); - GLHelper.checkGlError("glEnableVertexAttribArray"); - GLES20.glVertexAttribPointer(maTextureCoordLoc, 2, - GLES20.GL_FLOAT, false, texStride, texBuffer); - GLHelper.checkGlError("glVertexAttribPointer"); - - // カーネル関数(行列) - if (muKernelLoc >= 0) { - if (!mHasKernel2) { - GLES20.glUniform1fv(muKernelLoc, KERNEL_SIZE3x3, mKernel, 0); - } else { - GLES20.glUniform1fv(muKernelLoc, KERNEL_SIZE3x3 * 2, mKernel, 0); - } - GLHelper.checkGlError("set kernel"); - } - // テクセルオフセット - if ((muTexOffsetLoc >= 0) && (mTexOffset != null)) { - GLES20.glUniform2fv(muTexOffsetLoc, KERNEL_SIZE3x3, mTexOffset, 0); - } - // 色調整オフセット - if (muColorAdjustLoc >= 0) { - GLES20.glUniform1f(muColorAdjustLoc, mColorAdjust); - } - // タッチ座標 - if (muTouchPositionLoc >= 0){ - GLES20.glUniform2fv(muTouchPositionLoc, 1, mSummedTouchPosition, 0); - } - // フラグ - if (muFlagsLoc >= 0) { - GLES20.glUniform1iv(muFlagsLoc, 4, mFlags, 0); - } - } - - internal_draw(firstVertex, vertexCount); - - // Done -- disable vertex array, texture, and program. - GLES20.glDisableVertexAttribArray(maPositionLoc); - GLES20.glDisableVertexAttribArray(maTextureCoordLoc); - GLES20.glBindTexture(mTextureTarget, 0); - GLES20.glUseProgram(0); - } - - protected void initLocation(float[] kernel, float[] kernel2) { - muKernelLoc = GLES20.glGetUniformLocation(mProgramHandle, "uKernel"); - if (muKernelLoc < 0) { - // no kernel in this one - muKernelLoc = -1; - muTexOffsetLoc = -1; - } else { - // has kernel, must also have tex offset and color adj - muTexOffsetLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexOffset"); - if (muTexOffsetLoc < 0) { - muTexOffsetLoc = -1; - } - // 未使用だと削除されてしまうのでチェックしない -// GLHelper.checkLocation(muTexOffsetLoc, "uTexOffset"); - - // initialize default values - if (kernel == null) { - kernel = KERNEL_NULL; - } - setKernel(kernel, 0f); - setTexSize(256, 256); - } - if (kernel2 != null) { - setKernel2(kernel2); - } - - muColorAdjustLoc = GLES20.glGetUniformLocation(mProgramHandle, "uColorAdjust"); - if (muColorAdjustLoc < 0) { - muColorAdjustLoc = -1; - } - // 未使用だと削除されてしまうのでチェックしない -// GLHelper.checkLocation(muColorAdjustLoc, "uColorAdjust"); - - muTouchPositionLoc = GLES20.glGetUniformLocation(mProgramHandle, "uPosition"); - if (muTouchPositionLoc < 0) { - // Shader doesn't use position - muTouchPositionLoc = -1; - } else { - // initialize default values - //handleTouchEvent(new float[]{0f, 0f}); - } - muFlagsLoc = GLES20.glGetUniformLocation(mProgramHandle, "uFlags"); - if (muFlagsLoc < 0) { - muFlagsLoc = -1; - } else { - } - } - - protected void internal_draw(final int firstVertex, final int vertexCount) { - // Draw the rect. - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount); - GLHelper.checkGlError("glDrawArrays"); - } -} \ No newline at end of file diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/TextureOffscreen.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/TextureOffscreen.java deleted file mode 100644 index 95bc148e99..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/TextureOffscreen.java +++ /dev/null @@ -1,446 +0,0 @@ -package com.serenegiant.glutils; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.Bitmap; -import android.opengl.GLES20; -import android.opengl.GLUtils; -import android.opengl.Matrix; -import android.util.Log; - -/** - * テクスチャへOpenGL|ESで描画するためのオフスクリーン描画クラス - * テクスチャをカラーバッファとしてFBOに割り当てる - */ -public class TextureOffscreen { - private static final boolean DEBUG = false; - private static final String TAG = "TextureOffscreen"; - - private static final boolean DEFAULT_ADJUST_POWER2 = false; - - private final int TEX_TARGET; - private final int TEX_UNIT; - private final boolean mHasDepthBuffer, mAdjustPower2; - /** 描画領域サイズ */ - private int mWidth, mHeight; - /** テクスチャサイズ */ - private int mTexWidth, mTexHeight; - /** オフスクリーンのカラーバッファに使うテクスチャ名 */ - private int mFBOTextureName = -1; - /** // オフスクリーン用のバッファオブジェクト */ - private int mDepthBufferObj = -1, mFrameBufferObj = -1; - /** テクスチャ座標変換行列 */ - private final float[] mTexMatrix = new float[16]; - - /** - * コンストラクタ(GL_TEXTURE_2D), デプスバッファ無し - * テクスチャユニットはGL_TEXTURE0 - * @param width - * @param height - */ - public TextureOffscreen(final int width, final int height) { - this(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE0, -1, - width, height, false, DEFAULT_ADJUST_POWER2); - } - - /** - * コンストラクタ(GL_TEXTURE_2D), デプスバッファ無し - * テクスチャユニットはGL_TEXTURE0 - * @param tex_unit - * @param width - * @param height - */ - public TextureOffscreen(final int tex_unit, - final int width, final int height) { - - this(GLES20.GL_TEXTURE_2D, tex_unit, -1, - width, height, - false, DEFAULT_ADJUST_POWER2); - } - - /** - * コンストラクタ(GL_TEXTURE_2D) - * テクスチャユニットはGL_TEXTURE0 - * @param width dimension of offscreen(width) - * @param height dimension of offscreen(height) - * @param use_depth_buffer set true if you use depth buffer. the depth is fixed as 16bits - */ - public TextureOffscreen(final int width, final int height, - final boolean use_depth_buffer) { - - this(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE0, -1, - width, height, use_depth_buffer, DEFAULT_ADJUST_POWER2); - } - - /** - * 既存のテクスチャ(GL_TEXTURE_2D)をwrapするためのコンストラクタ - * テクスチャユニットはGL_TEXTURE0 - * @param tex_unit - * @param width - * @param height - * @param use_depth_buffer - */ - public TextureOffscreen(final int tex_unit, - final int width, final int height, final boolean use_depth_buffer) { - - this(GLES20.GL_TEXTURE_2D, tex_unit, -1, - width, height, - use_depth_buffer, DEFAULT_ADJUST_POWER2); - } - - /** - * コンストラクタ(GL_TEXTURE_2D) - * テクスチャユニットはGL_TEXTURE0 - * @param width - * @param height - * @param use_depth_buffer - * @param adjust_power2 - */ - public TextureOffscreen(final int width, final int height, - final boolean use_depth_buffer, final boolean adjust_power2) { - - this(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE0, -1, - width, height, use_depth_buffer, adjust_power2); - } - - /** - * コンストラクタ(GL_TEXTURE_2D) - * @param tex_unit - * @param width - * @param height - * @param use_depth_buffer - * @param adjust_power2 - */ - public TextureOffscreen(final int tex_unit, - final int width, final int height, - final boolean use_depth_buffer, final boolean adjust_power2) { - - this(GLES20.GL_TEXTURE_2D, tex_unit, -1, - width, height, use_depth_buffer, adjust_power2); - } - - /** - * 既存のテクスチャ(GL_TEXTURE_2D)をwrapするためのコンストラクタ, デプスバッファなし - * @param tex_id - * @param tex_unit - * @param width - * @param height - */ - public TextureOffscreen(final int tex_unit, final int tex_id, - final int width, final int height) { - - this(GLES20.GL_TEXTURE_2D, tex_unit, tex_id, - width, height, - false, DEFAULT_ADJUST_POWER2); - } - - /** - * 既存のテクスチャ(GL_TEXTURE_2D)をwrapするためのコンストラクタ - * @param tex_unit - * @param tex_id - * @param width - * @param height - * @param use_depth_buffer - */ - public TextureOffscreen(final int tex_unit, final int tex_id, - final int width, final int height, final boolean use_depth_buffer) { - - this(GLES20.GL_TEXTURE_2D, tex_unit, tex_id, - width, height, - use_depth_buffer, DEFAULT_ADJUST_POWER2); - } - - /** - * 既存のテクスチャをwrapするためのコンストラクタ - * @param tex_target GL_TEXTURE_2D - * @param tex_id - * @param width - * @param height - * @param use_depth_buffer - * @param adjust_power2 - */ - public TextureOffscreen(final int tex_target, final int tex_unit, final int tex_id, - final int width, final int height, - final boolean use_depth_buffer, final boolean adjust_power2) { - - if (DEBUG) Log.v(TAG, "Constructor"); - TEX_TARGET = tex_target; - TEX_UNIT = tex_unit; - mWidth = width; - mHeight = height; - mHasDepthBuffer = use_depth_buffer; - mAdjustPower2 = adjust_power2; - - createFrameBuffer(width, height); - int tex = tex_id; - if (tex < 0) { - tex = genTexture(tex_target, tex_unit, mTexWidth, mTexHeight); - } - assignTexture(tex, width, height); - } - - /** 破棄する */ - public void release() { - if (DEBUG) Log.v(TAG, "release"); - releaseFrameBuffer(); - } - - /** - * オフスクリーン描画用のレンダリングバッファに切り替える - * Viewportも変更になるので必要であればunbind後にViewportの設定をすること - */ - public void bind() { -// if (DEBUG) Log.v(TAG, "bind:"); - GLES20.glActiveTexture(TEX_UNIT); - GLES20.glBindTexture(TEX_TARGET, mFBOTextureName); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferObj); - GLES20.glViewport(0, 0, mWidth, mHeight); - } - - /** - * デフォルトのレンダリングバッファに戻す - */ - public void unbind() { -// if (DEBUG) Log.v(TAG, "unbind:"); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - GLES20.glActiveTexture(TEX_UNIT); - GLES20.glBindTexture(TEX_TARGET, 0); - } - - private final float[] mResultMatrix = new float[16]; - /** - * get copy of texture matrix - * @return - */ - public float[] getTexMatrix() { - System.arraycopy(mTexMatrix, 0, mResultMatrix, 0, 16); - return mResultMatrix; - } - - /** - * テクスチャ座標変換行列を取得(内部配列を直接返すので変更時は要注意) - * @return - */ - public float[] getRawTexMatrix() { - return mTexMatrix; - } - - /** - * テクスチャ変換行列のコピーを返す - * 領域チェックしていないのでoffset位置から16個以上確保しておくこと - * @param matrix - */ - public void getTexMatrix(final float[] matrix, final int offset) { - System.arraycopy(mTexMatrix, 0, matrix, offset, mTexMatrix.length); - } - - /** - * オフスクリーンテクスチャ名を取得 - * このオフスクリーンへ書き込んだ画像をテクスチャとして使って他の描画を行う場合に使用できる - * @return - */ - public int getTexture() { - return mFBOTextureName; - } - - /** 指定したテクスチャをこのオフスクリーンに割り当てる */ - public void assignTexture(final int texture_name, - final int width, final int height) { - - if ((width > mTexWidth) || (height > mTexHeight)) { - mWidth = width; - mHeight = height; - releaseFrameBuffer(); - createFrameBuffer(width, height); - } - mFBOTextureName = texture_name; - GLES20.glActiveTexture(TEX_UNIT); - // フレームバッファオブジェクトをbindする - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferObj); - GLHelper.checkGlError("glBindFramebuffer " + mFrameBufferObj); - // フレームバッファにカラーバッファ(テクスチャ)を接続する - GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, - TEX_TARGET, mFBOTextureName, 0); - GLHelper.checkGlError("glFramebufferTexture2D"); - - if (mHasDepthBuffer) { - // フレームバッファにデプスバッファを接続する - GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, - GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, mDepthBufferObj); - GLHelper.checkGlError("glFramebufferRenderbuffer"); - } - - // 正常に終了したかどうかを確認する - final int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); - if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) { - throw new RuntimeException("Framebuffer not complete, status=" + status); - } - - // デフォルトのフレームバッファに戻す - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - - // テクスチャ座標変換行列を初期化 - Matrix.setIdentityM(mTexMatrix, 0); - mTexMatrix[0] = width / (float)mTexWidth; - mTexMatrix[5] = height / (float)mTexHeight; - } - - /** Bitmapからテクスチャを読み込む */ - public void loadBitmap(final Bitmap bitmap) { - final int width = bitmap.getWidth(); - final int height = bitmap.getHeight(); - if ((width > mTexWidth) || (height > mTexHeight)) { - mWidth = width; - mHeight = height; - releaseFrameBuffer(); - createFrameBuffer(width, height); - } - GLES20.glActiveTexture(TEX_UNIT); - GLES20.glBindTexture(TEX_TARGET, mFBOTextureName); - GLUtils.texImage2D(TEX_TARGET, 0, bitmap, 0); - GLES20.glBindTexture(TEX_TARGET, 0); - // initialize texture matrix - Matrix.setIdentityM(mTexMatrix, 0); - mTexMatrix[0] = width / (float)mTexWidth; - mTexMatrix[5] = height / (float)mTexHeight; - } - - /** - * カラーバッファのためにテクスチャを生成する - * @param tex_target - * @param tex_unit - * @param tex_width - * @param tex_height - * @return - */ - private static int genTexture(final int tex_target, final int tex_unit, - final int tex_width, final int tex_height) { - // カラーバッファのためにテクスチャを生成する - final int tex_name = GLHelper.initTex(tex_target, tex_unit, - GLES20.GL_LINEAR, GLES20.GL_LINEAR, GLES20.GL_CLAMP_TO_EDGE); - // テクスチャのメモリ領域を確保する - GLES20.glTexImage2D(tex_target, 0, GLES20.GL_RGBA, tex_width, tex_height, 0, - GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); - GLHelper.checkGlError("glTexImage2D"); - return tex_name; - } - - /** オフスクリーン描画用のフレームバッファオブジェクトを生成する */ - private final void createFrameBuffer(final int width, final int height) { - final int[] ids = new int[1]; - - if (mAdjustPower2) { - // テクスチャのサイズは2の乗数にする - int w = 1; - for (; w < width; w <<= 1) ; - int h = 1; - for (; h < height; h <<= 1) ; - if (mTexWidth != w || mTexHeight != h) { - mTexWidth = w; - mTexHeight = h; - } - } else { - mTexWidth = width; - mTexHeight = height; - } - - if (mHasDepthBuffer) { - // デプスバッファが必要な場合は、レンダーバッファオブジェクトを生成・初期化する - GLES20.glGenRenderbuffers(1, ids, 0); - mDepthBufferObj = ids[0]; - GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, mDepthBufferObj); - // デプスバッファは16ビット - GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, - GLES20.GL_DEPTH_COMPONENT16, mTexWidth, mTexHeight); - } - // フレームバッファオブジェクトを生成してbindする - GLES20.glGenFramebuffers(1, ids, 0); - GLHelper.checkGlError("glGenFramebuffers"); - mFrameBufferObj = ids[0]; - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferObj); - GLHelper.checkGlError("glBindFramebuffer " + mFrameBufferObj); - - // デフォルトのフレームバッファに戻す - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - - } - - /** オフスクリーンフレームバッファを破棄 */ - private final void releaseFrameBuffer() { - final int[] names = new int[1]; - // デプスバッファがある時はデプスバッファを破棄 - if (mDepthBufferObj >= 0) { - names[0] = mDepthBufferObj; - GLES20.glDeleteRenderbuffers(1, names, 0); - mDepthBufferObj = -1; - } - // オフスクリーンのカラーバッファ用のテクスチャを破棄 - if (mFBOTextureName >= 0) { - names[0] = mFBOTextureName; - GLES20.glDeleteTextures(1, names, 0); - mFBOTextureName = -1; - } - // オフスクリーンのフレームバッファーオブジェクトを破棄 - if (mFrameBufferObj >= 0) { - names[0] = mFrameBufferObj; - GLES20.glDeleteFramebuffers(1, names, 0); - mFrameBufferObj = -1; - } - } - - /** - * get dimension(width) of this offscreen - * @return - */ - public int getWidth() { - return mWidth; - } - - /** - * get dimension(height) of this offscreen - * @return - */ - public int getHeight() { - return mHeight; - } - - /** - * get backing texture dimension(width) of this offscreen - * @return - */ - public int getTexWidth() { - return mTexWidth; - } - - /** - * get backing texture dimension(height) of this offscreen - * @return - */ - public int getTexHeight() { - return mTexHeight; - } - - public int getTexTarget() { - return TEX_TARGET; - } - - public int getTexUnit() { - return TEX_UNIT; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLDrawer2D.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLDrawer2D.java deleted file mode 100644 index 54f56183df..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLDrawer2D.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.serenegiant.glutils.es1; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import static com.serenegiant.glutils.ShaderConst.GL_TEXTURE_2D; -import static com.serenegiant.glutils.ShaderConst.GL_TEXTURE_EXTERNAL_OES; - -import android.opengl.GLES10; -import android.opengl.Matrix; - -import com.serenegiant.glutils.IDrawer2D; -import com.serenegiant.glutils.ITexture; -import com.serenegiant.glutils.TextureOffscreen; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -public class GLDrawer2D implements IDrawer2D { - private static final float[] VERTICES = { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f }; - private static final float[] TEXCOORD = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; - private static final int FLOAT_SZ = Float.SIZE / 8; - private static final int VERTEX_NUM = 4; - private static final int VERTEX_SZ = VERTEX_NUM * 2; - - private final float[] mMvpMatrix = new float[16]; - private final FloatBuffer pVertex; - private final FloatBuffer pTexCoord; - private final int mTexTarget; - - /** - * コンストラクタ - * GLコンテキスト/EGLレンダリングコンテキストが有効な状態で呼ばないとダメ - * @param isOES 外部テクスチャ(GL_TEXTURE_EXTERNAL_OES)を使う場合はtrue。通常の2Dテキスチャならfalse - */ - public GLDrawer2D(final boolean isOES) { - mTexTarget = isOES ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; - pVertex = ByteBuffer.allocateDirect(VERTEX_SZ * FLOAT_SZ) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - pVertex.put(VERTICES); - pVertex.flip(); - pTexCoord = ByteBuffer.allocateDirect(VERTEX_SZ * FLOAT_SZ) - .order(ByteOrder.nativeOrder()).asFloatBuffer(); - pTexCoord.put(TEXCOORD); - pTexCoord.flip(); - // モデルビュー変換行列を初期化 - Matrix.setIdentityM(mMvpMatrix, 0); - } - - @Override - public void release() { - - } - - /** - * モデルビュー変換行列を取得(内部配列を直接返すので変更時は要注意) - * @return - */ - @Override - public float[] getMvpMatrix() { - return mMvpMatrix; - } - - /** - * モデルビュー変換行列に行列を割り当てる - * @param matrix 領域チェックしていないのでoffsetから16個以上必須 - * @param offset - * @return - */ - @Override - public IDrawer2D setMvpMatrix(final float[] matrix, final int offset) { - System.arraycopy(matrix, offset, mMvpMatrix, 0, 16); - return this; - } - - /** - * モデルビュー変換行列のコピーを取得 - * @param matrix 領域チェックしていないのでoffsetから16個以上必須 - * @param offset - */ - @Override - public void getMvpMatrix(final float[] matrix, final int offset) { - System.arraycopy(mMvpMatrix, 0, matrix, offset, 16); - } - - @Override - public void draw(final int texId, final float[] tex_matrix, final int offset) { - // FIXME Matrixを適用 - GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY); - pVertex.position(0); - GLES10.glVertexPointer(2, GLES10.GL_FLOAT, VERTEX_SZ, pVertex); -//-------------------------------------------------------------------------------- - GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY); - pTexCoord.position(0); - GLES10.glTexCoordPointer(VERTEX_NUM, GLES10.GL_FLOAT, VERTEX_SZ, pTexCoord); - GLES10.glActiveTexture(GLES10.GL_TEXTURE0); - GLES10.glBindTexture(mTexTarget, texId); -//-------------------------------------------------------------------------------- - GLES10.glDrawArrays(GLES10.GL_TRIANGLE_STRIP, 0, VERTEX_NUM); -//-------------------------------------------------------------------------------- - GLES10.glBindTexture(mTexTarget, 0); - GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY); -//-------------------------------------------------------------------------------- - GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY); - } - - @Override - public void draw(final ITexture texture) { - draw(texture.getTexture(), texture.getTexMatrix(), 0); - } - - @Override - public void draw(final TextureOffscreen offscreen) { - draw(offscreen.getTexture(), offscreen.getTexMatrix(), 0); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLHelper.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLHelper.java deleted file mode 100644 index 3a4943f935..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLHelper.java +++ /dev/null @@ -1,459 +0,0 @@ -package com.serenegiant.glutils.es1; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.opengl.GLES10; -import android.opengl.GLES30; -import android.opengl.GLUtils; -import android.opengl.Matrix; -import android.util.Log; - -import com.serenegiant.utils.BuildCheck; - -import javax.microedition.khronos.opengles.GL10; - -/** - * OpenGL|ES用のヘルパークラス - */ -public final class GLHelper { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = "GLHelper"; - - /** - * OpenGL|ESのエラーをチェックしてlogCatに出力する - * @param op - */ - public static void checkGlError(final String op) { - final int error = GLES10.glGetError(); - if (error != GLES10.GL_NO_ERROR) { - final String msg = op + ": glError 0x" + Integer.toHexString(error); - Log.e(TAG, msg); - new Throwable(msg).printStackTrace(); -// if (DEBUG) { -// throw new RuntimeException(msg); -// } - } - } - - /** - * OpenGL|ESのエラーをチェックしてlogCatに出力する - * @param gl - * @param op - */ - public static void checkGlError(final GL10 gl, final String op) { - final int error = gl.glGetError(); - if (error != GL10.GL_NO_ERROR) { - final String msg = op + ": glError 0x" + Integer.toHexString(error); - Log.e(TAG, msg); - new Throwable(msg).printStackTrace(); -// if (DEBUG) { -// throw new RuntimeException(msg); -// } - } - } - - /** - * テクスチャ名を生成, テクスチャユニットはGL_TEXTURE0, クランプ方法はGL_CLAMP_TO_EDGE - * @param texTarget - * @param filter_param テクスチャの補完方法を指定, min/mag共に同じ値になる, GL_LINEARとかGL_NEAREST - * @return - */ - public static int initTex(final int texTarget, final int filter_param) { - return initTex(texTarget, GLES10.GL_TEXTURE0, filter_param, filter_param, GLES10.GL_CLAMP_TO_EDGE); - } - - /** - * テクスチャ名を生成 - * @param texTarget - * @param texUnit テクスチャユニット, GL_TEXTURE0...GL_TEXTURE31 - * @param min_filter テクスチャの補間方法を指定, GL_LINEARとかGL_NEAREST - * @param mag_filter テクスチャの補間方法を指定, GL_LINEARとかGL_NEAREST - * @param wrap テクスチャのクランプ方法, GL_CLAMP_TO_EDGE - * @return - */ - public static int initTex(final int texTarget, final int texUnit, final int min_filter, final int mag_filter, final int wrap) { -// if (DEBUG) Log.v(TAG, "initTex:target=" + texTarget); - final int[] tex = new int[1]; - GLES10.glActiveTexture(texUnit); - GLES10.glGenTextures(1, tex, 0); - GLES10.glBindTexture(texTarget, tex[0]); - GLES10.glTexParameterx(texTarget, GLES10.GL_TEXTURE_WRAP_S, wrap); - GLES10.glTexParameterx(texTarget, GLES10.GL_TEXTURE_WRAP_T, wrap); - GLES10.glTexParameterx(texTarget, GLES10.GL_TEXTURE_MIN_FILTER, min_filter); - GLES10.glTexParameterx(texTarget, GLES10.GL_TEXTURE_MAG_FILTER, mag_filter); - return tex[0]; - } - - /** - * テクスチャ名を生成(GL_TEXTURE0のみ) - * @param gl - * @param texTarget - * @param filter_param テクスチャの補間方法を指定 GL_LINEARとかGL_NEAREST - * @return - */ - public static int initTex(final GL10 gl, final int texTarget, final int filter_param) { -// if (DEBUG) Log.v(TAG, "initTex:target=" + texTarget); - final int[] tex = new int[1]; - gl.glActiveTexture(GL10.GL_TEXTURE0); - gl.glGenTextures(1, tex, 0); - gl.glBindTexture(texTarget, tex[0]); - gl.glTexParameterx(texTarget, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); - gl.glTexParameterx(texTarget, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); - gl.glTexParameterx(texTarget, GL10.GL_TEXTURE_MIN_FILTER, filter_param); - gl.glTexParameterx(texTarget, GL10.GL_TEXTURE_MAG_FILTER, filter_param); - return tex[0]; - } - - /** - * delete specific texture - */ - public static void deleteTex(final int hTex) { -// if (DEBUG) Log.v(TAG, "deleteTex:"); - final int[] tex = new int[] {hTex}; - GLES10.glDeleteTextures(1, tex, 0); - } - - /** - * delete specific texture - */ - public static void deleteTex(final GL10 gl, final int hTex) { -// if (DEBUG) Log.v(TAG, "deleteTex:"); - final int[] tex = new int[] {hTex}; - gl.glDeleteTextures(1, tex, 0); - } - - public static int loadTextureFromResource(final Context context, final int resId) { - // Create an empty, mutable bitmap - final Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888); - // get a canvas to paint over the bitmap - final Canvas canvas = new Canvas(bitmap); - canvas.drawARGB(0,0,255,0); - - // get a background image from resources - // note the image format must match the bitmap format - final Drawable background = context.getResources().getDrawable(resId); - background.setBounds(0, 0, 256, 256); - background.draw(canvas); // draw the background to our bitmap - - final int[] textures = new int[1]; - - //Generate one texture pointer... - GLES10.glGenTextures(1, textures, 0); - //...and bind it to our array - GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, textures[0]); - - //Create Nearest Filtered Texture - GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_NEAREST); - GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR); - - //Different possible texture parameters, e.g. GLES10.GL_CLAMP_TO_EDGE - GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_REPEAT); - GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_REPEAT); - - //Use the Android GLUtils to specify a two-dimensional texture image from our bitmap - GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, bitmap, 0); - //Clean up - bitmap.recycle(); - - return textures[0]; - } - - public static int createTextureWithTextContent (final String text) { - // Create an empty, mutable bitmap - final Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888); - // get a canvas to paint over the bitmap - final Canvas canvas = new Canvas(bitmap); - canvas.drawARGB(0,0,255,0); - - // Draw the text - final Paint textPaint = new Paint(); - textPaint.setTextSize(32); - textPaint.setAntiAlias(true); - textPaint.setARGB(0xff, 0xff, 0xff, 0xff); - // draw the text centered - canvas.drawText(text, 16, 112, textPaint); - - final int texture = initTex(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE0, GLES10.GL_NEAREST, GLES10.GL_LINEAR, GLES10.GL_REPEAT); - - // Alpha blending - // GLES10.glEnable(GLES10.GL_BLEND); - // GLES10.glBlendFunc(GLES10.GL_SRC_ALPHA, GLES10.GL_ONE_MINUS_SRC_ALPHA); - - // Use the Android GLUtils to specify a two-dimensional texture image from our bitmap - GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, bitmap, 0); - // Clean up - bitmap.recycle(); - - return texture; - } - - /** - * Checks to see if the location we obtained is valid. GLES returns -1 if a label - * could not be found, but does not set the GL error. - *

- * Throws a RuntimeException if the location is invalid. - */ - public static void checkLocation(final int location, final String label) { - if (location < 0) { - throw new RuntimeException("Unable to locate '" + label + "' in program"); - } - } - - /** - * Writes GL version info to the log. - */ - @SuppressLint("InlinedApi") - public static void logVersionInfo() { - Log.i(TAG, "vendor : " + GLES10.glGetString(GLES10.GL_VENDOR)); - Log.i(TAG, "renderer: " + GLES10.glGetString(GLES10.GL_RENDERER)); - Log.i(TAG, "version : " + GLES10.glGetString(GLES10.GL_VERSION)); - - if (BuildCheck.isAndroid4_3()) { - final int[] values = new int[1]; - GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, values, 0); - final int majorVersion = values[0]; - GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, values, 0); - final int minorVersion = values[0]; - if (GLES30.glGetError() == GLES30.GL_NO_ERROR) { - Log.i(TAG, "version: " + majorVersion + "." + minorVersion); - } - } - } - -// came from GLU - /** - * Return an error string from a GL or GLU error code. - * - * @param error - a GL or GLU error code. - * @return the error string for the input error code, or NULL if the input - * was not a valid GL or GLU error code. - */ - public static String gluErrorString(final int error) { - switch (error) { - case GLES10.GL_NO_ERROR: - return "no error"; - case GLES10.GL_INVALID_ENUM: - return "invalid enum"; - case GLES10.GL_INVALID_VALUE: - return "invalid value"; - case GLES10.GL_INVALID_OPERATION: - return "invalid operation"; - case GLES10.GL_STACK_OVERFLOW: - return "stack overflow"; - case GLES10.GL_STACK_UNDERFLOW: - return "stack underflow"; - case GLES10.GL_OUT_OF_MEMORY: - return "out of memory"; - default: - return null; - } - } - - /** - * Define a viewing transformation in terms of an eye point, a center of - * view, and an up vector. - * - * @param eyeX eye point X - * @param eyeY eye point Y - * @param eyeZ eye point Z - * @param centerX center of view X - * @param centerY center of view Y - * @param centerZ center of view Z - * @param upX up vector X - * @param upY up vector Y - * @param upZ up vector Z - */ - public static void gluLookAt(final float eyeX, final float eyeY, final float eyeZ, - final float centerX, final float centerY, final float centerZ, - final float upX, final float upY, final float upZ) { - - final float[] scratch = sScratch; - synchronized (scratch) { - Matrix.setLookAtM(scratch, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, - upX, upY, upZ); - GLES10.glMultMatrixf(scratch, 0); - } - } - - /** - * Set up a 2D orthographic projection matrix - * - * @param left - * @param right - * @param bottom - * @param top - */ - public static void gluOrtho2D(final float left, final float right, - final float bottom, final float top) { - GLES10.glOrthof(left, right, bottom, top, -1.0f, 1.0f); - } - - /** - * Set up a perspective projection matrix - * - * @param fovy specifies the field of view angle, in degrees, in the Y - * direction. - * @param aspect specifies the aspect ration that determins the field of - * view in the x direction. The aspect ratio is the ratio of x - * (width) to y (height). - * @param zNear specifies the distance from the viewer to the near clipping - * plane (always positive). - * @param zFar specifies the distance from the viewer to the far clipping - * plane (always positive). - */ - public static void gluPerspective(final float fovy, final float aspect, - final float zNear, final float zFar) { - - final float top = zNear * (float) Math.tan(fovy * (Math.PI / 360.0)); - final float bottom = -top; - final float left = bottom * aspect; - final float right = top * aspect; - GLES10.glFrustumf(left, right, bottom, top, zNear, zFar); - } - - /** - * Map object coordinates into window coordinates. gluProject transforms the - * specified object coordinates into window coordinates using model, proj, - * and view. The result is stored in win. - *

- * Note that you can use the OES_matrix_get extension, if present, to get - * the current modelView and projection matrices. - * - * @param objX object coordinates X - * @param objY object coordinates Y - * @param objZ object coordinates Z - * @param model the current modelview matrix - * @param modelOffset the offset into the model array where the modelview - * maxtrix data starts. - * @param project the current projection matrix - * @param projectOffset the offset into the project array where the project - * matrix data starts. - * @param view the current view, {x, y, width, height} - * @param viewOffset the offset into the view array where the view vector - * data starts. - * @param win the output vector {winX, winY, winZ}, that returns the - * computed window coordinates. - * @param winOffset the offset into the win array where the win vector data - * starts. - * @return A return value of GL_TRUE indicates success, a return value of - * GL_FALSE indicates failure. - */ - public static int gluProject(final float objX, final float objY, final float objZ, - final float[] model, final int modelOffset, final float[] project, final int projectOffset, - final int[] view, final int viewOffset, final float[] win, final int winOffset) { - - final float[] scratch = sScratch; - synchronized (scratch) { - final int M_OFFSET = 0; // 0..15 - final int V_OFFSET = 16; // 16..19 - final int V2_OFFSET = 20; // 20..23 - Matrix.multiplyMM(scratch, M_OFFSET, project, projectOffset, model, modelOffset); - - scratch[V_OFFSET + 0] = objX; - scratch[V_OFFSET + 1] = objY; - scratch[V_OFFSET + 2] = objZ; - scratch[V_OFFSET + 3] = 1.0f; - - Matrix.multiplyMV(scratch, V2_OFFSET, scratch, M_OFFSET, scratch, V_OFFSET); - - final float w = scratch[V2_OFFSET + 3]; - if (w == 0.0f) { - return GLES10.GL_FALSE; - } - - final float rw = 1.0f / w; - - win[winOffset] = view[viewOffset] - + view[viewOffset + 2] - * (scratch[V2_OFFSET + 0] * rw + 1.0f) - * 0.5f; - win[winOffset + 1] = - view[viewOffset + 1] + view[viewOffset + 3] - * (scratch[V2_OFFSET + 1] * rw + 1.0f) * 0.5f; - win[winOffset + 2] = (scratch[V2_OFFSET + 2] * rw + 1.0f) * 0.5f; - } - - return GL10.GL_TRUE; - } - - /** - * Map window coordinates to object coordinates. gluUnProject maps the - * specified window coordinates into object coordinates using model, proj, - * and view. The result is stored in obj. - *

- * Note that you can use the OES_matrix_get extension, if present, to get - * the current modelView and projection matrices. - * - * @param winX window coordinates X - * @param winY window coordinates Y - * @param winZ window coordinates Z - * @param model the current modelview matrix - * @param modelOffset the offset into the model array where the modelview - * maxtrix data starts. - * @param project the current projection matrix - * @param projectOffset the offset into the project array where the project - * matrix data starts. - * @param view the current view, {x, y, width, height} - * @param viewOffset the offset into the view array where the view vector - * data starts. - * @param obj the output vector {objX, objY, objZ}, that returns the - * computed object coordinates. - * @param objOffset the offset into the obj array where the obj vector data - * starts. - * @return A return value of GL10.GL_TRUE indicates success, a return value - * of GL10.GL_FALSE indicates failure. - */ - public static int gluUnProject(final float winX, final float winY, final float winZ, - final float[] model, final int modelOffset, final float[] project, final int projectOffset, - final int[] view, final int viewOffset, final float[] obj, final int objOffset) { - - final float[] scratch = sScratch; - synchronized (scratch) { - final int PM_OFFSET = 0; // 0..15 - final int INVPM_OFFSET = 16; // 16..31 - final int V_OFFSET = 0; // 0..3 Reuses PM_OFFSET space - Matrix.multiplyMM(scratch, PM_OFFSET, project, projectOffset, model, modelOffset); - - if (!Matrix.invertM(scratch, INVPM_OFFSET, scratch, PM_OFFSET)) { - return GL10.GL_FALSE; - } - - scratch[V_OFFSET + 0] = - 2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2] - - 1.0f; - scratch[V_OFFSET + 1] = - 2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3] - - 1.0f; - scratch[V_OFFSET + 2] = 2.0f * winZ - 1.0f; - scratch[V_OFFSET + 3] = 1.0f; - - Matrix.multiplyMV(obj, objOffset, scratch, INVPM_OFFSET, scratch, V_OFFSET); - } - - return GL10.GL_TRUE; - } - - private static final float[] sScratch = new float[32]; -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLTexture.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLTexture.java deleted file mode 100644 index 599d36a72e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/glutils/es1/GLTexture.java +++ /dev/null @@ -1,234 +0,0 @@ -package com.serenegiant.glutils.es1; -/* - * libcommon - * utility/helper classes for myself - * - * Copyright (c) 2014-2018 saki t_saki@serenegiant.com - * - * 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. -*/ - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.opengl.GLES10; -import android.opengl.GLUtils; -import android.opengl.Matrix; -import android.text.TextUtils; - -import com.serenegiant.glutils.ITexture; - -import java.io.IOException; - -/** - * OpenGL|ESのテクスチャ操作用のヘルパークラス - */ -public class GLTexture implements ITexture { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること -// private static final String TAG = "GLTexture"; - - /* package */final int mTextureTarget; - /* package */final int mTextureUnit; - /* package */int mTextureId; - /* package */final float[] mTexMatrix = new float[16]; // テクスチャ変換行列 - /* package */int mTexWidth, mTexHeight; - /* package */int mImageWidth, mImageHeight; - - /** - * コンストラクタ - * テクスチャユニットが常時GL_TEXTURE0なので複数のテクスチャを同時に使えない - * @param width - * @param height - * @param filter_param - */ - public GLTexture(final int width, final int height, final int filter_param) { - this(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE0, width, height, filter_param); - } - - /** - * コンストラクタ - * @param texTarget GL_TEXTURE_EXTERNAL_OESはだめ - * @param texUnit - * @param width テクスチャサイズ - * @param height テクスチャサイズ - * @param filter_param テクスチャの補間方法を指定 GL_LINEARとかGL_NEAREST - */ - public GLTexture(final int texTarget, final int texUnit, - final int width, final int height, final int filter_param) { - -// if (DEBUG) Log.v(TAG, String.format("コンストラクタ(%d,%d)", width, height)); - mTextureTarget = texTarget; - mTextureUnit = texUnit; - // テクスチャに使うビットマップは縦横サイズが2の乗数でないとダメ。 - // 更に、ミップマップするなら正方形でないとダメ - // 指定したwidth/heightと同じか大きい2の乗数にする - int w = 32; - for (; w < width; w <<= 1); - int h = 32; - for (; h < height; h <<= 1); - if (mTexWidth != w || mTexHeight != h) { - mTexWidth = w; - mTexHeight = h; - } -// if (DEBUG) Log.v(TAG, String.format("texSize(%d,%d)", mTexWidth, mTexHeight)); - mTextureId = GLHelper.initTex(mTextureTarget, filter_param); - // テクスチャのメモリ領域を確保する - GLES10.glTexImage2D(mTextureTarget, - 0, // ミップマップレベル0(ミップマップしない) - GLES10.GL_RGBA, // 内部フォーマット - mTexWidth, mTexHeight, // サイズ - 0, // 境界幅 - GLES10.GL_RGBA, // 引き渡すデータのフォーマット - GLES10.GL_UNSIGNED_BYTE, // データの型 - null); // ピクセルデータ無し - // テクスチャ変換行列を初期化 - Matrix.setIdentityM(mTexMatrix, 0); - mTexMatrix[0] = width / (float)mTexWidth; - mTexMatrix[5] = height / (float)mTexHeight; -// if (DEBUG) Log.v(TAG, "GLTexture:id=" + mTextureId); - } - - @Override - protected void finalize() throws Throwable { - release(); // GLコンテキスト内じゃない可能性があるのであまり良くないけど - super.finalize(); - } - - /** - * テクスチャを破棄 - * GLコンテキスト/EGLレンダリングコンテキスト内で呼び出すこと - */ - @Override - public void release() { -// if (DEBUG) Log.v(TAG, "release:"); - if (mTextureId > 0) { - GLHelper.deleteTex(mTextureId); - mTextureId = 0; - } - } - - /** - * このインスタンスで管理しているテクスチャを有効にする(バインドする) - */ - @Override - public void bind() { -// if (DEBUG) Log.v(TAG, "bind:"); - GLES10.glActiveTexture(mTextureUnit); // テクスチャユニットを選択 - GLES10.glBindTexture(mTextureTarget, mTextureId); - } - - /** - * このインスタンスで管理しているテクスチャを無効にする(アンバインドする) - */ - @Override - public void unbind() { -// if (DEBUG) Log.v(TAG, "unbind:"); - GLES10.glActiveTexture(mTextureUnit); // テクスチャユニットを選択 - GLES10.glBindTexture(mTextureTarget, 0); - } - - /** - * テクスチャターゲットを取得(GL_TEXTURE_2D) - * @return - */ - @Override - public int getTexTarget() { return mTextureTarget; } - /** - * テクスチャ名を取得 - * @return - */ - @Override - public int getTexture() { return mTextureId; } - /** - * テクスチャ座標変換行列を取得(内部配列をそのまま返すので変更時は要注意) - * @return - */ - @Override - public float[] getTexMatrix() { return mTexMatrix; } - /** - * テクスチャ座標変換行列のコピーを取得 - * @param matrix 領域チェックしていないのでoffset位置から16個以上確保しておくこと - * @param offset - */ - @Override - public void getTexMatrix(final float[] matrix, final int offset) { - System.arraycopy(mTexMatrix, 0, matrix, offset, mTexMatrix.length); - } - /** - * テクスチャ幅を取得 - * @return - */ - @Override - public int getTexWidth() { return mTexWidth; } - /** - * テクスチャ高さを取得 - * @return - */ - @Override - public int getTexHeight() { return mTexHeight; } - - /** - * 指定したファイルから画像をテクスチャに読み込む - * ファイルが存在しないか読み込めなければIOException/NullPointerExceptionを生成 - * @param filePath - */ - @Override - public void loadTexture(final String filePath) throws NullPointerException, IOException { -// if (DEBUG) Log.v(TAG, "loadTexture:path=" + filePath); - if (TextUtils.isEmpty(filePath)) - throw new NullPointerException("image file path should not be a null"); - final BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; // Bitmapを生成せずにサイズ等の情報だけを取得する - BitmapFactory.decodeFile(filePath, options); - // テキスチャサイズ内に指定したイメージが収まるためのサブサンプリングを値を求める - final int imageWidth = options.outWidth; - final int imageHeight = options.outHeight; - int inSampleSize = 1; // サブサンプリングサイズ - if ((imageHeight > mTexHeight) || (imageWidth > mTexWidth)) { - if (imageWidth > imageHeight) { - inSampleSize = (int)Math.ceil(imageHeight / (float)mTexHeight); - } else { - inSampleSize = (int)Math.ceil(imageWidth / (float)mTexWidth); - } - } -// if (DEBUG) Log.v(TAG, String.format("image(%d,%d),tex(%d,%d),inSampleSize=%d", imageWidth, imageHeight, mTexWidth, mTexHeight, inSampleSize)); - // 実際の読み込み処理 - options.inSampleSize = inSampleSize; - options.inJustDecodeBounds = false; - loadTexture(BitmapFactory.decodeFile(filePath, options)); - } - - /** - * ビットマップからテクスチャを読み込む - * @param bitmap - * @throws NullPointerException - */ - @Override - public void loadTexture(final Bitmap bitmap) throws NullPointerException { - mImageWidth = bitmap.getWidth(); // 読み込んだイメージのサイズを取得 - mImageHeight = bitmap.getHeight(); - Bitmap texture = Bitmap.createBitmap(mTexWidth, mTexHeight, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(texture); - canvas.drawBitmap(bitmap, 0, 0, null); - bitmap.recycle(); - // テクスチャ座標変換行列を設定(読み込んだイメージサイズがテクスチャサイズにフィットするようにスケール変換) - Matrix.setIdentityM(mTexMatrix, 0); - mTexMatrix[0] = mImageWidth / (float)mTexWidth; - mTexMatrix[5] = mImageHeight / (float)mTexHeight; -// if (DEBUG) Log.v(TAG, String.format("image(%d,%d),scale(%f,%f)", mImageWidth, mImageHeight, mMvpMatrix[0], mMvpMatrix[5])); - bind(); - GLUtils.texImage2D(mTextureTarget, 0, texture, 0); - unbind(); - texture.recycle(); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java deleted file mode 100644 index dfad92686f..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/CameraDialog.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.Context; -import android.content.DialogInterface; -import android.hardware.usb.UsbDevice; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.Button; -import android.widget.CheckedTextView; -import android.widget.Spinner; - - -import com.mogo.usbcamera.R; - -import java.util.ArrayList; -import java.util.List; - -public class CameraDialog extends DialogFragment { - private static final String TAG = CameraDialog.class.getSimpleName(); - - public interface CameraDialogParent { - public USBMonitor getUSBMonitor(); - public void onDialogResult(boolean canceled); - } - - /** - * Helper method - * @param parent FragmentActivity - * @return - */ - public static CameraDialog showDialog(final Activity parent/* add parameters here if you need */) { - CameraDialog dialog = newInstance(/* add parameters here if you need */); - try { - dialog.show(parent.getFragmentManager(), TAG); - } catch (final IllegalStateException e) { - dialog = null; - } - return dialog; - } - - public static CameraDialog newInstance(/* add parameters here if you need */) { - final CameraDialog dialog = new CameraDialog(); - final Bundle args = new Bundle(); - // add parameters here if you need - dialog.setArguments(args); - return dialog; - } - - protected USBMonitor mUSBMonitor; - private Spinner mSpinner; - private DeviceListAdapter mDeviceListAdapter; - - public CameraDialog(/* no arguments */) { - // Fragment need default constructor - } - - @SuppressWarnings("deprecation") - @Override - public void onAttach(final Activity activity) { - super.onAttach(activity); - if (mUSBMonitor == null) - try { - mUSBMonitor = ((CameraDialogParent)activity).getUSBMonitor(); - } catch (final ClassCastException e) { - } catch (final NullPointerException e) { - } - if (mUSBMonitor == null) { - throw new ClassCastException(activity.toString() + " must implement CameraDialogParent#getUSBController"); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (savedInstanceState == null) - savedInstanceState = getArguments(); - } - - @Override - public void onSaveInstanceState(final Bundle saveInstanceState) { - final Bundle args = getArguments(); - if (args != null) - saveInstanceState.putAll(args); - super.onSaveInstanceState(saveInstanceState); - } - - @Override - public Dialog onCreateDialog(final Bundle savedInstanceState) { - final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setView(initView()); - builder.setTitle(R.string.select); - builder.setPositiveButton(android.R.string.ok, mOnDialogClickListener); - builder.setNegativeButton(android.R.string.cancel , mOnDialogClickListener); - builder.setNeutralButton(R.string.refresh, null); - final Dialog dialog = builder.create(); - dialog.setCancelable(true); - dialog.setCanceledOnTouchOutside(true); - return dialog; - } - - /** - * create view that this fragment shows - * @return - */ - private final View initView() { - final View rootView = getActivity().getLayoutInflater().inflate(R.layout.dialog_camera, null); - mSpinner = (Spinner)rootView.findViewById(R.id.spinner1); - final View empty = rootView.findViewById(android.R.id.empty); - mSpinner.setEmptyView(empty); - return rootView; - } - - - @Override - public void onResume() { - super.onResume(); - updateDevices(); - final Button button = (Button)getDialog().findViewById(android.R.id.button3); - if (button != null) { - button.setOnClickListener(mOnClickListener); - } - } - - private final OnClickListener mOnClickListener = new OnClickListener() { - @Override - public void onClick(final View v) { - switch (v.getId()) { - case android.R.id.button3: - updateDevices(); - break; - } - } - }; - - private final DialogInterface.OnClickListener mOnDialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - final Object item = mSpinner.getSelectedItem(); - if (item instanceof UsbDevice) { - mUSBMonitor.requestPermission((UsbDevice)item); - ((CameraDialogParent)getActivity()).onDialogResult(false); - } - break; - case DialogInterface.BUTTON_NEGATIVE: - ((CameraDialogParent)getActivity()).onDialogResult(true); - break; - } - } - }; - - @Override - public void onCancel(final DialogInterface dialog) { - ((CameraDialogParent)getActivity()).onDialogResult(true); - super.onCancel(dialog); - } - - public void updateDevices() { -// mUSBMonitor.dumpDevices(); - final List filter = DeviceFilter.getDeviceFilters(getActivity(), R.xml.device_filter); - mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0))); - mSpinner.setAdapter(mDeviceListAdapter); - } - - private static final class DeviceListAdapter extends BaseAdapter { - - private final LayoutInflater mInflater; - private final List mList; - - public DeviceListAdapter(final Context context, final Listlist) { - mInflater = LayoutInflater.from(context); - mList = list != null ? list : new ArrayList(); - } - - @Override - public int getCount() { - return mList.size(); - } - - @Override - public UsbDevice getItem(final int position) { - if ((position >= 0) && (position < mList.size())) - return mList.get(position); - else - return null; - } - - @Override - public long getItemId(final int position) { - return position; - } - - @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate(R.layout.listitem_device, parent, false); - } - if (convertView instanceof CheckedTextView) { - final UsbDevice device = getItem(position); - ((CheckedTextView)convertView).setText( - String.format("UVC Camera:(%x:%x:%s)", device.getVendorId(), device.getProductId(), device.getDeviceName())); - } - return convertView; - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java deleted file mode 100644 index 2e94263c92..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/DeviceFilter.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import android.content.Context; -import android.content.res.Resources.NotFoundException; -import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbInterface; -import android.text.TextUtils; -import android.util.Log; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public final class DeviceFilter { - - private static final String TAG = "DeviceFilter"; - - // USB Vendor ID (or -1 for unspecified) - public final int mVendorId; - // USB Product ID (or -1 for unspecified) - public final int mProductId; - // USB device or interface class (or -1 for unspecified) - public final int mClass; - // USB device subclass (or -1 for unspecified) - public final int mSubclass; - // USB device protocol (or -1 for unspecified) - public final int mProtocol; - // USB device manufacturer name string (or null for unspecified) - public final String mManufacturerName; - // USB device product name string (or null for unspecified) - public final String mProductName; - // USB device serial number string (or null for unspecified) - public final String mSerialNumber; - // set true if specific device(s) should exclude - public final boolean isExclude; - - public DeviceFilter(final int vid, final int pid, final int clasz, final int subclass, - final int protocol, final String manufacturer, final String product, final String serialNum) { - this(vid, pid, clasz, subclass, protocol, manufacturer, product, serialNum, false); - } - - public DeviceFilter(final int vid, final int pid, final int clasz, final int subclass, - final int protocol, final String manufacturer, final String product, final String serialNum, final boolean isExclude) { - mVendorId = vid; - mProductId = pid; - mClass = clasz; - mSubclass = subclass; - mProtocol = protocol; - mManufacturerName = manufacturer; - mProductName = product; - mSerialNumber = serialNum; - this.isExclude = isExclude; -/* Log.i(TAG, String.format("vendorId=0x%04x,productId=0x%04x,class=0x%02x,subclass=0x%02x,protocol=0x%02x", - mVendorId, mProductId, mClass, mSubclass, mProtocol)); */ - } - - public DeviceFilter(final UsbDevice device) { - this(device, false); - } - - public DeviceFilter(final UsbDevice device, final boolean isExclude) { - mVendorId = device.getVendorId(); - mProductId = device.getProductId(); - mClass = device.getDeviceClass(); - mSubclass = device.getDeviceSubclass(); - mProtocol = device.getDeviceProtocol(); - mManufacturerName = null; // device.getManufacturerName(); - mProductName = null; // device.getProductName(); - mSerialNumber = null; // device.getSerialNumber(); - this.isExclude = isExclude; -/* Log.i(TAG, String.format("vendorId=0x%04x,productId=0x%04x,class=0x%02x,subclass=0x%02x,protocol=0x%02x", - mVendorId, mProductId, mClass, mSubclass, mProtocol)); */ - } - - /** - * 指定したxmlリソースからDeviceFilterリストを生成する - * @param context - * @param deviceFilterXmlId - * @return - */ - public static List getDeviceFilters(final Context context, final int deviceFilterXmlId) { - final XmlPullParser parser = context.getResources().getXml(deviceFilterXmlId); - final List deviceFilters = new ArrayList(); - try { - int eventType = parser.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - final DeviceFilter deviceFilter = readEntryOne(context, parser); - if (deviceFilter != null) { - deviceFilters.add(deviceFilter); - } - } - eventType = parser.next(); - } - } catch (final XmlPullParserException e) { - Log.d(TAG, "XmlPullParserException", e); - } catch (final IOException e) { - Log.d(TAG, "IOException", e); - } - - return Collections.unmodifiableList(deviceFilters); - } - - /** - * read as integer values with default value from xml(w/o exception throws) - * resource integer id is also resolved into integer - * @param parser - * @param namespace - * @param name - * @param defaultValue - * @return - */ - private static final int getAttributeInteger(final Context context, final XmlPullParser parser, final String namespace, final String name, final int defaultValue) { - int result = defaultValue; - try { - String v = parser.getAttributeValue(namespace, name); - if (!TextUtils.isEmpty(v) && v.startsWith("@")) { - final String r = v.substring(1); - final int resId = context.getResources().getIdentifier(r, null, context.getPackageName()); - if (resId > 0) { - result = context.getResources().getInteger(resId); - } - } else { - int radix = 10; - if (v != null && v.length() > 2 && v.charAt(0) == '0' && - (v.charAt(1) == 'x' || v.charAt(1) == 'X')) { - // allow hex values starting with 0x or 0X - radix = 16; - v = v.substring(2); - } - result = Integer.parseInt(v, radix); - } - } catch (final NotFoundException e) { - result = defaultValue; - } catch (final NumberFormatException e) { - result = defaultValue; - } catch (final NullPointerException e) { - result = defaultValue; - } - return result; - } - - /** - * read as boolean values with default value from xml(w/o exception throws) - * resource boolean id is also resolved into boolean - * if the value is zero, return false, if the value is non-zero integer, return true - * @param context - * @param parser - * @param namespace - * @param name - * @param defaultValue - * @return - */ - private static final boolean getAttributeBoolean(final Context context, final XmlPullParser parser, final String namespace, final String name, final boolean defaultValue) { - boolean result = defaultValue; - try { - String v = parser.getAttributeValue(namespace, name); - if ("TRUE".equalsIgnoreCase(v)) { - result = true; - } else if ("FALSE".equalsIgnoreCase(v)) { - result = false; - } else if (!TextUtils.isEmpty(v) && v.startsWith("@")) { - final String r = v.substring(1); - final int resId = context.getResources().getIdentifier(r, null, context.getPackageName()); - if (resId > 0) { - result = context.getResources().getBoolean(resId); - } - } else { - int radix = 10; - if (v != null && v.length() > 2 && v.charAt(0) == '0' && - (v.charAt(1) == 'x' || v.charAt(1) == 'X')) { - // allow hex values starting with 0x or 0X - radix = 16; - v = v.substring(2); - } - final int val = Integer.parseInt(v, radix); - result = val != 0; - } - } catch (final NotFoundException e) { - result = defaultValue; - } catch (final NumberFormatException e) { - result = defaultValue; - } catch (final NullPointerException e) { - result = defaultValue; - } - return result; - } - - /** - * read as String attribute with default value from xml(w/o exception throws) - * resource string id is also resolved into string - * @param parser - * @param namespace - * @param name - * @param defaultValue - * @return - */ - private static final String getAttributeString(final Context context, final XmlPullParser parser, final String namespace, final String name, final String defaultValue) { - String result = defaultValue; - try { - result = parser.getAttributeValue(namespace, name); - if (result == null) - result = defaultValue; - if (!TextUtils.isEmpty(result) && result.startsWith("@")) { - final String r = result.substring(1); - final int resId = context.getResources().getIdentifier(r, null, context.getPackageName()); - if (resId > 0) - result = context.getResources().getString(resId); - } - } catch (final NotFoundException e) { - result = defaultValue; - } catch (final NumberFormatException e) { - result = defaultValue; - } catch (final NullPointerException e) { - result = defaultValue; - } - return result; - } - - public static DeviceFilter readEntryOne(final Context context, final XmlPullParser parser) - throws XmlPullParserException, IOException { - int vendorId = -1; - int productId = -1; - int deviceClass = -1; - int deviceSubclass = -1; - int deviceProtocol = -1; - boolean exclude = false; - String manufacturerName = null; - String productName = null; - String serialNumber = null; - boolean hasValue = false; - - String tag; - int eventType = parser.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - tag = parser.getName(); - if (!TextUtils.isEmpty(tag) && (tag.equalsIgnoreCase("usb-device"))) { - if (eventType == XmlPullParser.START_TAG) { - hasValue = true; - vendorId = getAttributeInteger(context, parser, null, "vendor-id", -1); - if (vendorId == -1) { - vendorId = getAttributeInteger(context, parser, null, "vendorId", -1); - if (vendorId == -1) - vendorId = getAttributeInteger(context, parser, null, "venderId", -1); - } - productId = getAttributeInteger(context, parser, null, "product-id", -1); - if (productId == -1) - productId = getAttributeInteger(context, parser, null, "productId", -1); - deviceClass = getAttributeInteger(context, parser, null, "class", -1); - deviceSubclass = getAttributeInteger(context, parser, null, "subclass", -1); - deviceProtocol = getAttributeInteger(context, parser, null, "protocol", -1); - manufacturerName = getAttributeString(context, parser, null, "manufacturer-name", null); - if (TextUtils.isEmpty(manufacturerName)) - manufacturerName = getAttributeString(context, parser, null, "manufacture", null); - productName = getAttributeString(context, parser, null, "product-name", null); - if (TextUtils.isEmpty(productName)) - productName = getAttributeString(context, parser, null, "product", null); - serialNumber = getAttributeString(context, parser, null, "serial-number", null); - if (TextUtils.isEmpty(serialNumber)) - serialNumber = getAttributeString(context, parser, null, "serial", null); - exclude = getAttributeBoolean(context, parser, null, "exclude", false); - } else if (eventType == XmlPullParser.END_TAG) { - if (hasValue) { - return new DeviceFilter(vendorId, productId, deviceClass, - deviceSubclass, deviceProtocol, manufacturerName, productName, - serialNumber, exclude); - } - } - } - eventType = parser.next(); - } - return null; - } - -/* public void write(XmlSerializer serializer) throws IOException { - serializer.startTag(null, "usb-device"); - if (mVendorId != -1) { - serializer - .attribute(null, "vendor-id", Integer.toString(mVendorId)); - } - if (mProductId != -1) { - serializer.attribute(null, "product-id", - Integer.toString(mProductId)); - } - if (mClass != -1) { - serializer.attribute(null, "class", Integer.toString(mClass)); - } - if (mSubclass != -1) { - serializer.attribute(null, "subclass", Integer.toString(mSubclass)); - } - if (mProtocol != -1) { - serializer.attribute(null, "protocol", Integer.toString(mProtocol)); - } - if (mManufacturerName != null) { - serializer.attribute(null, "manufacturer-name", mManufacturerName); - } - if (mProductName != null) { - serializer.attribute(null, "product-name", mProductName); - } - if (mSerialNumber != null) { - serializer.attribute(null, "serial-number", mSerialNumber); - } - serializer.attribute(null, "serial-number", Boolean.toString(isExclude)); - serializer.endTag(null, "usb-device"); - } */ - - /** - * 指定したクラス・サブクラス・プロトコルがこのDeviceFilterとマッチするかどうかを返す - * mExcludeフラグは別途#isExcludeか自前でチェックすること - * @param clasz - * @param subclass - * @param protocol - * @return - */ - private boolean matches(final int clasz, final int subclass, final int protocol) { - return ((mClass == -1 || clasz == mClass) - && (mSubclass == -1 || subclass == mSubclass) && (mProtocol == -1 || protocol == mProtocol)); - } - - /** - * 指定したUsbDeviceがこのDeviceFilterにマッチするかどうかを返す - * mExcludeフラグは別途#isExcludeか自前でチェックすること - * @param device - * @return - */ - public boolean matches(final UsbDevice device) { - if (mVendorId != -1 && device.getVendorId() != mVendorId) { - return false; - } - if (mProductId != -1 && device.getProductId() != mProductId) { - return false; - } -/* if (mManufacturerName != null && device.getManufacturerName() == null) - return false; - if (mProductName != null && device.getProductName() == null) - return false; - if (mSerialNumber != null && device.getSerialNumber() == null) - return false; - if (mManufacturerName != null && device.getManufacturerName() != null - && !mManufacturerName.equals(device.getManufacturerName())) - return false; - if (mProductName != null && device.getProductName() != null - && !mProductName.equals(device.getProductName())) - return false; - if (mSerialNumber != null && device.getSerialNumber() != null - && !mSerialNumber.equals(device.getSerialNumber())) - return false; */ - - // check device class/subclass/protocol - if (matches(device.getDeviceClass(), device.getDeviceSubclass(), device.getDeviceProtocol())) { - return true; - } - - // if device doesn't match, check the interfaces - final int count = device.getInterfaceCount(); - for (int i = 0; i < count; i++) { - final UsbInterface intf = device.getInterface(i); - if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(), intf.getInterfaceProtocol())) { - return true; - } - } - - return false; - } - - /** - * このDeviceFilterに一致してかつmExcludeがtrueならtrueを返す - * @param device - * @return - */ - public boolean isExclude(final UsbDevice device) { - return isExclude && matches(device); - } - - /** - * これって要らんかも, equalsでできる気が - * @param f - * @return - */ - public boolean matches(final DeviceFilter f) { - if (isExclude != f.isExclude) { - return false; - } - if (mVendorId != -1 && f.mVendorId != mVendorId) { - return false; - } - if (mProductId != -1 && f.mProductId != mProductId) { - return false; - } - if (f.mManufacturerName != null && mManufacturerName == null) { - return false; - } - if (f.mProductName != null && mProductName == null) { - return false; - } - if (f.mSerialNumber != null && mSerialNumber == null) { - return false; - } - if (mManufacturerName != null && f.mManufacturerName != null - && !mManufacturerName.equals(f.mManufacturerName)) { - return false; - } - if (mProductName != null && f.mProductName != null - && !mProductName.equals(f.mProductName)) { - return false; - } - if (mSerialNumber != null && f.mSerialNumber != null - && !mSerialNumber.equals(f.mSerialNumber)) { - return false; - } - - // check device class/subclass/protocol - return matches(f.mClass, f.mSubclass, f.mProtocol); - } - - @Override - public boolean equals(final Object obj) { - // can't compare if we have wildcard strings - if (mVendorId == -1 || mProductId == -1 || mClass == -1 - || mSubclass == -1 || mProtocol == -1) { - return false; - } - if (obj instanceof DeviceFilter) { - final DeviceFilter filter = (DeviceFilter) obj; - - if (filter.mVendorId != mVendorId - || filter.mProductId != mProductId - || filter.mClass != mClass || filter.mSubclass != mSubclass - || filter.mProtocol != mProtocol) { - return false; - } - if ((filter.mManufacturerName != null && mManufacturerName == null) - || (filter.mManufacturerName == null && mManufacturerName != null) - || (filter.mProductName != null && mProductName == null) - || (filter.mProductName == null && mProductName != null) - || (filter.mSerialNumber != null && mSerialNumber == null) - || (filter.mSerialNumber == null && mSerialNumber != null)) { - return false; - } - if ((filter.mManufacturerName != null && mManufacturerName != null && !mManufacturerName - .equals(filter.mManufacturerName)) - || (filter.mProductName != null && mProductName != null && !mProductName - .equals(filter.mProductName)) - || (filter.mSerialNumber != null && mSerialNumber != null && !mSerialNumber - .equals(filter.mSerialNumber))) { - return false; - } - return (filter.isExclude != isExclude); - } - if (obj instanceof UsbDevice) { - final UsbDevice device = (UsbDevice) obj; - if (isExclude - || (device.getVendorId() != mVendorId) - || (device.getProductId() != mProductId) - || (device.getDeviceClass() != mClass) - || (device.getDeviceSubclass() != mSubclass) - || (device.getDeviceProtocol() != mProtocol) ) { - return false; - } -/* if ((mManufacturerName != null && device.getManufacturerName() == null) - || (mManufacturerName == null && device - .getManufacturerName() != null) - || (mProductName != null && device.getProductName() == null) - || (mProductName == null && device.getProductName() != null) - || (mSerialNumber != null && device.getSerialNumber() == null) - || (mSerialNumber == null && device.getSerialNumber() != null)) { - return (false); - } */ -/* if ((device.getManufacturerName() != null && !mManufacturerName - .equals(device.getManufacturerName())) - || (device.getProductName() != null && !mProductName - .equals(device.getProductName())) - || (device.getSerialNumber() != null && !mSerialNumber - .equals(device.getSerialNumber()))) { - return (false); - } */ - return true; - } - return false; - } - - @Override - public int hashCode() { - return (((mVendorId << 16) | mProductId) ^ ((mClass << 16) - | (mSubclass << 8) | mProtocol)); - } - - @Override - public String toString() { - return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" - + mProductId + ",mClass=" + mClass + ",mSubclass=" + mSubclass - + ",mProtocol=" + mProtocol - + ",mManufacturerName=" + mManufacturerName - + ",mProductName=" + mProductName - + ",mSerialNumber=" + mSerialNumber - + ",isExclude=" + isExclude - + "]"; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IButtonCallback.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IButtonCallback.java deleted file mode 100644 index 4025085c46..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IButtonCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.serenegiant.usb; - -public interface IButtonCallback { - void onButton(int button, int state); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java deleted file mode 100644 index f6aee755e0..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IFrameCallback.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import java.nio.ByteBuffer; - -/** - * Callback interface for UVCCamera class - * If you need frame data as ByteBuffer, you can use this callback interface with UVCCamera#setFrameCallback - */ -public interface IFrameCallback { - /** - * This method is called from native library via JNI on the same thread as UVCCamera#startCapture. - * You can use both UVCCamera#startCapture and #setFrameCallback - * but it is better to use either for better performance. - * You can also pass pixel format type to UVCCamera#setFrameCallback for this method. - * Some frames may drops if this method takes a time. - * When you use some color format like NV21, this library never execute color space conversion, - * just execute pixel format conversion. If you want to get same result as on screen, please try to - * consider to get images via texture(SurfaceTexture) and read pixel buffer from it using OpenGL|ES2/3 - * instead of using IFrameCallback(this way is much efficient in most case than using IFrameCallback). - * @param frame this is direct ByteBuffer from JNI layer and you should handle it's byte order and limitation. - */ - public void onFrame(ByteBuffer frame); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IStatusCallback.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IStatusCallback.java deleted file mode 100644 index ad743204ff..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/IStatusCallback.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.serenegiant.usb; - -import java.nio.ByteBuffer; - -public interface IStatusCallback { - void onStatus(int statusClass, int event, int selector, int statusAttribute, ByteBuffer data); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/ParentPreviewConstraintLayout.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/ParentPreviewConstraintLayout.java deleted file mode 100644 index 96dfc06ee2..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/ParentPreviewConstraintLayout.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.serenegiant.usb; - -import android.content.Context; -import android.util.AttributeSet; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.constraintlayout.widget.ConstraintLayout; - -/** - * @author mogoauto - */ -public abstract class ParentPreviewConstraintLayout extends ConstraintLayout { - private boolean mDestroyed; - - public ParentPreviewConstraintLayout(@NonNull Context context) { - super(context); - } - - public ParentPreviewConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public ParentPreviewConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public ParentPreviewConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - public boolean isDestroyed() { - return mDestroyed; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mDestroyed = false; - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mDestroyed = true; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/Size.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/Size.java deleted file mode 100644 index 963a805398..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/Size.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Locale; - -public class Size implements Parcelable { - // - /** - * native側のuvc_raw_format_tの値, こっちは主にlibuvc用 - * 9999 is still image - */ - public int type; - /** - * native側のraw_frame_tの値, androusb用, - * libuvcは対応していない - */ - public int frame_type; - public int index; - public int width; - public int height; - public int frameIntervalType; - public int frameIntervalIndex; - public int[] intervals; - // ここ以下はframeIntervalTypeとintervalsから#updateFrameRateで計算する - public float[] fps; - private String frameRates; - - /** - * コンストラクタ - * @param _type native側のraw_format_tの値, ただし9999は静止画 - * @param _frame_type native側のraw_frame_tの値 - * @param _index - * @param _width - * @param _height - */ - public Size(final int _type, final int _frame_type, final int _index, final int _width, final int _height) { - type = _type; - frame_type = _frame_type; - index = _index; - width = _width; - height = _height; - frameIntervalType = -1; - frameIntervalIndex = 0; - intervals = null; - updateFrameRate(); - } - - /** - * コンストラクタ - * @param _type native側のraw_format_tの値, ただし9999は静止画 - * @param _frame_type native側のraw_frame_tの値 - * @param _index - * @param _width - * @param _height - * @param _min_intervals - * @param _max_intervals - */ - public Size(final int _type, final int _frame_type, final int _index, final int _width, final int _height, final int _min_intervals, final int _max_intervals, final int _step) { - type = _type; - frame_type = _frame_type; - index = _index; - width = _width; - height = _height; - frameIntervalType = 0; - frameIntervalIndex = 0; - intervals = new int[3]; - intervals[0] = _min_intervals; - intervals[1] = _max_intervals; - intervals[2] = _step; - updateFrameRate(); - } - - /** - * コンストラクタ - * @param _type native側のraw_format_tの値, ただし9999は静止画 - * @param _frame_type native側のraw_frame_tの値 - * @param _index - * @param _width - * @param _height - * @param _intervals - */ - public Size(final int _type, final int _frame_type, final int _index, final int _width, final int _height, final int[] _intervals) { - type = _type; - frame_type = _frame_type; - index = _index; - width = _width; - height = _height; - final int n = _intervals != null ? _intervals.length : -1; - if (n > 0) { - frameIntervalType = n; - intervals = new int[n]; - System.arraycopy(_intervals, 0, intervals, 0, n); - } else { - frameIntervalType = -1; - intervals = null; - } - frameIntervalIndex = 0; - updateFrameRate(); - } - - /** - * コピーコンストラクタ - * @param other - */ - public Size(final Size other) { - type = other.type; - frame_type = other.frame_type; - index = other.index; - width = other.width; - height = other.height; - frameIntervalType = other.frameIntervalType; - frameIntervalIndex = other.frameIntervalIndex; - final int n = other.intervals != null ? other.intervals.length : -1; - if (n > 0) { - intervals = new int[n]; - System.arraycopy(other.intervals, 0, intervals, 0, n); - } else { - intervals = null; - } - updateFrameRate(); - } - - private Size(final Parcel source) { - // 読み取り順はwriteToParcelでの書き込み順と同じでないとダメ - type = source.readInt(); - frame_type = source.readInt(); - index = source.readInt(); - width = source.readInt(); - height = source.readInt(); - frameIntervalType = source.readInt(); - frameIntervalIndex = source.readInt(); - if (frameIntervalType >= 0) { - if (frameIntervalType > 0) { - intervals = new int[frameIntervalType]; - } else { - intervals = new int[3]; - } - source.readIntArray(intervals); - } else { - intervals = null; - } - updateFrameRate(); - } - - public Size set(final Size other) { - if (other != null) { - type = other.type; - frame_type = other.frame_type; - index = other.index; - width = other.width; - height = other.height; - frameIntervalType = other.frameIntervalType; - frameIntervalIndex = other.frameIntervalIndex; - final int n = other.intervals != null ? other.intervals.length : -1; - if (n > 0) { - intervals = new int[n]; - System.arraycopy(other.intervals, 0, intervals, 0, n); - } else { - intervals = null; - } - updateFrameRate(); - } - return this; - } - - public float getCurrentFrameRate() throws IllegalStateException { - final int n = fps != null ? fps.length : 0; - if ((frameIntervalIndex >= 0) && (frameIntervalIndex < n)) { - return fps[frameIntervalIndex]; - } - throw new IllegalStateException("unknown frame rate or not ready"); - } - - public void setCurrentFrameRate(final float frameRate) { - // 一番近いのを選ぶ - int index = -1; - final int n = fps != null ? fps.length : 0; - for (int i = 0; i < n; i++) { - if (fps[i] <= frameRate) { - index = i; - break; - } - } - frameIntervalIndex = index; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(final Parcel dest, final int flags) { - dest.writeInt(type); - dest.writeInt(frame_type); - dest.writeInt(index); - dest.writeInt(width); - dest.writeInt(height); - dest.writeInt(frameIntervalType); - dest.writeInt(frameIntervalIndex); - if (intervals != null) { - dest.writeIntArray(intervals); - } - } - - public void updateFrameRate() { - final int n = frameIntervalType; - if (n > 0) { - fps = new float[n]; - for (int i = 0; i < n; i++) { - final float _fps = fps[i] = 10000000.0f / intervals[i]; - } - } else if (n == 0) { - try { - final int min = Math.min(intervals[0], intervals[1]); - final int max = Math.max(intervals[0], intervals[1]); - final int step = intervals[2]; - if (step > 0) { - int m = 0; - for (int i = min; i <= max; i+= step) { m++; } - fps = new float[m]; - m = 0; - for (int i = min; i <= max; i+= step) { - final float _fps = fps[m++] = 10000000.0f / i; - } - } else { - final float max_fps = 10000000.0f / min; - int m = 0; - for (float fps = 10000000.0f / min; fps <= max_fps; fps += 1.0f) { m++; } - fps = new float[m]; - m = 0; - for (float fps = 10000000.0f / min; fps <= max_fps; fps += 1.0f) { - this.fps[m++] = fps; - } - } - } catch (final Exception e) { - // ignore, なんでかminとmaxが0になってるんちゃうかな - fps = null; - } - } - final int m = fps != null ? fps.length : 0; - final StringBuilder sb = new StringBuilder(); - sb.append("["); - for (int i = 0; i < m; i++) { - sb.append(String.format(Locale.US, "%4.1f", fps[i])); - if (i < m-1) { - sb.append(","); - } - } - sb.append("]"); - frameRates = sb.toString(); - if (frameIntervalIndex > m) { - frameIntervalIndex = 0; - } - } - - @Override - public String toString() { - float frame_rate = 0.0f; - try { - frame_rate = getCurrentFrameRate(); - } catch (final Exception e) { - } - return String.format(Locale.US, "Size(%dx%d@%4.1f,type:%d,frame:%d,index:%d,%s)", width, height, frame_rate, type, frame_type, index, frameRates); - } - - public static final Creator CREATOR = new Creator() { - @Override - public Size createFromParcel(final Parcel source) { - return new Size(source); - } - @Override - public Size[] newArray(final int size) { - return new Size[size]; - } - }; -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java deleted file mode 100644 index b46ee9f4a6..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBMonitor.java +++ /dev/null @@ -1,1416 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbDeviceConnection; -import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbManager; -import android.os.Build; -import android.os.Environment; -import android.os.Handler; -import android.text.TextUtils; -import android.util.Log; -import android.util.SparseArray; - -import com.serenegiant.utils.BuildCheck; -import com.serenegiant.utils.HandlerThreadHandler; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -public final class USBMonitor { - - private static final boolean DEBUG = false; // TODO set false on production - private static final String TAG = "USBMonitor"; - - private static final String ACTION_USB_PERMISSION_BASE = "com.serenegiant.USB_PERMISSION."; - private final String ACTION_USB_PERMISSION = ACTION_USB_PERMISSION_BASE + hashCode(); - - public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"; - - /** - * openしているUsbControlBlock - */ - private final ConcurrentHashMap mCtrlBlocks = new ConcurrentHashMap(); - private final SparseArray> mHasPermissions = new SparseArray>(); - - private final WeakReference mWeakContext; - private final UsbManager mUsbManager; - private final OnDeviceConnectListener mOnDeviceConnectListener; - private PendingIntent mPermissionIntent = null; - private List mDeviceFilters = new ArrayList(); - - /** - * コールバックをワーカースレッドで呼び出すためのハンドラー - */ - private final Handler mAsyncHandler; - private volatile boolean destroyed; - /** - * USB機器の状態変更時のコールバックリスナー - */ - public interface OnDeviceConnectListener { - /** - * called when device attached - * @param device - */ - public void onAttach(UsbDevice device); - /** - * called when device dettach(after onDisconnect) - * @param device - */ - public void onDettach(UsbDevice device); - /** - * called after device opend - * @param device - * @param ctrlBlock - * @param createNew - */ - public void onConnect(UsbDevice device, UsbControlBlock ctrlBlock, boolean createNew); - /** - * called when USB device removed or its power off (this callback is called after device closing) - * @param device - * @param ctrlBlock - */ - public void onDisconnect(UsbDevice device, UsbControlBlock ctrlBlock); - /** - * called when canceled or could not get permission from user - * @param device - */ - public void onCancel(UsbDevice device); - } - - public USBMonitor(final Context context, final OnDeviceConnectListener listener) { - if (DEBUG) Log.v(TAG, "USBMonitor:Constructor"); - if (listener == null) - throw new IllegalArgumentException("OnDeviceConnectListener should not null."); - mWeakContext = new WeakReference(context); - mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); - mOnDeviceConnectListener = listener; - mAsyncHandler = HandlerThreadHandler.createHandler(TAG); - destroyed = false; - if (DEBUG) Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager); - } - - /** - * Release all related resources, - * never reuse again - */ - public void destroy() { - if (DEBUG) Log.i(TAG, "destroy:"); - unregister(); - if (!destroyed) { - destroyed = true; - // モニターしているUSB機器を全てcloseする - final Set keys = mCtrlBlocks.keySet(); - if (keys != null) { - UsbControlBlock ctrlBlock; - try { - for (final UsbDevice key: keys) { - ctrlBlock = mCtrlBlocks.remove(key); - if (ctrlBlock != null) { - ctrlBlock.close(); - } - } - } catch (final Exception e) { - Log.e(TAG, "destroy:", e); - } - } - mCtrlBlocks.clear(); - try { - mAsyncHandler.getLooper().quit(); - } catch (final Exception e) { - Log.e(TAG, "destroy:", e); - } - } - } - - /** - * register BroadcastReceiver to monitor USB events - * @throws IllegalStateException - */ - public synchronized void register() throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - if (mPermissionIntent == null) { - if (DEBUG) Log.i(TAG, "register:"); - final Context context = mWeakContext.get(); - if (context != null) { - mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0); - final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); - // ACTION_USB_DEVICE_ATTACHED never comes on some devices so it should not be added here - filter.addAction(ACTION_USB_DEVICE_ATTACHED); - filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); - context.registerReceiver(mUsbReceiver, filter); - } - // start connection check - mDeviceCounts = 0; - mAsyncHandler.postDelayed(mDeviceCheckRunnable, 1000); - } - } - - /** - * unregister BroadcastReceiver - * @throws IllegalStateException - */ - public synchronized void unregister() throws IllegalStateException { - // 接続チェック用Runnableを削除 - mDeviceCounts = 0; - if (!destroyed) { - mAsyncHandler.removeCallbacks(mDeviceCheckRunnable); - } - if (mPermissionIntent != null) { -// if (DEBUG) Log.i(TAG, "unregister:"); - final Context context = mWeakContext.get(); - try { - if (context != null) { - context.unregisterReceiver(mUsbReceiver); - } - } catch (final Exception e) { - Log.w(TAG, e); - } - mPermissionIntent = null; - } - } - - public synchronized boolean isRegistered() { - return !destroyed && (mPermissionIntent != null); - } - - /** - * set device filter - * @param filter - * @throws IllegalStateException - */ - public void setDeviceFilter(final DeviceFilter filter) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - mDeviceFilters.clear(); - mDeviceFilters.add(filter); - } - - /** - * デバイスフィルターを追加 - * @param filter - * @throws IllegalStateException - */ - public void addDeviceFilter(final DeviceFilter filter) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - mDeviceFilters.add(filter); - } - - /** - * デバイスフィルターを削除 - * @param filter - * @throws IllegalStateException - */ - public void removeDeviceFilter(final DeviceFilter filter) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - mDeviceFilters.remove(filter); - } - - /** - * set device filters - * @param filters - * @throws IllegalStateException - */ - public void setDeviceFilter(final List filters) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - mDeviceFilters.clear(); - mDeviceFilters.addAll(filters); - } - - /** - * add device filters - * @param filters - * @throws IllegalStateException - */ - public void addDeviceFilter(final List filters) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - mDeviceFilters.addAll(filters); - } - - /** - * remove device filters - * @param filters - */ - public void removeDeviceFilter(final List filters) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - mDeviceFilters.removeAll(filters); - } - - /** - * return the number of connected USB devices that matched device filter - * @return - * @throws IllegalStateException - */ - public int getDeviceCount() throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - return getDeviceList().size(); - } - - /** - * return device list, return empty list if no device matched - * @return - * @throws IllegalStateException - */ - public List getDeviceList() throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - return getDeviceList(mDeviceFilters); - } - - /** - * return device list, return empty list if no device matched - * @param filters - * @return - * @throws IllegalStateException - */ - public List getDeviceList(final List filters) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - // get detected devices - final HashMap deviceList = mUsbManager.getDeviceList(); - // store those devices info before matching filter xml file - String fileName = Environment.getExternalStorageDirectory().getAbsolutePath()+ "/USBCamera/failed_devices.txt"; - - File logFile = new File(fileName); - if(!logFile.getParentFile().exists()) { - logFile.getParentFile().mkdirs(); - } - - if(! logFile.exists()) { - try { - logFile.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - FileWriter fw = null; - PrintWriter pw = null; - try { - fw = new FileWriter(logFile, true); - } catch (IOException e) { - e.printStackTrace(); - } - if(fw != null) { - pw = new PrintWriter(fw); - } - final List result = new ArrayList(); - if (deviceList != null) { - if ((filters == null) || filters.isEmpty()) { - result.addAll(deviceList.values()); - } else { - for (final UsbDevice device: deviceList.values() ) { - // match devices - for (final DeviceFilter filter: filters) { - if ((filter != null) && filter.matches(device) || (filter != null && filter.mSubclass == device.getDeviceSubclass())) { - // when filter matches - if (!filter.isExclude) { - result.add(device); - } - break; - } else { - // collection failed dev's class and subclass - String devModel = Build.MODEL; - String devSystemVersion = Build.VERSION.RELEASE; - String devClass = String.valueOf(device.getDeviceClass()); - String subClass = String.valueOf(device.getDeviceSubclass()); - try{ - if(pw != null) { - StringBuilder sb = new StringBuilder(); - sb.append(devModel); - sb.append("/"); - sb.append(devSystemVersion); - sb.append(":"); - sb.append("class="+devClass+", subclass="+subClass); - pw.println(sb.toString()); - pw.flush(); - fw.flush(); - } - }catch (IOException e) { - e.printStackTrace(); - } - } - } - } - } - } - if (pw != null) { - pw.close(); - } - if (fw != null) { - try { - fw.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return result; - } - - /** - * return device list, return empty list if no device matched - * @param filter - * @return - * @throws IllegalStateException - */ - public List getDeviceList(final DeviceFilter filter) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - final HashMap deviceList = mUsbManager.getDeviceList(); - final List result = new ArrayList(); - if (deviceList != null) { - for (final UsbDevice device: deviceList.values() ) { - if ((filter == null) || (filter.matches(device) && !filter.isExclude)) { - result.add(device); - } - } - } - return result; - } - - /** - * get USB device list, without filter - * @return - * @throws IllegalStateException - */ - public Iterator getDevices() throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - Iterator iterator = null; - final HashMap list = mUsbManager.getDeviceList(); - if (list != null) - iterator = list.values().iterator(); - return iterator; - } - - /** - * output device list to LogCat - */ - public final void dumpDevices() { - final HashMap list = mUsbManager.getDeviceList(); - if (list != null) { - final Set keys = list.keySet(); - if (keys != null && keys.size() > 0) { - final StringBuilder sb = new StringBuilder(); - for (final String key: keys) { - final UsbDevice device = list.get(key); - final int num_interface = device != null ? device.getInterfaceCount() : 0; - sb.setLength(0); - for (int i = 0; i < num_interface; i++) { - sb.append(String.format(Locale.US, "interface%d:%s", i, device.getInterface(i).toString())); - } - Log.i(TAG, "key=" + key + ":" + device + ":" + sb.toString()); - } - } else { - Log.i(TAG, "no device"); - } - } else { - Log.i(TAG, "no device"); - } - } - - /** - * return whether the specific Usb device has permission - * @param device - * @return true: 指定したUsbDeviceにパーミッションがある - * @throws IllegalStateException - */ - public final boolean hasPermission(final UsbDevice device) throws IllegalStateException { - if (destroyed) throw new IllegalStateException("already destroyed"); - return updatePermission(device, device != null && mUsbManager.hasPermission(device)); - } - - /** - * 内部で保持しているパーミッション状態を更新 - * @param device - * @param hasPermission - * @return hasPermission - */ - private boolean updatePermission(final UsbDevice device, final boolean hasPermission) { - final int deviceKey = getDeviceKey(device, true); - synchronized (mHasPermissions) { - if (hasPermission) { - if (mHasPermissions.get(deviceKey) == null) { - mHasPermissions.put(deviceKey, new WeakReference(device)); - } - } else { - mHasPermissions.remove(deviceKey); - } - } - return hasPermission; - } - - /** - * request permission to access to USB device - * @param device - * @return true if fail to request permission - */ - public synchronized boolean requestPermission(final UsbDevice device) { -// if (DEBUG) Log.v(TAG, "requestPermission:device=" + device); - boolean result = false; - if (isRegistered()) { - if (device != null) { - if (mUsbManager.hasPermission(device)) { - // call onConnect if app already has permission - processConnect(device); - } else { - try { - // パーミッションがなければ要求する - mUsbManager.requestPermission(device, mPermissionIntent); - } catch (final Exception e) { - // Android5.1.xのGALAXY系でandroid.permission.sec.MDM_APP_MGMTという意味不明の例外生成するみたい - Log.w(TAG, e); - processCancel(device); - result = true; - } - } - } else { - processCancel(device); - result = true; - } - } else { - processCancel(device); - result = true; - } - return result; - } - - /** - * 指定したUsbDeviceをopenする - * @param device - * @return - * @throws SecurityException パーミッションがなければSecurityExceptionを投げる - */ - public UsbControlBlock openDevice(final UsbDevice device) throws SecurityException { - if (hasPermission(device)) { - UsbControlBlock result = mCtrlBlocks.get(device); - if (result == null) { - result = new UsbControlBlock(USBMonitor.this, device); // この中でopenDeviceする - mCtrlBlocks.put(device, result); - } - return result; - } else { - throw new SecurityException("has no permission"); - } - } - - /** - * BroadcastReceiver for USB permission - */ - private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(final Context context, final Intent intent) { - if (destroyed) return; - final String action = intent.getAction(); - if (ACTION_USB_PERMISSION.equals(action)) { - // when received the result of requesting USB permission - synchronized (USBMonitor.this) { - final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); - if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { - if (device != null) { - // get permission, call onConnect - processConnect(device); - } - } else { - // failed to get permission - processCancel(device); - } - } - } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { - final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); - updatePermission(device, hasPermission(device)); - processAttach(device); - } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { - // when device removed - final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); - if (device != null) { - UsbControlBlock ctrlBlock = mCtrlBlocks.remove(device); - if (ctrlBlock != null) { - // cleanup - ctrlBlock.close(); - } - mDeviceCounts = 0; - processDettach(device); - } - } - } - }; - - /** number of connected & detected devices */ - private volatile int mDeviceCounts = 0; - /** - * periodically check connected devices and if it changed, call onAttach - */ - private final Runnable mDeviceCheckRunnable = new Runnable() { - @Override - public void run() { - if (destroyed) return; - final List devices = getDeviceList(); - final int n = devices.size(); - final int hasPermissionCounts; - final int m; - synchronized (mHasPermissions) { - hasPermissionCounts = mHasPermissions.size(); - mHasPermissions.clear(); - for (final UsbDevice device: devices) { - hasPermission(device); - } - m = mHasPermissions.size(); - } - if ((n > mDeviceCounts) || (m > hasPermissionCounts)) { - mDeviceCounts = n; - if (mOnDeviceConnectListener != null) { - for (int i = 0; i < n; i++) { - final UsbDevice device = devices.get(i); - mAsyncHandler.post(new Runnable() { - @Override - public void run() { - mOnDeviceConnectListener.onAttach(device); - } - }); - } - } - } - mAsyncHandler.postDelayed(this, 2000); // confirm every 2 seconds - } - }; - - /** - * open specific USB device - * @param device - */ - private final void processConnect(final UsbDevice device) { - if (destroyed) return; - updatePermission(device, true); - mAsyncHandler.post(new Runnable() { - @Override - public void run() { - if (DEBUG) Log.v(TAG, "processConnect:device=" + device); - UsbControlBlock ctrlBlock; - final boolean createNew; - ctrlBlock = mCtrlBlocks.get(device); - if (ctrlBlock == null) { - ctrlBlock = new UsbControlBlock(USBMonitor.this, device); - mCtrlBlocks.put(device, ctrlBlock); - createNew = true; - } else { - createNew = false; - } - if (mOnDeviceConnectListener != null) { - mOnDeviceConnectListener.onConnect(device, ctrlBlock, createNew); - } - } - }); - } - - private final void processCancel(final UsbDevice device) { - if (destroyed) return; - if (DEBUG) Log.v(TAG, "processCancel:"); - updatePermission(device, false); - if (mOnDeviceConnectListener != null) { - mAsyncHandler.post(new Runnable() { - @Override - public void run() { - mOnDeviceConnectListener.onCancel(device); - } - }); - } - } - - private final void processAttach(final UsbDevice device) { - if (destroyed) return; - if (DEBUG) Log.v(TAG, "processAttach:"); - if (mOnDeviceConnectListener != null) { - mAsyncHandler.post(new Runnable() { - @Override - public void run() { - mOnDeviceConnectListener.onAttach(device); - } - }); - } - } - - private final void processDettach(final UsbDevice device) { - if (destroyed) return; - if (DEBUG) Log.v(TAG, "processDettach:"); - if (mOnDeviceConnectListener != null) { - mAsyncHandler.post(new Runnable() { - @Override - public void run() { - mOnDeviceConnectListener.onDettach(device); - } - }); - } - } - - /** - * USB機器毎の設定保存用にデバイスキー名を生成する。 - * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成 - * 同種の製品だと同じキー名になるので注意 - * @param device nullなら空文字列を返す - * @return - */ - public static final String getDeviceKeyName(final UsbDevice device) { - return getDeviceKeyName(device, null, false); - } - - /** - * USB機器毎の設定保存用にデバイスキー名を生成する。 - * useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意 - * @param device - * @param useNewAPI - * @return - */ - public static final String getDeviceKeyName(final UsbDevice device, final boolean useNewAPI) { - return getDeviceKeyName(device, null, useNewAPI); - } - /** - * USB機器毎の設定保存用にデバイスキー名を生成する。この機器名をHashMapのキーにする - * UsbDeviceがopenしている時のみ有効 - * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成 - * serialがnullや空文字でなければserialを含めたデバイスキー名を生成する - * useNewAPI=trueでAPIレベルを満たしていればマニュファクチャ名, バージョン, コンフィギュレーションカウントも使う - * @param device nullなら空文字列を返す - * @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得 - * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による) - * @return - */ - @SuppressLint("NewApi") - public static final String getDeviceKeyName(final UsbDevice device, final String serial, final boolean useNewAPI) { - if (device == null) return ""; - final StringBuilder sb = new StringBuilder(); - sb.append(device.getVendorId()); sb.append("#"); // API >= 12 - sb.append(device.getProductId()); sb.append("#"); // API >= 12 - sb.append(device.getDeviceClass()); sb.append("#"); // API >= 12 - sb.append(device.getDeviceSubclass()); sb.append("#"); // API >= 12 - sb.append(device.getDeviceProtocol()); // API >= 12 - if (!TextUtils.isEmpty(serial)) { - sb.append("#"); sb.append(serial); - } - if (useNewAPI && BuildCheck.isAndroid5()) { - sb.append("#"); - if (TextUtils.isEmpty(serial)) { - sb.append(device.getSerialNumber()); sb.append("#"); // API >= 21 - } - sb.append(device.getManufacturerName()); sb.append("#"); // API >= 21 - sb.append(device.getConfigurationCount()); sb.append("#"); // API >= 21 - if (BuildCheck.isMarshmallow()) { - sb.append(device.getVersion()); sb.append("#"); // API >= 23 - } - } -// if (DEBUG) Log.v(TAG, "getDeviceKeyName:" + sb.toString()); - return sb.toString(); - } - - /** - * デバイスキーを整数として取得 - * getDeviceKeyNameで得られる文字列のhasCodeを取得 - * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成 - * 同種の製品だと同じデバイスキーになるので注意 - * @param device nullなら0を返す - * @return - */ - public static final int getDeviceKey(final UsbDevice device) { - return device != null ? getDeviceKeyName(device, null, false).hashCode() : 0; - } - - /** - * デバイスキーを整数として取得 - * getDeviceKeyNameで得られる文字列のhasCodeを取得 - * useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意 - * @param device - * @param useNewAPI - * @return - */ - public static final int getDeviceKey(final UsbDevice device, final boolean useNewAPI) { - return device != null ? getDeviceKeyName(device, null, useNewAPI).hashCode() : 0; - } - - /** - * デバイスキーを整数として取得 - * getDeviceKeyNameで得られる文字列のhasCodeを取得 - * serialがnullでuseNewAPI=falseで同種の製品だと同じデバイスキーになるので注意 - * @param device nullなら0を返す - * @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得 - * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による) - * @return - */ - public static final int getDeviceKey(final UsbDevice device, final String serial, final boolean useNewAPI) { - return device != null ? getDeviceKeyName(device, serial, useNewAPI).hashCode() : 0; - } - - public static class UsbDeviceInfo { - public String usb_version; - public String manufacturer; - public String product; - public String version; - public String serial; - - private void clear() { - usb_version = manufacturer = product = version = serial = null; - } - - @Override - public String toString() { - return String.format("UsbDevice:usb_version=%s,manufacturer=%s,product=%s,version=%s,serial=%s", - usb_version != null ? usb_version : "", - manufacturer != null ? manufacturer : "", - product != null ? product : "", - version != null ? version : "", - serial != null ? serial : ""); - } - } - - private static final int USB_DIR_OUT = 0; - private static final int USB_DIR_IN = 0x80; - private static final int USB_TYPE_MASK = (0x03 << 5); - private static final int USB_TYPE_STANDARD = (0x00 << 5); - private static final int USB_TYPE_CLASS = (0x01 << 5); - private static final int USB_TYPE_VENDOR = (0x02 << 5); - private static final int USB_TYPE_RESERVED = (0x03 << 5); - private static final int USB_RECIP_MASK = 0x1f; - private static final int USB_RECIP_DEVICE = 0x00; - private static final int USB_RECIP_INTERFACE = 0x01; - private static final int USB_RECIP_ENDPOINT = 0x02; - private static final int USB_RECIP_OTHER = 0x03; - private static final int USB_RECIP_PORT = 0x04; - private static final int USB_RECIP_RPIPE = 0x05; - private static final int USB_REQ_GET_STATUS = 0x00; - private static final int USB_REQ_CLEAR_FEATURE = 0x01; - private static final int USB_REQ_SET_FEATURE = 0x03; - private static final int USB_REQ_SET_ADDRESS = 0x05; - private static final int USB_REQ_GET_DESCRIPTOR = 0x06; - private static final int USB_REQ_SET_DESCRIPTOR = 0x07; - private static final int USB_REQ_GET_CONFIGURATION = 0x08; - private static final int USB_REQ_SET_CONFIGURATION = 0x09; - private static final int USB_REQ_GET_INTERFACE = 0x0A; - private static final int USB_REQ_SET_INTERFACE = 0x0B; - private static final int USB_REQ_SYNCH_FRAME = 0x0C; - private static final int USB_REQ_SET_SEL = 0x30; - private static final int USB_REQ_SET_ISOCH_DELAY = 0x31; - private static final int USB_REQ_SET_ENCRYPTION = 0x0D; - private static final int USB_REQ_GET_ENCRYPTION = 0x0E; - private static final int USB_REQ_RPIPE_ABORT = 0x0E; - private static final int USB_REQ_SET_HANDSHAKE = 0x0F; - private static final int USB_REQ_RPIPE_RESET = 0x0F; - private static final int USB_REQ_GET_HANDSHAKE = 0x10; - private static final int USB_REQ_SET_CONNECTION = 0x11; - private static final int USB_REQ_SET_SECURITY_DATA = 0x12; - private static final int USB_REQ_GET_SECURITY_DATA = 0x13; - private static final int USB_REQ_SET_WUSB_DATA = 0x14; - private static final int USB_REQ_LOOPBACK_DATA_WRITE = 0x15; - private static final int USB_REQ_LOOPBACK_DATA_READ = 0x16; - private static final int USB_REQ_SET_INTERFACE_DS = 0x17; - - private static final int USB_REQ_STANDARD_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE); // 0x10 - private static final int USB_REQ_STANDARD_DEVICE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE); // 0x90 - private static final int USB_REQ_STANDARD_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE); // 0x11 - private static final int USB_REQ_STANDARD_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE); // 0x91 - private static final int USB_REQ_STANDARD_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); // 0x12 - private static final int USB_REQ_STANDARD_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); // 0x92 - - private static final int USB_REQ_CS_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0x20 - private static final int USB_REQ_CS_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0xa0 - private static final int USB_REQ_CS_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0x21 - private static final int USB_REQ_CS_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0xa1 - private static final int USB_REQ_CS_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0x22 - private static final int USB_REQ_CS_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0xa2 - - private static final int USB_REQ_VENDER_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0x40 - private static final int USB_REQ_VENDER_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0xc0 - private static final int USB_REQ_VENDER_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0x41 - private static final int USB_REQ_VENDER_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0xc1 - private static final int USB_REQ_VENDER_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0x42 - private static final int USB_REQ_VENDER_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0xc2 - - private static final int USB_DT_DEVICE = 0x01; - private static final int USB_DT_CONFIG = 0x02; - private static final int USB_DT_STRING = 0x03; - private static final int USB_DT_INTERFACE = 0x04; - private static final int USB_DT_ENDPOINT = 0x05; - private static final int USB_DT_DEVICE_QUALIFIER = 0x06; - private static final int USB_DT_OTHER_SPEED_CONFIG = 0x07; - private static final int USB_DT_INTERFACE_POWER = 0x08; - private static final int USB_DT_OTG = 0x09; - private static final int USB_DT_DEBUG = 0x0a; - private static final int USB_DT_INTERFACE_ASSOCIATION = 0x0b; - private static final int USB_DT_SECURITY = 0x0c; - private static final int USB_DT_KEY = 0x0d; - private static final int USB_DT_ENCRYPTION_TYPE = 0x0e; - private static final int USB_DT_BOS = 0x0f; - private static final int USB_DT_DEVICE_CAPABILITY = 0x10; - private static final int USB_DT_WIRELESS_ENDPOINT_COMP = 0x11; - private static final int USB_DT_WIRE_ADAPTER = 0x21; - private static final int USB_DT_RPIPE = 0x22; - private static final int USB_DT_CS_RADIO_CONTROL = 0x23; - private static final int USB_DT_PIPE_USAGE = 0x24; - private static final int USB_DT_SS_ENDPOINT_COMP = 0x30; - private static final int USB_DT_CS_DEVICE = (USB_TYPE_CLASS | USB_DT_DEVICE); - private static final int USB_DT_CS_CONFIG = (USB_TYPE_CLASS | USB_DT_CONFIG); - private static final int USB_DT_CS_STRING = (USB_TYPE_CLASS | USB_DT_STRING); - private static final int USB_DT_CS_INTERFACE = (USB_TYPE_CLASS | USB_DT_INTERFACE); - private static final int USB_DT_CS_ENDPOINT = (USB_TYPE_CLASS | USB_DT_ENDPOINT); - private static final int USB_DT_DEVICE_SIZE = 18; - - /** - * 指定したIDのStringディスクリプタから文字列を取得する。取得できなければnull - * @param connection - * @param id - * @param languageCount - * @param languages - * @return - */ - private static String getString(final UsbDeviceConnection connection, final int id, final int languageCount, final byte[] languages) { - final byte[] work = new byte[256]; - String result = null; - for (int i = 1; i <= languageCount; i++) { - int ret = connection.controlTransfer( - USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE - USB_REQ_GET_DESCRIPTOR, - (USB_DT_STRING << 8) | id, languages[i], work, 256, 0); - if ((ret > 2) && (work[0] == ret) && (work[1] == USB_DT_STRING)) { - // skip first two bytes(bLength & bDescriptorType), and copy the rest to the string - try { - result = new String(work, 2, ret - 2, "UTF-16LE"); - if (!"Љ".equals(result)) { // 変なゴミが返ってくる時がある - break; - } else { - result = null; - } - } catch (final UnsupportedEncodingException e) { - // ignore - } - } - } - return result; - } - - /** - * ベンダー名・製品名・バージョン・シリアルを取得する - * @param device - * @return - */ - public UsbDeviceInfo getDeviceInfo(final UsbDevice device) { - return updateDeviceInfo(mUsbManager, device, null); - } - - /** - * ベンダー名・製品名・バージョン・シリアルを取得する - * #updateDeviceInfo(final UsbManager, final UsbDevice, final UsbDeviceInfo)のヘルパーメソッド - * @param context - * @param device - * @return - */ - public static UsbDeviceInfo getDeviceInfo(final Context context, final UsbDevice device) { - return updateDeviceInfo((UsbManager)context.getSystemService(Context.USB_SERVICE), device, new UsbDeviceInfo()); - } - - /** - * ベンダー名・製品名・バージョン・シリアルを取得する - * @param manager - * @param device - * @param _info - * @return - */ - @TargetApi(Build.VERSION_CODES.M) - public static UsbDeviceInfo updateDeviceInfo(final UsbManager manager, final UsbDevice device, final UsbDeviceInfo _info) { - final UsbDeviceInfo info = _info != null ? _info : new UsbDeviceInfo(); - info.clear(); - - if (device != null) { - if (BuildCheck.isLollipop()) { - info.manufacturer = device.getManufacturerName(); - info.product = device.getProductName(); - info.serial = device.getSerialNumber(); - } - if (BuildCheck.isMarshmallow()) { - info.usb_version = device.getVersion(); - } - if ((manager != null) && manager.hasPermission(device)) { - final UsbDeviceConnection connection = manager.openDevice(device); - if(connection == null) { - return null; - } - final byte[] desc = connection.getRawDescriptors(); - - if (TextUtils.isEmpty(info.usb_version)) { - info.usb_version = String.format("%x.%02x", ((int)desc[3] & 0xff), ((int)desc[2] & 0xff)); - } - if (TextUtils.isEmpty(info.version)) { - info.version = String.format("%x.%02x", ((int)desc[13] & 0xff), ((int)desc[12] & 0xff)); - } - if (TextUtils.isEmpty(info.serial)) { - info.serial = connection.getSerial(); - } - - final byte[] languages = new byte[256]; - int languageCount = 0; - // controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout) - try { - int result = connection.controlTransfer( - USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE - USB_REQ_GET_DESCRIPTOR, - (USB_DT_STRING << 8) | 0, 0, languages, 256, 0); - if (result > 0) { - languageCount = (result - 2) / 2; - } - if (languageCount > 0) { - if (TextUtils.isEmpty(info.manufacturer)) { - info.manufacturer = getString(connection, desc[14], languageCount, languages); - } - if (TextUtils.isEmpty(info.product)) { - info.product = getString(connection, desc[15], languageCount, languages); - } - if (TextUtils.isEmpty(info.serial)) { - info.serial = getString(connection, desc[16], languageCount, languages); - } - } - } finally { - connection.close(); - } - } - if (TextUtils.isEmpty(info.manufacturer)) { - info.manufacturer = USBVendorId.vendorName(device.getVendorId()); - } - if (TextUtils.isEmpty(info.manufacturer)) { - info.manufacturer = String.format("%04x", device.getVendorId()); - } - if (TextUtils.isEmpty(info.product)) { - info.product = String.format("%04x", device.getProductId()); - } - } - return info; - } - - /** - * control class - * never reuse the instance when it closed - */ - public static final class UsbControlBlock implements Cloneable { - private final WeakReference mWeakMonitor; - private final WeakReference mWeakDevice; - protected UsbDeviceConnection mConnection; - protected final UsbDeviceInfo mInfo; - private final int mBusNum; - private final int mDevNum; - private final SparseArray> mInterfaces = new SparseArray>(); - - /** - * this class needs permission to access USB device before constructing - * @param monitor - * @param device - */ - private UsbControlBlock(final USBMonitor monitor, final UsbDevice device) { - if (DEBUG) Log.i(TAG, "UsbControlBlock:constructor"); - mWeakMonitor = new WeakReference(monitor); - mWeakDevice = new WeakReference(device); - mConnection = monitor.mUsbManager.openDevice(device); - mInfo = updateDeviceInfo(monitor.mUsbManager, device, null); - final String name = device.getDeviceName(); - final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null; - int busnum = 0; - int devnum = 0; - if (v != null) { - busnum = Integer.parseInt(v[v.length-2]); - devnum = Integer.parseInt(v[v.length-1]); - } - mBusNum = busnum; - mDevNum = devnum; -// if (DEBUG) { - if (mConnection != null) { - final int desc = mConnection.getFileDescriptor(); - final byte[] rawDesc = mConnection.getRawDescriptors(); - Log.i(TAG, String.format(Locale.US, "name=%s,desc=%d,busnum=%d,devnum=%d,rawDesc=", name, desc, busnum, devnum) + rawDesc); - } else { - Log.e(TAG, "could not connect to device " + name); - } -// } - } - - /** - * copy constructor - * @param src - * @throws IllegalStateException - */ - private UsbControlBlock(final UsbControlBlock src) throws IllegalStateException { - final USBMonitor monitor = src.getUSBMonitor(); - final UsbDevice device = src.getDevice(); - if (device == null) { - throw new IllegalStateException("device may already be removed"); - } - mConnection = monitor.mUsbManager.openDevice(device); - if (mConnection == null) { - throw new IllegalStateException("device may already be removed or have no permission"); - } - mInfo = updateDeviceInfo(monitor.mUsbManager, device, null); - mWeakMonitor = new WeakReference(monitor); - mWeakDevice = new WeakReference(device); - mBusNum = src.mBusNum; - mDevNum = src.mDevNum; - // FIXME USBMonitor.mCtrlBlocksに追加する(今はHashMapなので追加すると置き換わってしまうのでだめ, ListかHashMapにListをぶら下げる?) - } - - /** - * duplicate by clone - * need permission - * USBMonitor never handle cloned UsbControlBlock, you should release it after using it. - * @return - * @throws CloneNotSupportedException - */ - @Override - public UsbControlBlock clone() throws CloneNotSupportedException { - final UsbControlBlock ctrlblock; - try { - ctrlblock = new UsbControlBlock(this); - } catch (final IllegalStateException e) { - throw new CloneNotSupportedException(e.getMessage()); - } - return ctrlblock; - } - - public USBMonitor getUSBMonitor() { - return mWeakMonitor.get(); - } - - public final UsbDevice getDevice() { - return mWeakDevice.get(); - } - - /** - * get device name - * @return - */ - public String getDeviceName() { - final UsbDevice device = mWeakDevice.get(); - return device != null ? device.getDeviceName() : ""; - } - - /** - * get device id - * @return - */ - public int getDeviceId() { - final UsbDevice device = mWeakDevice.get(); - return device != null ? device.getDeviceId() : 0; - } - - /** - * get device key string - * @return same value if the devices has same vendor id, product id, device class, device subclass and device protocol - */ - public String getDeviceKeyName() { - return USBMonitor.getDeviceKeyName(mWeakDevice.get()); - } - - /** - * get device key string - * @param useNewAPI if true, try to use serial number - * @return - * @throws IllegalStateException - */ - public String getDeviceKeyName(final boolean useNewAPI) throws IllegalStateException { - if (useNewAPI) checkConnection(); - return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, useNewAPI); - } - - /** - * get device key - * @return - * @throws IllegalStateException - */ - public int getDeviceKey() throws IllegalStateException { - checkConnection(); - return USBMonitor.getDeviceKey(mWeakDevice.get()); - } - - /** - * get device key - * @param useNewAPI if true, try to use serial number - * @return - * @throws IllegalStateException - */ - public int getDeviceKey(final boolean useNewAPI) throws IllegalStateException { - if (useNewAPI) checkConnection(); - return USBMonitor.getDeviceKey(mWeakDevice.get(), mInfo.serial, useNewAPI); - } - - /** - * get device key string - * if device has serial number, use it - * @return - */ - public String getDeviceKeyNameWithSerial() { - return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, false); - } - - /** - * get device key - * if device has serial number, use it - * @return - */ - public int getDeviceKeyWithSerial() { - return getDeviceKeyNameWithSerial().hashCode(); - } - - /** - * get UsbDeviceConnection - * @return - */ - public synchronized UsbDeviceConnection getConnection() { - return mConnection; - } - - /** - * get file descriptor to access USB device - * @return - * @throws IllegalStateException - */ - public synchronized int getFileDescriptor() throws IllegalStateException { - checkConnection(); - return mConnection.getFileDescriptor(); - } - - /** - * get raw descriptor for the USB device - * @return - * @throws IllegalStateException - */ - public synchronized byte[] getRawDescriptors() throws IllegalStateException { - checkConnection(); - return mConnection.getRawDescriptors(); - } - - /** - * get vendor id - * @return - */ - public int getVenderId() { - final UsbDevice device = mWeakDevice.get(); - return device != null ? device.getVendorId() : 0; - } - - /** - * get product id - * @return - */ - public int getProductId() { - final UsbDevice device = mWeakDevice.get(); - return device != null ? device.getProductId() : 0; - } - - /** - * get version string of USB - * @return - */ - public String getUsbVersion() { - return mInfo.usb_version; - } - - /** - * get manufacture - * @return - */ - public String getManufacture() { - return mInfo.manufacturer; - } - - /** - * get product name - * @return - */ - public String getProductName() { - return mInfo.product; - } - - /** - * get version - * @return - */ - public String getVersion() { - return mInfo.version; - } - - /** - * get serial number - * @return - */ - public String getSerial() { - return mInfo.serial; - } - - public int getBusNum() { - return mBusNum; - } - - public int getDevNum() { - return mDevNum; - } - - /** - * get interface - * @param interface_id - * @throws IllegalStateException - */ - public synchronized UsbInterface getInterface(final int interface_id) throws IllegalStateException { - return getInterface(interface_id, 0); - } - - /** - * get interface - * @param interface_id - * @param altsetting - * @return - * @throws IllegalStateException - */ - public synchronized UsbInterface getInterface(final int interface_id, final int altsetting) throws IllegalStateException { - checkConnection(); - SparseArray intfs = mInterfaces.get(interface_id); - if (intfs == null) { - intfs = new SparseArray(); - mInterfaces.put(interface_id, intfs); - } - UsbInterface intf = intfs.get(altsetting); - if (intf == null) { - final UsbDevice device = mWeakDevice.get(); - final int n = device.getInterfaceCount(); - for (int i = 0; i < n; i++) { - final UsbInterface temp = device.getInterface(i); - if ((temp.getId() == interface_id) && (temp.getAlternateSetting() == altsetting)) { - intf = temp; - break; - } - } - if (intf != null) { - intfs.append(altsetting, intf); - } - } - return intf; - } - - /** - * open specific interface - * @param intf - */ - public synchronized void claimInterface(final UsbInterface intf) { - claimInterface(intf, true); - } - - public synchronized void claimInterface(final UsbInterface intf, final boolean force) { - checkConnection(); - mConnection.claimInterface(intf, force); - } - - /** - * close interface - * @param intf - * @throws IllegalStateException - */ - public synchronized void releaseInterface(final UsbInterface intf) throws IllegalStateException { - checkConnection(); - final SparseArray intfs = mInterfaces.get(intf.getId()); - if (intfs != null) { - final int index = intfs.indexOfValue(intf); - intfs.removeAt(index); - if (intfs.size() == 0) { - mInterfaces.remove(intf.getId()); - } - } - mConnection.releaseInterface(intf); - } - - /** - * Close device - * This also close interfaces if they are opened in Java side - */ - public synchronized void close() { - if (DEBUG) Log.i(TAG, "UsbControlBlock#close:"); - - if (mConnection != null) { - final int n = mInterfaces.size(); - for (int i = 0; i < n; i++) { - final SparseArray intfs = mInterfaces.valueAt(i); - if (intfs != null) { - final int m = intfs.size(); - for (int j = 0; j < m; j++) { - final UsbInterface intf = intfs.valueAt(j); - mConnection.releaseInterface(intf); - } - intfs.clear(); - } - } - mInterfaces.clear(); - mConnection.close(); - mConnection = null; - final USBMonitor monitor = mWeakMonitor.get(); - if (monitor != null) { - if (monitor.mOnDeviceConnectListener != null) { - monitor.mOnDeviceConnectListener.onDisconnect(mWeakDevice.get(), UsbControlBlock.this); - } - monitor.mCtrlBlocks.remove(getDevice()); - } - } - } - - @Override - public boolean equals(final Object o) { - if (o == null) return false; - if (o instanceof UsbControlBlock) { - final UsbDevice device = ((UsbControlBlock) o).getDevice(); - return device == null ? mWeakDevice.get() == null - : device.equals(mWeakDevice.get()); - } else if (o instanceof UsbDevice) { - return o.equals(mWeakDevice.get()); - } - return super.equals(o); - } - -// @Override -// protected void finalize() throws Throwable { -/// close(); -// super.finalize(); -// } - - private synchronized void checkConnection() throws IllegalStateException { - if (mConnection == null) { - throw new IllegalStateException("already closed"); - } - } - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java deleted file mode 100644 index d354b66ca7..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/USBVendorId.java +++ /dev/null @@ -1,859 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import android.util.SparseArray; - -public class USBVendorId { - private static final SparseArray IDS = new SparseArray(); - - public static String vendorName(final int vendor_id) { - return IDS.get(vendor_id); - } - - static { - IDS.put(10006, "YUEN DA ELECTRONIC PRODUCTS FACTORY"); - IDS.put(10013, "Gionee Communication Equipment Co., Ltd. ShenZhen"); - IDS.put(10022, "Universal Electronics Inc. (dba: TVIEW)"); - IDS.put(1003, "Atmel Corporation"); - IDS.put(1006, "Mitsumi"); - IDS.put(1008, "HP Inc."); - IDS.put(10112, "M31 Technology Corp."); - IDS.put(10113, "Liteconn Co., Ltd."); - IDS.put(10121, "Suzhou WEIJU Electronics Technology Co., Ltd."); - IDS.put(10144, "Mondokey Limited"); - IDS.put(10149, "Advantest Corporation"); - IDS.put(10150, "iRobot Corporation"); - IDS.put(1020, "Elitegroup Computer Systems"); - IDS.put(1021, "Xilinx Inc."); - IDS.put(10226, "Sibridge Tech."); - IDS.put(1026, "ALi Corporation"); - IDS.put(1027, "Future Technology Devices International Limited"); - IDS.put(10275, "Dongguan Jiumutong Industry Co., Ltd."); - IDS.put(10289, "Power Integrations"); - IDS.put(10291, "Oculus VR, Inc."); - IDS.put(10300, "HIGH TEK HARNESS ENTERPRISE CO., LTD."); - IDS.put(10316, "Full in Hope Co., Ltd."); - IDS.put(1032, "Quanta Computer Inc."); - IDS.put(10329, "Viconn Technology (HK) Co., Ltd."); - IDS.put(1033, "NEC Corporation"); - IDS.put(1035, "Weltrend Semiconductor"); - IDS.put(1037, "VIA Technologies, Inc."); - IDS.put(10374, "Seeed Technology Co., Ltd."); - IDS.put(10375, "Specwerkz"); - IDS.put(1038, "MCCI Corporation"); - IDS.put(10398, "Esselte Leitz GmbH & Co. KG"); - IDS.put(10406, "E-SEEK Inc."); - IDS.put(1041, "BUFFALO INC."); - IDS.put(10423, "Pleora Technologies Inc."); - IDS.put(10431, "Vitetech Int'l Co., Ltd."); - IDS.put(1044, "Giga-Byte Technology Co., Ltd."); - IDS.put(10446, "Changzhou Shi Wujin Miqi East Electronic Co., Ltd."); - IDS.put(10457, "Shenzhen Ourconn Technology Co., Ltd."); - IDS.put(10458, "G.SKILL Int'l Enterprice Co., Ltd."); - IDS.put(1046, "Nuvoton Technology Corp."); - IDS.put(10466, "Surplus Electronic Technology Co., Ltd."); - IDS.put(10470, "BIAMP SYSTEMS"); - IDS.put(10509, "IBCONN Technologies (Shenzhen) Co., Ltd."); - IDS.put(10510, "Fugoo Inc."); - IDS.put(10519, "Pan Xin Precision Electronics Co., Ltd."); - IDS.put(10530, "Dongguan Digi-in Digital Technology Co., Ltd."); - IDS.put(1054, "Creative Labs"); - IDS.put(10540, "GENUSION, Inc."); - IDS.put(10544, "Ineda Systems Inc."); - IDS.put(10545, "Jolla Ltd."); - IDS.put(10546, "Peraso Technologies, Inc."); - IDS.put(10549, "Nanjing Magewell Electronics Co., Ltd."); - IDS.put(10560, "Shenzhen Yiwanda Electronics Co., Ltd."); - IDS.put(1057, "Nokia Corporation"); - IDS.put(10575, "Dollar Connection Ltd."); - IDS.put(10595, "BIO-key International, Inc."); - IDS.put(1060, "Microchip-SMSC"); - IDS.put(10603, "Xacti Corporation"); - IDS.put(10615, "Shenzhen Zowee Technology Co., Ltd."); - IDS.put(10643, "ADPlaus Technology Limited"); - IDS.put(10646, "Unwired Technology"); - IDS.put(1065, "Cirrus Logic Inc."); - IDS.put(10657, "Union Electric Plug & Connector Corp."); - IDS.put(10674, "Canova Tech"); - IDS.put(10685, "Silicon Works"); - IDS.put(10695, "HANRICO ANFU ELECTRONICS CO., LTD."); - IDS.put(10700, "Kodak Alaris"); - IDS.put(10702, "JGR Optics Inc."); - IDS.put(10703, "Richtek Technology Corporation"); - IDS.put(10705, "Binatone Electronics Int. Ltd."); - IDS.put(1071, "Molex Inc."); - IDS.put(10715, "Shenzhen iBoard Technology Co., Ltd."); - IDS.put(10719, "SMIT(HK) Limited"); - IDS.put(1072, "Fujitsu Component Limited"); - IDS.put(10725, "Dongguan Kechenda Electronic Technology Co., Ltd."); - IDS.put(10726, "Fengshun Peiying Electro-Acoustic Co., Ltd."); - IDS.put(10744, "MD ELEKTRONIK GmbH"); - IDS.put(10749, "Bad Elf, LLC"); - IDS.put(10770, "Vreo Limited"); - IDS.put(10772, "Kanex"); - IDS.put(10781, "Oxford Nanopore Technologies"); - IDS.put(10782, "Obsidian Technology"); - IDS.put(10783, "Lucent Trans Electronics Co., Ltd."); - IDS.put(10784, "GUOGUANG GROUP CO., LTD."); - IDS.put(10788, "CNPLUS"); - IDS.put(10789, "Fourstar Group"); - IDS.put(10790, "Tragant International Co., Ltd."); - IDS.put(10791, "DongGuan LianGang Optoelectronic Technology Co., Ltd."); - IDS.put(10797, "Atrust Computer Corp."); - IDS.put(10798, "VIA Alliance Semiconductor Co., Ltd."); - IDS.put(10799, "BSUN Electronics Co., Ltd."); - IDS.put(1080, "Advanced Micro Devices"); - IDS.put(10807, "RTD Embedded Technologies, Inc."); - IDS.put(10816, "Shenzhen Choseal Industrial Co., Ltd."); - IDS.put(10817, "Canyon Semiconductor"); - IDS.put(10818, "Spectra7 Microsystems Corp."); - IDS.put(10821, "Meizu Technology Co., Ltd."); - IDS.put(10822, "Hubei Yingtong Telecommunication Cable Inc."); - IDS.put(10829, "Wilder Technologies"); - IDS.put(10837, "Diodes Inc."); - IDS.put(10846, "DuPont"); - IDS.put(1085, "Lexmark International Inc."); - IDS.put(10852, "Zhejiang Songcheng Electronics Co., Ltd."); - IDS.put(10859, "VSN Mobil"); - IDS.put(10875, "Bellwether Electronic Corp."); - IDS.put(10878, "VAIO Corporation"); - IDS.put(10879, "Perixx Computer GmbH"); - IDS.put(10885, "HANK ELECTRONICS CO., LTD"); - IDS.put(10892, "Sonnet Technologies, Inc."); - IDS.put(10893, "Keysight Technologies Inc."); - IDS.put(10895, "Manutronics Vietnam Joint Stock Company"); - IDS.put(10900, "G2 Touch Co., Ltd."); - IDS.put(10902, "Micromax Informatics Ltd"); - IDS.put(10910, "SEIKO SOLUTIONS Inc."); - IDS.put(10912, "Casco Products Corp."); - IDS.put(10922, "Virtium Technology, Inc."); - IDS.put(10923, "Field and Company LLC, dba Leef USA"); - IDS.put(10928, "GM Global Technology Operations LLC"); - IDS.put(10931, "Key Asic Inc."); - IDS.put(10943, "Revolabs, Inc."); - IDS.put(10945, "Lattice Semiconductor Corp"); - IDS.put(10947, "Foshan Nanhai Saga Audio Equipment Co., Ltd."); - IDS.put(10957, "Silergy Corp."); - IDS.put(10963, "Shenzhen Hali-Power Industrial Co., Ltd."); - IDS.put(10971, "I-PEX (Dai-ichi Seiko)"); - IDS.put(10973, "SEE-PLUS INDUSTRIAL LTD."); - IDS.put(10990, "Adapt-IP Company"); - IDS.put(10997, "Libratone A/S"); - IDS.put(10999, "Shenzhen Hazens Automotive Electronics (SZ) Co., Ltd."); - IDS.put(11000, "Jiangsu Toppower Automotive Electronics Co., Ltd."); - IDS.put(11001, "Drapho Electronics Technology Co., Ltd."); - IDS.put(1102, "Alps Electric Co., Ltd."); - IDS.put(11022, "Le Shi Zhi Xin Electronic Technology (Tian Jin) Limited"); - IDS.put(11024, "Cardiac Insight, Inc."); - IDS.put(11028, "EverPro Technologies Company, Ltd."); - IDS.put(11029, "Rosenberger Hochfrequenztechnik"); - IDS.put(11035, "Dongguan City Sanji Electronics Co., Ltd."); - IDS.put(11037, "Lintes Technology Co., Ltd."); - IDS.put(11039, "KinnexA, Inc."); - IDS.put(11042, "Metra Electronics Corp."); - IDS.put(11044, "KeepKey, LLC"); - IDS.put(11047, "FluxData Incorporated"); - IDS.put(1105, "Texas Instruments"); - IDS.put(11061, "Assem Technology Co., Ltd."); - IDS.put(11062, "Dongguan City Jianghan Electronics Co., Ltd."); - IDS.put(11063, "Huizhou Desay SV Automotive Co., Ltd."); - IDS.put(11064, "Ningbo Rixing Electronics Co., Ltd."); - IDS.put(11069, "GuangDong YuanFeng Automotive Electroics Co., Ltd."); - IDS.put(11080, "Sounding Audio Industrial Limited"); - IDS.put(11082, "Yueqing Huaxin Electronic Co., Ltd."); - IDS.put(11098, "Universal Audio, Inc."); - IDS.put(11111, "Lifesize, Inc."); - IDS.put(11123, "Pioneer DJ Corporation"); - IDS.put(11124, "Embedded Intelligence, Inc."); - IDS.put(11125, "New Matter"); - IDS.put(11126, "Shanghai Wingtech Electronic Technology Co., Ltd."); - IDS.put(11127, "Epiphan Systems Inc."); - IDS.put(11130, "Spin Master Far East Ltd."); - IDS.put(11131, "Gigaset Digital Technology (Shenzhen) Co., Ltd."); - IDS.put(11132, "Noveltek Semiconductor Corp."); - IDS.put(11139, "Silicon Line GmbH"); - IDS.put(11140, "Ever Win International Corp."); - IDS.put(11144, "Socionext Inc."); - IDS.put(11145, "Ugreen Group Limited"); - IDS.put(11146, "Shanghai Pateo Electronic Equipment Mfg. Co., Ltd."); - IDS.put(1115, "Renesas Electronics Corp."); - IDS.put(11154, "i-BLADES, Inc."); - IDS.put(11155, "Altia Systems Inc."); - IDS.put(11156, "ShenZhen Baoyuanda Electronics Co., Ltd."); - IDS.put(11157, "iST - Integrated Service Technology Inc."); - IDS.put(11158, "HYUNDAI MOBIS Co., Ltd."); - IDS.put(11161, "360fly, Inc."); - IDS.put(11162, "HUIZHOU CHENG SHUO HARDWARE PLASTIC CO., LTD."); - IDS.put(11163, "Zhongshan Aute Electronics Technology Co., Ltd."); - IDS.put(11164, "Guangdong King Link Industrial Co., Ltd."); - IDS.put(11167, "Scietera Technologies, Inc."); - IDS.put(11168, "InVue Security Products"); - IDS.put(11169, "I-Sheng Electric Wire & Cable Co., Ltd."); - IDS.put(11170, "China Daheng Group Inc Beijing Image Vision Tech Branch"); - IDS.put(11171, "Shenzhen FeiTianXia Technology Ltd."); - IDS.put(11172, "Shenzhen HengJia New Energy Auto Part Co., Ltd."); - IDS.put(11175, "77 Elektronika Kft."); - IDS.put(11176, "YUDU EASON ELECTRONIC CO., LTD."); - IDS.put(1118, "Microsoft Corporation"); - IDS.put(11181, "XIN JI (SHENZHEN) COMPUTER PARTS CO., LTD."); - IDS.put(11189, "Silk ID Systems"); - IDS.put(11190, "3D Imaging & Simulations Corp. (3DISC)"); - IDS.put(11191, "Dongguan ChengXiang Industrial Co., Ltd."); - IDS.put(11192, "OCC (Zhuhai) Electronic Co., Ltd."); - IDS.put(11194, "Sinseader Electronic Co., Ltd."); - IDS.put(11195, "DONGGUAN YELLOWKNIFE Industrial Co., Ltd."); - IDS.put(11197, "RF Creations Ltd."); - IDS.put(11198, "Chengyi Semiconductors (Shanghai) Co., Ltd."); - IDS.put(11199, "Shenzhen Shinning Electronic Co., Ltd."); - IDS.put(11200, "Shenzhen WFD Electronics Co., Ltd."); - IDS.put(11201, "Dongguan Sino Syncs Industrial Co., Ltd."); - IDS.put(11202, "JNTC Co., Ltd."); - IDS.put(11208, "DONGGUAN POLIXIN ELECTRIC CO., LTD."); - IDS.put(11209, "Tama Electric (Suzhou) Co., Ltd."); - IDS.put(1121, "Primax Electronics"); - IDS.put(11210, "Exvision, Inc."); - IDS.put(11216, "mophie, LLC"); - IDS.put(11219, "Dongguan ULT-unite electronic technology co., LTD"); - IDS.put(11220, "JL Audio, Inc."); - IDS.put(11221, "Cable Matters Inc."); - IDS.put(11222, "CoroWare, Inc."); - IDS.put(11229, "Charm Sciences Inc."); - IDS.put(1123, "EATON"); - IDS.put(11230, "Pickering Interfaces Limited"); - IDS.put(11231, "Hangzhou Hikvision Digital Technology Co., Ltd."); - IDS.put(11232, "FULLINK ELECTRONICS TECHNOLOGY (SZ) LTD"); - IDS.put(11233, "AutoChips Inc."); - IDS.put(11234, "Electric Connector Technology Co., Ltd."); - IDS.put(11237, "LELTEK"); - IDS.put(11238, "Dongguan KaiWin Electronics Co., Ltd."); - IDS.put(11239, "BEFS Co., Ltd."); - IDS.put(11240, "Archisite, Inc."); - IDS.put(11241, "Magneti Marelli S.p.A Electr BL"); - IDS.put(11246, "Ventev Mobile"); - IDS.put(11247, "Quanta Storage Inc."); - IDS.put(11248, "Tech-Top Technology Limited"); - IDS.put(11253, "Shenzhen YOOBAO Technology Co., Ltd."); - IDS.put(11254, "Shenzhen Sinotek Technology Co., Ltd."); - IDS.put(11255, "KEYW"); - IDS.put(11256, "Visual Land Inc."); - IDS.put(11264, "MEEM SL Ltd"); - IDS.put(11265, "Dongguan Arin Electronics Technology Co., Ltd."); - IDS.put(11266, "DongGuan City JianNuo Electronics Co., Ltd."); - IDS.put(11268, "Shenzhen XOX Electronics Co., Ltd."); - IDS.put(11269, "Protop International Inc."); - IDS.put(11270, "Microsemi Semiconductor (US) Inc."); - IDS.put(11271, "Webcloak LLC"); - IDS.put(11272, "INVECAS INC."); - IDS.put(11274, "ATANS Technology Inc."); - IDS.put(11275, "Triple Win Precision Technology Co., Ltd."); - IDS.put(11276, "IC Realtech"); - IDS.put(11277, "Embrava Pty Ltd"); - IDS.put(1128, "Wieson Technologies Co., Ltd."); - IDS.put(11280, "Sinotronics Co., Ltd."); - IDS.put(11281, "ALLBEST ELECTRONICS TECHNOLOGY CO., LTD."); - IDS.put(11282, "Shenzhen Xin Kai Feng Electronics Factory"); - IDS.put(11283, "MOST WELL Technology Corp."); - IDS.put(11284, "Buffalo Memory Co., Ltd."); - IDS.put(11285, "Xentris Wireless"); - IDS.put(11286, "Priferential Accessories Ltd"); - IDS.put(11289, "Sunlike Technology Co., Ltd."); - IDS.put(11290, "Young Fast Optoelectronics Co., Ltd."); - IDS.put(11291, "ISAW Camera Inc"); - IDS.put(11298, "Qanba USA, LLC"); - IDS.put(11299, "Super Micro Computer Inc."); - IDS.put(11302, "Micromax International Corporation"); - IDS.put(11304, "Granite River Labs Japan Ltd."); - IDS.put(11305, "Coagent Enterprise Limited"); - IDS.put(11306, "LEIA Inc."); - IDS.put(11309, "Shenzhen Ebull Technology Limited"); - IDS.put(1131, "American Megatrends"); - IDS.put(11310, "Hualun Technology Co., Ltd."); - IDS.put(11311, "Sensel, Inc."); - IDS.put(11319, "Shenzhen Adition Audio Science & Technology Co., Ltd."); - IDS.put(11320, "Goldenconn Electronics Technology (Suzhou) Co., Ltd."); - IDS.put(11321, "JIB Electronics Technology Co., Ltd."); - IDS.put(11322, "Changzhou Shinco Automotive Electronics Co., Ltd."); - IDS.put(11323, "Shenzhen Hangsheng Electronics Corp., Ltd."); - IDS.put(11324, "Beartooth Radio, Inc."); - IDS.put(11325, "Audience, A Knowles Company"); - IDS.put(11327, "Nextbit Systems, Inc."); - IDS.put(11328, "Leadtrend"); - IDS.put(11329, "Adaptertek Technology Co., Ltd."); - IDS.put(1133, "Logitech Inc."); - IDS.put(11330, "Feature Integration Technology Inc."); - IDS.put(11331, "Avegant Corporation"); - IDS.put(11335, "Chunghsin International Electronics Co., Ltd."); - IDS.put(11336, "Delphi Electrical Centers (Shanghai) Co., Ltd."); - IDS.put(11341, "VVETEK DOO"); - IDS.put(11347, "Huizhou Foryou General Electronics Co., Ltd."); - IDS.put(11348, "LifeWatch Technologies Ltd."); - IDS.put(11349, "Magicleap"); - IDS.put(11355, "Dongguan City Shenglan Electronics Co., LTD."); - IDS.put(11356, "Neusoft Corporation"); - IDS.put(11357, "SIP Simya Electronics Technology Co., Ltd."); - IDS.put(11358, "GNSD Automotive Co., Ltd."); - IDS.put(11359, "YOODS Co., Ltd."); - IDS.put(11360, "Sirin Mobile Technologies AG"); - IDS.put(11361, "Jadmam Corporation dba: Boytone"); - IDS.put(11373, "Gibson Innovations"); - IDS.put(11374, "Shen Zhen Xian Shuo Technology Co. LTD"); - IDS.put(11375, "PST Eletronica LTDA"); - IDS.put(11376, "PERI, Inc."); - IDS.put(11377, "Bozhou BoTong Information Technology Co., Ltd."); - IDS.put(11383, "Profindustry GmbH"); - IDS.put(11384, "BRAGI GmbH"); - IDS.put(11385, "WAWGD, Inc. (DBA: Foresight Sports)"); - IDS.put(11390, "Dongguan Allpass Electronic Co., Ltd."); - IDS.put(11391, "SHENZHEN D-VITEC INDUSTRIAL CO., LTD."); - IDS.put(11392, "motomobile AG"); - IDS.put(11393, "Indie Semiconductor"); - IDS.put(11397, "Audientes"); - IDS.put(11403, "Huizhou Dehong Technology Co., Ltd."); - IDS.put(11404, "PowerCenter Technology Limited"); - IDS.put(11405, "Mizco International, Inc."); - IDS.put(11408, "I. AM. PLUS, LLC"); - IDS.put(11409, "Corigine, Inc."); - IDS.put(11410, "Ningbo Yinzhou Shengke Electronics Co., Ltd."); - IDS.put(11417, "Prusa Research s.r.o."); - IDS.put(11423, "e-Smart Systems Pvt. Ltd."); - IDS.put(11424, "Leagtech Jiangxi Electronic Co., Ltd."); - IDS.put(11425, "Dongguan Yujia Electronics Technology Co., Ltd."); - IDS.put(11426, "GuangZhou MingPing Electronics Technology"); - IDS.put(11427, "DJI Technology Co., Ltd."); - IDS.put(11428, "Shenzhen Alex Technology Co., Ltd."); - IDS.put(11433, "JITS TECHNOLOGY CO., LIMITED"); - IDS.put(11434, "LIVV Brand llc"); - IDS.put(11444, "Ava Enterprises, Inc. dba: Boss Audio Systems"); - IDS.put(11448, "Shenzhen Sydixon Electronic Technology Co., Ltd."); - IDS.put(11449, "On-Bright Electronics (Shanghai) Co., Ltd."); - IDS.put(11450, "Dongguan Puxu Industrial Co., Ltd."); - IDS.put(11451, "Shenzhen Soling Indusrtial Co., Ltd."); - IDS.put(11453, "EGGCYTE, INC."); - IDS.put(11455, "Donggguan Yuhua Electronic Co., Ltd."); - IDS.put(11456, "Hangzhou Zero Zero Technology Co., Ltd."); - IDS.put(11462, "Prodigy Technovations Pvt Ltd"); - IDS.put(11463, "EmergiTech, Inc"); - IDS.put(11464, "Hewlett Packard Enterprise"); - IDS.put(11465, "Monolithic Power Systems Inc."); - IDS.put(11467, "USB Memory Direct"); - IDS.put(11468, "Silicon Mitus Inc."); - IDS.put(11472, "Technics Global Electronics & JCE Co., Ltd."); - IDS.put(11478, "Immersive Media"); - IDS.put(11479, "Cosemi Technologies Inc."); - IDS.put(11481, "Cambrionix Ltd"); - IDS.put(11482, "CXUN Co. Ltd."); - IDS.put(11483, "China Tsp Inc"); - IDS.put(11490, "Yanfeng Visteon (Chongqing) Automotive Electronics Co"); - IDS.put(11491, "Alcorlink Corp."); - IDS.put(11492, "ISBC Ltd."); - IDS.put(11493, "InX8 Inc dba: AKiTiO"); - IDS.put(11494, "SDAN Tecchnology Co., Ltd."); - IDS.put(11495, "Lemobile Information Technology (Beijing) Co., Ltd."); - IDS.put(11496, "GongGuan HWX Electronic Technology Co., Ltd."); - IDS.put(11497, "Suzhu Jingshi Electronic Technology Co., Ltd."); - IDS.put(11498, "Zhong Shan City Richsound Electronic Industrial Ltd."); - IDS.put(11499, "Dongguang Kangbang Electronics Co., Ltd."); - IDS.put(1151, "Plantronics, Inc."); - IDS.put(1154, "Kyocera Corporation"); - IDS.put(1155, "STMicroelectronics"); - IDS.put(1161, "Foxconn / Hon Hai"); - IDS.put(1165, "ITE Tech Inc."); - IDS.put(1177, "Yamaha Corporation"); - IDS.put(1188, "Hitachi, Ltd."); - IDS.put(1191, "Visioneer"); - IDS.put(1193, "Canon Inc."); - IDS.put(1200, "Nikon Corporation"); - IDS.put(1201, "Pan International"); - IDS.put(1204, "Cypress Semiconductor"); - IDS.put(1205, "ROHM Co., Ltd."); - IDS.put(1207, "Compal Electronics, Inc."); - IDS.put(1208, "Seiko Epson Corp."); - IDS.put(1211, "I-O Data Device, Inc."); - IDS.put(1221, "Fujitsu Ltd."); - IDS.put(1227, "FUJIFILM Corporation"); - IDS.put(1238, "Mentor Graphics"); - IDS.put(1240, "Microchip Technology Inc."); - IDS.put(1241, "Holtek Semiconductor, Inc."); - IDS.put(1242, "Panasonic Corporation"); - IDS.put(1245, "Sharp Corporation"); - IDS.put(1250, "Exar Corporation"); - IDS.put(1254, "Identiv, Inc."); - IDS.put(1256, "Samsung Electronics Co., Ltd."); - IDS.put(1260, "Tokyo Electron Device Limited"); - IDS.put(1266, "Chicony Electronics Co., Ltd."); - IDS.put(1271, "Newnex Technology Corp."); - IDS.put(1273, "Brother Industries, Ltd."); - IDS.put(1276, "SUNPLUS TECHNOLOGY CO., LTD."); - IDS.put(1278, "PFU Limited"); - IDS.put(1281, "Fujikura/DDK"); - IDS.put(1282, "Acer, Inc."); - IDS.put(1287, "Hosiden Corporation"); - IDS.put(1293, "Belkin International, Inc."); - IDS.put(1300, "FCI Electronics"); - IDS.put(1302, "Longwell Electronics/Longwell Company"); - IDS.put(1305, "Star Micronics Co., LTD"); - IDS.put(1309, "American Power Conversion"); - IDS.put(1314, "ACON, Advanced-Connectek, Inc."); - IDS.put(1343, "Synopsys, Inc."); - IDS.put(1356, "Sony Corporation"); - IDS.put(1360, "Fuji Xerox Co., Ltd."); - IDS.put(1367, "ATEN International Co. Ltd."); - IDS.put(1369, "Cadence Design Systems, Inc."); - IDS.put(1386, "WACOM Co., Ltd."); - IDS.put(1389, "EIZO Corporation"); - IDS.put(1390, "Elecom Co., Ltd."); - IDS.put(1394, "Conexant Systems, Inc."); - IDS.put(1398, "BAFO/Quality Computer Accessories"); - IDS.put(1403, "Y-E Data, Inc."); - IDS.put(1404, "AVM GmbH"); - IDS.put(1410, "Roland Corporation"); - IDS.put(1412, "RATOC Systems, Inc."); - IDS.put(1419, "Infineon Technologies"); - IDS.put(1423, "Alcor Micro, Corp."); - IDS.put(1424, "OMRON Corporation"); - IDS.put(1447, "Bose Corporation"); - IDS.put(1449, "OmniVision Technologies, Inc."); - IDS.put(1452, "Apple"); - IDS.put(1453, "Y.C. Cable U.S.A., Inc"); - IDS.put(14627, "National Instruments"); - IDS.put(1470, "Tyco Electronics Corp., a TE Connectivity Ltd. company"); - IDS.put(1473, "MegaChips Corporation"); - IDS.put(1478, "Qualcomm, Inc"); - IDS.put(1480, "Foxlink/Cheng Uei Precision Industry Co., Ltd."); - IDS.put(1482, "Ricoh Company Ltd."); - IDS.put(1498, "Microtek International Inc."); - IDS.put(1504, "Symbol Technologies"); - IDS.put(1507, "Genesys Logic, Inc."); - IDS.put(1509, "Fuji Electric Co., Ltd."); - IDS.put(1525, "Unixtar Technology Inc."); - IDS.put(1529, "Datalogic ADC"); - IDS.put(1535, "LeCroy Corporation"); - IDS.put(1539, "Novatek Microelectronics Corp."); - IDS.put(1545, "SMK Manufacturing Inc."); - IDS.put(1551, "Joinsoon Electronics Mfg. Co., Ltd."); - IDS.put(1555, "TransAct Technologies Incorporated"); - IDS.put(1561, "Seiko Instruments Inc."); - IDS.put(1582, "JPC/MAIN SUPER Inc."); - IDS.put(1583, "Sin Sheng Terminal & Machine Inc."); - IDS.put(1593, "Chrontel, Inc."); - IDS.put(1611, "Analog Devices, Inc. Development Tools"); - IDS.put(1612, "Ji-Haw Industrial Co., Ltd"); - IDS.put(1614, "Suyin Corporation"); - IDS.put(1621, "Space Shuttle Hi-Tech Co.,Ltd."); - IDS.put(1622, "Glory Mark Electronic Ltd."); - IDS.put(1623, "Tekcon Electronics Corp."); - IDS.put(1624, "Sigma Designs, Inc."); - IDS.put(1631, "Good Way Technology Co., Ltd. & GWC technology Inc"); - IDS.put(1632, "TSAY-E (BVI) International Inc."); - IDS.put(1633, "Hamamatsu Photonics K.K."); - IDS.put(1642, "Total Technologies, Ltd."); - IDS.put(1659, "Prolific Technology, Inc."); - IDS.put(16700, "Dell Inc."); - IDS.put(1680, "Golden Bridge Electech Inc."); - IDS.put(1689, "Tektronix, Inc."); - IDS.put(1690, "Askey Computer Corporation"); - IDS.put(1709, "Greatland Electronics Taiwan Ltd."); - IDS.put(1710, "Eurofins Digital Testing Belgium"); - IDS.put(1720, "Pixela Corporation"); - IDS.put(1724, "Oki Data Corporation"); - IDS.put(1727, "Leoco Corporation"); - IDS.put(1732, "Bizlink Technology, Inc."); - IDS.put(1736, "SIIG, Inc."); - IDS.put(1747, "Mitsubishi Electric Corporation"); - IDS.put(1758, "Heisei Technology Co., Ltd."); - IDS.put(1802, "Oki Electric Industry Co., Ltd."); - IDS.put(1805, "Comoss Electronic Co., Ltd."); - IDS.put(1809, "Magic Control Technology Corp."); - IDS.put(1816, "Imation Corp."); - IDS.put(1838, "Sunix Co., Ltd."); - IDS.put(1846, "Lorom Industrial Co., Ltd."); - IDS.put(1848, "Mad Catz, Inc."); - IDS.put(1899, "HID Global GmbH"); - IDS.put(1901, "Denso Corporation"); - IDS.put(1913, "Fairchild Semiconductor"); - IDS.put(1921, "SanDisk Corporation"); - IDS.put(1937, "Copartner Technology Corporation"); - IDS.put(1954, "National Technical Systems"); - IDS.put(1971, "Plustek, Inc."); - IDS.put(1972, "OLYMPUS CORPORATION"); - IDS.put(1975, "TIME Interconnect Ltd."); - IDS.put(1994, "AVerMedia Technologies, Inc."); - IDS.put(1999, "Casio Computer Co., Ltd."); - IDS.put(2015, "David Electronics Company, Ltd."); - IDS.put(2039, "Century Corporation"); - IDS.put(2058, "Evermuch Technology Co., Ltd."); - IDS.put(2101, "Action Star Enterprise Co., Ltd."); - IDS.put(2112, "Argosy Research Inc."); - IDS.put(2122, "Wipro Limited"); - IDS.put(2159, "MEC IMEX INC/HPT"); - IDS.put(2205, "Icron Technologies Corporation"); - IDS.put(2247, "TAI TWUN ENTERPRISE CO., LTD."); - IDS.put(2276, "Pioneer Corporation"); - IDS.put(2278, "Gemalto SA"); - IDS.put(2310, "FARADAY Technology Corp."); - IDS.put(2313, "Audio-Technica Corp."); - IDS.put(2316, "Silicon Motion, Inc. - Taiwan"); - IDS.put(2334, "Garmin International"); - IDS.put(2352, "Toshiba Corporation"); - IDS.put(2362, "Pixart Imaging, Inc."); - IDS.put(2363, "Plextor LLC"); - IDS.put(2366, "J.S.T. Mfg. Co., Ltd."); - IDS.put(2385, "Kingston Technology Company"); - IDS.put(2389, "NVIDIA"); - IDS.put(2395, "Medialogic Corporation"); - IDS.put(2397, "Polycom, Inc."); - IDS.put(2468, "Contech Research, Inc."); - IDS.put(2472, "Lin Shiung Enterprise Co., Ltd."); - IDS.put(2475, "Japan Cash Machine Co., Ltd."); - IDS.put(2498, "NISCA Corporation"); - IDS.put(2511, "Electronics Testing Center, Taiwan"); - IDS.put(2522, "A-FOUR TECH CO., LTD."); - IDS.put(2555, "Altera"); - IDS.put(2578, "Cambridge Silicon Radio Ltd."); - IDS.put(2583, "HOYA Corporation"); - IDS.put(2631, "Hirose Electric Co., Ltd."); - IDS.put(2636, "COMPUTEX Co., Ltd."); - IDS.put(2640, "Mimaki Engineering Co., Ltd."); - IDS.put(2652, "Broadcom Corp."); - IDS.put(2667, "Green House Co., Ltd."); - IDS.put(2702, "Japan Aviation Electronics Industry Ltd. (JAE)"); - IDS.put(2727, "Wincor Nixdorf GmbH & Co KG"); - IDS.put(2733, "Rohde & Schwarz GmbH & Co. KG"); - IDS.put(2787, "Allion Labs, Inc."); - IDS.put(2821, "ASUSTek Computer Inc."); - IDS.put(2849, "Yokogawa Electric Corporation"); - IDS.put(2851, "Pan-Asia Electronics Co., Ltd."); - IDS.put(2894, "Musical Electronics Ltd."); - IDS.put(2907, "Anritsu Corporation"); - IDS.put(2922, "Maxim Integrated Products"); - IDS.put(2965, "ASIX Electronics Corporation"); - IDS.put(2967, "O2Micro, Inc."); - IDS.put(3010, "Seagate Technology LLC"); - IDS.put(3034, "Realtek Semiconductor Corp."); - IDS.put(3035, "Ericsson AB"); - IDS.put(3044, "Elka International Ltd."); - IDS.put(3056, "Pace Micro Technology PLC"); - IDS.put(3108, "Taiyo Yuden Co., Ltd."); - IDS.put(3129, "Aeroflex"); - IDS.put(3132, "Radius Co., Ltd."); - IDS.put(3141, "Sonix Technology Co., Ltd."); - IDS.put(3158, "Billion Bright (HK) Corporation Limited"); - IDS.put(3161, "Dong Guan Shinko Wire Co., Ltd."); - IDS.put(3170, "Chant Sincere Co., Ltd"); - IDS.put(3190, "Solid State System Co., Ltd."); - IDS.put(3209, "Honda Tsushin Kogyo Co., Ltd"); - IDS.put(3245, "Motorola Solutions"); - IDS.put(3255, "Singatron Enterprise Co. Ltd."); - IDS.put(3268, "emsys Embedded Systems GmbH"); - IDS.put(32902, "Intel Corporation"); - IDS.put(3294, "Z-Com INC."); - IDS.put(3313, "e-CONN ELECTRONIC CO., LTD."); - IDS.put(3314, "ENE Technology Inc."); - IDS.put(3351, "NALTEC, Inc."); - IDS.put(3402, "NF Corporation"); - IDS.put(3403, "Grape Systems Inc."); - IDS.put(3409, "Volex (Asia) Pte Ltd"); - IDS.put(3425, "MEILU ELECTRONICS (SHENZHEN) CO., LTD."); - IDS.put(3441, "Hirakawa Hewtech Corp."); - IDS.put(3452, "Taiwan Line Tek Electronic Co., Ltd."); - IDS.put(3463, "Dolby Laboratories Inc."); - IDS.put(3468, "C-MEDIA ELECTRONICS INC."); - IDS.put(3472, "Sure-Fire Electrical Corporation"); - IDS.put(3495, "IOGEAR, Inc."); - IDS.put(3504, "Micro-Star International Co., Ltd."); - IDS.put(3537, "Contek Electronics Co., Ltd."); - IDS.put(3540, "Custom Engineering SPA"); - IDS.put(3641, "Smart Modular Technologies, Inc."); - IDS.put(3658, "Shenzhen Bao Hing Electric Wire & Cable Mfr. Co."); - IDS.put(3673, "Bourns, Inc."); - IDS.put(3690, "Megawin Technology Co., Ltd."); - IDS.put(3698, "Hsi-Chin Electronics Co., Ltd."); - IDS.put(3714, "Ching Tai Electric Wire & Cable Co., Ltd."); - IDS.put(3724, "Well Force Electronic Co., Ltd"); - IDS.put(3725, "MediaTek Inc."); - IDS.put(3728, "CRU"); - IDS.put(3744, "Ours Technology Inc."); - IDS.put(3762, "Y-S ELECTRONIC CO., LTD."); - IDS.put(3778, "Sweetray Industrial Ltd."); - IDS.put(3779, "Axell Corporation"); - IDS.put(3782, "InnoVISION Multimedia Limited"); - IDS.put(3790, "TaiSol Electronics Co., Ltd."); - IDS.put(3812, "Sunrich Technology (H.K.) Ltd."); - IDS.put(3868, "Funai Electric Co., Ltd."); - IDS.put(3873, "IOI Technology Corporation"); - IDS.put(3890, "YFC-BonEagle Electric Co., Ltd."); - IDS.put(3896, "Nien-Yi Industrial Corp."); - IDS.put(3916, "WORLDWIDE CABLE OPTO CORP."); - IDS.put(3923, "Taiyo Cable (Dongguan) Co. Ltd."); - IDS.put(3924, "Kawai Musical Instruments Mfg. Co., Ltd."); - IDS.put(3936, "GuangZhou Chief Tech Electronic Technology Co. Ltd."); - IDS.put(3944, "UQUEST, LTD."); - IDS.put(3991, "CviLux Corporation"); - IDS.put(4003, "Chief Land Electronic Co., Ltd."); - IDS.put(4046, "Sony Mobile Communications"); - IDS.put(4087, "CHI SHING COMPUTER ACCESSORIES CO., LTD."); - IDS.put(4096, "Speed Tech Corp."); - IDS.put(4100, "LG Electronics Inc."); - IDS.put(4101, "Apacer Technology Inc."); - IDS.put(4134, "Newly Corporation"); - IDS.put(4168, "Targus Group International"); - IDS.put(4172, "AMCO TEC International Inc."); - IDS.put(4183, "ON Semiconductor"); - IDS.put(4184, "Western Digital Technologies, Inc."); - IDS.put(4227, "CANON ELECTRONICS INC."); - IDS.put(4235, "Grand-tek Technology Co., Ltd."); - IDS.put(4236, "Robert Bosch GmbH"); - IDS.put(4238, "Lotes Co., Ltd."); - IDS.put(4266, "Cables To Go"); - IDS.put(4267, "Universal Global Scientific Industrial Co., Ltd."); - IDS.put(4292, "Silicon Laboratories, Inc."); - IDS.put(4301, "Kycon Inc."); - IDS.put(4362, "Moxa Inc."); - IDS.put(4370, "Golden Bright (Sichuan) Electronic Technology Co Ltd"); - IDS.put(4382, "VSO ELECTRONICS CO., LTD."); - IDS.put(4398, "Master Hill Electric Wire and Cable Co., Ltd."); - IDS.put(4477, "Santa Electronic Inc."); - IDS.put(4505, "Sierra Wireless Inc."); - IDS.put(4522, "GlobalMedia Group, LLC"); - IDS.put(4528, "ATECH FLASH TECHNOLOGY"); - IDS.put(4643, "SKYCABLE ENTERPRISE CO., LTD."); - IDS.put(4703, "ADATA Technology Co., Ltd."); - IDS.put(4716, "Aristocrat Technologies"); - IDS.put(4717, "Bel Stewart"); - IDS.put(4742, "MARVELL SEMICONDUCTOR, INC."); - IDS.put(4756, "RISO KAGAKU CORP."); - IDS.put(4792, "Zhejiang Xinya Electronic Technology Co., Ltd."); - IDS.put(4817, "Huawei Technologies Co., Ltd."); - IDS.put(4823, "Better Holdings (HK) Limited"); - IDS.put(4907, "Konica Minolta, Inc."); - IDS.put(4925, "Jasco Products Company"); - IDS.put(4989, "Pericom Semiconductor Corp."); - IDS.put(5008, "TomTom International B.V."); - IDS.put(5075, "AzureWave Technologies, Inc."); - IDS.put(5117, "Initio Corporation"); - IDS.put(5118, "Phison Electronics Corp."); - IDS.put(5134, "Telechips, Inc."); - IDS.put(5145, "ABILITY ENTERPRISE CO., LTD."); - IDS.put(5148, "Leviton Manufacturing"); - IDS.put(5271, "Panstrong Company Ltd."); - IDS.put(5293, "CTK Corporation"); - IDS.put(5296, "StarTech.com Ltd."); - IDS.put(5376, "Ellisys"); - IDS.put(5404, "VeriSilicon Holdings Co., Ltd."); - IDS.put(5421, "JMicron Technology Corp."); - IDS.put(5422, "HLDS (Hitachi-LG Data Storage, Inc.)"); - IDS.put(5440, "Phihong Technology Co., Ltd."); - IDS.put(5451, "PNY Technologies Inc."); - IDS.put(5453, "Rapid Conn, Connect County Holdings Bhd"); - IDS.put(5454, "D & M Holdings, Inc."); - IDS.put(5480, "Sunf Pu Technology Co., Ltd"); - IDS.put(5488, "ALLTOP TECHNOLOGY CO., LTD."); - IDS.put(5510, "Palconn Technology Co., Ltd."); - IDS.put(5528, "Kunshan Guoji Electronics Co., Ltd."); - IDS.put(5546, "DongGuan Ya Lian Electronics Co., Ltd."); - IDS.put(5645, "Samtec"); - IDS.put(5694, "HongLin Electronics Co., Ltd."); - IDS.put(5753, "Total Phase"); - IDS.put(5766, "ZOOM Corporation"); - IDS.put(5836, "silex technology, Inc."); - IDS.put(5946, "F. Hoffmann-La Roche AG"); - IDS.put(5960, "MQP Electronics Ltd."); - IDS.put(5964, "ASMedia Technology Inc."); - IDS.put(5998, "UD electronic corp."); - IDS.put(6001, "Shenzhen Alex Connector Co., Ltd."); - IDS.put(6002, "System Level Solutions, Inc."); - IDS.put(6018, "Spreadtrum Hong Kong Limited"); - IDS.put(6024, "ShenZhen Litkconn Technology Co., Ltd."); - IDS.put(6053, "Advanced Connection Technology Inc."); - IDS.put(6095, "Hip Hing Cable & Plug Mfy. Ltd."); - IDS.put(6121, "DisplayLink (UK) Ltd."); - IDS.put(6127, "Lenovo"); - IDS.put(6133, "K.K. Rocky"); - IDS.put(6160, "Wanshih Electronic Co., Ltd."); - IDS.put(6185, "Dongguan YuQiu Electronics Co., Ltd."); - IDS.put(6193, "Gwo Jinn Industries Co., Ltd."); - IDS.put(6297, "Linkiss Co., Ltd."); - IDS.put(6353, "Google Inc."); - IDS.put(6394, "Kuang Ying Computer Equipment Co., Ltd."); - IDS.put(6421, "Nordic Semiconductor ASA"); - IDS.put(6448, "Shenzhen Xianhe Technology Co., Ltd."); - IDS.put(6449, "Ningbo Broad Telecommunication Co., Ltd."); - IDS.put(6470, "Irisguard UK Ltd"); - IDS.put(6473, "Lab126"); - IDS.put(6481, "Hyperstone GmbH"); - IDS.put(6487, "BIOS Corporation"); - IDS.put(6626, "Solomon Systech Limited"); - IDS.put(6639, "Pak Heng Technology (Shenzhen) Co., Ltd."); - IDS.put(6655, "Best Buy China Ltd."); - IDS.put(6666, "USB-IF non-workshop"); - IDS.put(6709, "Artesyn Technologies Inc."); - IDS.put(6720, "TERMINUS TECHNOLOGY INC."); - IDS.put(6766, "Global Unichip Corp."); - IDS.put(6786, "Proconn Technology Co., Ltd."); - IDS.put(6794, "Simula Technology Inc."); - IDS.put(6795, "SGS Taiwan Ltd."); - IDS.put(6830, "Johnson Component & Equipments Co., Ltd."); - IDS.put(6834, "Allied Vision Technologies GmbH"); - IDS.put(6859, "Salcomp Plc"); - IDS.put(6865, "Desan Wire Co., Ltd."); - IDS.put(6944, "MStar Semiconductor, Inc."); - IDS.put(6984, "Plastron Precision Co., Ltd."); - IDS.put(7013, "The Hong Kong Standards and Testing Centre Ltd."); - IDS.put(7048, "ShenMing Electron (Dong Guan) Co., Ltd."); - IDS.put(7086, "Vuzix Corporation"); - IDS.put(7108, "Ford Motor Co."); - IDS.put(7118, "Contac Cable Industrial Limited"); - IDS.put(7119, "Sunplus Innovation Technology Inc."); - IDS.put(7120, "Hangzhou Riyue Electronics Co., Ltd."); - IDS.put(7158, "Orient Semiconductor Electronics, Ltd."); - IDS.put(7207, "SHENZHEN DNS INDUSTRIES CO., LTD."); - IDS.put(7217, "LS Mtron Ltd."); - IDS.put(7229, "NONIN MEDICAL INC."); - IDS.put(7275, "Philips & Lite-ON Digital Solutions Corporation"); - IDS.put(7310, "ASTRON INTERNATIONAL CORP."); - IDS.put(7320, "ALPINE ELECTRONICS, INC."); - IDS.put(7347, "Aces Electronics Co., Ltd."); - IDS.put(7348, "OPEX CORPORATION"); - IDS.put(7390, "Telecommunications Technology Association (TTA)"); - IDS.put(7434, "Visteon Corporation"); - IDS.put(7465, "Horng Tong Enterprise Co., Ltd."); - IDS.put(7501, "Pegatron Corporation"); - IDS.put(7516, "Fresco Logic Inc."); - IDS.put(7529, "Walta Electronic Co., Ltd."); - IDS.put(7543, "Yueqing Changling Electronic Instrument Corp., Ltd."); - IDS.put(7584, "Parade Technologies, Inc."); - IDS.put(7647, "L&T Technology Services"); - IDS.put(7649, "Actions Microelectronics Co., Ltd."); - IDS.put(7666, "China Telecommunication Technology Labs - Terminals"); - IDS.put(7668, "SHEN ZHEN FORMAN PRECISION INDUSTRY CO., LTD."); - IDS.put(7682, "GLOBEMASTER TECHNOLOGIES CO., LTD."); - IDS.put(7696, "Point Grey Research Inc."); - IDS.put(7751, "HUNG TA H.T.ENTERPRISE CO., LTD."); - IDS.put(7758, "Etron Technology, Inc."); - IDS.put(7795, "COMLINK ELECTRONICS CO., LTD."); - IDS.put(7818, "HIBEST Electronic (DongGuan) Co., Ltd."); - IDS.put(7825, "Other World Computing"); - IDS.put(7863, "WIN WIN PRECISION INDUSTRIAL CO., LTD."); - IDS.put(7879, "Gefen Inc."); - IDS.put(7881, "MOSER BAER INDIA LIMITED"); - IDS.put(7898, "AIRTIES WIRELESS NETWORKS"); - IDS.put(7956, "Astoria Networks GmbH"); - IDS.put(7969, "Scosche Industries"); - IDS.put(7976, "Cal-Comp Electronics & Communications"); - IDS.put(7977, "Analogix Semiconductor, Inc."); - IDS.put(7989, "Amphenol ShouhMin Industry (ShenZhen) Co., Ltd"); - IDS.put(7996, "Chang Yang Electronics Company Ltd."); - IDS.put(8073, "Dongguan Goldconn Electronics Co., Ltd."); - IDS.put(8074, "Morning Star Industrial Co., Ltd."); - IDS.put(8117, "Unify Software and Solutions GmbH & Co. KG"); - IDS.put(8137, "NXP Semiconductors"); - IDS.put(8181, "Changzhou Wujin BEST Electronic Cables Co., Ltd."); - IDS.put(8205, "Belkin Electronic (Changzhou) Co., Ltd."); - IDS.put(8220, "Freeport Resources Enterprises Corp."); - IDS.put(8222, "Qingdao Haier Telecom Co., Ltd."); - IDS.put(8284, "Shenzhen Tronixin Electronics Co., Ltd."); - IDS.put(8294, "Unicorn Electronics Components Co., Ltd."); - IDS.put(8334, "Luxshare-ICT"); - IDS.put(8341, "CE LINK LIMITED"); - IDS.put(8342, "Microconn Electronic Co., Ltd."); - IDS.put(8367, "Shenzhen CARVE Electronics Co., Ltd."); - IDS.put(8382, "BURY GmbH & Co. KG"); - IDS.put(8384, "FENGHUA KINGSUN CO., LTD."); - IDS.put(8386, "Sumitomo Electric Ind., Ltd., Optical Comm. R&D Lab"); - IDS.put(8439, "XIMEA s.r.o."); - IDS.put(8457, "VIA Labs, Inc."); - IDS.put(8492, "Shenzhen Linoya Electronic Co., Ltd."); - IDS.put(8494, "Amphenol AssembleTech (Xiamen) Co., Ltd."); - IDS.put(8524, "Y Soft Corporation"); - IDS.put(8550, "JVC KENWOOD Corporation"); - IDS.put(8564, "Transcend Information, Inc."); - IDS.put(8566, "TMC/Allion Test Labs"); - IDS.put(8613, "Genesis Technology USA, Inc."); - IDS.put(8627, "Dongguan Teconn Electronics Technology Co., Ltd."); - IDS.put(8644, "Netcom Technology (HK) Limited"); - IDS.put(8659, "Compupack Technology Co., Ltd."); - IDS.put(8667, "G-Max Technology Co., Ltd."); - IDS.put(8679, "Sagemcom Broadband SAS"); - IDS.put(8695, "Wuerth-Elektronik eiSos GmbH & Co. KG"); - IDS.put(8707, "Shin Shin Co., Ltd."); - IDS.put(8709, "3eYamaichi Electronics Co., Ltd."); - IDS.put(8710, "Wiretek International Investment Ltd."); - IDS.put(8711, "Fuzhou Rockchip Electronics Co., Ltd."); - IDS.put(8752, "Plugable Technologies"); - IDS.put(8756, "T-CONN PRECISION CORPORATION"); - IDS.put(8831, "Granite River Labs"); - IDS.put(8842, "Hotron Precision Electronic Ind. Corp."); - IDS.put(8875, "Trigence Semiconductor, Inc."); - IDS.put(8888, "Motorola Mobility Inc."); - IDS.put(8904, "Karming Electronic (Shenzhen) Co., Ltd."); - IDS.put(8981, "Avery Design Systems, Inc."); - IDS.put(8993, "iKingdom Corp. (d.b.a. iConnectivity)"); - IDS.put(9051, "KangXiang Electronic Co., Ltd."); - IDS.put(9068, "ZheJiang Chunsheng Electronics Co., Ltd."); - IDS.put(9130, "DOK (HK) Trading Limited"); - IDS.put(9132, "Marunix Electron Limited"); - IDS.put(9165, "Avconn Precise Connector Co., Ltd."); - IDS.put(9184, "BitifEye Digital Test Solutions GmbH"); - IDS.put(9205, "Speed Conn Co., Ltd."); - IDS.put(9222, "INSIDE Secure"); - IDS.put(9292, "Minebea Co., Ltd."); - IDS.put(9299, "BAANTO"); - IDS.put(9338, "Suzhou Jutze Technologies Co., Ltd"); - IDS.put(9355, "DONGGUAN SYNCONN PRECISION INDUSTRY CO. LTD."); - IDS.put(9382, "Shenzhen Pangngai Industrial Co., Ltd."); - IDS.put(9422, "Shenzhen Deren Electronic Co., Ltd."); - IDS.put(9424, "Smith Micro Software, Inc."); - IDS.put(9453, "ZEN FACTORY GROUP (ASIA) LTD."); - IDS.put(9481, "Chain-In Electronic Co., Ltd."); - IDS.put(9514, "SUZHOU KELI TECHNOLOGY DEVELOPMENT CO., LTD."); - IDS.put(9515, "TOP Exactitude Industry (ShenZhen) Co., Ltd."); - IDS.put(9525, "ShenZhen Hogend Precision Technology Co., Ltd."); - IDS.put(9527, "Norel Systems Ltd."); - IDS.put(9556, "ASSA ABLOY AB"); - IDS.put(9575, "DongGuan LongTao Electronic Co., Ltd."); - IDS.put(9577, "DongGuan City MingJi Electronics Co., Ltd."); - IDS.put(9589, "Weida Hi-Tech Co., Ltd."); - IDS.put(9593, "Dongguan Wisechamp Electronic Co., Ltd."); - IDS.put(9613, "Sequans Communications"); - IDS.put(9636, "ALGOLTEK, INC."); - IDS.put(9651, "DongGuan Elinke Industrial Co., Ltd."); - IDS.put(9679, "Corning Optical Communications LLC"); - IDS.put(9714, "Dongguan Jinyue Electronics Co., Ltd."); - IDS.put(9723, "RICOH IMAGING COMPANY, LTD."); - IDS.put(9742, "DongGuan HYX Industrial Co., Ltd."); - IDS.put(9753, "Advanced Silicon SA"); - IDS.put(9756, "EISST Limited"); - IDS.put(9771, "YTOP Electronics Technical (Kunshan) Co., Ltd."); - IDS.put(9841, "Innovative Logic"); - IDS.put(9842, "GoPro"); - IDS.put(9846, "Basler AG"); - IDS.put(9851, "Palpilot International Corp."); - IDS.put(9896, "UNIREX CORPORATION"); - IDS.put(9917, "Integral Memory Plc."); - IDS.put(9973, "Morning Star Digital Connector Co., Ltd."); - IDS.put(9984, "MITACHI CO., LTD."); - IDS.put(9999, "HGST, a Western Digital Company"); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java deleted file mode 100644 index 15a4180b75..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/UVCCamera.java +++ /dev/null @@ -1,1238 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb; - -import android.graphics.SurfaceTexture; -import android.hardware.usb.UsbDevice; -import android.text.TextUtils; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; - -import com.serenegiant.usb.USBMonitor.UsbControlBlock; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -public class UVCCamera { - private static final boolean DEBUG = false; // TODO set false when releasing - private static final String TAG = UVCCamera.class.getSimpleName(); - private static final String DEFAULT_USBFS = "/dev/bus/usb"; - - public static final int DEFAULT_PREVIEW_WIDTH = 640; - public static final int DEFAULT_PREVIEW_HEIGHT = 480; - public static final int DEFAULT_PREVIEW_MODE = 0; - public static final int DEFAULT_PREVIEW_MIN_FPS = 1; - public static final int DEFAULT_PREVIEW_MAX_FPS = 31; - public static final float DEFAULT_BANDWIDTH = 1.0f; - - public static final int FRAME_FORMAT_YUYV = 0; - public static final int FRAME_FORMAT_MJPEG = 1; - - public static final int PIXEL_FORMAT_RAW = 0; - public static final int PIXEL_FORMAT_YUV = 1; - public static final int PIXEL_FORMAT_RGB565 = 2; - public static final int PIXEL_FORMAT_RGBX = 3; - public static final int PIXEL_FORMAT_YUV420SP = 4; // NV12 - public static final int PIXEL_FORMAT_NV21 = 5; // = YVU420SemiPlanar,NV21,但是保存到jpg颜色失真 - - //-------------------------------------------------------------------------------- - public static final int CTRL_SCANNING = 0x00000001; // D0: Scanning Mode - public static final int CTRL_AE = 0x00000002; // D1: Auto-Exposure Mode - public static final int CTRL_AE_PRIORITY = 0x00000004; // D2: Auto-Exposure Priority - public static final int CTRL_AE_ABS = 0x00000008; // D3: Exposure Time (Absolute) - public static final int CTRL_AR_REL = 0x00000010; // D4: Exposure Time (Relative) - public static final int CTRL_FOCUS_ABS = 0x00000020; // D5: Focus (Absolute) - public static final int CTRL_FOCUS_REL = 0x00000040; // D6: Focus (Relative) - public static final int CTRL_IRIS_ABS = 0x00000080; // D7: Iris (Absolute) - public static final int CTRL_IRIS_REL = 0x00000100; // D8: Iris (Relative) - public static final int CTRL_ZOOM_ABS = 0x00000200; // D9: Zoom (Absolute) - public static final int CTRL_ZOOM_REL = 0x00000400; // D10: Zoom (Relative) - public static final int CTRL_PANTILT_ABS = 0x00000800; // D11: PanTilt (Absolute) - public static final int CTRL_PANTILT_REL = 0x00001000; // D12: PanTilt (Relative) - public static final int CTRL_ROLL_ABS = 0x00002000; // D13: Roll (Absolute) - public static final int CTRL_ROLL_REL = 0x00004000; // D14: Roll (Relative) - public static final int CTRL_FOCUS_AUTO = 0x00020000; // D17: Focus, Auto - public static final int CTRL_PRIVACY = 0x00040000; // D18: Privacy - public static final int CTRL_FOCUS_SIMPLE = 0x00080000; // D19: Focus, Simple - public static final int CTRL_WINDOW = 0x00100000; // D20: Window - - public static final int PU_BRIGHTNESS = 0x80000001; // D0: Brightness - public static final int PU_CONTRAST = 0x80000002; // D1: Contrast - public static final int PU_HUE = 0x80000004; // D2: Hue - public static final int PU_SATURATION = 0x80000008; // D3: Saturation - public static final int PU_SHARPNESS = 0x80000010; // D4: Sharpness - public static final int PU_GAMMA = 0x80000020; // D5: Gamma - public static final int PU_WB_TEMP = 0x80000040; // D6: White Balance Temperature - public static final int PU_WB_COMPO = 0x80000080; // D7: White Balance Component - public static final int PU_BACKLIGHT = 0x80000100; // D8: Backlight Compensation - public static final int PU_GAIN = 0x80000200; // D9: Gain - public static final int PU_POWER_LF = 0x80000400; // D10: Power Line Frequency - public static final int PU_HUE_AUTO = 0x80000800; // D11: Hue, Auto - public static final int PU_WB_TEMP_AUTO = 0x80001000; // D12: White Balance Temperature, Auto - public static final int PU_WB_COMPO_AUTO = 0x80002000; // D13: White Balance Component, Auto - public static final int PU_DIGITAL_MULT = 0x80004000; // D14: Digital Multiplier - public static final int PU_DIGITAL_LIMIT = 0x80008000; // D15: Digital Multiplier Limit - public static final int PU_AVIDEO_STD = 0x80010000; // D16: Analog Video Standard - public static final int PU_AVIDEO_LOCK = 0x80020000; // D17: Analog Video Lock Status - public static final int PU_CONTRAST_AUTO = 0x80040000; // D18: Contrast, Auto - - // uvc_status_class from libuvc.h - public static final int STATUS_CLASS_CONTROL = 0x10; - public static final int STATUS_CLASS_CONTROL_CAMERA = 0x11; - public static final int STATUS_CLASS_CONTROL_PROCESSING = 0x12; - - // uvc_status_attribute from libuvc.h - public static final int STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00; - public static final int STATUS_ATTRIBUTE_INFO_CHANGE = 0x01; - public static final int STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02; - public static final int STATUS_ATTRIBUTE_UNKNOWN = 0xff; - - private static boolean isLoaded; - static { - if (!isLoaded) { - System.loadLibrary("jpeg-turbo1500"); - System.loadLibrary("usb100"); - System.loadLibrary("uvc"); - System.loadLibrary("UVCCamera"); - isLoaded = true; - } - } - - private UsbControlBlock mCtrlBlock; - protected long mControlSupports; // カメラコントロールでサポートしている機能フラグ - protected long mProcSupports; // プロセッシングユニットでサポートしている機能フラグ - protected int mCurrentFrameFormat = FRAME_FORMAT_MJPEG; - protected int mCurrentWidth = DEFAULT_PREVIEW_WIDTH, mCurrentHeight = DEFAULT_PREVIEW_HEIGHT; - protected float mCurrentBandwidthFactor = DEFAULT_BANDWIDTH; - protected String mSupportedSize; - protected List mCurrentSizeList; - // these fields from here are accessed from native code and do not change name and remove - protected long mNativePtr; - protected int mScanningModeMin, mScanningModeMax, mScanningModeDef; - protected int mExposureModeMin, mExposureModeMax, mExposureModeDef; - protected int mExposurePriorityMin, mExposurePriorityMax, mExposurePriorityDef; - protected int mExposureMin, mExposureMax, mExposureDef; - protected int mAutoFocusMin, mAutoFocusMax, mAutoFocusDef; - protected int mFocusMin, mFocusMax, mFocusDef; - protected int mFocusRelMin, mFocusRelMax, mFocusRelDef; - protected int mFocusSimpleMin, mFocusSimpleMax, mFocusSimpleDef; - protected int mIrisMin, mIrisMax, mIrisDef; - protected int mIrisRelMin, mIrisRelMax, mIrisRelDef; - protected int mPanMin, mPanMax, mPanDef; - protected int mTiltMin, mTiltMax, mTiltDef; - protected int mRollMin, mRollMax, mRollDef; - protected int mPanRelMin, mPanRelMax, mPanRelDef; - protected int mTiltRelMin, mTiltRelMax, mTiltRelDef; - protected int mRollRelMin, mRollRelMax, mRollRelDef; - protected int mPrivacyMin, mPrivacyMax, mPrivacyDef; - protected int mAutoWhiteBlanceMin, mAutoWhiteBlanceMax, mAutoWhiteBlanceDef; - protected int mAutoWhiteBlanceCompoMin, mAutoWhiteBlanceCompoMax, mAutoWhiteBlanceCompoDef; - protected int mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef; - protected int mWhiteBlanceCompoMin, mWhiteBlanceCompoMax, mWhiteBlanceCompoDef; - protected int mWhiteBlanceRelMin, mWhiteBlanceRelMax, mWhiteBlanceRelDef; - protected int mBacklightCompMin, mBacklightCompMax, mBacklightCompDef; - protected int mBrightnessMin, mBrightnessMax, mBrightnessDef; - protected int mContrastMin, mContrastMax, mContrastDef; - protected int mSharpnessMin, mSharpnessMax, mSharpnessDef; - protected int mGainMin, mGainMax, mGainDef; - protected int mGammaMin, mGammaMax, mGammaDef; - protected int mSaturationMin, mSaturationMax, mSaturationDef; - protected int mHueMin, mHueMax, mHueDef; - protected int mZoomMin, mZoomMax, mZoomDef; - protected int mZoomRelMin, mZoomRelMax, mZoomRelDef; - protected int mPowerlineFrequencyMin, mPowerlineFrequencyMax, mPowerlineFrequencyDef; - protected int mMultiplierMin, mMultiplierMax, mMultiplierDef; - protected int mMultiplierLimitMin, mMultiplierLimitMax, mMultiplierLimitDef; - protected int mAnalogVideoStandardMin, mAnalogVideoStandardMax, mAnalogVideoStandardDef; - protected int mAnalogVideoLockStateMin, mAnalogVideoLockStateMax, mAnalogVideoLockStateDef; - // until here - /** - * the sonctructor of this class should be call within the thread that has a looper - * (UI thread or a thread that called Looper.prepare) - */ - public UVCCamera() { - mNativePtr = nativeCreate(); - mSupportedSize = null; - } - - /** - * connect to a UVC camera - * USB permission is necessary before this method is called - * @param ctrlBlock - */ - public synchronized void open(final UsbControlBlock ctrlBlock) { - int result = -2; - StringBuilder sb = new StringBuilder(); - try { - mCtrlBlock = ctrlBlock.clone(); - result = nativeConnect(mNativePtr, - mCtrlBlock.getVenderId(), mCtrlBlock.getProductId(), - mCtrlBlock.getFileDescriptor(), - mCtrlBlock.getBusNum(), - mCtrlBlock.getDevNum(), - getUSBFSName(mCtrlBlock)); - sb.append("调用nativeConnect返回值:"+result); -// long id_camera, int venderId, int productId, int fileDescriptor, int busNum, int devAddr, String usbfs - } catch (final Exception e) { - Log.w(TAG, e); - for(int i = 0; i< e.getStackTrace().length; i++){ - sb.append(e.getStackTrace()[i].toString()); - sb.append("\n"); - } - sb.append("core message ->"+e.getLocalizedMessage()); - result = -1; - } - - if (result != 0) { - throw new UnsupportedOperationException("open failed:result=" + result+"----->" + - "id_camera="+mNativePtr+";venderId="+mCtrlBlock.getVenderId() - +";productId="+mCtrlBlock.getProductId()+";fileDescriptor="+mCtrlBlock.getFileDescriptor() - +";busNum="+mCtrlBlock.getBusNum()+";devAddr="+mCtrlBlock.getDevNum() - +";usbfs="+getUSBFSName(mCtrlBlock)+"\n"+"Exception:"+sb.toString()); - } - - if (mNativePtr != 0 && TextUtils.isEmpty(mSupportedSize)) { - mSupportedSize = nativeGetSupportedSize(mNativePtr); - } - nativeSetPreviewSize(mNativePtr, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT, - DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, DEFAULT_PREVIEW_MODE, DEFAULT_BANDWIDTH); - } - - /** - * set status callback - * @param callback - */ - public void setStatusCallback(final IStatusCallback callback) { - if (mNativePtr != 0) { - nativeSetStatusCallback(mNativePtr, callback); - } - } - - /** - * set button callback - * @param callback - */ - public void setButtonCallback(final IButtonCallback callback) { - if (mNativePtr != 0) { - nativeSetButtonCallback(mNativePtr, callback); - } - } - - /** - * close and release UVC camera - */ - public synchronized void close() { - stopPreview(); - if (mNativePtr != 0) { - nativeRelease(mNativePtr); -// mNativePtr = 0; // nativeDestroyを呼ぶのでここでクリアしちゃダメ - } - if (mCtrlBlock != null) { - mCtrlBlock.close(); - mCtrlBlock = null; - } - mControlSupports = mProcSupports = 0; - mCurrentFrameFormat = -1; - mCurrentBandwidthFactor = 0; - mSupportedSize = null; - mCurrentSizeList = null; - if (DEBUG) Log.v(TAG, "close:finished"); - } - - public UsbDevice getDevice() { - return mCtrlBlock != null ? mCtrlBlock.getDevice() : null; - } - - public String getDeviceName(){ - return mCtrlBlock != null ? mCtrlBlock.getDeviceName() : null; - } - - public UsbControlBlock getUsbControlBlock() { - return mCtrlBlock; - } - - public synchronized String getSupportedSize() { - return !TextUtils.isEmpty(mSupportedSize) ? mSupportedSize : (mSupportedSize = nativeGetSupportedSize(mNativePtr)); - } - - public Size getPreviewSize() { - Size result = null; - final List list = getSupportedSizeList(); - for (final Size sz: list) { - if ((sz.width == mCurrentWidth) - || (sz.height == mCurrentHeight)) { - result =sz; - break; - } - } - return result; - } - - /** - * Set preview size and preview mode - * @param width - @param height - */ - public void setPreviewSize(final int width, final int height) { - setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, mCurrentFrameFormat, mCurrentBandwidthFactor); - } - - /** - * Set preview size and preview mode - * @param width - * @param height - * @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1) - */ - public void setPreviewSize(final int width, final int height, final int frameFormat) { - setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, frameFormat, mCurrentBandwidthFactor); - } - - /** - * Set preview size and preview mode - * @param width - @param height - @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1) - @param bandwidth [0.0f,1.0f] - */ - public void setPreviewSize(final int width, final int height, final int frameFormat, final float bandwidth) { - setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, frameFormat, bandwidth); - } - - /** - * Set preview size and preview mode - * @param width - * @param height - * @param min_fps - * @param max_fps - * @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1) - * @param bandwidthFactor - */ - public void setPreviewSize(final int width, final int height, final int min_fps, final int max_fps, final int frameFormat, final float bandwidthFactor) { - if ((width == 0) || (height == 0)) - throw new IllegalArgumentException("invalid preview size"); - if (mNativePtr != 0) { - final int result = nativeSetPreviewSize(mNativePtr, width, height, min_fps, max_fps, frameFormat, bandwidthFactor); - if (result != 0) - throw new IllegalArgumentException("Failed to set preview size"); - mCurrentFrameFormat = frameFormat; - mCurrentWidth = width; - mCurrentHeight = height; - mCurrentBandwidthFactor = bandwidthFactor; - } - } - - public List getSupportedSizeList() { - final int type = (mCurrentFrameFormat > 0) ? 6 : 4; - return getSupportedSize(type, mSupportedSize); - } - - public static List getSupportedSize(final int type, final String supportedSize) { - final List result = new ArrayList(); - if (!TextUtils.isEmpty(supportedSize)) - try { - final JSONObject json = new JSONObject(supportedSize); - final JSONArray formats = json.getJSONArray("formats"); - final int format_nums = formats.length(); - for (int i = 0; i < format_nums; i++) { - final JSONObject format = formats.getJSONObject(i); - if(format.has("type") && format.has("size")) { - final int format_type = format.getInt("type"); - if ((format_type == type) || (type == -1)) { - addSize(format, format_type, 0, result); - } - } - } - } catch (final JSONException e) { - e.printStackTrace(); - } - return result; - } - - private static final void addSize(final JSONObject format, final int formatType, final int frameType, final List size_list) throws JSONException { - final JSONArray size = format.getJSONArray("size"); - final int size_nums = size.length(); - for (int j = 0; j < size_nums; j++) { - final String[] sz = size.getString(j).split("x"); - try { - size_list.add(new Size(formatType, frameType, j, Integer.parseInt(sz[0]), Integer.parseInt(sz[1]))); - } catch (final Exception e) { - break; - } - } - } - - /** - * set preview surface with SurfaceHolder
- * you can use SurfaceHolder came from SurfaceView/GLSurfaceView - * @param holder - */ - public synchronized void setPreviewDisplay(final SurfaceHolder holder) { - nativeSetPreviewDisplay(mNativePtr, holder.getSurface()); - } - - /** - * set preview surface with SurfaceTexture. - * this method require API >= 14 - * @param texture - */ - public synchronized void setPreviewTexture(final SurfaceTexture texture) { // API >= 11 - final Surface surface = new Surface(texture); // XXX API >= 14 - nativeSetPreviewDisplay(mNativePtr, surface); - } - - /** - * set preview surface with Surface - * @param surface - */ - public synchronized void setPreviewDisplay(final Surface surface) { - nativeSetPreviewDisplay(mNativePtr, surface); - } - - /** - * set frame callback - * @param callback - * @param pixelFormat - */ - public void setFrameCallback(final IFrameCallback callback, final int pixelFormat) { - if (mNativePtr != 0) { - nativeSetFrameCallback(mNativePtr, callback, pixelFormat); - } - } - - /** - * start preview - */ - public synchronized void startPreview() { - if (mCtrlBlock != null) { - nativeStartPreview(mNativePtr); - } - } - - /** - * stop preview - */ - public synchronized void stopPreview() { - setFrameCallback(null, 0); - if (mCtrlBlock != null) { - nativeStopPreview(mNativePtr); - } - } - - /** - * destroy UVCCamera object - */ - public synchronized void destroy() { - close(); - if (mNativePtr != 0) { - nativeDestroy(mNativePtr); - mNativePtr = 0; - } - } - - // wrong result may return when you call this just after camera open. - // it is better to wait several hundreads millseconds. - public boolean checkSupportFlag(final long flag) { - updateCameraParams(); - if ((flag & 0x80000000) == 0x80000000) - return ((mProcSupports & flag) == (flag & 0x7ffffffF)); - else - return (mControlSupports & flag) == flag; - } - -//================================================================================ - public synchronized void setAutoFocus(final boolean autoFocus) { - if (mNativePtr != 0) { - nativeSetAutoFocus(mNativePtr, autoFocus); - } - } - - public synchronized boolean getAutoFocus() { - boolean result = true; - if (mNativePtr != 0) { - result = nativeGetAutoFocus(mNativePtr) > 0; - } - return result; - } -//================================================================================ - /** - * @param focus [%] - */ - public synchronized void setFocus(final int focus) { - if (mNativePtr != 0) { - final float range = Math.abs(mFocusMax - mFocusMin); - if (range > 0) - nativeSetFocus(mNativePtr, (int)(focus / 100.f * range) + mFocusMin); - } - } - - /** - * @param focus_abs - * @return focus[%] - */ - public synchronized int getFocus(final int focus_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateFocusLimit(mNativePtr); - final float range = Math.abs(mFocusMax - mFocusMin); - if (range > 0) { - result = (int)((focus_abs - mFocusMin) * 100.f / range); - } - } - return result; - } - - /** - * @return focus[%] - */ - public synchronized int getFocus() { - return getFocus(nativeGetFocus(mNativePtr)); - } - - public synchronized void resetFocus() { - if (mNativePtr != 0) { - nativeSetFocus(mNativePtr, mFocusDef); - } - } - -//================================================================================ - public synchronized void setAutoWhiteBlance(final boolean autoWhiteBlance) { - if (mNativePtr != 0) { - nativeSetAutoWhiteBlance(mNativePtr, autoWhiteBlance); - } - } - - public synchronized boolean getAutoWhiteBlance() { - boolean result = true; - if (mNativePtr != 0) { - result = nativeGetAutoWhiteBlance(mNativePtr) > 0; - } - return result; - } - -//================================================================================ - /** - * @param whiteBlance [%] - */ - public synchronized void setWhiteBlance(final int whiteBlance) { - if (mNativePtr != 0) { - final float range = Math.abs(mWhiteBlanceMax - mWhiteBlanceMin); - if (range > 0) - nativeSetWhiteBlance(mNativePtr, (int)(whiteBlance / 100.f * range) + mWhiteBlanceMin); - } - } - - /** - * @param whiteBlance_abs - * @return whiteBlance[%] - */ - public synchronized int getWhiteBlance(final int whiteBlance_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateWhiteBlanceLimit(mNativePtr); - final float range = Math.abs(mWhiteBlanceMax - mWhiteBlanceMin); - if (range > 0) { - result = (int)((whiteBlance_abs - mWhiteBlanceMin) * 100.f / range); - } - } - return result; - } - - /** - * @return white blance[%] - */ - public synchronized int getWhiteBlance() { - return getFocus(nativeGetWhiteBlance(mNativePtr)); - } - - public synchronized void resetWhiteBlance() { - if (mNativePtr != 0) { - nativeSetWhiteBlance(mNativePtr, mWhiteBlanceDef); - } - } -//================================================================================ - /** - * @param brightness [%] - */ - public synchronized void setBrightness(final int brightness) { - if (mNativePtr != 0) { - final float range = Math.abs(mBrightnessMax - mBrightnessMin); - if (range > 0) - nativeSetBrightness(mNativePtr, (int)(brightness / 100.f * range) + mBrightnessMin); - } - } - - /** - * @param brightness_abs - * @return brightness[%] - */ - public synchronized int getBrightness(final int brightness_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateBrightnessLimit(mNativePtr); - final float range = Math.abs(mBrightnessMax - mBrightnessMin); - if (range > 0) { - result = (int)((brightness_abs - mBrightnessMin) * 100.f / range); - } - } - return result; - } - - /** - * @return brightness[%] - */ - public synchronized int getBrightness() { - return getBrightness(nativeGetBrightness(mNativePtr)); - } - - public synchronized void resetBrightness() { - if (mNativePtr != 0) { - nativeSetBrightness(mNativePtr, mBrightnessDef); - } - } - -//================================================================================ - /** - * @param contrast [%] - */ - public synchronized void setContrast(final int contrast) { - if (mNativePtr != 0) { - nativeUpdateContrastLimit(mNativePtr); - final float range = Math.abs(mContrastMax - mContrastMin); - if (range > 0) - nativeSetContrast(mNativePtr, (int)(contrast / 100.f * range) + mContrastMin); - } - } - - /** - * @param contrast_abs - * @return contrast[%] - */ - public synchronized int getContrast(final int contrast_abs) { - int result = 0; - if (mNativePtr != 0) { - final float range = Math.abs(mContrastMax - mContrastMin); - if (range > 0) { - result = (int)((contrast_abs - mContrastMin) * 100.f / range); - } - } - return result; - } - - /** - * @return contrast[%] - */ - public synchronized int getContrast() { - return getContrast(nativeGetContrast(mNativePtr)); - } - - public synchronized void resetContrast() { - if (mNativePtr != 0) { - nativeSetContrast(mNativePtr, mContrastDef); - } - } - -//================================================================================ - /** - * @param sharpness [%] - */ - public synchronized void setSharpness(final int sharpness) { - if (mNativePtr != 0) { - final float range = Math.abs(mSharpnessMax - mSharpnessMin); - if (range > 0) - nativeSetSharpness(mNativePtr, (int)(sharpness / 100.f * range) + mSharpnessMin); - } - } - - /** - * @param sharpness_abs - * @return sharpness[%] - */ - public synchronized int getSharpness(final int sharpness_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateSharpnessLimit(mNativePtr); - final float range = Math.abs(mSharpnessMax - mSharpnessMin); - if (range > 0) { - result = (int)((sharpness_abs - mSharpnessMin) * 100.f / range); - } - } - return result; - } - - /** - * @return sharpness[%] - */ - public synchronized int getSharpness() { - return getSharpness(nativeGetSharpness(mNativePtr)); - } - - public synchronized void resetSharpness() { - if (mNativePtr != 0) { - nativeSetSharpness(mNativePtr, mSharpnessDef); - } - } -//================================================================================ - /** - * @param gain [%] - */ - public synchronized void setGain(final int gain) { - if (mNativePtr != 0) { - final float range = Math.abs(mGainMax - mGainMin); - if (range > 0) - nativeSetGain(mNativePtr, (int)(gain / 100.f * range) + mGainMin); - } - } - - /** - * @param gain_abs - * @return gain[%] - */ - public synchronized int getGain(final int gain_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateGainLimit(mNativePtr); - final float range = Math.abs(mGainMax - mGainMin); - if (range > 0) { - result = (int)((gain_abs - mGainMin) * 100.f / range); - } - } - return result; - } - - /** - * @return gain[%] - */ - public synchronized int getGain() { - return getGain(nativeGetGain(mNativePtr)); - } - - public synchronized void resetGain() { - if (mNativePtr != 0) { - nativeSetGain(mNativePtr, mGainDef); - } - } - -//================================================================================ - /** - * @param gamma [%] - */ - public synchronized void setGamma(final int gamma) { - if (mNativePtr != 0) { - final float range = Math.abs(mGammaMax - mGammaMin); - if (range > 0) - nativeSetGamma(mNativePtr, (int)(gamma / 100.f * range) + mGammaMin); - } - } - - /** - * @param gamma_abs - * @return gamma[%] - */ - public synchronized int getGamma(final int gamma_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateGammaLimit(mNativePtr); - final float range = Math.abs(mGammaMax - mGammaMin); - if (range > 0) { - result = (int)((gamma_abs - mGammaMin) * 100.f / range); - } - } - return result; - } - - /** - * @return gamma[%] - */ - public synchronized int getGamma() { - return getGamma(nativeGetGamma(mNativePtr)); - } - - public synchronized void resetGamma() { - if (mNativePtr != 0) { - nativeSetGamma(mNativePtr, mGammaDef); - } - } - -//================================================================================ - /** - * @param saturation [%] - */ - public synchronized void setSaturation(final int saturation) { - if (mNativePtr != 0) { - final float range = Math.abs(mSaturationMax - mSaturationMin); - if (range > 0) - nativeSetSaturation(mNativePtr, (int)(saturation / 100.f * range) + mSaturationMin); - } - } - - /** - * @param saturation_abs - * @return saturation[%] - */ - public synchronized int getSaturation(final int saturation_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateSaturationLimit(mNativePtr); - final float range = Math.abs(mSaturationMax - mSaturationMin); - if (range > 0) { - result = (int)((saturation_abs - mSaturationMin) * 100.f / range); - } - } - return result; - } - - /** - * @return saturation[%] - */ - public synchronized int getSaturation() { - return getSaturation(nativeGetSaturation(mNativePtr)); - } - - public synchronized void resetSaturation() { - if (mNativePtr != 0) { - nativeSetSaturation(mNativePtr, mSaturationDef); - } - } -//================================================================================ - /** - * @param hue [%] - */ - public synchronized void setHue(final int hue) { - if (mNativePtr != 0) { - final float range = Math.abs(mHueMax - mHueMin); - if (range > 0) - nativeSetHue(mNativePtr, (int)(hue / 100.f * range) + mHueMin); - } - } - - /** - * @param hue_abs - * @return hue[%] - */ - public synchronized int getHue(final int hue_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateHueLimit(mNativePtr); - final float range = Math.abs(mHueMax - mHueMin); - if (range > 0) { - result = (int)((hue_abs - mHueMin) * 100.f / range); - } - } - return result; - } - - /** - * @return hue[%] - */ - public synchronized int getHue() { - return getHue(nativeGetHue(mNativePtr)); - } - - public synchronized void resetHue() { - if (mNativePtr != 0) { - nativeSetHue(mNativePtr, mSaturationDef); - } - } - -//================================================================================ - public void setPowerlineFrequency(final int frequency) { - if (mNativePtr != 0) - nativeSetPowerlineFrequency(mNativePtr, frequency); - } - - public int getPowerlineFrequency() { - return nativeGetPowerlineFrequency(mNativePtr); - } - -//================================================================================ - /** - * this may not work well with some combination of camera and device - * @param zoom [%] - */ - public synchronized void setZoom(final int zoom) { - if (mNativePtr != 0) { - final float range = Math.abs(mZoomMax - mZoomMin); - if (range > 0) { - final int z = (int)(zoom / 100.f * range) + mZoomMin; -// Log.d(TAG, "setZoom:zoom=" + zoom + " ,value=" + z); - nativeSetZoom(mNativePtr, z); - } - } - } - - /** - * @param zoom_abs - * @return zoom[%] - */ - public synchronized int getZoom(final int zoom_abs) { - int result = 0; - if (mNativePtr != 0) { - nativeUpdateZoomLimit(mNativePtr); - final float range = Math.abs(mZoomMax - mZoomMin); - if (range > 0) { - result = (int)((zoom_abs - mZoomMin) * 100.f / range); - } - } - return result; - } - - /** - * @return zoom[%] - */ - public synchronized int getZoom() { - return getZoom(nativeGetZoom(mNativePtr)); - } - - public synchronized void resetZoom() { - if (mNativePtr != 0) { - nativeSetZoom(mNativePtr, mZoomDef); - } - } - -//================================================================================ - public synchronized void updateCameraParams() { - if (mNativePtr != 0) { - if ((mControlSupports == 0) || (mProcSupports == 0)) { - // サポートしている機能フラグを取得 - if (mControlSupports == 0) - mControlSupports = nativeGetCtrlSupports(mNativePtr); - if (mProcSupports == 0) - mProcSupports = nativeGetProcSupports(mNativePtr); - // 設定値を取得 - if ((mControlSupports != 0) && (mProcSupports != 0)) { - nativeUpdateBrightnessLimit(mNativePtr); - nativeUpdateContrastLimit(mNativePtr); - nativeUpdateSharpnessLimit(mNativePtr); - nativeUpdateGainLimit(mNativePtr); - nativeUpdateGammaLimit(mNativePtr); - nativeUpdateSaturationLimit(mNativePtr); - nativeUpdateHueLimit(mNativePtr); - nativeUpdateZoomLimit(mNativePtr); - nativeUpdateWhiteBlanceLimit(mNativePtr); - nativeUpdateFocusLimit(mNativePtr); - } - if (DEBUG) { - dumpControls(mControlSupports); - dumpProc(mProcSupports); - Log.v(TAG, String.format("Brightness:min=%d,max=%d,def=%d", mBrightnessMin, mBrightnessMax, mBrightnessDef)); - Log.v(TAG, String.format("Contrast:min=%d,max=%d,def=%d", mContrastMin, mContrastMax, mContrastDef)); - Log.v(TAG, String.format("Sharpness:min=%d,max=%d,def=%d", mSharpnessMin, mSharpnessMax, mSharpnessDef)); - Log.v(TAG, String.format("Gain:min=%d,max=%d,def=%d", mGainMin, mGainMax, mGainDef)); - Log.v(TAG, String.format("Gamma:min=%d,max=%d,def=%d", mGammaMin, mGammaMax, mGammaDef)); - Log.v(TAG, String.format("Saturation:min=%d,max=%d,def=%d", mSaturationMin, mSaturationMax, mSaturationDef)); - Log.v(TAG, String.format("Hue:min=%d,max=%d,def=%d", mHueMin, mHueMax, mHueDef)); - Log.v(TAG, String.format("Zoom:min=%d,max=%d,def=%d", mZoomMin, mZoomMax, mZoomDef)); - Log.v(TAG, String.format("WhiteBlance:min=%d,max=%d,def=%d", mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef)); - Log.v(TAG, String.format("Focus:min=%d,max=%d,def=%d", mFocusMin, mFocusMax, mFocusDef)); - } - } - } else { - mControlSupports = mProcSupports = 0; - } - } - - private static final String[] SUPPORTS_CTRL = { - "D0: Scanning Mode", - "D1: Auto-Exposure Mode", - "D2: Auto-Exposure Priority", - "D3: Exposure Time (Absolute)", - "D4: Exposure Time (Relative)", - "D5: Focus (Absolute)", - "D6: Focus (Relative)", - "D7: Iris (Absolute)", - "D8: Iris (Relative)", - "D9: Zoom (Absolute)", - "D10: Zoom (Relative)", - "D11: PanTilt (Absolute)", - "D12: PanTilt (Relative)", - "D13: Roll (Absolute)", - "D14: Roll (Relative)", - "D15: Reserved", - "D16: Reserved", - "D17: Focus, Auto", - "D18: Privacy", - "D19: Focus, Simple", - "D20: Window", - "D21: Region of Interest", - "D22: Reserved, set to zero", - "D23: Reserved, set to zero", - }; - - private static final String[] SUPPORTS_PROC = { - "D0: Brightness", - "D1: Contrast", - "D2: Hue", - "D3: Saturation", - "D4: Sharpness", - "D5: Gamma", - "D6: White Balance Temperature", - "D7: White Balance Component", - "D8: Backlight Compensation", - "D9: Gain", - "D10: Power Line Frequency", - "D11: Hue, Auto", - "D12: White Balance Temperature, Auto", - "D13: White Balance Component, Auto", - "D14: Digital Multiplier", - "D15: Digital Multiplier Limit", - "D16: Analog Video Standard", - "D17: Analog Video Lock Status", - "D18: Contrast, Auto", - "D19: Reserved. Set to zero", - "D20: Reserved. Set to zero", - "D21: Reserved. Set to zero", - "D22: Reserved. Set to zero", - "D23: Reserved. Set to zero", - }; - - private static final void dumpControls(final long controlSupports) { - Log.i(TAG, String.format("controlSupports=%x", controlSupports)); - for (int i = 0; i < SUPPORTS_CTRL.length; i++) { - Log.i(TAG, SUPPORTS_CTRL[i] + ((controlSupports & (0x1 << i)) != 0 ? "=enabled" : "=disabled")); - } - } - - private static final void dumpProc(final long procSupports) { - Log.i(TAG, String.format("procSupports=%x", procSupports)); - for (int i = 0; i < SUPPORTS_PROC.length; i++) { - Log.i(TAG, SUPPORTS_PROC[i] + ((procSupports & (0x1 << i)) != 0 ? "=enabled" : "=disabled")); - } - } - - private final String getUSBFSName(final UsbControlBlock ctrlBlock) { - String result = null; - final String name = ctrlBlock.getDeviceName(); - final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null; - if ((v != null) && (v.length > 2)) { - final StringBuilder sb = new StringBuilder(v[0]); - for (int i = 1; i < v.length - 2; i++) - sb.append("/").append(v[i]); - result = sb.toString(); - } - if (TextUtils.isEmpty(result)) { - Log.w(TAG, "failed to get USBFS path, try to use default path:" + name); - result = DEFAULT_USBFS; - } - return result; - } - - // #nativeCreate and #nativeDestroy are not static methods. - private final native long nativeCreate(); - private final native void nativeDestroy(final long id_camera); - - private final native int nativeConnect(long id_camera, int venderId, int productId, int fileDescriptor, int busNum, int devAddr, String usbfs); - private static final native int nativeRelease(final long id_camera); - - private static final native int nativeSetStatusCallback(final long mNativePtr, final IStatusCallback callback); - private static final native int nativeSetButtonCallback(final long mNativePtr, final IButtonCallback callback); - - private static final native int nativeSetPreviewSize(final long id_camera, final int width, final int height, final int min_fps, final int max_fps, final int mode, final float bandwidth); - private static final native String nativeGetSupportedSize(final long id_camera); - private static final native int nativeStartPreview(final long id_camera); - private static final native int nativeStopPreview(final long id_camera); - private static final native int nativeSetPreviewDisplay(final long id_camera, final Surface surface); - private static final native int nativeSetFrameCallback(final long mNativePtr, final IFrameCallback callback, final int pixelFormat); - -//********************************************************************** - /** - * start movie capturing(this should call while previewing) - * @param surface - */ - public void startCapture(final Surface surface) { - if (mCtrlBlock != null && surface != null) { - nativeSetCaptureDisplay(mNativePtr, surface); - } else - throw new NullPointerException("startCapture"); - } - - /** - * stop movie capturing - */ - public void stopCapture() { - if (mCtrlBlock != null) { - nativeSetCaptureDisplay(mNativePtr, null); - } - } - private static final native int nativeSetCaptureDisplay(final long id_camera, final Surface surface); - - private static final native long nativeGetCtrlSupports(final long id_camera); - private static final native long nativeGetProcSupports(final long id_camera); - - private final native int nativeUpdateScanningModeLimit(final long id_camera); - private static final native int nativeSetScanningMode(final long id_camera, final int scanning_mode); - private static final native int nativeGetScanningMode(final long id_camera); - - private final native int nativeUpdateExposureModeLimit(final long id_camera); - private static final native int nativeSetExposureMode(final long id_camera, final int exposureMode); - private static final native int nativeGetExposureMode(final long id_camera); - - private final native int nativeUpdateExposurePriorityLimit(final long id_camera); - private static final native int nativeSetExposurePriority(final long id_camera, final int priority); - private static final native int nativeGetExposurePriority(final long id_camera); - - private final native int nativeUpdateExposureLimit(final long id_camera); - private static final native int nativeSetExposure(final long id_camera, final int exposure); - private static final native int nativeGetExposure(final long id_camera); - - private final native int nativeUpdateExposureRelLimit(final long id_camera); - private static final native int nativeSetExposureRel(final long id_camera, final int exposure_rel); - private static final native int nativeGetExposureRel(final long id_camera); - - private final native int nativeUpdateAutoFocusLimit(final long id_camera); - private static final native int nativeSetAutoFocus(final long id_camera, final boolean autofocus); - private static final native int nativeGetAutoFocus(final long id_camera); - - private final native int nativeUpdateFocusLimit(final long id_camera); - private static final native int nativeSetFocus(final long id_camera, final int focus); - private static final native int nativeGetFocus(final long id_camera); - - private final native int nativeUpdateFocusRelLimit(final long id_camera); - private static final native int nativeSetFocusRel(final long id_camera, final int focus_rel); - private static final native int nativeGetFocusRel(final long id_camera); - - private final native int nativeUpdateIrisLimit(final long id_camera); - private static final native int nativeSetIris(final long id_camera, final int iris); - private static final native int nativeGetIris(final long id_camera); - - private final native int nativeUpdateIrisRelLimit(final long id_camera); - private static final native int nativeSetIrisRel(final long id_camera, final int iris_rel); - private static final native int nativeGetIrisRel(final long id_camera); - - private final native int nativeUpdatePanLimit(final long id_camera); - private static final native int nativeSetPan(final long id_camera, final int pan); - private static final native int nativeGetPan(final long id_camera); - - private final native int nativeUpdatePanRelLimit(final long id_camera); - private static final native int nativeSetPanRel(final long id_camera, final int pan_rel); - private static final native int nativeGetPanRel(final long id_camera); - - private final native int nativeUpdateTiltLimit(final long id_camera); - private static final native int nativeSetTilt(final long id_camera, final int tilt); - private static final native int nativeGetTilt(final long id_camera); - - private final native int nativeUpdateTiltRelLimit(final long id_camera); - private static final native int nativeSetTiltRel(final long id_camera, final int tilt_rel); - private static final native int nativeGetTiltRel(final long id_camera); - - private final native int nativeUpdateRollLimit(final long id_camera); - private static final native int nativeSetRoll(final long id_camera, final int roll); - private static final native int nativeGetRoll(final long id_camera); - - private final native int nativeUpdateRollRelLimit(final long id_camera); - private static final native int nativeSetRollRel(final long id_camera, final int roll_rel); - private static final native int nativeGetRollRel(final long id_camera); - - private final native int nativeUpdateAutoWhiteBlanceLimit(final long id_camera); - private static final native int nativeSetAutoWhiteBlance(final long id_camera, final boolean autoWhiteBlance); - private static final native int nativeGetAutoWhiteBlance(final long id_camera); - - private final native int nativeUpdateAutoWhiteBlanceCompoLimit(final long id_camera); - private static final native int nativeSetAutoWhiteBlanceCompo(final long id_camera, final boolean autoWhiteBlanceCompo); - private static final native int nativeGetAutoWhiteBlanceCompo(final long id_camera); - - private final native int nativeUpdateWhiteBlanceLimit(final long id_camera); - private static final native int nativeSetWhiteBlance(final long id_camera, final int whiteBlance); - private static final native int nativeGetWhiteBlance(final long id_camera); - - private final native int nativeUpdateWhiteBlanceCompoLimit(final long id_camera); - private static final native int nativeSetWhiteBlanceCompo(final long id_camera, final int whiteBlance_compo); - private static final native int nativeGetWhiteBlanceCompo(final long id_camera); - - private final native int nativeUpdateBacklightCompLimit(final long id_camera); - private static final native int nativeSetBacklightComp(final long id_camera, final int backlight_comp); - private static final native int nativeGetBacklightComp(final long id_camera); - - private final native int nativeUpdateBrightnessLimit(final long id_camera); - private static final native int nativeSetBrightness(final long id_camera, final int brightness); - private static final native int nativeGetBrightness(final long id_camera); - - private final native int nativeUpdateContrastLimit(final long id_camera); - private static final native int nativeSetContrast(final long id_camera, final int contrast); - private static final native int nativeGetContrast(final long id_camera); - - private final native int nativeUpdateAutoContrastLimit(final long id_camera); - private static final native int nativeSetAutoContrast(final long id_camera, final boolean autocontrast); - private static final native int nativeGetAutoContrast(final long id_camera); - - private final native int nativeUpdateSharpnessLimit(final long id_camera); - private static final native int nativeSetSharpness(final long id_camera, final int sharpness); - private static final native int nativeGetSharpness(final long id_camera); - - private final native int nativeUpdateGainLimit(final long id_camera); - private static final native int nativeSetGain(final long id_camera, final int gain); - private static final native int nativeGetGain(final long id_camera); - - private final native int nativeUpdateGammaLimit(final long id_camera); - private static final native int nativeSetGamma(final long id_camera, final int gamma); - private static final native int nativeGetGamma(final long id_camera); - - private final native int nativeUpdateSaturationLimit(final long id_camera); - private static final native int nativeSetSaturation(final long id_camera, final int saturation); - private static final native int nativeGetSaturation(final long id_camera); - - private final native int nativeUpdateHueLimit(final long id_camera); - private static final native int nativeSetHue(final long id_camera, final int hue); - private static final native int nativeGetHue(final long id_camera); - - private final native int nativeUpdateAutoHueLimit(final long id_camera); - private static final native int nativeSetAutoHue(final long id_camera, final boolean autohue); - private static final native int nativeGetAutoHue(final long id_camera); - - private final native int nativeUpdatePowerlineFrequencyLimit(final long id_camera); - private static final native int nativeSetPowerlineFrequency(final long id_camera, final int frequency); - private static final native int nativeGetPowerlineFrequency(final long id_camera); - - private final native int nativeUpdateZoomLimit(final long id_camera); - private static final native int nativeSetZoom(final long id_camera, final int zoom); - private static final native int nativeGetZoom(final long id_camera); - - private final native int nativeUpdateZoomRelLimit(final long id_camera); - private static final native int nativeSetZoomRel(final long id_camera, final int zoom_rel); - private static final native int nativeGetZoomRel(final long id_camera); - - private final native int nativeUpdateDigitalMultiplierLimit(final long id_camera); - private static final native int nativeSetDigitalMultiplier(final long id_camera, final int multiplier); - private static final native int nativeGetDigitalMultiplier(final long id_camera); - - private final native int nativeUpdateDigitalMultiplierLimitLimit(final long id_camera); - private static final native int nativeSetDigitalMultiplierLimit(final long id_camera, final int multiplier_limit); - private static final native int nativeGetDigitalMultiplierLimit(final long id_camera); - - private final native int nativeUpdateAnalogVideoStandardLimit(final long id_camera); - private static final native int nativeSetAnalogVideoStandard(final long id_camera, final int standard); - private static final native int nativeGetAnalogVideoStandard(final long id_camera); - - private final native int nativeUpdateAnalogVideoLockStateLimit(final long id_camera); - private static final native int nativeSetAnalogVideoLoackState(final long id_camera, final int state); - private static final native int nativeGetAnalogVideoLoackState(final long id_camera); - - private final native int nativeUpdatePrivacyLimit(final long id_camera); - private static final native int nativeSetPrivacy(final long id_camera, final boolean privacy); - private static final native int nativeGetPrivacy(final long id_camera); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java deleted file mode 100644 index 992d1cf562..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java +++ /dev/null @@ -1,1144 +0,0 @@ -package com.serenegiant.usb.common; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.ImageFormat; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; -import android.graphics.YuvImage; -import android.hardware.usb.UsbDevice; -import android.media.MediaScannerConnection; -import android.os.Build; -import android.os.Environment; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.text.TextUtils; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; - -import com.serenegiant.usb.IFrameCallback; -import com.serenegiant.usb.Size; -import com.serenegiant.usb.USBMonitor; -import com.serenegiant.usb.UVCCamera; -import com.serenegiant.usb.encoder.MediaEncoder; -import com.serenegiant.usb.encoder.MediaMuxerWrapper; -import com.serenegiant.usb.encoder.MediaSurfaceEncoder; -import com.serenegiant.usb.encoder.MediaVideoBufferEncoder; -import com.serenegiant.usb.encoder.MediaVideoEncoder; -import com.serenegiant.usb.encoder.RecordParams; -import com.serenegiant.usb.encoder.biz.AACEncodeConsumer; -import com.serenegiant.usb.encoder.biz.H264EncodeConsumer; -import com.serenegiant.usb.encoder.biz.Mp4MediaMuxer; -import com.serenegiant.usb.widget.CameraViewInterface; - -import org.easydarwin.sw.TxtOverlay; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.nio.ByteBuffer; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * Camera业务处理抽象类 - */ -public abstract class AbstractUVCCameraHandler extends Handler { - - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "AbsUVCCameraHandler"; - - - // 对外回调接口 - public interface CameraCallback { - public void onOpen(); - - public void onClose(); - - public void onStartPreview(); - - public void onStopPreview(); - - public void onStartRecording(); - - public void onStopRecording(); - - public void onError(final Exception e); - } - - public static OnEncodeResultListener mListener; - public static OnPreViewResultListener mPreviewListener; - public static OnCaptureListener mCaptureListener; - - public interface OnEncodeResultListener { - void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type); - - void onRecordResult(String videoPath); - } - - public interface OnPreViewResultListener { - void onPreviewResult(byte[] data); - } - - public interface OnCaptureListener { - void onCaptureResult(String picPath); - } - - private static final int MSG_OPEN = 0; - private static final int MSG_CLOSE = 1; - private static final int MSG_PREVIEW_START = 2; - private static final int MSG_PREVIEW_STOP = 3; - private static final int MSG_CAPTURE_STILL = 4; - private static final int MSG_CAPTURE_START = 5; - private static final int MSG_CAPTURE_STOP = 6; - private static final int MSG_MEDIA_UPDATE = 7; - private static final int MSG_RELEASE = 9; - private static final int MSG_CAMERA_FOUCS = 10; - // 音频线程 -// private static final int MSG_AUDIO_START = 10; -// private static final int MSG_AUDIO_STOP = 11; - - private final WeakReference mWeakThread; - private volatile boolean mReleased; - protected static boolean isCaptureStill; - - protected AbstractUVCCameraHandler(final CameraThread thread) { - mWeakThread = new WeakReference(thread); - } - - public int getWidth() { - final CameraThread thread = mWeakThread.get(); - return thread != null ? thread.getWidth() : 0; - } - - public int getHeight() { - final CameraThread thread = mWeakThread.get(); - return thread != null ? thread.getHeight() : 0; - } - - public boolean isOpened() { - final CameraThread thread = mWeakThread.get(); - return thread != null && thread.isCameraOpened(); - } - - public boolean isPreviewing() { - final CameraThread thread = mWeakThread.get(); - return thread != null && thread.isPreviewing(); - } - - public boolean isRecording() { - final CameraThread thread = mWeakThread.get(); - return thread != null && thread.isRecording(); - } - -// public boolean isAudioThreadStart() { -// final CameraThread thread = mWeakThread.get(); -// return thread != null && thread.isAudioRecording(); -// } - - public boolean isEqual(final UsbDevice device) { - final CameraThread thread = mWeakThread.get(); - return (thread != null) && thread.isEqual(device); - } - - protected boolean isCameraThread() { - final CameraThread thread = mWeakThread.get(); - return thread != null && (thread.getId() == Thread.currentThread().getId()); - } - - protected boolean isReleased() { - final CameraThread thread = mWeakThread.get(); - return mReleased || (thread == null); - } - - protected void checkReleased() { - if (isReleased()) { - throw new IllegalStateException("already released"); - } - } - - public void open(final USBMonitor.UsbControlBlock ctrlBlock) { - checkReleased(); - sendMessage(obtainMessage(MSG_OPEN, ctrlBlock)); - } - - public void close() { - if (DEBUG) Log.v(TAG, "close:"); - if (isOpened()) { - stopPreview(); - sendEmptyMessage(MSG_CLOSE); - } - if (DEBUG) Log.v(TAG, "close:finished"); - } - - // 切换分辨率 - public void resize(final int width, final int height) { - checkReleased(); - throw new UnsupportedOperationException("does not support now"); - } - - // 开启Camera预览 - public void startPreview(final Object surface) { - checkReleased(); - if (!((surface instanceof SurfaceHolder) || (surface instanceof Surface) || (surface instanceof SurfaceTexture))) { - throw new IllegalArgumentException("surface should be one of SurfaceHolder, Surface or SurfaceTexture: " + surface); - } - - sendMessage(obtainMessage(MSG_PREVIEW_START, surface)); - } - - public void setOnPreViewResultListener(OnPreViewResultListener listener) { - AbstractUVCCameraHandler.mPreviewListener = listener; - } - - // 关闭Camera预览 - public void stopPreview() { - if (DEBUG) Log.v(TAG, "stopPreview:"); - removeMessages(MSG_PREVIEW_START); - if (isRecording()) { - stopRecording(); - } - if (isPreviewing()) { - final CameraThread thread = mWeakThread.get(); - if (thread == null) return; - synchronized (thread.mSync) { - sendEmptyMessage(MSG_PREVIEW_STOP); - if (!isCameraThread()) { - // wait for actually preview stopped to avoid releasing Surface/SurfaceTexture - // while preview is still running. - // therefore this method will take a time to execute - try { - thread.mSync.wait(); - } catch (final InterruptedException e) { - } - } - } - } - if (DEBUG) Log.v(TAG, "stopPreview:finished"); - } - - public void captureStill(final String path, OnCaptureListener listener) { - AbstractUVCCameraHandler.mCaptureListener = listener; - checkReleased(); - sendMessage(obtainMessage(MSG_CAPTURE_STILL, path)); - isCaptureStill = true; - } - - // 开始录制 - public void startRecording(final RecordParams params, OnEncodeResultListener listener) { - AbstractUVCCameraHandler.mListener = listener; - checkReleased(); - sendMessage(obtainMessage(MSG_CAPTURE_START, params)); - } - - // 停止录制 - public void stopRecording() { - sendEmptyMessage(MSG_CAPTURE_STOP); - } - - public void startCameraFoucs() { - sendEmptyMessage(MSG_CAMERA_FOUCS); - } - - public List getSupportedPreviewSizes() { - return mWeakThread.get().getSupportedSizes(); - } - -// // 启动音频线程 -// public void startAudioThread(){ -// sendEmptyMessage(MSG_AUDIO_START); -// } -// -// // 关闭音频线程 -// public void stopAudioThread(){ -// sendEmptyMessage(MSG_AUDIO_STOP); -// } - - public void release() { - mReleased = true; - close(); - sendEmptyMessage(MSG_RELEASE); - } - - // 对外注册监听事件 - public void addCallback(final CameraCallback callback) { - checkReleased(); - if (!mReleased && (callback != null)) { - final CameraThread thread = mWeakThread.get(); - if (thread != null) { - thread.mCallbacks.add(callback); - } - } - } - - public void removeCallback(final CameraCallback callback) { - if (callback != null) { - final CameraThread thread = mWeakThread.get(); - if (thread != null) { - thread.mCallbacks.remove(callback); - } - } - } - - protected void updateMedia(final String path) { - sendMessage(obtainMessage(MSG_MEDIA_UPDATE, path)); - } - - public boolean checkSupportFlag(final long flag) { - checkReleased(); - final CameraThread thread = mWeakThread.get(); - return thread != null && thread.mUVCCamera != null && thread.mUVCCamera.checkSupportFlag(flag); - } - - public int getValue(final int flag) { - checkReleased(); - final CameraThread thread = mWeakThread.get(); - final UVCCamera camera = thread != null ? thread.mUVCCamera : null; - if (camera != null) { - if (flag == UVCCamera.PU_BRIGHTNESS) { - return camera.getBrightness(); - } else if (flag == UVCCamera.PU_CONTRAST) { - return camera.getContrast(); - } - } - throw new IllegalStateException(); - } - - public int setValue(final int flag, final int value) { - checkReleased(); - final CameraThread thread = mWeakThread.get(); - final UVCCamera camera = thread != null ? thread.mUVCCamera : null; - if (camera != null) { - if (flag == UVCCamera.PU_BRIGHTNESS) { - camera.setBrightness(value); - return camera.getBrightness(); - } else if (flag == UVCCamera.PU_CONTRAST) { - camera.setContrast(value); - return camera.getContrast(); - } - } - throw new IllegalStateException(); - } - - public int resetValue(final int flag) { - checkReleased(); - final CameraThread thread = mWeakThread.get(); - final UVCCamera camera = thread != null ? thread.mUVCCamera : null; - if (camera != null) { - if (flag == UVCCamera.PU_BRIGHTNESS) { - camera.resetBrightness(); - return camera.getBrightness(); - } else if (flag == UVCCamera.PU_CONTRAST) { - camera.resetContrast(); - return camera.getContrast(); - } - } - throw new IllegalStateException(); - } - - @Override - public void handleMessage(final Message msg) { - final CameraThread thread = mWeakThread.get(); - if (thread == null) return; - switch (msg.what) { - case MSG_OPEN: - thread.handleOpen((USBMonitor.UsbControlBlock) msg.obj); - break; - case MSG_CLOSE: - thread.handleClose(); - break; - case MSG_PREVIEW_START: - thread.handleStartPreview(msg.obj); - break; - case MSG_PREVIEW_STOP: - thread.handleStopPreview(); - break; - case MSG_CAPTURE_STILL: -// thread.handleCaptureStill((String)msg.obj); - thread.handleStillPicture((String) msg.obj); - break; - case MSG_CAPTURE_START: -// thread.handleStartRecording((String)msg.obj); - thread.handleStartPusher((RecordParams) msg.obj); - break; - case MSG_CAPTURE_STOP: - thread.handleStopPusher(); - break; - case MSG_MEDIA_UPDATE: - thread.handleUpdateMedia((String) msg.obj); - break; - case MSG_RELEASE: - thread.handleRelease(); - break; - // 自动对焦 - case MSG_CAMERA_FOUCS: - thread.handleCameraFoucs(); - break; - default: - throw new RuntimeException("unsupported message:what=" + msg.what); - } - } - - public static final class CameraThread extends Thread { - private static final String TAG_THREAD = "CameraThread"; - private final Object mSync = new Object(); - private final Class mHandlerClass; - private final WeakReference mWeakParent; - private final WeakReference mWeakCameraView; - private final int mEncoderType; - private final Set mCallbacks = new CopyOnWriteArraySet(); - private int mWidth, mHeight, mPreviewMode; - private float mBandwidthFactor; - private boolean mIsPreviewing; - private boolean mIsRecording; - - // 播放声音 -// private SoundPool mSoundPool; -// private int mSoundId; - private AbstractUVCCameraHandler mHandler; - // 处理与Camera相关的逻辑,比如获取byte数据流等 - private UVCCamera mUVCCamera; - - // private MediaMuxerWrapper mMuxer; - private MediaVideoBufferEncoder mVideoEncoder; - private Mp4MediaMuxer mMuxer; - private boolean isPushing; - private String videoPath; - private boolean isSupportOverlay; -// private boolean isAudioThreadStart; - - /** - * 构造方法 - *

- * clazz 继承于AbstractUVCCameraHandler - * parent Activity子类 - * cameraView 用于捕获静止图像 - * encoderType 0表示使用MediaSurfaceEncoder;1表示使用MediaVideoEncoder, 2表示使用MediaVideoBufferEncoder - * width 分辨率的宽 - * height 分辨率的高 - * format 颜色格式,0为FRAME_FORMAT_YUYV;1为FRAME_FORMAT_MJPEG - * bandwidthFactor - */ - CameraThread(final Class clazz, - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height, final int format, - final float bandwidthFactor) { - - super("CameraThread"); - mHandlerClass = clazz; - mEncoderType = encoderType; - mWidth = width; - mHeight = height; - mPreviewMode = format; - mBandwidthFactor = bandwidthFactor; - mWeakParent = new WeakReference<>(parent); - mWeakCameraView = new WeakReference<>(cameraView); -// loadShutterSound(parent); - } - - @Override - protected void finalize() throws Throwable { - Log.i(TAG, "CameraThread#finalize"); - super.finalize(); - } - - public AbstractUVCCameraHandler getHandler() { - if (DEBUG) Log.v(TAG_THREAD, "getHandler:"); - synchronized (mSync) { - if (mHandler == null) - try { - mSync.wait(); - } catch (final InterruptedException e) { - } - } - return mHandler; - } - - public int getWidth() { - synchronized (mSync) { - return mWidth; - } - } - - public int getHeight() { - synchronized (mSync) { - return mHeight; - } - } - - public boolean isCameraOpened() { - synchronized (mSync) { - return mUVCCamera != null; - } - } - - public boolean isPreviewing() { - synchronized (mSync) { - return mUVCCamera != null && mIsPreviewing; - } - } - - public boolean isRecording() { - synchronized (mSync) { - return (mUVCCamera != null) && (mH264Consumer != null); - } - } - -// public boolean isAudioRecording(){ -// synchronized (mSync){ -// return isAudioThreadStart; -// } -// } - - public boolean isEqual(final UsbDevice device) { - return (mUVCCamera != null) && (mUVCCamera.getDevice() != null) && mUVCCamera.getDevice().equals(device); - } - - public void handleOpen(final USBMonitor.UsbControlBlock ctrlBlock) { - if (DEBUG) Log.v(TAG_THREAD, "handleOpen:"); - handleClose(); - try { - final UVCCamera camera = new UVCCamera(); - camera.open(ctrlBlock); - synchronized (mSync) { - mUVCCamera = camera; - } - callOnOpen(); - } catch (final Exception e) { - callOnError(e); - } - if (DEBUG) - Log.i(TAG, "supportedSize:" + (mUVCCamera != null ? mUVCCamera.getSupportedSize() : null)); - } - - public void handleClose() { - if (DEBUG) Log.v(TAG_THREAD, "handleClose:"); - handleStopPusher(); - final UVCCamera camera; - synchronized (mSync) { - camera = mUVCCamera; - mUVCCamera = null; - } - if (camera != null) { - camera.stopPreview(); - camera.destroy(); - callOnClose(); - } - } - - public void handleStartPreview(final Object surface) { - if (DEBUG) Log.v(TAG_THREAD, "handleStartPreview:"); - if ((mUVCCamera == null) || mIsPreviewing) return; - try { - mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, mPreviewMode, mBandwidthFactor); - // 获取USB Camera预览数据,使用NV21颜色会失真 - // 无论使用YUV还是MPEG,setFrameCallback的设置效果一致 -// mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21); - mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP); - } catch (final IllegalArgumentException e) { - try { - // fallback to YUV mode - mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, UVCCamera.DEFAULT_PREVIEW_MODE, mBandwidthFactor); - } catch (final IllegalArgumentException e1) { - callOnError(e1); - return; - } - } - if (surface instanceof SurfaceHolder) { - mUVCCamera.setPreviewDisplay((SurfaceHolder) surface); - } - if (surface instanceof Surface) { - mUVCCamera.setPreviewDisplay((Surface) surface); - } else { - mUVCCamera.setPreviewTexture((SurfaceTexture) surface); - } - mUVCCamera.startPreview(); - mUVCCamera.updateCameraParams(); - synchronized (mSync) { - mIsPreviewing = true; - } - callOnStartPreview(); - } - - public void handleStopPreview() { - if (DEBUG) Log.v(TAG_THREAD, "handleStopPreview:"); - if (mIsPreviewing) { - if (mUVCCamera != null) { - mUVCCamera.stopPreview(); - mUVCCamera.setFrameCallback(null, 0); - } - synchronized (mSync) { - mIsPreviewing = false; - mSync.notifyAll(); - } - callOnStopPreview(); - } - if (DEBUG) Log.v(TAG_THREAD, "handleStopPreview:finished"); - } - - // 捕获静态图片 - public void handleCaptureStill(final String path) { - if (DEBUG) Log.v(TAG_THREAD, "handleCaptureStill:"); - final Activity parent = mWeakParent.get(); - if (parent == null) return; -// mSoundPool.play(mSoundId, 0.2f, 0.2f, 0, 0, 1.0f); // play shutter sound - try { - final Bitmap bitmap = mWeakCameraView.get().captureStillImage(mWidth, mHeight); - // get buffered output stream for saving a captured still image as a file on external storage. - // the file name is came from current time. - // You should use extension name as same as CompressFormat when calling Bitmap#compress. - final File outputFile = TextUtils.isEmpty(path) - ? MediaMuxerWrapper.getCaptureFile(Environment.DIRECTORY_DCIM, ".jpg") - : new File(path); - final BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile)); - try { - try { - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); - os.flush(); - mHandler.sendMessage(mHandler.obtainMessage(MSG_MEDIA_UPDATE, outputFile.getPath())); - } catch (final IOException e) { - } - } finally { - os.close(); - } - if (mCaptureListener != null) { - mCaptureListener.onCaptureResult(path); - } - } catch (final Exception e) { - callOnError(e); - } - } - - // 开始录制视频 -// public void handleStartRecording2(String path) { -// if (DEBUG) Log.v(TAG_THREAD, "handleStartRecording:"); -// try { -// if ((mUVCCamera == null) || (mMuxer != null)) return; -//// final MediaMuxerWrapper muxer = new MediaMuxerWrapper(".mp4"); // if you record audio only, ".m4a" is also OK. -// final MediaMuxerWrapper muxer = new MediaMuxerWrapper(path); -// MediaVideoBufferEncoder videoEncoder = null; -// switch (mEncoderType) { -// case 1: // for video capturing using MediaVideoEncoder -// // 开启视频编码线程 -// new MediaVideoEncoder(muxer,getWidth(), getHeight(), mMediaEncoderListener); -// break; -// case 2: // for video capturing using MediaVideoBufferEncoder -// videoEncoder = new MediaVideoBufferEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener); -// break; -// // case 0: // for video capturing using MediaSurfaceEncoder -// default: -// new MediaSurfaceEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener); -// break; -// } -// // 开启音频编码线程 -// if (true) { -// // for audio capturing -//// new MediaAudioEncoder(muxer, mMediaEncoderListener); -// } -// muxer.prepare(); -// muxer.startRecording(); -// if (videoEncoder != null) { -// mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21); -// } -// synchronized (mSync) { -// mMuxer = muxer; -// mVideoEncoder = videoEncoder; -// } -// callOnStartRecording(); -// } catch (final IOException e) { -// callOnError(e); -// Log.e(TAG, "startCapture:", e); -// } -// } - - private AACEncodeConsumer mAacConsumer; - private H264EncodeConsumer mH264Consumer; - - public void handleStartPusher(RecordParams params) { - if ((mUVCCamera == null) || (mH264Consumer != null)) - return; -// // 获取USB Camera预览数据 -// mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21); - - // 初始化混合器 - if (params != null) { - isSupportOverlay = params.isSupportOverlay(); - if(isSupportOverlay) { - // init overlay engine - TxtOverlay.getInstance().init(mWidth, mHeight); - } - videoPath = params.getRecordPath(); - File file = new File(videoPath); - if(! Objects.requireNonNull(file.getParentFile()).exists()) { - file.getParentFile().mkdirs(); - } - mMuxer = new Mp4MediaMuxer(params.getRecordPath(), - params.getRecordDuration() * 60 * 1000, params.isVoiceClose()); - } - // 启动视频编码线程 - startVideoRecord(); - // 启动音频编码线程 - if (params != null && !params.isVoiceClose()) { - startAudioRecord(); - } - callOnStartRecording(); - } - - - public void handleStopPusher() { - // 停止混合器 - if (mMuxer != null) { - mMuxer.release(); - mMuxer = null; - Log.i(TAG, TAG + "---->停止本地录制"); - } - // 停止音视频编码线程 - stopAudioRecord(); - stopVideoRecord(); - if(isSupportOverlay) - TxtOverlay.getInstance().release(); -// // 停止捕获视频数据 -// if (mUVCCamera != null) { -// mUVCCamera.stopCapture(); -// } - mWeakCameraView.get().setVideoEncoder(null); - // you should not wait here - callOnStopRecording(); - // 返回路径 - if (mListener != null) { - mListener.onRecordResult(videoPath + ".mp4"); - } - } - - private void startVideoRecord() { - mH264Consumer = new H264EncodeConsumer(getWidth(), getHeight()); - mH264Consumer.setOnH264EncodeResultListener(new H264EncodeConsumer.OnH264EncodeResultListener() { - @Override - public void onEncodeResult(byte[] data, int offset, int length, long timestamp) { - if (mListener != null) { - mListener.onEncodeResult(data, offset, length, timestamp, 1); - } - } - }); - mH264Consumer.start(); - // 添加混合器 - if (mMuxer != null) { - if (mH264Consumer != null) { - mH264Consumer.setTmpuMuxer(mMuxer); - } - } - } - - private void stopVideoRecord() { - if (mH264Consumer != null) { - mH264Consumer.exit(); - mH264Consumer.setTmpuMuxer(null); - try { - Thread t2 = mH264Consumer; - mH264Consumer = null; - if (t2 != null) { - t2.interrupt(); - t2.join(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - private void startAudioRecord() { - mAacConsumer = new AACEncodeConsumer(); - mAacConsumer.setOnAACEncodeResultListener(new AACEncodeConsumer.OnAACEncodeResultListener() { - @Override - public void onEncodeResult(byte[] data, int offset, int length, long timestamp) { - if (mListener != null) { - mListener.onEncodeResult(data, offset, length, timestamp, 0); - } - } - }); - mAacConsumer.start(); - // 添加混合器 - if (mMuxer != null) { - if (mAacConsumer != null) { - mAacConsumer.setTmpuMuxer(mMuxer); - } - } - } - - private void stopAudioRecord() { - if (mAacConsumer != null) { - mAacConsumer.exit(); - mAacConsumer.setTmpuMuxer(null); - try { - Thread t1 = mAacConsumer; - mAacConsumer = null; - if (t1 != null) { - t1.interrupt(); - t1.join(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - -// isAudioThreadStart = false; - } - - private String picPath = null; - - public void handleStillPicture(String picPath) { - this.picPath = picPath; - } - - private final IFrameCallback mIFrameCallback = new IFrameCallback() { - @Override - public void onFrame(final ByteBuffer frame) { -// final MediaVideoBufferEncoder videoEncoder; -// synchronized (mSync) { -// videoEncoder = mVideoEncoder; -// } -// if (videoEncoder != null) { -// videoEncoder.frameAvailableSoon(); -// videoEncoder.encode(frame); -// } - int len = frame.capacity(); - final byte[] yuv = new byte[len]; - frame.get(yuv); - // nv21 yuv data callback - if (mPreviewListener != null) { - mPreviewListener.onPreviewResult(yuv); - } - // picture - if (isCaptureStill && !TextUtils.isEmpty(picPath)) { - isCaptureStill = false; - new Thread(new Runnable() { - @Override - public void run() { - saveYuv2Jpeg(picPath, yuv); - } - }).start(); - } - // video - if (mH264Consumer != null) { - // overlay - if(isSupportOverlay) { - TxtOverlay.getInstance().overlay(yuv, new SimpleDateFormat("yyyy-MM-dd EEEE HH:mm:ss").format(new Date())); - } - - mH264Consumer.setRawYuv(yuv, mWidth, mHeight); - } - } - }; - - private void saveYuv2Jpeg(String path, byte[] data) { - YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, mWidth, mHeight, null); - ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length); - boolean result = yuvImage.compressToJpeg(new Rect(0, 0, mWidth, mHeight), 100, bos); - if (result) { - - byte[] buffer = bos.toByteArray(); - File file = new File(path); - FileOutputStream fos = null; - try { - fos = new FileOutputStream(file); - // fixing bm is null bug instead of using BitmapFactory.decodeByteArray - fos.write(buffer); - fos.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - if (mCaptureListener != null) { - mCaptureListener.onCaptureResult(path); - } - } - try { - bos.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - public void handleUpdateMedia(final String path) { - if (DEBUG) Log.v(TAG_THREAD, "handleUpdateMedia:path=" + path); - final Activity parent = mWeakParent.get(); - final boolean released = (mHandler == null) || mHandler.mReleased; - if (parent != null && parent.getApplicationContext() != null) { - try { - if (DEBUG) Log.i(TAG, "MediaScannerConnection#scanFile"); - MediaScannerConnection.scanFile(parent.getApplicationContext(), new String[]{path}, null, null); - } catch (final Exception e) { - Log.e(TAG, "handleUpdateMedia:", e); - } - if (released || parent.isDestroyed()) - handleRelease(); - } else { - Log.w(TAG, "MainActivity already destroyed"); - // give up to add this movie to MediaStore now. - // Seeing this movie on Gallery app etc. will take a lot of time. - handleRelease(); - } - } - - public void handleRelease() { - if (DEBUG) Log.v(TAG_THREAD, "handleRelease:mIsRecording=" + mIsRecording); - handleClose(); - mCallbacks.clear(); - if (!mIsRecording) { - mHandler.mReleased = true; - Looper.myLooper().quit(); - } - if (DEBUG) Log.v(TAG_THREAD, "handleRelease:finished"); - } - - // 自动对焦 - public void handleCameraFoucs() { - if (DEBUG) Log.v(TAG_THREAD, "handleStartPreview:"); - if ((mUVCCamera == null) || !mIsPreviewing) - return; - mUVCCamera.setAutoFocus(true); - } - - // 获取支持的分辨率 - public List getSupportedSizes() { - if ((mUVCCamera == null) || !mIsPreviewing) - return null; - return mUVCCamera.getSupportedSizeList(); - } - - private final MediaEncoder.MediaEncoderListener mMediaEncoderListener = new MediaEncoder.MediaEncoderListener() { - @Override - public void onPrepared(final MediaEncoder encoder) { - if (DEBUG) Log.v(TAG, "onPrepared:encoder=" + encoder); - mIsRecording = true; - if (encoder instanceof MediaVideoEncoder) - try { - mWeakCameraView.get().setVideoEncoder((MediaVideoEncoder) encoder); - } catch (final Exception e) { - Log.e(TAG, "onPrepared:", e); - } - if (encoder instanceof MediaSurfaceEncoder) - try { - mWeakCameraView.get().setVideoEncoder((MediaSurfaceEncoder) encoder); - mUVCCamera.startCapture(((MediaSurfaceEncoder) encoder).getInputSurface()); - } catch (final Exception e) { - Log.e(TAG, "onPrepared:", e); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - @Override - public void onStopped(final MediaEncoder encoder) { - if (DEBUG) Log.v(TAG_THREAD, "onStopped:encoder=" + encoder); - if ((encoder instanceof MediaVideoEncoder) - || (encoder instanceof MediaSurfaceEncoder)) - try { - mIsRecording = false; - final Activity parent = mWeakParent.get(); - mWeakCameraView.get().setVideoEncoder(null); - synchronized (mSync) { - if (mUVCCamera != null) { - mUVCCamera.stopCapture(); - } - } - final String path = encoder.getOutputPath(); - if (!TextUtils.isEmpty(path)) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_MEDIA_UPDATE, path), 1000); - } else { - final boolean released = (mHandler == null) || mHandler.mReleased; - if (released || parent == null || parent.isDestroyed()) { - handleRelease(); - } - } - } catch (final Exception e) { - Log.e(TAG, "onPrepared:", e); - } - } - - @Override - public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) { - if (mListener != null) { - mListener.onEncodeResult(data, offset, length, timestamp, type); - } - } - - }; - -// private void loadShutterSound(final Context context) { -// // get system stream type using reflection -// int streamType; -// try { -// final Class audioSystemClass = Class.forName("android.media.AudioSystem"); -// final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED"); -// streamType = sseField.getInt(null); -// } catch (final Exception e) { -// streamType = AudioManager.STREAM_SYSTEM; // set appropriate according to your app policy -// } -// if (mSoundPool != null) { -// try { -// mSoundPool.release(); -// } catch (final Exception e) { -// } -// mSoundPool = null; -// } -// // load shutter sound from resource -// mSoundPool = new SoundPool(2, streamType, 0); -// mSoundId = mSoundPool.load(context, R.raw.camera_click, 1); -// } - - /** - * prepare and load shutter sound for still image capturing - */ - @SuppressWarnings("deprecation") -// private void loadShutterSound(final Context context) { -// // get system stream type using reflection -// int streamType; -// try { -// final Class audioSystemClass = Class.forName("android.media.AudioSystem"); -// final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED"); -// streamType = sseField.getInt(null); -// } catch (final Exception e) { -// streamType = AudioManager.STREAM_SYSTEM; // set appropriate according to your app policy -// } -// if (mSoundPool != null) { -// try { -// mSoundPool.release(); -// } catch (final Exception e) { -// } -// mSoundPool = null; -// } -// // load shutter sound from resource -// mSoundPool = new SoundPool(2, streamType, 0); -// mSoundId = mSoundPool.load(context, R.raw.camera_click, 1); -// } - - @Override - public void run() { - Looper.prepare(); - AbstractUVCCameraHandler handler = null; - try { - final Constructor constructor = mHandlerClass.getDeclaredConstructor(CameraThread.class); - handler = constructor.newInstance(this); - } catch (final NoSuchMethodException e) { - Log.w(TAG, e); - } catch (final IllegalAccessException e) { - Log.w(TAG, e); - } catch (final InstantiationException e) { - Log.w(TAG, e); - } catch (final InvocationTargetException e) { - Log.w(TAG, e); - } - if (handler != null) { - synchronized (mSync) { - mHandler = handler; - mSync.notifyAll(); - } - Looper.loop(); -// if (mSoundPool != null) { -// mSoundPool.release(); -// mSoundPool = null; -// } - if (mHandler != null) { - mHandler.mReleased = true; - } - } - mCallbacks.clear(); - synchronized (mSync) { - mHandler = null; - mSync.notifyAll(); - } - } - - private void callOnOpen() { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onOpen(); - } catch (final Exception e) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - - private void callOnClose() { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onClose(); - } catch (final Exception e) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - - private void callOnStartPreview() { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onStartPreview(); - } catch (final Exception e) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - - private void callOnStopPreview() { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onStopPreview(); - } catch (final Exception e) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - - private void callOnStartRecording() { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onStartRecording(); - } catch (final Exception e) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - - private void callOnStopRecording() { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onStopRecording(); - } catch (final Exception e) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - - private void callOnError(final Exception e) { - for (final CameraCallback callback : mCallbacks) { - try { - callback.onError(e); - } catch (final Exception e1) { - mCallbacks.remove(callback); - Log.w(TAG, e); - } - } - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseActivity.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseActivity.java deleted file mode 100644 index 8a446cd2a8..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseActivity.java +++ /dev/null @@ -1,321 +0,0 @@ -package com.serenegiant.usb.common; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.appcompat.app.AppCompatActivity; - -import com.mogo.usbcamera.R; -import com.serenegiant.dialog.MessageDialogFragmentV4; -import com.serenegiant.utils.BuildCheck; -import com.serenegiant.utils.HandlerThreadHandler; -import com.serenegiant.utils.PermissionCheck; - -/** - * Created by saki on 2016/11/18. - * - */ -public class BaseActivity extends AppCompatActivity - implements MessageDialogFragmentV4.MessageDialogListener { - - private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること - private static final String TAG = BaseActivity.class.getSimpleName(); - - /** UI操作のためのHandler */ - private final Handler mUIHandler = new Handler(Looper.getMainLooper()); - private final Thread mUiThread = mUIHandler.getLooper().getThread(); - /** ワーカースレッド上で処理するためのHandler */ - private Handler mWorkerHandler; - private long mWorkerThreadID = -1; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // ワーカースレッドを生成 - if (mWorkerHandler == null) { - mWorkerHandler = HandlerThreadHandler.createHandler(TAG); - mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId(); - } - } - - @Override - protected void onPause() { - clearToast(); - super.onPause(); - } - - @Override - protected synchronized void onDestroy() { - // ワーカースレッドを破棄 - if (mWorkerHandler != null) { - try { - mWorkerHandler.getLooper().quit(); - } catch (final Exception e) { - // - } - mWorkerHandler = null; - } - super.onDestroy(); - } - -//================================================================================ - /** - * UIスレッドでRunnableを実行するためのヘルパーメソッド - * @param task - * @param duration - */ - public final void runOnUiThread(final Runnable task, final long duration) { - if (task == null) { - return; - } - mUIHandler.removeCallbacks(task); - if ((duration > 0) || Thread.currentThread() != mUiThread) { - mUIHandler.postDelayed(task, duration); - } else { - try { - task.run(); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - - /** - * UIスレッド上で指定したRunnableが実行待ちしていれば実行待ちを解除する - * @param task - */ - public final void removeFromUiThread(final Runnable task) { - if (task == null) { - return; - } - mUIHandler.removeCallbacks(task); - } - - /** - * ワーカースレッド上で指定したRunnableを実行する - * 未実行の同じRunnableがあればキャンセルされる(後から指定した方のみ実行される) - * @param task - * @param delayMillis - */ - protected final synchronized void queueEvent(final Runnable task, final long delayMillis) { - if ((task == null) || (mWorkerHandler == null)) { - return; - } - try { - mWorkerHandler.removeCallbacks(task); - if (delayMillis > 0) { - mWorkerHandler.postDelayed(task, delayMillis); - } else if (mWorkerThreadID == Thread.currentThread().getId()) { - task.run(); - } else { - mWorkerHandler.post(task); - } - } catch (final Exception e) { - // ignore - } - } - - /** - * 指定したRunnableをワーカースレッド上で実行予定であればキャンセルする - * @param task - */ - protected final synchronized void removeEvent(final Runnable task) { - if (task == null) { - return; - } - try { - mWorkerHandler.removeCallbacks(task); - } catch (final Exception e) { - // ignore - } - } - -//================================================================================ - private Toast mToast; - /** - * Toastでメッセージを表示 - * @param msg - */ - protected void showToast(@StringRes final int msg, final Object... args) { - removeFromUiThread(mShowToastTask); - mShowToastTask = new ShowToastTask(msg, args); - runOnUiThread(mShowToastTask, 0); - } - - /** - * Toastが表示されていればキャンセルする - */ - protected void clearToast() { - removeFromUiThread(mShowToastTask); - mShowToastTask = null; - try { - if (mToast != null) { - mToast.cancel(); - mToast = null; - } - } catch (final Exception e) { - // ignore - } - } - - private ShowToastTask mShowToastTask; - private final class ShowToastTask implements Runnable { - final int msg; - final Object args; - private ShowToastTask(@StringRes final int msg, final Object... args) { - this.msg = msg; - this.args = args; - } - - @Override - public void run() { - try { - if (mToast != null) { - mToast.cancel(); - mToast = null; - } - final String _msg = (args != null) ? getString(msg, args) : getString(msg); - mToast = Toast.makeText(BaseActivity.this, _msg, Toast.LENGTH_SHORT); - mToast.show(); - } catch (final Exception e) { - // ignore - } - } - } - -//================================================================================ - /** - * MessageDialogFragmentメッセージダイアログからのコールバックリスナー - * @param dialog - * @param requestCode - * @param permissions - * @param result - */ - @SuppressLint("NewApi") - @Override - public void onMessageDialogResult(final MessageDialogFragmentV4 dialog, final int requestCode, final String[] permissions, final boolean result) { - if (result) { - // メッセージダイアログでOKを押された時はパーミッション要求する - if (BuildCheck.isMarshmallow()) { - requestPermissions(permissions, requestCode); - return; - } - } - // メッセージダイアログでキャンセルされた時とAndroid6でない時は自前でチェックして#checkPermissionResultを呼び出す - for (final String permission: permissions) { - checkPermissionResult(requestCode, permission, PermissionCheck.hasPermission(this, permission)); - } - } - - /** - * パーミッション要求結果を受け取るためのメソッド - * @param requestCode - * @param permissions - * @param grantResults - */ - @Override - public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 何もしてないけど一応呼んどく - final int n = Math.min(permissions.length, grantResults.length); - for (int i = 0; i < n; i++) { - checkPermissionResult(requestCode, permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED); - } - } - - /** - * パーミッション要求の結果をチェック - * ここではパーミッションを取得できなかった時にToastでメッセージ表示するだけ - * @param requestCode - * @param permission - * @param result - */ - protected void checkPermissionResult(final int requestCode, final String permission, final boolean result) { - // パーミッションがないときにはメッセージを表示する - if (!result && (permission != null)) { - if (Manifest.permission.RECORD_AUDIO.equals(permission)) { - showToast(R.string.permission_audio); - } - if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) { - showToast(R.string.permission_ext_storage); - } - if (Manifest.permission.INTERNET.equals(permission)) { - showToast(R.string.permission_network); - } - } - } - - // 動的パーミッション要求時の要求コード - protected static final int REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE = 0x12345; - protected static final int REQUEST_PERMISSION_AUDIO_RECORDING = 0x234567; - protected static final int REQUEST_PERMISSION_NETWORK = 0x345678; - protected static final int REQUEST_PERMISSION_CAMERA = 0x537642; - - /** - * 外部ストレージへの書き込みパーミッションが有るかどうかをチェック - * なければ説明ダイアログを表示する - * @return true 外部ストレージへの書き込みパーミッションが有る - */ - protected boolean checkPermissionWriteExternalStorage() { - if (!PermissionCheck.hasWriteExternalStorage(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, - R.string.permission_title, R.string.permission_ext_storage_request, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); - return false; - } - return true; - } - - /** - * 録音のパーミッションが有るかどうかをチェック - * なければ説明ダイアログを表示する - * @return true 録音のパーミッションが有る - */ - protected boolean checkPermissionAudio() { - if (!PermissionCheck.hasAudio(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING, - R.string.permission_title, R.string.permission_audio_recording_request, - new String[]{Manifest.permission.RECORD_AUDIO}); - return false; - } - return true; - } - - /** - * ネットワークアクセスのパーミッションが有るかどうかをチェック - * なければ説明ダイアログを表示する - * @return true ネットワークアクセスのパーミッションが有る - */ - protected boolean checkPermissionNetwork() { - if (!PermissionCheck.hasNetwork(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_NETWORK, - R.string.permission_title, R.string.permission_network_request, - new String[]{Manifest.permission.INTERNET}); - return false; - } - return true; - } - - /** - * カメラアクセスのパーミッションがあるかどうかをチェック - * なければ説明ダイアログを表示する - * @return true カメラアクセスのパーミッションが有る - */ - protected boolean checkPermissionCamera() { - if (!PermissionCheck.hasCamera(this)) { - MessageDialogFragmentV4.showDialog(this, REQUEST_PERMISSION_CAMERA, - R.string.permission_title, R.string.permission_camera_request, - new String[]{Manifest.permission.CAMERA}); - return false; - } - return true; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseFragment.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseFragment.java deleted file mode 100644 index 4e883ce185..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseFragment.java +++ /dev/null @@ -1,348 +0,0 @@ -package com.serenegiant.usb.common; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.app.Fragment; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - -import com.mogo.usbcamera.R; -import com.serenegiant.dialog.MessageDialogFragment; -import com.serenegiant.utils.BuildCheck; -import com.serenegiant.utils.HandlerThreadHandler; -import com.serenegiant.utils.PermissionCheck; - -/** - * Created by saki on 2016/11/19. - */ -public class BaseFragment extends Fragment - implements MessageDialogFragment.MessageDialogListener { - - private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること - private static final String TAG = BaseFragment.class.getSimpleName(); - - /** - * UI操作のためのHandler - */ - private final Handler mUIHandler = new Handler(Looper.getMainLooper()); - private final Thread mUiThread = mUIHandler.getLooper().getThread(); - /** - * ワーカースレッド上で処理するためのHandler - */ - private Handler mWorkerHandler; - private long mWorkerThreadID = -1; - - public BaseFragment() { - super(); - } - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // ワーカースレッドを生成 - if (mWorkerHandler == null) { - mWorkerHandler = HandlerThreadHandler.createHandler(TAG); - mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId(); - } - } - - @Override - public void onPause() { - clearToast(); - super.onPause(); - } - - @Override - public synchronized void onDestroy() { - // ワーカースレッドを破棄 - if (mWorkerHandler != null) { - try { - mWorkerHandler.getLooper().quit(); - } catch (final Exception e) { - // - } - mWorkerHandler = null; - } - super.onDestroy(); - } - -//================================================================================ - - /** - * UIスレッドでRunnableを実行するためのヘルパーメソッド - * - * @param task - * @param duration - */ - public final void runOnUiThread(final Runnable task, final long duration) { - if (task == null) { - return; - } - mUIHandler.removeCallbacks(task); - if ((duration > 0) || Thread.currentThread() != mUiThread) { - mUIHandler.postDelayed(task, duration); - } else { - try { - task.run(); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - - /** - * UIスレッド上で指定したRunnableが実行待ちしていれば実行待ちを解除する - * - * @param task - */ - public final void removeFromUiThread(final Runnable task) { - if (task == null) { - return; - } - mUIHandler.removeCallbacks(task); - } - - /** - * ワーカースレッド上で指定したRunnableを実行する - * 未実行の同じRunnableがあればキャンセルされる(後から指定した方のみ実行される) - * - * @param task - * @param delayMillis - */ - protected final synchronized void queueEvent(final Runnable task, final long delayMillis) { - if ((task == null) || (mWorkerHandler == null)) { - return; - } - try { - mWorkerHandler.removeCallbacks(task); - if (delayMillis > 0) { - mWorkerHandler.postDelayed(task, delayMillis); - } else if (mWorkerThreadID == Thread.currentThread().getId()) { - task.run(); - } else { - mWorkerHandler.post(task); - } - } catch (final Exception e) { - // ignore - } - } - - /** - * 指定したRunnableをワーカースレッド上で実行予定であればキャンセルする - * - * @param task - */ - protected final synchronized void removeEvent(final Runnable task) { - if (task == null) { - return; - } - try { - mWorkerHandler.removeCallbacks(task); - } catch (final Exception e) { - // ignore - } - } - - //================================================================================ - private Toast mToast; - - /** - * Toastでメッセージを表示 - * - * @param msg - */ - protected void showToast(@StringRes final int msg, final Object... args) { - removeFromUiThread(mShowToastTask); - mShowToastTask = new ShowToastTask(msg, args); - runOnUiThread(mShowToastTask, 0); - } - - /** - * Toastが表示されていればキャンセルする - */ - protected void clearToast() { - removeFromUiThread(mShowToastTask); - mShowToastTask = null; - try { - if (mToast != null) { - mToast.cancel(); - mToast = null; - } - } catch (final Exception e) { - // ignore - } - } - - private ShowToastTask mShowToastTask; - - private final class ShowToastTask implements Runnable { - final int msg; - final Object args; - - private ShowToastTask(@StringRes final int msg, final Object... args) { - this.msg = msg; - this.args = args; - } - - @Override - public void run() { - try { - if (mToast != null) { - mToast.cancel(); - mToast = null; - } - if (args != null) { - final String _msg = getString(msg, args); - mToast = Toast.makeText(getActivity(), _msg, Toast.LENGTH_SHORT); - } else { - mToast = Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT); - } - mToast.show(); - } catch (final Exception e) { - // ignore - } - } - } - -//================================================================================ - - /** - * MessageDialogFragmentメッセージダイアログからのコールバックリスナー - * - * @param dialog - * @param requestCode - * @param permissions - * @param result - */ - @SuppressLint("NewApi") - @Override - public void onMessageDialogResult(final MessageDialogFragment dialog, final int requestCode, final String[] permissions, final boolean result) { - if (result) { - // メッセージダイアログでOKを押された時はパーミッション要求する - if (BuildCheck.isMarshmallow()) { - requestPermissions(permissions, requestCode); - return; - } - } - // メッセージダイアログでキャンセルされた時とAndroid6でない時は自前でチェックして#checkPermissionResultを呼び出す - for (final String permission : permissions) { - checkPermissionResult(requestCode, permission, PermissionCheck.hasPermission(getActivity(), permission)); - } - } - - /** - * パーミッション要求結果を受け取るためのメソッド - * - * @param requestCode - * @param permissions - * @param grantResults - */ - @Override - public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 何もしてないけど一応呼んどく - final int n = Math.min(permissions.length, grantResults.length); - for (int i = 0; i < n; i++) { - checkPermissionResult(requestCode, permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED); - } - } - - /** - * パーミッション要求の結果をチェック - * ここではパーミッションを取得できなかった時にToastでメッセージ表示するだけ - * - * @param requestCode - * @param permission - * @param result - */ - protected void checkPermissionResult(final int requestCode, final String permission, final boolean result) { - // パーミッションがないときにはメッセージを表示する - if (!result && (permission != null)) { - if (Manifest.permission.RECORD_AUDIO.equals(permission)) { - showToast(R.string.permission_audio); - } - if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) { - showToast(R.string.permission_ext_storage); - } - if (Manifest.permission.INTERNET.equals(permission)) { - showToast(R.string.permission_network); - } - } - } - - // 動的パーミッション要求時の要求コード - protected static final int REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE = 0x12345; - protected static final int REQUEST_PERMISSION_AUDIO_RECORDING = 0x234567; - protected static final int REQUEST_PERMISSION_NETWORK = 0x345678; - protected static final int REQUEST_PERMISSION_CAMERA = 0x537642; - - /** - * 外部ストレージへの書き込みパーミッションが有るかどうかをチェック - * なければ説明ダイアログを表示する - * - * @return true 外部ストレージへの書き込みパーミッションが有る - */ - protected boolean checkPermissionWriteExternalStorage() { - if (!PermissionCheck.hasWriteExternalStorage(getActivity())) { - MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, - R.string.permission_title, R.string.permission_ext_storage_request, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); - return false; - } - return true; - } - - /** - * 録音のパーミッションが有るかどうかをチェック - * なければ説明ダイアログを表示する - * - * @return true 録音のパーミッションが有る - */ - protected boolean checkPermissionAudio() { - if (!PermissionCheck.hasAudio(getActivity())) { - MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING, - R.string.permission_title, R.string.permission_audio_recording_request, - new String[]{Manifest.permission.RECORD_AUDIO}); - return false; - } - return true; - } - - /** - * ネットワークアクセスのパーミッションが有るかどうかをチェック - * なければ説明ダイアログを表示する - * - * @return true ネットワークアクセスのパーミッションが有る - */ - protected boolean checkPermissionNetwork() { - if (!PermissionCheck.hasNetwork(getActivity())) { - MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_NETWORK, - R.string.permission_title, R.string.permission_network_request, - new String[]{Manifest.permission.INTERNET}); - return false; - } - return true; - } - - /** - * カメラアクセスのパーミッションがあるかどうかをチェック - * なければ説明ダイアログを表示する - * - * @return true カメラアクセスのパーミッションが有る - */ - protected boolean checkPermissionCamera() { - if (!PermissionCheck.hasCamera(getActivity())) { - MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_CAMERA, - R.string.permission_title, R.string.permission_camera_request, - new String[]{Manifest.permission.CAMERA}); - return false; - } - return true; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseService.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseService.java deleted file mode 100644 index 78a2307af6..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/BaseService.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.serenegiant.usb.common; - -import android.app.Service; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import com.serenegiant.utils.HandlerThreadHandler; - -public abstract class BaseService extends Service { - private static boolean DEBUG = false; // FIXME 実働時はfalseにセットすること - private static final String TAG = BaseService.class.getSimpleName(); - - /** UI操作のためのHandler */ - private final Handler mUIHandler = new Handler(Looper.getMainLooper()); - private final Thread mUiThread = mUIHandler.getLooper().getThread(); - /** ワーカースレッド上で処理するためのHandler */ - private Handler mWorkerHandler; - private long mWorkerThreadID = -1; - - @Override - public void onCreate() { - super.onCreate(); - // ワーカースレッドを生成 - if (mWorkerHandler == null) { - mWorkerHandler = HandlerThreadHandler.createHandler(TAG); - mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId(); - } - } - - @Override - public synchronized void onDestroy() { - // ワーカースレッドを破棄 - if (mWorkerHandler != null) { - try { - mWorkerHandler.getLooper().quit(); - } catch (final Exception e) { - // - } - mWorkerHandler = null; - } - super.onDestroy(); - } - -//================================================================================ - /** - * UIスレッドでRunnableを実行するためのヘルパーメソッド - * @param task - * @param duration - */ - public final void runOnUiThread(final Runnable task, final long duration) { - if (task == null) return; - mUIHandler.removeCallbacks(task); - if ((duration > 0) || Thread.currentThread() != mUiThread) { - mUIHandler.postDelayed(task, duration); - } else { - try { - task.run(); - } catch (final Exception e) { - Log.w(TAG, e); - } - } - } - - /** - * UIスレッド上で指定したRunnableが実行待ちしていれば実行待ちを解除する - * @param task - */ - public final void removeFromUiThread(final Runnable task) { - if (task == null) return; - mUIHandler.removeCallbacks(task); - } - - /** - * ワーカースレッド上で指定したRunnableを実行する - * 未実行の同じRunnableがあればキャンセルされる(後から指定した方のみ実行される) - * @param task - * @param delayMillis - */ - protected final synchronized void queueEvent(final Runnable task, final long delayMillis) { - if ((task == null) || (mWorkerHandler == null)) return; - try { - mWorkerHandler.removeCallbacks(task); - if (delayMillis > 0) { - mWorkerHandler.postDelayed(task, delayMillis); - } else if (mWorkerThreadID == Thread.currentThread().getId()) { - task.run(); - } else { - mWorkerHandler.post(task); - } - } catch (final Exception e) { - // ignore - } - } - - /** - * 指定したRunnableをワーカースレッド上で実行予定であればキャンセルする - * @param task - */ - protected final synchronized void removeEvent(final Runnable task) { - if (task == null) return; - try { - mWorkerHandler.removeCallbacks(task); - } catch (final Exception e) { - // ignore - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandler.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandler.java deleted file mode 100644 index 2d01f1cd25..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandler.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.common; - -import android.app.Activity; - -import com.serenegiant.usb.UVCCamera; -import com.serenegiant.usb.widget.CameraViewInterface; - -public class UVCCameraHandler extends AbstractUVCCameraHandler { - - /** - * create UVCCameraHandler, use MediaVideoEncoder, try MJPEG, default bandwidth - * @param parent - * @param cameraView - * @param width - * @param height - * @return - */ - public static final UVCCameraHandler createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int width, final int height) { - - return createHandler(parent, cameraView, 1, width, height, UVCCamera.FRAME_FORMAT_MJPEG, UVCCamera.DEFAULT_BANDWIDTH); - } - - /** - * create UVCCameraHandler, use MediaVideoEncoder, try MJPEG - * @param parent - * @param cameraView - * @param width - * @param height - * @param bandwidthFactor - * @return - */ - public static final UVCCameraHandler createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int width, final int height, final float bandwidthFactor) { - - return createHandler(parent, cameraView, 1, width, height, UVCCamera.FRAME_FORMAT_MJPEG, bandwidthFactor); - } - - /** - * create UVCCameraHandler, try MJPEG, default bandwidth - * @param parent - * @param cameraView - * @param encoderType 0: use MediaSurfaceEncoder, 1: use MediaVideoEncoder, 2: use MediaVideoBufferEncoder - * @param width - * @param height - * @return - */ - public static final UVCCameraHandler createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height) { - - return createHandler(parent, cameraView, encoderType, width, height, UVCCamera.FRAME_FORMAT_MJPEG, UVCCamera.DEFAULT_BANDWIDTH); - } - - /** - * create UVCCameraHandler, default bandwidth - * @param parent - * @param cameraView - * @param encoderType 0: use MediaSurfaceEncoder, 1: use MediaVideoEncoder, 2: use MediaVideoBufferEncoder - * @param width - * @param height - * @param format either UVCCamera.FRAME_FORMAT_YUYV(0) or UVCCamera.FRAME_FORMAT_MJPEG(1) - * @return - */ - public static final UVCCameraHandler createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height, final int format) { - - return createHandler(parent, cameraView, encoderType, width, height, format, UVCCamera.DEFAULT_BANDWIDTH); - } - - /** - * create UVCCameraHandler - * @param parent - * @param cameraView - * @param encoderType 0: use MediaSurfaceEncoder, 1: use MediaVideoEncoder, 2: use MediaVideoBufferEncoder - * @param width - * @param height - * @param format either UVCCamera.FRAME_FORMAT_YUYV(0) or UVCCamera.FRAME_FORMAT_MJPEG(1) - * @param bandwidthFactor - * @return - */ - public static final UVCCameraHandler createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height, final int format, final float bandwidthFactor) { - - final CameraThread thread = new CameraThread(UVCCameraHandler.class, parent, cameraView, encoderType, width, height, format, bandwidthFactor); - thread.start(); - return (UVCCameraHandler)thread.getHandler(); - } - - protected UVCCameraHandler(final CameraThread thread) { - super(thread); - } - - @Override - public void startPreview(final Object surface) { - super.startPreview(surface); - } - -// @Override -// public void captureStill() { -// super.captureStill(); -// } - - @Override - public void captureStill(final String path,OnCaptureListener listener) { - super.captureStill(path,listener); - } - - @Override - public void startCameraFoucs() { - super.startCameraFoucs(); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandlerMultiSurface.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandlerMultiSurface.java deleted file mode 100644 index d8df6c26d1..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandlerMultiSurface.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.common; - -import android.app.Activity; -import android.view.Surface; - -import com.serenegiant.glutils.RendererHolder; -import com.serenegiant.usb.UVCCamera; -import com.serenegiant.usb.widget.CameraViewInterface; - -import java.io.FileNotFoundException; - -public class UVCCameraHandlerMultiSurface extends AbstractUVCCameraHandler { - /** - * create UVCCameraHandlerMultiSurface, use MediaVideoEncoder, try MJPEG, default bandwidth - * @param parent - * @param cameraView - * @param width - * @param height - * @return - */ - public static final UVCCameraHandlerMultiSurface createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int width, final int height) { - - return createHandler(parent, cameraView, 1, width, height, UVCCamera.FRAME_FORMAT_MJPEG, UVCCamera.DEFAULT_BANDWIDTH); - } - - /** - * create UVCCameraHandlerMultiSurface, use MediaVideoEncoder, try MJPEG - * @param parent - * @param cameraView - * @param width - * @param height - * @param bandwidthFactor - * @return - */ - public static final UVCCameraHandlerMultiSurface createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int width, final int height, final float bandwidthFactor) { - - return createHandler(parent, cameraView, 1, width, height, UVCCamera.FRAME_FORMAT_MJPEG, bandwidthFactor); - } - - /** - * create UVCCameraHandlerMultiSurface, try MJPEG, default bandwidth - * @param parent - * @param cameraView - * @param encoderType - * @param width - * @param height - * @return - */ - public static final UVCCameraHandlerMultiSurface createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height) { - - return createHandler(parent, cameraView, encoderType, width, height, UVCCamera.FRAME_FORMAT_MJPEG, UVCCamera.DEFAULT_BANDWIDTH); - } - - /** - * create UVCCameraHandlerMultiSurface, default bandwidth - * @param parent - * @param cameraView - * @param encoderType - * @param width - * @param height - * @param format - * @return - */ - public static final UVCCameraHandlerMultiSurface createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height, final int format) { - - return createHandler(parent, cameraView, encoderType, width, height, format, UVCCamera.DEFAULT_BANDWIDTH); - } - - /** - * create UVCCameraHandlerMultiSurface - * @param parent - * @param cameraView - * @param encoderType 0: use MediaSurfaceEncoder, 1: use MediaVideoEncoder, 2: use MediaVideoBufferEncoder - * @param width - * @param height - * @param format either UVCCamera.FRAME_FORMAT_YUYV(0) or UVCCamera.FRAME_FORMAT_MJPEG(1) - * @param bandwidthFactor - * @return - */ - public static final UVCCameraHandlerMultiSurface createHandler( - final Activity parent, final CameraViewInterface cameraView, - final int encoderType, final int width, final int height, final int format, final float bandwidthFactor) { - - final CameraThread thread = new CameraThread(UVCCameraHandlerMultiSurface.class, parent, cameraView, encoderType, width, height, format, bandwidthFactor); - thread.start(); - return (UVCCameraHandlerMultiSurface)thread.getHandler(); - } - - private RendererHolder mRendererHolder; - protected UVCCameraHandlerMultiSurface(final CameraThread thread) { - super(thread); - mRendererHolder = new RendererHolder(thread.getWidth(), thread.getHeight(), null); - } - - public synchronized void release() { - if (mRendererHolder != null) { - mRendererHolder.release(); - mRendererHolder = null; - } - super.release(); - } - - public synchronized void resize(final int width, final int height) { - super.resize(width, height); - if (mRendererHolder != null) { - mRendererHolder.resize(width, height); - } - } - - public synchronized void startPreview() { - checkReleased(); - if (mRendererHolder != null) { - super.startPreview(mRendererHolder.getSurface()); - } else { - throw new IllegalStateException(); - } - } - - public synchronized void addSurface(final int surfaceId, final Surface surface, final boolean isRecordable) { - checkReleased(); - mRendererHolder.addSurface(surfaceId, surface, isRecordable); - } - - public synchronized void removeSurface(final int surfaceId) { - if (mRendererHolder != null) { - mRendererHolder.removeSurface(surfaceId); - } - } - -// @Override -// public void captureStill() { -// checkReleased(); -// super.captureStill(); -// } - - @Override - public void captureStill(final String path,OnCaptureListener listener) { - checkReleased(); - post(new Runnable() { - @Override - public void run() { - synchronized (UVCCameraHandlerMultiSurface.this) { - if (mRendererHolder != null) { - try { - mRendererHolder.captureStill(path); - updateMedia(path); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } - } - }); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IAudioEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IAudioEncoder.java deleted file mode 100644 index 9a0c0bdb7e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IAudioEncoder.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.encoder; - -public interface IAudioEncoder { -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IVideoEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IVideoEncoder.java deleted file mode 100644 index 7b8429d262..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/IVideoEncoder.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.encoder; - -public interface IVideoEncoder { - public boolean frameAvailableSoon(); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaAudioEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaAudioEncoder.java deleted file mode 100644 index 3246364cff..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaAudioEncoder.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.encoder; - -import android.media.AudioFormat; -import android.media.AudioRecord; -import android.media.MediaCodec; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; -import android.media.MediaFormat; -import android.media.MediaRecorder; -import android.util.Log; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -public class MediaAudioEncoder extends MediaEncoder implements IAudioEncoder { - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "MediaAudioEncoder"; - - private static final String MIME_TYPE = "audio/mp4a-latm"; - public static final int SAMPLE_RATE = 44100; // 44.1[KHz] is only setting guaranteed to be available on all devices. - private static final int BIT_RATE = 64000; - public static final int SAMPLES_PER_FRAME = 1024; // AAC, bytes/frame/channel - public static final int FRAMES_PER_BUFFER = 25; // AAC, frame/buffer/sec - - private AudioThread mAudioThread = null; - - public MediaAudioEncoder(final MediaMuxerWrapper muxer, final MediaEncoderListener listener) { - super(muxer, listener); - } - - @Override - protected void prepare() throws IOException { - if (DEBUG) Log.v(TAG, "prepare:"); - mTrackIndex = -1; - mMuxerStarted = mIsEOS = false; - // prepare MediaCodec for AAC encoding of audio data from inernal mic. - final MediaCodecInfo audioCodecInfo = selectAudioCodec(MIME_TYPE); - if (audioCodecInfo == null) { - Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); - return; - } - if (DEBUG) Log.i(TAG, "selected codec: " + audioCodecInfo.getName()); - - final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, 1); - audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); - audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_MONO); - audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); - audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); -// audioFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length()); -// audioFormat.setLong(MediaFormat.KEY_DURATION, (long)durationInMs ); - if (DEBUG) Log.i(TAG, "format: " + audioFormat); - mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); - mMediaCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - mMediaCodec.start(); - if (DEBUG) Log.i(TAG, "prepare finishing"); - if (mListener != null) { - try { - mListener.onPrepared(this); - } catch (final Exception e) { - Log.e(TAG, "prepare:", e); - } - } - } - - @Override - protected void startRecording() { - super.startRecording(); - // create and execute audio capturing thread using internal mic - if (mAudioThread == null) { - mAudioThread = new AudioThread(); - mAudioThread.start(); - } - } - - @Override - protected void release() { - mAudioThread = null; - super.release(); - } - - private static final int[] AUDIO_SOURCES = new int[] { - MediaRecorder.AudioSource.DEFAULT, - MediaRecorder.AudioSource.MIC, - MediaRecorder.AudioSource.CAMCORDER, - }; - - /** - * Thread to capture audio data from internal mic as uncompressed 16bit PCM data - * and write them to the MediaCodec encoder - */ - private class AudioThread extends Thread { - @Override - public void run() { - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); // THREAD_PRIORITY_URGENT_AUDIO - int cnt = 0; - final int min_buffer_size = AudioRecord.getMinBufferSize( - SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); - int buffer_size = SAMPLES_PER_FRAME * FRAMES_PER_BUFFER; - if (buffer_size < min_buffer_size) - buffer_size = ((min_buffer_size / SAMPLES_PER_FRAME) + 1) * SAMPLES_PER_FRAME * 2; - final ByteBuffer buf = ByteBuffer.allocateDirect(SAMPLES_PER_FRAME).order(ByteOrder.nativeOrder()); - AudioRecord audioRecord = null; - for (final int src: AUDIO_SOURCES) { - try { - audioRecord = new AudioRecord(src, - SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffer_size); - if (audioRecord != null) { - if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { - audioRecord.release(); - audioRecord = null; - } - } - } catch (final Exception e) { - audioRecord = null; - } - if (audioRecord != null) { - break; - } - } - if (audioRecord != null) { - try { - if (mIsCapturing) { - if (DEBUG) Log.v(TAG, "AudioThread:start audio recording"); - int readBytes; - audioRecord.startRecording(); - try { - for ( ; mIsCapturing && !mRequestStop && !mIsEOS ; ) { - // read audio data from internal mic - buf.clear(); - try { - readBytes = audioRecord.read(buf, SAMPLES_PER_FRAME); - } catch (final Exception e) { - break; - } - if (readBytes > 0) { - // set audio data to encoder - buf.position(readBytes); - buf.flip(); - encode(buf, readBytes, getPTSUs()); - frameAvailableSoon(); - cnt++; - } - } - if (cnt > 0) { - frameAvailableSoon(); - } - } finally { - audioRecord.stop(); - } - } - } catch (final Exception e) { - Log.e(TAG, "AudioThread#run", e); - } finally { - audioRecord.release(); - } - } - if (cnt == 0) { - for (int i = 0; mIsCapturing && (i < 5); i++) { - buf.position(SAMPLES_PER_FRAME); - buf.flip(); - try { - encode(buf, SAMPLES_PER_FRAME, getPTSUs()); - frameAvailableSoon(); - } catch (final Exception e) { - break; - } - synchronized(this) { - try { - wait(50); - } catch (final InterruptedException e) { - - } - } - } - } - if (DEBUG) Log.v(TAG, "AudioThread:finished"); - } - } - - /** - * select the first codec that match a specific MIME type - * @param mimeType - * @return - */ - private static final MediaCodecInfo selectAudioCodec(final String mimeType) { - if (DEBUG) Log.v(TAG, "selectAudioCodec:"); - - MediaCodecInfo result = null; - // get the list of available codecs - final int numCodecs = MediaCodecList.getCodecCount(); -LOOP: for (int i = 0; i < numCodecs; i++) { - final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - if (!codecInfo.isEncoder()) { // skipp decoder - continue; - } - final String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (DEBUG) Log.i(TAG, "supportedType:" + codecInfo.getName() + ",MIME=" + types[j]); - if (types[j].equalsIgnoreCase(mimeType)) { - if (result == null) { - result = codecInfo; - break LOOP; - } - } - } - } - return result; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java deleted file mode 100644 index d11770bdc5..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java +++ /dev/null @@ -1,570 +0,0 @@ -package com.serenegiant.usb.encoder; - -import android.media.MediaCodec; -import android.media.MediaFormat; -import android.os.Build; -import android.os.Environment; -import android.util.Log; - - -import com.mogo.usbcamera.utils.FileUtils; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; - -public abstract class MediaEncoder implements Runnable { - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "MediaEncoder"; - public static final int TYPE_AUDIO = 0; // 音频数据 - public static final int TYPE_VIDEO = 1; // 视频数据 - - protected static final int TIMEOUT_USEC = 10000; // 10毫秒 - protected static final int MSG_FRAME_AVAILABLE = 1; - protected static final int MSG_STOP_RECORDING = 9; - private long lastPush; - private long millisPerframe; - private boolean isExit; - - public interface MediaEncoderListener { - void onPrepared(MediaEncoder encoder); - void onStopped(MediaEncoder encoder); - // 音频或视频流,type=0为音频,type=1为视频 - void onEncodeResult(byte[] data, int offset, - int length, long timestamp, int type); - } - - protected final Object mSync = new Object(); - /** - * Flag that indicate this encoder is capturing now. - */ - protected volatile boolean mIsCapturing; - /** - * Flag that indicate the frame data will be available soon. - */ - private int mRequestDrain; - /** - * Flag to request stop capturing - */ - protected volatile boolean mRequestStop; - /** - * Flag that indicate encoder received EOS(End Of Stream) - */ - protected boolean mIsEOS; - /** - * Flag the indicate the muxer is running - */ - protected boolean mMuxerStarted; - /** - * Track Number - */ - protected int mTrackIndex; - /** - * MediaCodec instance for encoding - */ - protected MediaCodec mMediaCodec; // API >= 16(Android4.1.2) - /** - * Weak refarence of MediaMuxerWarapper instance - */ - protected final WeakReference mWeakMuxer; - /** - * BufferInfo instance for dequeuing - */ - private MediaCodec.BufferInfo mBufferInfo; // API >= 16(Android4.1.2) - - protected final MediaEncoderListener mListener; - - /** - * There are 13 supported frequencies by ADTS. - **/ - public static final int[] AUDIO_SAMPLING_RATES = { 96000, // 0 - 88200, // 1 - 64000, // 2 - 48000, // 3 - 44100, // 4 - 32000, // 5 - 24000, // 6 - 22050, // 7 - 16000, // 8 - 12000, // 9 - 11025, // 10 - 8000, // 11 - 7350, // 12 - -1, // 13 - -1, // 14 - -1, // 15 - }; - - public MediaEncoder(final MediaMuxerWrapper muxer, final MediaEncoderListener listener) { - if (listener == null) throw new NullPointerException("MediaEncoderListener is null"); - if (muxer == null) throw new NullPointerException("MediaMuxerWrapper is null"); - mWeakMuxer = new WeakReference(muxer); - muxer.addEncoder(this); - mListener = listener; - synchronized (mSync) { - // create BufferInfo here for effectiveness(to reduce GC) - mBufferInfo = new MediaCodec.BufferInfo(); - // wait for starting thread - new Thread(this, getClass().getSimpleName()).start(); - try { - mSync.wait(); - } catch (final InterruptedException e) { - } - } - } - - public String getOutputPath() { - final MediaMuxerWrapper muxer = mWeakMuxer.get(); - return muxer != null ? muxer.getOutputPath() : null; - } - - /** - * the method to indicate frame data is soon available or already available - * @return return true if encoder is ready to encod. - */ - public boolean frameAvailableSoon() { -// if (DEBUG) Log.v(TAG, "frameAvailableSoon"); - synchronized (mSync) { - if (!mIsCapturing || mRequestStop) { - return false; - } - mRequestDrain++; - mSync.notifyAll(); - } - return true; - } - - /** - * encoding loop on private thread - */ - @Override - public void run() { -// android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); - synchronized (mSync) { - mRequestStop = false; - mRequestDrain = 0; - mSync.notify(); - } - final boolean isRunning = true; - boolean localRequestStop; - boolean localRequestDrain; - boolean localIsNotExit; - // 创建h264 - FileUtils.createfile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test222.h264"); - - while (isRunning) { - synchronized (mSync) { - localRequestStop = mRequestStop; - localRequestDrain = (mRequestDrain > 0); - if (localRequestDrain) - mRequestDrain--; - } - if (localRequestStop) { - drain(); - // request stop recording - signalEndOfInputStream(); - // process output data again for EOS signale - drain(); - // release all related objects - release(); - break; - } - if (localRequestDrain) { - drain(); - } else { - synchronized (mSync) { - try { - mSync.wait(); - } catch (final InterruptedException e) { - break; - } - } - } - } // end of while - synchronized (mSync) { - mRequestStop = true; - mIsCapturing = false; - } - FileUtils.releaseFile(); - } - - /* - * prepareing method for each sub class - * this method should be implemented in sub class, so set this as abstract method - * @throws IOException - */ - /*package*/ abstract void prepare() throws IOException; - - /*package*/ void startRecording() { - if (DEBUG) Log.v(TAG, "startRecording"); - synchronized (mSync) { - mIsCapturing = true; - mRequestStop = false; - isExit = false; - mSync.notifyAll(); - } - } - - /** - * the method to request stop encoding - */ - /*package*/ void stopRecording() { - if (DEBUG) Log.v(TAG, "stopRecording"); - synchronized (mSync) { - if (!mIsCapturing || mRequestStop) { - return; - } - mRequestStop = true; // for rejecting newer frame - isExit = true; - mSync.notifyAll(); - // We can not know when the encoding and writing finish. - // so we return immediately after request to avoid delay of caller thread - } - } - -//******************************************************************************** -//******************************************************************************** - /** - * Release all releated objects - */ - protected void release() { - if (DEBUG) Log.d(TAG, "release:"); - try { - mListener.onStopped(this); - } catch (final Exception e) { - Log.e(TAG, "failed onStopped", e); - } - mIsCapturing = false; - if (mMediaCodec != null) { - try { - mMediaCodec.stop(); - mMediaCodec.release(); - mMediaCodec = null; - } catch (final Exception e) { - Log.e(TAG, "failed releasing MediaCodec", e); - } - } - if (mMuxerStarted) { - final MediaMuxerWrapper muxer = mWeakMuxer.get(); - if (muxer != null) { - try { - muxer.stop(); - } catch (final Exception e) { - Log.e(TAG, "failed stopping muxer", e); - } - } - } - mBufferInfo = null; - } - - protected void signalEndOfInputStream() { - if (DEBUG) Log.d(TAG, "sending EOS to encoder"); - // signalEndOfInputStream is only avairable for video encoding with surface - // and equivalent sending a empty buffer with BUFFER_FLAG_END_OF_STREAM flag. -// mMediaCodec.signalEndOfInputStream(); // API >= 18 - encode((byte[])null, 0, getPTSUs()); - } - - /** - * Method to set byte array to the MediaCodec encoder - * @param buffer - * @param length length of byte array, zero means EOS. - * @param presentationTimeUs - */ - @SuppressWarnings("deprecation") - protected void encode(final byte[] buffer, final int length, final long presentationTimeUs) { - if (!mIsCapturing) return; - int ix = 0, sz; - final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers(); - while (mIsCapturing && ix < length) { - final int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_USEC); - if (inputBufferIndex >= 0) { - final ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; - inputBuffer.clear(); - sz = inputBuffer.remaining(); - sz = (ix + sz < length) ? sz : length - ix; - if (sz > 0 && (buffer != null)) { - inputBuffer.put(buffer, ix, sz); - } - ix += sz; -// if (DEBUG) Log.v(TAG, "encode:queueInputBuffer"); - if (length <= 0) { - // send EOS - mIsEOS = true; - if (DEBUG) Log.i(TAG, "send BUFFER_FLAG_END_OF_STREAM"); - mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, - presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); - break; - } else { - mMediaCodec.queueInputBuffer(inputBufferIndex, 0, sz, - presentationTimeUs, 0); - } - } else if (inputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { - // wait for MediaCodec encoder is ready to encode - // nothing to do here because MediaCodec#dequeueInputBuffer(TIMEOUT_USEC) - // will wait for maximum TIMEOUT_USEC(10msec) on each call - } - } - } - - protected void encode(ByteBuffer yuvBuffer,int len){ - if (!mIsCapturing) return; - try { - if (lastPush == 0) { - lastPush = System.currentTimeMillis(); - } - long time = System.currentTimeMillis() - lastPush; - if (time >= 0) { - time = millisPerframe - time; - if (time > 0) - Thread.sleep(time / 2); - } - final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers(); - int bufferIndex = -1; - try{ - bufferIndex = mMediaCodec.dequeueInputBuffer(0); - }catch (IllegalStateException e){ - e.printStackTrace(); - } - if (bufferIndex >= 0) { - ByteBuffer mBuffer; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mBuffer = mMediaCodec.getInputBuffer(bufferIndex); - } else { - mBuffer = inputBuffers[bufferIndex]; - } - byte[] yuvData = new byte[yuvBuffer.capacity()]; - yuvBuffer.get(yuvData); - - mBuffer.clear(); - mBuffer.put(yuvData); - mBuffer.clear(); - mMediaCodec.queueInputBuffer(bufferIndex, 0, yuvData.length, System.nanoTime() / 1000, MediaCodec.BUFFER_FLAG_KEY_FRAME); - } - lastPush = System.currentTimeMillis(); - } catch (InterruptedException ex) { - ex.printStackTrace(); - } - } - - /** - * Method to set ByteBuffer to the MediaCodec encoder - * @param buffer null means EOS - * @param presentationTimeUs - */ - @SuppressWarnings("deprecation") - protected void encode(final ByteBuffer buffer, final int length, final long presentationTimeUs) { -// if (DEBUG) Log.v(TAG, "encode:buffer=" + buffer); - if (!mIsCapturing) return; - int ix = 0, sz; - final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers(); - while (mIsCapturing && ix < length) { - final int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_USEC); - if (inputBufferIndex >= 0) { - final ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; - inputBuffer.clear(); - sz = inputBuffer.remaining(); - sz = (ix + sz < length) ? sz : length - ix; - if (sz > 0 && (buffer != null)) { - buffer.position(ix + sz); - buffer.flip(); - inputBuffer.put(buffer); - } - ix += sz; -// if (DEBUG) Log.v(TAG, "encode:queueInputBuffer"); - if (length <= 0) { - // send EOS - mIsEOS = true; - if (DEBUG) Log.i(TAG, "send BUFFER_FLAG_END_OF_STREAM"); - mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, - presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); - break; - } else { - mMediaCodec.queueInputBuffer(inputBufferIndex, 0, sz, - presentationTimeUs, 0); - } - } else if (inputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { - // wait for MediaCodec encoder is ready to encode - // nothing to do here because MediaCodec#dequeueInputBuffer(TIMEOUT_USEC) - // will wait for maximum TIMEOUT_USEC(10msec) on each call - } - } - } - - ByteBuffer mBuffer = ByteBuffer.allocate(10240); - - /** - * drain encoded data and write them to muxer - */ - @SuppressWarnings("deprecation") - protected void drain() { - if (mMediaCodec == null) - return; - ByteBuffer[] encoderOutputBuffers = mMediaCodec.getOutputBuffers(); - int encoderStatus, count = 0; - final MediaMuxerWrapper muxer = mWeakMuxer.get(); - if (muxer == null) { - Log.w(TAG, "muxer is unexpectedly null"); - return; - } - byte[] mPpsSps = new byte[0]; - byte[] h264 = new byte[640 * 480]; - - while (mIsCapturing) { - encoderStatus = mMediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC); - if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { - // 等待 TIMEOUT_USEC x 5 = 50毫秒 - // 如果还没有数据,终止循环 - if (!mIsEOS) { - if (++count > 5) - break; - } - } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { - encoderOutputBuffers = mMediaCodec.getOutputBuffers(); - } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - if (mMuxerStarted) { - throw new RuntimeException("format changed twice"); - } - final MediaFormat format = mMediaCodec.getOutputFormat(); - mTrackIndex = muxer.addTrack(format); - mMuxerStarted = true; - if (!muxer.start()) { - synchronized (muxer) { - while (!muxer.isStarted()) - try { - muxer.wait(100); - } catch (final InterruptedException e) { - break; - } - } - } - } else if (encoderStatus < 0) { - if (DEBUG) Log.w(TAG, "drain:unexpected result from encoder#dequeueOutputBuffer: " + encoderStatus); - } else { - ByteBuffer encodedData; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - encodedData = mMediaCodec.getOutputBuffer(encoderStatus); - } else { - encodedData = encoderOutputBuffers[encoderStatus]; - } - encodedData.position(mBufferInfo.offset); - encodedData.limit(mBufferInfo.offset + mBufferInfo.size); - -// final ByteBuffer encodedData = encoderOutputBuffers[encoderStatus]; - if (encodedData == null) { - throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null"); - } - // BUFFER_FLAG_CODEC_CONFIG标志 - // BufferInfo清零 - if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { - if (DEBUG) Log.d(TAG, "drain:BUFFER_FLAG_CODEC_CONFIG"); - mBufferInfo.size = 0; - } - // BUFFER_FLAG_END_OF_STREAM标志 - // 流结束,终止循环 - if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { - mMuxerStarted = mIsCapturing = false; - break; - } - // 有效编码数据流 - if (mBufferInfo.size != 0) { - count = 0; - if (!mMuxerStarted) { - throw new RuntimeException("drain:muxer hasn't started"); - } - // 写入音频流或视频流到混合器 - mBufferInfo.presentationTimeUs = getPTSUs(); - muxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo); - prevOutputPTSUs = mBufferInfo.presentationTimeUs; - - // 推流,获取h.264数据流 - // mTrackIndex=0 视频;mTrackIndex=1 音频 - if(mTrackIndex == 0) { - encodedData.position(mBufferInfo.offset); - encodedData.limit(mBufferInfo.offset + mBufferInfo.size); - boolean sync = false; - if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {// sps - sync = (mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - if (!sync) { - byte[] temp = new byte[mBufferInfo.size]; - encodedData.get(temp); - mPpsSps = temp; - mMediaCodec.releaseOutputBuffer(encoderStatus, false); - continue; - } else { - mPpsSps = new byte[0]; - } - } - sync |= (mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - int len = mPpsSps.length + mBufferInfo.size; - if (len > h264.length) { - h264 = new byte[len]; - } - if (sync) { - System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length); - encodedData.get(h264, mPpsSps.length, mBufferInfo.size); - if(mListener != null) { - mListener.onEncodeResult(h264, 0,mPpsSps.length + mBufferInfo.size, - mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); - } - // 保存数据流到文件 - FileUtils.putFileStream(h264, 0,mPpsSps.length + mBufferInfo.size); - } else { - encodedData.get(h264, 0, mBufferInfo.size); - if(mListener != null) { - mListener.onEncodeResult(h264, 0,mBufferInfo.size, - mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); - } - FileUtils.putFileStream(h264, 0,mBufferInfo.size); - } - } else if(mTrackIndex == 1){ - mBuffer.clear(); - encodedData.get(mBuffer.array(), 7, mBufferInfo.size); - encodedData.clear(); - mBuffer.position(7 + mBufferInfo.size); - addADTStoPacket(mBuffer.array(), mBufferInfo.size + 7); - mBuffer.flip(); - if(mListener != null){ - mListener.onEncodeResult(mBuffer.array(),0, mBufferInfo.size + 7, - mBufferInfo.presentationTimeUs / 1000,TYPE_AUDIO); - } - } - } - // 释放输出缓存,将其还给编码器 - mMediaCodec.releaseOutputBuffer(encoderStatus, false); - } - } - } - - private void addADTStoPacket(byte[] packet, int packetLen) { - packet[0] = (byte) 0xFF; - packet[1] = (byte) 0xF1; - packet[2] = (byte) (((2 - 1) << 6) + (getSamplingRateIndex() << 2) + (1 >> 2)); - packet[3] = (byte) (((1 & 3) << 6) + (packetLen >> 11)); - packet[4] = (byte) ((packetLen & 0x7FF) >> 3); - packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F); - packet[6] = (byte) 0xFC; - } - - private int getSamplingRateIndex(){ - int mSamplingRateIndex = -1; - for (int i=0;i < AUDIO_SAMPLING_RATES.length; i++) { - if (AUDIO_SAMPLING_RATES[i] == MediaAudioEncoder.SAMPLE_RATE) { - mSamplingRateIndex = i; - break; - } - } - return mSamplingRateIndex; - } - - - private long prevOutputPTSUs = 0; - - protected long getPTSUs() { - long result = System.nanoTime() / 1000L; - if (result < prevOutputPTSUs) - result = (prevOutputPTSUs - result) + result; - return result; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java deleted file mode 100644 index f13982674b..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.serenegiant.usb.encoder; - -import android.annotation.TargetApi; -import android.media.MediaCodec; -import android.media.MediaFormat; -import android.media.MediaMuxer; -import android.os.Build; -import android.os.Environment; -import android.text.TextUtils; -import android.util.Log; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.text.SimpleDateFormat; -import java.util.GregorianCalendar; -import java.util.Locale; - -public class MediaMuxerWrapper { - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "MediaMuxerWrapper"; - - private static final String DIR_NAME = "USBCameraTest"; - private static final SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); - - private String mOutputPath; - private final MediaMuxer mMediaMuxer; // API >= 18 - private int mEncoderCount, mStatredCount; - private boolean mIsStarted; - private MediaEncoder mVideoEncoder, mAudioEncoder; - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) - public MediaMuxerWrapper(String path) throws IOException { - try { - // 保存到自定义路径还是手机默认Movies路径 - if (TextUtils.isEmpty(path)) - mOutputPath = getCaptureFile(Environment.DIRECTORY_MOVIES, ".mp4").toString(); - mOutputPath = path; - - } catch (final NullPointerException e) { - throw new RuntimeException("This app has no permission of writing external storage"); - } - mMediaMuxer = new MediaMuxer(mOutputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); - mEncoderCount = mStatredCount = 0; - mIsStarted = false; - } - - public String getOutputPath() { - return mOutputPath; - } - - public void prepare() throws IOException { - if (mVideoEncoder != null) - mVideoEncoder.prepare(); - if (mAudioEncoder != null) - mAudioEncoder.prepare(); - } - - public void startRecording() { - if (mVideoEncoder != null) - mVideoEncoder.startRecording(); - if (mAudioEncoder != null) - mAudioEncoder.startRecording(); - } - - public void stopRecording() { - if (mVideoEncoder != null) - mVideoEncoder.stopRecording(); - mVideoEncoder = null; - if (mAudioEncoder != null) - mAudioEncoder.stopRecording(); - mAudioEncoder = null; - } - - public synchronized boolean isStarted() { - return mIsStarted; - } - -//********************************************************************** -//********************************************************************** - /** - * assign encoder to this calss. this is called from encoder. - * @param encoder instance of MediaVideoEncoder or MediaAudioEncoder - */ - /*package*/ void addEncoder(final MediaEncoder encoder) { - if (encoder instanceof MediaVideoEncoder) { - if (mVideoEncoder != null) - throw new IllegalArgumentException("Video encoder already added."); - mVideoEncoder = encoder; - } else if (encoder instanceof MediaSurfaceEncoder) { - if (mVideoEncoder != null) - throw new IllegalArgumentException("Video encoder already added."); - mVideoEncoder = encoder; - } else if (encoder instanceof MediaVideoBufferEncoder) { - if (mVideoEncoder != null) - throw new IllegalArgumentException("Video encoder already added."); - mVideoEncoder = encoder; - } else if (encoder instanceof MediaAudioEncoder) { - if (mAudioEncoder != null) - throw new IllegalArgumentException("Video encoder already added."); - mAudioEncoder = encoder; - } else - throw new IllegalArgumentException("unsupported encoder"); - mEncoderCount = (mVideoEncoder != null ? 1 : 0) + (mAudioEncoder != null ? 1 : 0); - } - - /** - * request start recording from encoder - * @return true when muxer is ready to write - */ - /*package*/ synchronized boolean start() { - if (DEBUG) Log.v(TAG, "start:"); - mStatredCount++; - if ((mEncoderCount > 0) && (mStatredCount == mEncoderCount)) { - mMediaMuxer.start(); - mIsStarted = true; - notifyAll(); - if (DEBUG) Log.v(TAG, "MediaMuxer started:"); - } - return mIsStarted; - } - - /** - * request stop recording from encoder when encoder received EOS - */ - /*package*/ synchronized void stop() { - if (DEBUG) Log.v(TAG, "stop:mStatredCount=" + mStatredCount); - mStatredCount--; - if ((mEncoderCount > 0) && (mStatredCount <= 0)) { - try { - mMediaMuxer.stop(); - } catch (final Exception e) { - Log.w(TAG, e); - } - mIsStarted = false; - if (DEBUG) Log.v(TAG, "MediaMuxer stopped:"); - } - } - - /** - * assign encoder to muxer - * @param format - * @return minus value indicate error - */ - /*package*/ synchronized int addTrack(final MediaFormat format) { - if (mIsStarted) - throw new IllegalStateException("muxer already started"); - final int trackIx = mMediaMuxer.addTrack(format); - if (DEBUG) Log.i(TAG, "addTrack:trackNum=" + mEncoderCount + ",trackIx=" + trackIx + ",format=" + format); - return trackIx; - } - - /** - * write encoded data to muxer - * @param trackIndex - * @param byteBuf - * @param bufferInfo - */ - /*package*/ synchronized void writeSampleData(final int trackIndex, final ByteBuffer byteBuf, final MediaCodec.BufferInfo bufferInfo) { - if (mStatredCount > 0) - mMediaMuxer.writeSampleData(trackIndex, byteBuf, bufferInfo); - } - -//********************************************************************** -//********************************************************************** - /** - * generate output file - * @param type Environment.DIRECTORY_MOVIES / Environment.DIRECTORY_DCIM etc. - * @param ext .mp4(.m4a for audio) or .png - * @return return null when this app has no writing permission to external storage. - */ - public static final File getCaptureFile(final String type, final String ext) { - final File dir = new File(Environment.getExternalStoragePublicDirectory(type), DIR_NAME); - Log.d(TAG, "path=" + dir.toString()); - dir.mkdirs(); - if (dir.canWrite()) { - return new File(dir, getDateTimeString() + ext); - } - return null; - } - - /** - * get current date and time as String - * @return - */ - private static final String getDateTimeString() { - final GregorianCalendar now = new GregorianCalendar(); - return mDateTimeFormat.format(now.getTime()); - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaSurfaceEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaSurfaceEncoder.java deleted file mode 100644 index 47eb607e08..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaSurfaceEncoder.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.encoder; - -import android.media.MediaCodec; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; -import android.media.MediaFormat; -import android.util.Log; -import android.view.Surface; - -import java.io.IOException; - -public class MediaSurfaceEncoder extends MediaEncoder implements IVideoEncoder { - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "MediaSurfaceEncoder"; - - private static final String MIME_TYPE = "video/avc"; - // parameters for recording - private final int mWidth, mHeight; - private static final int FRAME_RATE = 15; - private static final float BPP = 0.50f; - - private Surface mSurface; - - public MediaSurfaceEncoder(final MediaMuxerWrapper muxer, final int width, final int height, final MediaEncoderListener listener) { - super(muxer, listener); - if (DEBUG) Log.i(TAG, "MediaVideoEncoder: "); - mWidth = width; - mHeight = height; - } - - /** - * Returns the encoder's input surface. - */ - public Surface getInputSurface() { - return mSurface; - } - - @Override - protected void prepare() throws IOException { - if (DEBUG) Log.i(TAG, "prepare: "); - mTrackIndex = -1; - mMuxerStarted = mIsEOS = false; - - final MediaCodecInfo videoCodecInfo = selectVideoCodec(MIME_TYPE); - if (videoCodecInfo == null) { - Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); - return; - } - if (DEBUG) Log.i(TAG, "selected codec: " + videoCodecInfo.getName()); - - final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight); - format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); // API >= 18 - format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); - format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); - format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); - if (DEBUG) Log.i(TAG, "format: " + format); - - mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); - mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - // get Surface for encoder input - // this method only can call between #configure and #start - mSurface = mMediaCodec.createInputSurface(); // API >= 18 - mMediaCodec.start(); - if (DEBUG) Log.i(TAG, "prepare finishing"); - if (mListener != null) { - try { - mListener.onPrepared(this); - } catch (final Exception e) { - Log.e(TAG, "prepare:", e); - } - } - } - - @Override - protected void release() { - if (DEBUG) Log.i(TAG, "release:"); - if (mSurface != null) { - mSurface.release(); - mSurface = null; - } - super.release(); - } - - private int calcBitRate() { - final int bitrate = (int)(BPP * FRAME_RATE * mWidth * mHeight); - Log.i(TAG, String.format("bitrate=%5.2f[Mbps]", bitrate / 1024f / 1024f)); - return bitrate; - } - - /** - * select the first codec that match a specific MIME type - * @param mimeType - * @return null if no codec matched - */ - protected static final MediaCodecInfo selectVideoCodec(final String mimeType) { - if (DEBUG) Log.v(TAG, "selectVideoCodec:"); - - // get the list of available codecs - final int numCodecs = MediaCodecList.getCodecCount(); - for (int i = 0; i < numCodecs; i++) { - final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - - if (!codecInfo.isEncoder()) { // skipp decoder - continue; - } - // select first codec that match a specific MIME type and color format - final String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (types[j].equalsIgnoreCase(mimeType)) { - if (DEBUG) Log.i(TAG, "codec:" + codecInfo.getName() + ",MIME=" + types[j]); - final int format = selectColorFormat(codecInfo, mimeType); - if (format > 0) { - return codecInfo; - } - } - } - } - return null; - } - - /** - * select color format available on specific codec and we can use. - * @return 0 if no colorFormat is matched - */ - protected static final int selectColorFormat(final MediaCodecInfo codecInfo, final String mimeType) { - if (DEBUG) Log.i(TAG, "selectColorFormat: "); - int result = 0; - final MediaCodecInfo.CodecCapabilities caps; - try { - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - caps = codecInfo.getCapabilitiesForType(mimeType); - } finally { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY); - } - int colorFormat; - for (int i = 0; i < caps.colorFormats.length; i++) { - colorFormat = caps.colorFormats[i]; - if (isRecognizedVideoFormat(colorFormat)) { - if (result == 0) - result = colorFormat; - break; - } - } - if (result == 0) - Log.e(TAG, "couldn't find a good color format for " + codecInfo.getName() + " / " + mimeType); - return result; - } - - /** - * color formats that we can use in this class - */ - protected static int[] recognizedFormats; - static { - recognizedFormats = new int[] { -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar, -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar, -// MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, - MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface, - }; - } - - private static final boolean isRecognizedVideoFormat(final int colorFormat) { - if (DEBUG) Log.i(TAG, "isRecognizedVideoFormat:colorFormat=" + colorFormat); - final int n = recognizedFormats != null ? recognizedFormats.length : 0; - for (int i = 0; i < n; i++) { - if (recognizedFormats[i] == colorFormat) { - return true; - } - } - return false; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoBufferEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoBufferEncoder.java deleted file mode 100644 index 40d26bfaa0..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoBufferEncoder.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.encoder; - -import android.media.MediaCodec; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; -import android.media.MediaFormat; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; - -import java.io.IOException; -import java.nio.ByteBuffer; - -public class MediaVideoBufferEncoder extends MediaEncoder implements IVideoEncoder { - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "MediaVideoBufferEncoder"; - - private static final String MIME_TYPE = "video/avc"; - private static final int FRAME_RATE = 15; - private static final float BPP = 0.50f; - - private final int mWidth, mHeight; - protected int mColorFormat; - - public MediaVideoBufferEncoder(final MediaMuxerWrapper muxer, final int width, final int height, final MediaEncoderListener listener) { - super(muxer, listener); - if (DEBUG) Log.i(TAG, "MediaVideoEncoder: "); - mWidth = width; - mHeight = height; - } - - public void encode(final ByteBuffer buffer) { - synchronized (mSync) { - if (!mIsCapturing || mRequestStop) return; - } -// encode(buffer, buffer.capacity(), getPTSUs()); - encode(buffer, buffer.capacity()); - } - - @Override - protected void prepare() throws IOException { - if (DEBUG) Log.i(TAG, "prepare: "); - mTrackIndex = -1; - mMuxerStarted = mIsEOS = false; - - final MediaCodecInfo videoCodecInfo = selectVideoCodec(MIME_TYPE); - if (videoCodecInfo == null) { - Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); - return; - } - if (DEBUG) Log.i(TAG, "selected codec: " + videoCodecInfo.getName()); - - final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight); - format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat); - format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); - format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); - format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); - if (DEBUG) Log.i(TAG, "format: " + format); - - mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); - mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - mMediaCodec.start(); - - Bundle params = new Bundle(); - params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mMediaCodec.setParameters(params); - } - if (DEBUG) Log.i(TAG, "prepare finishing"); - if (mListener != null) { - try { - mListener.onPrepared(this); - } catch (final Exception e) { - Log.e(TAG, "prepare:", e); - } - } - } - - private int calcBitRate() { - final int bitrate = (int)(BPP * FRAME_RATE * mWidth * mHeight); - Log.i(TAG, String.format("bitrate=%5.2f[Mbps]", bitrate / 1024f / 1024f)); - return bitrate; - } - - // 选择第一个与制定MIME类型匹配的编码器 - @SuppressWarnings("deprecation") - protected final MediaCodecInfo selectVideoCodec(final String mimeType) { - if (DEBUG) Log.v(TAG, "selectVideoCodec:"); - - // get the list of available codecs - final int numCodecs = MediaCodecList.getCodecCount(); - for (int i = 0; i < numCodecs; i++) { - final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - - if (!codecInfo.isEncoder()) { // skipp decoder - continue; - } - // select first codec that match a specific MIME type and color format - final String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (types[j].equalsIgnoreCase(mimeType)) { - if (DEBUG) Log.i(TAG, "codec:" + codecInfo.getName() + ",MIME=" + types[j]); - final int format = selectColorFormat(codecInfo, mimeType); - if (format > 0) { - mColorFormat = format; - return codecInfo; - } - } - } - } - return null; - } - - // 选择编码器支持的格式 - protected static final int selectColorFormat(final MediaCodecInfo codecInfo, final String mimeType) { - if (DEBUG) Log.i(TAG, "selectColorFormat: "); - int result = 0; - final MediaCodecInfo.CodecCapabilities caps; - try { - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - caps = codecInfo.getCapabilitiesForType(mimeType); - } finally { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY); - } - int colorFormat; - for (int i = 0; i < caps.colorFormats.length; i++) { - colorFormat = caps.colorFormats[i]; - if (isRecognizedViewoFormat(colorFormat)) { - if (result == 0) - result = colorFormat; - break; - } - } - if (result == 0) - Log.e(TAG, "couldn't find a good color format for " + codecInfo.getName() + " / " + mimeType); - return result; - } - - // YUV颜色格式 - protected static int[] recognizedFormats; - static { - recognizedFormats = new int[] { -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar, - MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar, - MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, -// MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface, - }; - } - - private static final boolean isRecognizedViewoFormat(final int colorFormat) { - if (DEBUG) Log.i(TAG, "isRecognizedViewoFormat:colorFormat=" + colorFormat); - final int n = recognizedFormats != null ? recognizedFormats.length : 0; - for (int i = 0; i < n; i++) { - if (recognizedFormats[i] == colorFormat) { - return true; - } - } - return false; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java deleted file mode 100644 index 59762351b6..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.encoder; - -import android.annotation.TargetApi; -import android.media.MediaCodec; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; -import android.media.MediaFormat; -import android.os.Build; -import android.util.Log; -import android.view.Surface; - -import com.serenegiant.glutils.EGLBase; -import com.serenegiant.glutils.RenderHandler; - -import java.io.IOException; - -/** - * Encode texture images as H.264 video - * using MediaCodec. - * This class render texture images into recording surface - * camera from MediaCodec encoder using Open GL|ES - */ -public class MediaVideoEncoder extends MediaEncoder implements IVideoEncoder { - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "MediaVideoEncoder"; - - private static final String MIME_TYPE = "video/avc"; - // parameters for recording - private final int mWidth, mHeight; - private static final int FRAME_RATE = 15; - private static final float BPP = 0.50f; - - private RenderHandler mRenderHandler; - private Surface mSurface; - - public MediaVideoEncoder(final MediaMuxerWrapper muxer, final int width, final int height, final MediaEncoderListener listener) { - super(muxer, listener); - if (DEBUG) Log.i(TAG, "MediaVideoEncoder: "); - mRenderHandler = RenderHandler.createHandler(TAG); - mWidth = width; - mHeight = height; - } - - public boolean frameAvailableSoon(final float[] tex_matrix) { - boolean result; - if (result = super.frameAvailableSoon()) - mRenderHandler.draw(tex_matrix); - return result; - } - - /** - * This method does not work correctly on this class, - * use #frameAvailableSoon(final float[]) instead - * @return - */ - @Override - public boolean frameAvailableSoon() { - boolean result; - if (result = super.frameAvailableSoon()) - mRenderHandler.draw(null); - return result; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) - @Override - protected void prepare() throws IOException { - if (DEBUG) Log.i(TAG, "prepare: "); - mTrackIndex = -1; - mMuxerStarted = mIsEOS = false; - - final MediaCodecInfo videoCodecInfo = selectVideoCodec(MIME_TYPE); - if (videoCodecInfo == null) { - Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); - return; - } - if (DEBUG) Log.i(TAG, "selected codec: " + videoCodecInfo.getName()); - - final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight); - format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); // API >= 18 - format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); - format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); - format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); - if (DEBUG) Log.i(TAG, "format: " + format); - - mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); - mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - // get Surface for encoder input - // this method only can call between #configure and #start - mSurface = mMediaCodec.createInputSurface(); // API >= 18 - mMediaCodec.start(); - if (DEBUG) Log.i(TAG, "prepare finishing"); - if (mListener != null) { - try { - mListener.onPrepared(this); - } catch (final Exception e) { - Log.e(TAG, "prepare:", e); - } - } - } - - public void setEglContext(final EGLBase.IContext sharedContext, final int tex_id) { - mRenderHandler.setEglContext(sharedContext, tex_id, mSurface, true); - } - - @Override - protected void release() { - if (DEBUG) Log.i(TAG, "release:"); - if (mSurface != null) { - mSurface.release(); - mSurface = null; - } - if (mRenderHandler != null) { - mRenderHandler.release(); - mRenderHandler = null; - } - super.release(); - } - - private int calcBitRate() { - final int bitrate = (int)(BPP * FRAME_RATE * mWidth * mHeight); - Log.i(TAG, String.format("bitrate=%5.2f[Mbps]", bitrate / 1024f / 1024f)); - return bitrate; - } - - /** - * select the first codec that match a specific MIME type - * @param mimeType - * @return null if no codec matched - */ - protected static final MediaCodecInfo selectVideoCodec(final String mimeType) { - if (DEBUG) Log.v(TAG, "selectVideoCodec:"); - - // get the list of available codecs - final int numCodecs = MediaCodecList.getCodecCount(); - for (int i = 0; i < numCodecs; i++) { - final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - - if (!codecInfo.isEncoder()) { // skipp decoder - continue; - } - // select first codec that match a specific MIME type and color format - final String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (types[j].equalsIgnoreCase(mimeType)) { - if (DEBUG) Log.i(TAG, "codec:" + codecInfo.getName() + ",MIME=" + types[j]); - final int format = selectColorFormat(codecInfo, mimeType); - if (format > 0) { - return codecInfo; - } - } - } - } - return null; - } - - /** - * select color format available on specific codec and we can use. - * @return 0 if no colorFormat is matched - */ - protected static final int selectColorFormat(final MediaCodecInfo codecInfo, final String mimeType) { - if (DEBUG) Log.i(TAG, "selectColorFormat: "); - int result = 0; - final MediaCodecInfo.CodecCapabilities caps; - try { - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - caps = codecInfo.getCapabilitiesForType(mimeType); - } finally { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY); - } - int colorFormat; - for (int i = 0; i < caps.colorFormats.length; i++) { - colorFormat = caps.colorFormats[i]; - if (isRecognizedVideoFormat(colorFormat)) { - if (result == 0) - result = colorFormat; - break; - } - } - if (result == 0) - Log.e(TAG, "couldn't find a good color format for " + codecInfo.getName() + " / " + mimeType); - return result; - } - - /** - * color formats that we can use in this class - */ - protected static int[] recognizedFormats; - static { - recognizedFormats = new int[] { -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar, -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar, -// MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, - MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface, - }; - } - - private static final boolean isRecognizedVideoFormat(final int colorFormat) { - if (DEBUG) Log.i(TAG, "isRecognizedVideoFormat:colorFormat=" + colorFormat); - final int n = recognizedFormats != null ? recognizedFormats.length : 0; - for (int i = 0; i < n; i++) { - if (recognizedFormats[i] == colorFormat) { - return true; - } - } - return false; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java deleted file mode 100644 index 0265cac1ea..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.serenegiant.usb.encoder; - -/** 录制参数 - * - * Created by jiangdongguo on 2017/10/19. - */ - -public class RecordParams { - private String recordPath; - private int recordDuration; - private boolean voiceClose; - private boolean isAutoSave; - private boolean isSupportOverlay; - - public RecordParams() { - } - - public boolean isSupportOverlay() { - return isSupportOverlay; - } - - public void setSupportOverlay(boolean supportOverlay) { - isSupportOverlay = supportOverlay; - } - - public boolean isVoiceClose() { - return voiceClose; - } - - public void setVoiceClose(boolean voiceClose) { - this.voiceClose = voiceClose; - } - - public String getRecordPath() { - return recordPath; - } - - public void setRecordPath(String recordPath) { - this.recordPath = recordPath; - } - - public int getRecordDuration() { - return recordDuration; - } - - public void setRecordDuration(int recordDuration) { - this.recordDuration = recordDuration; - } - - public boolean isAutoSave() { - return isAutoSave; - } - - public void setAutoSave(boolean autoSave) { - isAutoSave = autoSave; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/AACEncodeConsumer.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/AACEncodeConsumer.java deleted file mode 100644 index 69319e9b7d..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/AACEncodeConsumer.java +++ /dev/null @@ -1,381 +0,0 @@ -package com.serenegiant.usb.encoder.biz; - -import android.annotation.TargetApi; -import android.media.AudioFormat; -import android.media.AudioRecord; -import android.media.MediaCodec; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; -import android.media.MediaFormat; -import android.media.MediaRecorder; -import android.os.Build; -import android.os.Process; -import android.util.Log; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ShortBuffer; - -/**将PCM编码为AAC - * - * Created by jianddongguo on 2017/7/21. - */ - -public class AACEncodeConsumer extends Thread{ - private static final boolean DEBUG = false; - private static final String TAG = "TMPU"; - private static final String MIME_TYPE = "audio/mp4a-latm"; - private static final long TIMES_OUT = 1000; - private static final int SAMPLE_RATE = 8000; // 采样率 - private static final int BIT_RATE = 16000; // 比特率 - private static final int BUFFER_SIZE = 1920; // 最小缓存 - private int outChannel = 1; - private int bitRateForLame = 32; - private int qaulityDegree = 7; - private int bufferSizeInBytes; - - private AudioRecord mAudioRecord; // 音频采集 - private MediaCodec mAudioEncoder; // 音频编码 - private OnAACEncodeResultListener listener; - private int mSamplingRateIndex = 0;//ADTS - private boolean isEncoderStart = false; - private boolean isRecMp3 = false; - private boolean isExit = false; - private long prevPresentationTimes = 0; - private WeakReference mMuxerRef; - private MediaFormat newFormat; - - private static final int[] AUDIO_SOURCES = new int[] { - MediaRecorder.AudioSource.DEFAULT, - MediaRecorder.AudioSource.MIC, - MediaRecorder.AudioSource.CAMCORDER, - }; - /** - * There are 13 supported frequencies by ADTS. - **/ - public static final int[] AUDIO_SAMPLING_RATES = { 96000, // 0 - 88200, // 1 - 64000, // 2 - 48000, // 3 - 44100, // 4 - 32000, // 5 - 24000, // 6 - 22050, // 7 - 16000, // 8 - 12000, // 9 - 11025, // 10 - 8000, // 11 - 7350, // 12 - -1, // 13 - -1, // 14 - -1, // 15 - }; - - private FileOutputStream fops; - - // 编码流结果回调接口 - public interface OnAACEncodeResultListener{ - void onEncodeResult(byte[] data, int offset, - int length, long timestamp); - } - - public AACEncodeConsumer(){ - for (int i=0;i < AUDIO_SAMPLING_RATES.length; i++) { - if (AUDIO_SAMPLING_RATES[i] == SAMPLE_RATE) { - mSamplingRateIndex = i; - break; - } - } - } - - public void setOnAACEncodeResultListener(OnAACEncodeResultListener listener){ - this.listener = listener; - } - - public void exit(){ - isExit = true; - } - - public synchronized void setTmpuMuxer(Mp4MediaMuxer mMuxer){ - this.mMuxerRef = new WeakReference<>(mMuxer); - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null && newFormat != null) { - muxer.addTrack(newFormat, false); - } - } - - @Override - public void run() { - // 开启音频采集、编码 - if(! isEncoderStart){ - initAudioRecord(); - initMediaCodec(); - } - // 初始化音频文件参数 - byte[] mp3Buffer = new byte[1024]; - - // 这里有问题,当本地录制结束后,没有写入 - while(! isExit){ - byte[] audioBuffer = new byte[2048]; - // 采集音频 - int readBytes = mAudioRecord.read(audioBuffer,0,BUFFER_SIZE); - - if(DEBUG) - Log.i(TAG,"采集音频readBytes = "+readBytes); - // 编码音频 - if(readBytes > 0){ - encodeBytes(audioBuffer,readBytes); - } - } - // 停止音频采集、编码 - stopMediaCodec(); - stopAudioRecord(); - } - - - @TargetApi(21) - private void encodeBytes(byte[] audioBuf, int readBytes) { - ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers(); - ByteBuffer[] outputBuffers = mAudioEncoder.getOutputBuffers(); - //返回编码器的一个输入缓存区句柄,-1表示当前没有可用的输入缓存区 - int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(TIMES_OUT); - if(inputBufferIndex >= 0){ - // 绑定一个被空的、可写的输入缓存区inputBuffer到客户端 - ByteBuffer inputBuffer = null; - if(!isLollipop()){ - inputBuffer = inputBuffers[inputBufferIndex]; - }else{ - inputBuffer = mAudioEncoder.getInputBuffer(inputBufferIndex); - } - // 向输入缓存区写入有效原始数据,并提交到编码器中进行编码处理 - if(audioBuf==null || readBytes<=0){ - mAudioEncoder.queueInputBuffer(inputBufferIndex,0,0,getPTSUs(),MediaCodec.BUFFER_FLAG_END_OF_STREAM); - }else{ - inputBuffer.clear(); - inputBuffer.put(audioBuf); - mAudioEncoder.queueInputBuffer(inputBufferIndex,0,readBytes,getPTSUs(),0); - } - } - - // 返回一个输出缓存区句柄,当为-1时表示当前没有可用的输出缓存区 - // mBufferInfo参数包含被编码好的数据,timesOut参数为超时等待的时间 - MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo(); - int outputBufferIndex = -1; - do{ - outputBufferIndex = mAudioEncoder.dequeueOutputBuffer(mBufferInfo,TIMES_OUT); - if(outputBufferIndex == MediaCodec. INFO_TRY_AGAIN_LATER){ - if(DEBUG) - Log.i(TAG,"获得编码器输出缓存区超时"); - }else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED){ - // 如果API小于21,APP需要重新绑定编码器的输入缓存区; - // 如果API大于21,则无需处理INFO_OUTPUT_BUFFERS_CHANGED - if(!isLollipop()){ - outputBuffers = mAudioEncoder.getOutputBuffers(); - } - }else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){ - // 编码器输出缓存区格式改变,通常在存储数据之前且只会改变一次 - // 这里设置混合器视频轨道,如果音频已经添加则启动混合器(保证音视频同步) - if(DEBUG) - Log.i(TAG,"编码器输出缓存区格式改变,添加视频轨道到混合器"); - synchronized (AACEncodeConsumer.this) { - newFormat = mAudioEncoder.getOutputFormat(); - if(mMuxerRef != null){ - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null) { - muxer.addTrack(newFormat, false); - } - } - } - }else{ - // 当flag属性置为BUFFER_FLAG_CODEC_CONFIG后,说明输出缓存区的数据已经被消费了 - if((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0){ - if(DEBUG) - Log.i(TAG,"编码数据被消费,BufferInfo的size属性置0"); - mBufferInfo.size = 0; - } - // 数据流结束标志,结束本次循环 - if((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0){ - if(DEBUG) - Log.i(TAG,"数据流结束,退出循环"); - break; - } - // 获取一个只读的输出缓存区inputBuffer ,它包含被编码好的数据 - ByteBuffer mBuffer = ByteBuffer.allocate(10240); - ByteBuffer outputBuffer = null; - if(!isLollipop()){ - outputBuffer = outputBuffers[outputBufferIndex]; - }else{ - outputBuffer = mAudioEncoder.getOutputBuffer(outputBufferIndex); - } - if(mBufferInfo.size != 0){ - // 获取输出缓存区失败,抛出异常 - if(outputBuffer == null){ - throw new RuntimeException("encodecOutputBuffer"+outputBufferIndex+"was null"); - } - // 添加视频流到混合器 - if(mMuxerRef != null){ - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null) { - muxer.pumpStream(outputBuffer, mBufferInfo, false); - } - } - // AAC流添加ADTS头,缓存到mBuffer - mBuffer.clear(); - outputBuffer.get(mBuffer.array(), 7, mBufferInfo.size); - outputBuffer.clear(); - mBuffer.position(7 + mBufferInfo.size); - addADTStoPacket(mBuffer.array(), mBufferInfo.size + 7); - mBuffer.flip(); - // 将AAC回调给MainModelImpl进行push - if(listener != null){ - Log.i(TAG,"----->得到aac数据流<-----"); - listener.onEncodeResult(mBuffer.array(),0, mBufferInfo.size + 7, mBufferInfo.presentationTimeUs / 1000); - } - } - // 处理结束,释放输出缓存区资源 - mAudioEncoder.releaseOutputBuffer(outputBufferIndex,false); - } - }while (outputBufferIndex >= 0); - } - - private void initAudioRecord(){ - if(DEBUG) - Log.d(TAG,"AACEncodeConsumer-->开始采集音频"); - // 设置进程优先级 - Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO); - int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT); - for (final int src: AUDIO_SOURCES) { - try { - mAudioRecord = new AudioRecord(src, - SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); - if (mAudioRecord != null) { - if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) { - mAudioRecord.release(); - mAudioRecord = null; - } - } - } catch (final Exception e) { - mAudioRecord = null; - } - if (mAudioRecord != null) { - break; - } - } - mAudioRecord.startRecording(); - } - - private void initMediaCodec(){ - if(DEBUG) - Log.d(TAG,"AACEncodeConsumer-->开始编码音频"); - MediaCodecInfo mCodecInfo = selectSupportCodec(MIME_TYPE); - if(mCodecInfo == null){ - Log.e(TAG,"编码器不支持"+MIME_TYPE+"类型"); - return; - } - try{ - mAudioEncoder = MediaCodec.createByCodecName(mCodecInfo.getName()); - }catch(IOException e){ - Log.e(TAG,"创建编码器失败"+e.getMessage()); - e.printStackTrace(); - } - MediaFormat format = new MediaFormat(); - format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); - format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); - format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); - format.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE); - format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); - format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, BUFFER_SIZE); - mAudioEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - mAudioEncoder.start(); - isEncoderStart = true; - } - - private void stopAudioRecord() { - if(DEBUG) - Log.d(TAG,"AACEncodeConsumer-->停止采集音频"); - if(mAudioRecord != null){ - mAudioRecord.stop(); - mAudioRecord.release(); - mAudioRecord = null; - } - } - - private void stopMediaCodec() { - if(DEBUG) - Log.d(TAG,"AACEncodeConsumer-->停止编码音频"); - if(mAudioEncoder != null){ - mAudioEncoder.stop(); - mAudioEncoder.release(); - mAudioEncoder = null; - } - isEncoderStart = false; - } - - // API>=21 - private boolean isLollipop(){ - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - } - - // API<=19 - private boolean isKITKAT(){ - return Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT; - } - - private long getPTSUs(){ - long result = System.nanoTime()/1000; - if(result < prevPresentationTimes){ - result = (prevPresentationTimes - result ) + result; - } - return result; - } - - /** - * 遍历所有编解码器,返回第一个与指定MIME类型匹配的编码器 - * 判断是否有支持指定mime类型的编码器 - * */ - private MediaCodecInfo selectSupportCodec(String mimeType){ - int numCodecs = MediaCodecList.getCodecCount(); - for (int i = 0; i < numCodecs; i++) { - MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - // 判断是否为编码器,否则直接进入下一次循环 - if (!codecInfo.isEncoder()) { - continue; - } - // 如果是编码器,判断是否支持Mime类型 - String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (types[j].equalsIgnoreCase(mimeType)) { - return codecInfo; - } - } - } - return null; - } - - private void addADTStoPacket(byte[] packet, int packetLen) { - packet[0] = (byte) 0xFF; - packet[1] = (byte) 0xF1; - packet[2] = (byte) (((2 - 1) << 6) + (mSamplingRateIndex << 2) + (1 >> 2)); - packet[3] = (byte) (((1 & 3) << 6) + (packetLen >> 11)); - packet[4] = (byte) ((packetLen & 0x7FF) >> 3); - packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F); - packet[6] = (byte) 0xFC; - } - - - private short[] transferByte2Short(byte[] data,int readBytes){ - // byte[] 转 short[],数组长度缩减一半 - int shortLen = readBytes / 2; - // 将byte[]数组装如ByteBuffer缓冲区 - ByteBuffer byteBuffer = ByteBuffer.wrap(data, 0, readBytes); - // 将ByteBuffer转成小端并获取shortBuffer - ShortBuffer shortBuffer = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); - short[] shortData = new short[shortLen]; - shortBuffer.get(shortData, 0, shortLen); - return shortData; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/H264EncodeConsumer.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/H264EncodeConsumer.java deleted file mode 100644 index 9310ce1ae4..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/H264EncodeConsumer.java +++ /dev/null @@ -1,461 +0,0 @@ -package com.serenegiant.usb.encoder.biz; - -import android.annotation.SuppressLint; -import android.media.MediaCodec; -import android.media.MediaCodecInfo; -import android.media.MediaCodecList; -import android.media.MediaFormat; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.util.Log; - -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; - -/** - * 对YUV视频流进行编码 - * Created by jiangdongguo on 2017/5/6. - */ - -@SuppressWarnings("deprecation") -public class H264EncodeConsumer extends Thread { - private static final boolean DEBUG = false; - private static final String TAG = "H264EncodeConsumer"; - private static final String MIME_TYPE = "video/avc"; - // 间隔1s插入一帧关键帧 - private static final int FRAME_INTERVAL = 1; - // 绑定编码器缓存区超时时间为10s - private static final int TIMES_OUT = 10000; - // 硬编码器 - private MediaCodec mMediaCodec; - private int mColorFormat; - private boolean isExit = false; - private boolean isEncoderStart = false; - - private MediaFormat mFormat; - private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test2.h264"; - private BufferedOutputStream outputStream; - final int millisPerframe = 1000 / 20; - long lastPush = 0; - private OnH264EncodeResultListener listener; - private int mWidth; - private int mHeight; - private MediaFormat newFormat; - private WeakReference mMuxerRef; - private boolean isAddKeyFrame = false; - - public interface OnH264EncodeResultListener { - void onEncodeResult(byte[] data, int offset, - int length, long timestamp); - } - - public void setOnH264EncodeResultListener(OnH264EncodeResultListener listener) { - this.listener = listener; - } - - public H264EncodeConsumer(int width, int height) { - this.mWidth = width; - this.mHeight = height; - } - - public synchronized void setTmpuMuxer(Mp4MediaMuxer mMuxer) { - this.mMuxerRef = new WeakReference<>(mMuxer); - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null && newFormat != null) { - muxer.addTrack(newFormat, true); - } - } - - private ByteBuffer[] inputBuffers; - private ByteBuffer[] outputBuffers; - - public void setRawYuv(byte[] yuvData, int width, int height) { - if (!isEncoderStart) - return; - if (mWidth != width || mHeight != height) { - mWidth = width; - mHeight = height; - return; - } - try { - if (lastPush == 0) { - lastPush = System.currentTimeMillis(); - } - long time = System.currentTimeMillis() - lastPush; - if (time >= 0) { - time = millisPerframe - time; - if (time > 0) - Thread.sleep(time / 2); - } - // 将数据写入编码器 - - feedMediaCodecData(nv12ToNV21(yuvData, mWidth, mHeight)); - - if (time > 0) - Thread.sleep(time / 2); - lastPush = System.currentTimeMillis(); - } catch (InterruptedException ex) { - ex.printStackTrace(); - } - } - - private void feedMediaCodecData(byte[] data) { - if (!isEncoderStart) - return; - int bufferIndex = -1; - try { - bufferIndex = mMediaCodec.dequeueInputBuffer(0); - } catch (IllegalStateException e) { - e.printStackTrace(); - } - if (bufferIndex >= 0) { - ByteBuffer buffer; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - buffer = mMediaCodec.getInputBuffer(bufferIndex); - } else { - buffer = inputBuffers[bufferIndex]; - } - buffer.clear(); - buffer.put(data); - buffer.clear(); - mMediaCodec.queueInputBuffer(bufferIndex, 0, data.length, System.nanoTime() / 1000, MediaCodec.BUFFER_FLAG_KEY_FRAME); - } - } - - public void exit() { - isExit = true; - } - - @SuppressLint("WrongConstant") - @Override - public void run() { - if (!isEncoderStart) { - startMediaCodec(); - } - // 休眠200ms,等待音频线程开启 - // 否则视频第一秒会卡住 - try { - Thread.sleep(200); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - - // 如果编码器没有启动或者没有图像数据,线程阻塞等待 - while (!isExit) { - MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); - int outputBufferIndex = 0; - byte[] mPpsSps = new byte[0]; - byte[] h264 = new byte[mWidth * mHeight]; - do { - outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 10000); - if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { - // no output available yet - } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { - // not expected for an encoder - outputBuffers = mMediaCodec.getOutputBuffers(); - } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - synchronized (H264EncodeConsumer.this) { - newFormat = mMediaCodec.getOutputFormat(); - if (mMuxerRef != null) { - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null) { - muxer.addTrack(newFormat, true); - } - } - } - } else if (outputBufferIndex < 0) { - // let's ignore it - } else { - ByteBuffer outputBuffer; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - outputBuffer = mMediaCodec.getOutputBuffer(outputBufferIndex); - } else { - outputBuffer = outputBuffers[outputBufferIndex]; - } - outputBuffer.position(bufferInfo.offset); - outputBuffer.limit(bufferInfo.offset + bufferInfo.size); - - boolean sync = false; - if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {// sps - sync = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - if (!sync) { - byte[] temp = new byte[bufferInfo.size]; - outputBuffer.get(temp); - mPpsSps = temp; - mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); - continue; - } else { - mPpsSps = new byte[0]; - } - } - sync |= (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - int len = mPpsSps.length + bufferInfo.size; - if (len > h264.length) { - h264 = new byte[len]; - } - if (sync) { - System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length); - outputBuffer.get(h264, mPpsSps.length, bufferInfo.size); - if (listener != null) { - listener.onEncodeResult(h264, 0, mPpsSps.length + bufferInfo.size, bufferInfo.presentationTimeUs / 1000); - } - - // 添加视频流到混合器 - if (mMuxerRef != null) { - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null) { - muxer.pumpStream(outputBuffer, bufferInfo, true); - } - isAddKeyFrame = true; - } - if (DEBUG) - Log.i(TAG, "关键帧 h264.length = " + h264.length + ";mPpsSps.length=" + mPpsSps.length - + " bufferInfo.size = " + bufferInfo.size); - } else { - outputBuffer.get(h264, 0, bufferInfo.size); - if (listener != null) { - listener.onEncodeResult(h264, 0, bufferInfo.size, bufferInfo.presentationTimeUs / 1000); - } - // 添加视频流到混合器 - if (isAddKeyFrame && mMuxerRef != null) { - Mp4MediaMuxer muxer = mMuxerRef.get(); - if (muxer != null) { - muxer.pumpStream(outputBuffer, bufferInfo, true); - } - } - if (DEBUG) - Log.i(TAG, "普通帧 h264.length = " + h264.length + " bufferInfo.size = " + bufferInfo.size); - } - mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); - } - } while (!isExit && isEncoderStart); - } - stopMediaCodec(); - } - - private void startMediaCodec() { - final MediaCodecInfo videoCodecInfo = selectVideoCodec(MIME_TYPE); - if (videoCodecInfo == null) { - Log.e(TAG, "Unable to find an appropriate codec for " + MIME_TYPE); - return; - } - - final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight); - format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat); - format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); - format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); - format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); - - try { - mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); - } catch (IOException e) { - e.printStackTrace(); - } - mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); - mMediaCodec.start(); - - - isEncoderStart = true; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP + 1) { - inputBuffers = outputBuffers = null; - } else { - inputBuffers = mMediaCodec.getInputBuffers(); - outputBuffers = mMediaCodec.getOutputBuffers(); - } - - Bundle params = new Bundle(); - params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mMediaCodec.setParameters(params); - } - } - - private void stopMediaCodec() { - isEncoderStart = false; - if (mMediaCodec != null) { - mMediaCodec.stop(); - mMediaCodec.release(); - Log.d(TAG, "关闭视频编码器"); - } - } - - private static final int FRAME_RATE = 15; - private static final float BPP = 0.50f; - - private int calcBitRate() { - final int bitrate = (int) (BPP * FRAME_RATE * mWidth * mHeight); - Log.i(TAG, String.format("bitrate=%5.2f[Mbps]", bitrate / 1024f / 1024f)); - return bitrate; - } - - /** - * select the first codec that match a specific MIME type - * - * @param mimeType - * @return null if no codec matched - */ - @SuppressWarnings("deprecation") - protected final MediaCodecInfo selectVideoCodec(final String mimeType) { - - // get the list of available codecs - final int numCodecs = MediaCodecList.getCodecCount(); - for (int i = 0; i < numCodecs; i++) { - final MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); - - if (!codecInfo.isEncoder()) { // skipp decoder - continue; - } - // select first codec that match a specific MIME type and color format - final String[] types = codecInfo.getSupportedTypes(); - for (int j = 0; j < types.length; j++) { - if (types[j].equalsIgnoreCase(mimeType)) { - final int format = selectColorFormat(codecInfo, mimeType); - if (format > 0) { - mColorFormat = format; - return codecInfo; - } - } - } - } - return null; - } - - /** - * select color format available on specific codec and we can use. - * - * @return 0 if no colorFormat is matched - */ - protected static final int selectColorFormat(final MediaCodecInfo codecInfo, final String mimeType) { - int result = 0; - final MediaCodecInfo.CodecCapabilities caps; - try { - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - caps = codecInfo.getCapabilitiesForType(mimeType); - } finally { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY); - } - int colorFormat; - for (int i = 0; i < caps.colorFormats.length; i++) { - colorFormat = caps.colorFormats[i]; - if (isRecognizedViewoFormat(colorFormat)) { - if (result == 0) - result = colorFormat; - break; - } - } - if (result == 0) - Log.e(TAG, "couldn't find a good color format for " + codecInfo.getName() + " / " + mimeType); - return result; - } - - /** - * color formats that we can use in this class - */ - protected static int[] recognizedFormats; - - static { - recognizedFormats = new int[]{ -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar, -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar, -// MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar, - MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar, - MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, - }; - } - - private static final boolean isRecognizedViewoFormat(final int colorFormat) { - final int n = recognizedFormats != null ? recognizedFormats.length : 0; - for (int i = 0; i < n; i++) { - if (recognizedFormats[i] == colorFormat) { - return true; - } - } - return false; - } - - - private byte[] nv21ToI420(byte[] data, int width, int height) { - byte[] ret = new byte[width * height * 3 / 2]; - int total = width * height; - - ByteBuffer bufferY = ByteBuffer.wrap(ret, 0, total); // I420的Y分量 - ByteBuffer bufferU = ByteBuffer.wrap(ret, total, total / 4); // I420的U分量 - ByteBuffer bufferV = ByteBuffer.wrap(ret, total + total / 4, total / 4); // I420的V分量 - // NV21 YYYYYYYY VUVU - bufferY.put(data, 0, total); - for (int i = total; i < data.length; i += 2) { - bufferV.put(data[i]); - bufferU.put(data[i + 1]); - } - - return ret; - } - - private byte[] nv12ToI420(byte[] data, int width, int height) { - byte[] ret = new byte[width * height * 3 / 2]; - int total = width * height; - - ByteBuffer bufferY = ByteBuffer.wrap(ret, 0, total); // I420的Y分量 - ByteBuffer bufferU = ByteBuffer.wrap(ret, total, total / 4); // I420的U分量 - ByteBuffer bufferV = ByteBuffer.wrap(ret, total + total / 4, total / 4); // I420的V分量 - - // NV12 YYYYYYYY UVUV - bufferY.put(data, 0, total); - for (int i = total; i < data.length; i += 2) { - bufferU.put(data[i]); - bufferV.put(data[i + 1]); - } - return ret; - } - - private byte[] nv12ToNv21(byte[] data, int width, int height) { - byte[] ret = new byte[width * height * 3 / 2]; - int total = width * height; - - ByteBuffer bufferY = ByteBuffer.wrap(ret, 0, total); // I420的Y分量 - ByteBuffer bufferU = ByteBuffer.wrap(ret, total, total / 4); // I420的U分量 - ByteBuffer bufferV = ByteBuffer.wrap(ret, total + total / 4, total / 4); // I420的V分量 - - // NV12 YYYYYYYY UVUV - bufferY.put(data, 0, total); - for (int i = total; i < data.length; i += 2) { - bufferU.put(data[i]); - bufferV.put(data[i + 1]); - } - return ret; - } - - // YYYYYYYY UVUV(nv21)--> YYYYYYYY VUVU(nv12) - private byte[] nv21ToNV12(byte[] nv21, int width, int height) { - byte[] ret = new byte[width * height * 3 /2]; - int framesize = width * height; - int i = 0, j = 0; - // 拷贝Y分量 - System.arraycopy(nv21, 0,ret , 0, framesize); - // 拷贝UV分量 - for (j = framesize; j < nv21.length; j += 2) { - ret[j+1] = nv21[j+1]; - ret[j] = nv21[j]; - } - return ret; - } - - // YYYYYYYY UVUV(nv12)--> YYYYYYYY VUVU(nv21) - private byte[] nv12ToNV21(byte[] nv12, int width, int height) { - byte[] ret = new byte[width * height * 3 /2]; - int framesize = width * height; - int i = 0, j = 0; - // 拷贝Y分量 - System.arraycopy(nv12, 0,ret , 0, framesize); - // 拷贝UV分量 - for (j = framesize; j < nv12.length; j += 2) { - ret[j] = nv12[j+1]; - ret[j+1] = nv12[j]; - } - return ret; - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java deleted file mode 100644 index 64307af008..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.serenegiant.usb.encoder.biz; - -import android.media.MediaCodec; -import android.media.MediaFormat; -import android.media.MediaMuxer; -import android.os.Build; -import android.util.Log; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; - -/**Mp4封装混合器 - * - * Created by jianddongguo on 2017/7/28. - */ - -public class Mp4MediaMuxer { - private static final boolean VERBOSE = false; - private static final String TAG = Mp4MediaMuxer.class.getSimpleName(); - private String mFilePath; - private MediaMuxer mMuxer; - private long durationMillis; - private int index = 0; - private int mVideoTrackIndex = -1; - private int mAudioTrackIndex = -1; - private long mBeginMillis; - private MediaFormat mVideoFormat; - private MediaFormat mAudioFormat; - private boolean isVoiceClose; - - // 文件路径;文件时长 - public Mp4MediaMuxer(String path, long durationMillis,boolean isVoiceClose) { - String mFilePath; - this.isVoiceClose = isVoiceClose; - this.durationMillis = durationMillis; - if(durationMillis != 0) { - mFilePath = path + "-" + index++ + ".mp4"; - }else{ - mFilePath = path+".mp4"; - } - Object mux = null; - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - mux = new MediaMuxer(mFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - mMuxer = (MediaMuxer) mux; - } - } - - public synchronized void addTrack(MediaFormat format, boolean isVideo) { - // now that we have the Magic Goodies, start the muxer - if ((!isVoiceClose && mAudioTrackIndex != -1) && mVideoTrackIndex != -1) - throw new RuntimeException("already add all tracks"); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - int track = mMuxer.addTrack(format); - if (VERBOSE) - Log.i(TAG, String.format("addTrack %s result %d", isVideo ? "video" : "audio", track)); - if (isVideo) { - mVideoFormat = format; - mVideoTrackIndex = track; - // 当音频轨道添加 - // 或者开启静音就start - if (isVoiceClose || mAudioTrackIndex != -1) { - if (VERBOSE) - Log.i(TAG, "both audio and video added,and muxer is started"); - mMuxer.start(); - mBeginMillis = System.currentTimeMillis(); - } - } else { - mAudioFormat = format; - mAudioTrackIndex = track; - if (mVideoTrackIndex != -1) { - mMuxer.start(); - mBeginMillis = System.currentTimeMillis(); - } - } - } - } - - public synchronized void pumpStream(ByteBuffer outputBuffer, MediaCodec.BufferInfo bufferInfo, boolean isVideo) { - if ((!isVoiceClose && mAudioTrackIndex == -1) || mVideoTrackIndex == -1) { -// Log.i(TAG, String.format("pumpStream [%s] but muxer is not start.ignore..", isVideo ? "video" : "audio")); - return; - } - if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { - // The codec config data was pulled out and fed to the muxer when we got - // the INFO_OUTPUT_FORMAT_CHANGED status. Ignore it. - } else if (bufferInfo.size != 0) { - if (isVideo && mVideoTrackIndex == -1) { - throw new RuntimeException("muxer hasn't started"); - } - - // adjust the ByteBuffer values to match BufferInfo (not needed?) - outputBuffer.position(bufferInfo.offset); - outputBuffer.limit(bufferInfo.offset + bufferInfo.size); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - mMuxer.writeSampleData(isVideo ? mVideoTrackIndex : mAudioTrackIndex, outputBuffer, bufferInfo); - } -// if (VERBOSE) -// Log.d(TAG, String.format("sent %s [" + bufferInfo.size + "] with timestamp:[%d] to muxer", isVideo ? "video" : "audio", bufferInfo.presentationTimeUs / 1000)); - } - - if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { -// if (VERBOSE) -// Log.i(TAG, "BUFFER_FLAG_END_OF_STREAM received"); - } - - if (durationMillis!=0 && System.currentTimeMillis() - mBeginMillis >= durationMillis) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { -// if (VERBOSE) -// Log.i(TAG, String.format("record file reach expiration.create new file:" + index)); - mMuxer.stop(); - mMuxer.release(); - mMuxer = null; - mVideoTrackIndex = mAudioTrackIndex = -1; - try { - mMuxer = new MediaMuxer(mFilePath + "-" + ++index + ".mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); - addTrack(mVideoFormat, true); - addTrack(mAudioFormat, false); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - public synchronized void release() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - if (mMuxer != null) { - //(!isVoiceClose&&mAudioTrackIndex != -1) - if (mVideoTrackIndex != -1) { - if (VERBOSE) - Log.i(TAG, String.format("muxer is started. now it will be stoped.")); - try { - mMuxer.stop(); - mMuxer.release(); - } catch (IllegalStateException ex) { - ex.printStackTrace(); - } - - if (System.currentTimeMillis() - mBeginMillis <= 1500){ - new File(mFilePath + "-" + index + ".mp4").delete(); - } - mAudioTrackIndex = mVideoTrackIndex = -1; - }else{ - if (VERBOSE) - Log.i(TAG, String.format("muxer is failed to be stoped.")); - } - } - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/AspectRatioTextureView.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/AspectRatioTextureView.java deleted file mode 100644 index c616a494ef..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/AspectRatioTextureView.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * UVCCamera - * library and sample to access to UVC web camera on non-rooted Android device - * - * Copyright (c) 2014-2017 saki t_saki@serenegiant.com - * - * 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. - * - * All files in the folder are under this Apache License, Version 2.0. - * Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder - * may have a different license, see the respective files. - */ - -package com.serenegiant.usb.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.TextureView; - -/** - * change the view size with keeping the specified aspect ratio. - * if you set this view with in a FrameLayout and set property "android:layout_gravity="center", - * you can show this view in the center of screen and keep the aspect ratio of content - * XXX it is better that can set the aspect ratio as xml property - * - * @author mogoauto - */ -public class AspectRatioTextureView extends TextureView // API >= 14 - implements IAspectRatioView { - - /**TODO set false on release*/ - private static final boolean DEBUG = true; - private static final String TAG = "AbstractCameraView"; - - private double mRequestedAspect = -1.0; - private CameraViewInterface.Callback mCallback; - - public AspectRatioTextureView(final Context context) { - this(context, null, 0); - } - - public AspectRatioTextureView(final Context context, final AttributeSet attrs) { - this(context, attrs, 0); - } - - public AspectRatioTextureView(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - } - - // 设置屏幕宽高比 - @Override - public void setAspectRatio(final double aspectRatio) { - if (aspectRatio < 0) { - throw new IllegalArgumentException(); - } - if (mRequestedAspect != aspectRatio) { - mRequestedAspect = aspectRatio; - requestLayout(); - } - } - - @Override - public void setAspectRatio(final int width, final int height) { - setAspectRatio(width / (double) height); - } - - @Override - public double getAspectRatio() { - return mRequestedAspect; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - if (mRequestedAspect > 0) { - int initialWidth = MeasureSpec.getSize(widthMeasureSpec); - int initialHeight = MeasureSpec.getSize(heightMeasureSpec); - - final int horizPadding = getPaddingLeft() + getPaddingRight(); - final int vertPadding = getPaddingTop() + getPaddingBottom(); - initialWidth -= horizPadding; - initialHeight -= vertPadding; - - final double viewAspectRatio = (double) initialWidth / initialHeight; - final double aspectDiff = mRequestedAspect / viewAspectRatio - 1; - - if (Math.abs(aspectDiff) > 0.01) { - if (aspectDiff > 0) { - // width priority decision - initialHeight = (int) (initialWidth / mRequestedAspect); - } else { - // height priority decision - initialWidth = (int) (initialHeight * mRequestedAspect); - } - initialWidth += horizPadding; - initialHeight += vertPadding; - widthMeasureSpec = MeasureSpec.makeMeasureSpec(initialWidth, MeasureSpec.EXACTLY); - heightMeasureSpec = MeasureSpec.makeMeasureSpec(initialHeight, MeasureSpec.EXACTLY); - } - } - - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/CameraViewInterface.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/CameraViewInterface.java deleted file mode 100644 index 413174669c..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/CameraViewInterface.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.serenegiant.usb.widget; - -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.view.Surface; - -import com.serenegiant.usb.encoder.IVideoEncoder; - -public interface CameraViewInterface extends IAspectRatioView { - public interface Callback { - public void onSurfaceCreated(CameraViewInterface view, Surface surface); - public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height); - public void onSurfaceDestroy(CameraViewInterface view, Surface surface); - } - public void onPause(); - public void onResume(); - public void setCallback(Callback callback); - public SurfaceTexture getSurfaceTexture(); - public Surface getSurface(); - public boolean hasSurface(); - public void setVideoEncoder(final IVideoEncoder encoder); - public Bitmap captureStillImage(int width,int height); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/IAspectRatioView.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/IAspectRatioView.java deleted file mode 100644 index 7e6ca85240..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/IAspectRatioView.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.serenegiant.usb.widget; - -public interface IAspectRatioView { - void setAspectRatio(double var1); - - void setAspectRatio(int var1, int var2); - - double getAspectRatio(); -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/UVCCameraTextureView.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/UVCCameraTextureView.java deleted file mode 100644 index 539a67318e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/usb/widget/UVCCameraTextureView.java +++ /dev/null @@ -1,575 +0,0 @@ -package com.serenegiant.usb.widget; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; -import android.view.TextureView; - -import com.serenegiant.glutils.EGLBase; -import com.serenegiant.glutils.GLDrawer2D; -import com.serenegiant.glutils.es1.GLHelper; -import com.serenegiant.usb.encoder.IVideoEncoder; -import com.serenegiant.usb.encoder.MediaEncoder; -import com.serenegiant.usb.encoder.MediaVideoEncoder; -import com.serenegiant.utils.FpsCounter; - -/** - * change the view size with keeping the specified aspect ratio. - * if you set this view with in a FrameLayout and set property "android:layout_gravity="center", - * you can show this view in the center of screen and keep the aspect ratio of content - * XXX it is better that can set the aspect ratio as xml property - */ -public class UVCCameraTextureView extends AspectRatioTextureView // API >= 14 - implements TextureView.SurfaceTextureListener, CameraViewInterface { - - private static final boolean DEBUG = true; // TODO set false on release - private static final String TAG = "UVCCameraTextureView"; - - private boolean mHasSurface; - private RenderHandler mRenderHandler; - private final Object mCaptureSync = new Object(); - private Bitmap mTempBitmap; - private boolean mReqesutCaptureStillImage; - private Callback mCallback; - // Camera分辨率宽度 - - - /** for calculation of frame rate */ - private final FpsCounter mFpsCounter = new FpsCounter(); - - public UVCCameraTextureView(final Context context) { - this(context, null, 0); - } - - public UVCCameraTextureView(final Context context, final AttributeSet attrs) { - this(context, attrs, 0); - } - - public UVCCameraTextureView(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - setSurfaceTextureListener(this); - } - - @Override - public void onResume() { - if (DEBUG) Log.v(TAG, "onResume:"); - if (mHasSurface) { - mRenderHandler = RenderHandler.createHandler(mFpsCounter, super.getSurfaceTexture(), getWidth(), getHeight()); - } - } - - @Override - public void onPause() { - if (DEBUG) Log.v(TAG, "onPause:"); - if (mRenderHandler != null) { - mRenderHandler.release(); - mRenderHandler = null; - } - if (mTempBitmap != null) { - mTempBitmap.recycle(); - mTempBitmap = null; - } - } - - @Override - public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) { - if (DEBUG) Log.i(TAG, "onSurfaceTextureAvailable:" + surface); - if (mRenderHandler == null) { - mRenderHandler = RenderHandler.createHandler(mFpsCounter, surface, width, height); - } else { - mRenderHandler.resize(width, height); - } - mHasSurface = true; - if (mCallback != null) { - mCallback.onSurfaceCreated(this, getSurface()); - } - } - - @Override - public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) { - if (DEBUG) Log.i(TAG, "onSurfaceTextureSizeChanged:" + surface); - if (mRenderHandler != null) { - mRenderHandler.resize(width, height); - } - if (mCallback != null) { - mCallback.onSurfaceChanged(this, getSurface(), width, height); - } - } - - @Override - public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) { - if (DEBUG) Log.i(TAG, "onSurfaceTextureDestroyed:" + surface); - if (mRenderHandler != null) { - mRenderHandler.release(); - mRenderHandler = null; - } - mHasSurface = false; - if (mCallback != null) { - mCallback.onSurfaceDestroy(this, getSurface()); - } - if (mPreviewSurface != null) { - mPreviewSurface.release(); - mPreviewSurface = null; - } - return true; - } - - @Override - public void onSurfaceTextureUpdated(final SurfaceTexture surface) { - synchronized (mCaptureSync) { - if (mReqesutCaptureStillImage) { - mReqesutCaptureStillImage = false; - if (mTempBitmap == null) - mTempBitmap = getBitmap(); - else - getBitmap(mTempBitmap); - mCaptureSync.notifyAll(); - } - } - } - - @Override - public boolean hasSurface() { - return mHasSurface; - } - - /** - * capture preview image as a bitmap - * this method blocks current thread until bitmap is ready - * if you call this method at almost same time from different thread, - * the returned bitmap will be changed while you are processing the bitmap - * (because we return same instance of bitmap on each call for memory saving) - * if you need to call this method from multiple thread, - * you should change this method(copy and return) - */ - @Override - public Bitmap captureStillImage(int width,int height) { - synchronized (mCaptureSync) { - mReqesutCaptureStillImage = true; - try { - mCaptureSync.wait(); - } catch (final InterruptedException e) { - } - return mTempBitmap; - } - } - - @Override - public SurfaceTexture getSurfaceTexture() { - return mRenderHandler != null ? mRenderHandler.getPreviewTexture() : null; - } - - private Surface mPreviewSurface; - @Override - public Surface getSurface() { - if (DEBUG) Log.v(TAG, "getSurface:hasSurface=" + mHasSurface); - if (mPreviewSurface == null) { - final SurfaceTexture st = getSurfaceTexture(); - if (st != null) { - mPreviewSurface = new Surface(st); - } - } - return mPreviewSurface; - } - - @Override - public void setVideoEncoder(final IVideoEncoder encoder) { - if (mRenderHandler != null) - mRenderHandler.setVideoEncoder(encoder); - } - - @Override - public void setCallback(final Callback callback) { - mCallback = callback; - } - - public void resetFps() { - mFpsCounter.reset(); - } - - /** update frame rate of image processing */ - public void updateFps() { - mFpsCounter.update(); - } - - /** - * get current frame rate of image processing - * @return - */ - public float getFps() { - return mFpsCounter.getFps(); - } - - /** - * get total frame rate from start - * @return - */ - public float getTotalFps() { - return mFpsCounter.getTotalFps(); - } - - /** - * render camera frames on this view on a private thread - * @author saki - * - */ - private static final class RenderHandler extends Handler - implements SurfaceTexture.OnFrameAvailableListener { - - private static final int MSG_REQUEST_RENDER = 1; - private static final int MSG_SET_ENCODER = 2; - private static final int MSG_CREATE_SURFACE = 3; - private static final int MSG_RESIZE = 4; - private static final int MSG_TERMINATE = 9; - - private RenderThread mThread; - private boolean mIsActive = true; - private final FpsCounter mFpsCounter; - - public static final RenderHandler createHandler(final FpsCounter counter, - final SurfaceTexture surface, final int width, final int height) { - - final RenderThread thread = new RenderThread(counter, surface, width, height); - thread.start(); - return thread.getHandler(); - } - - private RenderHandler(final FpsCounter counter, final RenderThread thread) { - mThread = thread; - mFpsCounter = counter; - } - - public final void setVideoEncoder(final IVideoEncoder encoder) { - if (DEBUG) Log.v(TAG, "setVideoEncoder:"); - if (mIsActive) - sendMessage(obtainMessage(MSG_SET_ENCODER, encoder)); - } - - public final SurfaceTexture getPreviewTexture() { - if (DEBUG) Log.v(TAG, "getPreviewTexture:"); - if (mIsActive) { - synchronized (mThread.mSync) { - sendEmptyMessage(MSG_CREATE_SURFACE); - try { - mThread.mSync.wait(); - } catch (final InterruptedException e) { - } - return mThread.mPreviewSurface; - } - } else { - return null; - } - } - - public void resize(final int width, final int height) { - if (DEBUG) Log.v(TAG, "resize:"); - if (mIsActive) { - synchronized (mThread.mSync) { - sendMessage(obtainMessage(MSG_RESIZE, width, height)); - try { - mThread.mSync.wait(); - } catch (final InterruptedException e) { - } - } - } - } - - public final void release() { - if (DEBUG) Log.v(TAG, "release:"); - if (mIsActive) { - mIsActive = false; - removeMessages(MSG_REQUEST_RENDER); - removeMessages(MSG_SET_ENCODER); - sendEmptyMessage(MSG_TERMINATE); - } - } - - @Override - public final void onFrameAvailable(final SurfaceTexture surfaceTexture) { - if (mIsActive) { - mFpsCounter.count(); - sendEmptyMessage(MSG_REQUEST_RENDER); - } - } - - @Override - public final void handleMessage(final Message msg) { - if (mThread == null) return; - switch (msg.what) { - case MSG_REQUEST_RENDER: - mThread.onDrawFrame(); - break; - case MSG_SET_ENCODER: - mThread.setEncoder((MediaEncoder)msg.obj); - break; - case MSG_CREATE_SURFACE: - mThread.updatePreviewSurface(); - break; - case MSG_RESIZE: - mThread.resize(msg.arg1, msg.arg2); - break; - case MSG_TERMINATE: - Looper.myLooper().quit(); - mThread = null; - break; - default: - super.handleMessage(msg); - } - } - - private static final class RenderThread extends Thread { - private final Object mSync = new Object(); - private final SurfaceTexture mSurface; - private RenderHandler mHandler; - private EGLBase mEgl; - /** IEglSurface instance related to this TextureView */ - private EGLBase.IEglSurface mEglSurface; - private GLDrawer2D mDrawer; - private int mTexId = -1; - /** SurfaceTexture instance to receive video images */ - private SurfaceTexture mPreviewSurface; - private final float[] mStMatrix = new float[16]; - private MediaEncoder mEncoder; - private int mViewWidth, mViewHeight; - private final FpsCounter mFpsCounter; - - /** - * constructor - * @param surface: drawing surface came from TexureView - */ - public RenderThread(final FpsCounter fpsCounter, final SurfaceTexture surface, final int width, final int height) { - mFpsCounter = fpsCounter; - mSurface = surface; - mViewWidth = width; - mViewHeight = height; - setName("RenderThread"); - } - - public final RenderHandler getHandler() { - if (DEBUG) Log.v(TAG, "RenderThread#getHandler:"); - synchronized (mSync) { - // create rendering thread - if (mHandler == null) - try { - mSync.wait(); - } catch (final InterruptedException e) { - } - } - return mHandler; - } - - public void resize(final int width, final int height) { - if (((width > 0) && (width != mViewWidth)) || ((height > 0) && (height != mViewHeight))) { - mViewWidth = width; - mViewHeight = height; - updatePreviewSurface(); - } else { - synchronized (mSync) { - mSync.notifyAll(); - } - } - } - - public final void updatePreviewSurface() { - if (DEBUG) Log.i(TAG, "RenderThread#updatePreviewSurface:"); - synchronized (mSync) { - if (mPreviewSurface != null) { - if (DEBUG) Log.d(TAG, "updatePreviewSurface:release mPreviewSurface"); - mPreviewSurface.setOnFrameAvailableListener(null); - mPreviewSurface.release(); - mPreviewSurface = null; - } - mEglSurface.makeCurrent(); - if (mTexId >= 0) { - mDrawer.deleteTex(mTexId); - } - // create texture and SurfaceTexture for input from camera - mTexId = mDrawer.initTex(); - if (DEBUG) Log.v(TAG, "updatePreviewSurface:tex_id=" + mTexId); - mPreviewSurface = new SurfaceTexture(mTexId); - mPreviewSurface.setDefaultBufferSize(mViewWidth, mViewHeight); - mPreviewSurface.setOnFrameAvailableListener(mHandler); - // notify to caller thread that previewSurface is ready - mSync.notifyAll(); - } - } - - public final void setEncoder(final MediaEncoder encoder) { - if (DEBUG) Log.v(TAG, "RenderThread#setEncoder:encoder=" + encoder); - if (encoder != null && (encoder instanceof MediaVideoEncoder)) { - ((MediaVideoEncoder)encoder).setEglContext(mEglSurface.getContext(), mTexId); - } - mEncoder = encoder; - } - -/* - * Now you can get frame data as ByteBuffer(as YUV/RGB565/RGBX/NV21 pixel format) using IFrameCallback interface - * with UVCCamera#setFrameCallback instead of using following code samples. - */ -/* // for part1 - private static final int BUF_NUM = 1; - private static final int BUF_STRIDE = 640 * 480; - private static final int BUF_SIZE = BUF_STRIDE * BUF_NUM; - int cnt = 0; - int offset = 0; - final int pixels[] = new int[BUF_SIZE]; - final IntBuffer buffer = IntBuffer.wrap(pixels); */ -/* // for part2 - private ByteBuffer buf = ByteBuffer.allocateDirect(640 * 480 * 4); - */ - /** - * draw a frame (and request to draw for video capturing if it is necessary) - */ - public final void onDrawFrame() { - mEglSurface.makeCurrent(); - // update texture(came from camera) - mPreviewSurface.updateTexImage(); - // get texture matrix - mPreviewSurface.getTransformMatrix(mStMatrix); - // notify video encoder if it exist - if (mEncoder != null) { - // notify to capturing thread that the camera frame is available. - if (mEncoder instanceof MediaVideoEncoder) - ((MediaVideoEncoder)mEncoder).frameAvailableSoon(mStMatrix); - else - mEncoder.frameAvailableSoon(); - } - // draw to preview screen - mDrawer.draw(mTexId, mStMatrix, 0); - mEglSurface.swap(); -/* // sample code to read pixels into Buffer and save as a Bitmap (part1) - buffer.position(offset); - GLES20.glReadPixels(0, 0, 640, 480, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer); - if (++cnt == 100) { // save as a Bitmap, only once on this sample code - // if you save every frame as a Bitmap, app will crash by Out of Memory exception... - Log.i(TAG, "Capture image using glReadPixels:offset=" + offset); - final Bitmap bitmap = createBitmap(pixels,offset, 640, 480); - final File outputFile = MediaMuxerWrapper.getCaptureFile(Environment.DIRECTORY_DCIM, ".png"); - try { - final BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile)); - try { - try { - bitmap.compress(CompressFormat.PNG, 100, os); - os.flush(); - bitmap.recycle(); - } catch (IOException e) { - } - } finally { - os.close(); - } - } catch (FileNotFoundException e) { - } catch (IOException e) { - } - } - offset = (offset + BUF_STRIDE) % BUF_SIZE; -*/ -/* // sample code to read pixels into Buffer and save as a Bitmap (part2) - buf.order(ByteOrder.LITTLE_ENDIAN); // it is enough to call this only once. - GLES20.glReadPixels(0, 0, 640, 480, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); - buf.rewind(); - if (++cnt == 100) { // save as a Bitmap, only once on this sample code - // if you save every frame as a Bitmap, app will crash by Out of Memory exception... - final File outputFile = MediaMuxerWrapper.getCaptureFile(Environment.DIRECTORY_DCIM, ".png"); - BufferedOutputStream os = null; - try { - try { - os = new BufferedOutputStream(new FileOutputStream(outputFile)); - Bitmap bmp = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888); - bmp.copyPixelsFromBuffer(buf); - bmp.compress(Bitmap.CompressFormat.PNG, 90, os); - bmp.recycle(); - } finally { - if (os != null) os.close(); - } - } catch (FileNotFoundException e) { - } catch (IOException e) { - } - } -*/ - } - -/* // sample code to read pixels into IntBuffer and save as a Bitmap (part1) - private static Bitmap createBitmap(final int[] pixels, final int offset, final int width, final int height) { - final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); - paint.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(new float[] { - 0, 0, 1, 0, 0, - 0, 1, 0, 0, 0, - 1, 0, 0, 0, 0, - 0, 0, 0, 1, 0 - }))); - - final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(bitmap); - - final Matrix matrix = new Matrix(); - matrix.postScale(1.0f, -1.0f); - matrix.postTranslate(0, height); - canvas.concat(matrix); - - canvas.drawBitmap(pixels, offset, width, 0, 0, width, height, false, paint); - - return bitmap; - } */ - - @Override - public final void run() { - Log.d(TAG, getName() + " started"); - init(); - Looper.prepare(); - synchronized (mSync) { - mHandler = new RenderHandler(mFpsCounter, this); - mSync.notify(); - } - - Looper.loop(); - - Log.d(TAG, getName() + " finishing"); - release(); - synchronized (mSync) { - mHandler = null; - mSync.notify(); - } - } - - private final void init() { - if (DEBUG) Log.v(TAG, "RenderThread#init:"); - // create EGLContext for this thread - mEgl = EGLBase.createFrom(null, false, false); - mEglSurface = mEgl.createFromSurface(mSurface); - mEglSurface.makeCurrent(); - // create drawing object - mDrawer = new GLDrawer2D(true); - } - - private final void release() { - if (DEBUG) Log.v(TAG, "RenderThread#release:"); - if (mDrawer != null) { - mDrawer.release(); - mDrawer = null; - } - if (mPreviewSurface != null) { - mPreviewSurface.release(); - mPreviewSurface = null; - } - if (mTexId >= 0) { - GLHelper.deleteTex(mTexId); - mTexId = -1; - } - if (mEglSurface != null) { - mEglSurface.release(); - mEglSurface = null; - } - if (mEgl != null) { - mEgl.release(); - mEgl = null; - } - } - } - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/AssetsHelper.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/AssetsHelper.java deleted file mode 100644 index 6b17620d0c..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/AssetsHelper.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.serenegiant.utils; - -import android.content.res.AssetManager; - -import androidx.annotation.NonNull; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -public class AssetsHelper { - - public static String loadString(@NonNull final AssetManager assets, @NonNull final String name) throws IOException { - final StringBuffer sb = new StringBuffer(); - final char[] buf = new char[1024]; - final BufferedReader reader = new BufferedReader(new InputStreamReader(assets.open(name))); - int r = reader.read(buf); - while (r > 0) { - sb.append(buf, 0, r); - r = reader.read(buf); - } - return sb.toString(); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/BuildCheck.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/BuildCheck.java deleted file mode 100644 index fd789a5e1b..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/BuildCheck.java +++ /dev/null @@ -1,458 +0,0 @@ -package com.serenegiant.utils; - -import android.os.Build; - -public final class BuildCheck { - - private static final boolean check(final int value) { - return (Build.VERSION.SDK_INT >= value); - } - - /** - * Magic version number for a current development build, - * which has not yet turned into an official release. API=10000 - * @return - */ - public static boolean isCurrentDevelopment() { - return (Build.VERSION.SDK_INT == Build.VERSION_CODES.CUR_DEVELOPMENT); - } - - /** - * October 2008: The original, first, version of Android. Yay!, API>=1 - * @return - */ - public static boolean isBase() { - return check(Build.VERSION_CODES.BASE); - } - - /** - * February 2009: First Android update, officially called 1.1., API>=2 - * @return - */ - public static boolean isBase11() { - return check(Build.VERSION_CODES.BASE_1_1); - } - - /** - * May 2009: Android 1.5., API>=3 - * @return - */ - public static boolean isCupcake() { - return check(Build.VERSION_CODES.CUPCAKE); - } - - /** - * May 2009: Android 1.5., API>=3 - * @return - */ - public static boolean isAndroid1_5() { - return check(Build.VERSION_CODES.CUPCAKE); - } - - /** - * September 2009: Android 1.6., API>=4 - * @return - */ - public static boolean isDonut() { - return check(Build.VERSION_CODES.DONUT); - } - - /** - * September 2009: Android 1.6., API>=4 - * @return - */ - public static boolean isAndroid1_6() { - return check(Build.VERSION_CODES.DONUT); - } - - /** - * November 2009: Android 2.0, API>=5 - * @return - */ - public static boolean isEclair() { - return check(Build.VERSION_CODES.ECLAIR); - } - - /** - * November 2009: Android 2.0, API>=5 - * @return - */ - public static boolean isAndroid2_0() { - return check(Build.VERSION_CODES.ECLAIR); - } - - /** - * December 2009: Android 2.0.1, API>=6 - * @return - */ - public static boolean isEclair01() { - return check(Build.VERSION_CODES.ECLAIR_0_1); - } - - /** - * January 2010: Android 2.1, API>=7 - * @return - */ - public static boolean isEclairMR1() { - return check(Build.VERSION_CODES.ECLAIR_MR1); - } - - /** - * June 2010: Android 2.2, API>=8 - * @return - */ - public static boolean isFroyo() { - return check(Build.VERSION_CODES.FROYO); - } - - /** - * June 2010: Android 2.2, API>=8 - * @return - */ - public static boolean isAndroid2_2() { - return check(Build.VERSION_CODES.FROYO); - } - - /** - * November 2010: Android 2.3, API>=9 - * @return - */ - public static boolean isGingerBread() { - return check(Build.VERSION_CODES.GINGERBREAD); - } - - /** - * November 2010: Android 2.3, API>=9 - * @return - */ - public static boolean isAndroid2_3() { - return check(Build.VERSION_CODES.GINGERBREAD); - } - - /** - * February 2011: Android 2.3.3., API>=10 - * @return - */ - public static boolean isGingerBreadMR1() { - return check(Build.VERSION_CODES.GINGERBREAD_MR1); - } - - /** - * February 2011: Android 2.3.3., API>=10 - * @return - */ - public static boolean isAndroid2_3_3() { - return check(Build.VERSION_CODES.GINGERBREAD_MR1); - } - - /** - * February 2011: Android 3.0., API>=11 - * @return - */ - public static boolean isHoneyComb() { - return check(Build.VERSION_CODES.HONEYCOMB); - } - - /** - * February 2011: Android 3.0., API>=11 - * @return - */ - public static boolean isAndroid3() { - return check(Build.VERSION_CODES.HONEYCOMB); - } - - /** - * May 2011: Android 3.1., API>=12 - * @return - */ - public static boolean isHoneyCombMR1() { - return check(Build.VERSION_CODES.HONEYCOMB_MR1); - } - - /** - * May 2011: Android 3.1., API>=12 - * @return - */ - public static boolean isAndroid3_1() { - return check(Build.VERSION_CODES.HONEYCOMB_MR1); - } - - /** - * June 2011: Android 3.2., API>=13 - * @return - */ - public static boolean isHoneyCombMR2() { - return check(Build.VERSION_CODES.HONEYCOMB_MR2); - } - - /** - * June 2011: Android 3.2., API>=13 - * @return - */ - public static boolean isAndroid3_2() { - return check(Build.VERSION_CODES.HONEYCOMB_MR2); - } - - /** - * October 2011: Android 4.0., API>=14 - * @return - */ - public static boolean isIcecreamSandwich() { - return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH); - } - - /** - * October 2011: Android 4.0., API>=14 - * @return - */ - public static boolean isAndroid4() { - return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH); - } - - /** - * December 2011: Android 4.0.3., API>=15 - * @return - */ - public static boolean isIcecreamSandwichMR1() { - return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1); - } - - /** - * December 2011: Android 4.0.3., API>=15 - * @return - */ - public static boolean isAndroid4_0_3() { - return check(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1); - } - - /** - * June 2012: Android 4.1., API>=16 - * @return - */ - public static boolean isJellyBean() { - return check(Build.VERSION_CODES.JELLY_BEAN); - } - - /** - * June 2012: Android 4.1., API>=16 - * @return - */ - public static boolean isAndroid4_1() { - return check(Build.VERSION_CODES.JELLY_BEAN); - } - - /** - * November 2012: Android 4.2, Moar jelly beans!, API>=17 - * @return - */ - public static boolean isJellyBeanMr1() { - return check(Build.VERSION_CODES.JELLY_BEAN_MR1); - } - - /** - * November 2012: Android 4.2, Moar jelly beans!, API>=17 - * @return - */ - public static boolean isAndroid4_2() { - return check(Build.VERSION_CODES.JELLY_BEAN_MR1); - } - - /** - * July 2013: Android 4.3, the revenge of the beans., API>=18 - * @return - */ - public static boolean isJellyBeanMR2() { - return check(Build.VERSION_CODES.JELLY_BEAN_MR2); - } - - /** - * July 2013: Android 4.3, the revenge of the beans., API>=18 - * @return - */ - public static boolean isAndroid4_3() { - return check(Build.VERSION_CODES.JELLY_BEAN_MR2); - } - - /** - * October 2013: Android 4.4, KitKat, another tasty treat., API>=19 - * @return - */ - public static boolean isKitKat() { - return check(Build.VERSION_CODES.KITKAT); - } - - /** - * October 2013: Android 4.4, KitKat, another tasty treat., API>=19 - * @return - */ - public static boolean isAndroid4_4() { - return check(Build.VERSION_CODES.KITKAT); - } - - /** - * Android 4.4W: KitKat for watches, snacks on the run., API>=20 - * @return - */ - public static boolean isKitKatWatch() { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH); - } - - /** - * Lollipop. A flat one with beautiful shadows. But still tasty., API>=21 - * @return - */ - public static boolean isL() { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); - } - - /** - * Lollipop. A flat one with beautiful shadows. But still tasty., API>=21 - * @return - */ - public static boolean isLollipop() { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); - } - - /** - * Lollipop. A flat one with beautiful shadows. But still tasty., API>=21 - * @return - */ - public static boolean isAndroid5() { - return check(Build.VERSION_CODES.LOLLIPOP); - } - - /** - * Lollipop with an extra sugar coating on the outside!, API>=22 - * @return - */ - public static boolean isLollipopMR1() { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1); - } - - /** - * Marshmallow. A flat one with beautiful shadows. But still tasty., API>=23 - * @return - */ - public static boolean isM() { - return check(Build.VERSION_CODES.M); - } - - /** - * Marshmallow. A flat one with beautiful shadows. But still tasty., API>=23 - * @return - */ - public static boolean isMarshmallow() { - return check(Build.VERSION_CODES.M); - } - - /** - * Marshmallow. A flat one with beautiful shadows. But still tasty., API>=23 - * @return - */ - public static boolean isAndroid6() { - return check(Build.VERSION_CODES.M); - } - - /** - * 虫歯の元, API >= 24 - * @return - */ - public static boolean isN() { - return check(Build.VERSION_CODES.N); - } - - /** - * 歯にくっつくやつ, API >= 24 - * @return - */ - public static boolean isNougat() { - return check(Build.VERSION_CODES.N); - } - /** - * API >= 24 - * @return - */ - public static boolean isAndroid7() { - return check(Build.VERSION_CODES.N); - } - - /** - * API>=25 - * @return - */ - public static boolean isNMR1() { - return check(Build.VERSION_CODES.N_MR1); - } - - /** - * API>=25 - * @return - */ - public static boolean isNougatMR1() { - return check(Build.VERSION_CODES.N_MR1); - } - - /** - * おれおれぇー API>=26 - * @return - */ - public static boolean isO() { - return check(Build.VERSION_CODES.O); - } - - /** - * おれおれぇー API>=26 - * @return - */ - public static boolean isOreo() { - return check(Build.VERSION_CODES.O); - } - - /** - * おれおれぇー API>=26 - * @return - */ - public static boolean isAndroid8() { - return check(Build.VERSION_CODES.O); - } - - /** - * おれおれぇー API>=27 - * @return - */ - public static boolean isOMR1() { - return check(Build.VERSION_CODES.O_MR1); - } - - /** - * おれおれぇー MR1 API>=27 - * @return - */ - public static boolean isOreoMR1() { - return check((Build.VERSION_CODES.O_MR1)); - } - - /** - * おっ!ぱい API>=28 - * @return - */ - public static boolean isP() { - return check((Build.VERSION_CODES.P)); - } - - /** - * おっ!ぱい API>=28 - * @return - */ - public static boolean isPie() { - return check((Build.VERSION_CODES.P)); - } - - /** - * おっ!ぱい API>=28 - * @return - */ - public static boolean isAndroid9() { - return check((Build.VERSION_CODES.P)); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/FpsCounter.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/FpsCounter.java deleted file mode 100644 index a60d4f770b..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/FpsCounter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.serenegiant.utils; - -public class FpsCounter { - private int cnt, prevCnt; - private long startTime, prevTime; - private float fps, totalFps; - public FpsCounter() { - reset(); - } - - public synchronized FpsCounter reset() { - cnt = prevCnt = 0; - startTime = prevTime = Time.nanoTime() - 1; - return this; - } - - /** - * フレームをカウント - */ - public synchronized void count() { - cnt++; - } - - /** - * FPSの値を更新, 1秒程度毎に呼び出す - * @return - */ - public synchronized FpsCounter update() { - final long t = Time.nanoTime(); - fps = (cnt - prevCnt) * 1000000000.0f / (t - prevTime); - prevCnt = cnt; - prevTime = t; - totalFps = cnt * 1000000000.0f / (t - startTime); - return this; - } - - public synchronized float getFps() { - return fps; - } - - public synchronized float getTotalFps() { - return totalFps; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/HandlerThreadHandler.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/HandlerThreadHandler.java deleted file mode 100644 index 81dcd39159..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/HandlerThreadHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.serenegiant.utils; - -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -public class HandlerThreadHandler extends Handler { - private static final String TAG = "HandlerThreadHandler"; - - public static final HandlerThreadHandler createHandler() { - return createHandler(TAG); - } - - public static final HandlerThreadHandler createHandler(final String name) { - final HandlerThread thread = new HandlerThread(name); - thread.start(); - return new HandlerThreadHandler(thread.getLooper()); - } - - public static final HandlerThreadHandler createHandler(@Nullable final Callback callback) { - return createHandler(TAG, callback); - } - - public static final HandlerThreadHandler createHandler(final String name, @Nullable final Callback callback) { - final HandlerThread thread = new HandlerThread(name); - thread.start(); - return new HandlerThreadHandler(thread.getLooper(), callback); - } - - private HandlerThreadHandler(@NonNull final Looper looper) { - super(looper); - } - - private HandlerThreadHandler(@NonNull final Looper looper, @Nullable final Callback callback) { - super(looper, callback); - } - -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/MessageTask.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/MessageTask.java deleted file mode 100644 index 852d432025..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/MessageTask.java +++ /dev/null @@ -1,515 +0,0 @@ -package com.serenegiant.utils; - -import android.util.Log; - -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.LinkedBlockingQueue; - -public abstract class MessageTask implements Runnable { -// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること - private static final String TAG = MessageTask.class.getSimpleName(); - - public static class TaskBreak extends RuntimeException { - } - - protected static final class Request { - int request; - int arg1; - int arg2; - Object obj; - int request_for_result; - Object result; - - private Request() { - request = request_for_result = REQUEST_TASK_NON; - } - - /** - * @param _request minus value is reserved internal use - * @param _arg1 - * @param _arg2 - * @param _obj - */ - public Request(final int _request, final int _arg1, final int _arg2, final Object _obj) { - request = _request; - arg1 = _arg1; - arg2 = _arg2; - obj = _obj; - request_for_result = REQUEST_TASK_NON; - } - - public void setResult(final Object result) { - synchronized (this) { - this.result = result; - request = request_for_result = REQUEST_TASK_NON; - notifyAll(); - } - } - - @Override - public boolean equals(final Object o) { - return (o instanceof Request) - ? (request == ((Request) o).request) - && (request_for_result == ((Request)o).request_for_result) - && (arg1 == ((Request) o).arg1) - && (arg2 == ((Request) o).arg2) - && (obj == ((Request) o).obj) - : super.equals(o); - } - } - - // minus values and zero are reserved for internal use - protected static final int REQUEST_TASK_NON = 0; - protected static final int REQUEST_TASK_RUN = -1; - protected static final int REQUEST_TASK_RUN_AND_WAIT = -2; - protected static final int REQUEST_TASK_START = -8; - protected static final int REQUEST_TASK_QUIT = -9; - - private final Object mSync = new Object(); - /** プール/キューのサイズ, -1なら無制限 */ - private final int mMaxRequest; - private final LinkedBlockingQueue mRequestPool; // FIXME これはArrayListにした方が速いかも - private final LinkedBlockingDeque mRequestQueue; - private volatile boolean mIsRunning, mFinished; - private Thread mWorkerThread; - - /** - * コンストラクタ - * プール&キューのサイズは無制限 - * プールは空で生成 - */ - public MessageTask() { - mMaxRequest = -1; - mRequestPool = new LinkedBlockingQueue(); - mRequestQueue = new LinkedBlockingDeque(); - } - - /** - * コンストラクタ - * プール&キューのサイズは無制限 - * @param init_num プールするRequestの初期数を指定 - */ - public MessageTask(final int init_num) { - mMaxRequest = -1; - mRequestPool = new LinkedBlockingQueue(); - mRequestQueue = new LinkedBlockingDeque(); - for (int i = 0; i < init_num; i++) { - if (!mRequestPool.offer(new Request())) break; - } - } - - /** - * コンストラクタ - * プール及びキュー可能な最大サイズを指定して初期化 - * @param max_request キューの最大サイズを指定 - * @param init_num プールするRequestの初期数を指定, max_requestよりも大きければ切り捨てる - */ - public MessageTask(final int max_request, final int init_num) { - mMaxRequest = max_request; - mRequestPool = new LinkedBlockingQueue(max_request); - mRequestQueue = new LinkedBlockingDeque(max_request); - for (int i = 0; i < init_num; i++) { - if (!mRequestPool.offer(new Request())) break; - } - } - - /** - * 初期化要求。継承クラスのコンストラクタから呼び出すこと - * パラメータはonInitに引き渡される - * @param arg1 - * @param arg2 - * @param obj - */ - protected void init(final int arg1, final int arg2, final Object obj) { - mFinished = false; - mRequestQueue.offer(obtain(REQUEST_TASK_START, arg1, arg2, obj)); -// offer(REQUEST_TASK_START, arg1, arg2, obj); - } - - /** 初期化処理 */ - protected abstract void onInit(final int arg1, final int arg2, final Object obj); - - /** 要求処理ループ開始直前に呼ばれる */ - protected abstract void onStart(); - - /** onStopの直前に呼び出される, interruptされた時は呼び出されない */ - protected void onBeforeStop() {} - - /** 停止処理, interruptされた時は呼び出されない */ - protected abstract void onStop(); - - /** onStop後に呼び出される。onStopで例外発生しても呼ばれる */ - protected abstract void onRelease(); - - /** - * メッセージ処理ループ中でのエラー発生時の処理 - * デフフォルトはtrueを返しメッセージ処理ループを終了する - * @return trueを返すとメッセージ処理ループを終了する - */ - protected boolean onError(final Exception e) { -// if (DEBUG) Log.w(TAG, e); - return true; - } - - /** 要求メッセージの処理(内部メッセージは来ない) - * TaskBreakをthrowすると要求メッセージ処理ループを終了する */ - protected abstract Object processRequest(final int request, final int arg1, final int arg2, final Object obj) throws TaskBreak; - - /** 要求メッセージを取り出す処理(要求メッセージがなければブロックされる) */ - protected Request takeRequest() throws InterruptedException { - return mRequestQueue.take(); - } - - public boolean waitReady() { - synchronized (mSync) { - for ( ; !mIsRunning && !mFinished ; ) { - try { - mSync.wait(500); - } catch (final InterruptedException e) { - break; - } - } - return mIsRunning; - } - } - - public boolean isRunning() { - return mIsRunning; - } - - public boolean isFinished() { - return mFinished; - } - - @Override - public void run() { - Request request = null; - mIsRunning = true; - try { - request = mRequestQueue.take(); - } catch (final InterruptedException e) { - mIsRunning = false; - mFinished = true; - } - synchronized (mSync) { - if (mIsRunning) { - mWorkerThread = Thread.currentThread(); - try { - onInit(request.arg1, request.arg2, request.obj); - } catch (final Exception e) { - Log.w(TAG, e); - mIsRunning = false; - mFinished = true; - } - } - mSync.notifyAll(); - } - if (mIsRunning) { - try { - onStart(); - } catch (final Exception e) { - if (callOnError(e)) { - mIsRunning = false; - mFinished = true; - } - } - } -LOOP: for (; mIsRunning; ) { - try { - request = takeRequest(); - switch (request.request) { - case REQUEST_TASK_NON: - break; - case REQUEST_TASK_QUIT: - break LOOP; - case REQUEST_TASK_RUN: - if (request.obj instanceof Runnable) - try { - ((Runnable)request.obj).run(); - } catch (final Exception e) { - if (callOnError(e)) - break LOOP; - } - break; - case REQUEST_TASK_RUN_AND_WAIT: - try { - request.setResult(processRequest(request.request_for_result, request.arg1, request.arg2, request.obj)); - } catch (final TaskBreak e) { - request.setResult(null); - break LOOP; - } catch (final Exception e) { - request.setResult(null); - if (callOnError(e)) - break LOOP; - } - break; - default: - try { - processRequest(request.request, request.arg1, request.arg2, request.obj); - } catch (final TaskBreak e) { - break LOOP; - } catch (final Exception e) { - if (callOnError(e)) - break LOOP; - } - break; - } - request.request = request.request_for_result = REQUEST_TASK_NON; - // プールへ返却する - mRequestPool.offer(request); - } catch (final InterruptedException e) { - break; - } - } - final boolean interrupted = Thread.interrupted(); - synchronized (mSync) { - mWorkerThread = null; - mIsRunning = false; - mFinished = true; - } - if (!interrupted) { - try { - onBeforeStop(); - onStop(); - } catch (final Exception e) { - callOnError(e); - } - } - try { - onRelease(); - } catch (final Exception e) { - // callOnError(e); - } - synchronized (mSync) { - mSync.notifyAll(); - } - } - - /** - * エラー処理。onErrorを呼び出す。 - * trueを返すと要求メッセージ処理ループを終了する - * @param e - * @return - */ - protected boolean callOnError(final Exception e) { - try { - return onError(e); - } catch (final Exception e2) { -// if (DEBUG) Log.e(TAG, "exception occurred in callOnError", e); - } - return true; - } - - /** - * RequestプールからRequestを取得する - * プールが空の場合は新規に生成する - * @param request minus values and zero are reserved - * @param arg1 - * @param arg2 - * @param obj - * @return Request - */ - protected Request obtain(final int request, final int arg1, final int arg2, final Object obj) { - Request req = mRequestPool.poll(); - if (req != null) { - req.request = request; - req.arg1 = arg1; - req.arg2 = arg2; - req.obj = obj; - } else { - req = new Request(request, arg1, arg2, obj); - } - return req; - } - - /** - * offer request to run on worker thread - * @param request minus values and zero are reserved - * @param arg1 - * @param arg2 - * @param obj - * @return true if success offer - */ - public boolean offer(final int request, final int arg1, final int arg2, final Object obj) { - return !mFinished && mRequestQueue.offer(obtain(request, arg1, arg2, obj)); - } - - /** - * offer request to run on worker thread - * @param request minus values and zero are reserved - * @param arg1 - * @param obj - * @return true if success offer - */ - public boolean offer(final int request, final int arg1, final Object obj) { - return !mFinished && mRequestQueue.offer(obtain(request, arg1, 0, obj)); - } - - /** - * offer request to run on worker thread - * @param request minus values and zero are reserved - * @param arg1 - * @param arg2 - * @return true if success offer - */ - public boolean offer(final int request, final int arg1, final int arg2) { - return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, arg1, arg2, null)); - } - - /** - * offer request to run on worker thread - * @param request minus values and zero are reserved - * @param arg1 - * @return true if success offer - */ - public boolean offer(final int request, final int arg1) { - return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, arg1, 0, null)); - } - - /** - * offer request to run on worker thread - * @param request minus values and zero are reserved - * @return true if success offer - */ - public boolean offer(final int request) { - return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, 0, 0, null)); - } - - /** - * offer request to run on worker thread - * @param request minus values and zero are reserved - * @param obj - * @return true if success offer - */ - public boolean offer(final int request, final Object obj) { - return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, 0, 0, obj)); - } - - /** - * offer request to run on worker thread on top of the request queue - * @param request minus values and zero are reserved - * @param arg1 - * @param arg2 - */ - public boolean offerFirst(final int request, final int arg1, final int arg2, final Object obj) { - return !mFinished && mIsRunning && mRequestQueue.offerFirst(obtain(request, arg1, arg2, obj)); - } - - /** - * offer request to run on worker thread and wait for result - * caller thread is blocked until the request finished running on worker thread - * FIXME このメソッドはMessageTaskを実行中のスレッド上で呼び出すとデッドロックする - * @param request - * @param arg1 - * @param arg2 - * @param obj - * @return - */ - public Object offerAndWait(final int request, final int arg1, final int arg2, final Object obj) { - if (!mFinished && (request > REQUEST_TASK_NON)) { - final Request req = obtain(REQUEST_TASK_RUN_AND_WAIT, arg1, arg2, obj); - synchronized (req) { - req.request_for_result = request; - req.result = null; - mRequestQueue.offer(req); - for (; mIsRunning && (req.request_for_result != REQUEST_TASK_NON); ) { - try { - req.wait(100); - } catch (final InterruptedException e) { - break; - } - } - } - return req.result; - } else { - return null; - } - } - - /** - * request to run on worker thread - * @param task - * @return true if success queue - */ - public boolean queueEvent(final Runnable task) { - return !mFinished && (task != null) && offer(REQUEST_TASK_RUN, task); - } - - public void removeRequest(final Request request) { - for (final Request req: mRequestQueue) { - if (!mIsRunning || mFinished) break; - if (req.equals(request)) { - mRequestQueue.remove(req); - mRequestPool.offer(req); - } - } - } - - public void removeRequest(final int request) { - for (final Request req: mRequestQueue) { - if (!mIsRunning || mFinished) break; - if (req.request == request) { - mRequestQueue.remove(req); - mRequestPool.offer(req); - } - } - } - - /** - * request terminate worker thread and release all related resources - */ - public void release() { - release(false); - } - - /** - * request terminate worker thread and release all related resources - * @param interrupt trueなら実行中のタスクをinterruptする - */ - public void release(final boolean interrupt) { - final boolean b = mIsRunning; - mIsRunning = false; - if (!mFinished) { - mRequestQueue.clear(); - mRequestQueue.offerFirst(obtain(REQUEST_TASK_QUIT, 0, 0, null)); - synchronized (mSync) { - if (b) { - final long current = Thread.currentThread().getId(); - final long id = mWorkerThread != null ? mWorkerThread.getId() : current; - if (id != current) { - if (interrupt && (mWorkerThread != null)) { - mWorkerThread.interrupt(); - } - for ( ; !mFinished ; ) { - try { - mSync.wait(300); - } catch (final InterruptedException e) { - // ignore - } - } - } - } - } - } - } - - /** - * 実行中のタスクが終了後開放する - */ - public void releaseSelf() { - mIsRunning = false; - if (!mFinished) { - mRequestQueue.clear(); - mRequestQueue.offerFirst(obtain(REQUEST_TASK_QUIT, 0, 0, null)); - } - } - - /** - * processRequest内でメッセージループを非常終了させるためのヘルパーメソッド - * 単にTaskBreakをthrowするだけ - * @throws TaskBreak - */ - public void userBreak() throws TaskBreak { - throw new TaskBreak(); - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/PermissionCheck.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/PermissionCheck.java deleted file mode 100644 index f3409fb84e..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/PermissionCheck.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.serenegiant.utils; - -import android.Manifest.permission; -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PermissionGroupInfo; -import android.net.Uri; -import android.provider.Settings; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public final class PermissionCheck { - - public static final void dumpPermissions(@Nullable final Context context) { - if (context == null) return; - try { - final PackageManager pm = context.getPackageManager(); - final List list = pm.getAllPermissionGroups(PackageManager.GET_META_DATA); - for (final PermissionGroupInfo info : list) { - Log.d("PermissionCheck", info.name); - } - } catch (final Exception e) { - Log.w("", e); - } - } - - /** - * パーミッションを確認 - * @param context - * @param permissionName - * @return 指定したパーミッションがあればtrue - */ - @SuppressLint("NewApi") - public static boolean hasPermission(@Nullable final Context context, final String permissionName) { - if (context == null) return false; - boolean result = false; - try { - final int check; - if (BuildCheck.isMarshmallow()) { - check = context.checkSelfPermission(permissionName); - } else { - final PackageManager pm = context.getPackageManager(); - check = pm.checkPermission(permissionName, context.getPackageName()); - } - switch (check) { - case PackageManager.PERMISSION_DENIED: - break; - case PackageManager.PERMISSION_GRANTED: - result = true; - break; - } - } catch (final Exception e) { - Log.w("", e); - } - return result; - } - - /** - * 録音のミッションがあるかどうかを確認 - * @param context - * @return 録音のパーミッションがあればtrue - */ - public static boolean hasAudio(@Nullable final Context context) { - return hasPermission(context, permission.RECORD_AUDIO); - } - - /** - * ネットワークへのアクセスパーミッションがあるかどうかを確認 - * @param context - * @return ネットワークへのアクセスパーミッションがあればtrue - */ - public static boolean hasNetwork(@Nullable final Context context) { - return hasPermission(context, permission.INTERNET); - } - - /** - * 外部ストレージへの書き込みパーミッションがあるかどうかを確認 - * @param context - * @return 外部ストレージへの書き込みパーミッションがあればtrue - */ - public static boolean hasWriteExternalStorage(@Nullable final Context context) { - return hasPermission(context, permission.WRITE_EXTERNAL_STORAGE); - } - - /** - * 外部ストレージからの読み込みパーミッションがあるかどうかを確認 - * @param context - * @return 外部ストレージへの読み込みパーミッションがあればtrue - */ - @SuppressLint("InlinedApi") - public static boolean hasReadExternalStorage(@Nullable final Context context) { - if (BuildCheck.isAndroid4()) - return hasPermission(context, permission.READ_EXTERNAL_STORAGE); - else - return hasPermission(context, permission.WRITE_EXTERNAL_STORAGE); - } - - /** - * 位置情報アクセスのパーミッションが有るかどうかを確認 - * @param context - * @return - */ - public static boolean hasAccessLocation(@Nullable final Context context) { - return hasPermission(context, permission.ACCESS_COARSE_LOCATION) - && hasPermission(context, permission.ACCESS_FINE_LOCATION); - } - - /** - * 低精度位置情報アクセスのパーミッションが有るかどうかを確認 - * @param context - * @return - */ - public static boolean hasAccessCoarseLocation(@Nullable final Context context) { - return hasPermission(context, permission.ACCESS_COARSE_LOCATION); - } - - /** - * 高精度位置情報アクセスのパーミッションが有るかどうかを確認 - * @param context - * @return - */ - public static boolean hasAccessFineLocation(@Nullable final Context context) { - return hasPermission(context, permission.ACCESS_FINE_LOCATION); - } - - /** - * カメラへアクセス可能かどうか - * @param context - * @return - */ - public static boolean hasCamera(@Nullable final Context context) { - return hasPermission(context, permission.CAMERA); - } - - /** - * アプリの詳細設定へ遷移させる(パーミッションを取得できなかった時など) - * @param context - */ - public static void openSettings(@NonNull final Context context) { - final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - final Uri uri = Uri.fromParts("package", context.getPackageName(), null); - intent.setData(uri); - context.startActivity(intent); - } - - /** - * AndroidManifest.xmlに設定されているはずのパーミッションをチェックする - * @param context - * @param expectations - * @return 空リストなら全てのパーミッションが入っていた, - * @throws IllegalArgumentException - * @throws PackageManager.NameNotFoundException - */ - public static List missingPermissions(@NonNull final Context context, @NonNull final String[] expectations) throws IllegalArgumentException, PackageManager.NameNotFoundException { - return missingPermissions(context, new ArrayList(Arrays.asList(expectations))); - } - - /** - * AndroidManifest.xmlに設定されているはずのパーミッションをチェックする - * @param context - * @param expectations - * @return 空リストなら全てのパーミッションが入っていた, - * @throws IllegalArgumentException - * @throws PackageManager.NameNotFoundException - */ - public static List missingPermissions(@NonNull final Context context, @NonNull final List expectations) throws IllegalArgumentException, PackageManager.NameNotFoundException { - final PackageManager pm = context.getPackageManager(); - final PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); - final String[] info = pi.requestedPermissions; - if (info != null) { - for (String i : info) { - expectations.remove(i); - } - } - return expectations; - } -} diff --git a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/Time.java b/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/Time.java deleted file mode 100644 index 6d7ecb3894..0000000000 --- a/libraries/map-usbcamera/src/main/java/com/serenegiant/utils/Time.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.serenegiant.utils; - -import android.annotation.SuppressLint; -import android.os.SystemClock; - -public class Time { - - public static boolean prohibitElapsedRealtimeNanos = true; - - private static Time sTime; - static { - reset(); - } - - public static long nanoTime() { - return sTime.timeNs(); - } - - public static void reset() { - if (!prohibitElapsedRealtimeNanos && BuildCheck.isJellyBeanMr1()) { - sTime = new TimeJellyBeanMr1(); - } else { - sTime = new Time(); - } - } - - private Time() { - } - - @SuppressLint("NewApi") - private static class TimeJellyBeanMr1 extends Time { - public long timeNs() { - return SystemClock.elapsedRealtimeNanos(); - } - } - - protected long timeNs() { - return System.nanoTime(); - } -} diff --git a/libraries/map-usbcamera/src/main/java/org/easydarwin/sw/JNIUtil.java b/libraries/map-usbcamera/src/main/java/org/easydarwin/sw/JNIUtil.java deleted file mode 100644 index 8e5c48e658..0000000000 --- a/libraries/map-usbcamera/src/main/java/org/easydarwin/sw/JNIUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.easydarwin.sw; - -/** - */ -public class JNIUtil { - - static { - System.loadLibrary("Utils"); - } - - /** - * 都是Y:U:V = 4:1:1但 U与 V顺序相反。变换可逆 - * - * @param buffer - * @param width - * @param height - */ - public static void yV12ToYUV420P(byte[] buffer, int width, int height) { - callMethod("YV12ToYUV420P", null, buffer, width, height); - } - - /** - * 都是Y:U+V = 4:2,但是这两者U、V方向相反。变换可逆 - * - * @param buffer - * @param width - * @param height - */ - public static void nV21To420SP(byte[] buffer, int width, int height) { - callMethod("NV21To420SP", null, buffer, width, height); - } - - /** - * 旋转1个字节为单位的矩阵 - * - * @param data 要旋转的矩阵 - * @param offset 偏移量 - * @param width 宽度 - * @param height 高度 - * @param degree 旋转度数 - */ - public static void rotateMatrix(byte[] data, int offset, int width, int height, int degree) { - callMethod("RotateByteMatrix", null, data, offset, width, height, degree); - } - - /** - * 旋转2个字节为单位的矩阵 - * - * @param data 要旋转的矩阵 - * @param offset 偏移量 - * @param width 宽度 - * @param height 高度 - * @param degree 旋转度数 - */ - public static void rotateShortMatrix(byte[] data, int offset, int width, int height, int degree) { - callMethod("RotateShortMatrix", null, data, offset, width, height, degree); - } - - private static native void callMethod(String methodName, Object[] returnValue, Object... params); - -} diff --git a/libraries/map-usbcamera/src/main/java/org/easydarwin/sw/TxtOverlay.java b/libraries/map-usbcamera/src/main/java/org/easydarwin/sw/TxtOverlay.java deleted file mode 100644 index 60f9e9de96..0000000000 --- a/libraries/map-usbcamera/src/main/java/org/easydarwin/sw/TxtOverlay.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.easydarwin.sw; - -import android.content.Context; -import android.content.res.AssetManager; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Created by jiangdg on 2020/1/11. - */ - -public class TxtOverlay { - - static { - System.loadLibrary("TxtOverlay"); - } - - private static TxtOverlay instance; - private final Context context; - private long ctx; - - private TxtOverlay(Context context){ - this.context = context; - } - - public static TxtOverlay getInstance() { - if(instance == null) { - throw new IllegalArgumentException("please call install in your application!"); - } - return instance; - } - - public static void install(Context context) { - if(instance == null) { - instance = new TxtOverlay(context.getApplicationContext()); - - File youyuan = context.getFileStreamPath("SIMYOU.ttf"); - if (!youyuan.exists()){ - AssetManager am = context.getAssets(); - try { - InputStream is = am.open("zk/SIMYOU.ttf"); - FileOutputStream os = context.openFileOutput("SIMYOU.ttf", Context.MODE_PRIVATE); - byte[] buffer = new byte[1024]; - int len = 0; - while ((len = is.read(buffer)) != -1) { - os.write(buffer, 0, len); - } - os.close(); - is.close(); - - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - public void init(int width, int height) { - File youyuan = context.getFileStreamPath("SIMYOU.ttf"); - if (!youyuan.exists()){ - throw new IllegalArgumentException("the font file must be exists,please call install before!"); - } - ctx = txtOverlayInit(width, height,youyuan.getAbsolutePath()); - } - - public void overlay(byte[] data, - String txt) { -// txt = "drawtext=fontfile="+context.getFileStreamPath("SIMYOU.ttf")+": text='EasyPusher 2017':x=(w-text_w)/2:y=H-60 :fontcolor=white :box=1:boxcolor=0x00000000@0.3"; -// txt = "movie=/sdcard/qrcode.png [logo];[in][logo] " -// + "overlay=" + 0 + ":" + 0 -// + " [out]"; -// if (ctx == 0) throw new RuntimeException("init should be called at first!"); - if (ctx == 0) return; - txtOverlay(ctx, data, txt); - } - - public void release() { - if (ctx == 0) return; - txtOverlayRelease(ctx); - ctx = 0; - } - - - private static native long txtOverlayInit(int width, int height, String fonts); - - private static native void txtOverlay(long ctx, byte[] data, String txt); - - private static native void txtOverlayRelease(long ctx); - -} diff --git a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libTxtOverlay.so b/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libTxtOverlay.so deleted file mode 100644 index f466716ce6..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libTxtOverlay.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUVCCamera.so b/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUVCCamera.so deleted file mode 100644 index 6b4d9fdfc4..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUVCCamera.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUtils.so b/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUtils.so deleted file mode 100644 index f0c3822a1d..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libUtils.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libjpeg-turbo1500.so b/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libjpeg-turbo1500.so deleted file mode 100644 index 7965444d8e..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libjpeg-turbo1500.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libusb100.so b/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libusb100.so deleted file mode 100644 index c27d595219..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libusb100.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libuvc.so b/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libuvc.so deleted file mode 100644 index 1f2486a5f6..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/arm64-v8a/libuvc.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libTxtOverlay.so b/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libTxtOverlay.so deleted file mode 100644 index a1139c47b8..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libTxtOverlay.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so b/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so deleted file mode 100644 index b6bf9769a5..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUVCCamera.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUtils.so b/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUtils.so deleted file mode 100644 index 681a9385d3..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libUtils.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so b/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so deleted file mode 100644 index 97408c6d46..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libjpeg-turbo1500.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so b/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so deleted file mode 100644 index 4f2603950e..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libusb100.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so b/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so deleted file mode 100644 index ba68f84d05..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/armeabi-v7a/libuvc.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86/libUVCCamera.so b/libraries/map-usbcamera/src/main/jniLibs/x86/libUVCCamera.so deleted file mode 100644 index df770e4e3a..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86/libUVCCamera.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so b/libraries/map-usbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so deleted file mode 100644 index d4b67c637c..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86/libjpeg-turbo1500.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86/libusb100.so b/libraries/map-usbcamera/src/main/jniLibs/x86/libusb100.so deleted file mode 100644 index 59d8f256cb..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86/libusb100.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86/libuvc.so b/libraries/map-usbcamera/src/main/jniLibs/x86/libuvc.so deleted file mode 100644 index fdf4318185..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86/libuvc.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libUVCCamera.so b/libraries/map-usbcamera/src/main/jniLibs/x86_64/libUVCCamera.so deleted file mode 100644 index 4c1ea8ab15..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libUVCCamera.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libjpeg-turbo1500.so b/libraries/map-usbcamera/src/main/jniLibs/x86_64/libjpeg-turbo1500.so deleted file mode 100644 index ee0ff7afe8..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libjpeg-turbo1500.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libusb100.so b/libraries/map-usbcamera/src/main/jniLibs/x86_64/libusb100.so deleted file mode 100644 index 0c7cf3a9ae..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libusb100.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libuvc.so b/libraries/map-usbcamera/src/main/jniLibs/x86_64/libuvc.so deleted file mode 100644 index 1c4eb3ecb8..0000000000 Binary files a/libraries/map-usbcamera/src/main/jniLibs/x86_64/libuvc.so and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/res/layout/dialog_camera.xml b/libraries/map-usbcamera/src/main/res/layout/dialog_camera.xml deleted file mode 100644 index 0d799d6deb..0000000000 --- a/libraries/map-usbcamera/src/main/res/layout/dialog_camera.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/libraries/map-usbcamera/src/main/res/layout/listitem_device.xml b/libraries/map-usbcamera/src/main/res/layout/listitem_device.xml deleted file mode 100644 index 0ac831a8cd..0000000000 --- a/libraries/map-usbcamera/src/main/res/layout/listitem_device.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - \ No newline at end of file diff --git a/libraries/map-usbcamera/src/main/res/raw/camera_click.ogg b/libraries/map-usbcamera/src/main/res/raw/camera_click.ogg deleted file mode 100644 index 52512ac0a0..0000000000 Binary files a/libraries/map-usbcamera/src/main/res/raw/camera_click.ogg and /dev/null differ diff --git a/libraries/map-usbcamera/src/main/res/values/dimens.xml b/libraries/map-usbcamera/src/main/res/values/dimens.xml deleted file mode 100644 index 997fea8543..0000000000 --- a/libraries/map-usbcamera/src/main/res/values/dimens.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - 16dp - 16dp - 48dp - 18sp - 32dp - diff --git a/libraries/map-usbcamera/src/main/res/values/strings.xml b/libraries/map-usbcamera/src/main/res/values/strings.xml deleted file mode 100644 index c7a70e8a0b..0000000000 --- a/libraries/map-usbcamera/src/main/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - libusbcamera - 请选择USB摄像头 - 刷新 - Camera - 未搜索到可用USB Camera设备 - diff --git a/libraries/map-usbcamera/src/main/res/values/strings_permissions.xml b/libraries/map-usbcamera/src/main/res/values/strings_permissions.xml deleted file mode 100644 index 9d7e54bfd7..0000000000 --- a/libraries/map-usbcamera/src/main/res/values/strings_permissions.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - Regarding permission - - No audio recording permission. \nAll audio function is disabled - Audio recording permission is necessary for movie capture with audio. - Audio recording permission is necessary for movie capture with audio. - Audio recording permission is necessary for streaming with audio. - Audio recording permission is necessary for streaming with audio. - - No permission of writing external storage. \nMovie/still image capturing are disabled. - Permission of writing external storage is necessary for movie/still image capturing. - Permission of writing external storage is necessary for movie/still image capturing. - No writing external storage permission. \nApp will finish soon - - No network access permission. - Network access permission is necessary for streaming. - Network access permission is necessary for streaming. - No network access permission. \nApp will finish soon - - No location access permission - Location access permission is necessary for %s - Location access permission is necessary for %s - No location access permission. \nApp will finish soon - - No camera access permission - No camera access permission. \nApp will finish soon - Camera access permission is necessary for fallback to built in camera. - Camera access permission is necessary for fallback to built in camera. - - Permission to access phone state/hardware id necessary for calling. - \ No newline at end of file diff --git a/libraries/map-usbcamera/src/main/res/xml/device_filter.xml b/libraries/map-usbcamera/src/main/res/xml/device_filter.xml deleted file mode 100644 index 3c195781a0..0000000000 --- a/libraries/map-usbcamera/src/main/res/xml/device_filter.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/modules.txt b/modules.txt index a44a7cf029..fc6988bb53 100644 --- a/modules.txt +++ b/modules.txt @@ -9,7 +9,6 @@ :libraries:mogo-map-api :foudations:mogo-aicloud-services-sdk :foudations:mogo-commons -:libraries:map-usbcamera :libraries:map-custom :libraries:mogo-map :libraries:mogo-adas-data diff --git a/settings.gradle b/settings.gradle index 9e4ae32d03..7c60496a0a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -40,7 +40,6 @@ include ':foudations:mogo-aicloud-services-sdk' include ':foudations:mogo-commons' // 基础库 -include ':libraries:map-usbcamera' include ':libraries:mogo-map-api' include ':libraries:mogo-map' include ':libraries:mogo-adas'