建立 MAG160C 逆向工程交接仓库
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
V1.0.1
|
||||
1. Separate face-tracking algorithm from SDK. ISVs can easily integrity their own algorithm in smart mode.
|
||||
2. Provide uniform API interface between android and windows.
|
||||
|
||||
V1.0.0
|
||||
1. First release.
|
||||
@@ -0,0 +1,6 @@
|
||||
V1.0.1
|
||||
1. Separate face-tracking algorithm from SDK. ISVs can easily integrity their own algorithm in smart mode.
|
||||
2. Provide uniform API interface between android and windows.
|
||||
|
||||
V1.0.0
|
||||
1. First release.
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id="EloThermal" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||
<option name="BUILDABLE" value="false" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,40 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.0'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'http://raw.github.com/saki4510t/libcommon/master/repository/' }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
ext {
|
||||
supportLibVersion = '27.1.1' // variable that can be referenced to keep support libs consistent
|
||||
commonLibVersion= '2.12.4'
|
||||
versionBuildTool = '27.0.3'
|
||||
versionCompiler = 27
|
||||
versionTarget = 27
|
||||
versionNameString = '1.0.0'
|
||||
javaSourceCompatibility = JavaVersion.VERSION_1_8
|
||||
javaTargetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,51 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility javaSourceCompatibility
|
||||
targetCompatibility javaTargetCompatibility
|
||||
}
|
||||
defaultConfig {
|
||||
applicationId "com.elotouch.elothermal"
|
||||
minSdkVersion 22
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
}
|
||||
sourceSets { main { assets.srcDirs = ['assets', 'assets/'] } }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation(name: 'thermallib-release', ext: 'aar')
|
||||
implementation(name: 'opencv-release', ext: 'aar')
|
||||
implementation project(path: ':libuvccamera')
|
||||
|
||||
|
||||
implementation 'com.serenegiant:common:2.12.4'
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":demo" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="EloThermal" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":demo" />
|
||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.6.0" />
|
||||
<option name="LAST_KNOWN_AGP_VERSION" value="3.6.0" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="release" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleRelease" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileReleaseSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateReleaseSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/src/release/res;file://$MODULE_DIR$/build/generated/res/rs/release" />
|
||||
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/androidTest/res;file://$MODULE_DIR$/src/test/res;file://$MODULE_DIR$/src/testRelease/res" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/javac/release/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/releaseUnitTest/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/release" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/release/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/release/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/release/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/release" type="java-resource" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/releaseUnitTest/out" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:collections:28.0.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:28.0.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.3@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: :thermallib-release:@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: :opencv-release:@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.serenegiant:common:2.12.4@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:preference-v7:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout:1.1.3@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-v4:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-fragment:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:loader:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:viewpager:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:coordinatorlayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:drawerlayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:slidingpanelayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:customview:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:swiperefreshlayout:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:asynclayoutinflater:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:versionedparcelable:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:cursoradapter:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:documentfile:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:localbroadcastmanager:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:print:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:interpolator:28.0.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.1@aar" level="project" />
|
||||
<orderEntry type="module" module-name="libuvccamera" />
|
||||
</component>
|
||||
</module>
|
||||
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
# 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
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("com.elotouch.elothermal", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.elotouch.elothermal">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity android:name=".TestActivity"
|
||||
android:label="Test"
|
||||
android:screenOrientation="portrait"
|
||||
>
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:name=".SmartModeActivity"
|
||||
android:label="Smart"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:name=".ExpertModeActivity"
|
||||
android:windowSoftInputMode="stateAlwaysHidden"
|
||||
android:label="Expert"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PaintFlagsDrawFilter;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.elotouch.thermallib.TemperatureResult;
|
||||
import com.elotouch.thermallib.ThermalConst;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class EloImageCoverView extends ImageView {
|
||||
public EloImageCoverView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public EloImageCoverView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public EloImageCoverView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
final int lineWidth = 12;
|
||||
|
||||
private Paint mPaint;
|
||||
private PaintFlagsDrawFilter mPfd;
|
||||
private List<RectF> mFaceLists = null;
|
||||
private List<TemperatureResult> mResults = null;
|
||||
private TemperatureResult mResult = null;
|
||||
|
||||
float mRatioX = 1;
|
||||
float mRatioY = 1;
|
||||
float mImageWidth = 1;
|
||||
float mImageHeight = 1;
|
||||
|
||||
private Bitmap coverBmp = null;
|
||||
|
||||
public void setImageSize(int width, int height) {
|
||||
mImageWidth = width;
|
||||
mImageHeight = height;
|
||||
}
|
||||
private void init() {
|
||||
mPaint = new Paint();
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setStrokeWidth(6);
|
||||
mPaint.setTextSize(50);
|
||||
mPaint.setColor(Color.GREEN);
|
||||
mPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
mPfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
mRatioX = 1.0f * getWidth() / mImageWidth;
|
||||
mRatioY = 1.0f * getHeight() / mImageHeight;
|
||||
|
||||
canvas.setDrawFilter(mPfd);
|
||||
|
||||
//Draw Image
|
||||
if (coverBmp != null) {
|
||||
Rect rect = new Rect(0, 0, getWidth(), getHeight());
|
||||
canvas.drawBitmap(coverBmp, null, rect, null);
|
||||
}
|
||||
|
||||
if (mFaceLists != null) {
|
||||
//Smart Mode
|
||||
int count = mFaceLists.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
try {
|
||||
_drawWithResult(canvas, mResults.get(i));
|
||||
_drawWithRect(canvas, mFaceLists.get(i));
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Expert Mode
|
||||
_drawWithResult(canvas, mResult);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawWithFace(Bitmap bmp, List<RectF> faces, List<TemperatureResult> results) {
|
||||
coverBmp = bmp;
|
||||
mFaceLists = faces;
|
||||
mResults = results;
|
||||
this.postInvalidate();
|
||||
}
|
||||
|
||||
public void drawWithSingleResult(TemperatureResult result) {
|
||||
mResult = result;
|
||||
this.postInvalidate();
|
||||
}
|
||||
|
||||
|
||||
private void _drawWithResult(Canvas canvas, TemperatureResult result) {
|
||||
if (result != null) {
|
||||
|
||||
int color = getResources().getColor(R.color.colorGreen);
|
||||
switch (result.getJudgement()) {
|
||||
case ThermalConst.Thermal_Judgement_Normal:
|
||||
color = getResources().getColor(R.color.colorGreen);
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Fever:
|
||||
color = getResources().getColor(R.color.colorRed);
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Beyond_Boundary:
|
||||
color = getResources().getColor(R.color.colorRed);
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Illegal_Temp:
|
||||
color = Color.TRANSPARENT;
|
||||
break;
|
||||
default:
|
||||
color = Color.TRANSPARENT;
|
||||
break;
|
||||
}
|
||||
|
||||
//Calc +
|
||||
PointF point = result.getPoint();
|
||||
float X = point.x * mImageWidth * mRatioX;
|
||||
float Y = point.y * mImageHeight * mRatioY;
|
||||
|
||||
//Calc String
|
||||
int unitMode = result.getUnitMode();
|
||||
String strUnit = (unitMode == ThermalConst.Thermal_Unit_Metric) ? "°C" : "°F";
|
||||
String s = String.format(Locale.ENGLISH, "%.1f %.1f", result.getArmTemperature(), result.getRawTemperature()) + strUnit;
|
||||
Rect strRect = new Rect();
|
||||
mPaint.getTextBounds(s, 0, s.length(), strRect);
|
||||
|
||||
//Draw Back
|
||||
int border = 4;
|
||||
strRect.offsetTo((int)X+lineWidth, (int)(Y-strRect.height()*.5));
|
||||
Rect backRect = new Rect(strRect.left-lineWidth*2-border,
|
||||
strRect.top-border,
|
||||
strRect.right+border,
|
||||
strRect.bottom+border);
|
||||
mPaint.setColor(Color.BLACK);
|
||||
canvas.drawRect(backRect, mPaint);
|
||||
|
||||
//Draw +
|
||||
mPaint.setColor(color);
|
||||
canvas.drawLine(X - lineWidth, Y, X + lineWidth, Y, mPaint);
|
||||
canvas.drawLine(X, Y - lineWidth, X, Y + lineWidth, mPaint);
|
||||
|
||||
|
||||
//Draw String
|
||||
canvas.drawText(s, X+lineWidth, Y+strRect.height()*.5f, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void _drawWithRect(Canvas canvas, RectF rectF) {
|
||||
//Draw Rect
|
||||
PointF lt = new PointF(rectF.left * mImageWidth * mRatioX, rectF.top * mImageHeight * mRatioY);
|
||||
PointF rt = new PointF(rectF.right * mImageWidth * mRatioX, rectF.top * mImageHeight * mRatioY);
|
||||
PointF lb = new PointF(rectF.left * mImageWidth * mRatioX, rectF.bottom * mImageHeight * mRatioY);
|
||||
PointF rb = new PointF(rectF.right * mImageWidth * mRatioX, rectF.bottom * mImageHeight * mRatioY);
|
||||
|
||||
canvas.drawLine(lt.x, lt.y, rt.x, rt.y, mPaint);
|
||||
canvas.drawLine(lb.x, lb.y, rb.x, rb.y, mPaint);
|
||||
canvas.drawLine(lt.x, lt.y, lb.x, lb.y, mPaint);
|
||||
canvas.drawLine(rt.x, rt.y, rb.x, rb.y, mPaint);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.elotouch.thermallib.INewDistance;
|
||||
import com.elotouch.thermallib.INewIRFrame;
|
||||
import com.elotouch.thermallib.TemperatureResult;
|
||||
import com.elotouch.thermallib.ThermalConst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ExpertModeActivity extends ThermalBaseActivity {
|
||||
|
||||
private static final String TAG = "ExpertModeActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
thermalController.setNewIRFrameDelegate(iNewIRFrame);
|
||||
thermalController.setNewDistanceDelegate(iNewDistance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentViewID() {
|
||||
return R.layout.activity_expert;
|
||||
}
|
||||
|
||||
volatile long lastIRTime = -1;
|
||||
volatile float lastDistance = -1;
|
||||
volatile float lastValidDistance = -1;
|
||||
volatile long lastValidDistanceTime = -1;
|
||||
|
||||
INewIRFrame iNewIRFrame = new INewIRFrame() {
|
||||
@Override
|
||||
public void onIRFrame(Bitmap bmp) {
|
||||
irSurfaceView.drawWithBitmap(bmp);
|
||||
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (curTime - lastIRTime >= 1000) {
|
||||
if (curTime - lastValidDistanceTime <= 500) {
|
||||
TemperatureResult result = thermalController.readTemperatureAtPoint(80, 40);
|
||||
irCoverView.drawWithSingleResult(result);
|
||||
|
||||
switch (result.getJudgement()) {
|
||||
case ThermalConst.Thermal_Judgement_Normal:
|
||||
onNormal();
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Fever:
|
||||
onAbnormal();
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Beyond_Boundary:
|
||||
onNobody();
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Illegal_Temp:
|
||||
onNobody();
|
||||
break;
|
||||
default:
|
||||
onNobody();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
irCoverView.drawWithSingleResult(null);
|
||||
onNobody();
|
||||
}
|
||||
lastIRTime = curTime;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
INewDistance iNewDistance = new INewDistance() {
|
||||
@Override
|
||||
public void onDistance(float distance) {
|
||||
if (distance > 0) {
|
||||
lastValidDistanceTime = System.currentTimeMillis();
|
||||
lastValidDistance = distance;
|
||||
}
|
||||
lastDistance = distance;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.ScaleAnimation;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.elotouch.CVFaceDetector;
|
||||
import com.elotouch.thermallib.INewDistance;
|
||||
import com.elotouch.thermallib.INewIRFrame;
|
||||
import com.elotouch.thermallib.TemperatureResult;
|
||||
import com.elotouch.thermallib.ThermalConst;
|
||||
import com.elotouch.uvc.EloUVCCameraConverter;
|
||||
import com.elotouch.uvc.INewUVCFrame;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SmartModeActivity extends ThermalBaseActivity {
|
||||
|
||||
private static final String TAG = "SmartModeActivity";
|
||||
|
||||
ImageView imageRed = null;
|
||||
ImageView imageGreen = null;
|
||||
TextView txName = null;
|
||||
CVFaceDetector faceDetector;
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String xmlPath = loadCascade(R.raw.uvc_mask_haar);
|
||||
faceDetector = new CVFaceDetector(this, xmlPath);
|
||||
|
||||
thermalController.setNewIRFrameDelegate(iNewIRFrame);
|
||||
thermalController.setNewDistanceDelegate(iNewDistance);
|
||||
|
||||
uvcCameraWrapper.setNewUVCFrame(iNewUVCFrame);
|
||||
|
||||
imageRed = findViewById(R.id.imgRed);
|
||||
imageGreen = findViewById(R.id.imgGreen);
|
||||
txName = findViewById(R.id.txName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentViewID() {
|
||||
return R.layout.activity_smart;
|
||||
}
|
||||
|
||||
|
||||
//Distance
|
||||
volatile float lastDistance = -1;
|
||||
volatile float lastValidDistance = -1;
|
||||
volatile long lastValidDistanceTime = -1;
|
||||
|
||||
volatile List<RectF> lastValidFaces = null;
|
||||
volatile long lastValidUVCTime = -1;
|
||||
volatile long nextRotateTime = -1;
|
||||
|
||||
volatile long lastIRTime = -1;
|
||||
|
||||
volatile Bitmap lastUVCBmp = null;
|
||||
INewUVCFrame iNewUVCFrame = new INewUVCFrame() {
|
||||
@Override
|
||||
public void onUVCFrame(Bitmap uvcBmp) {
|
||||
long curTime = System.currentTimeMillis();
|
||||
|
||||
Bitmap trackBmp = EloUVCCameraConverter.UVCBitmapWithIRWidth(uvcBmp);
|
||||
ArrayList<Rect> faces = faceDetector.processFaces(trackBmp, 0.1f, 1.0f);
|
||||
List<RectF> rectfs = EloUVCCameraConverter.openCVRect2Local(faces);
|
||||
|
||||
uvcBmp.recycle();
|
||||
trackBmp.recycle();
|
||||
|
||||
if ((rectfs != null) && (rectfs.size() > 0)) {
|
||||
lastValidFaces = rectfs;
|
||||
lastValidUVCTime = curTime;
|
||||
|
||||
if (curTime > nextRotateTime)
|
||||
{
|
||||
double sumCenterY = 0;
|
||||
for (int i = 0; i < rectfs.size(); ++i)
|
||||
{
|
||||
sumCenterY += lastValidFaces.get(i).centerY();
|
||||
}
|
||||
double centerY = sumCenterY / rectfs.size();
|
||||
int step = (int)((centerY - 0.5) * -0.10 * EloUVCCameraConverter.IR_HEIGHT);
|
||||
|
||||
if (step != 0)
|
||||
{
|
||||
if (centerY > 0.6)
|
||||
{
|
||||
thermalController.rotate(step);
|
||||
}
|
||||
else if (centerY < 0.4)
|
||||
{
|
||||
thermalController.rotate(step);
|
||||
}
|
||||
nextRotateTime = curTime + Math.abs(step) * 10 + 80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curTime - lastValidUVCTime >= 1000) {
|
||||
lastValidFaces = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
INewIRFrame iNewIRFrame = new INewIRFrame() {
|
||||
@Override
|
||||
public void onIRFrame(Bitmap bmp) {
|
||||
irSurfaceView.drawWithBitmap(bmp);
|
||||
|
||||
long curTime = System.currentTimeMillis();
|
||||
|
||||
//Update every 500ms
|
||||
if (curTime - lastIRTime >= 500) {
|
||||
if ((lastValidFaces != null) && (lastValidFaces.size() > 0)) {
|
||||
int countAbnormal = 0;
|
||||
int countNormal = 0;
|
||||
|
||||
List<TemperatureResult> results = new ArrayList<>();
|
||||
for (int i = 0; i < lastValidFaces.size(); ++i)
|
||||
{
|
||||
RectF faceF = lastValidFaces.get(i);
|
||||
Rect face = new Rect(
|
||||
(int)(faceF.left * EloUVCCameraConverter.IR_WIDTH),
|
||||
(int)(faceF.top * EloUVCCameraConverter.IR_HEIGHT),
|
||||
(int)(faceF.right * EloUVCCameraConverter.IR_WIDTH),
|
||||
(int)(faceF.bottom * EloUVCCameraConverter.IR_HEIGHT));
|
||||
TemperatureResult temperatureResult = thermalController.readTemperatureInRect(face);
|
||||
if (temperatureResult.getJudgement() == ThermalConst.Thermal_Judgement_Fever)
|
||||
{
|
||||
countAbnormal++;
|
||||
}
|
||||
else if (temperatureResult.getJudgement() == ThermalConst.Thermal_Judgement_Normal)
|
||||
{
|
||||
countNormal++;
|
||||
}
|
||||
results.add(temperatureResult);
|
||||
}
|
||||
|
||||
uvcCoverView.drawWithFace(lastUVCBmp, lastValidFaces, results);
|
||||
irCoverView.drawWithFace(null, lastValidFaces, results);
|
||||
|
||||
if (countAbnormal > 0) {
|
||||
onAbnormal();
|
||||
}
|
||||
else if (countNormal > 0) {
|
||||
onNormal();
|
||||
}
|
||||
else {
|
||||
onNobody();
|
||||
}
|
||||
}
|
||||
else {
|
||||
uvcCoverView.drawWithFace(lastUVCBmp, null, null);
|
||||
irCoverView.drawWithFace(null, null, null);
|
||||
onNobody();
|
||||
}
|
||||
lastIRTime = curTime;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
INewDistance iNewDistance = new INewDistance() {
|
||||
@Override
|
||||
public void onDistance(float distance) {
|
||||
if (distance > 0) {
|
||||
lastValidDistanceTime = System.currentTimeMillis();
|
||||
lastValidDistance = distance;
|
||||
}
|
||||
lastDistance = distance;
|
||||
}
|
||||
};
|
||||
|
||||
private String loadCascade(int resId) {
|
||||
try {
|
||||
InputStream is = this.getResources().openRawResource(resId);
|
||||
File cascadeDir = this.getDir("cascade", Context.MODE_PRIVATE);
|
||||
String CASCADE_PATH = "cascade.xml";
|
||||
File cascadeFile = new File(cascadeDir, CASCADE_PATH);
|
||||
FileOutputStream os = new FileOutputStream(cascadeFile);
|
||||
|
||||
byte[] buffer = new byte[40960];
|
||||
int bytesRead;
|
||||
while ((bytesRead = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
is.close();
|
||||
os.close();
|
||||
|
||||
return cascadeFile.getAbsolutePath();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.elotouch.helper.EloHelper;
|
||||
import com.elotouch.thermallib.INewDistance;
|
||||
import com.elotouch.thermallib.INewIRFrame;
|
||||
import com.elotouch.thermallib.IUpdateCallback;
|
||||
import com.elotouch.thermallib.TemperatureResult;
|
||||
import com.elotouch.thermallib.ThermalConst;
|
||||
import com.elotouch.uvc.EloUVCCameraConverter;
|
||||
import com.elotouch.uvc.INewUVCFrame;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class TestActivity extends ThermalBaseActivity {
|
||||
|
||||
private static final String TAG = "TestActivity";
|
||||
|
||||
private TextView txDistance;
|
||||
private TextView txInnerTemp;
|
||||
private TextView txOffset;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
txDistance = findViewById(R.id.txDistance);
|
||||
txOffset = findViewById(R.id.txOffset);
|
||||
txInnerTemp = findViewById(R.id.txInnerTemp);
|
||||
|
||||
thermalController.setNewDistanceDelegate(iNewDistance);
|
||||
thermalController.setNewIRFrameDelegate(iNewIRFrame);
|
||||
// thermalController.setEmissivity(1);
|
||||
|
||||
findViewById(R.id.btnUp).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
thermalController.rotate(10);
|
||||
}
|
||||
});
|
||||
findViewById(R.id.btnDown).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
thermalController.rotate(-10);
|
||||
}
|
||||
});
|
||||
findViewById(R.id.btnTrigger).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
thermalController.trigger();
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.btnUpdate).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
try {
|
||||
byte[] firm = EloHelper.readFromAssets(TestActivity.this, "motor.bin");
|
||||
thermalController.setFirmwareData(firm);
|
||||
thermalController.setUpdateCallback(iUpdateCallback);
|
||||
thermalController.startUpdate();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.btnXPlus).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
EloUVCCameraConverter.adjustX(1);
|
||||
updateOffset();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.btnXMinus).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
EloUVCCameraConverter.adjustX(-1);
|
||||
updateOffset();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.btnYPlus).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
EloUVCCameraConverter.adjustY(1);
|
||||
updateOffset();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.btnYMinus).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
EloUVCCameraConverter.adjustY(-1);
|
||||
updateOffset();
|
||||
}
|
||||
});
|
||||
|
||||
if (true) {
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String ver = thermalController.getTCMVersion();
|
||||
if (ver != null) {
|
||||
((TextView) findViewById(R.id.txTCMVersion)).setText(ver);
|
||||
}
|
||||
Log.d(TAG, "VER:" + ver);
|
||||
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentViewID() {
|
||||
return R.layout.activity_test;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNormal() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAbnormal() {
|
||||
}
|
||||
protected void onNobody() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
IUpdateCallback iUpdateCallback = new IUpdateCallback() {
|
||||
@Override
|
||||
public void onUpdate(boolean isSuc, int prog) {
|
||||
Log.d(TAG, "update:" + prog);
|
||||
|
||||
TestActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
((TextView) findViewById(R.id.txTCMVersion)).setText("Update:" + prog);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
INewIRFrame iNewIRFrame = new INewIRFrame() {
|
||||
@Override
|
||||
public void onIRFrame(Bitmap bmp) {
|
||||
irSurfaceView.drawWithBitmap(bmp);
|
||||
|
||||
TemperatureResult result = thermalController.readTemperatureAtPoint(80, 40);
|
||||
irCoverView.drawWithSingleResult(result);
|
||||
uvcCoverView.drawWithSingleResult(result);
|
||||
|
||||
double innerTemp = thermalController.getInnerIRCameraTemp();
|
||||
String serial = thermalController.getIRSerial();
|
||||
String strUnit = isUnitUS ? "°F" : "°C";
|
||||
String s = "IR:" + serial + " Inner:" + String.format(Locale.ENGLISH, "%.1f", innerTemp+0.05) + strUnit;
|
||||
|
||||
TestActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
txInnerTemp.setText(s);
|
||||
}
|
||||
});
|
||||
switch (result.getJudgement()) {
|
||||
case ThermalConst.Thermal_Judgement_Normal:
|
||||
onNormal();
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Fever:
|
||||
onAbnormal();
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Beyond_Boundary:
|
||||
onNobody();
|
||||
break;
|
||||
case ThermalConst.Thermal_Judgement_Illegal_Temp:
|
||||
onNobody();
|
||||
break;
|
||||
default:
|
||||
onNobody();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
INewDistance iNewDistance = new INewDistance() {
|
||||
@Override
|
||||
public void onDistance(final float distance) {
|
||||
try {
|
||||
TestActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isUnitUS) {
|
||||
txDistance.setText("" + (int)distance + "inch");
|
||||
}
|
||||
else {
|
||||
txDistance.setText("" + (int)distance + "mm");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void updateOffset() {
|
||||
int x = EloUVCCameraConverter.getOffsetX();
|
||||
int y = EloUVCCameraConverter.getOffsetY();
|
||||
|
||||
EloUVCCameraConverter.setDefaultX(this, x);
|
||||
EloUVCCameraConverter.setDefaultY(this, y);
|
||||
txOffset.setText("" + x + "-" + y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.RectF;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.media.SoundPool;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.elotouch.thermallib.INewDistance;
|
||||
import com.elotouch.thermallib.INewIRFrame;
|
||||
import com.elotouch.thermallib.TemperatureResult;
|
||||
import com.elotouch.thermallib.ThermalConst;
|
||||
import com.elotouch.thermallib.ThermalController;
|
||||
import com.elotouch.thermallib.ThermalSurfaceView;
|
||||
import com.elotouch.uvc.EloUVCCameraConverter;
|
||||
import com.elotouch.uvc.EloUVCCameraView;
|
||||
import com.elotouch.uvc.UVCCameraWrapper;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
public class ThermalBaseActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "ThermalBaseActivity";
|
||||
|
||||
protected ThermalController thermalController = null;
|
||||
protected ThermalSurfaceView irSurfaceView = null;
|
||||
protected EloImageCoverView irCoverView = null;
|
||||
|
||||
protected UVCCameraWrapper uvcCameraWrapper = null;
|
||||
protected EloUVCCameraView uvcTextureView = null;
|
||||
protected EloImageCoverView uvcCoverView = null;
|
||||
|
||||
protected ImageView imageNormal = null;
|
||||
protected ImageView imageAbnormal = null;
|
||||
|
||||
protected Handler handler = new Handler();
|
||||
protected boolean isUnitUS = false;
|
||||
|
||||
protected int getContentViewID() {
|
||||
return -1;
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(getContentViewID());
|
||||
|
||||
int x = EloUVCCameraConverter.getDefaultX(this);
|
||||
int y = EloUVCCameraConverter.getDefaultY(this);
|
||||
Log.d("EloUVCCameraConverter", "x,y"+ x + "-" + y);
|
||||
EloUVCCameraConverter.setOffset(x, y);
|
||||
|
||||
irSurfaceView = findViewById(R.id.IRSurfaceView);
|
||||
irCoverView = findViewById(R.id.IRCover);
|
||||
irCoverView.setImageSize(EloUVCCameraConverter.IR_WIDTH, EloUVCCameraConverter.IR_HEIGHT);
|
||||
thermalController = new ThermalController(this);
|
||||
|
||||
if (isUnitUS) {
|
||||
thermalController.setUnitMode(ThermalConst.Thermal_Unit_US);
|
||||
thermalController.setTempBoundary(30 * 1.8 + 32, 44 * 1.8 + 32, 37 * 1.8 + 32);
|
||||
}
|
||||
else {
|
||||
thermalController.setUnitMode(ThermalConst.Thermal_Unit_Metric);
|
||||
thermalController.setTempBoundary(30, 44, 37);
|
||||
}
|
||||
|
||||
uvcTextureView = findViewById(R.id.RGBView);
|
||||
uvcCoverView = findViewById(R.id.RGBCover);
|
||||
uvcCoverView.setImageSize(EloUVCCameraConverter.IR_SCALED_WIDTH, EloUVCCameraConverter.IR_SCALED_HEIGHT);
|
||||
uvcCameraWrapper = new UVCCameraWrapper(this, uvcTextureView);
|
||||
|
||||
imageNormal = findViewById(R.id.imgNormal);
|
||||
imageAbnormal = findViewById(R.id.imgAbnormal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
thermalController.onStart();
|
||||
uvcCameraWrapper.onStart();
|
||||
}
|
||||
@Override
|
||||
protected void onStop() {
|
||||
thermalController.onStop();
|
||||
uvcCameraWrapper.onStop();
|
||||
super.onStop();
|
||||
}
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
uvcCameraWrapper.onDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
protected void onNormal() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imageNormal.setVisibility(View.VISIBLE);
|
||||
imageAbnormal.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
protected void onAbnormal() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imageNormal.setVisibility(View.INVISIBLE);
|
||||
imageAbnormal.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
protected void onNobody() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imageNormal.setVisibility(View.INVISIBLE);
|
||||
imageAbnormal.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.elotouch.thermallib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PaintFlagsDrawFilter;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
import com.elotouch.thermallib.TemperatureResult;
|
||||
import com.elotouch.thermallib.ThermalConst;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ThermalSurfaceView extends SurfaceView
|
||||
implements SurfaceHolder.Callback {
|
||||
private static final String TAG = "ThermalSurfaceView";
|
||||
private Paint mPaint;
|
||||
private PaintFlagsDrawFilter mPfd;
|
||||
|
||||
public ThermalSurfaceView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
getHolder().addCallback(this);
|
||||
}
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
mPaint = new Paint();
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setStrokeWidth(6);
|
||||
mPaint.setTextSize(50);
|
||||
mPaint.setColor(Color.GREEN);
|
||||
mPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
mPfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mPaint = null;
|
||||
mPfd = null;
|
||||
}
|
||||
|
||||
public void drawWithBitmap(Bitmap bmp) {
|
||||
|
||||
if (bmp == null) {
|
||||
return;
|
||||
}
|
||||
Canvas canvas = getHolder().lockCanvas();
|
||||
if (canvas != null) {
|
||||
canvas.setDrawFilter(mPfd);
|
||||
|
||||
Rect rect = new Rect(0, 0, getWidth(), getHeight());
|
||||
|
||||
//Draw Image
|
||||
canvas.drawBitmap(bmp, null, rect, null);
|
||||
|
||||
getHolder().unlockCanvasAndPost(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package com.elotouch.uvc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EloUVCCameraConverter {
|
||||
public static final int UVC_WIDTH = 640;
|
||||
public static final int UVC_HEIGHT = 480;
|
||||
|
||||
public static final int IR_WIDTH = 160;
|
||||
public static final int IR_HEIGHT = 120;
|
||||
|
||||
public static final int IR_SCALED_WIDTH = 408;
|
||||
public static final int IR_SCALED_HEIGHT = 306;
|
||||
|
||||
public static final float IR_SCALE = (float)IR_SCALED_HEIGHT/UVC_HEIGHT;
|
||||
public static final boolean IR_FLIPX = false;
|
||||
|
||||
//(0,0) is at Left/Bottom
|
||||
private static int CAMERAS_OFFSET_X = 81; //
|
||||
private static int CAMERAS_OFFSET_Y = 65; //
|
||||
|
||||
public static Bitmap UVCBitmapWithIRSize(Bitmap uvcBitmap) {
|
||||
if (IR_FLIPX) {
|
||||
Matrix m = new Matrix();
|
||||
m.postScale(-1, 1);
|
||||
return Bitmap.createBitmap(uvcBitmap, UVC_WIDTH-CAMERAS_OFFSET_X-IR_SCALED_WIDTH, UVC_HEIGHT-CAMERAS_OFFSET_Y-IR_SCALED_HEIGHT, IR_SCALED_WIDTH, IR_SCALED_HEIGHT, m, true);
|
||||
}
|
||||
else {
|
||||
return Bitmap.createBitmap(uvcBitmap, CAMERAS_OFFSET_X, UVC_HEIGHT-CAMERAS_OFFSET_Y-IR_SCALED_HEIGHT, IR_SCALED_WIDTH, IR_SCALED_HEIGHT);
|
||||
}
|
||||
}
|
||||
public static Bitmap UVCBitmapWithIRWidth(Bitmap uvcBitmap) {
|
||||
if (IR_FLIPX) {
|
||||
Matrix m = new Matrix();
|
||||
m.postScale(-1, 1);
|
||||
return Bitmap.createBitmap(uvcBitmap, UVC_WIDTH-CAMERAS_OFFSET_X-IR_SCALED_WIDTH, 0, IR_SCALED_WIDTH, IR_SCALED_HEIGHT, m, true);
|
||||
}
|
||||
else {
|
||||
return Bitmap.createBitmap(uvcBitmap, CAMERAS_OFFSET_X, 0, IR_SCALED_WIDTH, UVC_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<RectF> openCVRect2Local(List<Rect> rects)
|
||||
{
|
||||
List<RectF> ret = new ArrayList<RectF>();
|
||||
|
||||
if ((rects != null) && (rects.size() > 0))
|
||||
{
|
||||
for (int i = 0; i < rects.size(); ++i)
|
||||
{
|
||||
Rect rect = rects.get(i);
|
||||
RectF rectF = new RectF();
|
||||
rectF.left = (float)rect.left / IR_SCALED_WIDTH;
|
||||
rectF.right = (float)rect.right / IR_SCALED_WIDTH;
|
||||
rectF.top = (float)(rect.top - (UVC_HEIGHT - IR_SCALED_HEIGHT - CAMERAS_OFFSET_Y)) / IR_SCALED_HEIGHT;
|
||||
rectF.bottom = (float)(rect.bottom - (UVC_HEIGHT - IR_SCALED_HEIGHT - CAMERAS_OFFSET_Y)) / IR_SCALED_HEIGHT;
|
||||
|
||||
ret.add(rectF);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
public static int getDefaultX(Context context) {
|
||||
SharedPreferences pref = context.getSharedPreferences("SETTINGS", Context.MODE_PRIVATE);
|
||||
int value = pref.getInt("defaultX", 60);
|
||||
return value;
|
||||
}
|
||||
public static int getDefaultY(Context context) {
|
||||
SharedPreferences pref = context.getSharedPreferences("SETTINGS", Context.MODE_PRIVATE);
|
||||
int value = pref.getInt("defaultY", 80);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void setDefaultX(Context context, int value) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
SharedPreferences.Editor editor = context.getSharedPreferences("SETTINGS", Context.MODE_PRIVATE).edit();
|
||||
editor.putInt("defaultX", value);
|
||||
editor.apply();
|
||||
}
|
||||
public static void setDefaultY(Context context, int value) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
SharedPreferences.Editor editor = context.getSharedPreferences("SETTINGS", Context.MODE_PRIVATE).edit();
|
||||
editor.putInt("defaultY", value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
|
||||
public static void setOffset(int x, int y) {
|
||||
CAMERAS_OFFSET_X = x;
|
||||
CAMERAS_OFFSET_Y = y;
|
||||
}
|
||||
public static int getOffsetX() {
|
||||
return CAMERAS_OFFSET_X;
|
||||
}
|
||||
public static int getOffsetY() {
|
||||
return CAMERAS_OFFSET_Y;
|
||||
}
|
||||
public static int adjustX(int adj) {
|
||||
CAMERAS_OFFSET_X += adj;
|
||||
return CAMERAS_OFFSET_X;
|
||||
}
|
||||
public static int adjustY(int adj) {
|
||||
CAMERAS_OFFSET_Y += adj;
|
||||
return CAMERAS_OFFSET_Y;
|
||||
}
|
||||
}
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
package com.elotouch.uvc;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import com.serenegiant.usb.IFrameCallback;
|
||||
import com.serenegiant.usb.USBMonitor;
|
||||
import com.serenegiant.usb.UVCCamera;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class EloUVCCameraHandler extends Handler {
|
||||
private static final boolean DEBUG = true; // TODO set false on release
|
||||
private static final String TAG = "EloUVCCameraHandler";
|
||||
|
||||
|
||||
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_RELEASE = 9;
|
||||
|
||||
private final WeakReference<CameraThread> mWeakThread;
|
||||
private volatile boolean mReleased;
|
||||
|
||||
public static final EloUVCCameraHandler createHandler(final int encoderType, final int width, final int height, final int format, final float bandwidthFactor) {
|
||||
|
||||
final CameraThread thread = new CameraThread(encoderType, width, height, format, bandwidthFactor);
|
||||
thread.start();
|
||||
return (EloUVCCameraHandler)thread.getHandler();
|
||||
}
|
||||
|
||||
private EloUVCCameraHandler(final CameraThread thread) {
|
||||
mWeakThread = new WeakReference<CameraThread>(thread);
|
||||
}
|
||||
|
||||
|
||||
public int getWidth() {
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
return thread != null ? thread.getWidth() : 0;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
return thread != null ? thread.getHeight() : 0;
|
||||
}
|
||||
|
||||
public boolean isOpened() {
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
return thread != null && thread.isCameraOpened();
|
||||
}
|
||||
|
||||
public boolean isPreviewing() {
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
return thread != null && thread.isPreviewing();
|
||||
}
|
||||
|
||||
public boolean isEqual(final UsbDevice device) {
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
return (thread != null) && thread.isEqual(device);
|
||||
}
|
||||
|
||||
protected boolean isCameraThread() {
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
return thread != null && (thread.getId() == Thread.currentThread().getId());
|
||||
}
|
||||
|
||||
protected boolean isReleased() {
|
||||
final EloUVCCameraHandler.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");
|
||||
}
|
||||
|
||||
protected 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");
|
||||
}
|
||||
sendMessage(obtainMessage(MSG_PREVIEW_START, surface));
|
||||
}
|
||||
|
||||
public void stopPreview() {
|
||||
if (DEBUG) Log.v(TAG, "stopPreview:");
|
||||
removeMessages(MSG_PREVIEW_START);
|
||||
|
||||
if (isPreviewing()) {
|
||||
final EloUVCCameraHandler.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 release() {
|
||||
mReleased = true;
|
||||
close();
|
||||
sendEmptyMessage(MSG_RELEASE);
|
||||
}
|
||||
|
||||
public void setFrameCallback(final IFrameCallback callback) {
|
||||
checkReleased();
|
||||
final EloUVCCameraHandler.CameraThread thread = mWeakThread.get();
|
||||
final UVCCamera camera = thread != null ? thread.mUVCCamera : null;
|
||||
if (camera != null) {
|
||||
camera.setFrameCallback(callback, UVCCamera.PIXEL_FORMAT_RGBX);
|
||||
}
|
||||
else {
|
||||
Log.d("xx", "xx");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final Message msg) {
|
||||
final EloUVCCameraHandler.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_RELEASE:
|
||||
thread.handleRelease();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("unsupported message:what=" + msg.what);
|
||||
}
|
||||
}
|
||||
static final class CameraThread extends Thread {
|
||||
private static final String TAG_THREAD = "CameraThread";
|
||||
private final Object mSync = new Object();
|
||||
private final int mEncoderType;
|
||||
private int mWidth, mHeight, mPreviewMode;
|
||||
private float mBandwidthFactor;
|
||||
private boolean mIsPreviewing;
|
||||
|
||||
private EloUVCCameraHandler mHandler;
|
||||
/**
|
||||
* for accessing UVC camera
|
||||
*/
|
||||
private UVCCamera mUVCCamera;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param encoderType 0: use MediaSurfaceEncoder, 1: use MediaVideoEncoder, 2: use MediaVideoBufferEncoder
|
||||
* @param width
|
||||
* @param height
|
||||
* @param format either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1)
|
||||
* @param bandwidthFactor
|
||||
*/
|
||||
CameraThread(final int encoderType, final int width, final int height, final int format,
|
||||
final float bandwidthFactor) {
|
||||
|
||||
super("CameraThread");
|
||||
mEncoderType = encoderType;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mPreviewMode = format;
|
||||
mBandwidthFactor = bandwidthFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
Log.i(TAG, "CameraThread#finalize");
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public EloUVCCameraHandler 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 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;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (DEBUG) Log.i(TAG, "supportedSize:" + (mUVCCamera != null ? mUVCCamera.getSupportedSize() : null));
|
||||
}
|
||||
|
||||
public void handleClose() {
|
||||
if (DEBUG) Log.v(TAG_THREAD, "handleClose:");
|
||||
final UVCCamera camera;
|
||||
synchronized (mSync) {
|
||||
camera = mUVCCamera;
|
||||
mUVCCamera = null;
|
||||
}
|
||||
if (camera != null) {
|
||||
camera.stopPreview();
|
||||
camera.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
try {
|
||||
// fallback to YUV mode
|
||||
mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, UVCCamera.DEFAULT_PREVIEW_MODE, mBandwidthFactor);
|
||||
} catch (final IllegalArgumentException 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;
|
||||
}
|
||||
}
|
||||
|
||||
public void handleStopPreview() {
|
||||
if (DEBUG) Log.v(TAG_THREAD, "handleStopPreview:");
|
||||
if (mIsPreviewing) {
|
||||
if (mUVCCamera != null) {
|
||||
mUVCCamera.stopPreview();
|
||||
}
|
||||
synchronized (mSync) {
|
||||
mIsPreviewing = false;
|
||||
mSync.notifyAll();
|
||||
}
|
||||
}
|
||||
if (DEBUG) Log.v(TAG_THREAD, "handleStopPreview:finished");
|
||||
}
|
||||
|
||||
public void handleRelease() {
|
||||
if (DEBUG) Log.v(TAG_THREAD, "handleRelease:" );
|
||||
handleClose();
|
||||
mHandler.mReleased = true;
|
||||
Looper.myLooper().quit();
|
||||
if (DEBUG) Log.v(TAG_THREAD, "handleRelease:finished");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
EloUVCCameraHandler handler = null;
|
||||
try {
|
||||
handler = new EloUVCCameraHandler(this);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (handler != null) {
|
||||
synchronized (mSync) {
|
||||
mHandler = handler;
|
||||
mSync.notifyAll();
|
||||
}
|
||||
Looper.loop();
|
||||
|
||||
if (mHandler != null) {
|
||||
mHandler.mReleased = true;
|
||||
}
|
||||
}
|
||||
synchronized (mSync) {
|
||||
mHandler = null;
|
||||
mSync.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
package com.elotouch.uvc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.Matrix;
|
||||
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;
|
||||
|
||||
public class EloUVCCameraView extends TextureView implements TextureView.SurfaceTextureListener {
|
||||
|
||||
private boolean mHasSurface;
|
||||
private RenderHandler mRenderHandler;
|
||||
private final Object mCaptureSync = new Object();
|
||||
private Bitmap mTempBitmap;
|
||||
private boolean mReqesutCaptureStillImage;
|
||||
|
||||
public EloUVCCameraView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public EloUVCCameraView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public EloUVCCameraView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOpaque(false);//设置背景透明,记住这里是[是否不透明]
|
||||
setSurfaceTextureListener(this);//设置监听
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
if (DEBUG) Log.v(TAG, "onResume:");
|
||||
if (mHasSurface) {
|
||||
mRenderHandler = RenderHandler.createHandler(this, super.getSurfaceTexture(), getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
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.v(TAG, "onSurfaceTextureAvailable:" + surface);
|
||||
if (mRenderHandler == null) {
|
||||
mRenderHandler = RenderHandler.createHandler(this, surface, width, height);
|
||||
} else {
|
||||
mRenderHandler.resize(width, height);
|
||||
}
|
||||
mHasSurface = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) {
|
||||
if (DEBUG) Log.v(TAG, "onSurfaceTextureSizeChanged:" + surface);
|
||||
if (mRenderHandler != null) {
|
||||
mRenderHandler.resize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) {
|
||||
if (DEBUG) Log.v(TAG, "onSurfaceTextureDestroyed:" + surface);
|
||||
if (mRenderHandler != null) {
|
||||
mRenderHandler.release();
|
||||
mRenderHandler = null;
|
||||
}
|
||||
mHasSurface = false;
|
||||
|
||||
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 SurfaceTexture getSurfaceTexture() {
|
||||
return mRenderHandler != null ? mRenderHandler.getPreviewTexture() : null;
|
||||
}
|
||||
|
||||
private Surface mPreviewSurface;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static final boolean DEBUG = true; // TODO set false on release
|
||||
private static final String TAG = "UVCCameraTextureView";
|
||||
|
||||
/**
|
||||
* render camera frames on this view on a private thread
|
||||
*
|
||||
* @author saki
|
||||
*/
|
||||
private static 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 EloUVCCameraView mCameraView;
|
||||
|
||||
public static RenderHandler createHandler(final EloUVCCameraView cameraView, final SurfaceTexture surface, final int width, final int height) {
|
||||
|
||||
final RenderThread thread = new RenderThread(cameraView, surface, width, height);
|
||||
thread.start();
|
||||
return thread.getHandler();
|
||||
}
|
||||
|
||||
private RenderHandler(final RenderThread thread) {
|
||||
mThread = thread;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
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_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 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 int mViewWidth, mViewHeight;
|
||||
private EloUVCCameraView mCameraView;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param surface: drawing surface came from TexureView
|
||||
*/
|
||||
public RenderThread(final EloUVCCameraView cameraView, final SurfaceTexture surface, final int width, final int height) {
|
||||
mCameraView = cameraView;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// draw to preview screen
|
||||
|
||||
//Derek
|
||||
// X Flip
|
||||
if (EloUVCCameraConverter.IR_FLIPX) {
|
||||
mStMatrix[0] = -1 * mStMatrix[0];
|
||||
mStMatrix[12] = 1.0f - mStMatrix[12];
|
||||
}
|
||||
|
||||
// Y Flip
|
||||
// mStMatrix[5] = -mStMatrix[5];
|
||||
// mStMatrix[13] = 1.0f - mStMatrix[13];
|
||||
|
||||
// Rotate 90
|
||||
// Matrix.rotateM(mStMatrix, 0, 90, 0, 0, 1);
|
||||
// Matrix.translateM(mStMatrix, 0, 0, -1, 0);
|
||||
|
||||
// Rotate 180
|
||||
// Matrix.rotateM(mStMatrix, 0, 180, 0, 0, 1);
|
||||
// Matrix.translateM(mStMatrix, 0, -1, -1, 0);
|
||||
|
||||
// Rotate 270
|
||||
// Matrix.rotateM(mStMatrix, 0, 270, 0, 0, 1);
|
||||
// Matrix.translateM(mStMatrix, 0, -1f, 0, 0);
|
||||
|
||||
// Matrix.scaleM(mStMatrix, 0, 0.5f, 1 ,1);
|
||||
// GLES20.glViewport(0, 0, 640, 480);
|
||||
// GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
// GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
//Derek
|
||||
|
||||
int viewWidth = mCameraView.getWidth();
|
||||
int viewHeight = mCameraView.getHeight();
|
||||
Matrix.scaleM(mStMatrix, 0, EloUVCCameraConverter.IR_SCALE, EloUVCCameraConverter.IR_SCALE, 1);
|
||||
Matrix.translateM(mStMatrix, 0, (float)EloUVCCameraConverter.getOffsetX()/EloUVCCameraConverter.IR_SCALED_WIDTH, (float)EloUVCCameraConverter.getOffsetY()/EloUVCCameraConverter.IR_SCALED_HEIGHT, 0);
|
||||
GLES20.glViewport(0, 0, viewWidth, viewHeight);
|
||||
|
||||
//160*120
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
mDrawer.draw(mTexId, mStMatrix, 0);
|
||||
mEglSurface.swap();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void run () {
|
||||
Log.d(TAG, getName() + " started");
|
||||
init();
|
||||
Looper.prepare();
|
||||
synchronized (mSync) {
|
||||
mHandler = new RenderHandler(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.elotouch.uvc;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public interface INewUVCFrame {
|
||||
void onUVCFrame(Bitmap bmp);
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
package com.elotouch.uvc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.serenegiant.usb.IFrameCallback;
|
||||
import com.serenegiant.usb.USBMonitor;
|
||||
import com.serenegiant.usb.UVCCamera;
|
||||
import com.serenegiant.utils.HandlerThreadHandler;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class UVCCameraWrapper {
|
||||
|
||||
private static final String TAG = "UVCCameraWrapper";
|
||||
private Context mContext = null;
|
||||
private USBMonitor mUSBMonitor;
|
||||
|
||||
|
||||
private Handler mWorkerHandler = null;
|
||||
private long mWorkerThreadID = -1;
|
||||
private final Handler mUIHandler = new Handler(Looper.getMainLooper());
|
||||
private final Thread mUiThread = mUIHandler.getLooper().getThread();
|
||||
|
||||
private EloUVCCameraHandler uvcCameraHandler = null;
|
||||
private EloUVCCameraView eloUVCCameraView = null;
|
||||
private INewUVCFrame mNewUVCFrame = null;
|
||||
|
||||
public UVCCameraWrapper(Context context, EloUVCCameraView eloUVCCameraView) {
|
||||
this.mContext = context;
|
||||
this.eloUVCCameraView = eloUVCCameraView;
|
||||
|
||||
if (mWorkerHandler == null) {
|
||||
mWorkerHandler = HandlerThreadHandler.createHandler(TAG);
|
||||
mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId();
|
||||
}
|
||||
|
||||
mUSBMonitor = new USBMonitor(mContext, mOnDeviceConnectListener);
|
||||
}
|
||||
public void setNewUVCFrame(INewUVCFrame newUVCFrame) {
|
||||
this.mNewUVCFrame = newUVCFrame;
|
||||
}
|
||||
|
||||
|
||||
private void connectDevice(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) {
|
||||
Log.v(TAG, "onConnect:" + device);
|
||||
|
||||
if (isCameraDevice(device))
|
||||
{
|
||||
try {
|
||||
if (uvcCameraHandler == null) {
|
||||
uvcCameraHandler = EloUVCCameraHandler.createHandler(1,
|
||||
EloUVCCameraConverter.UVC_WIDTH,
|
||||
EloUVCCameraConverter.UVC_HEIGHT,
|
||||
UVCCamera.FRAME_FORMAT_MJPEG,
|
||||
1.0f
|
||||
);
|
||||
uvcCameraHandler.open(ctrlBlock);
|
||||
isCameraConnected = true;
|
||||
|
||||
Thread.sleep(200);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (uvcCameraHandler != null) {
|
||||
uvcCameraHandler.setFrameCallback(frameCallback);
|
||||
}
|
||||
uvcCameraHandler.startPreview(eloUVCCameraView.getSurfaceTexture());
|
||||
}
|
||||
}
|
||||
private void disconnectDevice(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) {
|
||||
Log.v(TAG, "onDisconnect:" + device);
|
||||
|
||||
if (isCameraDevice(device))
|
||||
{
|
||||
queueEvent(() -> {
|
||||
try {
|
||||
uvcCameraHandler.close();
|
||||
uvcCameraHandler = null;
|
||||
isCameraConnected = false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private long lastConnectTime = -1;
|
||||
private boolean isCameraDevice(final UsbDevice device) {
|
||||
if (device.getDeviceClass() == 239) {
|
||||
if (device.getVendorId() == 7119) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean isCameraConnected = false;
|
||||
private final USBMonitor.OnDeviceConnectListener mOnDeviceConnectListener = new USBMonitor.OnDeviceConnectListener() {
|
||||
@Override
|
||||
public void onAttach(final UsbDevice device) {
|
||||
Log.v(TAG, "onAttach:" + device);
|
||||
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (lastConnectTime == -1) {
|
||||
lastConnectTime = curTime + 500;
|
||||
}
|
||||
else {
|
||||
lastConnectTime = Math.max(curTime+500, lastConnectTime+500);
|
||||
}
|
||||
|
||||
if (isCameraDevice(device) && (isCameraConnected == false))
|
||||
{
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mUSBMonitor.requestPermission(device);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, lastConnectTime - curTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) {
|
||||
connectDevice(device, ctrlBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) {
|
||||
disconnectDevice(device, ctrlBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDettach(final UsbDevice device) {
|
||||
Log.v(TAG, "onDettach:" + device);
|
||||
|
||||
if (isCameraDevice(device)) {
|
||||
isCameraConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(final UsbDevice device) {
|
||||
Log.v(TAG, "onCancel:");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private void processUVCFrame(ByteBuffer frame) {
|
||||
try {
|
||||
Bitmap uvcBmp = Bitmap.createBitmap(EloUVCCameraConverter.UVC_WIDTH, EloUVCCameraConverter.UVC_HEIGHT, Bitmap.Config.ARGB_8888);
|
||||
uvcBmp.copyPixelsFromBuffer(frame);
|
||||
// ImageSaver.saveImage(uvcBmp, "uvc");
|
||||
|
||||
if (mNewUVCFrame != null) {
|
||||
mNewUVCFrame.onUVCFrame(uvcBmp);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
final IFrameCallback frameCallback = new IFrameCallback() {
|
||||
@Override
|
||||
public void onFrame(ByteBuffer frame) {
|
||||
processUVCFrame(frame);
|
||||
}
|
||||
};
|
||||
|
||||
public void onStart() {
|
||||
mUSBMonitor.register();
|
||||
}
|
||||
|
||||
public void onStop() {
|
||||
mUSBMonitor.unregister();
|
||||
}
|
||||
public void onDestroy() {
|
||||
|
||||
if (mUSBMonitor != null) {
|
||||
mUSBMonitor.destroy();
|
||||
mUSBMonitor = null;
|
||||
}
|
||||
|
||||
if (mWorkerHandler != null) {
|
||||
try {
|
||||
mWorkerHandler.getLooper().quit();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mWorkerHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
public USBMonitor getUSBMonitor() {
|
||||
return mUSBMonitor;
|
||||
}
|
||||
|
||||
static int cnt = 0;
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+170
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+73
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ExpertModeActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/frameRGB"
|
||||
app:layout_constraintDimensionRatio="h, 4:3"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
<com.elotouch.uvc.EloUVCCameraView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/RGBView"/>
|
||||
<com.elotouch.elothermal.EloImageCoverView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/RGBCover"
|
||||
android:src="@drawable/mask2"/>
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/frameIR"
|
||||
app:layout_constraintDimensionRatio="h, 4:3"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frameRGB">
|
||||
|
||||
<com.elotouch.thermallib.ThermalSurfaceView
|
||||
android:id="@+id/IRSurfaceView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<com.elotouch.elothermal.EloImageCoverView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/IRCover"
|
||||
android:src="@drawable/mask_empty" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frameIR"
|
||||
android:background="@color/colorBlack">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/normal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/imgNormal"
|
||||
android:visibility="invisible" />
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/abnormal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/imgAbnormal"
|
||||
android:visibility="invisible" />
|
||||
</FrameLayout>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".SmartModeActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/frameRGB"
|
||||
app:layout_constraintDimensionRatio="h, 4:3"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
<com.elotouch.uvc.EloUVCCameraView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/RGBView" />
|
||||
<com.elotouch.elothermal.EloImageCoverView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/RGBCover"
|
||||
android:src="@drawable/mask_empty" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/frameIR"
|
||||
app:layout_constraintDimensionRatio="h, 4:3"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frameRGB">
|
||||
|
||||
<com.elotouch.thermallib.ThermalSurfaceView
|
||||
android:id="@+id/IRSurfaceView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<com.elotouch.elothermal.EloImageCoverView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/IRCover"
|
||||
android:src="@drawable/mask_empty" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frameIR"
|
||||
android:background="@color/colorBlack"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/normal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/imgNormal"
|
||||
android:visibility="invisible" />
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/abnormal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/imgAbnormal"
|
||||
android:visibility="invisible" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left|center_vertical"
|
||||
android:src="@drawable/red_ball"
|
||||
android:id="@+id/imgRed"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:src="@drawable/green_ball"
|
||||
android:id="@+id/imgGreen"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".TestActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/frameRGB"
|
||||
app:layout_constraintDimensionRatio="h, 4:3"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
<com.elotouch.uvc.EloUVCCameraView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/RGBView" />
|
||||
<com.elotouch.elothermal.EloImageCoverView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/RGBCover"
|
||||
android:src="@drawable/mask_empty" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/frameIR"
|
||||
app:layout_constraintDimensionRatio="h, 4:3"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frameRGB">
|
||||
|
||||
<com.elotouch.thermallib.ThermalSurfaceView
|
||||
android:id="@+id/IRSurfaceView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<com.elotouch.elothermal.EloImageCoverView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/IRCover"
|
||||
android:src="@drawable/mask_empty" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/frameIR"
|
||||
android:background="@color/colorBlack"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/normal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/imgNormal"
|
||||
android:visibility="invisible" />
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/abnormal"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/imgAbnormal"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="xxx"
|
||||
android:textSize="@dimen/txSize"
|
||||
android:textColor="@color/colorGreen"
|
||||
android:layout_gravity="center_horizontal|top"
|
||||
android:id="@+id/txName"
|
||||
android:visibility="gone"
|
||||
>
|
||||
</TextView>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="left|center_vertical"
|
||||
>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=" Up "
|
||||
android:textSize="50sp"
|
||||
android:id="@+id/btnUp"
|
||||
/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Down"
|
||||
android:textSize="50sp"
|
||||
android:id="@+id/btnDown"
|
||||
/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Trigger"
|
||||
android:textSize="50sp"
|
||||
android:id="@+id/btnTrigger"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="500dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_horizontal|center_vertical"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="400dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/txDistance"
|
||||
android:textColor="@color/colorGreen"
|
||||
android:textSize="50sp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="400dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/txInnerTemp"
|
||||
android:textColor="@color/colorGreen"
|
||||
android:textSize="20sp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Update"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/btnUpdate"
|
||||
android:gravity="center_horizontal"
|
||||
android:visibility="gone"
|
||||
>
|
||||
|
||||
</Button>
|
||||
<TextView
|
||||
android:layout_width="400dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/txTCMVersion"
|
||||
android:textColor="@color/colorGreen"
|
||||
android:textSize="20sp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="X+"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/btnXPlus"
|
||||
/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="X-"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/btnXMinus"
|
||||
/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Y+"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/btnYPlus"
|
||||
/>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Y-"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/btnYMinus"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/colorGreen"
|
||||
android:id="@+id/txOffset"
|
||||
android:text="xxx"/>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
IR_Camera_SDK-1.0.1/android/android/EloThermal/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
+12665
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- <color name="colorPrimary">#6200EE</color>-->
|
||||
<!-- <color name="colorPrimaryDark">#3700B3</color>-->
|
||||
<!-- <color name="colorAccent">#03DAC5</color>-->
|
||||
<color name="colorRed">#FF1D1D</color>
|
||||
<color name="colorGreen">#00EA85</color>
|
||||
<color name="colorBlack">#292929</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="txSize">40sp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">EloThermal</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,11 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/colorPrimary</item>-->
|
||||
<!-- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>-->
|
||||
<!-- <item name="colorAccent">@color/colorAccent</item>-->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.elotouch.elothermal;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
|
||||
BIN
Binary file not shown.
+6
@@ -0,0 +1,6 @@
|
||||
#Tue Apr 28 09:17:08 CST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,95 @@
|
||||
apply plugin: 'com.android.library'
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
android {
|
||||
compileSdkVersion versionCompiler
|
||||
buildToolsVersion versionBuildTool
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility javaSourceCompatibility
|
||||
targetCompatibility javaTargetCompatibility
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion versionTarget
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDir 'src/main/libs'
|
||||
jni.srcDirs = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
compileTask -> compileTask.dependsOn ndkBuild
|
||||
}
|
||||
|
||||
String getNdkBuildPath() {
|
||||
Properties properties = new Properties()
|
||||
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||
def ndkBuildingDir = properties.getProperty("ndk.dir")
|
||||
def ndkBuildPath = ndkBuildingDir
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
ndkBuildPath = ndkBuildingDir + '/ndk-build.cmd'
|
||||
} else {
|
||||
ndkBuildPath = ndkBuildingDir + '/ndk-build'
|
||||
}
|
||||
return ndkBuildPath
|
||||
}
|
||||
|
||||
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
|
||||
println('executing ndkBuild')
|
||||
def ndkBuildPath = getNdkBuildPath();
|
||||
commandLine ndkBuildPath, '-j8', '-C', file('src/main').absolutePath
|
||||
}
|
||||
|
||||
task ndkClean(type: Exec, description: 'clean JNI libraries') {
|
||||
println('executing ndkBuild clean')
|
||||
def ndkBuildPath = getNdkBuildPath();
|
||||
commandLine ndkBuildPath, 'clean', '-C', file('src/main').absolutePath
|
||||
}
|
||||
|
||||
clean.dependsOn 'ndkClean'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: new File(buildDir, 'libs'), include: '*.jar')
|
||||
|
||||
implementation "com.android.support:support-v4:${supportLibVersion}"
|
||||
implementation "com.android.support:support-annotations:${supportLibVersion}"
|
||||
|
||||
implementation("com.serenegiant:common:${commonLibVersion}") {
|
||||
exclude module: 'support-v4'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":libuvccamera" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="EloThermal" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":libuvccamera" />
|
||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.6.0" />
|
||||
<option name="LAST_KNOWN_AGP_VERSION" value="3.6.0" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="release" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleRelease" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileReleaseSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateReleaseSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/src/release/res;file://$MODULE_DIR$/build/generated/res/rs/release" />
|
||||
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/androidTest/res;file://$MODULE_DIR$/src/test/res;file://$MODULE_DIR$/src/testRelease/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
<option name="PROJECT_TYPE" value="1" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/javac/release/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/releaseUnitTest/classes" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/release/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/release/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/release/out" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/release" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/release" type="java-resource" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/releaseUnitTest/out" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/release/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testRelease/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-v4:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.serenegiant:common:2.12.4@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:preference-v7:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-fragment:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat:27.1.1@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.0@aar" level="project" />
|
||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.0@aar" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.serenegiant.uvccamera"
|
||||
android:versionCode="2"
|
||||
android:versionName="1.1" >
|
||||
|
||||
<uses-sdk android:targetSdkVersion="29" />
|
||||
|
||||
</manifest>
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* 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.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.support.annotation.NonNull;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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.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.support.annotation.NonNull;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
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(com.serenegiant.common.R.string.permission_audio);
|
||||
}
|
||||
if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) {
|
||||
showToast(com.serenegiant.common.R.string.permission_ext_storage);
|
||||
}
|
||||
if (Manifest.permission.INTERNET.equals(permission)) {
|
||||
showToast(com.serenegiant.common.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,
|
||||
com.serenegiant.common.R.string.permission_title, com.serenegiant.common.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,
|
||||
com.serenegiant.common.R.string.permission_title, com.serenegiant.common.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,
|
||||
com.serenegiant.common.R.string.permission_title, com.serenegiant.common.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,
|
||||
com.serenegiant.common.R.string.permission_title, com.serenegiant.common.R.string.permission_camera_request,
|
||||
new String[]{Manifest.permission.CAMERA});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.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
|
||||
}
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.serenegiant.usb.DeviceFilter;
|
||||
import com.serenegiant.usb.USBMonitor;
|
||||
|
||||
import com.serenegiant.uvccamera.R;
|
||||
|
||||
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<DeviceFilter> 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<UsbDevice> mList;
|
||||
|
||||
public DeviceListAdapter(final Context context, final List<UsbDevice>list) {
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mList = list != null ? list : new ArrayList<UsbDevice>();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+527
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
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;
|
||||
|
||||
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<DeviceFilter> getDeviceFilters(final Context context, final int deviceFilterXmlId) {
|
||||
final XmlPullParser parser = context.getResources().getXml(deviceFilterXmlId);
|
||||
final List<DeviceFilter> deviceFilters = new ArrayList<DeviceFilter>();
|
||||
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
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.serenegiant.usb;
|
||||
|
||||
public interface IButtonCallback {
|
||||
void onButton(int button, int state);
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.serenegiant.usb;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface IStatusCallback {
|
||||
void onStatus(int statusClass, int event, int selector, int statusAttribute, ByteBuffer data);
|
||||
}
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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.util.Locale;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
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<Size> CREATOR = new Parcelable.Creator<Size>() {
|
||||
@Override
|
||||
public Size createFromParcel(final Parcel source) {
|
||||
return new Size(source);
|
||||
}
|
||||
@Override
|
||||
public Size[] newArray(final int size) {
|
||||
return new Size[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
+1346
File diff suppressed because it is too large
Load Diff
+859
@@ -0,0 +1,859 @@
|
||||
/*
|
||||
* 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<String> IDS = new SparseArray<String>();
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
+1224
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
#include $(call all-subdir-makefiles)
|
||||
PROJ_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
include $(PROJ_PATH)/UVCCamera/Android.mk
|
||||
include $(PROJ_PATH)/libjpeg-turbo-1.5.0/Android.mk
|
||||
include $(PROJ_PATH)/libusb/android/jni/Android.mk
|
||||
include $(PROJ_PATH)/libuvc/android/jni/Android.mk
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#/*
|
||||
# * UVCCamera
|
||||
# * library and sample to access to UVC web camera on non-rooted Android device
|
||||
# *
|
||||
# * Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
# *
|
||||
# * File name: Application.mk
|
||||
# *
|
||||
# * 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
#*/
|
||||
|
||||
# This is just for mips, if you really needs MSA, un-comment and build with GCC.
|
||||
# Note: Supporting GCC on NDK is already deprecated and GCC will be removed from NDK soon.
|
||||
#NDK_TOOLCHAIN_VERSION := 4.9
|
||||
|
||||
APP_PLATFORM := android-16
|
||||
APP_ABI := armeabi-v7a arm64-v8a
|
||||
|
||||
|
||||
#APP_OPTIM := debug
|
||||
APP_OPTIM := release
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
#/*
|
||||
# * UVCCamera
|
||||
# * library and sample to access to UVC web camera on non-rooted Android device
|
||||
# *
|
||||
# * Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
# *
|
||||
# * File name: Android.mk
|
||||
# *
|
||||
# * 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
#*/
|
||||
|
||||
######################################################################
|
||||
# Make shared library libUVCCamera.so
|
||||
######################################################################
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
######################################################################
|
||||
# Make shared library libUVCCamera.so
|
||||
######################################################################
|
||||
CFLAGS := -Werror
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/ \
|
||||
$(LOCAL_PATH)/../ \
|
||||
$(LOCAL_PATH)/../rapidjson/include \
|
||||
|
||||
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
|
||||
LOCAL_CFLAGS += -DANDROID_NDK
|
||||
LOCAL_CFLAGS += -DLOG_NDEBUG
|
||||
LOCAL_CFLAGS += -DACCESS_RAW_DESCRIPTORS
|
||||
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays
|
||||
|
||||
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl
|
||||
LOCAL_LDLIBS += -llog
|
||||
LOCAL_LDLIBS += -landroid
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += usb100 uvc
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
_onload.cpp \
|
||||
utilbase.cpp \
|
||||
UVCCamera.cpp \
|
||||
UVCPreview.cpp \
|
||||
UVCButtonCallback.cpp \
|
||||
UVCStatusCallback.cpp \
|
||||
Parameters.cpp \
|
||||
serenegiant_usb_UVCCamera.cpp
|
||||
|
||||
LOCAL_MODULE := UVCCamera
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: Parameters.cpp
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
#define LOG_TAG "Parameters"
|
||||
|
||||
#include "Parameters.h"
|
||||
#include "rapidjson/rapidjson.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "libuvc/libuvc_internal.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
static void write(Writer<StringBuffer> &writer, const char *key, const char *value) {
|
||||
writer.String(key);
|
||||
writer.String(value);
|
||||
}
|
||||
|
||||
static void write(Writer<StringBuffer> &writer, const char *key, uint16_t value) {
|
||||
writer.String(key);
|
||||
writer.Uint(value);
|
||||
}
|
||||
|
||||
static void write(Writer<StringBuffer> &writer, const char *key, int32_t value) {
|
||||
writer.String(key);
|
||||
writer.Int(value);
|
||||
}
|
||||
|
||||
static void write(Writer<StringBuffer> &writer, const char *key, uint32_t value) {
|
||||
writer.String(key);
|
||||
writer.Uint(value);
|
||||
}
|
||||
|
||||
static void write(Writer<StringBuffer> &writer, const char *key, int64_t value) {
|
||||
writer.String(key);
|
||||
writer.Int64(value);
|
||||
}
|
||||
|
||||
static void write(Writer<StringBuffer> &writer, const char *key, uint64_t value) {
|
||||
writer.String(key);
|
||||
writer.Uint64(value);
|
||||
}
|
||||
|
||||
static const char *_uvc_name_for_format_subtype(uint8_t subtype) {
|
||||
switch (subtype) {
|
||||
case UVC_VS_FORMAT_UNCOMPRESSED:
|
||||
return "UncompressedFormat";
|
||||
case UVC_VS_FORMAT_MJPEG:
|
||||
return "MJPEGFormat";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#define INDEX "index"
|
||||
#define TYPE "type"
|
||||
#define SUBTYPE "subType"
|
||||
#define WIDTH "width"
|
||||
#define HEIGHT "height"
|
||||
#define VALUE "value"
|
||||
#define DETAIL "detail"
|
||||
|
||||
#define DESCRIPTION "description"
|
||||
#define DESC_SUBTYPE SUBTYPE
|
||||
#define DESC_VENDERID "venderId"
|
||||
#define DESC_PRODUCTID "productId"
|
||||
#define DESC_SERIALNUMBER "serialNumber"
|
||||
#define DESC_MANIFUCTURE "manifuctureName"
|
||||
#define DESC_PRODUCT "productName"
|
||||
#define DESC_UVC "uvc"
|
||||
#define DESC_VIDEO_CONTROL "videoControl"
|
||||
#define DESC_INTERFACES "interfaces"
|
||||
|
||||
#define INTERFACE_TYPE TYPE
|
||||
#define INTERFACE_TYPE_VIDEOSTREAM "videoStreaming"
|
||||
#define INTERFACE_TYPE_AUDIOSTREAM "audioStreaming"
|
||||
#define INTERFACE_INDEX INDEX
|
||||
#define INTERFACE_ENDPOINT_ADDR "endpointAddress"
|
||||
|
||||
#define FORMATS "formats"
|
||||
#define FORMAT_INDEX INDEX
|
||||
#define FORMAT_NAME "format"
|
||||
#define FORMAT_DETAIL DETAIL
|
||||
#define FORMAT_BITS_PER_PIXEL "bitsPerPixel"
|
||||
#define FORMAT_GUID "GUID"
|
||||
#define FORMAT_DEFAULT_FRAME_INDEX "defaultFrameIndex"
|
||||
#define FORMAT_ASPECTRATIO_X "aspectRatioX"
|
||||
#define FORMAT_ASPECTRATIO_Y "aspectRatioY"
|
||||
#define FORMAT_INTERLACE_FLAGS "interlaceFlags"
|
||||
#define FORMAT_COPY_PROTECT "copyProtect"
|
||||
#define FORMAT_FRAMEDESCRIPTORS "frameDescriptors"
|
||||
|
||||
#define FRAME_INDEX INDEX
|
||||
#define FRAME_CAPABILITIES "capabilities"
|
||||
#define FRAME_WIDTH WIDTH
|
||||
#define FRAME_HEIGHT HEIGHT
|
||||
#define FRAME_BITRATE_MIN "minBitRate"
|
||||
#define FRAME_BITRATE_MAX "maxBitRate"
|
||||
#define FRAME_FRAMEBUFFERSIZE_MAX "maxFrameBufferSize"
|
||||
#define FRAME_INTERVAL_DEFAULT "defaultFrameInterval"
|
||||
#define FRAME_FPS_DEFAULT "defaultFps"
|
||||
#define FRAME_INTERVALS "intervals"
|
||||
#define FRAME_INTERVAL_INDEX INDEX
|
||||
#define FRAME_INTERVAL_VALUE VALUE
|
||||
#define FRAME_INTERVAL_FPS "fps"
|
||||
#define FRAME_INTERVAL_MIN "minFrameInterval"
|
||||
#define FRAME_INTERVAL_MAX "maxFrameInterval"
|
||||
#define FRAME_INTERVAL_STEP "frameIntervalStep"
|
||||
|
||||
static void writerFormat(Writer<StringBuffer> &writer, uvc_format_desc_t *fmt_desc) {
|
||||
uvc_frame_desc_t *frame_desc;
|
||||
char work[256];
|
||||
|
||||
writer.String(FORMAT_DETAIL);
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, FORMAT_BITS_PER_PIXEL, fmt_desc->bBitsPerPixel);
|
||||
sprintf(work,
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
fmt_desc->guidFormat[0], fmt_desc->guidFormat[1],
|
||||
fmt_desc->guidFormat[2], fmt_desc->guidFormat[3],
|
||||
fmt_desc->guidFormat[4], fmt_desc->guidFormat[5],
|
||||
fmt_desc->guidFormat[6], fmt_desc->guidFormat[7],
|
||||
fmt_desc->guidFormat[8], fmt_desc->guidFormat[9],
|
||||
fmt_desc->guidFormat[10], fmt_desc->guidFormat[11],
|
||||
fmt_desc->guidFormat[12], fmt_desc->guidFormat[13],
|
||||
fmt_desc->guidFormat[14], fmt_desc->guidFormat[15]);
|
||||
write(writer, FORMAT_GUID, work);
|
||||
write(writer, FORMAT_DEFAULT_FRAME_INDEX, fmt_desc->bDefaultFrameIndex);
|
||||
write(writer, FORMAT_ASPECTRATIO_X, fmt_desc->bAspectRatioX);
|
||||
write(writer, FORMAT_ASPECTRATIO_Y, fmt_desc->bAspectRatioY);
|
||||
write(writer, FORMAT_INTERLACE_FLAGS, fmt_desc->bmInterlaceFlags);
|
||||
write(writer, FORMAT_COPY_PROTECT, fmt_desc->bCopyProtect);
|
||||
|
||||
writer.String(FORMAT_FRAMEDESCRIPTORS);
|
||||
writer.StartArray();
|
||||
DL_FOREACH(fmt_desc->frame_descs, frame_desc)
|
||||
{
|
||||
uint32_t *interval_ptr;
|
||||
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, FRAME_INDEX, frame_desc->bFrameIndex);
|
||||
write(writer, FRAME_CAPABILITIES, frame_desc->bmCapabilities);
|
||||
write(writer, FRAME_WIDTH, frame_desc->wWidth);
|
||||
write(writer, FRAME_HEIGHT, frame_desc->wHeight);
|
||||
write(writer, FRAME_BITRATE_MIN, frame_desc->dwMinBitRate);
|
||||
write(writer, FRAME_BITRATE_MAX, frame_desc->dwMaxBitRate);
|
||||
write(writer, FRAME_FRAMEBUFFERSIZE_MAX, frame_desc->dwMaxVideoFrameBufferSize);
|
||||
write(writer, FRAME_INTERVAL_DEFAULT, frame_desc->dwDefaultFrameInterval);
|
||||
write(writer, FRAME_FPS_DEFAULT, 10000000 / frame_desc->dwDefaultFrameInterval);
|
||||
|
||||
if (frame_desc->intervals) {
|
||||
writer.String(FRAME_INTERVALS);
|
||||
writer.StartArray();
|
||||
for (interval_ptr = frame_desc->intervals; *interval_ptr; ++interval_ptr) {
|
||||
writer.StartObject();
|
||||
write(writer, FRAME_INTERVAL_INDEX, (int ) (interval_ptr - frame_desc->intervals));
|
||||
write(writer, FRAME_INTERVAL_VALUE, *interval_ptr);
|
||||
write(writer, FRAME_INTERVAL_FPS, 10000000 / *interval_ptr);
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
} else {
|
||||
// 最小fps
|
||||
writer.String(FRAME_INTERVAL_MIN);
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, FRAME_INTERVAL_INDEX, frame_desc->dwMinFrameInterval);
|
||||
write(writer, FRAME_INTERVAL_VALUE, frame_desc->dwMinFrameInterval);
|
||||
write(writer, FRAME_INTERVAL_FPS, 10000000 / frame_desc->dwMinFrameInterval);
|
||||
}
|
||||
writer.EndObject();
|
||||
// 最大fps
|
||||
writer.String(FRAME_INTERVAL_MAX);
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, FRAME_INTERVAL_INDEX, frame_desc->dwMaxFrameInterval);
|
||||
write(writer, FRAME_INTERVAL_VALUE, frame_desc->dwMaxFrameInterval);
|
||||
write(writer, FRAME_INTERVAL_FPS, 10000000 / frame_desc->dwMaxFrameInterval);
|
||||
}
|
||||
writer.EndObject();
|
||||
if (frame_desc->dwFrameIntervalStep) {
|
||||
// fpsステップ
|
||||
writer.String(FRAME_INTERVAL_STEP);
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, FRAME_INTERVAL_INDEX, frame_desc->dwFrameIntervalStep);
|
||||
write(writer, FRAME_INTERVAL_VALUE, frame_desc->dwFrameIntervalStep);
|
||||
write(writer, FRAME_INTERVAL_FPS, 10000000 / frame_desc->dwFrameIntervalStep);
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray(); // end of FORMAT_FRAMEDESCRIPTORS
|
||||
}
|
||||
writer.EndObject(); // end of FORMAT_DETAIL
|
||||
}
|
||||
|
||||
static void writerFormatDescriptions(Writer<StringBuffer> &writer, uvc_streaming_interface_t *stream_if) {
|
||||
|
||||
uvc_format_desc_t *fmt_desc;
|
||||
int i;
|
||||
|
||||
writer.String(FORMATS);
|
||||
writer.StartArray();
|
||||
DL_FOREACH(stream_if->format_descs, fmt_desc)
|
||||
{
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, FORMAT_INDEX, fmt_desc->bFormatIndex);
|
||||
write(writer, DESC_SUBTYPE, fmt_desc->bDescriptorSubtype);
|
||||
write(writer, FORMAT_NAME, _uvc_name_for_format_subtype(fmt_desc->bDescriptorSubtype));
|
||||
switch (fmt_desc->bDescriptorSubtype) {
|
||||
case UVC_VS_FORMAT_UNCOMPRESSED:
|
||||
case UVC_VS_FORMAT_MJPEG:
|
||||
writerFormat(writer, fmt_desc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray(); // end of FORMATS
|
||||
}
|
||||
|
||||
UVCDiags::UVCDiags() {}
|
||||
UVCDiags::~UVCDiags() {};
|
||||
|
||||
char *UVCDiags::getDescriptions(const uvc_device_handle_t *deviceHandle) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
char work[256];
|
||||
|
||||
ENTER();
|
||||
writer.StartObject();
|
||||
{
|
||||
writer.String(DESCRIPTION);
|
||||
writer.StartObject();
|
||||
{
|
||||
uvc_device_descriptor_t *desc;
|
||||
uvc_get_device_descriptor(deviceHandle->dev, &desc);
|
||||
write(writer, DESC_VENDERID, desc->idVendor);
|
||||
write(writer, DESC_PRODUCTID, desc->idProduct);
|
||||
write(writer, DESC_SERIALNUMBER, desc->serialNumber ? desc->serialNumber : "[none]");
|
||||
write(writer, DESC_MANIFUCTURE, desc->manufacturer ? desc->manufacturer : "[unknown]");
|
||||
// write(writer, DESC_PRODUCT, desc->product ? desc->product : "UVC Camera");
|
||||
if (desc->product)
|
||||
write(writer, DESC_PRODUCT, desc->product);
|
||||
else {
|
||||
sprintf(work, "UVC Camera (%x:%x)", desc->idVendor, desc->idProduct);
|
||||
write(writer, DESC_PRODUCT, work);
|
||||
}
|
||||
uvc_free_device_descriptor(desc);
|
||||
|
||||
if (deviceHandle->info->ctrl_if.bcdUVC) {
|
||||
writer.String(DESC_UVC);
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, DESC_VIDEO_CONTROL, deviceHandle->info->ctrl_if.bcdUVC);
|
||||
|
||||
writer.String(DESC_INTERFACES);
|
||||
writer.StartArray();
|
||||
{
|
||||
assert(deviceHandle->info->stream_ifs);
|
||||
uvc_streaming_interface_t *stream_if;
|
||||
int stream_idx = 0;
|
||||
|
||||
DL_FOREACH(deviceHandle->info->stream_ifs, stream_if)
|
||||
{
|
||||
++stream_idx;
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, INTERFACE_TYPE, INTERFACE_TYPE_VIDEOSTREAM);
|
||||
write(writer, INTERFACE_INDEX, stream_idx);
|
||||
write(writer, INTERFACE_ENDPOINT_ADDR, stream_if->bEndpointAddress);
|
||||
writerFormatDescriptions(writer, stream_if);
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
}
|
||||
writer.EndArray(); // end of DESC_INTERFACES
|
||||
}
|
||||
writer.EndObject(); // end of DESC_UVC
|
||||
}
|
||||
// XXX other interfaces
|
||||
}
|
||||
writer.EndObject(); // end of DESCRIPTION
|
||||
}
|
||||
writer.EndObject();
|
||||
RETURN(strdup(buffer.GetString()), char *);
|
||||
}
|
||||
|
||||
char *UVCDiags::getCurrentStream(const uvc_stream_ctrl_t *ctrl) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
|
||||
ENTER();
|
||||
writer.StartObject();
|
||||
{
|
||||
write(writer, "hint", ctrl->bmHint);
|
||||
write(writer, "formatIndex", ctrl->bFormatIndex);
|
||||
write(writer, "frameIndex", ctrl->bFrameIndex);
|
||||
write(writer, "frameInterval", ctrl->dwFrameInterval);
|
||||
write(writer, "keyFrameRate", ctrl->wKeyFrameRate);
|
||||
write(writer, "frameRate", ctrl->wPFrameRate);
|
||||
write(writer, "compQuality", ctrl->wCompQuality);
|
||||
write(writer, "compWindowSize", ctrl->wCompWindowSize);
|
||||
write(writer, "delay", ctrl->wDelay);
|
||||
write(writer, "maxVideoFrameSize", ctrl->dwMaxVideoFrameSize);
|
||||
write(writer, "maxPayloadTransferSize", ctrl->dwMaxPayloadTransferSize);
|
||||
write(writer, "interfaceNumber", ctrl->bInterfaceNumber);
|
||||
}
|
||||
writer.EndObject();
|
||||
RETURN(strdup(buffer.GetString()), char *);
|
||||
}
|
||||
|
||||
char *UVCDiags::getSupportedSize(const uvc_device_handle_t *deviceHandle) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
char buf[256];
|
||||
|
||||
ENTER();
|
||||
writer.StartObject();
|
||||
{
|
||||
if (deviceHandle->info->stream_ifs) {
|
||||
uvc_streaming_interface_t *stream_if;
|
||||
int stream_idx = 0;
|
||||
|
||||
writer.String("formats");
|
||||
writer.StartArray();
|
||||
DL_FOREACH(deviceHandle->info->stream_ifs, stream_if)
|
||||
{
|
||||
++stream_idx;
|
||||
uvc_format_desc_t *fmt_desc;
|
||||
uvc_frame_desc_t *frame_desc;
|
||||
DL_FOREACH(stream_if->format_descs, fmt_desc)
|
||||
{
|
||||
writer.StartObject();
|
||||
{
|
||||
switch (fmt_desc->bDescriptorSubtype) {
|
||||
case UVC_VS_FORMAT_UNCOMPRESSED:
|
||||
case UVC_VS_FORMAT_MJPEG:
|
||||
write(writer, "index", fmt_desc->bFormatIndex);
|
||||
write(writer, "type", fmt_desc->bDescriptorSubtype);
|
||||
write(writer, "default", fmt_desc->bDefaultFrameIndex);
|
||||
writer.String("size");
|
||||
writer.StartArray();
|
||||
DL_FOREACH(fmt_desc->frame_descs, frame_desc)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%dx%d", frame_desc->wWidth, frame_desc->wHeight);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
writer.String(buf);
|
||||
}
|
||||
writer.EndArray();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
}
|
||||
writer.EndArray();
|
||||
// FIXME still image is not supported now
|
||||
}
|
||||
}
|
||||
writer.EndObject();
|
||||
RETURN(strdup(buffer.GetString()), char *);
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2015-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: Parameters.h
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
#ifndef PARAMETERS_H_
|
||||
#define PARAMETERS_H_
|
||||
|
||||
#pragma interface
|
||||
|
||||
#include "libUVCCamera.h"
|
||||
|
||||
class UVCDiags {
|
||||
private:
|
||||
public:
|
||||
UVCDiags();
|
||||
~UVCDiags();
|
||||
char *getDescriptions(const uvc_device_handle_t *deviceHandle);
|
||||
char *getCurrentStream(const uvc_stream_ctrl_t *ctrl);
|
||||
char *getSupportedSize(const uvc_device_handle_t *deviceHandle);
|
||||
};
|
||||
|
||||
#endif /* PARAMETERS_H_ */
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
#include <stdlib.h>
|
||||
#include <linux/time.h>
|
||||
#include <unistd.h>
|
||||
#include "utilbase.h"
|
||||
#include "UVCButtonCallback.h"
|
||||
#include "libuvc_internal.h"
|
||||
|
||||
#define LOCAL_DEBUG 0
|
||||
|
||||
UVCButtonCallback::UVCButtonCallback(uvc_device_handle_t *devh)
|
||||
: mDeviceHandle(devh),
|
||||
mButtonCallbackObj(NULL) {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_init(&button_mutex, NULL);
|
||||
|
||||
uvc_set_button_callback(mDeviceHandle, uvc_button_callback, (void *)this);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
UVCButtonCallback::~UVCButtonCallback() {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_destroy(&button_mutex);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
int UVCButtonCallback::setCallback(JNIEnv *env, jobject button_callback_obj) {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_lock(&button_mutex);
|
||||
{
|
||||
if (!env->IsSameObject(mButtonCallbackObj, button_callback_obj)) {
|
||||
ibuttoncallback_fields.onButton = NULL;
|
||||
if (mButtonCallbackObj) {
|
||||
env->DeleteGlobalRef(mButtonCallbackObj);
|
||||
}
|
||||
mButtonCallbackObj = button_callback_obj;
|
||||
if (button_callback_obj) {
|
||||
// get method IDs of Java object for callback
|
||||
jclass clazz = env->GetObjectClass(button_callback_obj);
|
||||
if (LIKELY(clazz)) {
|
||||
ibuttoncallback_fields.onButton = env->GetMethodID(clazz,
|
||||
"onButton", "(II)V");
|
||||
} else {
|
||||
LOGW("failed to get object class");
|
||||
}
|
||||
env->ExceptionClear();
|
||||
if (!ibuttoncallback_fields.onButton) {
|
||||
LOGE("Can't find IButtonCallback#onButton");
|
||||
env->DeleteGlobalRef(button_callback_obj);
|
||||
mButtonCallbackObj = button_callback_obj = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&button_mutex);
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
void UVCButtonCallback::notifyButtonCallback(JNIEnv* env, int button, int state) {
|
||||
|
||||
pthread_mutex_lock(&button_mutex);
|
||||
{
|
||||
if (mButtonCallbackObj) {
|
||||
env->CallVoidMethod(mButtonCallbackObj, ibuttoncallback_fields.onButton, button, state);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&button_mutex);
|
||||
}
|
||||
|
||||
void UVCButtonCallback::uvc_button_callback(int button, int state, void *user_ptr) {
|
||||
|
||||
UVCButtonCallback *buttonCallback = reinterpret_cast<UVCButtonCallback *>(user_ptr);
|
||||
|
||||
JavaVM *vm = getVM();
|
||||
JNIEnv *env;
|
||||
// attach to JavaVM
|
||||
vm->AttachCurrentThread(&env, NULL);
|
||||
|
||||
buttonCallback->notifyButtonCallback(env, button, state);
|
||||
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#ifndef UVCBUTTONCALLBACK_H_
|
||||
#define UVCBUTTONCALLBACK_H_
|
||||
|
||||
#include "libUVCCamera.h"
|
||||
#include <pthread.h>
|
||||
#include <android/native_window.h>
|
||||
#include "objectarray.h"
|
||||
|
||||
#pragma interface
|
||||
|
||||
// for callback to Java object
|
||||
typedef struct {
|
||||
jmethodID onButton;
|
||||
} Fields_ibuttoncallback;
|
||||
|
||||
class UVCButtonCallback {
|
||||
private:
|
||||
uvc_device_handle_t *mDeviceHandle;
|
||||
pthread_mutex_t button_mutex;
|
||||
jobject mButtonCallbackObj;
|
||||
Fields_ibuttoncallback ibuttoncallback_fields;
|
||||
void notifyButtonCallback(JNIEnv *env, int button, int state);
|
||||
static void uvc_button_callback(int button, int state, void *user_ptr);
|
||||
public:
|
||||
UVCButtonCallback(uvc_device_handle_t *devh);
|
||||
~UVCButtonCallback();
|
||||
|
||||
int setCallback(JNIEnv *env, jobject button_callback_obj);
|
||||
};
|
||||
|
||||
#endif /* UVCBUTTONCALLBACK_H_ */
|
||||
+2285
File diff suppressed because it is too large
Load Diff
+358
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: UVCCamera.h
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#pragma interface
|
||||
|
||||
#ifndef UVCCAMERA_H_
|
||||
#define UVCCAMERA_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <android/native_window.h>
|
||||
#include "UVCStatusCallback.h"
|
||||
#include "UVCButtonCallback.h"
|
||||
#include "UVCPreview.h"
|
||||
|
||||
#define CTRL_SCANNING 0x000001 // D0: Scanning Mode
|
||||
#define CTRL_AE 0x000002 // D1: Auto-Exposure Mode
|
||||
#define CTRL_AE_PRIORITY 0x000004 // D2: Auto-Exposure Priority
|
||||
#define CTRL_AE_ABS 0x000008 // D3: Exposure Time (Absolute)
|
||||
#define CTRL_AE_REL 0x000010 // D4: Exposure Time (Relative)
|
||||
#define CTRL_FOCUS_ABS 0x000020 // D5: Focus (Absolute)
|
||||
#define CTRL_FOCUS_REL 0x000040 // D6: Focus (Relative)
|
||||
#define CTRL_IRIS_ABS 0x000080 // D7: Iris (Absolute)
|
||||
#define CTRL_IRIS_REL 0x000100 // D8: Iris (Relative)
|
||||
#define CTRL_ZOOM_ABS 0x000200 // D9: Zoom (Absolute)
|
||||
#define CTRL_ZOOM_REL 0x000400 // D10: Zoom (Relative)
|
||||
#define CTRL_PANTILT_ABS 0x000800 // D11: PanTilt (Absolute)
|
||||
#define CTRL_PANTILT_REL 0x001000 // D12: PanTilt (Relative)
|
||||
#define CTRL_ROLL_ABS 0x002000 // D13: Roll (Absolute)
|
||||
#define CTRL_ROLL_REL 0x004000 // D14: Roll (Relative)
|
||||
//#define CTRL_D15 0x008000 // D15: Reserved
|
||||
//#define CTRL_D16 0x010000 // D16: Reserved
|
||||
#define CTRL_FOCUS_AUTO 0x020000 // D17: Focus, Auto
|
||||
#define CTRL_PRIVACY 0x040000 // D18: Privacy
|
||||
#define CTRL_FOCUS_SIMPLE 0x080000 // D19: Focus, Simple
|
||||
#define CTRL_WINDOW 0x100000 // D20: Window
|
||||
|
||||
#define PU_BRIGHTNESS 0x000001 // D0: Brightness
|
||||
#define PU_CONTRAST 0x000002 // D1: Contrast
|
||||
#define PU_HUE 0x000004 // D2: Hue
|
||||
#define PU_SATURATION 0x000008 // D3: Saturation
|
||||
#define PU_SHARPNESS 0x000010 // D4: Sharpness
|
||||
#define PU_GAMMA 0x000020 // D5: Gamma
|
||||
#define PU_WB_TEMP 0x000040 // D6: White Balance Temperature
|
||||
#define PU_WB_COMPO 0x000080 // D7: White Balance Component
|
||||
#define PU_BACKLIGHT 0x000100 // D8: Backlight Compensation
|
||||
#define PU_GAIN 0x000200 // D9: Gain
|
||||
#define PU_POWER_LF 0x000400 // D10: Power Line Frequency
|
||||
#define PU_HUE_AUTO 0x000800 // D11: Hue, Auto
|
||||
#define PU_WB_TEMP_AUTO 0x001000 // D12: White Balance Temperature, Auto
|
||||
#define PU_WB_COMPO_AUTO 0x002000 // D13: White Balance Component, Auto
|
||||
#define PU_DIGITAL_MULT 0x004000 // D14: Digital Multiplier
|
||||
#define PU_DIGITAL_LIMIT 0x008000 // D15: Digital Multiplier Limit
|
||||
#define PU_AVIDEO_STD 0x010000 // D16: Analog Video Standard
|
||||
#define PU_AVIDEO_LOCK 0x020000 // D17: Analog Video Lock Status
|
||||
#define PU_CONTRAST_AUTO 0x040000 // D18: Contrast, Auto
|
||||
|
||||
typedef struct control_value {
|
||||
int res; // unused
|
||||
int min;
|
||||
int max;
|
||||
int def;
|
||||
int current;
|
||||
} control_value_t;
|
||||
|
||||
typedef uvc_error_t (*paramget_func_i8)(uvc_device_handle_t *devh, int8_t *value, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_i16)(uvc_device_handle_t *devh, int16_t *value, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_i32)(uvc_device_handle_t *devh, int32_t *value, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_u8)(uvc_device_handle_t *devh, uint8_t *value, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_u16)(uvc_device_handle_t *devh, uint16_t *value, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_u32)(uvc_device_handle_t *devh, uint32_t *value, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_u8u8)(uvc_device_handle_t *devh, uint8_t *value1, uint8_t *value2, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_i8u8)(uvc_device_handle_t *devh, int8_t *value1, uint8_t *value2, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_i8u8u8)(uvc_device_handle_t *devh, int8_t *value1, uint8_t *value2, uint8_t *value3, enum uvc_req_code req_code);
|
||||
typedef uvc_error_t (*paramget_func_i32i32)(uvc_device_handle_t *devh, int32_t *value1, int32_t *value2, enum uvc_req_code req_code);
|
||||
|
||||
typedef uvc_error_t (*paramset_func_i8)(uvc_device_handle_t *devh, int8_t value);
|
||||
typedef uvc_error_t (*paramset_func_i16)(uvc_device_handle_t *devh, int16_t value);
|
||||
typedef uvc_error_t (*paramset_func_i32)(uvc_device_handle_t *devh, int32_t value);
|
||||
typedef uvc_error_t (*paramset_func_u8)(uvc_device_handle_t *devh, uint8_t value);
|
||||
typedef uvc_error_t (*paramset_func_u16)(uvc_device_handle_t *devh, uint16_t value);
|
||||
typedef uvc_error_t (*paramset_func_u32)(uvc_device_handle_t *devh, uint32_t value);
|
||||
typedef uvc_error_t (*paramset_func_u8u8)(uvc_device_handle_t *devh, uint8_t value1, uint8_t value2);
|
||||
typedef uvc_error_t (*paramset_func_i8u8)(uvc_device_handle_t *devh, int8_t value1, uint8_t value2);
|
||||
typedef uvc_error_t (*paramset_func_i8u8u8)(uvc_device_handle_t *devh, int8_t value1, uint8_t value2, uint8_t value3);
|
||||
typedef uvc_error_t (*paramset_func_i32i32)(uvc_device_handle_t *devh, int32_t value1, int32_t value2);
|
||||
|
||||
class UVCCamera {
|
||||
char *mUsbFs;
|
||||
uvc_context_t *mContext;
|
||||
int mFd;
|
||||
uvc_device_t *mDevice;
|
||||
uvc_device_handle_t *mDeviceHandle;
|
||||
UVCStatusCallback *mStatusCallback;
|
||||
UVCButtonCallback *mButtonCallback;
|
||||
// プレビュー用
|
||||
UVCPreview *mPreview;
|
||||
uint64_t mCtrlSupports;
|
||||
uint64_t mPUSupports;
|
||||
control_value_t mScanningMode;
|
||||
control_value_t mExposureMode;
|
||||
control_value_t mExposurePriority;
|
||||
control_value_t mExposureAbs;
|
||||
control_value_t mAutoFocus;
|
||||
control_value_t mAutoWhiteBlance;
|
||||
control_value_t mAutoWhiteBlanceCompo;
|
||||
control_value_t mWhiteBlance;
|
||||
control_value_t mWhiteBlanceCompo;
|
||||
control_value_t mBacklightComp;
|
||||
control_value_t mBrightness;
|
||||
control_value_t mContrast;
|
||||
control_value_t mAutoContrast;
|
||||
control_value_t mSharpness;
|
||||
control_value_t mGain;
|
||||
control_value_t mGamma;
|
||||
control_value_t mSaturation;
|
||||
control_value_t mHue;
|
||||
control_value_t mAutoHue;
|
||||
control_value_t mZoom;
|
||||
control_value_t mZoomRel;
|
||||
control_value_t mFocus;
|
||||
control_value_t mFocusRel;
|
||||
control_value_t mFocusSimple;
|
||||
control_value_t mIris;
|
||||
control_value_t mIrisRel;
|
||||
control_value_t mPan;
|
||||
control_value_t mTilt;
|
||||
control_value_t mRoll;
|
||||
control_value_t mPanRel;
|
||||
control_value_t mTiltRel;
|
||||
control_value_t mRollRel;
|
||||
control_value_t mPrivacy;
|
||||
control_value_t mPowerlineFrequency;
|
||||
control_value_t mMultiplier;
|
||||
control_value_t mMultiplierLimit;
|
||||
control_value_t mAnalogVideoStandard;
|
||||
control_value_t mAnalogVideoLockState;
|
||||
|
||||
void clearCameraParams();
|
||||
int internalSetCtrlValue(control_value_t &values, int8_t value,
|
||||
paramget_func_i8 get_func, paramset_func_i8 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, uint8_t value,
|
||||
paramget_func_u8 get_func, paramset_func_u8 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, uint8_t value1, uint8_t value2,
|
||||
paramget_func_u8u8 get_func, paramset_func_u8u8 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, int8_t value1, uint8_t value2,
|
||||
paramget_func_i8u8 get_func, paramset_func_i8u8 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, int8_t value1, uint8_t value2, uint8_t value3,
|
||||
paramget_func_i8u8u8 get_func, paramset_func_i8u8u8 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, int16_t value,
|
||||
paramget_func_i16 get_func, paramset_func_i16 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, uint16_t value,
|
||||
paramget_func_u16 get_func, paramset_func_u16 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, int32_t value,
|
||||
paramget_func_i32 get_func, paramset_func_i32 set_func);
|
||||
int internalSetCtrlValue(control_value_t &values, uint32_t value,
|
||||
paramget_func_u32 get_func, paramset_func_u32 set_func);
|
||||
public:
|
||||
UVCCamera();
|
||||
~UVCCamera();
|
||||
|
||||
int connect(int vid, int pid, int fd, int busnum, int devaddr, const char *usbfs);
|
||||
int release();
|
||||
|
||||
int setStatusCallback(JNIEnv *env, jobject status_callback_obj);
|
||||
int setButtonCallback(JNIEnv *env, jobject button_callback_obj);
|
||||
|
||||
char *getSupportedSize();
|
||||
int setPreviewSize(int width, int height, int min_fps, int max_fps, int mode, float bandwidth = DEFAULT_BANDWIDTH);
|
||||
int setPreviewDisplay(ANativeWindow *preview_window);
|
||||
int setFrameCallback(JNIEnv *env, jobject frame_callback_obj, int pixel_format);
|
||||
int startPreview();
|
||||
int stopPreview();
|
||||
int setCaptureDisplay(ANativeWindow *capture_window);
|
||||
|
||||
int getCtrlSupports(uint64_t *supports);
|
||||
int getProcSupports(uint64_t *supports);
|
||||
|
||||
int updateScanningModeLimit(int &min, int &max, int &def);
|
||||
int setScanningMode(int mode);
|
||||
int getScanningMode();
|
||||
|
||||
int updateExposureModeLimit(int &min, int &max, int &def);
|
||||
int setExposureMode(int mode);
|
||||
int getExposureMode();
|
||||
|
||||
int updateExposurePriorityLimit(int &min, int &max, int &def);
|
||||
int setExposurePriority(int priority);
|
||||
int getExposurePriority();
|
||||
|
||||
int updateExposureLimit(int &min, int &max, int &def);
|
||||
int setExposure(int ae_abs);
|
||||
int getExposure();
|
||||
|
||||
int updateExposureRelLimit(int &min, int &max, int &def);
|
||||
int setExposureRel(int ae_rel);
|
||||
int getExposureRel();
|
||||
|
||||
int updateAutoFocusLimit(int &min, int &max, int &def);
|
||||
int setAutoFocus(bool autoFocus);
|
||||
bool getAutoFocus();
|
||||
|
||||
int updateFocusLimit(int &min, int &max, int &def);
|
||||
int setFocus(int focus);
|
||||
int getFocus();
|
||||
|
||||
int updateFocusRelLimit(int &min, int &max, int &def);
|
||||
int setFocusRel(int focus);
|
||||
int getFocusRel();
|
||||
|
||||
/* int updateFocusSimpleLimit(int &min, int &max, int &def);
|
||||
int setFocusSimple(int focus);
|
||||
int getFocusSimple(); */
|
||||
|
||||
int updateIrisLimit(int &min, int &max, int &def);
|
||||
int setIris(int iris);
|
||||
int getIris();
|
||||
|
||||
int updateIrisRelLimit(int &min, int &max, int &def);
|
||||
int setIrisRel(int iris);
|
||||
int getIrisRel();
|
||||
|
||||
int updatePanLimit(int &min, int &max, int &def);
|
||||
int setPan(int pan);
|
||||
int getPan();
|
||||
|
||||
int updateTiltLimit(int &min, int &max, int &def);
|
||||
int setTilt(int tilt);
|
||||
int getTilt();
|
||||
|
||||
int updateRollLimit(int &min, int &max, int &def);
|
||||
int setRoll(int roll);
|
||||
int getRoll();
|
||||
|
||||
int updatePanRelLimit(int &min, int &max, int &def);
|
||||
int setPanRel(int pan_rel);
|
||||
int getPanRel();
|
||||
|
||||
int updateTiltRelLimit(int &min, int &max, int &def);
|
||||
int setTiltRel(int tilt_rel);
|
||||
int getTiltRel();
|
||||
|
||||
int updateRollRelLimit(int &min, int &max, int &def);
|
||||
int setRollRel(int roll_rel);
|
||||
int getRollRel();
|
||||
|
||||
int updatePrivacyLimit(int &min, int &max, int &def);
|
||||
int setPrivacy(int privacy);
|
||||
int getPrivacy();
|
||||
|
||||
int updateAutoWhiteBlanceLimit(int &min, int &max, int &def);
|
||||
int setAutoWhiteBlance(bool autoWhiteBlance);
|
||||
bool getAutoWhiteBlance();
|
||||
|
||||
int updateAutoWhiteBlanceCompoLimit(int &min, int &max, int &def);
|
||||
int setAutoWhiteBlanceCompo(bool autoWhiteBlanceCompo);
|
||||
bool getAutoWhiteBlanceCompo();
|
||||
|
||||
int updateWhiteBlanceLimit(int &min, int &max, int &def);
|
||||
int setWhiteBlance(int temp);
|
||||
int getWhiteBlance();
|
||||
|
||||
int updateWhiteBlanceCompoLimit(int &min, int &max, int &def);
|
||||
int setWhiteBlanceCompo(int white_blance_compo);
|
||||
int getWhiteBlanceCompo();
|
||||
|
||||
int updateBacklightCompLimit(int &min, int &max, int &def);
|
||||
int setBacklightComp(int backlight);
|
||||
int getBacklightComp();
|
||||
|
||||
int updateBrightnessLimit(int &min, int &max, int &def);
|
||||
int setBrightness(int brightness);
|
||||
int getBrightness();
|
||||
|
||||
int updateContrastLimit(int &min, int &max, int &def);
|
||||
int setContrast(uint16_t contrast);
|
||||
int getContrast();
|
||||
|
||||
int updateAutoContrastLimit(int &min, int &max, int &def);
|
||||
int setAutoContrast(bool autoFocus);
|
||||
bool getAutoContrast();
|
||||
|
||||
int updateSharpnessLimit(int &min, int &max, int &def);
|
||||
int setSharpness(int sharpness);
|
||||
int getSharpness();
|
||||
|
||||
int updateGainLimit(int &min, int &max, int &def);
|
||||
int setGain(int gain);
|
||||
int getGain();
|
||||
|
||||
int updateGammaLimit(int &min, int &max, int &def);
|
||||
int setGamma(int gamma);
|
||||
int getGamma();
|
||||
|
||||
int updateSaturationLimit(int &min, int &max, int &def);
|
||||
int setSaturation(int saturation);
|
||||
int getSaturation();
|
||||
|
||||
int updateHueLimit(int &min, int &max, int &def);
|
||||
int setHue(int hue);
|
||||
int getHue();
|
||||
|
||||
int updateAutoHueLimit(int &min, int &max, int &def);
|
||||
int setAutoHue(bool autoFocus);
|
||||
bool getAutoHue();
|
||||
|
||||
int updatePowerlineFrequencyLimit(int &min, int &max, int &def);
|
||||
int setPowerlineFrequency(int frequency);
|
||||
int getPowerlineFrequency();
|
||||
|
||||
int updateZoomLimit(int &min, int &max, int &def);
|
||||
int setZoom(int zoom);
|
||||
int getZoom();
|
||||
|
||||
int updateZoomRelLimit(int &min, int &max, int &def);
|
||||
int setZoomRel(int zoom);
|
||||
int getZoomRel();
|
||||
|
||||
int updateDigitalMultiplierLimit(int &min, int &max, int &def);
|
||||
int setDigitalMultiplier(int multiplier);
|
||||
int getDigitalMultiplier();
|
||||
|
||||
int updateDigitalMultiplierLimitLimit(int &min, int &max, int &def);
|
||||
int setDigitalMultiplierLimit(int multiplier_limit);
|
||||
int getDigitalMultiplierLimit();
|
||||
|
||||
int updateAnalogVideoStandardLimit(int &min, int &max, int &def);
|
||||
int setAnalogVideoStandard(int standard);
|
||||
int getAnalogVideoStandard();
|
||||
|
||||
int updateAnalogVideoLockStateLimit(int &min, int &max, int &def);
|
||||
int setAnalogVideoLockState(int status);
|
||||
int getAnalogVideoLockState();
|
||||
};
|
||||
|
||||
#endif /* UVCCAMERA_H_ */
|
||||
+876
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: UVCPreview.cpp
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <linux/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if 1 // set 1 if you don't need debug log
|
||||
#ifndef LOG_NDEBUG
|
||||
#define LOG_NDEBUG // w/o LOGV/LOGD/MARK
|
||||
#endif
|
||||
#undef USE_LOGALL
|
||||
#else
|
||||
#define USE_LOGALL
|
||||
#undef LOG_NDEBUG
|
||||
// #undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include "utilbase.h"
|
||||
#include "UVCPreview.h"
|
||||
#include "libuvc_internal.h"
|
||||
|
||||
#define LOCAL_DEBUG 0
|
||||
#define MAX_FRAME 4
|
||||
#define PREVIEW_PIXEL_BYTES 4 // RGBA/RGBX
|
||||
#define FRAME_POOL_SZ MAX_FRAME + 2
|
||||
|
||||
UVCPreview::UVCPreview(uvc_device_handle_t *devh)
|
||||
: mPreviewWindow(NULL),
|
||||
mCaptureWindow(NULL),
|
||||
mDeviceHandle(devh),
|
||||
requestWidth(DEFAULT_PREVIEW_WIDTH),
|
||||
requestHeight(DEFAULT_PREVIEW_HEIGHT),
|
||||
requestMinFps(DEFAULT_PREVIEW_FPS_MIN),
|
||||
requestMaxFps(DEFAULT_PREVIEW_FPS_MAX),
|
||||
requestMode(DEFAULT_PREVIEW_MODE),
|
||||
requestBandwidth(DEFAULT_BANDWIDTH),
|
||||
frameWidth(DEFAULT_PREVIEW_WIDTH),
|
||||
frameHeight(DEFAULT_PREVIEW_HEIGHT),
|
||||
frameBytes(DEFAULT_PREVIEW_WIDTH * DEFAULT_PREVIEW_HEIGHT * 2), // YUYV
|
||||
frameMode(0),
|
||||
previewBytes(DEFAULT_PREVIEW_WIDTH * DEFAULT_PREVIEW_HEIGHT * PREVIEW_PIXEL_BYTES),
|
||||
previewFormat(WINDOW_FORMAT_RGBA_8888),
|
||||
mIsRunning(false),
|
||||
mIsCapturing(false),
|
||||
captureQueu(NULL),
|
||||
mFrameCallbackObj(NULL),
|
||||
mFrameCallbackFunc(NULL),
|
||||
callbackPixelBytes(2) {
|
||||
|
||||
ENTER();
|
||||
pthread_cond_init(&preview_sync, NULL);
|
||||
pthread_mutex_init(&preview_mutex, NULL);
|
||||
//
|
||||
pthread_cond_init(&capture_sync, NULL);
|
||||
pthread_mutex_init(&capture_mutex, NULL);
|
||||
//
|
||||
pthread_mutex_init(&pool_mutex, NULL);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
UVCPreview::~UVCPreview() {
|
||||
|
||||
ENTER();
|
||||
if (mPreviewWindow)
|
||||
ANativeWindow_release(mPreviewWindow);
|
||||
mPreviewWindow = NULL;
|
||||
if (mCaptureWindow)
|
||||
ANativeWindow_release(mCaptureWindow);
|
||||
mCaptureWindow = NULL;
|
||||
clearPreviewFrame();
|
||||
clearCaptureFrame();
|
||||
clear_pool();
|
||||
pthread_mutex_destroy(&preview_mutex);
|
||||
pthread_cond_destroy(&preview_sync);
|
||||
pthread_mutex_destroy(&capture_mutex);
|
||||
pthread_cond_destroy(&capture_sync);
|
||||
pthread_mutex_destroy(&pool_mutex);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
/**
|
||||
* get uvc_frame_t from frame pool
|
||||
* if pool is empty, create new frame
|
||||
* this function does not confirm the frame size
|
||||
* and you may need to confirm the size
|
||||
*/
|
||||
uvc_frame_t *UVCPreview::get_frame(size_t data_bytes) {
|
||||
uvc_frame_t *frame = NULL;
|
||||
pthread_mutex_lock(&pool_mutex);
|
||||
{
|
||||
if (!mFramePool.isEmpty()) {
|
||||
frame = mFramePool.last();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&pool_mutex);
|
||||
if UNLIKELY(!frame) {
|
||||
LOGW("allocate new frame");
|
||||
frame = uvc_allocate_frame(data_bytes);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
void UVCPreview::recycle_frame(uvc_frame_t *frame) {
|
||||
pthread_mutex_lock(&pool_mutex);
|
||||
if (LIKELY(mFramePool.size() < FRAME_POOL_SZ)) {
|
||||
mFramePool.put(frame);
|
||||
frame = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&pool_mutex);
|
||||
if (UNLIKELY(frame)) {
|
||||
uvc_free_frame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UVCPreview::init_pool(size_t data_bytes) {
|
||||
ENTER();
|
||||
|
||||
clear_pool();
|
||||
pthread_mutex_lock(&pool_mutex);
|
||||
{
|
||||
for (int i = 0; i < FRAME_POOL_SZ; i++) {
|
||||
mFramePool.put(uvc_allocate_frame(data_bytes));
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&pool_mutex);
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
void UVCPreview::clear_pool() {
|
||||
ENTER();
|
||||
|
||||
pthread_mutex_lock(&pool_mutex);
|
||||
{
|
||||
const int n = mFramePool.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
uvc_free_frame(mFramePool[i]);
|
||||
}
|
||||
mFramePool.clear();
|
||||
}
|
||||
pthread_mutex_unlock(&pool_mutex);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
inline const bool UVCPreview::isRunning() const {return mIsRunning; }
|
||||
|
||||
int UVCPreview::setPreviewSize(int width, int height, int min_fps, int max_fps, int mode, float bandwidth) {
|
||||
ENTER();
|
||||
|
||||
int result = 0;
|
||||
if ((requestWidth != width) || (requestHeight != height) || (requestMode != mode)) {
|
||||
requestWidth = width;
|
||||
requestHeight = height;
|
||||
requestMinFps = min_fps;
|
||||
requestMaxFps = max_fps;
|
||||
requestMode = mode;
|
||||
requestBandwidth = bandwidth;
|
||||
|
||||
uvc_stream_ctrl_t ctrl;
|
||||
result = uvc_get_stream_ctrl_format_size_fps(mDeviceHandle, &ctrl,
|
||||
!requestMode ? UVC_FRAME_FORMAT_YUYV : UVC_FRAME_FORMAT_MJPEG,
|
||||
requestWidth, requestHeight, requestMinFps, requestMaxFps);
|
||||
}
|
||||
|
||||
RETURN(result, int);
|
||||
}
|
||||
|
||||
int UVCPreview::setPreviewDisplay(ANativeWindow *preview_window) {
|
||||
ENTER();
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
if (mPreviewWindow != preview_window) {
|
||||
if (mPreviewWindow)
|
||||
ANativeWindow_release(mPreviewWindow);
|
||||
mPreviewWindow = preview_window;
|
||||
if (LIKELY(mPreviewWindow)) {
|
||||
ANativeWindow_setBuffersGeometry(mPreviewWindow,
|
||||
frameWidth, frameHeight, previewFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
int UVCPreview::setFrameCallback(JNIEnv *env, jobject frame_callback_obj, int pixel_format) {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
{
|
||||
if (isRunning() && isCapturing()) {
|
||||
mIsCapturing = false;
|
||||
if (mFrameCallbackObj) {
|
||||
pthread_cond_signal(&capture_sync);
|
||||
pthread_cond_wait(&capture_sync, &capture_mutex); // wait finishing capturing
|
||||
}
|
||||
}
|
||||
if (!env->IsSameObject(mFrameCallbackObj, frame_callback_obj)) {
|
||||
iframecallback_fields.onFrame = NULL;
|
||||
if (mFrameCallbackObj) {
|
||||
env->DeleteGlobalRef(mFrameCallbackObj);
|
||||
}
|
||||
mFrameCallbackObj = frame_callback_obj;
|
||||
if (frame_callback_obj) {
|
||||
// get method IDs of Java object for callback
|
||||
jclass clazz = env->GetObjectClass(frame_callback_obj);
|
||||
if (LIKELY(clazz)) {
|
||||
iframecallback_fields.onFrame = env->GetMethodID(clazz,
|
||||
"onFrame", "(Ljava/nio/ByteBuffer;)V");
|
||||
} else {
|
||||
LOGW("failed to get object class");
|
||||
}
|
||||
env->ExceptionClear();
|
||||
if (!iframecallback_fields.onFrame) {
|
||||
LOGE("Can't find IFrameCallback#onFrame");
|
||||
env->DeleteGlobalRef(frame_callback_obj);
|
||||
mFrameCallbackObj = frame_callback_obj = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frame_callback_obj) {
|
||||
mPixelFormat = pixel_format;
|
||||
callbackPixelFormatChanged();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
void UVCPreview::callbackPixelFormatChanged() {
|
||||
mFrameCallbackFunc = NULL;
|
||||
const size_t sz = requestWidth * requestHeight;
|
||||
switch (mPixelFormat) {
|
||||
case PIXEL_FORMAT_RAW:
|
||||
LOGI("PIXEL_FORMAT_RAW:");
|
||||
callbackPixelBytes = sz * 2;
|
||||
break;
|
||||
case PIXEL_FORMAT_YUV:
|
||||
LOGI("PIXEL_FORMAT_YUV:");
|
||||
callbackPixelBytes = sz * 2;
|
||||
break;
|
||||
case PIXEL_FORMAT_RGB565:
|
||||
LOGI("PIXEL_FORMAT_RGB565:");
|
||||
mFrameCallbackFunc = uvc_any2rgb565;
|
||||
callbackPixelBytes = sz * 2;
|
||||
break;
|
||||
case PIXEL_FORMAT_RGBX:
|
||||
LOGI("PIXEL_FORMAT_RGBX:");
|
||||
mFrameCallbackFunc = uvc_any2rgbx;
|
||||
callbackPixelBytes = sz * 4;
|
||||
break;
|
||||
case PIXEL_FORMAT_YUV20SP:
|
||||
LOGI("PIXEL_FORMAT_YUV20SP:");
|
||||
mFrameCallbackFunc = uvc_yuyv2iyuv420SP;
|
||||
callbackPixelBytes = (sz * 3) / 2;
|
||||
break;
|
||||
case PIXEL_FORMAT_NV21:
|
||||
LOGI("PIXEL_FORMAT_NV21:");
|
||||
mFrameCallbackFunc = uvc_yuyv2yuv420SP;
|
||||
callbackPixelBytes = (sz * 3) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UVCPreview::clearDisplay() {
|
||||
ENTER();
|
||||
|
||||
ANativeWindow_Buffer buffer;
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
{
|
||||
if (LIKELY(mCaptureWindow)) {
|
||||
if (LIKELY(ANativeWindow_lock(mCaptureWindow, &buffer, NULL) == 0)) {
|
||||
uint8_t *dest = (uint8_t *)buffer.bits;
|
||||
const size_t bytes = buffer.width * PREVIEW_PIXEL_BYTES;
|
||||
const int stride = buffer.stride * PREVIEW_PIXEL_BYTES;
|
||||
for (int i = 0; i < buffer.height; i++) {
|
||||
memset(dest, 0, bytes);
|
||||
dest += stride;
|
||||
}
|
||||
ANativeWindow_unlockAndPost(mCaptureWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
if (LIKELY(mPreviewWindow)) {
|
||||
if (LIKELY(ANativeWindow_lock(mPreviewWindow, &buffer, NULL) == 0)) {
|
||||
uint8_t *dest = (uint8_t *)buffer.bits;
|
||||
const size_t bytes = buffer.width * PREVIEW_PIXEL_BYTES;
|
||||
const int stride = buffer.stride * PREVIEW_PIXEL_BYTES;
|
||||
for (int i = 0; i < buffer.height; i++) {
|
||||
memset(dest, 0, bytes);
|
||||
dest += stride;
|
||||
}
|
||||
ANativeWindow_unlockAndPost(mPreviewWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
int UVCPreview::startPreview() {
|
||||
ENTER();
|
||||
|
||||
int result = EXIT_FAILURE;
|
||||
if (!isRunning()) {
|
||||
mIsRunning = true;
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
if (LIKELY(mPreviewWindow)) {
|
||||
result = pthread_create(&preview_thread, NULL, preview_thread_func, (void *)this);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
if (UNLIKELY(result != EXIT_SUCCESS)) {
|
||||
LOGW("UVCCamera::window does not exist/already running/could not create thread etc.");
|
||||
mIsRunning = false;
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
pthread_cond_signal(&preview_sync);
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
}
|
||||
}
|
||||
RETURN(result, int);
|
||||
}
|
||||
|
||||
int UVCPreview::stopPreview() {
|
||||
ENTER();
|
||||
bool b = isRunning();
|
||||
if (LIKELY(b)) {
|
||||
mIsRunning = false;
|
||||
pthread_cond_signal(&preview_sync);
|
||||
pthread_cond_signal(&capture_sync);
|
||||
if (pthread_join(capture_thread, NULL) != EXIT_SUCCESS) {
|
||||
LOGW("UVCPreview::terminate capture thread: pthread_join failed");
|
||||
}
|
||||
if (pthread_join(preview_thread, NULL) != EXIT_SUCCESS) {
|
||||
LOGW("UVCPreview::terminate preview thread: pthread_join failed");
|
||||
}
|
||||
clearDisplay();
|
||||
}
|
||||
clearPreviewFrame();
|
||||
clearCaptureFrame();
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
if (mPreviewWindow) {
|
||||
ANativeWindow_release(mPreviewWindow);
|
||||
mPreviewWindow = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
if (mCaptureWindow) {
|
||||
ANativeWindow_release(mCaptureWindow);
|
||||
mCaptureWindow = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
//**********************************************************************
|
||||
//
|
||||
//**********************************************************************
|
||||
void UVCPreview::uvc_preview_frame_callback(uvc_frame_t *frame, void *vptr_args) {
|
||||
UVCPreview *preview = reinterpret_cast<UVCPreview *>(vptr_args);
|
||||
if UNLIKELY(!preview->isRunning() || !frame || !frame->frame_format || !frame->data || !frame->data_bytes) return;
|
||||
if (UNLIKELY(
|
||||
((frame->frame_format != UVC_FRAME_FORMAT_MJPEG) && (frame->actual_bytes < preview->frameBytes))
|
||||
|| (frame->width != preview->frameWidth) || (frame->height != preview->frameHeight) )) {
|
||||
|
||||
#if LOCAL_DEBUG
|
||||
LOGD("broken frame!:format=%d,actual_bytes=%d/%d(%d,%d/%d,%d)",
|
||||
frame->frame_format, frame->actual_bytes, preview->frameBytes,
|
||||
frame->width, frame->height, preview->frameWidth, preview->frameHeight);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (LIKELY(preview->isRunning())) {
|
||||
uvc_frame_t *copy = preview->get_frame(frame->data_bytes);
|
||||
if (UNLIKELY(!copy)) {
|
||||
#if LOCAL_DEBUG
|
||||
LOGE("uvc_callback:unable to allocate duplicate frame!");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
uvc_error_t ret = uvc_duplicate_frame(frame, copy);
|
||||
if (UNLIKELY(ret)) {
|
||||
preview->recycle_frame(copy);
|
||||
return;
|
||||
}
|
||||
preview->addPreviewFrame(copy);
|
||||
}
|
||||
}
|
||||
|
||||
void UVCPreview::addPreviewFrame(uvc_frame_t *frame) {
|
||||
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
if (isRunning() && (previewFrames.size() < MAX_FRAME)) {
|
||||
previewFrames.put(frame);
|
||||
frame = NULL;
|
||||
pthread_cond_signal(&preview_sync);
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
if (frame) {
|
||||
recycle_frame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
uvc_frame_t *UVCPreview::waitPreviewFrame() {
|
||||
uvc_frame_t *frame = NULL;
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
if (!previewFrames.size()) {
|
||||
pthread_cond_wait(&preview_sync, &preview_mutex);
|
||||
}
|
||||
if (LIKELY(isRunning() && previewFrames.size() > 0)) {
|
||||
frame = previewFrames.remove(0);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
return frame;
|
||||
}
|
||||
|
||||
void UVCPreview::clearPreviewFrame() {
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
for (int i = 0; i < previewFrames.size(); i++)
|
||||
recycle_frame(previewFrames[i]);
|
||||
previewFrames.clear();
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
}
|
||||
|
||||
void *UVCPreview::preview_thread_func(void *vptr_args) {
|
||||
int result;
|
||||
|
||||
ENTER();
|
||||
UVCPreview *preview = reinterpret_cast<UVCPreview *>(vptr_args);
|
||||
if (LIKELY(preview)) {
|
||||
uvc_stream_ctrl_t ctrl;
|
||||
result = preview->prepare_preview(&ctrl);
|
||||
if (LIKELY(!result)) {
|
||||
preview->do_preview(&ctrl);
|
||||
}
|
||||
}
|
||||
PRE_EXIT();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int UVCPreview::prepare_preview(uvc_stream_ctrl_t *ctrl) {
|
||||
uvc_error_t result;
|
||||
|
||||
ENTER();
|
||||
result = uvc_get_stream_ctrl_format_size_fps(mDeviceHandle, ctrl,
|
||||
!requestMode ? UVC_FRAME_FORMAT_YUYV : UVC_FRAME_FORMAT_MJPEG,
|
||||
requestWidth, requestHeight, requestMinFps, requestMaxFps
|
||||
);
|
||||
if (LIKELY(!result)) {
|
||||
#if LOCAL_DEBUG
|
||||
uvc_print_stream_ctrl(ctrl, stderr);
|
||||
#endif
|
||||
uvc_frame_desc_t *frame_desc;
|
||||
result = uvc_get_frame_desc(mDeviceHandle, ctrl, &frame_desc);
|
||||
if (LIKELY(!result)) {
|
||||
frameWidth = frame_desc->wWidth;
|
||||
frameHeight = frame_desc->wHeight;
|
||||
LOGI("frameSize=(%d,%d)@%s", frameWidth, frameHeight, (!requestMode ? "YUYV" : "MJPEG"));
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
if (LIKELY(mPreviewWindow)) {
|
||||
ANativeWindow_setBuffersGeometry(mPreviewWindow,
|
||||
frameWidth, frameHeight, previewFormat);
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
} else {
|
||||
frameWidth = requestWidth;
|
||||
frameHeight = requestHeight;
|
||||
}
|
||||
frameMode = requestMode;
|
||||
frameBytes = frameWidth * frameHeight * (!requestMode ? 2 : 4);
|
||||
previewBytes = frameWidth * frameHeight * PREVIEW_PIXEL_BYTES;
|
||||
} else {
|
||||
LOGE("could not negotiate with camera:err=%d", result);
|
||||
}
|
||||
RETURN(result, int);
|
||||
}
|
||||
|
||||
void UVCPreview::do_preview(uvc_stream_ctrl_t *ctrl) {
|
||||
ENTER();
|
||||
|
||||
uvc_frame_t *frame = NULL;
|
||||
uvc_frame_t *frame_mjpeg = NULL;
|
||||
uvc_error_t result = uvc_start_streaming_bandwidth(
|
||||
mDeviceHandle, ctrl, uvc_preview_frame_callback, (void *)this, requestBandwidth, 0);
|
||||
|
||||
if (LIKELY(!result)) {
|
||||
clearPreviewFrame();
|
||||
pthread_create(&capture_thread, NULL, capture_thread_func, (void *)this);
|
||||
|
||||
#if LOCAL_DEBUG
|
||||
LOGI("Streaming...");
|
||||
#endif
|
||||
if (frameMode) {
|
||||
// MJPEG mode
|
||||
for ( ; LIKELY(isRunning()) ; ) {
|
||||
frame_mjpeg = waitPreviewFrame();
|
||||
if (LIKELY(frame_mjpeg)) {
|
||||
frame = get_frame(frame_mjpeg->width * frame_mjpeg->height * 2);
|
||||
result = uvc_mjpeg2yuyv(frame_mjpeg, frame); // MJPEG => yuyv
|
||||
recycle_frame(frame_mjpeg);
|
||||
if (LIKELY(!result)) {
|
||||
frame = draw_preview_one(frame, &mPreviewWindow, uvc_any2rgbx, 4);
|
||||
addCaptureFrame(frame);
|
||||
} else {
|
||||
recycle_frame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// yuvyv mode
|
||||
for ( ; LIKELY(isRunning()) ; ) {
|
||||
frame = waitPreviewFrame();
|
||||
if (LIKELY(frame)) {
|
||||
frame = draw_preview_one(frame, &mPreviewWindow, uvc_any2rgbx, 4);
|
||||
addCaptureFrame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_cond_signal(&capture_sync);
|
||||
#if LOCAL_DEBUG
|
||||
LOGI("preview_thread_func:wait for all callbacks complete");
|
||||
#endif
|
||||
uvc_stop_streaming(mDeviceHandle);
|
||||
#if LOCAL_DEBUG
|
||||
LOGI("Streaming finished");
|
||||
#endif
|
||||
} else {
|
||||
uvc_perror(result, "failed start_streaming");
|
||||
}
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
static void copyFrame(const uint8_t *src, uint8_t *dest, const int width, int height, const int stride_src, const int stride_dest) {
|
||||
const int h8 = height % 8;
|
||||
for (int i = 0; i < h8; i++) {
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
}
|
||||
for (int i = 0; i < height; i += 8) {
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
memcpy(dest, src, width);
|
||||
dest += stride_dest; src += stride_src;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// transfer specific frame data to the Surface(ANativeWindow)
|
||||
int copyToSurface(uvc_frame_t *frame, ANativeWindow **window) {
|
||||
// ENTER();
|
||||
int result = 0;
|
||||
if (LIKELY(*window)) {
|
||||
ANativeWindow_Buffer buffer;
|
||||
if (LIKELY(ANativeWindow_lock(*window, &buffer, NULL) == 0)) {
|
||||
// source = frame data
|
||||
const uint8_t *src = (uint8_t *)frame->data;
|
||||
const int src_w = frame->width * PREVIEW_PIXEL_BYTES;
|
||||
const int src_step = frame->width * PREVIEW_PIXEL_BYTES;
|
||||
// destination = Surface(ANativeWindow)
|
||||
uint8_t *dest = (uint8_t *)buffer.bits;
|
||||
const int dest_w = buffer.width * PREVIEW_PIXEL_BYTES;
|
||||
const int dest_step = buffer.stride * PREVIEW_PIXEL_BYTES;
|
||||
// use lower transfer bytes
|
||||
const int w = src_w < dest_w ? src_w : dest_w;
|
||||
// use lower height
|
||||
const int h = frame->height < buffer.height ? frame->height : buffer.height;
|
||||
// transfer from frame data to the Surface
|
||||
copyFrame(src, dest, w, h, src_step, dest_step);
|
||||
ANativeWindow_unlockAndPost(*window);
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
} else {
|
||||
result = -1;
|
||||
}
|
||||
return result; //RETURN(result, int);
|
||||
}
|
||||
|
||||
// changed to return original frame instead of returning converted frame even if convert_func is not null.
|
||||
uvc_frame_t *UVCPreview::draw_preview_one(uvc_frame_t *frame, ANativeWindow **window, convFunc_t convert_func, int pixcelBytes) {
|
||||
// ENTER();
|
||||
|
||||
int b = 0;
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
{
|
||||
b = *window != NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
if (LIKELY(b)) {
|
||||
uvc_frame_t *converted;
|
||||
if (convert_func) {
|
||||
converted = get_frame(frame->width * frame->height * pixcelBytes);
|
||||
if LIKELY(converted) {
|
||||
b = convert_func(frame, converted);
|
||||
if (!b) {
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
copyToSurface(converted, window);
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
} else {
|
||||
LOGE("failed converting");
|
||||
}
|
||||
recycle_frame(converted);
|
||||
}
|
||||
} else {
|
||||
pthread_mutex_lock(&preview_mutex);
|
||||
copyToSurface(frame, window);
|
||||
pthread_mutex_unlock(&preview_mutex);
|
||||
}
|
||||
}
|
||||
return frame; //RETURN(frame, uvc_frame_t *);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
inline const bool UVCPreview::isCapturing() const { return mIsCapturing; }
|
||||
|
||||
int UVCPreview::setCaptureDisplay(ANativeWindow *capture_window) {
|
||||
ENTER();
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
{
|
||||
if (isRunning() && isCapturing()) {
|
||||
mIsCapturing = false;
|
||||
if (mCaptureWindow) {
|
||||
pthread_cond_signal(&capture_sync);
|
||||
pthread_cond_wait(&capture_sync, &capture_mutex); // wait finishing capturing
|
||||
}
|
||||
}
|
||||
if (mCaptureWindow != capture_window) {
|
||||
// release current Surface if already assigned.
|
||||
if (UNLIKELY(mCaptureWindow))
|
||||
ANativeWindow_release(mCaptureWindow);
|
||||
mCaptureWindow = capture_window;
|
||||
// if you use Surface came from MediaCodec#createInputSurface
|
||||
// you could not change window format at least when you use
|
||||
// ANativeWindow_lock / ANativeWindow_unlockAndPost
|
||||
// to write frame data to the Surface...
|
||||
// So we need check here.
|
||||
if (mCaptureWindow) {
|
||||
int32_t window_format = ANativeWindow_getFormat(mCaptureWindow);
|
||||
if ((window_format != WINDOW_FORMAT_RGB_565)
|
||||
&& (previewFormat == WINDOW_FORMAT_RGB_565)) {
|
||||
LOGE("window format mismatch, cancelled movie capturing.");
|
||||
ANativeWindow_release(mCaptureWindow);
|
||||
mCaptureWindow = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
void UVCPreview::addCaptureFrame(uvc_frame_t *frame) {
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
if (LIKELY(isRunning())) {
|
||||
// keep only latest one
|
||||
if (captureQueu) {
|
||||
recycle_frame(captureQueu);
|
||||
}
|
||||
captureQueu = frame;
|
||||
pthread_cond_broadcast(&capture_sync);
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* get frame data for capturing, if not exist, block and wait
|
||||
*/
|
||||
uvc_frame_t *UVCPreview::waitCaptureFrame() {
|
||||
uvc_frame_t *frame = NULL;
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
{
|
||||
if (!captureQueu) {
|
||||
pthread_cond_wait(&capture_sync, &capture_mutex);
|
||||
}
|
||||
if (LIKELY(isRunning() && captureQueu)) {
|
||||
frame = captureQueu;
|
||||
captureQueu = NULL;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear drame data for capturing
|
||||
*/
|
||||
void UVCPreview::clearCaptureFrame() {
|
||||
pthread_mutex_lock(&capture_mutex);
|
||||
{
|
||||
if (captureQueu)
|
||||
recycle_frame(captureQueu);
|
||||
captureQueu = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&capture_mutex);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
/*
|
||||
* thread function
|
||||
* @param vptr_args pointer to UVCPreview instance
|
||||
*/
|
||||
// static
|
||||
void *UVCPreview::capture_thread_func(void *vptr_args) {
|
||||
int result;
|
||||
|
||||
ENTER();
|
||||
UVCPreview *preview = reinterpret_cast<UVCPreview *>(vptr_args);
|
||||
if (LIKELY(preview)) {
|
||||
JavaVM *vm = getVM();
|
||||
JNIEnv *env;
|
||||
// attach to JavaVM
|
||||
vm->AttachCurrentThread(&env, NULL);
|
||||
preview->do_capture(env); // never return until finish previewing
|
||||
// detach from JavaVM
|
||||
vm->DetachCurrentThread();
|
||||
MARK("DetachCurrentThread");
|
||||
}
|
||||
PRE_EXIT();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* the actual function for capturing
|
||||
*/
|
||||
void UVCPreview::do_capture(JNIEnv *env) {
|
||||
|
||||
ENTER();
|
||||
|
||||
clearCaptureFrame();
|
||||
callbackPixelFormatChanged();
|
||||
for (; isRunning() ;) {
|
||||
mIsCapturing = true;
|
||||
if (mCaptureWindow) {
|
||||
do_capture_surface(env);
|
||||
} else {
|
||||
do_capture_idle_loop(env);
|
||||
}
|
||||
pthread_cond_broadcast(&capture_sync);
|
||||
} // end of for (; isRunning() ;)
|
||||
EXIT();
|
||||
}
|
||||
|
||||
void UVCPreview::do_capture_idle_loop(JNIEnv *env) {
|
||||
ENTER();
|
||||
|
||||
for (; isRunning() && isCapturing() ;) {
|
||||
do_capture_callback(env, waitCaptureFrame());
|
||||
}
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
/**
|
||||
* write frame data to Surface for capturing
|
||||
*/
|
||||
void UVCPreview::do_capture_surface(JNIEnv *env) {
|
||||
ENTER();
|
||||
|
||||
uvc_frame_t *frame = NULL;
|
||||
uvc_frame_t *converted = NULL;
|
||||
char *local_picture_path;
|
||||
|
||||
for (; isRunning() && isCapturing() ;) {
|
||||
frame = waitCaptureFrame();
|
||||
if (LIKELY(frame)) {
|
||||
// frame data is always YUYV format.
|
||||
if LIKELY(isCapturing()) {
|
||||
if (UNLIKELY(!converted)) {
|
||||
converted = get_frame(previewBytes);
|
||||
}
|
||||
if (LIKELY(converted)) {
|
||||
int b = uvc_any2rgbx(frame, converted);
|
||||
if (!b) {
|
||||
if (LIKELY(mCaptureWindow)) {
|
||||
copyToSurface(converted, &mCaptureWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
do_capture_callback(env, frame);
|
||||
}
|
||||
}
|
||||
if (converted) {
|
||||
recycle_frame(converted);
|
||||
}
|
||||
if (mCaptureWindow) {
|
||||
ANativeWindow_release(mCaptureWindow);
|
||||
mCaptureWindow = NULL;
|
||||
}
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
/**
|
||||
* call IFrameCallback#onFrame if needs
|
||||
*/
|
||||
void UVCPreview::do_capture_callback(JNIEnv *env, uvc_frame_t *frame) {
|
||||
ENTER();
|
||||
|
||||
if (LIKELY(frame)) {
|
||||
uvc_frame_t *callback_frame = frame;
|
||||
if (mFrameCallbackObj) {
|
||||
if (mFrameCallbackFunc) {
|
||||
callback_frame = get_frame(callbackPixelBytes);
|
||||
if (LIKELY(callback_frame)) {
|
||||
int b = mFrameCallbackFunc(frame, callback_frame);
|
||||
recycle_frame(frame);
|
||||
if (UNLIKELY(b)) {
|
||||
LOGW("failed to convert for callback frame");
|
||||
goto SKIP;
|
||||
}
|
||||
} else {
|
||||
LOGW("failed to allocate for callback frame");
|
||||
callback_frame = frame;
|
||||
goto SKIP;
|
||||
}
|
||||
}
|
||||
jobject buf = env->NewDirectByteBuffer(callback_frame->data, callbackPixelBytes);
|
||||
env->CallVoidMethod(mFrameCallbackObj, iframecallback_fields.onFrame, buf);
|
||||
env->ExceptionClear();
|
||||
env->DeleteLocalRef(buf);
|
||||
}
|
||||
SKIP:
|
||||
recycle_frame(callback_frame);
|
||||
}
|
||||
EXIT();
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: UVCPreview.h
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#ifndef UVCPREVIEW_H_
|
||||
#define UVCPREVIEW_H_
|
||||
|
||||
#include "libUVCCamera.h"
|
||||
#include <pthread.h>
|
||||
#include <android/native_window.h>
|
||||
#include "objectarray.h"
|
||||
|
||||
#pragma interface
|
||||
|
||||
#define DEFAULT_PREVIEW_WIDTH 640
|
||||
#define DEFAULT_PREVIEW_HEIGHT 480
|
||||
#define DEFAULT_PREVIEW_FPS_MIN 1
|
||||
#define DEFAULT_PREVIEW_FPS_MAX 30
|
||||
#define DEFAULT_PREVIEW_MODE 0
|
||||
#define DEFAULT_BANDWIDTH 1.0f
|
||||
|
||||
typedef uvc_error_t (*convFunc_t)(uvc_frame_t *in, uvc_frame_t *out);
|
||||
|
||||
#define PIXEL_FORMAT_RAW 0 // same as PIXEL_FORMAT_YUV
|
||||
#define PIXEL_FORMAT_YUV 1
|
||||
#define PIXEL_FORMAT_RGB565 2
|
||||
#define PIXEL_FORMAT_RGBX 3
|
||||
#define PIXEL_FORMAT_YUV20SP 4
|
||||
#define PIXEL_FORMAT_NV21 5 // YVU420SemiPlanar
|
||||
|
||||
// for callback to Java object
|
||||
typedef struct {
|
||||
jmethodID onFrame;
|
||||
} Fields_iframecallback;
|
||||
|
||||
class UVCPreview {
|
||||
private:
|
||||
uvc_device_handle_t *mDeviceHandle;
|
||||
ANativeWindow *mPreviewWindow;
|
||||
volatile bool mIsRunning;
|
||||
int requestWidth, requestHeight, requestMode;
|
||||
int requestMinFps, requestMaxFps;
|
||||
float requestBandwidth;
|
||||
int frameWidth, frameHeight;
|
||||
int frameMode;
|
||||
size_t frameBytes;
|
||||
pthread_t preview_thread;
|
||||
pthread_mutex_t preview_mutex;
|
||||
pthread_cond_t preview_sync;
|
||||
ObjectArray<uvc_frame_t *> previewFrames;
|
||||
int previewFormat;
|
||||
size_t previewBytes;
|
||||
//
|
||||
volatile bool mIsCapturing;
|
||||
ANativeWindow *mCaptureWindow;
|
||||
pthread_t capture_thread;
|
||||
pthread_mutex_t capture_mutex;
|
||||
pthread_cond_t capture_sync;
|
||||
uvc_frame_t *captureQueu; // keep latest frame
|
||||
jobject mFrameCallbackObj;
|
||||
convFunc_t mFrameCallbackFunc;
|
||||
Fields_iframecallback iframecallback_fields;
|
||||
int mPixelFormat;
|
||||
size_t callbackPixelBytes;
|
||||
// improve performance by reducing memory allocation
|
||||
pthread_mutex_t pool_mutex;
|
||||
ObjectArray<uvc_frame_t *> mFramePool;
|
||||
uvc_frame_t *get_frame(size_t data_bytes);
|
||||
void recycle_frame(uvc_frame_t *frame);
|
||||
void init_pool(size_t data_bytes);
|
||||
void clear_pool();
|
||||
//
|
||||
void clearDisplay();
|
||||
static void uvc_preview_frame_callback(uvc_frame_t *frame, void *vptr_args);
|
||||
void addPreviewFrame(uvc_frame_t *frame);
|
||||
uvc_frame_t *waitPreviewFrame();
|
||||
void clearPreviewFrame();
|
||||
static void *preview_thread_func(void *vptr_args);
|
||||
int prepare_preview(uvc_stream_ctrl_t *ctrl);
|
||||
void do_preview(uvc_stream_ctrl_t *ctrl);
|
||||
uvc_frame_t *draw_preview_one(uvc_frame_t *frame, ANativeWindow **window, convFunc_t func, int pixelBytes);
|
||||
//
|
||||
void addCaptureFrame(uvc_frame_t *frame);
|
||||
uvc_frame_t *waitCaptureFrame();
|
||||
void clearCaptureFrame();
|
||||
static void *capture_thread_func(void *vptr_args);
|
||||
void do_capture(JNIEnv *env);
|
||||
void do_capture_surface(JNIEnv *env);
|
||||
void do_capture_idle_loop(JNIEnv *env);
|
||||
void do_capture_callback(JNIEnv *env, uvc_frame_t *frame);
|
||||
void callbackPixelFormatChanged();
|
||||
public:
|
||||
UVCPreview(uvc_device_handle_t *devh);
|
||||
~UVCPreview();
|
||||
|
||||
inline const bool isRunning() const;
|
||||
int setPreviewSize(int width, int height, int min_fps, int max_fps, int mode, float bandwidth = 1.0f);
|
||||
int setPreviewDisplay(ANativeWindow *preview_window);
|
||||
int setFrameCallback(JNIEnv *env, jobject frame_callback_obj, int pixel_format);
|
||||
int startPreview();
|
||||
int stopPreview();
|
||||
inline const bool isCapturing() const;
|
||||
int setCaptureDisplay(ANativeWindow *capture_window);
|
||||
};
|
||||
|
||||
#endif /* UVCPREVIEW_H_ */
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#include <stdlib.h>
|
||||
#include <linux/time.h>
|
||||
#include <unistd.h>
|
||||
#include "utilbase.h"
|
||||
#include "UVCStatusCallback.h"
|
||||
#include "libuvc_internal.h"
|
||||
|
||||
#define LOCAL_DEBUG 0
|
||||
|
||||
UVCStatusCallback::UVCStatusCallback(uvc_device_handle_t *devh)
|
||||
: mDeviceHandle(devh),
|
||||
mStatusCallbackObj(NULL) {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_init(&status_mutex, NULL);
|
||||
|
||||
uvc_set_status_callback(mDeviceHandle, uvc_status_callback, (void *)this);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
UVCStatusCallback::~UVCStatusCallback() {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_destroy(&status_mutex);
|
||||
EXIT();
|
||||
}
|
||||
|
||||
int UVCStatusCallback::setCallback(JNIEnv *env, jobject status_callback_obj) {
|
||||
|
||||
ENTER();
|
||||
pthread_mutex_lock(&status_mutex);
|
||||
{
|
||||
if (!env->IsSameObject(mStatusCallbackObj, status_callback_obj)) {
|
||||
istatuscallback_fields.onStatus = NULL;
|
||||
if (mStatusCallbackObj) {
|
||||
env->DeleteGlobalRef(mStatusCallbackObj);
|
||||
}
|
||||
mStatusCallbackObj = status_callback_obj;
|
||||
if (status_callback_obj) {
|
||||
// get method IDs of Java object for callback
|
||||
jclass clazz = env->GetObjectClass(status_callback_obj);
|
||||
if (LIKELY(clazz)) {
|
||||
istatuscallback_fields.onStatus = env->GetMethodID(clazz,
|
||||
"onStatus", "(IIIILjava/nio/ByteBuffer;)V");
|
||||
} else {
|
||||
LOGW("failed to get object class");
|
||||
}
|
||||
env->ExceptionClear();
|
||||
if (!istatuscallback_fields.onStatus) {
|
||||
LOGE("Can't find IStatusCallback#onStatus");
|
||||
env->DeleteGlobalRef(status_callback_obj);
|
||||
mStatusCallbackObj = status_callback_obj = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&status_mutex);
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
void UVCStatusCallback::notifyStatusCallback(JNIEnv* env, uvc_status_class status_class, int event, int selector, uvc_status_attribute status_attribute, void *data, size_t data_len) {
|
||||
|
||||
pthread_mutex_lock(&status_mutex);
|
||||
{
|
||||
if (mStatusCallbackObj) {
|
||||
jobject buf = env->NewDirectByteBuffer(data, data_len);
|
||||
env->CallVoidMethod(mStatusCallbackObj, istatuscallback_fields.onStatus, (int)status_class, event, selector, (int)status_attribute, buf);
|
||||
env->ExceptionClear();
|
||||
env->DeleteLocalRef(buf);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&status_mutex);
|
||||
}
|
||||
|
||||
void UVCStatusCallback::uvc_status_callback(uvc_status_class status_class, int event, int selector, uvc_status_attribute status_attribute, void *data, size_t data_len, void *user_ptr) {
|
||||
|
||||
UVCStatusCallback *statusCallback = reinterpret_cast<UVCStatusCallback *>(user_ptr);
|
||||
|
||||
JavaVM *vm = getVM();
|
||||
JNIEnv *env;
|
||||
// attach to JavaVM
|
||||
vm->AttachCurrentThread(&env, NULL);
|
||||
|
||||
statusCallback->notifyStatusCallback(env, status_class, event, selector, status_attribute, data, data_len);
|
||||
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#ifndef UVCSTATUSCALLBACK_H_
|
||||
#define UVCSTATUSCALLBACK_H_
|
||||
|
||||
#include "libUVCCamera.h"
|
||||
#include <pthread.h>
|
||||
#include <android/native_window.h>
|
||||
#include "objectarray.h"
|
||||
|
||||
#pragma interface
|
||||
|
||||
// for callback to Java object
|
||||
typedef struct {
|
||||
jmethodID onStatus;
|
||||
} Fields_istatuscallback;
|
||||
|
||||
class UVCStatusCallback {
|
||||
private:
|
||||
uvc_device_handle_t *mDeviceHandle;
|
||||
pthread_mutex_t status_mutex;
|
||||
jobject mStatusCallbackObj;
|
||||
Fields_istatuscallback istatuscallback_fields;
|
||||
void notifyStatusCallback(JNIEnv *env, uvc_status_class status_class, int event, int selector, uvc_status_attribute status_attribute, void *data, size_t data_len);
|
||||
static void uvc_status_callback(uvc_status_class status_class, int event, int selector, uvc_status_attribute status_attribute, void *data, size_t data_len, void *user_ptr);
|
||||
public:
|
||||
UVCStatusCallback(uvc_device_handle_t *devh);
|
||||
~UVCStatusCallback();
|
||||
|
||||
int setCallback(JNIEnv *env, jobject status_callback_obj);
|
||||
};
|
||||
|
||||
#endif /* UVCSTATUSCALLBACK_H_ */
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: _onload.cpp
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#include "_onload.h"
|
||||
#include "utilbase.h"
|
||||
|
||||
#define LOCAL_DEBUG 0
|
||||
|
||||
extern int register_uvccamera(JNIEnv *env);
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
#if LOCAL_DEBUG
|
||||
LOGD("JNI_OnLoad");
|
||||
#endif
|
||||
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
// register native methods
|
||||
int result = register_uvccamera(env);
|
||||
setVM(vm);
|
||||
#if LOCAL_DEBUG
|
||||
LOGD("JNI_OnLoad:finshed:result=%d", result);
|
||||
#endif
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: _onload.h
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#ifndef ONLOAD_H_
|
||||
#define ONLOAD_H_
|
||||
|
||||
#pragma interface
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ONLOAD_H_ */
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: libUVCCamera.h
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#ifndef LIBUVCCAMERA_H_
|
||||
#define LIBUVCCAMERA_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include "libusb.h"
|
||||
#include "libuvc.h"
|
||||
#include "utilbase.h"
|
||||
|
||||
#endif /* LIBUVCCAMERA_H_ */
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* UVCCamera
|
||||
* library and sample to access to UVC web camera on non-rooted Android device
|
||||
*
|
||||
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
|
||||
*
|
||||
* File name: objectarray.h
|
||||
*
|
||||
* 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 jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
|
||||
*/
|
||||
|
||||
#ifndef OBJECTARRAY_H_
|
||||
#define OBJECTARRAY_H_
|
||||
|
||||
#include "utilbase.h"
|
||||
|
||||
template <class T>
|
||||
class ObjectArray {
|
||||
private:
|
||||
T *m_elements;
|
||||
const int min_size;
|
||||
int m_max_size;
|
||||
int m_size;
|
||||
public:
|
||||
ObjectArray(int initial_capacity = 2)
|
||||
: m_elements(new T[initial_capacity]),
|
||||
m_max_size(initial_capacity),
|
||||
m_size(0),
|
||||
min_size(initial_capacity) {
|
||||
}
|
||||
|
||||
~ObjectArray() { SAFE_DELETE_ARRAY(m_elements); }
|
||||
void size(int new_size) {
|
||||
if (new_size != capacity()) {
|
||||
T *new_elements = new T[new_size];
|
||||
LOG_ASSERT(new_elements, "out of memory:size=%d,capacity=%d", new_size, m_max_size);
|
||||
const int n = (new_size < capacity()) ? new_size : capacity();
|
||||
for (int i = 0; i < n; i++) {
|
||||
new_elements[i] = m_elements[i];
|
||||
}
|
||||
SAFE_DELETE_ARRAY(m_elements);
|
||||
m_elements = new_elements;
|
||||
m_max_size = new_size;
|
||||
m_size = (m_size < new_size) ? m_size : new_size;
|
||||
}
|
||||
}
|
||||
|
||||
inline int size() const { return m_size; }
|
||||
inline bool isEmpty() const { return (m_size < 1); }
|
||||
inline int capacity() const { return m_max_size; }
|
||||
inline T &operator[](int index) { return m_elements[index]; }
|
||||
inline const T &operator[](int index) const { return m_elements[index]; }
|
||||
int put(T object) {
|
||||
if LIKELY(object) {
|
||||
if UNLIKELY(size() >= capacity()) {
|
||||
size(capacity() ? capacity() * 2 : 2);
|
||||
}
|
||||
m_elements[m_size++] = object;
|
||||
}
|
||||
return m_size;
|
||||
}
|
||||
/**
|
||||
* remove T which posisioned on index
|
||||
*/
|
||||
T remove(int index) {
|
||||
T obj = m_elements[index];
|
||||
for (int i = index; i < m_size - 1; i++) {
|
||||
m_elements[i] = m_elements[i+1];
|
||||
}
|
||||
m_size--;
|
||||
return obj;
|
||||
}
|
||||
/**
|
||||
* search the T object and remove if exist
|
||||
*/
|
||||
void removeObject(T object) {
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (m_elements[i] == object) {
|
||||
remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* get last T and remove from this array ¥
|
||||
* this is faster than remove(size()-1)
|
||||
*/
|
||||
inline T last() {
|
||||
if LIKELY(m_size > 0)
|
||||
return m_elements[--m_size];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* search the T object and return it's index
|
||||
* if the T is not in this array, return -1
|
||||
*/
|
||||
int getIndex(const T object) {
|
||||
int result = -1;
|
||||
for (int i = 0; i < size(); i++) {
|
||||
if (m_elements[i] == object) {
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the T array but never delete actual T instance
|
||||
*/
|
||||
inline void clear() {
|
||||
size(min_size);
|
||||
m_size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // OBJECTARRAY_H_
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
//
|
||||
// Created by saki on 15/11/05.
|
||||
//
|
||||
|
||||
#if 1 // set 1 if you don't need debug message
|
||||
#ifndef LOG_NDEBUG
|
||||
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
|
||||
#endif
|
||||
#undef USE_LOGALL
|
||||
#else
|
||||
#define USE_LOGALL
|
||||
#undef LOG_NDEBUG
|
||||
#undef NDEBUG // depends on definition in Android.mk and Application.mk
|
||||
#endif
|
||||
|
||||
#include "utilbase.h"
|
||||
#include "AbstractBufferedPipeline.h"
|
||||
|
||||
/*public*/
|
||||
AbstractBufferedPipeline::AbstractBufferedPipeline(const int &_max_buffer_num, const int &_init_pool_num,
|
||||
const size_t &_default_frame_size, const bool &drop_frames_when_buffer_empty)
|
||||
: IPipeline(_default_frame_size),
|
||||
max_buffer_num(_max_buffer_num),
|
||||
init_pool_num(_init_pool_num),
|
||||
drop_frames(drop_frames_when_buffer_empty),
|
||||
total_frame_num(0)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
/*public*/
|
||||
AbstractBufferedPipeline::~AbstractBufferedPipeline() {
|
||||
ENTER();
|
||||
|
||||
release();
|
||||
setState(PIPELINE_STATE_UNINITIALIZED);
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
/*public*/
|
||||
int AbstractBufferedPipeline::release() {
|
||||
ENTER();
|
||||
|
||||
setState(PIPELINE_STATE_RELEASING);
|
||||
stop();
|
||||
clear_frames();
|
||||
clear_pool();
|
||||
setState(PIPELINE_STATE_UNINITIALIZED);
|
||||
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
int AbstractBufferedPipeline::start() {
|
||||
ENTER();
|
||||
|
||||
int result = EXIT_FAILURE;
|
||||
if (!isRunning()) {
|
||||
mIsRunning = true;
|
||||
setState(PIPELINE_STATE_STARTING);
|
||||
buffer_mutex.lock();
|
||||
{
|
||||
result = pthread_create(&handler_thread, NULL, handler_thread_func, (void *) this);
|
||||
}
|
||||
buffer_mutex.unlock();
|
||||
if (UNLIKELY(result != EXIT_SUCCESS)) {
|
||||
LOGW("AbstractBufferedPipeline::already running/could not create thread etc.");
|
||||
setState(PIPELINE_STATE_INITIALIZED);
|
||||
mIsRunning = false;
|
||||
buffer_mutex.lock();
|
||||
{
|
||||
pool_sync.broadcast();
|
||||
buffer_sync.broadcast();
|
||||
}
|
||||
buffer_mutex.unlock();
|
||||
}
|
||||
}
|
||||
RETURN(result, int);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
int AbstractBufferedPipeline::stop() {
|
||||
ENTER();
|
||||
|
||||
bool b = isRunning();
|
||||
if (LIKELY(b)) {
|
||||
setState(PIPELINE_STATE_STOPPING);
|
||||
mIsRunning = false;
|
||||
pool_sync.broadcast();
|
||||
buffer_sync.broadcast();
|
||||
LOGD("pthread_join:handler_thread");
|
||||
if (pthread_join(handler_thread, NULL) != EXIT_SUCCESS) {
|
||||
LOGW("PublisherPipeline::terminate publisher thread: pthread_join failed");
|
||||
}
|
||||
setState(PIPELINE_STATE_INITIALIZED);
|
||||
LOGD("handler_thread finished");
|
||||
}
|
||||
clear_frames();
|
||||
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
/*public*/
|
||||
int AbstractBufferedPipeline::queueFrame(uvc_frame_t *frame) {
|
||||
ENTER();
|
||||
|
||||
int ret = UVC_ERROR_OTHER;
|
||||
if (LIKELY(frame)) {
|
||||
// get empty frame from frame pool
|
||||
uvc_frame_t *copy = get_frame(frame->data_bytes);
|
||||
if (UNLIKELY(!copy)) {
|
||||
LOGD("buffer pool is empty and exceeds the limit, drop frame");
|
||||
RETURN(UVC_ERROR_NO_MEM, int);
|
||||
}
|
||||
// duplicate frame buffer and pass copy to publisher
|
||||
ret = uvc_duplicate_frame(frame, copy);
|
||||
if (LIKELY(!ret)) {
|
||||
ret = add_frame(copy);
|
||||
} else {
|
||||
LOGW("uvc_duplicate_frame failed:%d", ret);
|
||||
recycle_frame(copy);
|
||||
}
|
||||
}
|
||||
|
||||
RETURN(ret, int);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
//
|
||||
//********************************************************************************
|
||||
/**
|
||||
* get uvc_frame_t from frame pool
|
||||
* if pool is empty, create new frame
|
||||
* this function does not confirm the frame size
|
||||
* and you may need to confirm the size
|
||||
*/
|
||||
uvc_frame_t *AbstractBufferedPipeline::get_frame(const size_t &data_bytes) {
|
||||
uvc_frame_t *frame = NULL;
|
||||
Mutex::Autolock lock(pool_mutex);
|
||||
|
||||
if (UNLIKELY(frame_pool.empty() && (total_frame_num < max_buffer_num))) {
|
||||
uint32_t n = total_frame_num * 2;
|
||||
if (n > max_buffer_num) {
|
||||
n = max_buffer_num;
|
||||
}
|
||||
n -= total_frame_num;
|
||||
if (LIKELY(n > 0)) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
frame = uvc_allocate_frame(data_bytes);
|
||||
total_frame_num++;
|
||||
}
|
||||
LOGW("allocate new frame:%d", total_frame_num);
|
||||
} else {
|
||||
LOGW("number of allocated frame exceeds limit");
|
||||
}
|
||||
}
|
||||
if (UNLIKELY(frame_pool.empty() && !drop_frames)) {
|
||||
// if pool is empty and need to block(avoid dropping frames), wait frame recycling.
|
||||
for (; mIsRunning && frame_pool.empty() ; ) {
|
||||
pool_sync.wait(pool_mutex);
|
||||
}
|
||||
}
|
||||
if (!frame_pool.empty()) {
|
||||
frame = frame_pool.front();
|
||||
frame_pool.pop_front();
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void AbstractBufferedPipeline::recycle_frame(uvc_frame_t *frame) {
|
||||
ENTER();
|
||||
|
||||
if (LIKELY(frame)) {
|
||||
Mutex::Autolock lock(pool_mutex);
|
||||
if (LIKELY(frame_pool.size() < max_buffer_num)) {
|
||||
frame_pool.push_back(frame);
|
||||
frame = NULL;
|
||||
}
|
||||
if (UNLIKELY(frame)) {
|
||||
// if pool overflowed
|
||||
total_frame_num--;
|
||||
uvc_free_frame(frame);
|
||||
}
|
||||
pool_sync.signal();
|
||||
}
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
void AbstractBufferedPipeline::init_pool(const size_t &data_bytes) {
|
||||
ENTER();
|
||||
|
||||
uvc_frame_t *frame = NULL;
|
||||
|
||||
clear_pool();
|
||||
pool_mutex.lock();
|
||||
{
|
||||
|
||||
size_t frame_sz = data_bytes / 4; // expects 25%, this will be able to much lower
|
||||
if (!frame_sz) {
|
||||
frame_sz = DEFAULT_FRAME_SZ;
|
||||
}
|
||||
for (uint32_t i = 0; i < init_pool_num; i++) {
|
||||
frame = uvc_allocate_frame(frame_sz);
|
||||
if (LIKELY(frame)) {
|
||||
frame_pool.push_back(frame);
|
||||
total_frame_num++;
|
||||
} else {
|
||||
LOGW("failed to allocate new frame:%d", total_frame_num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pool_mutex.unlock();
|
||||
|
||||
EXIT();
|
||||
}
|
||||
|
||||
void AbstractBufferedPipeline::clear_pool() {
|
||||
ENTER();
|
||||
|
||||
Mutex::Autolock lock(pool_mutex);
|
||||
|
||||
for (auto iter = frame_pool.begin(); iter != frame_pool.end(); iter++) {
|
||||
total_frame_num--;
|
||||
uvc_free_frame(*iter);
|
||||
}
|
||||
frame_pool.clear();
|
||||
EXIT();
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
//
|
||||
//********************************************************************************
|
||||
|
||||
void AbstractBufferedPipeline::clear_frames() {
|
||||
Mutex::Autolock lock(buffer_mutex);
|
||||
|
||||
for (auto iter = frame_buffers.begin(); iter != frame_buffers.end(); iter++) {
|
||||
recycle_frame(*iter);
|
||||
}
|
||||
frame_buffers.clear();
|
||||
}
|
||||
|
||||
int AbstractBufferedPipeline::add_frame(uvc_frame_t *frame) {
|
||||
ENTER();
|
||||
|
||||
buffer_mutex.lock();
|
||||
{
|
||||
// FIXME as current implementation, transferring frame data on my device is slower than that coming from UVC camera... just drop them now
|
||||
if (frame_buffers.size() > max_buffer_num) {
|
||||
// erase old frames
|
||||
int cnt = 0;
|
||||
for (auto iter = frame_buffers.begin();
|
||||
(iter != frame_buffers.end()) && (cnt < 5); iter++, cnt++) {
|
||||
recycle_frame(*iter);
|
||||
iter = frame_buffers.erase(iter);
|
||||
}
|
||||
LOGW("droped frame data");
|
||||
}
|
||||
if (isRunning() && (frame_buffers.size() < max_buffer_num)) {
|
||||
frame_buffers.push_back(frame);
|
||||
frame = NULL;
|
||||
}
|
||||
buffer_sync.signal();
|
||||
}
|
||||
buffer_mutex.unlock();
|
||||
if (frame) {
|
||||
recycle_frame(frame);
|
||||
}
|
||||
|
||||
RETURN(0, int);
|
||||
}
|
||||
|
||||
uvc_frame_t *AbstractBufferedPipeline::wait_frame() {
|
||||
uvc_frame_t *frame = NULL;
|
||||
|
||||
Mutex::Autolock lock(buffer_mutex);
|
||||
|
||||
if (!frame_buffers.size()) {
|
||||
buffer_sync.wait(buffer_mutex);
|
||||
}
|
||||
if (LIKELY(isRunning() && frame_buffers.size() > 0)) {
|
||||
frame = frame_buffers.front();
|
||||
frame_buffers.pop_front();
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
uint32_t AbstractBufferedPipeline::get_frame_count() {
|
||||
ENTER();
|
||||
|
||||
Mutex::Autolock lock(buffer_mutex);
|
||||
uint32_t result = frame_buffers.size();
|
||||
|
||||
RETURN(result, uint32_t);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
//
|
||||
//********************************************************************************
|
||||
void *AbstractBufferedPipeline::handler_thread_func(void *vptr_args) {
|
||||
|
||||
ENTER();
|
||||
AbstractBufferedPipeline *pipeline = reinterpret_cast<AbstractBufferedPipeline *>(vptr_args);
|
||||
if (LIKELY(pipeline)) {
|
||||
pipeline->do_loop();
|
||||
}
|
||||
PRE_EXIT();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void AbstractBufferedPipeline::do_loop() {
|
||||
ENTER();
|
||||
|
||||
clear_frames();
|
||||
init_pool(default_frame_size);
|
||||
|
||||
on_start();
|
||||
setState(PIPELINE_STATE_RUNNING);
|
||||
for ( ; LIKELY(isRunning()) ; ) {
|
||||
uvc_frame_t *frame = wait_frame();
|
||||
if ((LIKELY(frame))) {
|
||||
try {
|
||||
if (!handle_frame(frame)) {
|
||||
chain_frame(frame);
|
||||
}
|
||||
} catch (...) {
|
||||
LOGE("exception");
|
||||
}
|
||||
recycle_frame(frame);
|
||||
}
|
||||
}
|
||||
setState(PIPELINE_STATE_STOPPING);
|
||||
mIsRunning = false;
|
||||
on_stop();
|
||||
setState(PIPELINE_STATE_INITIALIZED);
|
||||
|
||||
EXIT();
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by saki on 15/11/05.
|
||||
//
|
||||
|
||||
#ifndef PUPILMOBILE_ABSTRACTBUFFEREDPIPELINE_H
|
||||
#define PUPILMOBILE_ABSTRACTBUFFEREDPIPELINE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <list>
|
||||
#include "Mutex.h"
|
||||
#include "Condition.h"
|
||||
|
||||
#include "libUVCCamera.h"
|
||||
#include "IPipeline.h"
|
||||
|
||||
#pragma interface
|
||||
|
||||
#define DEFAULT_INIT_FRAME_POOL_SZ 2
|
||||
#define DEFAULT_MAX_FRAME_NUM 8
|
||||
|
||||
using namespace android;
|
||||
|
||||
class AbstractBufferedPipeline;
|
||||
|
||||
class AbstractBufferedPipeline : virtual public IPipeline {
|
||||
private:
|
||||
const uint32_t max_buffer_num;
|
||||
const uint32_t init_pool_num;
|
||||
const bool drop_frames;
|
||||
volatile uint32_t total_frame_num;
|
||||
|
||||
// frame buffer pool to improve performance by reducing memory allocation
|
||||
mutable Mutex pool_mutex;
|
||||
Condition pool_sync;
|
||||
std::list<uvc_frame_t *> frame_pool;
|
||||
// frame buffers
|
||||
pthread_t handler_thread;
|
||||
mutable Mutex buffer_mutex;
|
||||
Condition buffer_sync;
|
||||
std::list<uvc_frame_t *> frame_buffers;
|
||||
static void *handler_thread_func(void *vptr_args);
|
||||
|
||||
protected:
|
||||
// frame buffer pool
|
||||
uvc_frame_t *get_frame(const size_t &data_bytes);
|
||||
void recycle_frame(uvc_frame_t *frame);
|
||||
void init_pool(const size_t &data_bytes);
|
||||
void clear_pool();
|
||||
// frame buffers
|
||||
void clear_frames();
|
||||
int add_frame(uvc_frame_t *frame);
|
||||
uvc_frame_t *wait_frame();
|
||||
uint32_t get_frame_count();
|
||||
virtual void do_loop();
|
||||
virtual void on_start() = 0;
|
||||
virtual void on_stop() = 0;
|
||||
virtual int handle_frame(uvc_frame_t *frame) = 0;
|
||||
public:
|
||||
AbstractBufferedPipeline(const int &_max_buffer_num = DEFAULT_MAX_FRAME_NUM, const int &init_pool_num = DEFAULT_INIT_FRAME_POOL_SZ,
|
||||
const size_t &default_frame_size = DEFAULT_FRAME_SZ, const bool &drop_frames_when_buffer_empty = true);
|
||||
virtual ~AbstractBufferedPipeline();
|
||||
virtual int release();
|
||||
virtual int start();
|
||||
virtual int stop();
|
||||
virtual int queueFrame(uvc_frame_t *frame);
|
||||
};
|
||||
|
||||
|
||||
#endif //PUPILMOBILE_ABSTRACTBUFFEREDPIPELINE_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user