建立 MAG160C 逆向工程交接仓库

This commit is contained in:
ZXCLI
2026-08-11 19:08:44 +08:00
commit 8409b27ba3
3135 changed files with 534408 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6
View File
@@ -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>
@@ -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
@@ -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>
@@ -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);
}
}
@@ -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;
}
};
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
});
}
}
@@ -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);
}
}
}
@@ -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;
}
}
@@ -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();
}
}
}
}
@@ -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;
}
}
}
}
}
@@ -0,0 +1,7 @@
package com.elotouch.uvc;
import android.graphics.Bitmap;
public interface INewUVCFrame {
void onUVCFrame(Bitmap bmp);
}
@@ -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);
}
}
}
}
@@ -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>
@@ -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>
@@ -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>
@@ -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>
@@ -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>
@@ -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>
@@ -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>
@@ -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>
@@ -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
@@ -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
+172
View File
@@ -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>
@@ -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>
@@ -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;
}
}
@@ -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;
}
}
@@ -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
}
}
}
@@ -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;
}
}
}
@@ -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
+ "]";
}
}
@@ -0,0 +1,5 @@
package com.serenegiant.usb;
public interface IButtonCallback {
void onButton(int button, int state);
}
@@ -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);
}
@@ -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);
}
@@ -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];
}
};
}
@@ -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");
}
}
@@ -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
@@ -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
@@ -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)
@@ -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 *);
}
@@ -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_ */
@@ -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();
}
@@ -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_ */
@@ -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_ */
@@ -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();
}
@@ -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_ */
@@ -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();
}
@@ -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_ */
@@ -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;
}
@@ -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_ */
@@ -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_ */

Some files were not shown because too many files have changed in this diff Show More