Repository: saki4510t/UVCCamera
Branch: master
Commit: c9399e63dfab
Files: 1018
Total size: 12.0 MB
Directory structure:
gitextract_nybbmgne/
├── .gitignore
├── .idea/
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── inspectionProfiles/
│ │ └── Project_Default.xml
│ └── vcs.xml
├── README.md
├── build.gradle
├── gradle/
│ └── wrapper/
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── libuvccamera/
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ ├── common/
│ │ │ ├── BaseActivity.java
│ │ │ ├── BaseFragment.java
│ │ │ └── BaseService.java
│ │ └── usb/
│ │ ├── CameraDialog.java
│ │ ├── DeviceFilter.java
│ │ ├── IButtonCallback.java
│ │ ├── IFrameCallback.java
│ │ ├── IStatusCallback.java
│ │ ├── Size.java
│ │ ├── USBMonitor.java
│ │ ├── USBVendorId.java
│ │ └── UVCCamera.java
│ ├── jni/
│ │ ├── Android.mk
│ │ ├── Application.mk
│ │ ├── UVCCamera/
│ │ │ ├── Android.mk
│ │ │ ├── Parameters.cpp
│ │ │ ├── Parameters.h
│ │ │ ├── UVCButtonCallback.cpp
│ │ │ ├── UVCButtonCallback.h
│ │ │ ├── UVCCamera.cpp
│ │ │ ├── UVCCamera.h
│ │ │ ├── UVCPreview.cpp
│ │ │ ├── UVCPreview.h
│ │ │ ├── UVCStatusCallback.cpp
│ │ │ ├── UVCStatusCallback.h
│ │ │ ├── _onload.cpp
│ │ │ ├── _onload.h
│ │ │ ├── libUVCCamera.h
│ │ │ ├── objectarray.h
│ │ │ ├── pipeline/
│ │ │ │ ├── AbstractBufferedPipeline.cpp
│ │ │ │ ├── AbstractBufferedPipeline.h
│ │ │ │ ├── CallbackPipeline.cpp
│ │ │ │ ├── CallbackPipeline.h
│ │ │ │ ├── CaptureBasePipeline.cpp
│ │ │ │ ├── CaptureBasePipeline.h
│ │ │ │ ├── ConvertPipeline.cpp
│ │ │ │ ├── ConvertPipeline.h
│ │ │ │ ├── DistributePipeline.cpp
│ │ │ │ ├── DistributePipeline.h
│ │ │ │ ├── IPipeline.cpp
│ │ │ │ ├── IPipeline.h
│ │ │ │ ├── PreviewPipeline.cpp
│ │ │ │ ├── PreviewPipeline.h
│ │ │ │ ├── PublisherPipeline.cpp
│ │ │ │ ├── PublisherPipeline.h
│ │ │ │ ├── SQLiteBufferedPipeline.cpp
│ │ │ │ ├── SQLiteBufferedPipeline.h
│ │ │ │ ├── SimpleBufferedPipeline.cpp
│ │ │ │ ├── SimpleBufferedPipeline.h
│ │ │ │ ├── pipeline_helper.cpp
│ │ │ │ └── pipeline_helper.h
│ │ │ ├── serenegiant_usb_UVCCamera.cpp
│ │ │ └── utilbase.cpp
│ │ ├── libjpeg-turbo-1.5.0/
│ │ │ ├── Android.mk
│ │ │ ├── BUILDING.md
│ │ │ ├── CMakeLists.txt
│ │ │ ├── ChangeLog.md
│ │ │ ├── LICENSE.md
│ │ │ ├── Makefile.am
│ │ │ ├── Makefile.in
│ │ │ ├── README.ijg
│ │ │ ├── README.md
│ │ │ ├── acinclude.m4
│ │ │ ├── aclocal.m4
│ │ │ ├── ar-lib
│ │ │ ├── bmp.c
│ │ │ ├── bmp.h
│ │ │ ├── cderror.h
│ │ │ ├── cdjpeg.c
│ │ │ ├── cdjpeg.h
│ │ │ ├── change.log
│ │ │ ├── cjpeg.1
│ │ │ ├── cjpeg.c
│ │ │ ├── cmakescripts/
│ │ │ │ └── testclean.cmake
│ │ │ ├── coderules.txt
│ │ │ ├── compile
│ │ │ ├── config.guess
│ │ │ ├── config.h.in
│ │ │ ├── config.sub
│ │ │ ├── configure
│ │ │ ├── configure.ac
│ │ │ ├── depcomp
│ │ │ ├── djpeg.1
│ │ │ ├── djpeg.c
│ │ │ ├── doc/
│ │ │ │ └── html/
│ │ │ │ ├── annotated.html
│ │ │ │ ├── classes.html
│ │ │ │ ├── doxygen-extra.css
│ │ │ │ ├── doxygen.css
│ │ │ │ ├── dynsections.js
│ │ │ │ ├── functions.html
│ │ │ │ ├── functions_vars.html
│ │ │ │ ├── group___turbo_j_p_e_g.html
│ │ │ │ ├── index.html
│ │ │ │ ├── jquery.js
│ │ │ │ ├── modules.html
│ │ │ │ ├── search/
│ │ │ │ │ ├── all_63.html
│ │ │ │ │ ├── all_63.js
│ │ │ │ │ ├── all_64.html
│ │ │ │ │ ├── all_64.js
│ │ │ │ │ ├── all_68.html
│ │ │ │ │ ├── all_68.js
│ │ │ │ │ ├── all_6e.html
│ │ │ │ │ ├── all_6e.js
│ │ │ │ │ ├── all_6f.html
│ │ │ │ │ ├── all_6f.js
│ │ │ │ │ ├── all_72.html
│ │ │ │ │ ├── all_72.js
│ │ │ │ │ ├── all_74.html
│ │ │ │ │ ├── all_74.js
│ │ │ │ │ ├── all_77.html
│ │ │ │ │ ├── all_77.js
│ │ │ │ │ ├── all_78.html
│ │ │ │ │ ├── all_78.js
│ │ │ │ │ ├── all_79.html
│ │ │ │ │ ├── all_79.js
│ │ │ │ │ ├── classes_74.html
│ │ │ │ │ ├── classes_74.js
│ │ │ │ │ ├── enums_74.html
│ │ │ │ │ ├── enums_74.js
│ │ │ │ │ ├── enumvalues_74.html
│ │ │ │ │ ├── enumvalues_74.js
│ │ │ │ │ ├── functions_74.html
│ │ │ │ │ ├── functions_74.js
│ │ │ │ │ ├── groups_74.html
│ │ │ │ │ ├── groups_74.js
│ │ │ │ │ ├── nomatches.html
│ │ │ │ │ ├── search.css
│ │ │ │ │ ├── search.js
│ │ │ │ │ ├── typedefs_74.html
│ │ │ │ │ ├── typedefs_74.js
│ │ │ │ │ ├── variables_63.html
│ │ │ │ │ ├── variables_63.js
│ │ │ │ │ ├── variables_64.html
│ │ │ │ │ ├── variables_64.js
│ │ │ │ │ ├── variables_68.html
│ │ │ │ │ ├── variables_68.js
│ │ │ │ │ ├── variables_6e.html
│ │ │ │ │ ├── variables_6e.js
│ │ │ │ │ ├── variables_6f.html
│ │ │ │ │ ├── variables_6f.js
│ │ │ │ │ ├── variables_72.html
│ │ │ │ │ ├── variables_72.js
│ │ │ │ │ ├── variables_74.html
│ │ │ │ │ ├── variables_74.js
│ │ │ │ │ ├── variables_77.html
│ │ │ │ │ ├── variables_77.js
│ │ │ │ │ ├── variables_78.html
│ │ │ │ │ ├── variables_78.js
│ │ │ │ │ ├── variables_79.html
│ │ │ │ │ └── variables_79.js
│ │ │ │ ├── structtjregion.html
│ │ │ │ ├── structtjscalingfactor.html
│ │ │ │ ├── structtjtransform.html
│ │ │ │ └── tabs.css
│ │ │ ├── doxygen-extra.css
│ │ │ ├── doxygen.config
│ │ │ ├── example.c
│ │ │ ├── include/
│ │ │ │ ├── config.h
│ │ │ │ ├── jconfig.h
│ │ │ │ ├── jconfigint.h
│ │ │ │ └── jsimdcfg.inc
│ │ │ ├── install-sh
│ │ │ ├── jaricom.c
│ │ │ ├── java/
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── MANIFEST.MF
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── Makefile.in
│ │ │ │ ├── README
│ │ │ │ ├── TJBench.java
│ │ │ │ ├── TJExample.java
│ │ │ │ ├── TJUnitTest.java
│ │ │ │ ├── doc/
│ │ │ │ │ ├── allclasses-frame.html
│ │ │ │ │ ├── allclasses-noframe.html
│ │ │ │ │ ├── constant-values.html
│ │ │ │ │ ├── deprecated-list.html
│ │ │ │ │ ├── help-doc.html
│ │ │ │ │ ├── index-all.html
│ │ │ │ │ ├── index.html
│ │ │ │ │ ├── org/
│ │ │ │ │ │ └── libjpegturbo/
│ │ │ │ │ │ └── turbojpeg/
│ │ │ │ │ │ ├── TJ.html
│ │ │ │ │ │ ├── TJCompressor.html
│ │ │ │ │ │ ├── TJCustomFilter.html
│ │ │ │ │ │ ├── TJDecompressor.html
│ │ │ │ │ │ ├── TJException.html
│ │ │ │ │ │ ├── TJScalingFactor.html
│ │ │ │ │ │ ├── TJTransform.html
│ │ │ │ │ │ ├── TJTransformer.html
│ │ │ │ │ │ ├── YUVImage.html
│ │ │ │ │ │ ├── package-frame.html
│ │ │ │ │ │ ├── package-summary.html
│ │ │ │ │ │ └── package-tree.html
│ │ │ │ │ ├── overview-tree.html
│ │ │ │ │ ├── package-list
│ │ │ │ │ ├── serialized-form.html
│ │ │ │ │ └── stylesheet.css
│ │ │ │ ├── org/
│ │ │ │ │ └── libjpegturbo/
│ │ │ │ │ └── turbojpeg/
│ │ │ │ │ ├── TJ.java
│ │ │ │ │ ├── TJCompressor.java
│ │ │ │ │ ├── TJCustomFilter.java
│ │ │ │ │ ├── TJDecompressor.java
│ │ │ │ │ ├── TJException.java
│ │ │ │ │ ├── TJLoader.java.in
│ │ │ │ │ ├── TJLoader.java.tmpl
│ │ │ │ │ ├── TJScalingFactor.java
│ │ │ │ │ ├── TJTransform.java
│ │ │ │ │ ├── TJTransformer.java
│ │ │ │ │ └── YUVImage.java
│ │ │ │ ├── org_libjpegturbo_turbojpeg_TJ.h
│ │ │ │ ├── org_libjpegturbo_turbojpeg_TJCompressor.h
│ │ │ │ ├── org_libjpegturbo_turbojpeg_TJDecompressor.h
│ │ │ │ └── org_libjpegturbo_turbojpeg_TJTransformer.h
│ │ │ ├── jcapimin.c
│ │ │ ├── jcapistd.c
│ │ │ ├── jcarith.c
│ │ │ ├── jccoefct.c
│ │ │ ├── jccolext.c
│ │ │ ├── jccolor.c
│ │ │ ├── jcdctmgr.c
│ │ │ ├── jchuff.c
│ │ │ ├── jchuff.h
│ │ │ ├── jcinit.c
│ │ │ ├── jcmainct.c
│ │ │ ├── jcmarker.c
│ │ │ ├── jcmaster.c
│ │ │ ├── jcomapi.c
│ │ │ ├── jconfig.h.in
│ │ │ ├── jconfig.txt
│ │ │ ├── jconfigint.h.in
│ │ │ ├── jcparam.c
│ │ │ ├── jcphuff.c
│ │ │ ├── jcprepct.c
│ │ │ ├── jcsample.c
│ │ │ ├── jcstest.c
│ │ │ ├── jctrans.c
│ │ │ ├── jdapimin.c
│ │ │ ├── jdapistd.c
│ │ │ ├── jdarith.c
│ │ │ ├── jdatadst-tj.c
│ │ │ ├── jdatadst.c
│ │ │ ├── jdatasrc-tj.c
│ │ │ ├── jdatasrc.c
│ │ │ ├── jdcoefct.c
│ │ │ ├── jdcoefct.h
│ │ │ ├── jdcol565.c
│ │ │ ├── jdcolext.c
│ │ │ ├── jdcolor.c
│ │ │ ├── jdct.h
│ │ │ ├── jddctmgr.c
│ │ │ ├── jdhuff.c
│ │ │ ├── jdhuff.h
│ │ │ ├── jdinput.c
│ │ │ ├── jdmainct.c
│ │ │ ├── jdmainct.h
│ │ │ ├── jdmarker.c
│ │ │ ├── jdmaster.c
│ │ │ ├── jdmaster.h
│ │ │ ├── jdmerge.c
│ │ │ ├── jdmrg565.c
│ │ │ ├── jdmrgext.c
│ │ │ ├── jdphuff.c
│ │ │ ├── jdpostct.c
│ │ │ ├── jdsample.c
│ │ │ ├── jdsample.h
│ │ │ ├── jdtrans.c
│ │ │ ├── jerror.c
│ │ │ ├── jerror.h
│ │ │ ├── jfdctflt.c
│ │ │ ├── jfdctfst.c
│ │ │ ├── jfdctint.c
│ │ │ ├── jidctflt.c
│ │ │ ├── jidctfst.c
│ │ │ ├── jidctint.c
│ │ │ ├── jidctred.c
│ │ │ ├── jinclude.h
│ │ │ ├── jmemmgr.c
│ │ │ ├── jmemnobs.c
│ │ │ ├── jmemsys.h
│ │ │ ├── jmorecfg.h
│ │ │ ├── jpeg_nbits_table.h
│ │ │ ├── jpegcomp.h
│ │ │ ├── jpegint.h
│ │ │ ├── jpeglib.h
│ │ │ ├── jpegtran.1
│ │ │ ├── jpegtran.c
│ │ │ ├── jquant1.c
│ │ │ ├── jquant2.c
│ │ │ ├── jsimd.h
│ │ │ ├── jsimd_none.c
│ │ │ ├── jsimddct.h
│ │ │ ├── jstdhuff.c
│ │ │ ├── jutils.c
│ │ │ ├── jversion.h
│ │ │ ├── libjpeg.map.in
│ │ │ ├── libjpeg.txt
│ │ │ ├── ltmain.sh
│ │ │ ├── md5/
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── Makefile.in
│ │ │ │ ├── md5.c
│ │ │ │ ├── md5.h
│ │ │ │ ├── md5cmp.c
│ │ │ │ └── md5hl.c
│ │ │ ├── missing
│ │ │ ├── rdbmp.c
│ │ │ ├── rdcolmap.c
│ │ │ ├── rdgif.c
│ │ │ ├── rdjpgcom.1
│ │ │ ├── rdjpgcom.c
│ │ │ ├── rdppm.c
│ │ │ ├── rdrle.c
│ │ │ ├── rdswitch.c
│ │ │ ├── rdtarga.c
│ │ │ ├── release/
│ │ │ │ ├── Distribution.xml
│ │ │ │ ├── License.rtf
│ │ │ │ ├── ReadMe.txt
│ │ │ │ ├── Welcome.rtf
│ │ │ │ ├── deb-control.tmpl
│ │ │ │ ├── libjpeg-turbo.nsi.in
│ │ │ │ ├── libjpeg-turbo.spec.in
│ │ │ │ ├── libjpeg.pc.in
│ │ │ │ ├── libturbojpeg.pc.in
│ │ │ │ ├── makecygwinpkg.in
│ │ │ │ ├── makedpkg.in
│ │ │ │ ├── makemacpkg.in
│ │ │ │ └── uninstall.in
│ │ │ ├── sharedlib/
│ │ │ │ └── CMakeLists.txt
│ │ │ ├── simd/
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── Makefile.in
│ │ │ │ ├── jccolext-altivec.c
│ │ │ │ ├── jccolext-mmx.asm
│ │ │ │ ├── jccolext-sse2-64.asm
│ │ │ │ ├── jccolext-sse2.asm
│ │ │ │ ├── jccolor-altivec.c
│ │ │ │ ├── jccolor-mmx.asm
│ │ │ │ ├── jccolor-sse2-64.asm
│ │ │ │ ├── jccolor-sse2.asm
│ │ │ │ ├── jcgray-altivec.c
│ │ │ │ ├── jcgray-mmx.asm
│ │ │ │ ├── jcgray-sse2-64.asm
│ │ │ │ ├── jcgray-sse2.asm
│ │ │ │ ├── jcgryext-altivec.c
│ │ │ │ ├── jcgryext-mmx.asm
│ │ │ │ ├── jcgryext-sse2-64.asm
│ │ │ │ ├── jcgryext-sse2.asm
│ │ │ │ ├── jchuff-sse2-64.asm
│ │ │ │ ├── jchuff-sse2.asm
│ │ │ │ ├── jcolsamp.inc
│ │ │ │ ├── jcsample-altivec.c
│ │ │ │ ├── jcsample-mmx.asm
│ │ │ │ ├── jcsample-sse2-64.asm
│ │ │ │ ├── jcsample-sse2.asm
│ │ │ │ ├── jcsample.h
│ │ │ │ ├── jdcolext-altivec.c
│ │ │ │ ├── jdcolext-mmx.asm
│ │ │ │ ├── jdcolext-sse2-64.asm
│ │ │ │ ├── jdcolext-sse2.asm
│ │ │ │ ├── jdcolor-altivec.c
│ │ │ │ ├── jdcolor-mmx.asm
│ │ │ │ ├── jdcolor-sse2-64.asm
│ │ │ │ ├── jdcolor-sse2.asm
│ │ │ │ ├── jdct.inc
│ │ │ │ ├── jdmerge-altivec.c
│ │ │ │ ├── jdmerge-mmx.asm
│ │ │ │ ├── jdmerge-sse2-64.asm
│ │ │ │ ├── jdmerge-sse2.asm
│ │ │ │ ├── jdmrgext-altivec.c
│ │ │ │ ├── jdmrgext-mmx.asm
│ │ │ │ ├── jdmrgext-sse2-64.asm
│ │ │ │ ├── jdmrgext-sse2.asm
│ │ │ │ ├── jdsample-altivec.c
│ │ │ │ ├── jdsample-mmx.asm
│ │ │ │ ├── jdsample-sse2-64.asm
│ │ │ │ ├── jdsample-sse2.asm
│ │ │ │ ├── jfdctflt-3dn.asm
│ │ │ │ ├── jfdctflt-sse-64.asm
│ │ │ │ ├── jfdctflt-sse.asm
│ │ │ │ ├── jfdctfst-altivec.c
│ │ │ │ ├── jfdctfst-mmx.asm
│ │ │ │ ├── jfdctfst-sse2-64.asm
│ │ │ │ ├── jfdctfst-sse2.asm
│ │ │ │ ├── jfdctint-altivec.c
│ │ │ │ ├── jfdctint-mmx.asm
│ │ │ │ ├── jfdctint-sse2-64.asm
│ │ │ │ ├── jfdctint-sse2.asm
│ │ │ │ ├── jidctflt-3dn.asm
│ │ │ │ ├── jidctflt-sse.asm
│ │ │ │ ├── jidctflt-sse2-64.asm
│ │ │ │ ├── jidctflt-sse2.asm
│ │ │ │ ├── jidctfst-altivec.c
│ │ │ │ ├── jidctfst-mmx.asm
│ │ │ │ ├── jidctfst-sse2-64.asm
│ │ │ │ ├── jidctfst-sse2.asm
│ │ │ │ ├── jidctint-altivec.c
│ │ │ │ ├── jidctint-mmx.asm
│ │ │ │ ├── jidctint-sse2-64.asm
│ │ │ │ ├── jidctint-sse2.asm
│ │ │ │ ├── jidctred-mmx.asm
│ │ │ │ ├── jidctred-sse2-64.asm
│ │ │ │ ├── jidctred-sse2.asm
│ │ │ │ ├── jpeg_nbits_table.inc
│ │ │ │ ├── jquant-3dn.asm
│ │ │ │ ├── jquant-mmx.asm
│ │ │ │ ├── jquant-sse.asm
│ │ │ │ ├── jquantf-sse2-64.asm
│ │ │ │ ├── jquantf-sse2.asm
│ │ │ │ ├── jquanti-altivec.c
│ │ │ │ ├── jquanti-sse2-64.asm
│ │ │ │ ├── jquanti-sse2.asm
│ │ │ │ ├── jsimd.h
│ │ │ │ ├── jsimd_altivec.h
│ │ │ │ ├── jsimd_arm.c
│ │ │ │ ├── jsimd_arm64.c
│ │ │ │ ├── jsimd_arm64_neon.S
│ │ │ │ ├── jsimd_arm_neon.S
│ │ │ │ ├── jsimd_i386.c
│ │ │ │ ├── jsimd_mips.c
│ │ │ │ ├── jsimd_mips_dspr2.S
│ │ │ │ ├── jsimd_mips_dspr2_asm.h
│ │ │ │ ├── jsimd_powerpc.c
│ │ │ │ ├── jsimd_x86_64.c
│ │ │ │ ├── jsimdcfg.inc.h
│ │ │ │ ├── jsimdcpu.asm
│ │ │ │ ├── jsimdext.inc
│ │ │ │ └── nasm_lt.sh
│ │ │ ├── structure.txt
│ │ │ ├── testimages/
│ │ │ │ ├── nightshot_iso_100.txt
│ │ │ │ └── testorig.ppm
│ │ │ ├── tjbench.c
│ │ │ ├── tjbenchtest.in
│ │ │ ├── tjbenchtest.java.in
│ │ │ ├── tjexampletest.in
│ │ │ ├── tjunittest.c
│ │ │ ├── tjutil.c
│ │ │ ├── tjutil.h
│ │ │ ├── transupp.c
│ │ │ ├── transupp.h
│ │ │ ├── turbojpeg-jni.c
│ │ │ ├── turbojpeg-mapfile
│ │ │ ├── turbojpeg-mapfile.jni
│ │ │ ├── turbojpeg.c
│ │ │ ├── turbojpeg.h
│ │ │ ├── usage.txt
│ │ │ ├── win/
│ │ │ │ ├── jconfig.h.in
│ │ │ │ ├── jconfigint.h.in
│ │ │ │ ├── jpeg62-memsrcdst.def
│ │ │ │ ├── jpeg62.def
│ │ │ │ ├── jpeg7-memsrcdst.def
│ │ │ │ ├── jpeg7.def
│ │ │ │ ├── jpeg8.def
│ │ │ │ └── jsimdcfg.inc
│ │ │ ├── wizard.txt
│ │ │ ├── wrbmp.c
│ │ │ ├── wrgif.c
│ │ │ ├── wrjpgcom.1
│ │ │ ├── wrjpgcom.c
│ │ │ ├── wrppm.c
│ │ │ ├── wrppm.h
│ │ │ ├── wrrle.c
│ │ │ └── wrtarga.c
│ │ ├── libusb/
│ │ │ ├── .private/
│ │ │ │ ├── README.txt
│ │ │ │ ├── bd.cmd
│ │ │ │ ├── bm.sh
│ │ │ │ ├── bwince.cmd
│ │ │ │ ├── post-rewrite.sh
│ │ │ │ ├── pre-commit.sh
│ │ │ │ ├── wbs.txt
│ │ │ │ └── wbs_wince.txt
│ │ │ ├── AUTHORS
│ │ │ ├── COPYING
│ │ │ ├── ChangeLog
│ │ │ ├── INSTALL
│ │ │ ├── INSTALL_WIN.txt
│ │ │ ├── Makefile.am
│ │ │ ├── NEWS
│ │ │ ├── PORTING
│ │ │ ├── README
│ │ │ ├── README.git
│ │ │ ├── TODO
│ │ │ ├── Xcode/
│ │ │ │ ├── common.xcconfig
│ │ │ │ ├── config.h
│ │ │ │ ├── debug.xcconfig
│ │ │ │ ├── libusb.xcconfig
│ │ │ │ ├── libusb.xcodeproj/
│ │ │ │ │ └── project.pbxproj
│ │ │ │ ├── libusb_debug.xcconfig
│ │ │ │ ├── libusb_release.xcconfig
│ │ │ │ └── release.xcconfig
│ │ │ ├── android/
│ │ │ │ ├── README
│ │ │ │ ├── config.h
│ │ │ │ ├── config_original.h
│ │ │ │ └── jni/
│ │ │ │ ├── Android.mk
│ │ │ │ ├── Android_original.mk
│ │ │ │ ├── Application.mk
│ │ │ │ ├── examples.mk
│ │ │ │ ├── libusb.mk
│ │ │ │ ├── libusb_original.mk
│ │ │ │ └── tests.mk
│ │ │ ├── autogen.sh
│ │ │ ├── bootstrap.sh
│ │ │ ├── configure.ac
│ │ │ ├── doc/
│ │ │ │ ├── Makefile.am
│ │ │ │ └── doxygen.cfg.in
│ │ │ ├── examples/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── dpfp.c
│ │ │ │ ├── dpfp_threaded.c
│ │ │ │ ├── ezusb.c
│ │ │ │ ├── ezusb.h
│ │ │ │ ├── fxload.c
│ │ │ │ ├── getopt/
│ │ │ │ │ ├── getopt.c
│ │ │ │ │ ├── getopt.h
│ │ │ │ │ └── getopt1.c
│ │ │ │ ├── hotplugtest.c
│ │ │ │ ├── listdevs.c
│ │ │ │ ├── sam3u_benchmark.c
│ │ │ │ └── xusb.c
│ │ │ ├── libusb/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── config.h
│ │ │ │ ├── core.c
│ │ │ │ ├── core_original.c
│ │ │ │ ├── descriptor.c
│ │ │ │ ├── descriptor_original.c
│ │ │ │ ├── hotplug.c
│ │ │ │ ├── hotplug.h
│ │ │ │ ├── hotplug_original.c
│ │ │ │ ├── io.c
│ │ │ │ ├── io_original.c
│ │ │ │ ├── libusb-1.0.def
│ │ │ │ ├── libusb-1.0.rc
│ │ │ │ ├── libusb.h
│ │ │ │ ├── libusb_original.h
│ │ │ │ ├── libusbi.h
│ │ │ │ ├── libusbi_original.h
│ │ │ │ ├── os/
│ │ │ │ │ ├── android_netlink.c
│ │ │ │ │ ├── android_usbfs.c
│ │ │ │ │ ├── android_usbfs.h
│ │ │ │ │ ├── darwin_usb.c
│ │ │ │ │ ├── darwin_usb.h
│ │ │ │ │ ├── linux_netlink.c
│ │ │ │ │ ├── linux_udev.c
│ │ │ │ │ ├── linux_usbfs.c
│ │ │ │ │ ├── linux_usbfs.h
│ │ │ │ │ ├── netbsd_usb.c
│ │ │ │ │ ├── openbsd_usb.c
│ │ │ │ │ ├── poll_posix.c
│ │ │ │ │ ├── poll_posix.h
│ │ │ │ │ ├── poll_posix_original.c
│ │ │ │ │ ├── poll_windows.c
│ │ │ │ │ ├── poll_windows.h
│ │ │ │ │ ├── threads_posix.c
│ │ │ │ │ ├── threads_posix.h
│ │ │ │ │ ├── threads_windows.c
│ │ │ │ │ ├── threads_windows.h
│ │ │ │ │ ├── wince_usb.c
│ │ │ │ │ ├── wince_usb.h
│ │ │ │ │ ├── windows_common.h
│ │ │ │ │ ├── windows_usb.c
│ │ │ │ │ └── windows_usb.h
│ │ │ │ ├── strerror.c
│ │ │ │ ├── sync.c
│ │ │ │ ├── sync_original.c
│ │ │ │ ├── version.h
│ │ │ │ └── version_nano.h
│ │ │ ├── libusb-1.0.pc.in
│ │ │ ├── msvc/
│ │ │ │ ├── config.h
│ │ │ │ ├── ddk_build.cmd
│ │ │ │ ├── errno.h
│ │ │ │ ├── fxload_2010.vcxproj
│ │ │ │ ├── fxload_2010.vcxproj.filters
│ │ │ │ ├── fxload_2012.vcxproj
│ │ │ │ ├── fxload_2012.vcxproj.filters
│ │ │ │ ├── fxload_2013.vcxproj
│ │ │ │ ├── fxload_sources
│ │ │ │ ├── getopt_2005.vcproj
│ │ │ │ ├── getopt_2010.vcxproj
│ │ │ │ ├── getopt_2010.vcxproj.filters
│ │ │ │ ├── getopt_2012.vcxproj
│ │ │ │ ├── getopt_2012.vcxproj.filters
│ │ │ │ ├── getopt_2013.vcxproj
│ │ │ │ ├── getopt_sources
│ │ │ │ ├── hotplugtest_2010.vcxproj
│ │ │ │ ├── hotplugtest_2010.vcxproj.filters
│ │ │ │ ├── hotplugtest_2012.vcxproj
│ │ │ │ ├── hotplugtest_2012.vcxproj.filters
│ │ │ │ ├── hotplugtest_2013.vcxproj
│ │ │ │ ├── hotplugtest_sources
│ │ │ │ ├── inttypes.h
│ │ │ │ ├── libusb.dsw
│ │ │ │ ├── libusb_2005.sln
│ │ │ │ ├── libusb_2010.sln
│ │ │ │ ├── libusb_2012.sln
│ │ │ │ ├── libusb_2013.sln
│ │ │ │ ├── libusb_dll.dsp
│ │ │ │ ├── libusb_dll_2005.vcproj
│ │ │ │ ├── libusb_dll_2010.vcxproj
│ │ │ │ ├── libusb_dll_2010.vcxproj.filters
│ │ │ │ ├── libusb_dll_2012.vcxproj
│ │ │ │ ├── libusb_dll_2012.vcxproj.filters
│ │ │ │ ├── libusb_dll_2013.vcxproj
│ │ │ │ ├── libusb_dll_wince.vcproj
│ │ │ │ ├── libusb_sources
│ │ │ │ ├── libusb_static.dsp
│ │ │ │ ├── libusb_static_2005.vcproj
│ │ │ │ ├── libusb_static_2010.vcxproj
│ │ │ │ ├── libusb_static_2010.vcxproj.filters
│ │ │ │ ├── libusb_static_2012.vcxproj
│ │ │ │ ├── libusb_static_2012.vcxproj.filters
│ │ │ │ ├── libusb_static_2013.vcxproj
│ │ │ │ ├── libusb_static_wince.vcproj
│ │ │ │ ├── libusb_wince.sln
│ │ │ │ ├── listdevs.dsp
│ │ │ │ ├── listdevs_2005.vcproj
│ │ │ │ ├── listdevs_2010.vcxproj
│ │ │ │ ├── listdevs_2010.vcxproj.filters
│ │ │ │ ├── listdevs_2012.vcxproj
│ │ │ │ ├── listdevs_2012.vcxproj.filters
│ │ │ │ ├── listdevs_2013.vcxproj
│ │ │ │ ├── listdevs_sources
│ │ │ │ ├── listdevs_wince.vcproj
│ │ │ │ ├── missing.c
│ │ │ │ ├── missing.h
│ │ │ │ ├── stdint.h
│ │ │ │ ├── stress_2005.vcproj
│ │ │ │ ├── stress_2010.vcxproj
│ │ │ │ ├── stress_2010.vcxproj.filters
│ │ │ │ ├── stress_2012.vcxproj
│ │ │ │ ├── stress_2012.vcxproj.filters
│ │ │ │ ├── stress_2013.vcxproj
│ │ │ │ ├── stress_wince.vcproj
│ │ │ │ ├── xusb.dsp
│ │ │ │ ├── xusb_2005.vcproj
│ │ │ │ ├── xusb_2010.vcxproj
│ │ │ │ ├── xusb_2010.vcxproj.filters
│ │ │ │ ├── xusb_2012.vcxproj
│ │ │ │ ├── xusb_2012.vcxproj.filters
│ │ │ │ ├── xusb_2013.vcxproj
│ │ │ │ ├── xusb_sources
│ │ │ │ └── xusb_wince.vcproj
│ │ │ └── tests/
│ │ │ ├── Makefile.am
│ │ │ ├── libusb_testlib.h
│ │ │ ├── stress.c
│ │ │ └── testlib.c
│ │ ├── libuvc/
│ │ │ ├── CMakeLists.txt
│ │ │ ├── README.md
│ │ │ ├── android/
│ │ │ │ └── jni/
│ │ │ │ └── Android.mk
│ │ │ ├── cameras/
│ │ │ │ ├── isight_imac.txt
│ │ │ │ ├── isight_macbook.txt
│ │ │ │ ├── ms_lifecam_show.txt
│ │ │ │ ├── quickcampro9000.txt
│ │ │ │ ├── quickcampro9000_builtin_ctrls.txt
│ │ │ │ └── quickcampro9000_extra_ctrls.txt
│ │ │ ├── changelog.txt
│ │ │ ├── doxygen.conf
│ │ │ ├── include/
│ │ │ │ ├── libuvc/
│ │ │ │ │ ├── libuvc.h
│ │ │ │ │ ├── libuvc_config.h
│ │ │ │ │ ├── libuvc_config.h.in
│ │ │ │ │ ├── libuvc_internal.h
│ │ │ │ │ ├── libuvc_internal_original.h
│ │ │ │ │ └── libuvc_original.h
│ │ │ │ └── utlist.h
│ │ │ ├── libuvcConfig.cmake.in
│ │ │ ├── libuvcConfigVersion.cmake.in
│ │ │ └── src/
│ │ │ ├── ctrl.c
│ │ │ ├── ctrl_original.c
│ │ │ ├── device.c
│ │ │ ├── device_original.c
│ │ │ ├── diag.c
│ │ │ ├── diag_original.c
│ │ │ ├── example.c
│ │ │ ├── frame-mjpeg.c
│ │ │ ├── frame-mjpeg_original.c
│ │ │ ├── frame.c
│ │ │ ├── frame_original.c
│ │ │ ├── init.c
│ │ │ ├── init_original.c
│ │ │ ├── misc.c
│ │ │ ├── stream.c
│ │ │ ├── stream_original.c
│ │ │ └── test.c
│ │ ├── localdefines.h
│ │ ├── rapidjson/
│ │ │ ├── .gitmodules
│ │ │ ├── .travis.yml
│ │ │ ├── doc/
│ │ │ │ ├── diagram/
│ │ │ │ │ ├── insituparsing.dot
│ │ │ │ │ ├── iterative-parser-states-diagram.dot
│ │ │ │ │ ├── makefile
│ │ │ │ │ ├── move1.dot
│ │ │ │ │ ├── move2.dot
│ │ │ │ │ ├── move3.dot
│ │ │ │ │ ├── normalparsing.dot
│ │ │ │ │ ├── simpledom.dot
│ │ │ │ │ └── tutorial.dot
│ │ │ │ ├── dom.md
│ │ │ │ ├── encoding.md
│ │ │ │ ├── faq.md
│ │ │ │ ├── features.md
│ │ │ │ ├── internals.md
│ │ │ │ ├── misc/
│ │ │ │ │ ├── DoxygenLayout.xml
│ │ │ │ │ ├── doxygenextra.css
│ │ │ │ │ ├── footer.html
│ │ │ │ │ └── header.html
│ │ │ │ ├── performance.md
│ │ │ │ ├── sax.md
│ │ │ │ ├── stream.md
│ │ │ │ └── tutorial.md
│ │ │ ├── example/
│ │ │ │ ├── capitalize/
│ │ │ │ │ └── capitalize.cpp
│ │ │ │ ├── condense/
│ │ │ │ │ └── condense.cpp
│ │ │ │ ├── messagereader/
│ │ │ │ │ └── messagereader.cpp
│ │ │ │ ├── pretty/
│ │ │ │ │ └── pretty.cpp
│ │ │ │ ├── prettyauto/
│ │ │ │ │ └── prettyauto.cpp
│ │ │ │ ├── serialize/
│ │ │ │ │ └── serialize.cpp
│ │ │ │ ├── simpledom/
│ │ │ │ │ └── simpledom.cpp
│ │ │ │ ├── simplereader/
│ │ │ │ │ └── simplereader.cpp
│ │ │ │ ├── simplewriter/
│ │ │ │ │ └── simplewriter.cpp
│ │ │ │ └── tutorial/
│ │ │ │ └── tutorial.cpp
│ │ │ ├── include/
│ │ │ │ └── rapidjson/
│ │ │ │ ├── allocators.h
│ │ │ │ ├── document.h
│ │ │ │ ├── encodedstream.h
│ │ │ │ ├── encodings.h
│ │ │ │ ├── error/
│ │ │ │ │ ├── en.h
│ │ │ │ │ └── error.h
│ │ │ │ ├── filereadstream.h
│ │ │ │ ├── filestream.h
│ │ │ │ ├── filewritestream.h
│ │ │ │ ├── internal/
│ │ │ │ │ ├── dtoa.h
│ │ │ │ │ ├── itoa.h
│ │ │ │ │ ├── meta.h
│ │ │ │ │ ├── pow10.h
│ │ │ │ │ ├── stack.h
│ │ │ │ │ └── strfunc.h
│ │ │ │ ├── memorybuffer.h
│ │ │ │ ├── memorystream.h
│ │ │ │ ├── msinttypes/
│ │ │ │ │ ├── inttypes.h
│ │ │ │ │ └── stdint.h
│ │ │ │ ├── prettywriter.h
│ │ │ │ ├── rapidjson.h
│ │ │ │ ├── reader.h
│ │ │ │ ├── stringbuffer.h
│ │ │ │ └── writer.h
│ │ │ ├── license.txt
│ │ │ ├── readme.md
│ │ │ ├── test/
│ │ │ │ ├── perftest/
│ │ │ │ │ ├── jsoncpptest.cpp
│ │ │ │ │ ├── misctest.cpp
│ │ │ │ │ ├── perftest.cpp
│ │ │ │ │ ├── perftest.h
│ │ │ │ │ ├── platformtest.cpp
│ │ │ │ │ ├── rapidjsontest.cpp
│ │ │ │ │ ├── ultrajsontest.cpp
│ │ │ │ │ ├── yajl_all.c
│ │ │ │ │ └── yajltest.cpp
│ │ │ │ └── unittest/
│ │ │ │ ├── documenttest.cpp
│ │ │ │ ├── encodedstreamtest.cpp
│ │ │ │ ├── encodingstest.cpp
│ │ │ │ ├── filestreamtest.cpp
│ │ │ │ ├── jsoncheckertest.cpp
│ │ │ │ ├── readertest.cpp
│ │ │ │ ├── unittest.cpp
│ │ │ │ ├── unittest.h
│ │ │ │ ├── valuetest.cpp
│ │ │ │ └── writertest.cpp
│ │ │ └── thirdparty/
│ │ │ ├── jsoncpp/
│ │ │ │ ├── AUTHORS
│ │ │ │ ├── LICENSE
│ │ │ │ ├── README.txt
│ │ │ │ ├── include/
│ │ │ │ │ └── json/
│ │ │ │ │ ├── autolink.h
│ │ │ │ │ ├── config.h
│ │ │ │ │ ├── features.h
│ │ │ │ │ ├── forwards.h
│ │ │ │ │ ├── json.h
│ │ │ │ │ ├── reader.h
│ │ │ │ │ ├── value.h
│ │ │ │ │ └── writer.h
│ │ │ │ ├── src/
│ │ │ │ │ ├── jsontestrunner/
│ │ │ │ │ │ ├── main.cpp
│ │ │ │ │ │ └── sconscript
│ │ │ │ │ ├── lib_json/
│ │ │ │ │ │ ├── json_batchallocator.h
│ │ │ │ │ │ ├── json_internalarray.inl
│ │ │ │ │ │ ├── json_internalmap.inl
│ │ │ │ │ │ ├── json_reader.cpp
│ │ │ │ │ │ ├── json_value.cpp
│ │ │ │ │ │ ├── json_valueiterator.inl
│ │ │ │ │ │ ├── json_writer.cpp
│ │ │ │ │ │ └── sconscript
│ │ │ │ │ └── test_lib_json/
│ │ │ │ │ ├── jsontest.cpp
│ │ │ │ │ ├── jsontest.h
│ │ │ │ │ ├── main.cpp
│ │ │ │ │ └── sconscript
│ │ │ │ └── version
│ │ │ ├── ultrajson/
│ │ │ │ ├── README
│ │ │ │ ├── ultrajson.h
│ │ │ │ ├── ultrajsondec.c
│ │ │ │ └── ultrajsonenc.c
│ │ │ └── yajl/
│ │ │ ├── COPYING
│ │ │ ├── ChangeLog
│ │ │ ├── README
│ │ │ ├── TODO
│ │ │ ├── include/
│ │ │ │ └── yajl/
│ │ │ │ ├── yajl_common.h
│ │ │ │ ├── yajl_gen.h
│ │ │ │ ├── yajl_parse.h
│ │ │ │ ├── yajl_tree.h
│ │ │ │ └── yajl_version.h
│ │ │ └── src/
│ │ │ ├── CMakeLists.txt
│ │ │ ├── YAJL.dxy
│ │ │ ├── api/
│ │ │ │ ├── yajl_common.h
│ │ │ │ ├── yajl_gen.h
│ │ │ │ ├── yajl_parse.h
│ │ │ │ ├── yajl_tree.h
│ │ │ │ └── yajl_version.h.cmake
│ │ │ ├── yajl
│ │ │ ├── yajl.c
│ │ │ ├── yajl_alloc.c
│ │ │ ├── yajl_alloc.h
│ │ │ ├── yajl_buf.c
│ │ │ ├── yajl_buf.h
│ │ │ ├── yajl_bytestack.h
│ │ │ ├── yajl_encode.c
│ │ │ ├── yajl_encode.h
│ │ │ ├── yajl_gen.c
│ │ │ ├── yajl_lex.c
│ │ │ ├── yajl_lex.h
│ │ │ ├── yajl_parser.c
│ │ │ ├── yajl_parser.h
│ │ │ ├── yajl_tree.c
│ │ │ └── yajl_version.c
│ │ └── utilbase.h
│ └── res/
│ ├── layout/
│ │ ├── dialog_camera.xml
│ │ └── listitem_device.xml
│ ├── values/
│ │ ├── dimens.xml
│ │ └── strings.xml
│ ├── values-ja/
│ │ └── strings.xml
│ └── xml/
│ └── device_filter.xml
├── settings.gradle
├── usbCameraCommon/
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ ├── encoder/
│ │ │ ├── IAudioEncoder.java
│ │ │ ├── IVideoEncoder.java
│ │ │ ├── MediaAudioEncoder.java
│ │ │ ├── MediaEncoder.java
│ │ │ ├── MediaMuxerWrapper.java
│ │ │ ├── MediaSurfaceEncoder.java
│ │ │ ├── MediaVideoBufferEncoder.java
│ │ │ └── MediaVideoEncoder.java
│ │ ├── usbcameracommon/
│ │ │ ├── AbstractUVCCameraHandler.java
│ │ │ ├── UVCCameraHandler.java
│ │ │ └── UVCCameraHandlerMultiSurface.java
│ │ └── widget/
│ │ ├── AspectRatioTextureView.java
│ │ ├── CameraViewInterface.java
│ │ └── UVCCameraTextureView.java
│ └── res/
│ ├── raw/
│ │ └── camera_click.ogg
│ └── values/
│ └── strings.xml
├── usbCameraTest/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ ├── usbcameratest/
│ │ │ └── MainActivity.java
│ │ └── widget/
│ │ ├── AspectRatioViewInterface.java
│ │ └── SimpleUVCCameraTextureView.java
│ └── res/
│ ├── layout/
│ │ └── activity_main.xml
│ ├── values/
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest0/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ └── usbcameratest0/
│ │ └── MainActivity.java
│ └── res/
│ ├── layout/
│ │ └── activity_main.xml
│ ├── values/
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest2/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ ├── usbcameratest2/
│ │ │ └── MainActivity.java
│ │ ├── video/
│ │ │ ├── Encoder.java
│ │ │ └── SurfaceEncoder.java
│ │ └── widget/
│ │ ├── AspectRatioViewInterface.java
│ │ └── SimpleUVCCameraTextureView.java
│ └── res/
│ ├── drawable/
│ │ └── border.xml
│ ├── layout/
│ │ └── activity_main.xml
│ ├── values/
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest3/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ ├── usbcameratest3/
│ │ │ └── MainActivity.java
│ │ └── widget/
│ │ └── UVCCameraTextureView2.java
│ └── res/
│ ├── drawable/
│ │ └── border.xml
│ ├── layout/
│ │ ├── activity_main.xml
│ │ └── activity_main2.xml
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest4/
│ ├── build.gradle
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── aidl/
│ │ ├── android/
│ │ │ ├── hardware/
│ │ │ │ └── usb/
│ │ │ │ └── UsbDevice.aidl
│ │ │ └── view/
│ │ │ └── Surface.aidl
│ │ └── com/
│ │ └── serenegiant/
│ │ └── service/
│ │ ├── IUVCService.aidl
│ │ ├── IUVCServiceCallback.aidl
│ │ ├── IUVCServiceOnFrameAvailable.aidl
│ │ └── IUVCSlaveService.aidl
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ ├── service/
│ │ │ ├── CameraServer.java
│ │ │ └── UVCService.java
│ │ ├── serviceclient/
│ │ │ ├── CameraClient.java
│ │ │ ├── ICameraClient.java
│ │ │ └── ICameraClientCallback.java
│ │ └── usbcameratest4/
│ │ ├── CameraFragment.java
│ │ └── MainActivity.java
│ └── res/
│ ├── drawable/
│ │ └── border.xml
│ ├── layout/
│ │ ├── activity_main.xml
│ │ └── fragment_main.xml
│ ├── raw/
│ │ └── camera_click.ogg
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest5/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ └── usbcameratest5/
│ │ └── MainActivity.java
│ └── res/
│ ├── drawable/
│ │ └── border.xml
│ ├── layout/
│ │ └── activity_main.xml
│ ├── raw/
│ │ └── camera_click.ogg
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest6/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ └── usbcameratest6/
│ │ └── MainActivity.java
│ └── res/
│ ├── drawable/
│ │ └── border.xml
│ ├── layout/
│ │ └── activity_main.xml
│ ├── raw/
│ │ └── camera_click.ogg
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
├── usbCameraTest7/
│ ├── build.gradle
│ ├── lint.xml
│ ├── proguard-project.txt
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ └── usbcameratest7/
│ │ └── MainActivity.java
│ └── res/
│ ├── drawable/
│ │ └── border.xml
│ ├── layout/
│ │ └── activity_main.xml
│ ├── raw/
│ │ └── camera_click.ogg
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ ├── values-v11/
│ │ └── styles.xml
│ ├── values-v14/
│ │ └── styles.xml
│ ├── values-w820dp/
│ │ └── dimens.xml
│ └── xml/
│ └── device_filter.xml
└── usbCameraTest8/
├── build.gradle
├── proguard-rules.pro
└── src/
├── androidTest/
│ └── java/
│ └── com/
│ └── serenegiant/
│ └── usbcameratest8/
│ └── ExampleInstrumentedTest.java
├── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── serenegiant/
│ │ └── usbcameratest8/
│ │ └── MainActivity.java
│ └── res/
│ ├── layout/
│ │ └── activity_main.xml
│ ├── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-ja/
│ │ └── strings.xml
│ └── values-w820dp/
│ └── dimens.xml
└── test/
└── java/
└── com/
└── serenegiant/
└── usbcameratest8/
└── ExampleUnitTest.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# built application files
*.apk
*.ap_
# files for the dex VM
*.dex
# Java class files
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# generated files
bin/
obj
obj/local
gen/
bin/dexedLibs
bin/res
bin/*.xml
bin/classes
bin/res
bin/jarlist.cache
*.cache
# Local configuration file (sdk path, etc)
local.properties
# Eclipse project files
.classpath
.project
# Proguard folder generated by Eclipse
proguard/
# Intellij project files
*.iml
*.ipr
*.iws
# Gradle
.gradle/
.gradle
build/
build
# gedit
*~
.idea/*.xml
!.idea/codeStyleSettings.xml
!.idea/copyright/*.xml
!.idea/fileColors.xml
!.idea/encodings.xml
!.idea/gradle.xml
!.idea/runConfigurations/*.xml
!.idea/inspectionProfiles/*.xml
.idea/inspectionProfiles/profiles_settings.xml
!.idea/scopes/*.xml
.idea/scopes/scope_settings.xml
!.idea/templateLanguages.xml
!.idea/vcs.xml
profiles_settings.xml
.idea/libraries
libuvccamera/src/main/libs
.idea/copyright
.idea/scopes
.idea/caches
.idea/codeStyles
================================================
FILE: .idea/encodings.xml
================================================
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/inspectionProfiles/Project_Default.xml
================================================
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: README.md
================================================
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 jni/libjpeg, jni/libusb and jin/libuvc folders may have a different license,
see the respective files.
How to compile library
=========
The Gradle build system will build the entire project, including the NDK parts. If you want to build with Gradle build system,
1. make directory on your favorite place (this directory is parent directory of `UVCCamera` project).
2. change directory into the directory.
3. clone this repository with `git clone https://github.com/saki4510t/UVCCamera.git`
4. change directory into `UVCCamera` directory with `cd UVCCamera`
5. build library with all sample projects using `gradle build`
It will takes several minutes to build. Now you can see apks in each `{sample project}/build/outputs/apks` directory.
Or if you want to install and try all sample projects on your device, run `gradle installDebug`.
Note: Just make sure that `local.properties` contains the paths for `sdk.dir` and `ndk.dir`. Or you can set them as enviroment variables of you shell. On some system, you may need add `JAVA_HOME` envairoment valiable that points to JDK directory.
If you want to use Android Studio(unfortunately NDK supporting on Android Studio is very poor though),
1. make directory on your favorite place (this directory is parent directory of `UVCCamera` project).
2. change directory into the directory.
3. clone this repository with `git clone https://github.com/saki4510t/UVCCamera.git`
4. start Android Studio and open the cloned repository using `Open an existing Android Studio project`
5. Android Studio raise some errors but just ignore now. Android Studio generate `local.properties` file. Please open `local.properties` and add `ndk.dir` key to the end of the file. The contents of the file looks like this.
```
sdk.dir={path to Android SDK on your storage}
ndk.dir={path to Android SDK on your storage}
```
Please replace actual path to SDK and NDK on your storage.
Of course you can make `local.properties` by manually instead of using automatically generated ones by Android Studio.
6. Synchronize project
7. execute `Make project` from `Build` menu.
If you want to use build-in VCS on Android Studio, use `Check out project from Version Control` from `https://github.com/saki4510t/UVCCamera.git`. After cloning, Android Studio ask you open the project but don't open now. Instead open the project using `Open an existing Android Studio project`. Other procedures are same as above.
If you still need to use Eclipse or if you don't want to use Gradle with some reason, you can build suing `ndk-build` command.
1. make directory on your favorite place.
2. change directory into the directory.
3. clone this repository with `git clone https://github.com/saki4510t/UVCCamera.git`
4. change directory into `{UVCCamera}/libuvccamera/build/src/main/jni` directory.
5. run `ndk-build`
6. resulted shared libraries are available under `{UVCCamera}/libuvccamera/build/src/main/libs` directory and copy them into your project with directories by manually.
7. copy files under `{UVCCamera}/libuvccamera/build/src/main/java` into your project source directory by manually.
How to use
=========
Please see sample project and/or our web site(but sorry web site is Japanese only).
These sample projects are IntelliJ projects, as is the library.
This library works on at least Android 3.1 or later(API >= 12), but Android 4.0(API >= 14)
or later is better. USB host function must be required.
If you want to try on Android 3.1, you will need some modification(need to remove
setPreviewTexture method in UVCCamera.java etc.), but we have not confirm whether the sample
project run on Android 3.1 yet.
Some sample projects need API>=18 though.
### 2014/07/25
Add some modification to the library and new sample project named "USBCameraTest2".
This new sample project demonstrate how to capture movie using frame data from
UVC camera with MediaCodec and MediaMuxer.
New sample requires at least Android 4.3(API>=18).
This limitation does not come from the library itself but from the limitation of
MediaMuxer and MediaCodec#createInputSurface.
### 2014/09/01
Add new sample project named `USBCameraTest3`
This new sample project demonstrate how to capture audio and movie simultaneously
using frame data from UVC camera and internal mic with MediaCodec and MediaMuxer.
This new sample includes still image capturing as png file.(you can easily change to
save as jpeg) This sample also requires at least Android 4.3(API>=18).
This limitation does not come from the library itself but from the limitation of
MediaMuxer and MediaCodec#createInputSurface.
### 2014/11/16
Add new sample project named `USBCameraTest4`
This new sample project mainly demonstrate how to use offscreen rendering
and record movie without any display.
The communication with camera execute as Service and continue working
even if you stop app. If you stop camera communication, click "stop service" button.
### 2014/12/17
Add bulk transfer mode and update sample projects.
### 2015/01/12
Add wiki page, [HowTo](https://github.com/saki4510t/UVCCamera/wiki/howto "HowTo")
### 2015/01/22
Add method to adjust preview resolution and frame data mode.
### 2015/02/12
Add IFrameCallback interface to get frame data as ByteArray
and new sample project `USBCameraTest5` to demonstrate how to use the callback method.
### 2015/02/18
Add `libUVCCamera` as a library project(source code is almost same as previous release except Android.mk).
All files and directories under `library` directory is deprecated.
### 2015/05/25
libraryProject branch merged to master.
### 2015/05/30
Fixed the issue that DeviceFilter class could not work well when providing venderID, productID etc.
### 2015/06/03
Add new sample project named `USBCameraTest6`
This new sample project mainly demonstrate how to show video images on two TextureView simultaneously, side by side.
### 2015/06/10
Fixed the issue of pixel format is wrong when NV21 mode on calling IFrameCallback#onFrame(U and V plane was swapped) and added YUV420SP mode.
### 2015/06/11
Improve the issue of `USBCameraTest4` that fails to connect/disconnect.
### 2015/07/19
Add new methods to get/set camera features like brightness, contrast etc.
Add new method to get supported resolution from camera as json format.
### 2015/08/17
Add new sample project `USBCameraTest7` to demonstrate how to use two camera at the same time.
### 2015/09/20
Fixed the issue that building native libraries fail on Windows.
### 2015/10/30
Merge pull request(add status and button callback). Thanks Alexey Pelykh.
### 2015/12/16
Add feature so that user can request fps range from Java code when negotiating with camera. Actual resulted fps depends on each UVC camera. Currently there is no way to get resulted fps(will add on future).
### 2016/03/01
update minoru001 branch, experimentaly support streo camera.
### 2016/06/18
replace libjpeg-turbo 1.4.0 with 1.5.0
### 2016/11/17
apply bandwidth factor setting of usbcameratest7 on master branch
### 2016/11/21
Now this repository supports Android N(7.x) and dynamic permission model of Android N and later.
### 2017/01/16
Add new sample app `usbCameraTest8` to show how to set/get uvc control like brightness
### 2017/04/17
Add new sample app on [OpenCVwithUVC](https://github.com/saki4510t/OpenCVwithUVC.git) repository.
This shows the way to pass video images from UVC into `cv::Mat` (after optional applying video effect by OpenGL|ES) and execute image processing by `OpenCV`.
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
// google()
maven { url 'https://maven.google.com' }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
}
}
allprojects {
repositories {
// google()
maven { url 'https://maven.google.com' }
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
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Tue Oct 02 16:16:11 JST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
================================================
FILE: gradle.properties
================================================
# 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.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# 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
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# 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
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# 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\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
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" ] ; 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"`
# 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
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@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
@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=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@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 Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_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=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
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
================================================
FILE: libuvccamera/build.gradle
================================================
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 14
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'
}
}
================================================
FILE: libuvccamera/src/main/AndroidManifest.xml
================================================
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/common/BaseActivity.java
================================================
/*
* 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;
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/common/BaseFragment.java
================================================
/*
* 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;
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/common/BaseService.java
================================================
/*
* 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
}
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/CameraDialog.java
================================================
/*
* 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 filter = DeviceFilter.getDeviceFilters(getActivity(), R.xml.device_filter);
mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0)));
mSpinner.setAdapter(mDeviceListAdapter);
}
private static final class DeviceListAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private final List mList;
public DeviceListAdapter(final Context context, final Listlist) {
mInflater = LayoutInflater.from(context);
mList = list != null ? list : new ArrayList();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public UsbDevice getItem(final int position) {
if ((position >= 0) && (position < mList.size()))
return mList.get(position);
else
return null;
}
@Override
public long getItemId(final int position) {
return position;
}
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem_device, parent, false);
}
if (convertView instanceof CheckedTextView) {
final UsbDevice device = getItem(position);
((CheckedTextView)convertView).setText(
String.format("UVC Camera:(%x:%x:%s)", device.getVendorId(), device.getProductId(), device.getDeviceName()));
}
return convertView;
}
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/DeviceFilter.java
================================================
/*
* 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 getDeviceFilters(final Context context, final int deviceFilterXmlId) {
final XmlPullParser parser = context.getResources().getXml(deviceFilterXmlId);
final List deviceFilters = new ArrayList();
try {
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
final DeviceFilter deviceFilter = readEntryOne(context, parser);
if (deviceFilter != null) {
deviceFilters.add(deviceFilter);
}
}
eventType = parser.next();
}
} catch (final XmlPullParserException e) {
Log.d(TAG, "XmlPullParserException", e);
} catch (final IOException e) {
Log.d(TAG, "IOException", e);
}
return Collections.unmodifiableList(deviceFilters);
}
/**
* read as integer values with default value from xml(w/o exception throws)
* resource integer id is also resolved into integer
* @param parser
* @param namespace
* @param name
* @param defaultValue
* @return
*/
private static final int getAttributeInteger(final Context context, final XmlPullParser parser, final String namespace, final String name, final int defaultValue) {
int result = defaultValue;
try {
String v = parser.getAttributeValue(namespace, name);
if (!TextUtils.isEmpty(v) && v.startsWith("@")) {
final String r = v.substring(1);
final int resId = context.getResources().getIdentifier(r, null, context.getPackageName());
if (resId > 0) {
result = context.getResources().getInteger(resId);
}
} else {
int radix = 10;
if (v != null && v.length() > 2 && v.charAt(0) == '0' &&
(v.charAt(1) == 'x' || v.charAt(1) == 'X')) {
// allow hex values starting with 0x or 0X
radix = 16;
v = v.substring(2);
}
result = Integer.parseInt(v, radix);
}
} catch (final NotFoundException e) {
result = defaultValue;
} catch (final NumberFormatException e) {
result = defaultValue;
} catch (final NullPointerException e) {
result = defaultValue;
}
return result;
}
/**
* read as boolean values with default value from xml(w/o exception throws)
* resource boolean id is also resolved into boolean
* if the value is zero, return false, if the value is non-zero integer, return true
* @param context
* @param parser
* @param namespace
* @param name
* @param defaultValue
* @return
*/
private static final boolean getAttributeBoolean(final Context context, final XmlPullParser parser, final String namespace, final String name, final boolean defaultValue) {
boolean result = defaultValue;
try {
String v = parser.getAttributeValue(namespace, name);
if ("TRUE".equalsIgnoreCase(v)) {
result = true;
} else if ("FALSE".equalsIgnoreCase(v)) {
result = false;
} else if (!TextUtils.isEmpty(v) && v.startsWith("@")) {
final String r = v.substring(1);
final int resId = context.getResources().getIdentifier(r, null, context.getPackageName());
if (resId > 0) {
result = context.getResources().getBoolean(resId);
}
} else {
int radix = 10;
if (v != null && v.length() > 2 && v.charAt(0) == '0' &&
(v.charAt(1) == 'x' || v.charAt(1) == 'X')) {
// allow hex values starting with 0x or 0X
radix = 16;
v = v.substring(2);
}
final int val = Integer.parseInt(v, radix);
result = val != 0;
}
} catch (final NotFoundException e) {
result = defaultValue;
} catch (final NumberFormatException e) {
result = defaultValue;
} catch (final NullPointerException e) {
result = defaultValue;
}
return result;
}
/**
* read as String attribute with default value from xml(w/o exception throws)
* resource string id is also resolved into string
* @param parser
* @param namespace
* @param name
* @param defaultValue
* @return
*/
private static final String getAttributeString(final Context context, final XmlPullParser parser, final String namespace, final String name, final String defaultValue) {
String result = defaultValue;
try {
result = parser.getAttributeValue(namespace, name);
if (result == null)
result = defaultValue;
if (!TextUtils.isEmpty(result) && result.startsWith("@")) {
final String r = result.substring(1);
final int resId = context.getResources().getIdentifier(r, null, context.getPackageName());
if (resId > 0)
result = context.getResources().getString(resId);
}
} catch (final NotFoundException e) {
result = defaultValue;
} catch (final NumberFormatException e) {
result = defaultValue;
} catch (final NullPointerException e) {
result = defaultValue;
}
return result;
}
public static DeviceFilter readEntryOne(final Context context, final XmlPullParser parser)
throws XmlPullParserException, IOException {
int vendorId = -1;
int productId = -1;
int deviceClass = -1;
int deviceSubclass = -1;
int deviceProtocol = -1;
boolean exclude = false;
String manufacturerName = null;
String productName = null;
String serialNumber = null;
boolean hasValue = false;
String tag;
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (!TextUtils.isEmpty(tag) && (tag.equalsIgnoreCase("usb-device"))) {
if (eventType == XmlPullParser.START_TAG) {
hasValue = true;
vendorId = getAttributeInteger(context, parser, null, "vendor-id", -1);
if (vendorId == -1) {
vendorId = getAttributeInteger(context, parser, null, "vendorId", -1);
if (vendorId == -1)
vendorId = getAttributeInteger(context, parser, null, "venderId", -1);
}
productId = getAttributeInteger(context, parser, null, "product-id", -1);
if (productId == -1)
productId = getAttributeInteger(context, parser, null, "productId", -1);
deviceClass = getAttributeInteger(context, parser, null, "class", -1);
deviceSubclass = getAttributeInteger(context, parser, null, "subclass", -1);
deviceProtocol = getAttributeInteger(context, parser, null, "protocol", -1);
manufacturerName = getAttributeString(context, parser, null, "manufacturer-name", null);
if (TextUtils.isEmpty(manufacturerName))
manufacturerName = getAttributeString(context, parser, null, "manufacture", null);
productName = getAttributeString(context, parser, null, "product-name", null);
if (TextUtils.isEmpty(productName))
productName = getAttributeString(context, parser, null, "product", null);
serialNumber = getAttributeString(context, parser, null, "serial-number", null);
if (TextUtils.isEmpty(serialNumber))
serialNumber = getAttributeString(context, parser, null, "serial", null);
exclude = getAttributeBoolean(context, parser, null, "exclude", false);
} else if (eventType == XmlPullParser.END_TAG) {
if (hasValue) {
return new DeviceFilter(vendorId, productId, deviceClass,
deviceSubclass, deviceProtocol, manufacturerName, productName,
serialNumber, exclude);
}
}
}
eventType = parser.next();
}
return null;
}
/* public void write(XmlSerializer serializer) throws IOException {
serializer.startTag(null, "usb-device");
if (mVendorId != -1) {
serializer
.attribute(null, "vendor-id", Integer.toString(mVendorId));
}
if (mProductId != -1) {
serializer.attribute(null, "product-id",
Integer.toString(mProductId));
}
if (mClass != -1) {
serializer.attribute(null, "class", Integer.toString(mClass));
}
if (mSubclass != -1) {
serializer.attribute(null, "subclass", Integer.toString(mSubclass));
}
if (mProtocol != -1) {
serializer.attribute(null, "protocol", Integer.toString(mProtocol));
}
if (mManufacturerName != null) {
serializer.attribute(null, "manufacturer-name", mManufacturerName);
}
if (mProductName != null) {
serializer.attribute(null, "product-name", mProductName);
}
if (mSerialNumber != null) {
serializer.attribute(null, "serial-number", mSerialNumber);
}
serializer.attribute(null, "serial-number", Boolean.toString(isExclude));
serializer.endTag(null, "usb-device");
} */
/**
* 指定したクラス・サブクラス・プロトコルがこのDeviceFilterとマッチするかどうかを返す
* mExcludeフラグは別途#isExcludeか自前でチェックすること
* @param clasz
* @param subclass
* @param protocol
* @return
*/
private boolean matches(final int clasz, final int subclass, final int protocol) {
return ((mClass == -1 || clasz == mClass)
&& (mSubclass == -1 || subclass == mSubclass) && (mProtocol == -1 || protocol == mProtocol));
}
/**
* 指定したUsbDeviceがこのDeviceFilterにマッチするかどうかを返す
* mExcludeフラグは別途#isExcludeか自前でチェックすること
* @param device
* @return
*/
public boolean matches(final UsbDevice device) {
if (mVendorId != -1 && device.getVendorId() != mVendorId) {
return false;
}
if (mProductId != -1 && device.getProductId() != mProductId) {
return false;
}
/* if (mManufacturerName != null && device.getManufacturerName() == null)
return false;
if (mProductName != null && device.getProductName() == null)
return false;
if (mSerialNumber != null && device.getSerialNumber() == null)
return false;
if (mManufacturerName != null && device.getManufacturerName() != null
&& !mManufacturerName.equals(device.getManufacturerName()))
return false;
if (mProductName != null && device.getProductName() != null
&& !mProductName.equals(device.getProductName()))
return false;
if (mSerialNumber != null && device.getSerialNumber() != null
&& !mSerialNumber.equals(device.getSerialNumber()))
return false; */
// check device class/subclass/protocol
if (matches(device.getDeviceClass(), device.getDeviceSubclass(), device.getDeviceProtocol())) {
return true;
}
// if device doesn't match, check the interfaces
final int count = device.getInterfaceCount();
for (int i = 0; i < count; i++) {
final UsbInterface intf = device.getInterface(i);
if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(), intf.getInterfaceProtocol())) {
return true;
}
}
return false;
}
/**
* このDeviceFilterに一致してかつmExcludeがtrueならtrueを返す
* @param device
* @return
*/
public boolean isExclude(final UsbDevice device) {
return isExclude && matches(device);
}
/**
* これって要らんかも, equalsでできる気が
* @param f
* @return
*/
public boolean matches(final DeviceFilter f) {
if (isExclude != f.isExclude) {
return false;
}
if (mVendorId != -1 && f.mVendorId != mVendorId) {
return false;
}
if (mProductId != -1 && f.mProductId != mProductId) {
return false;
}
if (f.mManufacturerName != null && mManufacturerName == null) {
return false;
}
if (f.mProductName != null && mProductName == null) {
return false;
}
if (f.mSerialNumber != null && mSerialNumber == null) {
return false;
}
if (mManufacturerName != null && f.mManufacturerName != null
&& !mManufacturerName.equals(f.mManufacturerName)) {
return false;
}
if (mProductName != null && f.mProductName != null
&& !mProductName.equals(f.mProductName)) {
return false;
}
if (mSerialNumber != null && f.mSerialNumber != null
&& !mSerialNumber.equals(f.mSerialNumber)) {
return false;
}
// check device class/subclass/protocol
return matches(f.mClass, f.mSubclass, f.mProtocol);
}
@Override
public boolean equals(final Object obj) {
// can't compare if we have wildcard strings
if (mVendorId == -1 || mProductId == -1 || mClass == -1
|| mSubclass == -1 || mProtocol == -1) {
return false;
}
if (obj instanceof DeviceFilter) {
final DeviceFilter filter = (DeviceFilter) obj;
if (filter.mVendorId != mVendorId
|| filter.mProductId != mProductId
|| filter.mClass != mClass || filter.mSubclass != mSubclass
|| filter.mProtocol != mProtocol) {
return false;
}
if ((filter.mManufacturerName != null && mManufacturerName == null)
|| (filter.mManufacturerName == null && mManufacturerName != null)
|| (filter.mProductName != null && mProductName == null)
|| (filter.mProductName == null && mProductName != null)
|| (filter.mSerialNumber != null && mSerialNumber == null)
|| (filter.mSerialNumber == null && mSerialNumber != null)) {
return false;
}
if ((filter.mManufacturerName != null && mManufacturerName != null && !mManufacturerName
.equals(filter.mManufacturerName))
|| (filter.mProductName != null && mProductName != null && !mProductName
.equals(filter.mProductName))
|| (filter.mSerialNumber != null && mSerialNumber != null && !mSerialNumber
.equals(filter.mSerialNumber))) {
return false;
}
return (filter.isExclude != isExclude);
}
if (obj instanceof UsbDevice) {
final UsbDevice device = (UsbDevice) obj;
if (isExclude
|| (device.getVendorId() != mVendorId)
|| (device.getProductId() != mProductId)
|| (device.getDeviceClass() != mClass)
|| (device.getDeviceSubclass() != mSubclass)
|| (device.getDeviceProtocol() != mProtocol) ) {
return false;
}
/* if ((mManufacturerName != null && device.getManufacturerName() == null)
|| (mManufacturerName == null && device
.getManufacturerName() != null)
|| (mProductName != null && device.getProductName() == null)
|| (mProductName == null && device.getProductName() != null)
|| (mSerialNumber != null && device.getSerialNumber() == null)
|| (mSerialNumber == null && device.getSerialNumber() != null)) {
return (false);
} */
/* if ((device.getManufacturerName() != null && !mManufacturerName
.equals(device.getManufacturerName()))
|| (device.getProductName() != null && !mProductName
.equals(device.getProductName()))
|| (device.getSerialNumber() != null && !mSerialNumber
.equals(device.getSerialNumber()))) {
return (false);
} */
return true;
}
return false;
}
@Override
public int hashCode() {
return (((mVendorId << 16) | mProductId) ^ ((mClass << 16)
| (mSubclass << 8) | mProtocol));
}
@Override
public String toString() {
return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId="
+ mProductId + ",mClass=" + mClass + ",mSubclass=" + mSubclass
+ ",mProtocol=" + mProtocol
+ ",mManufacturerName=" + mManufacturerName
+ ",mProductName=" + mProductName
+ ",mSerialNumber=" + mSerialNumber
+ ",isExclude=" + isExclude
+ "]";
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/IButtonCallback.java
================================================
package com.serenegiant.usb;
public interface IButtonCallback {
void onButton(int button, int state);
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/IFrameCallback.java
================================================
/*
* 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);
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/IStatusCallback.java
================================================
package com.serenegiant.usb;
import java.nio.ByteBuffer;
public interface IStatusCallback {
void onStatus(int statusClass, int event, int selector, int statusAttribute, ByteBuffer data);
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/Size.java
================================================
/*
* 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 CREATOR = new Parcelable.Creator() {
@Override
public Size createFromParcel(final Parcel source) {
return new Size(source);
}
@Override
public Size[] newArray(final int size) {
return new Size[size];
}
};
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/USBMonitor.java
================================================
/*
* 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.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import com.serenegiant.utils.BuildCheck;
import com.serenegiant.utils.HandlerThreadHandler;
public final class USBMonitor {
private static final boolean DEBUG = false; // TODO set false on production
private static final String TAG = "USBMonitor";
private static final String ACTION_USB_PERMISSION_BASE = "com.serenegiant.USB_PERMISSION.";
private final String ACTION_USB_PERMISSION = ACTION_USB_PERMISSION_BASE + hashCode();
public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
/**
* openしているUsbControlBlock
*/
private final ConcurrentHashMap mCtrlBlocks = new ConcurrentHashMap();
private final SparseArray> mHasPermissions = new SparseArray>();
private final WeakReference mWeakContext;
private final UsbManager mUsbManager;
private final OnDeviceConnectListener mOnDeviceConnectListener;
private PendingIntent mPermissionIntent = null;
private List mDeviceFilters = new ArrayList();
/**
* コールバックをワーカースレッドで呼び出すためのハンドラー
*/
private final Handler mAsyncHandler;
private volatile boolean destroyed;
/**
* USB機器の状態変更時のコールバックリスナー
*/
public interface OnDeviceConnectListener {
/**
* called when device attached
* @param device
*/
public void onAttach(UsbDevice device);
/**
* called when device dettach(after onDisconnect)
* @param device
*/
public void onDettach(UsbDevice device);
/**
* called after device opend
* @param device
* @param ctrlBlock
* @param createNew
*/
public void onConnect(UsbDevice device, UsbControlBlock ctrlBlock, boolean createNew);
/**
* called when USB device removed or its power off (this callback is called after device closing)
* @param device
* @param ctrlBlock
*/
public void onDisconnect(UsbDevice device, UsbControlBlock ctrlBlock);
/**
* called when canceled or could not get permission from user
* @param device
*/
public void onCancel(UsbDevice device);
}
public USBMonitor(final Context context, final OnDeviceConnectListener listener) {
if (DEBUG) Log.v(TAG, "USBMonitor:Constructor");
if (listener == null)
throw new IllegalArgumentException("OnDeviceConnectListener should not null.");
mWeakContext = new WeakReference(context);
mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
mOnDeviceConnectListener = listener;
mAsyncHandler = HandlerThreadHandler.createHandler(TAG);
destroyed = false;
if (DEBUG) Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager);
}
/**
* Release all related resources,
* never reuse again
*/
public void destroy() {
if (DEBUG) Log.i(TAG, "destroy:");
unregister();
if (!destroyed) {
destroyed = true;
// モニターしているUSB機器を全てcloseする
final Set keys = mCtrlBlocks.keySet();
if (keys != null) {
UsbControlBlock ctrlBlock;
try {
for (final UsbDevice key: keys) {
ctrlBlock = mCtrlBlocks.remove(key);
if (ctrlBlock != null) {
ctrlBlock.close();
}
}
} catch (final Exception e) {
Log.e(TAG, "destroy:", e);
}
}
mCtrlBlocks.clear();
try {
mAsyncHandler.getLooper().quit();
} catch (final Exception e) {
Log.e(TAG, "destroy:", e);
}
}
}
/**
* register BroadcastReceiver to monitor USB events
* @throws IllegalStateException
*/
public synchronized void register() throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
if (mPermissionIntent == null) {
if (DEBUG) Log.i(TAG, "register:");
final Context context = mWeakContext.get();
if (context != null) {
mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
// ACTION_USB_DEVICE_ATTACHED never comes on some devices so it should not be added here
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
context.registerReceiver(mUsbReceiver, filter);
}
// start connection check
mDeviceCounts = 0;
mAsyncHandler.postDelayed(mDeviceCheckRunnable, 1000);
}
}
/**
* unregister BroadcastReceiver
* @throws IllegalStateException
*/
public synchronized void unregister() throws IllegalStateException {
// 接続チェック用Runnableを削除
mDeviceCounts = 0;
if (!destroyed) {
mAsyncHandler.removeCallbacks(mDeviceCheckRunnable);
}
if (mPermissionIntent != null) {
// if (DEBUG) Log.i(TAG, "unregister:");
final Context context = mWeakContext.get();
try {
if (context != null) {
context.unregisterReceiver(mUsbReceiver);
}
} catch (final Exception e) {
Log.w(TAG, e);
}
mPermissionIntent = null;
}
}
public synchronized boolean isRegistered() {
return !destroyed && (mPermissionIntent != null);
}
/**
* set device filter
* @param filter
* @throws IllegalStateException
*/
public void setDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.clear();
mDeviceFilters.add(filter);
}
/**
* デバイスフィルターを追加
* @param filter
* @throws IllegalStateException
*/
public void addDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.add(filter);
}
/**
* デバイスフィルターを削除
* @param filter
* @throws IllegalStateException
*/
public void removeDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.remove(filter);
}
/**
* set device filters
* @param filters
* @throws IllegalStateException
*/
public void setDeviceFilter(final List filters) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.clear();
mDeviceFilters.addAll(filters);
}
/**
* add device filters
* @param filters
* @throws IllegalStateException
*/
public void addDeviceFilter(final List filters) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.addAll(filters);
}
/**
* remove device filters
* @param filters
*/
public void removeDeviceFilter(final List filters) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
mDeviceFilters.removeAll(filters);
}
/**
* return the number of connected USB devices that matched device filter
* @return
* @throws IllegalStateException
*/
public int getDeviceCount() throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
return getDeviceList().size();
}
/**
* return device list, return empty list if no device matched
* @return
* @throws IllegalStateException
*/
public List getDeviceList() throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
return getDeviceList(mDeviceFilters);
}
/**
* return device list, return empty list if no device matched
* @param filters
* @return
* @throws IllegalStateException
*/
public List getDeviceList(final List filters) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
final HashMap deviceList = mUsbManager.getDeviceList();
final List result = new ArrayList();
if (deviceList != null) {
if ((filters == null) || filters.isEmpty()) {
result.addAll(deviceList.values());
} else {
for (final UsbDevice device: deviceList.values() ) {
for (final DeviceFilter filter: filters) {
if ((filter != null) && filter.matches(device)) {
// when filter matches
if (!filter.isExclude) {
result.add(device);
}
break;
}
}
}
}
}
return result;
}
/**
* return device list, return empty list if no device matched
* @param filter
* @return
* @throws IllegalStateException
*/
public List getDeviceList(final DeviceFilter filter) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
final HashMap deviceList = mUsbManager.getDeviceList();
final List result = new ArrayList();
if (deviceList != null) {
for (final UsbDevice device: deviceList.values() ) {
if ((filter == null) || (filter.matches(device) && !filter.isExclude)) {
result.add(device);
}
}
}
return result;
}
/**
* get USB device list, without filter
* @return
* @throws IllegalStateException
*/
public Iterator getDevices() throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
Iterator iterator = null;
final HashMap list = mUsbManager.getDeviceList();
if (list != null)
iterator = list.values().iterator();
return iterator;
}
/**
* output device list to LogCat
*/
public final void dumpDevices() {
final HashMap list = mUsbManager.getDeviceList();
if (list != null) {
final Set keys = list.keySet();
if (keys != null && keys.size() > 0) {
final StringBuilder sb = new StringBuilder();
for (final String key: keys) {
final UsbDevice device = list.get(key);
final int num_interface = device != null ? device.getInterfaceCount() : 0;
sb.setLength(0);
for (int i = 0; i < num_interface; i++) {
sb.append(String.format(Locale.US, "interface%d:%s", i, device.getInterface(i).toString()));
}
Log.i(TAG, "key=" + key + ":" + device + ":" + sb.toString());
}
} else {
Log.i(TAG, "no device");
}
} else {
Log.i(TAG, "no device");
}
}
/**
* return whether the specific Usb device has permission
* @param device
* @return true: 指定したUsbDeviceにパーミッションがある
* @throws IllegalStateException
*/
public final boolean hasPermission(final UsbDevice device) throws IllegalStateException {
if (destroyed) throw new IllegalStateException("already destroyed");
return updatePermission(device, device != null && mUsbManager.hasPermission(device));
}
/**
* 内部で保持しているパーミッション状態を更新
* @param device
* @param hasPermission
* @return hasPermission
*/
private boolean updatePermission(final UsbDevice device, final boolean hasPermission) {
final int deviceKey = getDeviceKey(device, true);
synchronized (mHasPermissions) {
if (hasPermission) {
if (mHasPermissions.get(deviceKey) == null) {
mHasPermissions.put(deviceKey, new WeakReference(device));
}
} else {
mHasPermissions.remove(deviceKey);
}
}
return hasPermission;
}
/**
* request permission to access to USB device
* @param device
* @return true if fail to request permission
*/
public synchronized boolean requestPermission(final UsbDevice device) {
// if (DEBUG) Log.v(TAG, "requestPermission:device=" + device);
boolean result = false;
if (isRegistered()) {
if (device != null) {
if (mUsbManager.hasPermission(device)) {
// call onConnect if app already has permission
processConnect(device);
} else {
try {
// パーミッションがなければ要求する
mUsbManager.requestPermission(device, mPermissionIntent);
} catch (final Exception e) {
// Android5.1.xのGALAXY系でandroid.permission.sec.MDM_APP_MGMTという意味不明の例外生成するみたい
Log.w(TAG, e);
processCancel(device);
result = true;
}
}
} else {
processCancel(device);
result = true;
}
} else {
processCancel(device);
result = true;
}
return result;
}
/**
* 指定したUsbDeviceをopenする
* @param device
* @return
* @throws SecurityException パーミッションがなければSecurityExceptionを投げる
*/
public UsbControlBlock openDevice(final UsbDevice device) throws SecurityException {
if (hasPermission(device)) {
UsbControlBlock result = mCtrlBlocks.get(device);
if (result == null) {
result = new UsbControlBlock(USBMonitor.this, device); // この中でopenDeviceする
mCtrlBlocks.put(device, result);
}
return result;
} else {
throw new SecurityException("has no permission");
}
}
/**
* BroadcastReceiver for USB permission
*/
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
if (destroyed) return;
final String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
// when received the result of requesting USB permission
synchronized (USBMonitor.this) {
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
// get permission, call onConnect
processConnect(device);
}
} else {
// failed to get permission
processCancel(device);
}
}
} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
updatePermission(device, hasPermission(device));
processAttach(device);
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
// when device removed
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
UsbControlBlock ctrlBlock = mCtrlBlocks.remove(device);
if (ctrlBlock != null) {
// cleanup
ctrlBlock.close();
}
mDeviceCounts = 0;
processDettach(device);
}
}
}
};
/** number of connected & detected devices */
private volatile int mDeviceCounts = 0;
/**
* periodically check connected devices and if it changed, call onAttach
*/
private final Runnable mDeviceCheckRunnable = new Runnable() {
@Override
public void run() {
if (destroyed) return;
final List devices = getDeviceList();
final int n = devices.size();
final int hasPermissionCounts;
final int m;
synchronized (mHasPermissions) {
hasPermissionCounts = mHasPermissions.size();
mHasPermissions.clear();
for (final UsbDevice device: devices) {
hasPermission(device);
}
m = mHasPermissions.size();
}
if ((n > mDeviceCounts) || (m > hasPermissionCounts)) {
mDeviceCounts = n;
if (mOnDeviceConnectListener != null) {
for (int i = 0; i < n; i++) {
final UsbDevice device = devices.get(i);
mAsyncHandler.post(new Runnable() {
@Override
public void run() {
mOnDeviceConnectListener.onAttach(device);
}
});
}
}
}
mAsyncHandler.postDelayed(this, 2000); // confirm every 2 seconds
}
};
/**
* open specific USB device
* @param device
*/
private final void processConnect(final UsbDevice device) {
if (destroyed) return;
updatePermission(device, true);
mAsyncHandler.post(new Runnable() {
@Override
public void run() {
if (DEBUG) Log.v(TAG, "processConnect:device=" + device);
UsbControlBlock ctrlBlock;
final boolean createNew;
ctrlBlock = mCtrlBlocks.get(device);
if (ctrlBlock == null) {
ctrlBlock = new UsbControlBlock(USBMonitor.this, device);
mCtrlBlocks.put(device, ctrlBlock);
createNew = true;
} else {
createNew = false;
}
if (mOnDeviceConnectListener != null) {
mOnDeviceConnectListener.onConnect(device, ctrlBlock, createNew);
}
}
});
}
private final void processCancel(final UsbDevice device) {
if (destroyed) return;
if (DEBUG) Log.v(TAG, "processCancel:");
updatePermission(device, false);
if (mOnDeviceConnectListener != null) {
mAsyncHandler.post(new Runnable() {
@Override
public void run() {
mOnDeviceConnectListener.onCancel(device);
}
});
}
}
private final void processAttach(final UsbDevice device) {
if (destroyed) return;
if (DEBUG) Log.v(TAG, "processAttach:");
if (mOnDeviceConnectListener != null) {
mAsyncHandler.post(new Runnable() {
@Override
public void run() {
mOnDeviceConnectListener.onAttach(device);
}
});
}
}
private final void processDettach(final UsbDevice device) {
if (destroyed) return;
if (DEBUG) Log.v(TAG, "processDettach:");
if (mOnDeviceConnectListener != null) {
mAsyncHandler.post(new Runnable() {
@Override
public void run() {
mOnDeviceConnectListener.onDettach(device);
}
});
}
}
/**
* USB機器毎の設定保存用にデバイスキー名を生成する。
* ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
* 同種の製品だと同じキー名になるので注意
* @param device nullなら空文字列を返す
* @return
*/
public static final String getDeviceKeyName(final UsbDevice device) {
return getDeviceKeyName(device, null, false);
}
/**
* USB機器毎の設定保存用にデバイスキー名を生成する。
* useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
* @param device
* @param useNewAPI
* @return
*/
public static final String getDeviceKeyName(final UsbDevice device, final boolean useNewAPI) {
return getDeviceKeyName(device, null, useNewAPI);
}
/**
* USB機器毎の設定保存用にデバイスキー名を生成する。この機器名をHashMapのキーにする
* UsbDeviceがopenしている時のみ有効
* ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
* serialがnullや空文字でなければserialを含めたデバイスキー名を生成する
* useNewAPI=trueでAPIレベルを満たしていればマニュファクチャ名, バージョン, コンフィギュレーションカウントも使う
* @param device nullなら空文字列を返す
* @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得
* @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による)
* @return
*/
@SuppressLint("NewApi")
public static final String getDeviceKeyName(final UsbDevice device, final String serial, final boolean useNewAPI) {
if (device == null) return "";
final StringBuilder sb = new StringBuilder();
sb.append(device.getVendorId()); sb.append("#"); // API >= 12
sb.append(device.getProductId()); sb.append("#"); // API >= 12
sb.append(device.getDeviceClass()); sb.append("#"); // API >= 12
sb.append(device.getDeviceSubclass()); sb.append("#"); // API >= 12
sb.append(device.getDeviceProtocol()); // API >= 12
if (!TextUtils.isEmpty(serial)) {
sb.append("#"); sb.append(serial);
}
if (useNewAPI && BuildCheck.isAndroid5()) {
sb.append("#");
if (TextUtils.isEmpty(serial)) {
sb.append(device.getSerialNumber()); sb.append("#"); // API >= 21
}
sb.append(device.getManufacturerName()); sb.append("#"); // API >= 21
sb.append(device.getConfigurationCount()); sb.append("#"); // API >= 21
if (BuildCheck.isMarshmallow()) {
sb.append(device.getVersion()); sb.append("#"); // API >= 23
}
}
// if (DEBUG) Log.v(TAG, "getDeviceKeyName:" + sb.toString());
return sb.toString();
}
/**
* デバイスキーを整数として取得
* getDeviceKeyNameで得られる文字列のhasCodeを取得
* ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
* 同種の製品だと同じデバイスキーになるので注意
* @param device nullなら0を返す
* @return
*/
public static final int getDeviceKey(final UsbDevice device) {
return device != null ? getDeviceKeyName(device, null, false).hashCode() : 0;
}
/**
* デバイスキーを整数として取得
* getDeviceKeyNameで得られる文字列のhasCodeを取得
* useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
* @param device
* @param useNewAPI
* @return
*/
public static final int getDeviceKey(final UsbDevice device, final boolean useNewAPI) {
return device != null ? getDeviceKeyName(device, null, useNewAPI).hashCode() : 0;
}
/**
* デバイスキーを整数として取得
* getDeviceKeyNameで得られる文字列のhasCodeを取得
* serialがnullでuseNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
* @param device nullなら0を返す
* @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得
* @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による)
* @return
*/
public static final int getDeviceKey(final UsbDevice device, final String serial, final boolean useNewAPI) {
return device != null ? getDeviceKeyName(device, serial, useNewAPI).hashCode() : 0;
}
public static class UsbDeviceInfo {
public String usb_version;
public String manufacturer;
public String product;
public String version;
public String serial;
private void clear() {
usb_version = manufacturer = product = version = serial = null;
}
@Override
public String toString() {
return String.format("UsbDevice:usb_version=%s,manufacturer=%s,product=%s,version=%s,serial=%s",
usb_version != null ? usb_version : "",
manufacturer != null ? manufacturer : "",
product != null ? product : "",
version != null ? version : "",
serial != null ? serial : "");
}
}
private static final int USB_DIR_OUT = 0;
private static final int USB_DIR_IN = 0x80;
private static final int USB_TYPE_MASK = (0x03 << 5);
private static final int USB_TYPE_STANDARD = (0x00 << 5);
private static final int USB_TYPE_CLASS = (0x01 << 5);
private static final int USB_TYPE_VENDOR = (0x02 << 5);
private static final int USB_TYPE_RESERVED = (0x03 << 5);
private static final int USB_RECIP_MASK = 0x1f;
private static final int USB_RECIP_DEVICE = 0x00;
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int USB_RECIP_ENDPOINT = 0x02;
private static final int USB_RECIP_OTHER = 0x03;
private static final int USB_RECIP_PORT = 0x04;
private static final int USB_RECIP_RPIPE = 0x05;
private static final int USB_REQ_GET_STATUS = 0x00;
private static final int USB_REQ_CLEAR_FEATURE = 0x01;
private static final int USB_REQ_SET_FEATURE = 0x03;
private static final int USB_REQ_SET_ADDRESS = 0x05;
private static final int USB_REQ_GET_DESCRIPTOR = 0x06;
private static final int USB_REQ_SET_DESCRIPTOR = 0x07;
private static final int USB_REQ_GET_CONFIGURATION = 0x08;
private static final int USB_REQ_SET_CONFIGURATION = 0x09;
private static final int USB_REQ_GET_INTERFACE = 0x0A;
private static final int USB_REQ_SET_INTERFACE = 0x0B;
private static final int USB_REQ_SYNCH_FRAME = 0x0C;
private static final int USB_REQ_SET_SEL = 0x30;
private static final int USB_REQ_SET_ISOCH_DELAY = 0x31;
private static final int USB_REQ_SET_ENCRYPTION = 0x0D;
private static final int USB_REQ_GET_ENCRYPTION = 0x0E;
private static final int USB_REQ_RPIPE_ABORT = 0x0E;
private static final int USB_REQ_SET_HANDSHAKE = 0x0F;
private static final int USB_REQ_RPIPE_RESET = 0x0F;
private static final int USB_REQ_GET_HANDSHAKE = 0x10;
private static final int USB_REQ_SET_CONNECTION = 0x11;
private static final int USB_REQ_SET_SECURITY_DATA = 0x12;
private static final int USB_REQ_GET_SECURITY_DATA = 0x13;
private static final int USB_REQ_SET_WUSB_DATA = 0x14;
private static final int USB_REQ_LOOPBACK_DATA_WRITE = 0x15;
private static final int USB_REQ_LOOPBACK_DATA_READ = 0x16;
private static final int USB_REQ_SET_INTERFACE_DS = 0x17;
private static final int USB_REQ_STANDARD_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE); // 0x10
private static final int USB_REQ_STANDARD_DEVICE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE); // 0x90
private static final int USB_REQ_STANDARD_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE); // 0x11
private static final int USB_REQ_STANDARD_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE); // 0x91
private static final int USB_REQ_STANDARD_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); // 0x12
private static final int USB_REQ_STANDARD_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT); // 0x92
private static final int USB_REQ_CS_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0x20
private static final int USB_REQ_CS_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0xa0
private static final int USB_REQ_CS_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0x21
private static final int USB_REQ_CS_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0xa1
private static final int USB_REQ_CS_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0x22
private static final int USB_REQ_CS_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0xa2
private static final int USB_REQ_VENDER_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0x40
private static final int USB_REQ_VENDER_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE); // 0xc0
private static final int USB_REQ_VENDER_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0x41
private static final int USB_REQ_VENDER_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); // 0xc1
private static final int USB_REQ_VENDER_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0x42
private static final int USB_REQ_VENDER_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT); // 0xc2
private static final int USB_DT_DEVICE = 0x01;
private static final int USB_DT_CONFIG = 0x02;
private static final int USB_DT_STRING = 0x03;
private static final int USB_DT_INTERFACE = 0x04;
private static final int USB_DT_ENDPOINT = 0x05;
private static final int USB_DT_DEVICE_QUALIFIER = 0x06;
private static final int USB_DT_OTHER_SPEED_CONFIG = 0x07;
private static final int USB_DT_INTERFACE_POWER = 0x08;
private static final int USB_DT_OTG = 0x09;
private static final int USB_DT_DEBUG = 0x0a;
private static final int USB_DT_INTERFACE_ASSOCIATION = 0x0b;
private static final int USB_DT_SECURITY = 0x0c;
private static final int USB_DT_KEY = 0x0d;
private static final int USB_DT_ENCRYPTION_TYPE = 0x0e;
private static final int USB_DT_BOS = 0x0f;
private static final int USB_DT_DEVICE_CAPABILITY = 0x10;
private static final int USB_DT_WIRELESS_ENDPOINT_COMP = 0x11;
private static final int USB_DT_WIRE_ADAPTER = 0x21;
private static final int USB_DT_RPIPE = 0x22;
private static final int USB_DT_CS_RADIO_CONTROL = 0x23;
private static final int USB_DT_PIPE_USAGE = 0x24;
private static final int USB_DT_SS_ENDPOINT_COMP = 0x30;
private static final int USB_DT_CS_DEVICE = (USB_TYPE_CLASS | USB_DT_DEVICE);
private static final int USB_DT_CS_CONFIG = (USB_TYPE_CLASS | USB_DT_CONFIG);
private static final int USB_DT_CS_STRING = (USB_TYPE_CLASS | USB_DT_STRING);
private static final int USB_DT_CS_INTERFACE = (USB_TYPE_CLASS | USB_DT_INTERFACE);
private static final int USB_DT_CS_ENDPOINT = (USB_TYPE_CLASS | USB_DT_ENDPOINT);
private static final int USB_DT_DEVICE_SIZE = 18;
/**
* 指定したIDのStringディスクリプタから文字列を取得する。取得できなければnull
* @param connection
* @param id
* @param languageCount
* @param languages
* @return
*/
private static String getString(final UsbDeviceConnection connection, final int id, final int languageCount, final byte[] languages) {
final byte[] work = new byte[256];
String result = null;
for (int i = 1; i <= languageCount; i++) {
int ret = connection.controlTransfer(
USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE
USB_REQ_GET_DESCRIPTOR,
(USB_DT_STRING << 8) | id, languages[i], work, 256, 0);
if ((ret > 2) && (work[0] == ret) && (work[1] == USB_DT_STRING)) {
// skip first two bytes(bLength & bDescriptorType), and copy the rest to the string
try {
result = new String(work, 2, ret - 2, "UTF-16LE");
if (!"Љ".equals(result)) { // 変なゴミが返ってくる時がある
break;
} else {
result = null;
}
} catch (final UnsupportedEncodingException e) {
// ignore
}
}
}
return result;
}
/**
* ベンダー名・製品名・バージョン・シリアルを取得する
* @param device
* @return
*/
public UsbDeviceInfo getDeviceInfo(final UsbDevice device) {
return updateDeviceInfo(mUsbManager, device, null);
}
/**
* ベンダー名・製品名・バージョン・シリアルを取得する
* #updateDeviceInfo(final UsbManager, final UsbDevice, final UsbDeviceInfo)のヘルパーメソッド
* @param context
* @param device
* @return
*/
public static UsbDeviceInfo getDeviceInfo(final Context context, final UsbDevice device) {
return updateDeviceInfo((UsbManager)context.getSystemService(Context.USB_SERVICE), device, new UsbDeviceInfo());
}
/**
* ベンダー名・製品名・バージョン・シリアルを取得する
* @param manager
* @param device
* @param _info
* @return
*/
public static UsbDeviceInfo updateDeviceInfo(final UsbManager manager, final UsbDevice device, final UsbDeviceInfo _info) {
final UsbDeviceInfo info = _info != null ? _info : new UsbDeviceInfo();
info.clear();
if (device != null) {
if (BuildCheck.isLollipop()) {
info.manufacturer = device.getManufacturerName();
info.product = device.getProductName();
info.serial = device.getSerialNumber();
}
if (BuildCheck.isMarshmallow()) {
info.usb_version = device.getVersion();
}
if ((manager != null) && manager.hasPermission(device)) {
final UsbDeviceConnection connection = manager.openDevice(device);
final byte[] desc = connection.getRawDescriptors();
if (TextUtils.isEmpty(info.usb_version)) {
info.usb_version = String.format("%x.%02x", ((int)desc[3] & 0xff), ((int)desc[2] & 0xff));
}
if (TextUtils.isEmpty(info.version)) {
info.version = String.format("%x.%02x", ((int)desc[13] & 0xff), ((int)desc[12] & 0xff));
}
if (TextUtils.isEmpty(info.serial)) {
info.serial = connection.getSerial();
}
final byte[] languages = new byte[256];
int languageCount = 0;
// controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)
try {
int result = connection.controlTransfer(
USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE
USB_REQ_GET_DESCRIPTOR,
(USB_DT_STRING << 8) | 0, 0, languages, 256, 0);
if (result > 0) {
languageCount = (result - 2) / 2;
}
if (languageCount > 0) {
if (TextUtils.isEmpty(info.manufacturer)) {
info.manufacturer = getString(connection, desc[14], languageCount, languages);
}
if (TextUtils.isEmpty(info.product)) {
info.product = getString(connection, desc[15], languageCount, languages);
}
if (TextUtils.isEmpty(info.serial)) {
info.serial = getString(connection, desc[16], languageCount, languages);
}
}
} finally {
connection.close();
}
}
if (TextUtils.isEmpty(info.manufacturer)) {
info.manufacturer = USBVendorId.vendorName(device.getVendorId());
}
if (TextUtils.isEmpty(info.manufacturer)) {
info.manufacturer = String.format("%04x", device.getVendorId());
}
if (TextUtils.isEmpty(info.product)) {
info.product = String.format("%04x", device.getProductId());
}
}
return info;
}
/**
* control class
* never reuse the instance when it closed
*/
public static final class UsbControlBlock implements Cloneable {
private final WeakReference mWeakMonitor;
private final WeakReference mWeakDevice;
protected UsbDeviceConnection mConnection;
protected final UsbDeviceInfo mInfo;
private final int mBusNum;
private final int mDevNum;
private final SparseArray> mInterfaces = new SparseArray>();
/**
* this class needs permission to access USB device before constructing
* @param monitor
* @param device
*/
private UsbControlBlock(final USBMonitor monitor, final UsbDevice device) {
if (DEBUG) Log.i(TAG, "UsbControlBlock:constructor");
mWeakMonitor = new WeakReference(monitor);
mWeakDevice = new WeakReference(device);
mConnection = monitor.mUsbManager.openDevice(device);
mInfo = updateDeviceInfo(monitor.mUsbManager, device, null);
final String name = device.getDeviceName();
final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null;
int busnum = 0;
int devnum = 0;
if (v != null) {
busnum = Integer.parseInt(v[v.length-2]);
devnum = Integer.parseInt(v[v.length-1]);
}
mBusNum = busnum;
mDevNum = devnum;
// if (DEBUG) {
if (mConnection != null) {
final int desc = mConnection.getFileDescriptor();
final byte[] rawDesc = mConnection.getRawDescriptors();
Log.i(TAG, String.format(Locale.US, "name=%s,desc=%d,busnum=%d,devnum=%d,rawDesc=", name, desc, busnum, devnum) + rawDesc);
} else {
Log.e(TAG, "could not connect to device " + name);
}
// }
}
/**
* copy constructor
* @param src
* @throws IllegalStateException
*/
private UsbControlBlock(final UsbControlBlock src) throws IllegalStateException {
final USBMonitor monitor = src.getUSBMonitor();
final UsbDevice device = src.getDevice();
if (device == null) {
throw new IllegalStateException("device may already be removed");
}
mConnection = monitor.mUsbManager.openDevice(device);
if (mConnection == null) {
throw new IllegalStateException("device may already be removed or have no permission");
}
mInfo = updateDeviceInfo(monitor.mUsbManager, device, null);
mWeakMonitor = new WeakReference(monitor);
mWeakDevice = new WeakReference(device);
mBusNum = src.mBusNum;
mDevNum = src.mDevNum;
// FIXME USBMonitor.mCtrlBlocksに追加する(今はHashMapなので追加すると置き換わってしまうのでだめ, ListかHashMapにListをぶら下げる?)
}
/**
* duplicate by clone
* need permission
* USBMonitor never handle cloned UsbControlBlock, you should release it after using it.
* @return
* @throws CloneNotSupportedException
*/
@Override
public UsbControlBlock clone() throws CloneNotSupportedException {
final UsbControlBlock ctrlblock;
try {
ctrlblock = new UsbControlBlock(this);
} catch (final IllegalStateException e) {
throw new CloneNotSupportedException(e.getMessage());
}
return ctrlblock;
}
public USBMonitor getUSBMonitor() {
return mWeakMonitor.get();
}
public final UsbDevice getDevice() {
return mWeakDevice.get();
}
/**
* get device name
* @return
*/
public String getDeviceName() {
final UsbDevice device = mWeakDevice.get();
return device != null ? device.getDeviceName() : "";
}
/**
* get device id
* @return
*/
public int getDeviceId() {
final UsbDevice device = mWeakDevice.get();
return device != null ? device.getDeviceId() : 0;
}
/**
* get device key string
* @return same value if the devices has same vendor id, product id, device class, device subclass and device protocol
*/
public String getDeviceKeyName() {
return USBMonitor.getDeviceKeyName(mWeakDevice.get());
}
/**
* get device key string
* @param useNewAPI if true, try to use serial number
* @return
* @throws IllegalStateException
*/
public String getDeviceKeyName(final boolean useNewAPI) throws IllegalStateException {
if (useNewAPI) checkConnection();
return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, useNewAPI);
}
/**
* get device key
* @return
* @throws IllegalStateException
*/
public int getDeviceKey() throws IllegalStateException {
checkConnection();
return USBMonitor.getDeviceKey(mWeakDevice.get());
}
/**
* get device key
* @param useNewAPI if true, try to use serial number
* @return
* @throws IllegalStateException
*/
public int getDeviceKey(final boolean useNewAPI) throws IllegalStateException {
if (useNewAPI) checkConnection();
return USBMonitor.getDeviceKey(mWeakDevice.get(), mInfo.serial, useNewAPI);
}
/**
* get device key string
* if device has serial number, use it
* @return
*/
public String getDeviceKeyNameWithSerial() {
return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, false);
}
/**
* get device key
* if device has serial number, use it
* @return
*/
public int getDeviceKeyWithSerial() {
return getDeviceKeyNameWithSerial().hashCode();
}
/**
* get UsbDeviceConnection
* @return
*/
public synchronized UsbDeviceConnection getConnection() {
return mConnection;
}
/**
* get file descriptor to access USB device
* @return
* @throws IllegalStateException
*/
public synchronized int getFileDescriptor() throws IllegalStateException {
checkConnection();
return mConnection.getFileDescriptor();
}
/**
* get raw descriptor for the USB device
* @return
* @throws IllegalStateException
*/
public synchronized byte[] getRawDescriptors() throws IllegalStateException {
checkConnection();
return mConnection.getRawDescriptors();
}
/**
* get vendor id
* @return
*/
public int getVenderId() {
final UsbDevice device = mWeakDevice.get();
return device != null ? device.getVendorId() : 0;
}
/**
* get product id
* @return
*/
public int getProductId() {
final UsbDevice device = mWeakDevice.get();
return device != null ? device.getProductId() : 0;
}
/**
* get version string of USB
* @return
*/
public String getUsbVersion() {
return mInfo.usb_version;
}
/**
* get manufacture
* @return
*/
public String getManufacture() {
return mInfo.manufacturer;
}
/**
* get product name
* @return
*/
public String getProductName() {
return mInfo.product;
}
/**
* get version
* @return
*/
public String getVersion() {
return mInfo.version;
}
/**
* get serial number
* @return
*/
public String getSerial() {
return mInfo.serial;
}
public int getBusNum() {
return mBusNum;
}
public int getDevNum() {
return mDevNum;
}
/**
* get interface
* @param interface_id
* @throws IllegalStateException
*/
public synchronized UsbInterface getInterface(final int interface_id) throws IllegalStateException {
return getInterface(interface_id, 0);
}
/**
* get interface
* @param interface_id
* @param altsetting
* @return
* @throws IllegalStateException
*/
public synchronized UsbInterface getInterface(final int interface_id, final int altsetting) throws IllegalStateException {
checkConnection();
SparseArray intfs = mInterfaces.get(interface_id);
if (intfs == null) {
intfs = new SparseArray();
mInterfaces.put(interface_id, intfs);
}
UsbInterface intf = intfs.get(altsetting);
if (intf == null) {
final UsbDevice device = mWeakDevice.get();
final int n = device.getInterfaceCount();
for (int i = 0; i < n; i++) {
final UsbInterface temp = device.getInterface(i);
if ((temp.getId() == interface_id) && (temp.getAlternateSetting() == altsetting)) {
intf = temp;
break;
}
}
if (intf != null) {
intfs.append(altsetting, intf);
}
}
return intf;
}
/**
* open specific interface
* @param intf
*/
public synchronized void claimInterface(final UsbInterface intf) {
claimInterface(intf, true);
}
public synchronized void claimInterface(final UsbInterface intf, final boolean force) {
checkConnection();
mConnection.claimInterface(intf, force);
}
/**
* close interface
* @param intf
* @throws IllegalStateException
*/
public synchronized void releaseInterface(final UsbInterface intf) throws IllegalStateException {
checkConnection();
final SparseArray intfs = mInterfaces.get(intf.getId());
if (intfs != null) {
final int index = intfs.indexOfValue(intf);
intfs.removeAt(index);
if (intfs.size() == 0) {
mInterfaces.remove(intf.getId());
}
}
mConnection.releaseInterface(intf);
}
/**
* Close device
* This also close interfaces if they are opened in Java side
*/
public synchronized void close() {
if (DEBUG) Log.i(TAG, "UsbControlBlock#close:");
if (mConnection != null) {
final int n = mInterfaces.size();
for (int i = 0; i < n; i++) {
final SparseArray intfs = mInterfaces.valueAt(i);
if (intfs != null) {
final int m = intfs.size();
for (int j = 0; j < m; j++) {
final UsbInterface intf = intfs.valueAt(j);
mConnection.releaseInterface(intf);
}
intfs.clear();
}
}
mInterfaces.clear();
mConnection.close();
mConnection = null;
final USBMonitor monitor = mWeakMonitor.get();
if (monitor != null) {
if (monitor.mOnDeviceConnectListener != null) {
monitor.mOnDeviceConnectListener.onDisconnect(mWeakDevice.get(), UsbControlBlock.this);
}
monitor.mCtrlBlocks.remove(getDevice());
}
}
}
@Override
public boolean equals(final Object o) {
if (o == null) return false;
if (o instanceof UsbControlBlock) {
final UsbDevice device = ((UsbControlBlock) o).getDevice();
return device == null ? mWeakDevice.get() == null
: device.equals(mWeakDevice.get());
} else if (o instanceof UsbDevice) {
return o.equals(mWeakDevice.get());
}
return super.equals(o);
}
// @Override
// protected void finalize() throws Throwable {
/// close();
// super.finalize();
// }
private synchronized void checkConnection() throws IllegalStateException {
if (mConnection == null) {
throw new IllegalStateException("already closed");
}
}
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/USBVendorId.java
================================================
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
* may have a different license, see the respective files.
*/
package com.serenegiant.usb;
import android.util.SparseArray;
public class USBVendorId {
private static final SparseArray IDS = new SparseArray();
public static String vendorName(final int vendor_id) {
return IDS.get(vendor_id);
}
static {
IDS.put(10006, "YUEN DA ELECTRONIC PRODUCTS FACTORY");
IDS.put(10013, "Gionee Communication Equipment Co., Ltd. ShenZhen");
IDS.put(10022, "Universal Electronics Inc. (dba: TVIEW)");
IDS.put(1003, "Atmel Corporation");
IDS.put(1006, "Mitsumi");
IDS.put(1008, "HP Inc.");
IDS.put(10112, "M31 Technology Corp.");
IDS.put(10113, "Liteconn Co., Ltd.");
IDS.put(10121, "Suzhou WEIJU Electronics Technology Co., Ltd.");
IDS.put(10144, "Mondokey Limited");
IDS.put(10149, "Advantest Corporation");
IDS.put(10150, "iRobot Corporation");
IDS.put(1020, "Elitegroup Computer Systems");
IDS.put(1021, "Xilinx Inc.");
IDS.put(10226, "Sibridge Tech.");
IDS.put(1026, "ALi Corporation");
IDS.put(1027, "Future Technology Devices International Limited");
IDS.put(10275, "Dongguan Jiumutong Industry Co., Ltd.");
IDS.put(10289, "Power Integrations");
IDS.put(10291, "Oculus VR, Inc.");
IDS.put(10300, "HIGH TEK HARNESS ENTERPRISE CO., LTD.");
IDS.put(10316, "Full in Hope Co., Ltd.");
IDS.put(1032, "Quanta Computer Inc.");
IDS.put(10329, "Viconn Technology (HK) Co., Ltd.");
IDS.put(1033, "NEC Corporation");
IDS.put(1035, "Weltrend Semiconductor");
IDS.put(1037, "VIA Technologies, Inc.");
IDS.put(10374, "Seeed Technology Co., Ltd.");
IDS.put(10375, "Specwerkz");
IDS.put(1038, "MCCI Corporation");
IDS.put(10398, "Esselte Leitz GmbH & Co. KG");
IDS.put(10406, "E-SEEK Inc.");
IDS.put(1041, "BUFFALO INC.");
IDS.put(10423, "Pleora Technologies Inc.");
IDS.put(10431, "Vitetech Int'l Co., Ltd.");
IDS.put(1044, "Giga-Byte Technology Co., Ltd.");
IDS.put(10446, "Changzhou Shi Wujin Miqi East Electronic Co., Ltd.");
IDS.put(10457, "Shenzhen Ourconn Technology Co., Ltd.");
IDS.put(10458, "G.SKILL Int'l Enterprice Co., Ltd.");
IDS.put(1046, "Nuvoton Technology Corp.");
IDS.put(10466, "Surplus Electronic Technology Co., Ltd.");
IDS.put(10470, "BIAMP SYSTEMS");
IDS.put(10509, "IBCONN Technologies (Shenzhen) Co., Ltd.");
IDS.put(10510, "Fugoo Inc.");
IDS.put(10519, "Pan Xin Precision Electronics Co., Ltd.");
IDS.put(10530, "Dongguan Digi-in Digital Technology Co., Ltd.");
IDS.put(1054, "Creative Labs");
IDS.put(10540, "GENUSION, Inc.");
IDS.put(10544, "Ineda Systems Inc.");
IDS.put(10545, "Jolla Ltd.");
IDS.put(10546, "Peraso Technologies, Inc.");
IDS.put(10549, "Nanjing Magewell Electronics Co., Ltd.");
IDS.put(10560, "Shenzhen Yiwanda Electronics Co., Ltd.");
IDS.put(1057, "Nokia Corporation");
IDS.put(10575, "Dollar Connection Ltd.");
IDS.put(10595, "BIO-key International, Inc.");
IDS.put(1060, "Microchip-SMSC");
IDS.put(10603, "Xacti Corporation");
IDS.put(10615, "Shenzhen Zowee Technology Co., Ltd.");
IDS.put(10643, "ADPlaus Technology Limited");
IDS.put(10646, "Unwired Technology");
IDS.put(1065, "Cirrus Logic Inc.");
IDS.put(10657, "Union Electric Plug & Connector Corp.");
IDS.put(10674, "Canova Tech");
IDS.put(10685, "Silicon Works");
IDS.put(10695, "HANRICO ANFU ELECTRONICS CO., LTD.");
IDS.put(10700, "Kodak Alaris");
IDS.put(10702, "JGR Optics Inc.");
IDS.put(10703, "Richtek Technology Corporation");
IDS.put(10705, "Binatone Electronics Int. Ltd.");
IDS.put(1071, "Molex Inc.");
IDS.put(10715, "Shenzhen iBoard Technology Co., Ltd.");
IDS.put(10719, "SMIT(HK) Limited");
IDS.put(1072, "Fujitsu Component Limited");
IDS.put(10725, "Dongguan Kechenda Electronic Technology Co., Ltd.");
IDS.put(10726, "Fengshun Peiying Electro-Acoustic Co., Ltd.");
IDS.put(10744, "MD ELEKTRONIK GmbH");
IDS.put(10749, "Bad Elf, LLC");
IDS.put(10770, "Vreo Limited");
IDS.put(10772, "Kanex");
IDS.put(10781, "Oxford Nanopore Technologies");
IDS.put(10782, "Obsidian Technology");
IDS.put(10783, "Lucent Trans Electronics Co., Ltd.");
IDS.put(10784, "GUOGUANG GROUP CO., LTD.");
IDS.put(10788, "CNPLUS");
IDS.put(10789, "Fourstar Group");
IDS.put(10790, "Tragant International Co., Ltd.");
IDS.put(10791, "DongGuan LianGang Optoelectronic Technology Co., Ltd.");
IDS.put(10797, "Atrust Computer Corp.");
IDS.put(10798, "VIA Alliance Semiconductor Co., Ltd.");
IDS.put(10799, "BSUN Electronics Co., Ltd.");
IDS.put(1080, "Advanced Micro Devices");
IDS.put(10807, "RTD Embedded Technologies, Inc.");
IDS.put(10816, "Shenzhen Choseal Industrial Co., Ltd.");
IDS.put(10817, "Canyon Semiconductor");
IDS.put(10818, "Spectra7 Microsystems Corp.");
IDS.put(10821, "Meizu Technology Co., Ltd.");
IDS.put(10822, "Hubei Yingtong Telecommunication Cable Inc.");
IDS.put(10829, "Wilder Technologies");
IDS.put(10837, "Diodes Inc.");
IDS.put(10846, "DuPont");
IDS.put(1085, "Lexmark International Inc.");
IDS.put(10852, "Zhejiang Songcheng Electronics Co., Ltd.");
IDS.put(10859, "VSN Mobil");
IDS.put(10875, "Bellwether Electronic Corp.");
IDS.put(10878, "VAIO Corporation");
IDS.put(10879, "Perixx Computer GmbH");
IDS.put(10885, "HANK ELECTRONICS CO., LTD");
IDS.put(10892, "Sonnet Technologies, Inc.");
IDS.put(10893, "Keysight Technologies Inc.");
IDS.put(10895, "Manutronics Vietnam Joint Stock Company");
IDS.put(10900, "G2 Touch Co., Ltd.");
IDS.put(10902, "Micromax Informatics Ltd");
IDS.put(10910, "SEIKO SOLUTIONS Inc.");
IDS.put(10912, "Casco Products Corp.");
IDS.put(10922, "Virtium Technology, Inc.");
IDS.put(10923, "Field and Company LLC, dba Leef USA");
IDS.put(10928, "GM Global Technology Operations LLC");
IDS.put(10931, "Key Asic Inc.");
IDS.put(10943, "Revolabs, Inc.");
IDS.put(10945, "Lattice Semiconductor Corp");
IDS.put(10947, "Foshan Nanhai Saga Audio Equipment Co., Ltd.");
IDS.put(10957, "Silergy Corp.");
IDS.put(10963, "Shenzhen Hali-Power Industrial Co., Ltd.");
IDS.put(10971, "I-PEX (Dai-ichi Seiko)");
IDS.put(10973, "SEE-PLUS INDUSTRIAL LTD.");
IDS.put(10990, "Adapt-IP Company");
IDS.put(10997, "Libratone A/S");
IDS.put(10999, "Shenzhen Hazens Automotive Electronics (SZ) Co., Ltd.");
IDS.put(11000, "Jiangsu Toppower Automotive Electronics Co., Ltd.");
IDS.put(11001, "Drapho Electronics Technology Co., Ltd.");
IDS.put(1102, "Alps Electric Co., Ltd.");
IDS.put(11022, "Le Shi Zhi Xin Electronic Technology (Tian Jin) Limited");
IDS.put(11024, "Cardiac Insight, Inc.");
IDS.put(11028, "EverPro Technologies Company, Ltd.");
IDS.put(11029, "Rosenberger Hochfrequenztechnik");
IDS.put(11035, "Dongguan City Sanji Electronics Co., Ltd.");
IDS.put(11037, "Lintes Technology Co., Ltd.");
IDS.put(11039, "KinnexA, Inc.");
IDS.put(11042, "Metra Electronics Corp.");
IDS.put(11044, "KeepKey, LLC");
IDS.put(11047, "FluxData Incorporated");
IDS.put(1105, "Texas Instruments");
IDS.put(11061, "Assem Technology Co., Ltd.");
IDS.put(11062, "Dongguan City Jianghan Electronics Co., Ltd.");
IDS.put(11063, "Huizhou Desay SV Automotive Co., Ltd.");
IDS.put(11064, "Ningbo Rixing Electronics Co., Ltd.");
IDS.put(11069, "GuangDong YuanFeng Automotive Electroics Co., Ltd.");
IDS.put(11080, "Sounding Audio Industrial Limited");
IDS.put(11082, "Yueqing Huaxin Electronic Co., Ltd.");
IDS.put(11098, "Universal Audio, Inc.");
IDS.put(11111, "Lifesize, Inc.");
IDS.put(11123, "Pioneer DJ Corporation");
IDS.put(11124, "Embedded Intelligence, Inc.");
IDS.put(11125, "New Matter");
IDS.put(11126, "Shanghai Wingtech Electronic Technology Co., Ltd.");
IDS.put(11127, "Epiphan Systems Inc.");
IDS.put(11130, "Spin Master Far East Ltd.");
IDS.put(11131, "Gigaset Digital Technology (Shenzhen) Co., Ltd.");
IDS.put(11132, "Noveltek Semiconductor Corp.");
IDS.put(11139, "Silicon Line GmbH");
IDS.put(11140, "Ever Win International Corp.");
IDS.put(11144, "Socionext Inc.");
IDS.put(11145, "Ugreen Group Limited");
IDS.put(11146, "Shanghai Pateo Electronic Equipment Mfg. Co., Ltd.");
IDS.put(1115, "Renesas Electronics Corp.");
IDS.put(11154, "i-BLADES, Inc.");
IDS.put(11155, "Altia Systems Inc.");
IDS.put(11156, "ShenZhen Baoyuanda Electronics Co., Ltd.");
IDS.put(11157, "iST - Integrated Service Technology Inc.");
IDS.put(11158, "HYUNDAI MOBIS Co., Ltd.");
IDS.put(11161, "360fly, Inc.");
IDS.put(11162, "HUIZHOU CHENG SHUO HARDWARE PLASTIC CO., LTD.");
IDS.put(11163, "Zhongshan Aute Electronics Technology Co., Ltd.");
IDS.put(11164, "Guangdong King Link Industrial Co., Ltd.");
IDS.put(11167, "Scietera Technologies, Inc.");
IDS.put(11168, "InVue Security Products");
IDS.put(11169, "I-Sheng Electric Wire & Cable Co., Ltd.");
IDS.put(11170, "China Daheng Group Inc Beijing Image Vision Tech Branch");
IDS.put(11171, "Shenzhen FeiTianXia Technology Ltd.");
IDS.put(11172, "Shenzhen HengJia New Energy Auto Part Co., Ltd.");
IDS.put(11175, "77 Elektronika Kft.");
IDS.put(11176, "YUDU EASON ELECTRONIC CO., LTD.");
IDS.put(1118, "Microsoft Corporation");
IDS.put(11181, "XIN JI (SHENZHEN) COMPUTER PARTS CO., LTD.");
IDS.put(11189, "Silk ID Systems");
IDS.put(11190, "3D Imaging & Simulations Corp. (3DISC)");
IDS.put(11191, "Dongguan ChengXiang Industrial Co., Ltd.");
IDS.put(11192, "OCC (Zhuhai) Electronic Co., Ltd.");
IDS.put(11194, "Sinseader Electronic Co., Ltd.");
IDS.put(11195, "DONGGUAN YELLOWKNIFE Industrial Co., Ltd.");
IDS.put(11197, "RF Creations Ltd.");
IDS.put(11198, "Chengyi Semiconductors (Shanghai) Co., Ltd.");
IDS.put(11199, "Shenzhen Shinning Electronic Co., Ltd.");
IDS.put(11200, "Shenzhen WFD Electronics Co., Ltd.");
IDS.put(11201, "Dongguan Sino Syncs Industrial Co., Ltd.");
IDS.put(11202, "JNTC Co., Ltd.");
IDS.put(11208, "DONGGUAN POLIXIN ELECTRIC CO., LTD.");
IDS.put(11209, "Tama Electric (Suzhou) Co., Ltd.");
IDS.put(1121, "Primax Electronics");
IDS.put(11210, "Exvision, Inc.");
IDS.put(11216, "mophie, LLC");
IDS.put(11219, "Dongguan ULT-unite electronic technology co., LTD");
IDS.put(11220, "JL Audio, Inc.");
IDS.put(11221, "Cable Matters Inc.");
IDS.put(11222, "CoroWare, Inc.");
IDS.put(11229, "Charm Sciences Inc.");
IDS.put(1123, "EATON");
IDS.put(11230, "Pickering Interfaces Limited");
IDS.put(11231, "Hangzhou Hikvision Digital Technology Co., Ltd.");
IDS.put(11232, "FULLINK ELECTRONICS TECHNOLOGY (SZ) LTD");
IDS.put(11233, "AutoChips Inc.");
IDS.put(11234, "Electric Connector Technology Co., Ltd.");
IDS.put(11237, "LELTEK");
IDS.put(11238, "Dongguan KaiWin Electronics Co., Ltd.");
IDS.put(11239, "BEFS Co., Ltd.");
IDS.put(11240, "Archisite, Inc.");
IDS.put(11241, "Magneti Marelli S.p.A Electr BL");
IDS.put(11246, "Ventev Mobile");
IDS.put(11247, "Quanta Storage Inc.");
IDS.put(11248, "Tech-Top Technology Limited");
IDS.put(11253, "Shenzhen YOOBAO Technology Co., Ltd.");
IDS.put(11254, "Shenzhen Sinotek Technology Co., Ltd.");
IDS.put(11255, "KEYW");
IDS.put(11256, "Visual Land Inc.");
IDS.put(11264, "MEEM SL Ltd");
IDS.put(11265, "Dongguan Arin Electronics Technology Co., Ltd.");
IDS.put(11266, "DongGuan City JianNuo Electronics Co., Ltd.");
IDS.put(11268, "Shenzhen XOX Electronics Co., Ltd.");
IDS.put(11269, "Protop International Inc.");
IDS.put(11270, "Microsemi Semiconductor (US) Inc.");
IDS.put(11271, "Webcloak LLC");
IDS.put(11272, "INVECAS INC.");
IDS.put(11274, "ATANS Technology Inc.");
IDS.put(11275, "Triple Win Precision Technology Co., Ltd.");
IDS.put(11276, "IC Realtech");
IDS.put(11277, "Embrava Pty Ltd");
IDS.put(1128, "Wieson Technologies Co., Ltd.");
IDS.put(11280, "Sinotronics Co., Ltd.");
IDS.put(11281, "ALLBEST ELECTRONICS TECHNOLOGY CO., LTD.");
IDS.put(11282, "Shenzhen Xin Kai Feng Electronics Factory");
IDS.put(11283, "MOST WELL Technology Corp.");
IDS.put(11284, "Buffalo Memory Co., Ltd.");
IDS.put(11285, "Xentris Wireless");
IDS.put(11286, "Priferential Accessories Ltd");
IDS.put(11289, "Sunlike Technology Co., Ltd.");
IDS.put(11290, "Young Fast Optoelectronics Co., Ltd.");
IDS.put(11291, "ISAW Camera Inc");
IDS.put(11298, "Qanba USA, LLC");
IDS.put(11299, "Super Micro Computer Inc.");
IDS.put(11302, "Micromax International Corporation");
IDS.put(11304, "Granite River Labs Japan Ltd.");
IDS.put(11305, "Coagent Enterprise Limited");
IDS.put(11306, "LEIA Inc.");
IDS.put(11309, "Shenzhen Ebull Technology Limited");
IDS.put(1131, "American Megatrends");
IDS.put(11310, "Hualun Technology Co., Ltd.");
IDS.put(11311, "Sensel, Inc.");
IDS.put(11319, "Shenzhen Adition Audio Science & Technology Co., Ltd.");
IDS.put(11320, "Goldenconn Electronics Technology (Suzhou) Co., Ltd.");
IDS.put(11321, "JIB Electronics Technology Co., Ltd.");
IDS.put(11322, "Changzhou Shinco Automotive Electronics Co., Ltd.");
IDS.put(11323, "Shenzhen Hangsheng Electronics Corp., Ltd.");
IDS.put(11324, "Beartooth Radio, Inc.");
IDS.put(11325, "Audience, A Knowles Company");
IDS.put(11327, "Nextbit Systems, Inc.");
IDS.put(11328, "Leadtrend");
IDS.put(11329, "Adaptertek Technology Co., Ltd.");
IDS.put(1133, "Logitech Inc.");
IDS.put(11330, "Feature Integration Technology Inc.");
IDS.put(11331, "Avegant Corporation");
IDS.put(11335, "Chunghsin International Electronics Co., Ltd.");
IDS.put(11336, "Delphi Electrical Centers (Shanghai) Co., Ltd.");
IDS.put(11341, "VVETEK DOO");
IDS.put(11347, "Huizhou Foryou General Electronics Co., Ltd.");
IDS.put(11348, "LifeWatch Technologies Ltd.");
IDS.put(11349, "Magicleap");
IDS.put(11355, "Dongguan City Shenglan Electronics Co., LTD.");
IDS.put(11356, "Neusoft Corporation");
IDS.put(11357, "SIP Simya Electronics Technology Co., Ltd.");
IDS.put(11358, "GNSD Automotive Co., Ltd.");
IDS.put(11359, "YOODS Co., Ltd.");
IDS.put(11360, "Sirin Mobile Technologies AG");
IDS.put(11361, "Jadmam Corporation dba: Boytone");
IDS.put(11373, "Gibson Innovations");
IDS.put(11374, "Shen Zhen Xian Shuo Technology Co. LTD");
IDS.put(11375, "PST Eletronica LTDA");
IDS.put(11376, "PERI, Inc.");
IDS.put(11377, "Bozhou BoTong Information Technology Co., Ltd.");
IDS.put(11383, "Profindustry GmbH");
IDS.put(11384, "BRAGI GmbH");
IDS.put(11385, "WAWGD, Inc. (DBA: Foresight Sports)");
IDS.put(11390, "Dongguan Allpass Electronic Co., Ltd.");
IDS.put(11391, "SHENZHEN D-VITEC INDUSTRIAL CO., LTD.");
IDS.put(11392, "motomobile AG");
IDS.put(11393, "Indie Semiconductor");
IDS.put(11397, "Audientes");
IDS.put(11403, "Huizhou Dehong Technology Co., Ltd.");
IDS.put(11404, "PowerCenter Technology Limited");
IDS.put(11405, "Mizco International, Inc.");
IDS.put(11408, "I. AM. PLUS, LLC");
IDS.put(11409, "Corigine, Inc.");
IDS.put(11410, "Ningbo Yinzhou Shengke Electronics Co., Ltd.");
IDS.put(11417, "Prusa Research s.r.o.");
IDS.put(11423, "e-Smart Systems Pvt. Ltd.");
IDS.put(11424, "Leagtech Jiangxi Electronic Co., Ltd.");
IDS.put(11425, "Dongguan Yujia Electronics Technology Co., Ltd.");
IDS.put(11426, "GuangZhou MingPing Electronics Technology");
IDS.put(11427, "DJI Technology Co., Ltd.");
IDS.put(11428, "Shenzhen Alex Technology Co., Ltd.");
IDS.put(11433, "JITS TECHNOLOGY CO., LIMITED");
IDS.put(11434, "LIVV Brand llc");
IDS.put(11444, "Ava Enterprises, Inc. dba: Boss Audio Systems");
IDS.put(11448, "Shenzhen Sydixon Electronic Technology Co., Ltd.");
IDS.put(11449, "On-Bright Electronics (Shanghai) Co., Ltd.");
IDS.put(11450, "Dongguan Puxu Industrial Co., Ltd.");
IDS.put(11451, "Shenzhen Soling Indusrtial Co., Ltd.");
IDS.put(11453, "EGGCYTE, INC.");
IDS.put(11455, "Donggguan Yuhua Electronic Co., Ltd.");
IDS.put(11456, "Hangzhou Zero Zero Technology Co., Ltd.");
IDS.put(11462, "Prodigy Technovations Pvt Ltd");
IDS.put(11463, "EmergiTech, Inc");
IDS.put(11464, "Hewlett Packard Enterprise");
IDS.put(11465, "Monolithic Power Systems Inc.");
IDS.put(11467, "USB Memory Direct");
IDS.put(11468, "Silicon Mitus Inc.");
IDS.put(11472, "Technics Global Electronics & JCE Co., Ltd.");
IDS.put(11478, "Immersive Media");
IDS.put(11479, "Cosemi Technologies Inc.");
IDS.put(11481, "Cambrionix Ltd");
IDS.put(11482, "CXUN Co. Ltd.");
IDS.put(11483, "China Tsp Inc");
IDS.put(11490, "Yanfeng Visteon (Chongqing) Automotive Electronics Co");
IDS.put(11491, "Alcorlink Corp.");
IDS.put(11492, "ISBC Ltd.");
IDS.put(11493, "InX8 Inc dba: AKiTiO");
IDS.put(11494, "SDAN Tecchnology Co., Ltd.");
IDS.put(11495, "Lemobile Information Technology (Beijing) Co., Ltd.");
IDS.put(11496, "GongGuan HWX Electronic Technology Co., Ltd.");
IDS.put(11497, "Suzhu Jingshi Electronic Technology Co., Ltd.");
IDS.put(11498, "Zhong Shan City Richsound Electronic Industrial Ltd.");
IDS.put(11499, "Dongguang Kangbang Electronics Co., Ltd.");
IDS.put(1151, "Plantronics, Inc.");
IDS.put(1154, "Kyocera Corporation");
IDS.put(1155, "STMicroelectronics");
IDS.put(1161, "Foxconn / Hon Hai");
IDS.put(1165, "ITE Tech Inc.");
IDS.put(1177, "Yamaha Corporation");
IDS.put(1188, "Hitachi, Ltd.");
IDS.put(1191, "Visioneer");
IDS.put(1193, "Canon Inc.");
IDS.put(1200, "Nikon Corporation");
IDS.put(1201, "Pan International");
IDS.put(1204, "Cypress Semiconductor");
IDS.put(1205, "ROHM Co., Ltd.");
IDS.put(1207, "Compal Electronics, Inc.");
IDS.put(1208, "Seiko Epson Corp.");
IDS.put(1211, "I-O Data Device, Inc.");
IDS.put(1221, "Fujitsu Ltd.");
IDS.put(1227, "FUJIFILM Corporation");
IDS.put(1238, "Mentor Graphics");
IDS.put(1240, "Microchip Technology Inc.");
IDS.put(1241, "Holtek Semiconductor, Inc.");
IDS.put(1242, "Panasonic Corporation");
IDS.put(1245, "Sharp Corporation");
IDS.put(1250, "Exar Corporation");
IDS.put(1254, "Identiv, Inc.");
IDS.put(1256, "Samsung Electronics Co., Ltd.");
IDS.put(1260, "Tokyo Electron Device Limited");
IDS.put(1266, "Chicony Electronics Co., Ltd.");
IDS.put(1271, "Newnex Technology Corp.");
IDS.put(1273, "Brother Industries, Ltd.");
IDS.put(1276, "SUNPLUS TECHNOLOGY CO., LTD.");
IDS.put(1278, "PFU Limited");
IDS.put(1281, "Fujikura/DDK");
IDS.put(1282, "Acer, Inc.");
IDS.put(1287, "Hosiden Corporation");
IDS.put(1293, "Belkin International, Inc.");
IDS.put(1300, "FCI Electronics");
IDS.put(1302, "Longwell Electronics/Longwell Company");
IDS.put(1305, "Star Micronics Co., LTD");
IDS.put(1309, "American Power Conversion");
IDS.put(1314, "ACON, Advanced-Connectek, Inc.");
IDS.put(1343, "Synopsys, Inc.");
IDS.put(1356, "Sony Corporation");
IDS.put(1360, "Fuji Xerox Co., Ltd.");
IDS.put(1367, "ATEN International Co. Ltd.");
IDS.put(1369, "Cadence Design Systems, Inc.");
IDS.put(1386, "WACOM Co., Ltd.");
IDS.put(1389, "EIZO Corporation");
IDS.put(1390, "Elecom Co., Ltd.");
IDS.put(1394, "Conexant Systems, Inc.");
IDS.put(1398, "BAFO/Quality Computer Accessories");
IDS.put(1403, "Y-E Data, Inc.");
IDS.put(1404, "AVM GmbH");
IDS.put(1410, "Roland Corporation");
IDS.put(1412, "RATOC Systems, Inc.");
IDS.put(1419, "Infineon Technologies");
IDS.put(1423, "Alcor Micro, Corp.");
IDS.put(1424, "OMRON Corporation");
IDS.put(1447, "Bose Corporation");
IDS.put(1449, "OmniVision Technologies, Inc.");
IDS.put(1452, "Apple");
IDS.put(1453, "Y.C. Cable U.S.A., Inc");
IDS.put(14627, "National Instruments");
IDS.put(1470, "Tyco Electronics Corp., a TE Connectivity Ltd. company");
IDS.put(1473, "MegaChips Corporation");
IDS.put(1478, "Qualcomm, Inc");
IDS.put(1480, "Foxlink/Cheng Uei Precision Industry Co., Ltd.");
IDS.put(1482, "Ricoh Company Ltd.");
IDS.put(1498, "Microtek International Inc.");
IDS.put(1504, "Symbol Technologies");
IDS.put(1507, "Genesys Logic, Inc.");
IDS.put(1509, "Fuji Electric Co., Ltd.");
IDS.put(1525, "Unixtar Technology Inc.");
IDS.put(1529, "Datalogic ADC");
IDS.put(1535, "LeCroy Corporation");
IDS.put(1539, "Novatek Microelectronics Corp.");
IDS.put(1545, "SMK Manufacturing Inc.");
IDS.put(1551, "Joinsoon Electronics Mfg. Co., Ltd.");
IDS.put(1555, "TransAct Technologies Incorporated");
IDS.put(1561, "Seiko Instruments Inc.");
IDS.put(1582, "JPC/MAIN SUPER Inc.");
IDS.put(1583, "Sin Sheng Terminal & Machine Inc.");
IDS.put(1593, "Chrontel, Inc.");
IDS.put(1611, "Analog Devices, Inc. Development Tools");
IDS.put(1612, "Ji-Haw Industrial Co., Ltd");
IDS.put(1614, "Suyin Corporation");
IDS.put(1621, "Space Shuttle Hi-Tech Co.,Ltd.");
IDS.put(1622, "Glory Mark Electronic Ltd.");
IDS.put(1623, "Tekcon Electronics Corp.");
IDS.put(1624, "Sigma Designs, Inc.");
IDS.put(1631, "Good Way Technology Co., Ltd. & GWC technology Inc");
IDS.put(1632, "TSAY-E (BVI) International Inc.");
IDS.put(1633, "Hamamatsu Photonics K.K.");
IDS.put(1642, "Total Technologies, Ltd.");
IDS.put(1659, "Prolific Technology, Inc.");
IDS.put(16700, "Dell Inc.");
IDS.put(1680, "Golden Bridge Electech Inc.");
IDS.put(1689, "Tektronix, Inc.");
IDS.put(1690, "Askey Computer Corporation");
IDS.put(1709, "Greatland Electronics Taiwan Ltd.");
IDS.put(1710, "Eurofins Digital Testing Belgium");
IDS.put(1720, "Pixela Corporation");
IDS.put(1724, "Oki Data Corporation");
IDS.put(1727, "Leoco Corporation");
IDS.put(1732, "Bizlink Technology, Inc.");
IDS.put(1736, "SIIG, Inc.");
IDS.put(1747, "Mitsubishi Electric Corporation");
IDS.put(1758, "Heisei Technology Co., Ltd.");
IDS.put(1802, "Oki Electric Industry Co., Ltd.");
IDS.put(1805, "Comoss Electronic Co., Ltd.");
IDS.put(1809, "Magic Control Technology Corp.");
IDS.put(1816, "Imation Corp.");
IDS.put(1838, "Sunix Co., Ltd.");
IDS.put(1846, "Lorom Industrial Co., Ltd.");
IDS.put(1848, "Mad Catz, Inc.");
IDS.put(1899, "HID Global GmbH");
IDS.put(1901, "Denso Corporation");
IDS.put(1913, "Fairchild Semiconductor");
IDS.put(1921, "SanDisk Corporation");
IDS.put(1937, "Copartner Technology Corporation");
IDS.put(1954, "National Technical Systems");
IDS.put(1971, "Plustek, Inc.");
IDS.put(1972, "OLYMPUS CORPORATION");
IDS.put(1975, "TIME Interconnect Ltd.");
IDS.put(1994, "AVerMedia Technologies, Inc.");
IDS.put(1999, "Casio Computer Co., Ltd.");
IDS.put(2015, "David Electronics Company, Ltd.");
IDS.put(2039, "Century Corporation");
IDS.put(2058, "Evermuch Technology Co., Ltd.");
IDS.put(2101, "Action Star Enterprise Co., Ltd.");
IDS.put(2112, "Argosy Research Inc.");
IDS.put(2122, "Wipro Limited");
IDS.put(2159, "MEC IMEX INC/HPT");
IDS.put(2205, "Icron Technologies Corporation");
IDS.put(2247, "TAI TWUN ENTERPRISE CO., LTD.");
IDS.put(2276, "Pioneer Corporation");
IDS.put(2278, "Gemalto SA");
IDS.put(2310, "FARADAY Technology Corp.");
IDS.put(2313, "Audio-Technica Corp.");
IDS.put(2316, "Silicon Motion, Inc. - Taiwan");
IDS.put(2334, "Garmin International");
IDS.put(2352, "Toshiba Corporation");
IDS.put(2362, "Pixart Imaging, Inc.");
IDS.put(2363, "Plextor LLC");
IDS.put(2366, "J.S.T. Mfg. Co., Ltd.");
IDS.put(2385, "Kingston Technology Company");
IDS.put(2389, "NVIDIA");
IDS.put(2395, "Medialogic Corporation");
IDS.put(2397, "Polycom, Inc.");
IDS.put(2468, "Contech Research, Inc.");
IDS.put(2472, "Lin Shiung Enterprise Co., Ltd.");
IDS.put(2475, "Japan Cash Machine Co., Ltd.");
IDS.put(2498, "NISCA Corporation");
IDS.put(2511, "Electronics Testing Center, Taiwan");
IDS.put(2522, "A-FOUR TECH CO., LTD.");
IDS.put(2555, "Altera");
IDS.put(2578, "Cambridge Silicon Radio Ltd.");
IDS.put(2583, "HOYA Corporation");
IDS.put(2631, "Hirose Electric Co., Ltd.");
IDS.put(2636, "COMPUTEX Co., Ltd.");
IDS.put(2640, "Mimaki Engineering Co., Ltd.");
IDS.put(2652, "Broadcom Corp.");
IDS.put(2667, "Green House Co., Ltd.");
IDS.put(2702, "Japan Aviation Electronics Industry Ltd. (JAE)");
IDS.put(2727, "Wincor Nixdorf GmbH & Co KG");
IDS.put(2733, "Rohde & Schwarz GmbH & Co. KG");
IDS.put(2787, "Allion Labs, Inc.");
IDS.put(2821, "ASUSTek Computer Inc.");
IDS.put(2849, "Yokogawa Electric Corporation");
IDS.put(2851, "Pan-Asia Electronics Co., Ltd.");
IDS.put(2894, "Musical Electronics Ltd.");
IDS.put(2907, "Anritsu Corporation");
IDS.put(2922, "Maxim Integrated Products");
IDS.put(2965, "ASIX Electronics Corporation");
IDS.put(2967, "O2Micro, Inc.");
IDS.put(3010, "Seagate Technology LLC");
IDS.put(3034, "Realtek Semiconductor Corp.");
IDS.put(3035, "Ericsson AB");
IDS.put(3044, "Elka International Ltd.");
IDS.put(3056, "Pace Micro Technology PLC");
IDS.put(3108, "Taiyo Yuden Co., Ltd.");
IDS.put(3129, "Aeroflex");
IDS.put(3132, "Radius Co., Ltd.");
IDS.put(3141, "Sonix Technology Co., Ltd.");
IDS.put(3158, "Billion Bright (HK) Corporation Limited");
IDS.put(3161, "Dong Guan Shinko Wire Co., Ltd.");
IDS.put(3170, "Chant Sincere Co., Ltd");
IDS.put(3190, "Solid State System Co., Ltd.");
IDS.put(3209, "Honda Tsushin Kogyo Co., Ltd");
IDS.put(3245, "Motorola Solutions");
IDS.put(3255, "Singatron Enterprise Co. Ltd.");
IDS.put(3268, "emsys Embedded Systems GmbH");
IDS.put(32902, "Intel Corporation");
IDS.put(3294, "Z-Com INC.");
IDS.put(3313, "e-CONN ELECTRONIC CO., LTD.");
IDS.put(3314, "ENE Technology Inc.");
IDS.put(3351, "NALTEC, Inc.");
IDS.put(3402, "NF Corporation");
IDS.put(3403, "Grape Systems Inc.");
IDS.put(3409, "Volex (Asia) Pte Ltd");
IDS.put(3425, "MEILU ELECTRONICS (SHENZHEN) CO., LTD.");
IDS.put(3441, "Hirakawa Hewtech Corp.");
IDS.put(3452, "Taiwan Line Tek Electronic Co., Ltd.");
IDS.put(3463, "Dolby Laboratories Inc.");
IDS.put(3468, "C-MEDIA ELECTRONICS INC.");
IDS.put(3472, "Sure-Fire Electrical Corporation");
IDS.put(3495, "IOGEAR, Inc.");
IDS.put(3504, "Micro-Star International Co., Ltd.");
IDS.put(3537, "Contek Electronics Co., Ltd.");
IDS.put(3540, "Custom Engineering SPA");
IDS.put(3641, "Smart Modular Technologies, Inc.");
IDS.put(3658, "Shenzhen Bao Hing Electric Wire & Cable Mfr. Co.");
IDS.put(3673, "Bourns, Inc.");
IDS.put(3690, "Megawin Technology Co., Ltd.");
IDS.put(3698, "Hsi-Chin Electronics Co., Ltd.");
IDS.put(3714, "Ching Tai Electric Wire & Cable Co., Ltd.");
IDS.put(3724, "Well Force Electronic Co., Ltd");
IDS.put(3725, "MediaTek Inc.");
IDS.put(3728, "CRU");
IDS.put(3744, "Ours Technology Inc.");
IDS.put(3762, "Y-S ELECTRONIC CO., LTD.");
IDS.put(3778, "Sweetray Industrial Ltd.");
IDS.put(3779, "Axell Corporation");
IDS.put(3782, "InnoVISION Multimedia Limited");
IDS.put(3790, "TaiSol Electronics Co., Ltd.");
IDS.put(3812, "Sunrich Technology (H.K.) Ltd.");
IDS.put(3868, "Funai Electric Co., Ltd.");
IDS.put(3873, "IOI Technology Corporation");
IDS.put(3890, "YFC-BonEagle Electric Co., Ltd.");
IDS.put(3896, "Nien-Yi Industrial Corp.");
IDS.put(3916, "WORLDWIDE CABLE OPTO CORP.");
IDS.put(3923, "Taiyo Cable (Dongguan) Co. Ltd.");
IDS.put(3924, "Kawai Musical Instruments Mfg. Co., Ltd.");
IDS.put(3936, "GuangZhou Chief Tech Electronic Technology Co. Ltd.");
IDS.put(3944, "UQUEST, LTD.");
IDS.put(3991, "CviLux Corporation");
IDS.put(4003, "Chief Land Electronic Co., Ltd.");
IDS.put(4046, "Sony Mobile Communications");
IDS.put(4087, "CHI SHING COMPUTER ACCESSORIES CO., LTD.");
IDS.put(4096, "Speed Tech Corp.");
IDS.put(4100, "LG Electronics Inc.");
IDS.put(4101, "Apacer Technology Inc.");
IDS.put(4134, "Newly Corporation");
IDS.put(4168, "Targus Group International");
IDS.put(4172, "AMCO TEC International Inc.");
IDS.put(4183, "ON Semiconductor");
IDS.put(4184, "Western Digital Technologies, Inc.");
IDS.put(4227, "CANON ELECTRONICS INC.");
IDS.put(4235, "Grand-tek Technology Co., Ltd.");
IDS.put(4236, "Robert Bosch GmbH");
IDS.put(4238, "Lotes Co., Ltd.");
IDS.put(4266, "Cables To Go");
IDS.put(4267, "Universal Global Scientific Industrial Co., Ltd.");
IDS.put(4292, "Silicon Laboratories, Inc.");
IDS.put(4301, "Kycon Inc.");
IDS.put(4362, "Moxa Inc.");
IDS.put(4370, "Golden Bright (Sichuan) Electronic Technology Co Ltd");
IDS.put(4382, "VSO ELECTRONICS CO., LTD.");
IDS.put(4398, "Master Hill Electric Wire and Cable Co., Ltd.");
IDS.put(4477, "Santa Electronic Inc.");
IDS.put(4505, "Sierra Wireless Inc.");
IDS.put(4522, "GlobalMedia Group, LLC");
IDS.put(4528, "ATECH FLASH TECHNOLOGY");
IDS.put(4643, "SKYCABLE ENTERPRISE CO., LTD.");
IDS.put(4703, "ADATA Technology Co., Ltd.");
IDS.put(4716, "Aristocrat Technologies");
IDS.put(4717, "Bel Stewart");
IDS.put(4742, "MARVELL SEMICONDUCTOR, INC.");
IDS.put(4756, "RISO KAGAKU CORP.");
IDS.put(4792, "Zhejiang Xinya Electronic Technology Co., Ltd.");
IDS.put(4817, "Huawei Technologies Co., Ltd.");
IDS.put(4823, "Better Holdings (HK) Limited");
IDS.put(4907, "Konica Minolta, Inc.");
IDS.put(4925, "Jasco Products Company");
IDS.put(4989, "Pericom Semiconductor Corp.");
IDS.put(5008, "TomTom International B.V.");
IDS.put(5075, "AzureWave Technologies, Inc.");
IDS.put(5117, "Initio Corporation");
IDS.put(5118, "Phison Electronics Corp.");
IDS.put(5134, "Telechips, Inc.");
IDS.put(5145, "ABILITY ENTERPRISE CO., LTD.");
IDS.put(5148, "Leviton Manufacturing");
IDS.put(5271, "Panstrong Company Ltd.");
IDS.put(5293, "CTK Corporation");
IDS.put(5296, "StarTech.com Ltd.");
IDS.put(5376, "Ellisys");
IDS.put(5404, "VeriSilicon Holdings Co., Ltd.");
IDS.put(5421, "JMicron Technology Corp.");
IDS.put(5422, "HLDS (Hitachi-LG Data Storage, Inc.)");
IDS.put(5440, "Phihong Technology Co., Ltd.");
IDS.put(5451, "PNY Technologies Inc.");
IDS.put(5453, "Rapid Conn, Connect County Holdings Bhd");
IDS.put(5454, "D & M Holdings, Inc.");
IDS.put(5480, "Sunf Pu Technology Co., Ltd");
IDS.put(5488, "ALLTOP TECHNOLOGY CO., LTD.");
IDS.put(5510, "Palconn Technology Co., Ltd.");
IDS.put(5528, "Kunshan Guoji Electronics Co., Ltd.");
IDS.put(5546, "DongGuan Ya Lian Electronics Co., Ltd.");
IDS.put(5645, "Samtec");
IDS.put(5694, "HongLin Electronics Co., Ltd.");
IDS.put(5753, "Total Phase");
IDS.put(5766, "ZOOM Corporation");
IDS.put(5836, "silex technology, Inc.");
IDS.put(5946, "F. Hoffmann-La Roche AG");
IDS.put(5960, "MQP Electronics Ltd.");
IDS.put(5964, "ASMedia Technology Inc.");
IDS.put(5998, "UD electronic corp.");
IDS.put(6001, "Shenzhen Alex Connector Co., Ltd.");
IDS.put(6002, "System Level Solutions, Inc.");
IDS.put(6018, "Spreadtrum Hong Kong Limited");
IDS.put(6024, "ShenZhen Litkconn Technology Co., Ltd.");
IDS.put(6053, "Advanced Connection Technology Inc.");
IDS.put(6095, "Hip Hing Cable & Plug Mfy. Ltd.");
IDS.put(6121, "DisplayLink (UK) Ltd.");
IDS.put(6127, "Lenovo");
IDS.put(6133, "K.K. Rocky");
IDS.put(6160, "Wanshih Electronic Co., Ltd.");
IDS.put(6185, "Dongguan YuQiu Electronics Co., Ltd.");
IDS.put(6193, "Gwo Jinn Industries Co., Ltd.");
IDS.put(6297, "Linkiss Co., Ltd.");
IDS.put(6353, "Google Inc.");
IDS.put(6394, "Kuang Ying Computer Equipment Co., Ltd.");
IDS.put(6421, "Nordic Semiconductor ASA");
IDS.put(6448, "Shenzhen Xianhe Technology Co., Ltd.");
IDS.put(6449, "Ningbo Broad Telecommunication Co., Ltd.");
IDS.put(6470, "Irisguard UK Ltd");
IDS.put(6473, "Lab126");
IDS.put(6481, "Hyperstone GmbH");
IDS.put(6487, "BIOS Corporation");
IDS.put(6626, "Solomon Systech Limited");
IDS.put(6639, "Pak Heng Technology (Shenzhen) Co., Ltd.");
IDS.put(6655, "Best Buy China Ltd.");
IDS.put(6666, "USB-IF non-workshop");
IDS.put(6709, "Artesyn Technologies Inc.");
IDS.put(6720, "TERMINUS TECHNOLOGY INC.");
IDS.put(6766, "Global Unichip Corp.");
IDS.put(6786, "Proconn Technology Co., Ltd.");
IDS.put(6794, "Simula Technology Inc.");
IDS.put(6795, "SGS Taiwan Ltd.");
IDS.put(6830, "Johnson Component & Equipments Co., Ltd.");
IDS.put(6834, "Allied Vision Technologies GmbH");
IDS.put(6859, "Salcomp Plc");
IDS.put(6865, "Desan Wire Co., Ltd.");
IDS.put(6944, "MStar Semiconductor, Inc.");
IDS.put(6984, "Plastron Precision Co., Ltd.");
IDS.put(7013, "The Hong Kong Standards and Testing Centre Ltd.");
IDS.put(7048, "ShenMing Electron (Dong Guan) Co., Ltd.");
IDS.put(7086, "Vuzix Corporation");
IDS.put(7108, "Ford Motor Co.");
IDS.put(7118, "Contac Cable Industrial Limited");
IDS.put(7119, "Sunplus Innovation Technology Inc.");
IDS.put(7120, "Hangzhou Riyue Electronics Co., Ltd.");
IDS.put(7158, "Orient Semiconductor Electronics, Ltd.");
IDS.put(7207, "SHENZHEN DNS INDUSTRIES CO., LTD.");
IDS.put(7217, "LS Mtron Ltd.");
IDS.put(7229, "NONIN MEDICAL INC.");
IDS.put(7275, "Philips & Lite-ON Digital Solutions Corporation");
IDS.put(7310, "ASTRON INTERNATIONAL CORP.");
IDS.put(7320, "ALPINE ELECTRONICS, INC.");
IDS.put(7347, "Aces Electronics Co., Ltd.");
IDS.put(7348, "OPEX CORPORATION");
IDS.put(7390, "Telecommunications Technology Association (TTA)");
IDS.put(7434, "Visteon Corporation");
IDS.put(7465, "Horng Tong Enterprise Co., Ltd.");
IDS.put(7501, "Pegatron Corporation");
IDS.put(7516, "Fresco Logic Inc.");
IDS.put(7529, "Walta Electronic Co., Ltd.");
IDS.put(7543, "Yueqing Changling Electronic Instrument Corp., Ltd.");
IDS.put(7584, "Parade Technologies, Inc.");
IDS.put(7647, "L&T Technology Services");
IDS.put(7649, "Actions Microelectronics Co., Ltd.");
IDS.put(7666, "China Telecommunication Technology Labs - Terminals");
IDS.put(7668, "SHEN ZHEN FORMAN PRECISION INDUSTRY CO., LTD.");
IDS.put(7682, "GLOBEMASTER TECHNOLOGIES CO., LTD.");
IDS.put(7696, "Point Grey Research Inc.");
IDS.put(7751, "HUNG TA H.T.ENTERPRISE CO., LTD.");
IDS.put(7758, "Etron Technology, Inc.");
IDS.put(7795, "COMLINK ELECTRONICS CO., LTD.");
IDS.put(7818, "HIBEST Electronic (DongGuan) Co., Ltd.");
IDS.put(7825, "Other World Computing");
IDS.put(7863, "WIN WIN PRECISION INDUSTRIAL CO., LTD.");
IDS.put(7879, "Gefen Inc.");
IDS.put(7881, "MOSER BAER INDIA LIMITED");
IDS.put(7898, "AIRTIES WIRELESS NETWORKS");
IDS.put(7956, "Astoria Networks GmbH");
IDS.put(7969, "Scosche Industries");
IDS.put(7976, "Cal-Comp Electronics & Communications");
IDS.put(7977, "Analogix Semiconductor, Inc.");
IDS.put(7989, "Amphenol ShouhMin Industry (ShenZhen) Co., Ltd");
IDS.put(7996, "Chang Yang Electronics Company Ltd.");
IDS.put(8073, "Dongguan Goldconn Electronics Co., Ltd.");
IDS.put(8074, "Morning Star Industrial Co., Ltd.");
IDS.put(8117, "Unify Software and Solutions GmbH & Co. KG");
IDS.put(8137, "NXP Semiconductors");
IDS.put(8181, "Changzhou Wujin BEST Electronic Cables Co., Ltd.");
IDS.put(8205, "Belkin Electronic (Changzhou) Co., Ltd.");
IDS.put(8220, "Freeport Resources Enterprises Corp.");
IDS.put(8222, "Qingdao Haier Telecom Co., Ltd.");
IDS.put(8284, "Shenzhen Tronixin Electronics Co., Ltd.");
IDS.put(8294, "Unicorn Electronics Components Co., Ltd.");
IDS.put(8334, "Luxshare-ICT");
IDS.put(8341, "CE LINK LIMITED");
IDS.put(8342, "Microconn Electronic Co., Ltd.");
IDS.put(8367, "Shenzhen CARVE Electronics Co., Ltd.");
IDS.put(8382, "BURY GmbH & Co. KG");
IDS.put(8384, "FENGHUA KINGSUN CO., LTD.");
IDS.put(8386, "Sumitomo Electric Ind., Ltd., Optical Comm. R&D Lab");
IDS.put(8439, "XIMEA s.r.o.");
IDS.put(8457, "VIA Labs, Inc.");
IDS.put(8492, "Shenzhen Linoya Electronic Co., Ltd.");
IDS.put(8494, "Amphenol AssembleTech (Xiamen) Co., Ltd.");
IDS.put(8524, "Y Soft Corporation");
IDS.put(8550, "JVC KENWOOD Corporation");
IDS.put(8564, "Transcend Information, Inc.");
IDS.put(8566, "TMC/Allion Test Labs");
IDS.put(8613, "Genesis Technology USA, Inc.");
IDS.put(8627, "Dongguan Teconn Electronics Technology Co., Ltd.");
IDS.put(8644, "Netcom Technology (HK) Limited");
IDS.put(8659, "Compupack Technology Co., Ltd.");
IDS.put(8667, "G-Max Technology Co., Ltd.");
IDS.put(8679, "Sagemcom Broadband SAS");
IDS.put(8695, "Wuerth-Elektronik eiSos GmbH & Co. KG");
IDS.put(8707, "Shin Shin Co., Ltd.");
IDS.put(8709, "3eYamaichi Electronics Co., Ltd.");
IDS.put(8710, "Wiretek International Investment Ltd.");
IDS.put(8711, "Fuzhou Rockchip Electronics Co., Ltd.");
IDS.put(8752, "Plugable Technologies");
IDS.put(8756, "T-CONN PRECISION CORPORATION");
IDS.put(8831, "Granite River Labs");
IDS.put(8842, "Hotron Precision Electronic Ind. Corp.");
IDS.put(8875, "Trigence Semiconductor, Inc.");
IDS.put(8888, "Motorola Mobility Inc.");
IDS.put(8904, "Karming Electronic (Shenzhen) Co., Ltd.");
IDS.put(8981, "Avery Design Systems, Inc.");
IDS.put(8993, "iKingdom Corp. (d.b.a. iConnectivity)");
IDS.put(9051, "KangXiang Electronic Co., Ltd.");
IDS.put(9068, "ZheJiang Chunsheng Electronics Co., Ltd.");
IDS.put(9130, "DOK (HK) Trading Limited");
IDS.put(9132, "Marunix Electron Limited");
IDS.put(9165, "Avconn Precise Connector Co., Ltd.");
IDS.put(9184, "BitifEye Digital Test Solutions GmbH");
IDS.put(9205, "Speed Conn Co., Ltd.");
IDS.put(9222, "INSIDE Secure");
IDS.put(9292, "Minebea Co., Ltd.");
IDS.put(9299, "BAANTO");
IDS.put(9338, "Suzhou Jutze Technologies Co., Ltd");
IDS.put(9355, "DONGGUAN SYNCONN PRECISION INDUSTRY CO. LTD.");
IDS.put(9382, "Shenzhen Pangngai Industrial Co., Ltd.");
IDS.put(9422, "Shenzhen Deren Electronic Co., Ltd.");
IDS.put(9424, "Smith Micro Software, Inc.");
IDS.put(9453, "ZEN FACTORY GROUP (ASIA) LTD.");
IDS.put(9481, "Chain-In Electronic Co., Ltd.");
IDS.put(9514, "SUZHOU KELI TECHNOLOGY DEVELOPMENT CO., LTD.");
IDS.put(9515, "TOP Exactitude Industry (ShenZhen) Co., Ltd.");
IDS.put(9525, "ShenZhen Hogend Precision Technology Co., Ltd.");
IDS.put(9527, "Norel Systems Ltd.");
IDS.put(9556, "ASSA ABLOY AB");
IDS.put(9575, "DongGuan LongTao Electronic Co., Ltd.");
IDS.put(9577, "DongGuan City MingJi Electronics Co., Ltd.");
IDS.put(9589, "Weida Hi-Tech Co., Ltd.");
IDS.put(9593, "Dongguan Wisechamp Electronic Co., Ltd.");
IDS.put(9613, "Sequans Communications");
IDS.put(9636, "ALGOLTEK, INC.");
IDS.put(9651, "DongGuan Elinke Industrial Co., Ltd.");
IDS.put(9679, "Corning Optical Communications LLC");
IDS.put(9714, "Dongguan Jinyue Electronics Co., Ltd.");
IDS.put(9723, "RICOH IMAGING COMPANY, LTD.");
IDS.put(9742, "DongGuan HYX Industrial Co., Ltd.");
IDS.put(9753, "Advanced Silicon SA");
IDS.put(9756, "EISST Limited");
IDS.put(9771, "YTOP Electronics Technical (Kunshan) Co., Ltd.");
IDS.put(9841, "Innovative Logic");
IDS.put(9842, "GoPro");
IDS.put(9846, "Basler AG");
IDS.put(9851, "Palpilot International Corp.");
IDS.put(9896, "UNIREX CORPORATION");
IDS.put(9917, "Integral Memory Plc.");
IDS.put(9973, "Morning Star Digital Connector Co., Ltd.");
IDS.put(9984, "MITACHI CO., LTD.");
IDS.put(9999, "HGST, a Western Digital Company");
}
}
================================================
FILE: libuvccamera/src/main/java/com/serenegiant/usb/UVCCamera.java
================================================
/*
* 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 org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
public class UVCCamera {
private static final boolean DEBUG = false; // TODO set false when releasing
private static final String TAG = UVCCamera.class.getSimpleName();
private static final String DEFAULT_USBFS = "/dev/bus/usb";
public static final int DEFAULT_PREVIEW_WIDTH = 640;
public static final int DEFAULT_PREVIEW_HEIGHT = 480;
public static final int DEFAULT_PREVIEW_MODE = 0;
public static final int DEFAULT_PREVIEW_MIN_FPS = 1;
public static final int DEFAULT_PREVIEW_MAX_FPS = 30;
public static final float DEFAULT_BANDWIDTH = 1.0f;
public static final int FRAME_FORMAT_YUYV = 0;
public static final int FRAME_FORMAT_MJPEG = 1;
public static final int PIXEL_FORMAT_RAW = 0;
public static final int PIXEL_FORMAT_YUV = 1;
public static final int PIXEL_FORMAT_RGB565 = 2;
public static final int PIXEL_FORMAT_RGBX = 3;
public static final int PIXEL_FORMAT_YUV420SP = 4;
public static final int PIXEL_FORMAT_NV21 = 5; // = YVU420SemiPlanar
//--------------------------------------------------------------------------------
public static final int CTRL_SCANNING = 0x00000001; // D0: Scanning Mode
public static final int CTRL_AE = 0x00000002; // D1: Auto-Exposure Mode
public static final int CTRL_AE_PRIORITY = 0x00000004; // D2: Auto-Exposure Priority
public static final int CTRL_AE_ABS = 0x00000008; // D3: Exposure Time (Absolute)
public static final int CTRL_AR_REL = 0x00000010; // D4: Exposure Time (Relative)
public static final int CTRL_FOCUS_ABS = 0x00000020; // D5: Focus (Absolute)
public static final int CTRL_FOCUS_REL = 0x00000040; // D6: Focus (Relative)
public static final int CTRL_IRIS_ABS = 0x00000080; // D7: Iris (Absolute)
public static final int CTRL_IRIS_REL = 0x00000100; // D8: Iris (Relative)
public static final int CTRL_ZOOM_ABS = 0x00000200; // D9: Zoom (Absolute)
public static final int CTRL_ZOOM_REL = 0x00000400; // D10: Zoom (Relative)
public static final int CTRL_PANTILT_ABS = 0x00000800; // D11: PanTilt (Absolute)
public static final int CTRL_PANTILT_REL = 0x00001000; // D12: PanTilt (Relative)
public static final int CTRL_ROLL_ABS = 0x00002000; // D13: Roll (Absolute)
public static final int CTRL_ROLL_REL = 0x00004000; // D14: Roll (Relative)
public static final int CTRL_FOCUS_AUTO = 0x00020000; // D17: Focus, Auto
public static final int CTRL_PRIVACY = 0x00040000; // D18: Privacy
public static final int CTRL_FOCUS_SIMPLE = 0x00080000; // D19: Focus, Simple
public static final int CTRL_WINDOW = 0x00100000; // D20: Window
public static final int PU_BRIGHTNESS = 0x80000001; // D0: Brightness
public static final int PU_CONTRAST = 0x80000002; // D1: Contrast
public static final int PU_HUE = 0x80000004; // D2: Hue
public static final int PU_SATURATION = 0x80000008; // D3: Saturation
public static final int PU_SHARPNESS = 0x80000010; // D4: Sharpness
public static final int PU_GAMMA = 0x80000020; // D5: Gamma
public static final int PU_WB_TEMP = 0x80000040; // D6: White Balance Temperature
public static final int PU_WB_COMPO = 0x80000080; // D7: White Balance Component
public static final int PU_BACKLIGHT = 0x80000100; // D8: Backlight Compensation
public static final int PU_GAIN = 0x80000200; // D9: Gain
public static final int PU_POWER_LF = 0x80000400; // D10: Power Line Frequency
public static final int PU_HUE_AUTO = 0x80000800; // D11: Hue, Auto
public static final int PU_WB_TEMP_AUTO = 0x80001000; // D12: White Balance Temperature, Auto
public static final int PU_WB_COMPO_AUTO = 0x80002000; // D13: White Balance Component, Auto
public static final int PU_DIGITAL_MULT = 0x80004000; // D14: Digital Multiplier
public static final int PU_DIGITAL_LIMIT = 0x80008000; // D15: Digital Multiplier Limit
public static final int PU_AVIDEO_STD = 0x80010000; // D16: Analog Video Standard
public static final int PU_AVIDEO_LOCK = 0x80020000; // D17: Analog Video Lock Status
public static final int PU_CONTRAST_AUTO = 0x80040000; // D18: Contrast, Auto
// uvc_status_class from libuvc.h
public static final int STATUS_CLASS_CONTROL = 0x10;
public static final int STATUS_CLASS_CONTROL_CAMERA = 0x11;
public static final int STATUS_CLASS_CONTROL_PROCESSING = 0x12;
// uvc_status_attribute from libuvc.h
public static final int STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00;
public static final int STATUS_ATTRIBUTE_INFO_CHANGE = 0x01;
public static final int STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02;
public static final int STATUS_ATTRIBUTE_UNKNOWN = 0xff;
private static boolean isLoaded;
static {
if (!isLoaded) {
System.loadLibrary("jpeg-turbo1500");
System.loadLibrary("usb100");
System.loadLibrary("uvc");
System.loadLibrary("UVCCamera");
isLoaded = true;
}
}
private UsbControlBlock mCtrlBlock;
protected long mControlSupports; // カメラコントロールでサポートしている機能フラグ
protected long mProcSupports; // プロセッシングユニットでサポートしている機能フラグ
protected int mCurrentFrameFormat = FRAME_FORMAT_MJPEG;
protected int mCurrentWidth = DEFAULT_PREVIEW_WIDTH, mCurrentHeight = DEFAULT_PREVIEW_HEIGHT;
protected float mCurrentBandwidthFactor = DEFAULT_BANDWIDTH;
protected String mSupportedSize;
protected List mCurrentSizeList;
// these fields from here are accessed from native code and do not change name and remove
protected long mNativePtr;
protected int mScanningModeMin, mScanningModeMax, mScanningModeDef;
protected int mExposureModeMin, mExposureModeMax, mExposureModeDef;
protected int mExposurePriorityMin, mExposurePriorityMax, mExposurePriorityDef;
protected int mExposureMin, mExposureMax, mExposureDef;
protected int mAutoFocusMin, mAutoFocusMax, mAutoFocusDef;
protected int mFocusMin, mFocusMax, mFocusDef;
protected int mFocusRelMin, mFocusRelMax, mFocusRelDef;
protected int mFocusSimpleMin, mFocusSimpleMax, mFocusSimpleDef;
protected int mIrisMin, mIrisMax, mIrisDef;
protected int mIrisRelMin, mIrisRelMax, mIrisRelDef;
protected int mPanMin, mPanMax, mPanDef;
protected int mTiltMin, mTiltMax, mTiltDef;
protected int mRollMin, mRollMax, mRollDef;
protected int mPanRelMin, mPanRelMax, mPanRelDef;
protected int mTiltRelMin, mTiltRelMax, mTiltRelDef;
protected int mRollRelMin, mRollRelMax, mRollRelDef;
protected int mPrivacyMin, mPrivacyMax, mPrivacyDef;
protected int mAutoWhiteBlanceMin, mAutoWhiteBlanceMax, mAutoWhiteBlanceDef;
protected int mAutoWhiteBlanceCompoMin, mAutoWhiteBlanceCompoMax, mAutoWhiteBlanceCompoDef;
protected int mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef;
protected int mWhiteBlanceCompoMin, mWhiteBlanceCompoMax, mWhiteBlanceCompoDef;
protected int mWhiteBlanceRelMin, mWhiteBlanceRelMax, mWhiteBlanceRelDef;
protected int mBacklightCompMin, mBacklightCompMax, mBacklightCompDef;
protected int mBrightnessMin, mBrightnessMax, mBrightnessDef;
protected int mContrastMin, mContrastMax, mContrastDef;
protected int mSharpnessMin, mSharpnessMax, mSharpnessDef;
protected int mGainMin, mGainMax, mGainDef;
protected int mGammaMin, mGammaMax, mGammaDef;
protected int mSaturationMin, mSaturationMax, mSaturationDef;
protected int mHueMin, mHueMax, mHueDef;
protected int mZoomMin, mZoomMax, mZoomDef;
protected int mZoomRelMin, mZoomRelMax, mZoomRelDef;
protected int mPowerlineFrequencyMin, mPowerlineFrequencyMax, mPowerlineFrequencyDef;
protected int mMultiplierMin, mMultiplierMax, mMultiplierDef;
protected int mMultiplierLimitMin, mMultiplierLimitMax, mMultiplierLimitDef;
protected int mAnalogVideoStandardMin, mAnalogVideoStandardMax, mAnalogVideoStandardDef;
protected int mAnalogVideoLockStateMin, mAnalogVideoLockStateMax, mAnalogVideoLockStateDef;
// until here
/**
* the sonctructor of this class should be call within the thread that has a looper
* (UI thread or a thread that called Looper.prepare)
*/
public UVCCamera() {
mNativePtr = nativeCreate();
mSupportedSize = null;
}
/**
* connect to a UVC camera
* USB permission is necessary before this method is called
* @param ctrlBlock
*/
public synchronized void open(final UsbControlBlock ctrlBlock) {
int result;
try {
mCtrlBlock = ctrlBlock.clone();
result = nativeConnect(mNativePtr,
mCtrlBlock.getVenderId(), mCtrlBlock.getProductId(),
mCtrlBlock.getFileDescriptor(),
mCtrlBlock.getBusNum(),
mCtrlBlock.getDevNum(),
getUSBFSName(mCtrlBlock));
} catch (final Exception e) {
Log.w(TAG, e);
result = -1;
}
if (result != 0) {
throw new UnsupportedOperationException("open failed:result=" + result);
}
if (mNativePtr != 0 && TextUtils.isEmpty(mSupportedSize)) {
mSupportedSize = nativeGetSupportedSize(mNativePtr);
}
nativeSetPreviewSize(mNativePtr, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT,
DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, DEFAULT_PREVIEW_MODE, DEFAULT_BANDWIDTH);
}
/**
* set status callback
* @param callback
*/
public void setStatusCallback(final IStatusCallback callback) {
if (mNativePtr != 0) {
nativeSetStatusCallback(mNativePtr, callback);
}
}
/**
* set button callback
* @param callback
*/
public void setButtonCallback(final IButtonCallback callback) {
if (mNativePtr != 0) {
nativeSetButtonCallback(mNativePtr, callback);
}
}
/**
* close and release UVC camera
*/
public synchronized void close() {
stopPreview();
if (mNativePtr != 0) {
nativeRelease(mNativePtr);
// mNativePtr = 0; // nativeDestroyを呼ぶのでここでクリアしちゃダメ
}
if (mCtrlBlock != null) {
mCtrlBlock.close();
mCtrlBlock = null;
}
mControlSupports = mProcSupports = 0;
mCurrentFrameFormat = -1;
mCurrentBandwidthFactor = 0;
mSupportedSize = null;
mCurrentSizeList = null;
if (DEBUG) Log.v(TAG, "close:finished");
}
public UsbDevice getDevice() {
return mCtrlBlock != null ? mCtrlBlock.getDevice() : null;
}
public String getDeviceName(){
return mCtrlBlock != null ? mCtrlBlock.getDeviceName() : null;
}
public UsbControlBlock getUsbControlBlock() {
return mCtrlBlock;
}
public synchronized String getSupportedSize() {
return !TextUtils.isEmpty(mSupportedSize) ? mSupportedSize : (mSupportedSize = nativeGetSupportedSize(mNativePtr));
}
public Size getPreviewSize() {
Size result = null;
final List list = getSupportedSizeList();
for (final Size sz: list) {
if ((sz.width == mCurrentWidth)
|| (sz.height == mCurrentHeight)) {
result =sz;
break;
}
}
return result;
}
/**
* Set preview size and preview mode
* @param width
@param height
*/
public void setPreviewSize(final int width, final int height) {
setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, mCurrentFrameFormat, mCurrentBandwidthFactor);
}
/**
* Set preview size and preview mode
* @param width
* @param height
* @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1)
*/
public void setPreviewSize(final int width, final int height, final int frameFormat) {
setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, frameFormat, mCurrentBandwidthFactor);
}
/**
* Set preview size and preview mode
* @param width
@param height
@param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1)
@param bandwidth [0.0f,1.0f]
*/
public void setPreviewSize(final int width, final int height, final int frameFormat, final float bandwidth) {
setPreviewSize(width, height, DEFAULT_PREVIEW_MIN_FPS, DEFAULT_PREVIEW_MAX_FPS, frameFormat, bandwidth);
}
/**
* Set preview size and preview mode
* @param width
* @param height
* @param min_fps
* @param max_fps
* @param frameFormat either FRAME_FORMAT_YUYV(0) or FRAME_FORMAT_MJPEG(1)
* @param bandwidthFactor
*/
public void setPreviewSize(final int width, final int height, final int min_fps, final int max_fps, final int frameFormat, final float bandwidthFactor) {
if ((width == 0) || (height == 0))
throw new IllegalArgumentException("invalid preview size");
if (mNativePtr != 0) {
final int result = nativeSetPreviewSize(mNativePtr, width, height, min_fps, max_fps, frameFormat, bandwidthFactor);
if (result != 0)
throw new IllegalArgumentException("Failed to set preview size");
mCurrentFrameFormat = frameFormat;
mCurrentWidth = width;
mCurrentHeight = height;
mCurrentBandwidthFactor = bandwidthFactor;
}
}
public List getSupportedSizeList() {
final int type = (mCurrentFrameFormat > 0) ? 6 : 4;
return getSupportedSize(type, mSupportedSize);
}
public static List getSupportedSize(final int type, final String supportedSize) {
final List result = new ArrayList();
if (!TextUtils.isEmpty(supportedSize))
try {
final JSONObject json = new JSONObject(supportedSize);
final JSONArray formats = json.getJSONArray("formats");
final int format_nums = formats.length();
for (int i = 0; i < format_nums; i++) {
final JSONObject format = formats.getJSONObject(i);
if(format.has("type") && format.has("size")) {
final int format_type = format.getInt("type");
if ((format_type == type) || (type == -1)) {
addSize(format, format_type, 0, result);
}
}
}
} catch (final JSONException e) {
e.printStackTrace();
}
return result;
}
private static final void addSize(final JSONObject format, final int formatType, final int frameType, final List size_list) throws JSONException {
final JSONArray size = format.getJSONArray("size");
final int size_nums = size.length();
for (int j = 0; j < size_nums; j++) {
final String[] sz = size.getString(j).split("x");
try {
size_list.add(new Size(formatType, frameType, j, Integer.parseInt(sz[0]), Integer.parseInt(sz[1])));
} catch (final Exception e) {
break;
}
}
}
/**
* set preview surface with SurfaceHolder
* you can use SurfaceHolder came from SurfaceView/GLSurfaceView
* @param holder
*/
public synchronized void setPreviewDisplay(final SurfaceHolder holder) {
nativeSetPreviewDisplay(mNativePtr, holder.getSurface());
}
/**
* set preview surface with SurfaceTexture.
* this method require API >= 14
* @param texture
*/
public synchronized void setPreviewTexture(final SurfaceTexture texture) { // API >= 11
final Surface surface = new Surface(texture); // XXX API >= 14
nativeSetPreviewDisplay(mNativePtr, surface);
}
/**
* set preview surface with Surface
* @param surface
*/
public synchronized void setPreviewDisplay(final Surface surface) {
nativeSetPreviewDisplay(mNativePtr, surface);
}
/**
* set frame callback
* @param callback
* @param pixelFormat
*/
public void setFrameCallback(final IFrameCallback callback, final int pixelFormat) {
if (mNativePtr != 0) {
nativeSetFrameCallback(mNativePtr, callback, pixelFormat);
}
}
/**
* start preview
*/
public synchronized void startPreview() {
if (mCtrlBlock != null) {
nativeStartPreview(mNativePtr);
}
}
/**
* stop preview
*/
public synchronized void stopPreview() {
setFrameCallback(null, 0);
if (mCtrlBlock != null) {
nativeStopPreview(mNativePtr);
}
}
/**
* destroy UVCCamera object
*/
public synchronized void destroy() {
close();
if (mNativePtr != 0) {
nativeDestroy(mNativePtr);
mNativePtr = 0;
}
}
// wrong result may return when you call this just after camera open.
// it is better to wait several hundreads millseconds.
public boolean checkSupportFlag(final long flag) {
updateCameraParams();
if ((flag & 0x80000000) == 0x80000000)
return ((mProcSupports & flag) == (flag & 0x7ffffffF));
else
return (mControlSupports & flag) == flag;
}
//================================================================================
public synchronized void setAutoFocus(final boolean autoFocus) {
if (mNativePtr != 0) {
nativeSetAutoFocus(mNativePtr, autoFocus);
}
}
public synchronized boolean getAutoFocus() {
boolean result = true;
if (mNativePtr != 0) {
result = nativeGetAutoFocus(mNativePtr) > 0;
}
return result;
}
//================================================================================
/**
* @param focus [%]
*/
public synchronized void setFocus(final int focus) {
if (mNativePtr != 0) {
final float range = Math.abs(mFocusMax - mFocusMin);
if (range > 0)
nativeSetFocus(mNativePtr, (int)(focus / 100.f * range) + mFocusMin);
}
}
/**
* @param focus_abs
* @return focus[%]
*/
public synchronized int getFocus(final int focus_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateFocusLimit(mNativePtr);
final float range = Math.abs(mFocusMax - mFocusMin);
if (range > 0) {
result = (int)((focus_abs - mFocusMin) * 100.f / range);
}
}
return result;
}
/**
* @return focus[%]
*/
public synchronized int getFocus() {
return getFocus(nativeGetFocus(mNativePtr));
}
public synchronized void resetFocus() {
if (mNativePtr != 0) {
nativeSetFocus(mNativePtr, mFocusDef);
}
}
//================================================================================
public synchronized void setAutoWhiteBlance(final boolean autoWhiteBlance) {
if (mNativePtr != 0) {
nativeSetAutoWhiteBlance(mNativePtr, autoWhiteBlance);
}
}
public synchronized boolean getAutoWhiteBlance() {
boolean result = true;
if (mNativePtr != 0) {
result = nativeGetAutoWhiteBlance(mNativePtr) > 0;
}
return result;
}
//================================================================================
/**
* @param whiteBlance [%]
*/
public synchronized void setWhiteBlance(final int whiteBlance) {
if (mNativePtr != 0) {
final float range = Math.abs(mWhiteBlanceMax - mWhiteBlanceMin);
if (range > 0)
nativeSetWhiteBlance(mNativePtr, (int)(whiteBlance / 100.f * range) + mWhiteBlanceMin);
}
}
/**
* @param whiteBlance_abs
* @return whiteBlance[%]
*/
public synchronized int getWhiteBlance(final int whiteBlance_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateWhiteBlanceLimit(mNativePtr);
final float range = Math.abs(mWhiteBlanceMax - mWhiteBlanceMin);
if (range > 0) {
result = (int)((whiteBlance_abs - mWhiteBlanceMin) * 100.f / range);
}
}
return result;
}
/**
* @return white blance[%]
*/
public synchronized int getWhiteBlance() {
return getFocus(nativeGetWhiteBlance(mNativePtr));
}
public synchronized void resetWhiteBlance() {
if (mNativePtr != 0) {
nativeSetWhiteBlance(mNativePtr, mWhiteBlanceDef);
}
}
//================================================================================
/**
* @param brightness [%]
*/
public synchronized void setBrightness(final int brightness) {
if (mNativePtr != 0) {
final float range = Math.abs(mBrightnessMax - mBrightnessMin);
if (range > 0)
nativeSetBrightness(mNativePtr, (int)(brightness / 100.f * range) + mBrightnessMin);
}
}
/**
* @param brightness_abs
* @return brightness[%]
*/
public synchronized int getBrightness(final int brightness_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateBrightnessLimit(mNativePtr);
final float range = Math.abs(mBrightnessMax - mBrightnessMin);
if (range > 0) {
result = (int)((brightness_abs - mBrightnessMin) * 100.f / range);
}
}
return result;
}
/**
* @return brightness[%]
*/
public synchronized int getBrightness() {
return getBrightness(nativeGetBrightness(mNativePtr));
}
public synchronized void resetBrightness() {
if (mNativePtr != 0) {
nativeSetBrightness(mNativePtr, mBrightnessDef);
}
}
//================================================================================
/**
* @param contrast [%]
*/
public synchronized void setContrast(final int contrast) {
if (mNativePtr != 0) {
nativeUpdateContrastLimit(mNativePtr);
final float range = Math.abs(mContrastMax - mContrastMin);
if (range > 0)
nativeSetContrast(mNativePtr, (int)(contrast / 100.f * range) + mContrastMin);
}
}
/**
* @param contrast_abs
* @return contrast[%]
*/
public synchronized int getContrast(final int contrast_abs) {
int result = 0;
if (mNativePtr != 0) {
final float range = Math.abs(mContrastMax - mContrastMin);
if (range > 0) {
result = (int)((contrast_abs - mContrastMin) * 100.f / range);
}
}
return result;
}
/**
* @return contrast[%]
*/
public synchronized int getContrast() {
return getContrast(nativeGetContrast(mNativePtr));
}
public synchronized void resetContrast() {
if (mNativePtr != 0) {
nativeSetContrast(mNativePtr, mContrastDef);
}
}
//================================================================================
/**
* @param sharpness [%]
*/
public synchronized void setSharpness(final int sharpness) {
if (mNativePtr != 0) {
final float range = Math.abs(mSharpnessMax - mSharpnessMin);
if (range > 0)
nativeSetSharpness(mNativePtr, (int)(sharpness / 100.f * range) + mSharpnessMin);
}
}
/**
* @param sharpness_abs
* @return sharpness[%]
*/
public synchronized int getSharpness(final int sharpness_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateSharpnessLimit(mNativePtr);
final float range = Math.abs(mSharpnessMax - mSharpnessMin);
if (range > 0) {
result = (int)((sharpness_abs - mSharpnessMin) * 100.f / range);
}
}
return result;
}
/**
* @return sharpness[%]
*/
public synchronized int getSharpness() {
return getSharpness(nativeGetSharpness(mNativePtr));
}
public synchronized void resetSharpness() {
if (mNativePtr != 0) {
nativeSetSharpness(mNativePtr, mSharpnessDef);
}
}
//================================================================================
/**
* @param gain [%]
*/
public synchronized void setGain(final int gain) {
if (mNativePtr != 0) {
final float range = Math.abs(mGainMax - mGainMin);
if (range > 0)
nativeSetGain(mNativePtr, (int)(gain / 100.f * range) + mGainMin);
}
}
/**
* @param gain_abs
* @return gain[%]
*/
public synchronized int getGain(final int gain_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateGainLimit(mNativePtr);
final float range = Math.abs(mGainMax - mGainMin);
if (range > 0) {
result = (int)((gain_abs - mGainMin) * 100.f / range);
}
}
return result;
}
/**
* @return gain[%]
*/
public synchronized int getGain() {
return getGain(nativeGetGain(mNativePtr));
}
public synchronized void resetGain() {
if (mNativePtr != 0) {
nativeSetGain(mNativePtr, mGainDef);
}
}
//================================================================================
/**
* @param gamma [%]
*/
public synchronized void setGamma(final int gamma) {
if (mNativePtr != 0) {
final float range = Math.abs(mGammaMax - mGammaMin);
if (range > 0)
nativeSetGamma(mNativePtr, (int)(gamma / 100.f * range) + mGammaMin);
}
}
/**
* @param gamma_abs
* @return gamma[%]
*/
public synchronized int getGamma(final int gamma_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateGammaLimit(mNativePtr);
final float range = Math.abs(mGammaMax - mGammaMin);
if (range > 0) {
result = (int)((gamma_abs - mGammaMin) * 100.f / range);
}
}
return result;
}
/**
* @return gamma[%]
*/
public synchronized int getGamma() {
return getGamma(nativeGetGamma(mNativePtr));
}
public synchronized void resetGamma() {
if (mNativePtr != 0) {
nativeSetGamma(mNativePtr, mGammaDef);
}
}
//================================================================================
/**
* @param saturation [%]
*/
public synchronized void setSaturation(final int saturation) {
if (mNativePtr != 0) {
final float range = Math.abs(mSaturationMax - mSaturationMin);
if (range > 0)
nativeSetSaturation(mNativePtr, (int)(saturation / 100.f * range) + mSaturationMin);
}
}
/**
* @param saturation_abs
* @return saturation[%]
*/
public synchronized int getSaturation(final int saturation_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateSaturationLimit(mNativePtr);
final float range = Math.abs(mSaturationMax - mSaturationMin);
if (range > 0) {
result = (int)((saturation_abs - mSaturationMin) * 100.f / range);
}
}
return result;
}
/**
* @return saturation[%]
*/
public synchronized int getSaturation() {
return getSaturation(nativeGetSaturation(mNativePtr));
}
public synchronized void resetSaturation() {
if (mNativePtr != 0) {
nativeSetSaturation(mNativePtr, mSaturationDef);
}
}
//================================================================================
/**
* @param hue [%]
*/
public synchronized void setHue(final int hue) {
if (mNativePtr != 0) {
final float range = Math.abs(mHueMax - mHueMin);
if (range > 0)
nativeSetHue(mNativePtr, (int)(hue / 100.f * range) + mHueMin);
}
}
/**
* @param hue_abs
* @return hue[%]
*/
public synchronized int getHue(final int hue_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateHueLimit(mNativePtr);
final float range = Math.abs(mHueMax - mHueMin);
if (range > 0) {
result = (int)((hue_abs - mHueMin) * 100.f / range);
}
}
return result;
}
/**
* @return hue[%]
*/
public synchronized int getHue() {
return getHue(nativeGetHue(mNativePtr));
}
public synchronized void resetHue() {
if (mNativePtr != 0) {
nativeSetHue(mNativePtr, mSaturationDef);
}
}
//================================================================================
public void setPowerlineFrequency(final int frequency) {
if (mNativePtr != 0)
nativeSetPowerlineFrequency(mNativePtr, frequency);
}
public int getPowerlineFrequency() {
return nativeGetPowerlineFrequency(mNativePtr);
}
//================================================================================
/**
* this may not work well with some combination of camera and device
* @param zoom [%]
*/
public synchronized void setZoom(final int zoom) {
if (mNativePtr != 0) {
final float range = Math.abs(mZoomMax - mZoomMin);
if (range > 0) {
final int z = (int)(zoom / 100.f * range) + mZoomMin;
// Log.d(TAG, "setZoom:zoom=" + zoom + " ,value=" + z);
nativeSetZoom(mNativePtr, z);
}
}
}
/**
* @param zoom_abs
* @return zoom[%]
*/
public synchronized int getZoom(final int zoom_abs) {
int result = 0;
if (mNativePtr != 0) {
nativeUpdateZoomLimit(mNativePtr);
final float range = Math.abs(mZoomMax - mZoomMin);
if (range > 0) {
result = (int)((zoom_abs - mZoomMin) * 100.f / range);
}
}
return result;
}
/**
* @return zoom[%]
*/
public synchronized int getZoom() {
return getZoom(nativeGetZoom(mNativePtr));
}
public synchronized void resetZoom() {
if (mNativePtr != 0) {
nativeSetZoom(mNativePtr, mZoomDef);
}
}
//================================================================================
public synchronized void updateCameraParams() {
if (mNativePtr != 0) {
if ((mControlSupports == 0) || (mProcSupports == 0)) {
// サポートしている機能フラグを取得
if (mControlSupports == 0)
mControlSupports = nativeGetCtrlSupports(mNativePtr);
if (mProcSupports == 0)
mProcSupports = nativeGetProcSupports(mNativePtr);
// 設定値を取得
if ((mControlSupports != 0) && (mProcSupports != 0)) {
nativeUpdateBrightnessLimit(mNativePtr);
nativeUpdateContrastLimit(mNativePtr);
nativeUpdateSharpnessLimit(mNativePtr);
nativeUpdateGainLimit(mNativePtr);
nativeUpdateGammaLimit(mNativePtr);
nativeUpdateSaturationLimit(mNativePtr);
nativeUpdateHueLimit(mNativePtr);
nativeUpdateZoomLimit(mNativePtr);
nativeUpdateWhiteBlanceLimit(mNativePtr);
nativeUpdateFocusLimit(mNativePtr);
}
if (DEBUG) {
dumpControls(mControlSupports);
dumpProc(mProcSupports);
Log.v(TAG, String.format("Brightness:min=%d,max=%d,def=%d", mBrightnessMin, mBrightnessMax, mBrightnessDef));
Log.v(TAG, String.format("Contrast:min=%d,max=%d,def=%d", mContrastMin, mContrastMax, mContrastDef));
Log.v(TAG, String.format("Sharpness:min=%d,max=%d,def=%d", mSharpnessMin, mSharpnessMax, mSharpnessDef));
Log.v(TAG, String.format("Gain:min=%d,max=%d,def=%d", mGainMin, mGainMax, mGainDef));
Log.v(TAG, String.format("Gamma:min=%d,max=%d,def=%d", mGammaMin, mGammaMax, mGammaDef));
Log.v(TAG, String.format("Saturation:min=%d,max=%d,def=%d", mSaturationMin, mSaturationMax, mSaturationDef));
Log.v(TAG, String.format("Hue:min=%d,max=%d,def=%d", mHueMin, mHueMax, mHueDef));
Log.v(TAG, String.format("Zoom:min=%d,max=%d,def=%d", mZoomMin, mZoomMax, mZoomDef));
Log.v(TAG, String.format("WhiteBlance:min=%d,max=%d,def=%d", mWhiteBlanceMin, mWhiteBlanceMax, mWhiteBlanceDef));
Log.v(TAG, String.format("Focus:min=%d,max=%d,def=%d", mFocusMin, mFocusMax, mFocusDef));
}
}
} else {
mControlSupports = mProcSupports = 0;
}
}
private static final String[] SUPPORTS_CTRL = {
"D0: Scanning Mode",
"D1: Auto-Exposure Mode",
"D2: Auto-Exposure Priority",
"D3: Exposure Time (Absolute)",
"D4: Exposure Time (Relative)",
"D5: Focus (Absolute)",
"D6: Focus (Relative)",
"D7: Iris (Absolute)",
"D8: Iris (Relative)",
"D9: Zoom (Absolute)",
"D10: Zoom (Relative)",
"D11: PanTilt (Absolute)",
"D12: PanTilt (Relative)",
"D13: Roll (Absolute)",
"D14: Roll (Relative)",
"D15: Reserved",
"D16: Reserved",
"D17: Focus, Auto",
"D18: Privacy",
"D19: Focus, Simple",
"D20: Window",
"D21: Region of Interest",
"D22: Reserved, set to zero",
"D23: Reserved, set to zero",
};
private static final String[] SUPPORTS_PROC = {
"D0: Brightness",
"D1: Contrast",
"D2: Hue",
"D3: Saturation",
"D4: Sharpness",
"D5: Gamma",
"D6: White Balance Temperature",
"D7: White Balance Component",
"D8: Backlight Compensation",
"D9: Gain",
"D10: Power Line Frequency",
"D11: Hue, Auto",
"D12: White Balance Temperature, Auto",
"D13: White Balance Component, Auto",
"D14: Digital Multiplier",
"D15: Digital Multiplier Limit",
"D16: Analog Video Standard",
"D17: Analog Video Lock Status",
"D18: Contrast, Auto",
"D19: Reserved. Set to zero",
"D20: Reserved. Set to zero",
"D21: Reserved. Set to zero",
"D22: Reserved. Set to zero",
"D23: Reserved. Set to zero",
};
private static final void dumpControls(final long controlSupports) {
Log.i(TAG, String.format("controlSupports=%x", controlSupports));
for (int i = 0; i < SUPPORTS_CTRL.length; i++) {
Log.i(TAG, SUPPORTS_CTRL[i] + ((controlSupports & (0x1 << i)) != 0 ? "=enabled" : "=disabled"));
}
}
private static final void dumpProc(final long procSupports) {
Log.i(TAG, String.format("procSupports=%x", procSupports));
for (int i = 0; i < SUPPORTS_PROC.length; i++) {
Log.i(TAG, SUPPORTS_PROC[i] + ((procSupports & (0x1 << i)) != 0 ? "=enabled" : "=disabled"));
}
}
private final String getUSBFSName(final UsbControlBlock ctrlBlock) {
String result = null;
final String name = ctrlBlock.getDeviceName();
final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null;
if ((v != null) && (v.length > 2)) {
final StringBuilder sb = new StringBuilder(v[0]);
for (int i = 1; i < v.length - 2; i++)
sb.append("/").append(v[i]);
result = sb.toString();
}
if (TextUtils.isEmpty(result)) {
Log.w(TAG, "failed to get USBFS path, try to use default path:" + name);
result = DEFAULT_USBFS;
}
return result;
}
// #nativeCreate and #nativeDestroy are not static methods.
private final native long nativeCreate();
private final native void nativeDestroy(final long id_camera);
private final native int nativeConnect(long id_camera, int venderId, int productId, int fileDescriptor, int busNum, int devAddr, String usbfs);
private static final native int nativeRelease(final long id_camera);
private static final native int nativeSetStatusCallback(final long mNativePtr, final IStatusCallback callback);
private static final native int nativeSetButtonCallback(final long mNativePtr, final IButtonCallback callback);
private static final native int nativeSetPreviewSize(final long id_camera, final int width, final int height, final int min_fps, final int max_fps, final int mode, final float bandwidth);
private static final native String nativeGetSupportedSize(final long id_camera);
private static final native int nativeStartPreview(final long id_camera);
private static final native int nativeStopPreview(final long id_camera);
private static final native int nativeSetPreviewDisplay(final long id_camera, final Surface surface);
private static final native int nativeSetFrameCallback(final long mNativePtr, final IFrameCallback callback, final int pixelFormat);
//**********************************************************************
/**
* start movie capturing(this should call while previewing)
* @param surface
*/
public void startCapture(final Surface surface) {
if (mCtrlBlock != null && surface != null) {
nativeSetCaptureDisplay(mNativePtr, surface);
} else
throw new NullPointerException("startCapture");
}
/**
* stop movie capturing
*/
public void stopCapture() {
if (mCtrlBlock != null) {
nativeSetCaptureDisplay(mNativePtr, null);
}
}
private static final native int nativeSetCaptureDisplay(final long id_camera, final Surface surface);
private static final native long nativeGetCtrlSupports(final long id_camera);
private static final native long nativeGetProcSupports(final long id_camera);
private final native int nativeUpdateScanningModeLimit(final long id_camera);
private static final native int nativeSetScanningMode(final long id_camera, final int scanning_mode);
private static final native int nativeGetScanningMode(final long id_camera);
private final native int nativeUpdateExposureModeLimit(final long id_camera);
private static final native int nativeSetExposureMode(final long id_camera, final int exposureMode);
private static final native int nativeGetExposureMode(final long id_camera);
private final native int nativeUpdateExposurePriorityLimit(final long id_camera);
private static final native int nativeSetExposurePriority(final long id_camera, final int priority);
private static final native int nativeGetExposurePriority(final long id_camera);
private final native int nativeUpdateExposureLimit(final long id_camera);
private static final native int nativeSetExposure(final long id_camera, final int exposure);
private static final native int nativeGetExposure(final long id_camera);
private final native int nativeUpdateExposureRelLimit(final long id_camera);
private static final native int nativeSetExposureRel(final long id_camera, final int exposure_rel);
private static final native int nativeGetExposureRel(final long id_camera);
private final native int nativeUpdateAutoFocusLimit(final long id_camera);
private static final native int nativeSetAutoFocus(final long id_camera, final boolean autofocus);
private static final native int nativeGetAutoFocus(final long id_camera);
private final native int nativeUpdateFocusLimit(final long id_camera);
private static final native int nativeSetFocus(final long id_camera, final int focus);
private static final native int nativeGetFocus(final long id_camera);
private final native int nativeUpdateFocusRelLimit(final long id_camera);
private static final native int nativeSetFocusRel(final long id_camera, final int focus_rel);
private static final native int nativeGetFocusRel(final long id_camera);
private final native int nativeUpdateIrisLimit(final long id_camera);
private static final native int nativeSetIris(final long id_camera, final int iris);
private static final native int nativeGetIris(final long id_camera);
private final native int nativeUpdateIrisRelLimit(final long id_camera);
private static final native int nativeSetIrisRel(final long id_camera, final int iris_rel);
private static final native int nativeGetIrisRel(final long id_camera);
private final native int nativeUpdatePanLimit(final long id_camera);
private static final native int nativeSetPan(final long id_camera, final int pan);
private static final native int nativeGetPan(final long id_camera);
private final native int nativeUpdatePanRelLimit(final long id_camera);
private static final native int nativeSetPanRel(final long id_camera, final int pan_rel);
private static final native int nativeGetPanRel(final long id_camera);
private final native int nativeUpdateTiltLimit(final long id_camera);
private static final native int nativeSetTilt(final long id_camera, final int tilt);
private static final native int nativeGetTilt(final long id_camera);
private final native int nativeUpdateTiltRelLimit(final long id_camera);
private static final native int nativeSetTiltRel(final long id_camera, final int tilt_rel);
private static final native int nativeGetTiltRel(final long id_camera);
private final native int nativeUpdateRollLimit(final long id_camera);
private static final native int nativeSetRoll(final long id_camera, final int roll);
private static final native int nativeGetRoll(final long id_camera);
private final native int nativeUpdateRollRelLimit(final long id_camera);
private static final native int nativeSetRollRel(final long id_camera, final int roll_rel);
private static final native int nativeGetRollRel(final long id_camera);
private final native int nativeUpdateAutoWhiteBlanceLimit(final long id_camera);
private static final native int nativeSetAutoWhiteBlance(final long id_camera, final boolean autoWhiteBlance);
private static final native int nativeGetAutoWhiteBlance(final long id_camera);
private final native int nativeUpdateAutoWhiteBlanceCompoLimit(final long id_camera);
private static final native int nativeSetAutoWhiteBlanceCompo(final long id_camera, final boolean autoWhiteBlanceCompo);
private static final native int nativeGetAutoWhiteBlanceCompo(final long id_camera);
private final native int nativeUpdateWhiteBlanceLimit(final long id_camera);
private static final native int nativeSetWhiteBlance(final long id_camera, final int whiteBlance);
private static final native int nativeGetWhiteBlance(final long id_camera);
private final native int nativeUpdateWhiteBlanceCompoLimit(final long id_camera);
private static final native int nativeSetWhiteBlanceCompo(final long id_camera, final int whiteBlance_compo);
private static final native int nativeGetWhiteBlanceCompo(final long id_camera);
private final native int nativeUpdateBacklightCompLimit(final long id_camera);
private static final native int nativeSetBacklightComp(final long id_camera, final int backlight_comp);
private static final native int nativeGetBacklightComp(final long id_camera);
private final native int nativeUpdateBrightnessLimit(final long id_camera);
private static final native int nativeSetBrightness(final long id_camera, final int brightness);
private static final native int nativeGetBrightness(final long id_camera);
private final native int nativeUpdateContrastLimit(final long id_camera);
private static final native int nativeSetContrast(final long id_camera, final int contrast);
private static final native int nativeGetContrast(final long id_camera);
private final native int nativeUpdateAutoContrastLimit(final long id_camera);
private static final native int nativeSetAutoContrast(final long id_camera, final boolean autocontrast);
private static final native int nativeGetAutoContrast(final long id_camera);
private final native int nativeUpdateSharpnessLimit(final long id_camera);
private static final native int nativeSetSharpness(final long id_camera, final int sharpness);
private static final native int nativeGetSharpness(final long id_camera);
private final native int nativeUpdateGainLimit(final long id_camera);
private static final native int nativeSetGain(final long id_camera, final int gain);
private static final native int nativeGetGain(final long id_camera);
private final native int nativeUpdateGammaLimit(final long id_camera);
private static final native int nativeSetGamma(final long id_camera, final int gamma);
private static final native int nativeGetGamma(final long id_camera);
private final native int nativeUpdateSaturationLimit(final long id_camera);
private static final native int nativeSetSaturation(final long id_camera, final int saturation);
private static final native int nativeGetSaturation(final long id_camera);
private final native int nativeUpdateHueLimit(final long id_camera);
private static final native int nativeSetHue(final long id_camera, final int hue);
private static final native int nativeGetHue(final long id_camera);
private final native int nativeUpdateAutoHueLimit(final long id_camera);
private static final native int nativeSetAutoHue(final long id_camera, final boolean autohue);
private static final native int nativeGetAutoHue(final long id_camera);
private final native int nativeUpdatePowerlineFrequencyLimit(final long id_camera);
private static final native int nativeSetPowerlineFrequency(final long id_camera, final int frequency);
private static final native int nativeGetPowerlineFrequency(final long id_camera);
private final native int nativeUpdateZoomLimit(final long id_camera);
private static final native int nativeSetZoom(final long id_camera, final int zoom);
private static final native int nativeGetZoom(final long id_camera);
private final native int nativeUpdateZoomRelLimit(final long id_camera);
private static final native int nativeSetZoomRel(final long id_camera, final int zoom_rel);
private static final native int nativeGetZoomRel(final long id_camera);
private final native int nativeUpdateDigitalMultiplierLimit(final long id_camera);
private static final native int nativeSetDigitalMultiplier(final long id_camera, final int multiplier);
private static final native int nativeGetDigitalMultiplier(final long id_camera);
private final native int nativeUpdateDigitalMultiplierLimitLimit(final long id_camera);
private static final native int nativeSetDigitalMultiplierLimit(final long id_camera, final int multiplier_limit);
private static final native int nativeGetDigitalMultiplierLimit(final long id_camera);
private final native int nativeUpdateAnalogVideoStandardLimit(final long id_camera);
private static final native int nativeSetAnalogVideoStandard(final long id_camera, final int standard);
private static final native int nativeGetAnalogVideoStandard(final long id_camera);
private final native int nativeUpdateAnalogVideoLockStateLimit(final long id_camera);
private static final native int nativeSetAnalogVideoLoackState(final long id_camera, final int state);
private static final native int nativeGetAnalogVideoLoackState(final long id_camera);
private final native int nativeUpdatePrivacyLimit(final long id_camera);
private static final native int nativeSetPrivacy(final long id_camera, final boolean privacy);
private static final native int nativeGetPrivacy(final long id_camera);
}
================================================
FILE: libuvccamera/src/main/jni/Android.mk
================================================
#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
================================================
FILE: libuvccamera/src/main/jni/Application.mk
================================================
#/*
# * 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-14
APP_ABI := armeabi armeabi-v7a x86 mips
#APP_OPTIM := debug
APP_OPTIM := release
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/Android.mk
================================================
#/*
# * 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)
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/Parameters.cpp
================================================
/*
* 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 &writer, const char *key, const char *value) {
writer.String(key);
writer.String(value);
}
static void write(Writer &writer, const char *key, uint16_t value) {
writer.String(key);
writer.Uint(value);
}
static void write(Writer &writer, const char *key, int32_t value) {
writer.String(key);
writer.Int(value);
}
static void write(Writer &writer, const char *key, uint32_t value) {
writer.String(key);
writer.Uint(value);
}
static void write(Writer &writer, const char *key, int64_t value) {
writer.String(key);
writer.Int64(value);
}
static void write(Writer &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 &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 &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 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 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 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 *);
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/Parameters.h
================================================
/*
* 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_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCButtonCallback.cpp
================================================
#include
#include
#include
#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(user_ptr);
JavaVM *vm = getVM();
JNIEnv *env;
// attach to JavaVM
vm->AttachCurrentThread(&env, NULL);
buttonCallback->notifyButtonCallback(env, button, state);
vm->DetachCurrentThread();
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCButtonCallback.h
================================================
#ifndef UVCBUTTONCALLBACK_H_
#define UVCBUTTONCALLBACK_H_
#include "libUVCCamera.h"
#include
#include
#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_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCCamera.cpp
================================================
/*
* 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.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 "UVCCamera"
#if 1 // デバッグ情報を出さない時1
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // LOGV/LOGD/MARKを出力しない時
#endif
#undef USE_LOGALL // 指定したLOGxだけを出力
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG
#define GET_RAW_DESCRIPTOR
#endif
//**********************************************************************
//
//**********************************************************************
#include
#include
#include
#include
#include "UVCCamera.h"
#include "Parameters.h"
#include "libuvc_internal.h"
#define LOCAL_DEBUG 0
//**********************************************************************
//
//**********************************************************************
/**
* コンストラクタ
*/
UVCCamera::UVCCamera()
: mFd(0),
mUsbFs(NULL),
mContext(NULL),
mDevice(NULL),
mDeviceHandle(NULL),
mStatusCallback(NULL),
mButtonCallback(NULL),
mPreview(NULL),
mCtrlSupports(0),
mPUSupports(0) {
ENTER();
clearCameraParams();
EXIT();
}
/**
* デストラクタ
*/
UVCCamera::~UVCCamera() {
ENTER();
release();
if (mContext) {
uvc_exit(mContext);
mContext = NULL;
}
if (mUsbFs) {
free(mUsbFs);
mUsbFs = NULL;
}
EXIT();
}
void UVCCamera::clearCameraParams() {
mCtrlSupports = mPUSupports = 0;
mScanningMode.min = mScanningMode.max = mScanningMode.def = 0;
mExposureMode.min = mExposureMode.max = mExposureMode.def = 0;
mExposurePriority.min = mExposurePriority.max = mExposurePriority.def = 0;
mExposureAbs.min = mExposureAbs.max = mExposureAbs.def = 0;
mAutoFocus.min = mAutoFocus.max = mAutoFocus.def = 0;
mAutoWhiteBlance.min = mAutoWhiteBlance.max = mAutoWhiteBlance.def = 0;
mWhiteBlance.min = mWhiteBlance.max = mWhiteBlance.def = 0;
mAutoWhiteBlanceCompo.min = mAutoWhiteBlanceCompo.max = mAutoWhiteBlanceCompo.def = 0;
mWhiteBlanceCompo.min = mWhiteBlanceCompo.max = mWhiteBlanceCompo.def = 0;
mBacklightComp.min = mBacklightComp.max = mBacklightComp.def = 0;
mBrightness.min = mBrightness.max = mBrightness.def = 0;
mContrast.min = mContrast.max = mContrast.def = 0;
mAutoContrast.min = mAutoContrast.max = mAutoContrast.def = 0;
mSharpness.min = mSharpness.max = mSharpness.def = 0;
mGain.min = mGain.max = mGain.def = 0;
mGamma.min = mGamma.max = mGamma.def = 0;
mSaturation.min = mSaturation.max = mSaturation.def = 0;
mHue.min = mHue.max = mHue.def = 0;
mAutoHue.min = mAutoHue.max = mAutoHue.def = 0;
mZoom.min = mZoom.max = mZoom.def = 0;
mZoomRel.min = mZoomRel.max = mZoomRel.def = 0;
mFocus.min = mFocus.max = mFocus.def = 0;
mFocusRel.min = mFocusRel.max = mFocusRel.def = 0;
mFocusSimple.min = mFocusSimple.max = mFocusSimple.def = 0;
mIris.min = mIris.max = mIris.def = 0;
mIrisRel.min = mIrisRel.max = mIrisRel.def = 0;
mPan.min = mPan.max = mPan.def = 0; mPan.current = -1;
mTilt.min = mTilt.max = mTilt.def = 0; mTilt.current = -1;
mRoll.min = mRoll.max = mRoll.def = 0;
mPanRel.min = mPanRel.max = mPanRel.def = 0; mPanRel.current = -1;
mTiltRel.min = mTiltRel.max = mTiltRel.def = 0; mTiltRel.current = -1;
mRollRel.min = mRollRel.max = mRollRel.def = 0;
mPrivacy.min = mPrivacy.max = mPrivacy.def = 0;
mPowerlineFrequency.min = mPowerlineFrequency.max = mPowerlineFrequency.def = 0;
mMultiplier.min = mMultiplier.max = mMultiplier.def = 0;
mMultiplierLimit.min = mMultiplierLimit.max = mMultiplierLimit.def = 0;
mAnalogVideoStandard.min = mAnalogVideoStandard.max = mAnalogVideoStandard.def = 0;
mAnalogVideoLockState.min = mAnalogVideoLockState.max = mAnalogVideoLockState.def = 0;
}
//======================================================================
/**
* カメラへ接続する
*/
int UVCCamera::connect(int vid, int pid, int fd, int busnum, int devaddr, const char *usbfs) {
ENTER();
uvc_error_t result = UVC_ERROR_BUSY;
if (!mDeviceHandle && fd) {
if (mUsbFs)
free(mUsbFs);
mUsbFs = strdup(usbfs);
if (UNLIKELY(!mContext)) {
result = uvc_init2(&mContext, NULL, mUsbFs);
// libusb_set_debug(mContext->usb_ctx, LIBUSB_LOG_LEVEL_DEBUG);
if (UNLIKELY(result < 0)) {
LOGD("failed to init libuvc");
RETURN(result, int);
}
}
// カメラ機能フラグをクリア
clearCameraParams();
fd = dup(fd);
// 指定したvid,idを持つデバイスを検索, 見つかれば0を返してmDeviceに見つかったデバイスをセットする(既に1回uvc_ref_deviceを呼んである)
// result = uvc_find_device2(mContext, &mDevice, vid, pid, NULL, fd);
result = uvc_get_device_with_fd(mContext, &mDevice, vid, pid, NULL, fd, busnum, devaddr);
if (LIKELY(!result)) {
// カメラのopen処理
result = uvc_open(mDevice, &mDeviceHandle);
if (LIKELY(!result)) {
// open出来た時
#if LOCAL_DEBUG
uvc_print_diag(mDeviceHandle, stderr);
#endif
mFd = fd;
mStatusCallback = new UVCStatusCallback(mDeviceHandle);
mButtonCallback = new UVCButtonCallback(mDeviceHandle);
mPreview = new UVCPreview(mDeviceHandle);
} else {
// open出来なかった時
LOGE("could not open camera:err=%d", result);
uvc_unref_device(mDevice);
// SAFE_DELETE(mDevice); // 参照カウンタが0ならuvc_unref_deviceでmDeviceがfreeされるから不要 XXX クラッシュ, 既に破棄されているのを再度破棄しようとしたからみたい
mDevice = NULL;
mDeviceHandle = NULL;
close(fd);
}
} else {
LOGE("could not find camera:err=%d", result);
close(fd);
}
} else {
// カメラが既にopenしている時
LOGW("camera is already opened. you should release first");
}
RETURN(result, int);
}
// カメラを開放する
int UVCCamera::release() {
ENTER();
stopPreview();
// カメラのclose処理
if (LIKELY(mDeviceHandle)) {
MARK("カメラがopenしていたら開放する");
// ステータスコールバックオブジェクトを破棄
SAFE_DELETE(mStatusCallback);
SAFE_DELETE(mButtonCallback);
// プレビューオブジェクトを破棄
SAFE_DELETE(mPreview);
// カメラをclose
uvc_close(mDeviceHandle);
mDeviceHandle = NULL;
}
if (LIKELY(mDevice)) {
MARK("カメラを開放");
uvc_unref_device(mDevice);
mDevice = NULL;
}
// カメラ機能フラグをクリア
clearCameraParams();
if (mUsbFs) {
close(mFd);
mFd = 0;
free(mUsbFs);
mUsbFs = NULL;
}
RETURN(0, int);
}
int UVCCamera::setStatusCallback(JNIEnv *env, jobject status_callback_obj) {
ENTER();
int result = EXIT_FAILURE;
if (mStatusCallback) {
result = mStatusCallback->setCallback(env, status_callback_obj);
}
RETURN(result, int);
}
int UVCCamera::setButtonCallback(JNIEnv *env, jobject button_callback_obj) {
ENTER();
int result = EXIT_FAILURE;
if (mButtonCallback) {
result = mButtonCallback->setCallback(env, button_callback_obj);
}
RETURN(result, int);
}
char *UVCCamera::getSupportedSize() {
ENTER();
if (mDeviceHandle) {
UVCDiags params;
RETURN(params.getSupportedSize(mDeviceHandle), char *)
}
RETURN(NULL, char *);
}
int UVCCamera::setPreviewSize(int width, int height, int min_fps, int max_fps, int mode, float bandwidth) {
ENTER();
int result = EXIT_FAILURE;
if (mPreview) {
result = mPreview->setPreviewSize(width, height, min_fps, max_fps, mode, bandwidth);
}
RETURN(result, int);
}
int UVCCamera::setPreviewDisplay(ANativeWindow *preview_window) {
ENTER();
int result = EXIT_FAILURE;
if (mPreview) {
result = mPreview->setPreviewDisplay(preview_window);
}
RETURN(result, int);
}
int UVCCamera::setFrameCallback(JNIEnv *env, jobject frame_callback_obj, int pixel_format) {
ENTER();
int result = EXIT_FAILURE;
if (mPreview) {
result = mPreview->setFrameCallback(env, frame_callback_obj, pixel_format);
}
RETURN(result, int);
}
int UVCCamera::startPreview() {
ENTER();
int result = EXIT_FAILURE;
if (mDeviceHandle) {
return mPreview->startPreview();
}
RETURN(result, int);
}
int UVCCamera::stopPreview() {
ENTER();
if (LIKELY(mPreview)) {
mPreview->stopPreview();
}
RETURN(0, int);
}
int UVCCamera::setCaptureDisplay(ANativeWindow *capture_window) {
ENTER();
int result = EXIT_FAILURE;
if (mPreview) {
result = mPreview->setCaptureDisplay(capture_window);
}
RETURN(result, int);
}
//======================================================================
// カメラのサポートしているコントロール機能を取得する
int UVCCamera::getCtrlSupports(uint64_t *supports) {
ENTER();
uvc_error_t ret = UVC_ERROR_NOT_FOUND;
if (LIKELY(mDeviceHandle)) {
if (!mCtrlSupports) {
// 何個あるのかわからへんねんけど、試した感じは1個みたいやからとりあえず先頭のを返す
const uvc_input_terminal_t *input_terminals = uvc_get_input_terminals(mDeviceHandle);
const uvc_input_terminal_t *it;
DL_FOREACH(input_terminals, it)
{
if (it) {
mCtrlSupports = it->bmControls;
MARK("getCtrlSupports=%lx", (unsigned long)mCtrlSupports);
ret = UVC_SUCCESS;
break;
}
}
} else
ret = UVC_SUCCESS;
}
if (supports)
*supports = mCtrlSupports;
RETURN(ret, int);
}
int UVCCamera::getProcSupports(uint64_t *supports) {
ENTER();
uvc_error_t ret = UVC_ERROR_NOT_FOUND;
if (LIKELY(mDeviceHandle)) {
if (!mPUSupports) {
// 何個あるのかわからへんねんけど、試した感じは1個みたいやからとりあえず先頭のを返す
const uvc_processing_unit_t *proc_units = uvc_get_processing_units(mDeviceHandle);
const uvc_processing_unit_t *pu;
DL_FOREACH(proc_units, pu)
{
if (pu) {
mPUSupports = pu->bmControls;
MARK("getProcSupports=%lx", (unsigned long)mPUSupports);
ret = UVC_SUCCESS;
break;
}
}
} else
ret = UVC_SUCCESS;
}
if (supports)
*supports = mPUSupports;
RETURN(ret, int);
}
//======================================================================
#define CTRL_BRIGHTNESS 0
#define CTRL_CONTRAST 1
#define CTRL_SHARPNESS 2
#define CTRL_GAIN 3
#define CTRL_WHITEBLANCE 4
#define CTRL_FOCUS 5
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_i16 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
int16_t value;
ret = get_func(devh, &value, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = value;
LOGV("update_params:min value=%d,min=%d", value, values.min);
ret = get_func(devh, &value, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = value;
LOGV("update_params:max value=%d,max=%d", value, values.max);
ret = get_func(devh, &value, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = value;
LOGV("update_params:def value=%d,def=%d", value, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_u16 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
uint16_t value;
ret = get_func(devh, &value, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = value;
LOGV("update_params:min value=%d,min=%d", value, values.min);
ret = get_func(devh, &value, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = value;
LOGV("update_params:max value=%d,max=%d", value, values.max);
ret = get_func(devh, &value, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = value;
LOGV("update_params:def value=%d,def=%d", value, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_i8 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
int8_t value;
ret = get_func(devh, &value, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = value;
LOGV("update_params:min value=%d,min=%d", value, values.min);
ret = get_func(devh, &value, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = value;
LOGV("update_params:max value=%d,max=%d", value, values.max);
ret = get_func(devh, &value, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = value;
LOGV("update_params:def value=%d,def=%d", value, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_u8 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
uint8_t value;
ret = get_func(devh, &value, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = value;
LOGV("update_params:min value=%d,min=%d", value, values.min);
ret = get_func(devh, &value, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = value;
LOGV("update_params:max value=%d,max=%d", value, values.max);
ret = get_func(devh, &value, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = value;
LOGV("update_params:def value=%d,def=%d", value, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_u8u8 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
uint8_t value1, value2;
ret = get_func(devh, &value1, &value2, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = (value1 << 8) + value2;
LOGV("update_params:min value1=%d,value2=%d,min=%d", value1, value2, values.min);
ret = get_func(devh, &value1, &value2, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = (value1 << 8) + value2;
LOGV("update_params:max value1=%d,value2=%d,max=%d", value1, value2, values.max);
ret = get_func(devh, &value1, &value2, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = (value1 << 8) + value2;
LOGV("update_params:def value1=%d,value2=%ddef=%d", value1, value2, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_i8u8 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
int8_t value1;
uint8_t value2;
ret = get_func(devh, &value1, &value2, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = (value1 << 8) + value2;
LOGV("update_params:min value1=%d,value2=%d,min=%d", value1, value2, values.min);
ret = get_func(devh, &value1, &value2, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = (value1 << 8) + value2;
LOGV("update_params:max value1=%d,value2=%d,max=%d", value1, value2, values.max);
ret = get_func(devh, &value1, &value2, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = (value1 << 8) + value2;
LOGV("update_params:def value1=%d,value2=%ddef=%d", value1, value2, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_i8u8u8 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
int8_t value1;
uint8_t value2;
uint8_t value3;
ret = get_func(devh, &value1, &value2, &value3, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = (value1 << 16) + (value2 <<8) +value3;
LOGV("update_params:min value1=%d,value2=%d,value3=%d,min=%d", value1, value2, value3, values.min);
ret = get_func(devh, &value1, &value2, &value3, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = (value1 << 16) + (value2 <<8) +value3;
LOGV("update_params:max value1=%d,value2=%d,value3=%d,max=%d", value1, value2, value3, values.max);
ret = get_func(devh, &value1, &value2, &value3, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = (value1 << 16) + (value2 <<8) +value3;
LOGV("update_params:def value1=%d,value2=%d,value3=%d,def=%d", value1, value2, value3, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_i32 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
int32_t value;
ret = get_func(devh, &value, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = value;
LOGV("update_params:min value=%d,min=%d", value, values.min);
ret = get_func(devh, &value, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = value;
LOGV("update_params:max value=%d,max=%d", value, values.max);
ret = get_func(devh, &value, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = value;
LOGV("update_params:def value=%d,def=%d", value, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values,
paramget_func_u32 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if (!values.min && !values.max) {
uint32_t value;
ret = get_func(devh, &value, UVC_GET_MIN);
if (LIKELY(!ret)) {
values.min = value;
LOGV("update_params:min value=%d,min=%d", value, values.min);
ret = get_func(devh, &value, UVC_GET_MAX);
if (LIKELY(!ret)) {
values.max = value;
LOGV("update_params:max value=%d,max=%d", value, values.max);
ret = get_func(devh, &value, UVC_GET_DEF);
if (LIKELY(!ret)) {
values.def = value;
LOGV("update_params:def value=%d,def=%d", value, values.def);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
static uvc_error_t update_ctrl_values(uvc_device_handle_t *devh, control_value_t &values1, control_value_t &values2,
paramget_func_i32i32 get_func) {
ENTER();
uvc_error_t ret = UVC_SUCCESS;
if ((!values1.min && !values1.max) ||(!values2.min && !values2.max)) {
int32_t value1, value2;
ret = get_func(devh, &value1, &value2, UVC_GET_MIN);
if (LIKELY(!ret)) {
values1.min = value1;
values2.min = value2;
LOGV("update_params:min value1=%d,value2=%d", value1, value2);
ret = get_func(devh, &value1, &value2, UVC_GET_MAX);
if (LIKELY(!ret)) {
values1.max = value1;
values2.max = value2;
LOGV("update_params:max value1=%d,value2=%d", value1, value2);
ret = get_func(devh, &value1, &value2, UVC_GET_DEF);
if (LIKELY(!ret)) {
values1.def = value1;
values2.def = value2;
LOGV("update_params:def value1=%d,value2=%d", value1, value2);
}
}
}
}
if (UNLIKELY(ret)) {
LOGD("update_params failed:err=%d", ret);
}
RETURN(ret, uvc_error_t);
}
#define UPDATE_CTRL_VALUES(VAL,FUNC) \
ret = update_ctrl_values(mDeviceHandle, VAL, FUNC); \
if (LIKELY(!ret)) { \
min = VAL.min; \
max = VAL.max; \
def = VAL.def; \
} else { \
MARK("failed to UPDATE_CTRL_VALUES"); \
} \
/**
* カメラコントロール設定の下請け
*/
int UVCCamera::internalSetCtrlValue(control_value_t &values, int8_t value,
paramget_func_i8 get_func, paramset_func_i8 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
value = value < values.min
? values.min
: (value > values.max ? values.max : value);
set_func(mDeviceHandle, value);
}
RETURN(ret, int);
}
int UVCCamera::internalSetCtrlValue(control_value_t &values, uint8_t value,
paramget_func_u8 get_func, paramset_func_u8 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
value = value < values.min
? values.min
: (value > values.max ? values.max : value);
set_func(mDeviceHandle, value);
}
RETURN(ret, int);
}
int UVCCamera::internalSetCtrlValue(control_value_t &values, uint8_t value1, uint8_t value2,
paramget_func_u8u8 get_func, paramset_func_u8u8 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint8_t v1min = (uint8_t)((values.min >> 8) & 0xff);
uint8_t v2min = (uint8_t)(values.min & 0xff);
uint8_t v1max = (uint8_t)((values.max >> 8) & 0xff);
uint8_t v2max = (uint8_t)(values.max & 0xff);
value1 = value1 < v1min
? v1min
: (value1 > v1max ? v1max : value1);
value2 = value2 < v2min
? v2min
: (value2 > v2max ? v2max : value2);
set_func(mDeviceHandle, value1, value2);
}
RETURN(ret, int);
}
int UVCCamera::internalSetCtrlValue(control_value_t &values, int8_t value1, uint8_t value2,
paramget_func_i8u8 get_func, paramset_func_i8u8 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int8_t v1min = (int8_t)((values.min >> 8) & 0xff);
uint8_t v2min = (uint8_t)(values.min & 0xff);
int8_t v1max = (int8_t)((values.max >> 8) & 0xff);
uint8_t v2max = (uint8_t)(values.max & 0xff);
value1 = value1 < v1min
? v1min
: (value1 > v1max ? v1max : value1);
value2 = value2 < v2min
? v2min
: (value2 > v2max ? v2max : value2);
set_func(mDeviceHandle, value1, value2);
}
RETURN(ret, int);
}
int UVCCamera::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 ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int8_t v1min = (int8_t)((values.min >> 16) & 0xff);
uint8_t v2min = (uint8_t)((values.min >> 8) & 0xff);
uint8_t v3min = (uint8_t)(values.min & 0xff);
int8_t v1max = (int8_t)((values.max >> 16) & 0xff);
uint8_t v2max = (uint8_t)((values.max >> 8) & 0xff);
uint8_t v3max = (uint8_t)(values.max & 0xff);
value1 = value1 < v1min
? v1min
: (value1 > v1max ? v1max : value1);
value2 = value2 < v2min
? v2min
: (value2 > v2max ? v2max : value2);
value3 = value3 < v3min
? v3min
: (value3 > v3max ? v3max : value3);
set_func(mDeviceHandle, value1, value2, value3);
}
RETURN(ret, int);
}
/**
* カメラコントロール設定の下請け
*/
int UVCCamera::internalSetCtrlValue(control_value_t &values, int16_t value,
paramget_func_i16 get_func, paramset_func_i16 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
value = value < values.min
? values.min
: (value > values.max ? values.max : value);
set_func(mDeviceHandle, value);
}
RETURN(ret, int);
}
/**
* カメラコントロール設定の下請け
*/
int UVCCamera::internalSetCtrlValue(control_value_t &values, uint16_t value,
paramget_func_u16 get_func, paramset_func_u16 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
value = value < values.min
? values.min
: (value > values.max ? values.max : value);
set_func(mDeviceHandle, value);
}
RETURN(ret, int);
}
/**
* カメラコントロール設定の下請け
*/
int UVCCamera::internalSetCtrlValue(control_value_t &values, int32_t value,
paramget_func_i32 get_func, paramset_func_i32 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
value = value < values.min
? values.min
: (value > values.max ? values.max : value);
set_func(mDeviceHandle, value);
}
RETURN(ret, int);
}
/**
* カメラコントロール設定の下請け
*/
int UVCCamera::internalSetCtrlValue(control_value_t &values, uint32_t value,
paramget_func_u32 get_func, paramset_func_u32 set_func) {
int ret = update_ctrl_values(mDeviceHandle, values, get_func);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
value = value < values.min
? values.min
: (value > values.max ? values.max : value);
set_func(mDeviceHandle, value);
}
RETURN(ret, int);
}
//======================================================================
// スキャニングモード
int UVCCamera::updateScanningModeLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & CTRL_SCANNING) {
UPDATE_CTRL_VALUES(mScanningMode, uvc_get_scanning_mode);
}
RETURN(ret, int);
}
// スキャニングモードをセット
int UVCCamera::setScanningMode(int mode) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_SCANNING)) {
// LOGI("ae:%d", mode);
r = uvc_set_scanning_mode(mDeviceHandle, mode/* & 0xff*/);
}
RETURN(r, int);
}
// スキャニングモード設定を取得
int UVCCamera::getScanningMode() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_SCANNING)) {
uint8_t mode;
r = uvc_get_scanning_mode(mDeviceHandle, &mode, UVC_GET_CUR);
// LOGI("ae:%d", mode);
if (LIKELY(!r)) {
r = mode;
}
}
RETURN(r, int);
}
//======================================================================
// 露出モード
int UVCCamera::updateExposureModeLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & CTRL_AE) {
UPDATE_CTRL_VALUES(mExposureMode, uvc_get_ae_mode);
}
RETURN(ret, int);
}
// 露出をセット
int UVCCamera::setExposureMode(int mode) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE)) {
// LOGI("ae:%d", mode);
r = uvc_set_ae_mode(mDeviceHandle, mode/* & 0xff*/);
}
RETURN(r, int);
}
// 露出設定を取得
int UVCCamera::getExposureMode() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE)) {
uint8_t mode;
r = uvc_get_ae_mode(mDeviceHandle, &mode, UVC_GET_CUR);
// LOGI("ae:%d", mode);
if (LIKELY(!r)) {
r = mode;
}
}
RETURN(r, int);
}
//======================================================================
// 露出優先設定
int UVCCamera::updateExposurePriorityLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & CTRL_AE_PRIORITY) {
UPDATE_CTRL_VALUES(mExposurePriority, uvc_get_ae_priority);
}
RETURN(ret, int);
}
// 露出優先設定をセット
int UVCCamera::setExposurePriority(int priority) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE_PRIORITY)) {
// LOGI("ae priority:%d", priority);
r = uvc_set_ae_priority(mDeviceHandle, priority/* & 0xff*/);
}
RETURN(r, int);
}
// 露出優先設定を取得
int UVCCamera::getExposurePriority() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE_PRIORITY)) {
uint8_t priority;
r = uvc_get_ae_priority(mDeviceHandle, &priority, UVC_GET_CUR);
// LOGI("ae priority:%d", priority);
if (LIKELY(!r)) {
r = priority;
}
}
RETURN(r, int);
}
//======================================================================
// 露出(絶対値)設定
int UVCCamera::updateExposureLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & CTRL_AE_ABS) {
UPDATE_CTRL_VALUES(mExposureAbs, uvc_get_exposure_abs);
}
RETURN(ret, int);
}
// 露出(絶対値)設定をセット
int UVCCamera::setExposure(int ae_abs) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE_ABS)) {
// LOGI("ae_abs:%d", ae_abs);
r = uvc_set_exposure_abs(mDeviceHandle, ae_abs/* & 0xff*/);
}
RETURN(r, int);
}
// 露出(絶対値)設定を取得
int UVCCamera::getExposure() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE_ABS)) {
int ae_abs;
r = uvc_get_exposure_abs(mDeviceHandle, &ae_abs, UVC_GET_CUR);
// LOGI("ae_abs:%d", ae_abs);
if (LIKELY(!r)) {
r = ae_abs;
}
}
RETURN(r, int);
}
//======================================================================
// 露出(相対値)設定
int UVCCamera::updateExposureRelLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & CTRL_AE_REL) {
UPDATE_CTRL_VALUES(mExposureAbs, uvc_get_exposure_rel);
}
RETURN(ret, int);
}
// 露出(相対値)設定をセット
int UVCCamera::setExposureRel(int ae_rel) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE_REL)) {
// LOGI("ae_rel:%d", ae_rel);
r = uvc_set_exposure_rel(mDeviceHandle, ae_rel/* & 0xff*/);
}
RETURN(r, int);
}
// 露出(相対値)設定を取得
int UVCCamera::getExposureRel() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_AE_REL)) {
int ae_rel;
r = uvc_get_exposure_rel(mDeviceHandle, &ae_rel, UVC_GET_CUR);
// LOGI("ae_rel:%d", ae_rel);
if (LIKELY(!r)) {
r = ae_rel;
}
}
RETURN(r, int);
}
//======================================================================
// オートフォーカス
int UVCCamera::updateAutoFocusLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & CTRL_FOCUS_AUTO) {
UPDATE_CTRL_VALUES(mAutoFocus, uvc_get_focus_auto);
}
RETURN(ret, int);
}
// オートフォーカスをon/off
int UVCCamera::setAutoFocus(bool autoFocus) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_FOCUS_AUTO)) {
r = uvc_set_focus_auto(mDeviceHandle, autoFocus);
}
RETURN(r, int);
}
// オートフォーカスのon/off状態を取得
bool UVCCamera::getAutoFocus() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mCtrlSupports & CTRL_FOCUS_AUTO)) {
uint8_t autoFocus;
r = uvc_get_focus_auto(mDeviceHandle, &autoFocus, UVC_GET_CUR);
if (LIKELY(!r))
r = autoFocus;
}
RETURN(r, int);
}
//======================================================================
// フォーカス(絶対値)調整
int UVCCamera::updateFocusLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_FOCUS_ABS) {
UPDATE_CTRL_VALUES(mFocus, uvc_get_focus_abs);
}
RETURN(ret, int);
}
// フォーカス(絶対値)を設定
int UVCCamera::setFocus(int focus) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_FOCUS_ABS) {
ret = internalSetCtrlValue(mFocus, focus, uvc_get_focus_abs, uvc_set_focus_abs);
}
RETURN(ret, int);
}
// フォーカス(絶対値)の現在値を取得
int UVCCamera::getFocus() {
ENTER();
if (mCtrlSupports & CTRL_FOCUS_ABS) {
int ret = update_ctrl_values(mDeviceHandle, mFocus, uvc_get_focus_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int16_t value;
ret = uvc_get_focus_abs(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// フォーカス(相対値)調整
int UVCCamera::updateFocusRelLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_FOCUS_REL) {
UPDATE_CTRL_VALUES(mFocusRel, uvc_get_focus_rel);
}
RETURN(ret, int);
}
// フォーカス(相対値)を設定
int UVCCamera::setFocusRel(int focus_rel) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_FOCUS_REL) {
ret = internalSetCtrlValue(mFocusRel, (int8_t)((focus_rel >> 8) & 0xff), (uint8_t)(focus_rel &0xff), uvc_get_focus_rel, uvc_set_focus_rel);
}
RETURN(ret, int);
}
// フォーカス(相対値)の現在値を取得
int UVCCamera::getFocusRel() {
ENTER();
if (mCtrlSupports & CTRL_FOCUS_REL) {
int ret = update_ctrl_values(mDeviceHandle, mFocusRel, uvc_get_focus_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int8_t focus;
uint8_t speed;
ret = uvc_get_focus_rel(mDeviceHandle, &focus, &speed, UVC_GET_CUR);
if (LIKELY(!ret))
return (focus <<8) + speed;
}
}
RETURN(0, int);
}
//======================================================================
/*
// フォーカス(シンプル)調整
int UVCCamera::updateFocusSimpleLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_FOCUS_SIMPLE) {
UPDATE_CTRL_VALUES(mFocusSimple, uvc_get_focus_simple_range);
}
RETURN(ret, int);
}
// フォーカス(シンプル)を設定
int UVCCamera::setFocusSimple(int focus) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_FOCUS_SIMPLE) {
ret = internalSetCtrlValue(mFocusSimple, focus, uvc_get_focus_simple_range, uvc_set_focus_simple_range);
}
RETURN(ret, int);
}
// フォーカス(シンプル)の現在値を取得
int UVCCamera::getFocusSimple() {
ENTER();
if (mCtrlSupports & CTRL_FOCUS_SIMPLE) {
int ret = update_ctrl_values(mDeviceHandle, mFocusSimple, uvc_get_focus_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint8_t value;
ret = uvc_get_focus_simple_range(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
*/
//======================================================================
// 絞り(絶対値)調整
int UVCCamera::updateIrisLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_IRIS_ABS) {
UPDATE_CTRL_VALUES(mIris, uvc_get_iris_abs);
}
RETURN(ret, int);
}
// 絞り(絶対値)を設定
int UVCCamera::setIris(int iris) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_IRIS_ABS) {
ret = internalSetCtrlValue(mIris, iris, uvc_get_iris_abs, uvc_set_iris_abs);
}
RETURN(ret, int);
}
// 絞り(絶対値)の現在値を取得
int UVCCamera::getIris() {
ENTER();
if (mCtrlSupports & CTRL_IRIS_ABS) {
int ret = update_ctrl_values(mDeviceHandle, mIris, uvc_get_iris_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_iris_abs(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// 絞り(相対値)調整
int UVCCamera::updateIrisRelLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_IRIS_REL) {
UPDATE_CTRL_VALUES(mIris, uvc_get_iris_rel);
}
RETURN(ret, int);
}
// 絞り(相対値)を設定
int UVCCamera::setIrisRel(int iris_rel) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_IRIS_REL) {
ret = internalSetCtrlValue(mIris, iris_rel, uvc_get_iris_rel, uvc_set_iris_rel);
}
RETURN(ret, int);
}
// 絞り(相対値)の現在値を取得
int UVCCamera::getIrisRel() {
ENTER();
if (mCtrlSupports & CTRL_IRIS_REL) {
int ret = update_ctrl_values(mDeviceHandle, mIris, uvc_get_iris_rel);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint8_t iris_rel;
ret = uvc_get_iris_rel(mDeviceHandle, &iris_rel, UVC_GET_CUR);
if (LIKELY(!ret))
return iris_rel;
}
}
RETURN(0, int);
}
//======================================================================
// Pan(絶対値)調整
int UVCCamera::updatePanLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_PANTILT_ABS) {
update_ctrl_values(mDeviceHandle, mPan, mTilt, uvc_get_pantilt_abs);
}
RETURN(ret, int);
}
// Pan(絶対値)を設定
int UVCCamera::setPan(int pan) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_PANTILT_ABS) {
ret = update_ctrl_values(mDeviceHandle, mPan, mTilt, uvc_get_pantilt_abs);
if (LIKELY(!ret)) {
pan = pan < mPan.min
? mPan.min
: (pan > mPan.max ? mPan.max : pan);
int tilt = mTilt.current < 0 ? mTilt.def : mTilt.current;
ret = uvc_set_pantilt_abs(mDeviceHandle, pan, tilt);
if (LIKELY(!ret)) {
mPan.current = pan;
mTilt.current = tilt;
}
}
}
RETURN(ret, int);
}
// Pan(絶対値)の現在値を取得
int UVCCamera::getPan() {
ENTER();
if (mCtrlSupports & CTRL_PANTILT_ABS) {
int ret = update_ctrl_values(mDeviceHandle, mPan, mTilt, uvc_get_pantilt_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int32_t pan, tilt;
ret = uvc_get_pantilt_abs(mDeviceHandle, &pan, &tilt, UVC_GET_CUR);
if (LIKELY(!ret)) {
mPan.current = pan;
mTilt.current = tilt;
return pan;
}
}
}
RETURN(0, int);
}
//======================================================================
// Tilt(絶対値)調整
int UVCCamera::updateTiltLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_PANTILT_ABS) {
update_ctrl_values(mDeviceHandle, mPan, mTilt, uvc_get_pantilt_abs);
}
RETURN(ret, int);
}
// Tilt(絶対値)を設定
int UVCCamera::setTilt(int tilt) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_PANTILT_ABS) {
ret = update_ctrl_values(mDeviceHandle, mPan, mTilt, uvc_get_pantilt_abs);
if (LIKELY(!ret)) {
tilt = tilt < mTilt.min
? mTilt.min
: (tilt > mTilt.max ? mTilt.max : tilt);
int pan = mPan.current < 0 ? mPan.def : mPan.current;
ret = uvc_set_pantilt_abs(mDeviceHandle, pan, tilt);
if (LIKELY(!ret)) {
mPan.current = pan;
mTilt.current = tilt;
}
}
}
RETURN(ret, int);
}
// Tilt(絶対値)の現在値を取得
int UVCCamera::getTilt() {
ENTER();
if (mCtrlSupports & CTRL_PANTILT_ABS) {
int ret = update_ctrl_values(mDeviceHandle, mPan, mTilt, uvc_get_pantilt_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int32_t pan, tilt;
ret = uvc_get_pantilt_abs(mDeviceHandle, &pan, &tilt, UVC_GET_CUR);
if (LIKELY(!ret)) {
mPan.current = pan;
mTilt.current = tilt;
return tilt;
}
}
}
RETURN(0, int);
}
//======================================================================
// Roll(絶対値)調整
int UVCCamera::updateRollLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_ROLL_ABS) {
UPDATE_CTRL_VALUES(mRoll, uvc_get_roll_abs);
}
RETURN(ret, int);
}
// Roll(絶対値)を設定
int UVCCamera::setRoll(int roll) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_ROLL_ABS) {
ret = internalSetCtrlValue(mRoll, roll, uvc_get_roll_abs, uvc_set_roll_abs);
}
RETURN(ret, int);
}
// Roll(絶対値)の現在値を取得
int UVCCamera::getRoll() {
ENTER();
if (mCtrlSupports & CTRL_ROLL_ABS) {
int ret = update_ctrl_values(mDeviceHandle, mRoll, uvc_get_roll_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int16_t roll;
ret = uvc_get_roll_abs(mDeviceHandle, &roll, UVC_GET_CUR);
if (LIKELY(!ret)) {
mRoll.current = roll;
return roll;
}
}
}
RETURN(0, int);
}
//======================================================================
int UVCCamera::updatePanRelLimit(int &min, int &max, int &def) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
int UVCCamera::setPanRel(int pan_rel) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
int UVCCamera::getPanRel() {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
//======================================================================
int UVCCamera::updateTiltRelLimit(int &min, int &max, int &def) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
int UVCCamera::setTiltRel(int tilt_rel) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
int UVCCamera::getTiltRel() {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
//======================================================================
int UVCCamera::updateRollRelLimit(int &min, int &max, int &def) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
int UVCCamera::setRollRel(int roll_rel) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
int UVCCamera::getRollRel() {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
//======================================================================
// プライバシーモード
int UVCCamera::updatePrivacyLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_PRIVACY) {
UPDATE_CTRL_VALUES(mPrivacy, uvc_get_focus_abs);
}
RETURN(ret, int);
}
// プライバシーモードを設定
int UVCCamera::setPrivacy(int privacy) {
ENTER();
int ret = UVC_ERROR_ACCESS;
if (mCtrlSupports & CTRL_PRIVACY) {
ret = internalSetCtrlValue(mPrivacy, privacy, uvc_get_privacy, uvc_set_privacy);
}
RETURN(ret, int);
}
// プライバシーモードの現在値を取得
int UVCCamera::getPrivacy() {
ENTER();
if (mCtrlSupports & CTRL_PRIVACY) {
int ret = update_ctrl_values(mDeviceHandle, mPrivacy, uvc_get_privacy);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint8_t privacy;
ret = uvc_get_privacy(mDeviceHandle, &privacy, UVC_GET_CUR);
if (LIKELY(!ret))
return privacy;
}
}
RETURN(0, int);
}
//======================================================================
/*
// DigitalWindow
int UVCCamera::updateDigitalWindowLimit(...not defined...) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
// DigitalWindowを設定
int UVCCamera::setDigitalWindow(int top, int reft, int bottom, int right) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
// DigitalWindowの現在値を取得
int UVCCamera::getDigitalWindow(int &top, int &reft, int &bottom, int &right) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
*/
//======================================================================
/*
// DigitalRoi
int UVCCamera::updateDigitalRoiLimit(...not defined...) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
// DigitalRoiを設定
int UVCCamera::setDigitalRoi(int top, int reft, int bottom, int right) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
// DigitalRoiの現在値を取得
int UVCCamera::getDigitalRoi(int &top, int &reft, int &bottom, int &right) {
ENTER();
// FIXME not implemented yet
RETURN(UVC_ERROR_ACCESS, int);
}
*/
//======================================================================
// backlight_compensation
int UVCCamera::updateBacklightCompLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_BACKLIGHT) {
UPDATE_CTRL_VALUES(mBacklightComp, uvc_get_backlight_compensation);
}
RETURN(ret, int);
}
// backlight_compensationを設定
int UVCCamera::setBacklightComp(int backlight) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_BACKLIGHT) {
ret = internalSetCtrlValue(mBacklightComp, backlight, uvc_get_backlight_compensation, uvc_set_backlight_compensation);
}
RETURN(ret, int);
}
// backlight_compensationの現在値を取得
int UVCCamera::getBacklightComp() {
ENTER();
if (mPUSupports & PU_BACKLIGHT) {
int ret = update_ctrl_values(mDeviceHandle, mBacklightComp, uvc_get_backlight_compensation);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int16_t value;
ret = uvc_get_backlight_compensation(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// 明るさ
int UVCCamera::updateBrightnessLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_BRIGHTNESS) {
UPDATE_CTRL_VALUES(mBrightness, uvc_get_brightness);
}
RETURN(ret, int);
}
int UVCCamera::setBrightness(int brightness) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_BRIGHTNESS) {
ret = internalSetCtrlValue(mBrightness, brightness, uvc_get_brightness, uvc_set_brightness);
}
RETURN(ret, int);
}
// 明るさの現在値を取得
int UVCCamera::getBrightness() {
ENTER();
if (mPUSupports & PU_BRIGHTNESS) {
int ret = update_ctrl_values(mDeviceHandle, mBrightness, uvc_get_brightness);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int16_t value;
ret = uvc_get_brightness(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// コントラスト調整
int UVCCamera::updateContrastLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_CONTRAST) {
UPDATE_CTRL_VALUES(mContrast, uvc_get_contrast);
}
RETURN(ret, int);
}
// コントラストを設定
int UVCCamera::setContrast(uint16_t contrast) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_CONTRAST) {
ret = internalSetCtrlValue(mContrast, contrast, uvc_get_contrast, uvc_set_contrast);
}
RETURN(ret, int);
}
// コントラストの現在値を取得
int UVCCamera::getContrast() {
ENTER();
if (mPUSupports & PU_CONTRAST) {
int ret = update_ctrl_values(mDeviceHandle, mContrast, uvc_get_contrast);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_contrast(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// オートコントラスト
int UVCCamera::updateAutoContrastLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_CONTRAST_AUTO) {
UPDATE_CTRL_VALUES(mAutoFocus, uvc_get_contrast_auto);
}
RETURN(ret, int);
}
// オートコントラストをon/off
int UVCCamera::setAutoContrast(bool autoContrast) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_CONTRAST_AUTO)) {
r = uvc_set_contrast_auto(mDeviceHandle, autoContrast);
}
RETURN(r, int);
}
// オートコントラストのon/off状態を取得
bool UVCCamera::getAutoContrast() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_CONTRAST_AUTO)) {
uint8_t autoContrast;
r = uvc_get_contrast_auto(mDeviceHandle, &autoContrast, UVC_GET_CUR);
if (LIKELY(!r))
r = autoContrast;
}
RETURN(r, int);
}
//======================================================================
// シャープネス調整
int UVCCamera::updateSharpnessLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_SHARPNESS) {
UPDATE_CTRL_VALUES(mSharpness, uvc_get_sharpness);
}
RETURN(ret, int);
}
// シャープネスを設定
int UVCCamera::setSharpness(int sharpness) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_SHARPNESS) {
ret = internalSetCtrlValue(mSharpness, sharpness, uvc_get_sharpness, uvc_set_sharpness);
}
RETURN(ret, int);
}
// シャープネスの現在値を取得
int UVCCamera::getSharpness() {
ENTER();
if (mPUSupports & PU_SHARPNESS) {
int ret = update_ctrl_values(mDeviceHandle, mSharpness, uvc_get_sharpness);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_sharpness(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// ゲイン調整
int UVCCamera::updateGainLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_GAIN) {
UPDATE_CTRL_VALUES(mGain, uvc_get_gain)
}
RETURN(ret, int);
}
// ゲインを設定
int UVCCamera::setGain(int gain) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_GAIN) {
// LOGI("gain:%d", gain);
ret = internalSetCtrlValue(mGain, gain, uvc_get_gain, uvc_set_gain);
}
RETURN(ret, int);
}
// ゲインの現在値を取得
int UVCCamera::getGain() {
ENTER();
if (mPUSupports & PU_GAIN) {
int ret = update_ctrl_values(mDeviceHandle, mGain, uvc_get_gain);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_gain(mDeviceHandle, &value, UVC_GET_CUR);
// LOGI("gain:%d", value);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// オートホワイトバランス(temp)
int UVCCamera::updateAutoWhiteBlanceLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_WB_TEMP_AUTO) {
UPDATE_CTRL_VALUES(mAutoWhiteBlance, uvc_get_white_balance_temperature_auto);
}
RETURN(ret, int);
}
// オートホワイトバランス(temp)をon/off
int UVCCamera::setAutoWhiteBlance(bool autoWhiteBlance) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_WB_TEMP_AUTO)) {
r = uvc_set_white_balance_temperature_auto(mDeviceHandle, autoWhiteBlance);
}
RETURN(r, int);
}
// オートホワイトバランス(temp)のon/off状態を取得
bool UVCCamera::getAutoWhiteBlance() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_WB_TEMP_AUTO)) {
uint8_t autoWhiteBlance;
r = uvc_get_white_balance_temperature_auto(mDeviceHandle, &autoWhiteBlance, UVC_GET_CUR);
if (LIKELY(!r))
r = autoWhiteBlance;
}
RETURN(r, int);
}
//======================================================================
// オートホワイトバランス(compo)
int UVCCamera::updateAutoWhiteBlanceCompoLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_WB_COMPO_AUTO) {
UPDATE_CTRL_VALUES(mAutoWhiteBlanceCompo, uvc_get_white_balance_component_auto);
}
RETURN(ret, int);
}
// オートホワイトバランス(compo)をon/off
int UVCCamera::setAutoWhiteBlanceCompo(bool autoWhiteBlanceCompo) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_WB_COMPO_AUTO)) {
r = uvc_set_white_balance_component_auto(mDeviceHandle, autoWhiteBlanceCompo);
}
RETURN(r, int);
}
// オートホワイトバランス(compo)のon/off状態を取得
bool UVCCamera::getAutoWhiteBlanceCompo() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_WB_COMPO_AUTO)) {
uint8_t autoWhiteBlanceCompo;
r = uvc_get_white_balance_component_auto(mDeviceHandle, &autoWhiteBlanceCompo, UVC_GET_CUR);
if (LIKELY(!r))
r = autoWhiteBlanceCompo;
}
RETURN(r, int);
}
//======================================================================
// ホワイトバランス色温度調整
int UVCCamera::updateWhiteBlanceLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_WB_TEMP) {
UPDATE_CTRL_VALUES(mWhiteBlance, uvc_get_white_balance_temperature)
}
RETURN(ret, int);
}
// ホワイトバランス色温度を設定
int UVCCamera::setWhiteBlance(int white_blance) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_WB_TEMP) {
ret = internalSetCtrlValue(mWhiteBlance, white_blance,
uvc_get_white_balance_temperature, uvc_set_white_balance_temperature);
}
RETURN(ret, int);
}
// ホワイトバランス色温度の現在値を取得
int UVCCamera::getWhiteBlance() {
ENTER();
if (mPUSupports & PU_WB_TEMP) {
int ret = update_ctrl_values(mDeviceHandle, mWhiteBlance, uvc_get_white_balance_temperature);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_white_balance_temperature(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// ホワイトバランスcompo調整
int UVCCamera::updateWhiteBlanceCompoLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_WB_COMPO) {
UPDATE_CTRL_VALUES(mWhiteBlanceCompo, uvc_get_white_balance_component)
}
RETURN(ret, int);
}
// ホワイトバランスcompoを設定
int UVCCamera::setWhiteBlanceCompo(int white_blance_compo) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_WB_COMPO) {
ret = internalSetCtrlValue(mWhiteBlanceCompo, white_blance_compo,
uvc_get_white_balance_component, uvc_set_white_balance_component);
}
RETURN(ret, int);
}
// ホワイトバランスcompoの現在値を取得
int UVCCamera::getWhiteBlanceCompo() {
ENTER();
if (mPUSupports & PU_WB_COMPO) {
int ret = update_ctrl_values(mDeviceHandle, mWhiteBlanceCompo, uvc_get_white_balance_component);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint32_t white_blance_compo;
ret = uvc_get_white_balance_component(mDeviceHandle, &white_blance_compo, UVC_GET_CUR);
if (LIKELY(!ret))
return white_blance_compo;
}
}
RETURN(0, int);
}
//======================================================================
// ガンマ調整
int UVCCamera::updateGammaLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_GAMMA) {
UPDATE_CTRL_VALUES(mGamma, uvc_get_gamma)
}
RETURN(ret, int);
}
// ガンマを設定
int UVCCamera::setGamma(int gamma) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_GAMMA) {
// LOGI("gamma:%d", gamma);
ret = internalSetCtrlValue(mGamma, gamma, uvc_get_gamma, uvc_set_gamma);
}
RETURN(ret, int);
}
// ガンマの現在値を取得
int UVCCamera::getGamma() {
ENTER();
if (mPUSupports & PU_GAMMA) {
int ret = update_ctrl_values(mDeviceHandle, mGamma, uvc_get_gamma);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_gamma(mDeviceHandle, &value, UVC_GET_CUR);
// LOGI("gamma:%d", ret);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// 彩度調整
int UVCCamera::updateSaturationLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_SATURATION) {
UPDATE_CTRL_VALUES(mSaturation, uvc_get_saturation)
}
RETURN(ret, int);
}
// 彩度を設定
int UVCCamera::setSaturation(int saturation) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_SATURATION) {
ret = internalSetCtrlValue(mSaturation, saturation, uvc_get_saturation, uvc_set_saturation);
}
RETURN(ret, int);
}
// 彩度の現在値を取得
int UVCCamera::getSaturation() {
ENTER();
if (mPUSupports & PU_SATURATION) {
int ret = update_ctrl_values(mDeviceHandle, mSaturation, uvc_get_saturation);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_saturation(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// 色相調整
int UVCCamera::updateHueLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_HUE) {
UPDATE_CTRL_VALUES(mHue, uvc_get_hue)
}
RETURN(ret, int);
}
// 色相を設定
int UVCCamera::setHue(int hue) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_HUE) {
ret = internalSetCtrlValue(mHue, hue, uvc_get_hue, uvc_set_hue);
}
RETURN(ret, int);
}
// 色相の現在値を取得
int UVCCamera::getHue() {
ENTER();
if (mPUSupports & PU_HUE) {
int ret = update_ctrl_values(mDeviceHandle, mHue, uvc_get_hue);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int16_t value;
ret = uvc_get_hue(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// オート色相
int UVCCamera::updateAutoHueLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_HUE_AUTO) {
UPDATE_CTRL_VALUES(mAutoHue, uvc_get_hue_auto);
}
RETURN(ret, int);
}
// オート色相をon/off
int UVCCamera::setAutoHue(bool autoHue) {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_HUE_AUTO)) {
r = uvc_set_hue_auto(mDeviceHandle, autoHue);
}
RETURN(r, int);
}
// オート色相のon/off状態を取得
bool UVCCamera::getAutoHue() {
ENTER();
int r = UVC_ERROR_ACCESS;
if LIKELY((mDeviceHandle) && (mPUSupports & PU_HUE_AUTO)) {
uint8_t autoHue;
r = uvc_get_hue_auto(mDeviceHandle, &autoHue, UVC_GET_CUR);
if (LIKELY(!r))
r = autoHue;
}
RETURN(r, int);
}
//======================================================================
// 電源周波数によるチラつき補正
int UVCCamera::updatePowerlineFrequencyLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mCtrlSupports & PU_POWER_LF) {
UPDATE_CTRL_VALUES(mPowerlineFrequency, uvc_get_powerline_freqency)
}
RETURN(ret, int);
}
// 電源周波数によるチラつき補正を設定
int UVCCamera::setPowerlineFrequency(int frequency) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_POWER_LF) {
if (frequency < 0) {
uint8_t value;
ret = uvc_get_powerline_freqency(mDeviceHandle, &value, UVC_GET_DEF);
if LIKELY(ret)
frequency = value;
else
RETURN(ret, int);
}
LOGD("frequency:%d", frequency);
ret = uvc_set_powerline_freqency(mDeviceHandle, frequency);
}
RETURN(ret, int);
}
// 電源周波数によるチラつき補正値を取得
int UVCCamera::getPowerlineFrequency() {
ENTER();
if (mPUSupports & PU_POWER_LF) {
uint8_t value;
int ret = uvc_get_powerline_freqency(mDeviceHandle, &value, UVC_GET_CUR);
LOGD("frequency:%d", ret);
if (LIKELY(!ret))
return value;
}
RETURN(0, int);
}
//======================================================================
// ズーム(abs)調整
int UVCCamera::updateZoomLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mCtrlSupports & CTRL_ZOOM_ABS) {
UPDATE_CTRL_VALUES(mZoom, uvc_get_zoom_abs)
}
RETURN(ret, int);
}
// ズーム(abs)を設定
int UVCCamera::setZoom(int zoom) {
ENTER();
int ret = UVC_ERROR_IO;
if (mCtrlSupports & CTRL_ZOOM_ABS) {
ret = internalSetCtrlValue(mZoom, zoom, uvc_get_zoom_abs, uvc_set_zoom_abs);
}
RETURN(ret, int);
}
// ズーム(abs)の現在値を取得
int UVCCamera::getZoom() {
ENTER();
if (mCtrlSupports & CTRL_ZOOM_ABS) {
int ret = update_ctrl_values(mDeviceHandle, mZoom, uvc_get_zoom_abs);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t value;
ret = uvc_get_zoom_abs(mDeviceHandle, &value, UVC_GET_CUR);
if (LIKELY(!ret))
return value;
}
}
RETURN(0, int);
}
//======================================================================
// ズーム(相対値)調整
int UVCCamera::updateZoomRelLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mCtrlSupports & CTRL_ZOOM_REL) {
UPDATE_CTRL_VALUES(mZoomRel, uvc_get_zoom_rel)
}
RETURN(ret, int);
}
// ズーム(相対値)を設定
int UVCCamera::setZoomRel(int zoom) {
ENTER();
int ret = UVC_ERROR_IO;
if (mCtrlSupports & CTRL_ZOOM_REL) {
ret = internalSetCtrlValue(mZoomRel,
(int8_t)((zoom >> 16) & 0xff), (uint8_t)((zoom >> 8) & 0xff), (uint8_t)(zoom & 0xff),
uvc_get_zoom_rel, uvc_set_zoom_rel);
}
RETURN(ret, int);
}
// ズーム(相対値)の現在値を取得
int UVCCamera::getZoomRel() {
ENTER();
if (mCtrlSupports & CTRL_ZOOM_REL) {
int ret = update_ctrl_values(mDeviceHandle, mZoomRel, uvc_get_zoom_rel);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
int8_t zoom;
uint8_t isdigital;
uint8_t speed;
ret = uvc_get_zoom_rel(mDeviceHandle, &zoom, &isdigital, &speed, UVC_GET_CUR);
if (LIKELY(!ret))
return (zoom << 16) +(isdigital << 8) + speed;
}
}
RETURN(0, int);
}
//======================================================================
// digital multiplier調整
int UVCCamera::updateDigitalMultiplierLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_DIGITAL_MULT) {
UPDATE_CTRL_VALUES(mMultiplier, uvc_get_digital_multiplier)
}
RETURN(ret, int);
}
// digital multiplierを設定
int UVCCamera::setDigitalMultiplier(int multiplier) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_DIGITAL_MULT) {
// LOGI("multiplier:%d", multiplier);
ret = internalSetCtrlValue(mMultiplier, multiplier, uvc_get_digital_multiplier, uvc_set_digital_multiplier);
}
RETURN(ret, int);
}
// digital multiplierの現在値を取得
int UVCCamera::getDigitalMultiplier() {
ENTER();
if (mPUSupports & PU_DIGITAL_MULT) {
int ret = update_ctrl_values(mDeviceHandle, mMultiplier, uvc_get_digital_multiplier);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t multiplier;
ret = uvc_get_digital_multiplier(mDeviceHandle, &multiplier, UVC_GET_CUR);
// LOGI("multiplier:%d", multiplier);
if (LIKELY(!ret))
return multiplier;
}
}
RETURN(0, int);
}
//======================================================================
// digital multiplier limit調整
int UVCCamera::updateDigitalMultiplierLimitLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_DIGITAL_LIMIT) {
UPDATE_CTRL_VALUES(mMultiplierLimit, uvc_get_digital_multiplier_limit)
}
RETURN(ret, int);
}
// digital multiplier limitを設定
int UVCCamera::setDigitalMultiplierLimit(int multiplier_limit) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_DIGITAL_LIMIT) {
// LOGI("multiplier limit:%d", multiplier_limit);
ret = internalSetCtrlValue(mMultiplierLimit, multiplier_limit, uvc_get_digital_multiplier_limit, uvc_set_digital_multiplier_limit);
}
RETURN(ret, int);
}
// digital multiplier limitの現在値を取得
int UVCCamera::getDigitalMultiplierLimit() {
ENTER();
if (mPUSupports & PU_DIGITAL_LIMIT) {
int ret = update_ctrl_values(mDeviceHandle, mMultiplierLimit, uvc_get_digital_multiplier_limit);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint16_t multiplier_limit;
ret = uvc_get_digital_multiplier_limit(mDeviceHandle, &multiplier_limit, UVC_GET_CUR);
// LOGI("multiplier_limit:%d", multiplier_limit);
if (LIKELY(!ret))
return multiplier_limit;
}
}
RETURN(0, int);
}
//======================================================================
// AnalogVideoStandard
int UVCCamera::updateAnalogVideoStandardLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_AVIDEO_STD) {
UPDATE_CTRL_VALUES(mAnalogVideoStandard, uvc_get_analog_video_standard)
}
RETURN(ret, int);
}
int UVCCamera::setAnalogVideoStandard(int standard) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_AVIDEO_STD) {
// LOGI("standard:%d", standard);
ret = internalSetCtrlValue(mAnalogVideoStandard, standard, uvc_get_analog_video_standard, uvc_set_analog_video_standard);
}
RETURN(ret, int);
}
int UVCCamera::getAnalogVideoStandard() {
ENTER();
if (mPUSupports & PU_AVIDEO_STD) {
int ret = update_ctrl_values(mDeviceHandle, mAnalogVideoStandard, uvc_get_analog_video_standard);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint8_t standard;
ret = uvc_get_analog_video_standard(mDeviceHandle, &standard, UVC_GET_CUR);
// LOGI("standard:%d", standard);
if (LIKELY(!ret))
return standard;
}
}
RETURN(0, int);
}
//======================================================================
// AnalogVideoLoackStatus
int UVCCamera::updateAnalogVideoLockStateLimit(int &min, int &max, int &def) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_AVIDEO_LOCK) {
UPDATE_CTRL_VALUES(mAnalogVideoLockState, uvc_get_analog_video_lockstate)
}
RETURN(ret, int);
}
int UVCCamera::setAnalogVideoLockState(int state) {
ENTER();
int ret = UVC_ERROR_IO;
if (mPUSupports & PU_AVIDEO_LOCK) {
// LOGI("status:%d", status);
ret = internalSetCtrlValue(mAnalogVideoLockState, state, uvc_get_analog_video_lockstate, uvc_set_analog_video_lockstate);
}
RETURN(ret, int);
}
int UVCCamera::getAnalogVideoLockState() {
ENTER();
if (mPUSupports & PU_AVIDEO_LOCK) {
int ret = update_ctrl_values(mDeviceHandle, mAnalogVideoLockState, uvc_get_analog_video_lockstate);
if (LIKELY(!ret)) { // 正常に最小・最大値を取得出来た時
uint8_t status;
ret = uvc_get_analog_video_lockstate(mDeviceHandle, &status, UVC_GET_CUR);
// LOGI("status:%d", status);
if (LIKELY(!ret))
return status;
}
}
RETURN(0, int);
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCCamera.h
================================================
/*
* 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
#include
#include
#include
#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_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCPreview.cpp
================================================
/*
* 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
#include
#include
#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(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(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(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();
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCPreview.h
================================================
/*
* 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
#include
#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 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 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_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCStatusCallback.cpp
================================================
#include
#include
#include
#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(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();
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/UVCStatusCallback.h
================================================
#ifndef UVCSTATUSCALLBACK_H_
#define UVCSTATUSCALLBACK_H_
#include "libUVCCamera.h"
#include
#include
#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_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/_onload.cpp
================================================
/*
* 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(&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;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/_onload.h
================================================
/*
* 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
#ifdef __cplusplus
extern "C" {
#endif
jint JNI_OnLoad(JavaVM *vm, void *reserved);
#ifdef __cplusplus
}
#endif
#endif /* ONLOAD_H_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/libUVCCamera.h
================================================
/*
* 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
#include "libusb.h"
#include "libuvc.h"
#include "utilbase.h"
#endif /* LIBUVCCAMERA_H_ */
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/objectarray.h
================================================
/*
* UVCCamera
* library and sample to access to UVC web camera on non-rooted Android device
*
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com
*
* File name: objectarray.h
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* All files in the folder are under this Apache License, Version 2.0.
* Files in the jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
*/
#ifndef OBJECTARRAY_H_
#define OBJECTARRAY_H_
#include "utilbase.h"
template
class ObjectArray {
private:
T *m_elements;
const int min_size;
int m_max_size;
int m_size;
public:
ObjectArray(int initial_capacity = 2)
: m_elements(new T[initial_capacity]),
m_max_size(initial_capacity),
m_size(0),
min_size(initial_capacity) {
}
~ObjectArray() { SAFE_DELETE_ARRAY(m_elements); }
void size(int new_size) {
if (new_size != capacity()) {
T *new_elements = new T[new_size];
LOG_ASSERT(new_elements, "out of memory:size=%d,capacity=%d", new_size, m_max_size);
const int n = (new_size < capacity()) ? new_size : capacity();
for (int i = 0; i < n; i++) {
new_elements[i] = m_elements[i];
}
SAFE_DELETE_ARRAY(m_elements);
m_elements = new_elements;
m_max_size = new_size;
m_size = (m_size < new_size) ? m_size : new_size;
}
}
inline int size() const { return m_size; }
inline bool isEmpty() const { return (m_size < 1); }
inline int capacity() const { return m_max_size; }
inline T &operator[](int index) { return m_elements[index]; }
inline const T &operator[](int index) const { return m_elements[index]; }
int put(T object) {
if LIKELY(object) {
if UNLIKELY(size() >= capacity()) {
size(capacity() ? capacity() * 2 : 2);
}
m_elements[m_size++] = object;
}
return m_size;
}
/**
* remove T which posisioned on index
*/
T remove(int index) {
T obj = m_elements[index];
for (int i = index; i < m_size - 1; i++) {
m_elements[i] = m_elements[i+1];
}
m_size--;
return obj;
}
/**
* search the T object and remove if exist
*/
void removeObject(T object) {
for (int i = 0; i < size(); i++) {
if (m_elements[i] == object) {
remove(i);
break;
}
}
}
/**
* get last T and remove from this array ¥
* this is faster than remove(size()-1)
*/
inline T last() {
if LIKELY(m_size > 0)
return m_elements[--m_size];
else
return NULL;
}
/**
* search the T object and return it's index
* if the T is not in this array, return -1
*/
int getIndex(const T object) {
int result = -1;
for (int i = 0; i < size(); i++) {
if (m_elements[i] == object) {
result = i;
break;
}
}
return result;
}
/**
* clear the T array but never delete actual T instance
*/
inline void clear() {
size(min_size);
m_size = 0;
}
};
#endif // OBJECTARRAY_H_
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/AbstractBufferedPipeline.cpp
================================================
//
// Created by saki on 15/11/05.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include "utilbase.h"
#include "AbstractBufferedPipeline.h"
/*public*/
AbstractBufferedPipeline::AbstractBufferedPipeline(const int &_max_buffer_num, const int &_init_pool_num,
const size_t &_default_frame_size, const bool &drop_frames_when_buffer_empty)
: IPipeline(_default_frame_size),
max_buffer_num(_max_buffer_num),
init_pool_num(_init_pool_num),
drop_frames(drop_frames_when_buffer_empty),
total_frame_num(0)
{
ENTER();
EXIT();
}
/*public*/
AbstractBufferedPipeline::~AbstractBufferedPipeline() {
ENTER();
release();
setState(PIPELINE_STATE_UNINITIALIZED);
EXIT();
}
/*public*/
int AbstractBufferedPipeline::release() {
ENTER();
setState(PIPELINE_STATE_RELEASING);
stop();
clear_frames();
clear_pool();
setState(PIPELINE_STATE_UNINITIALIZED);
RETURN(0, int);
}
/*public*/
int AbstractBufferedPipeline::start() {
ENTER();
int result = EXIT_FAILURE;
if (!isRunning()) {
mIsRunning = true;
setState(PIPELINE_STATE_STARTING);
buffer_mutex.lock();
{
result = pthread_create(&handler_thread, NULL, handler_thread_func, (void *) this);
}
buffer_mutex.unlock();
if (UNLIKELY(result != EXIT_SUCCESS)) {
LOGW("AbstractBufferedPipeline::already running/could not create thread etc.");
setState(PIPELINE_STATE_INITIALIZED);
mIsRunning = false;
buffer_mutex.lock();
{
pool_sync.broadcast();
buffer_sync.broadcast();
}
buffer_mutex.unlock();
}
}
RETURN(result, int);
}
/*public*/
int AbstractBufferedPipeline::stop() {
ENTER();
bool b = isRunning();
if (LIKELY(b)) {
setState(PIPELINE_STATE_STOPPING);
mIsRunning = false;
pool_sync.broadcast();
buffer_sync.broadcast();
LOGD("pthread_join:handler_thread");
if (pthread_join(handler_thread, NULL) != EXIT_SUCCESS) {
LOGW("PublisherPipeline::terminate publisher thread: pthread_join failed");
}
setState(PIPELINE_STATE_INITIALIZED);
LOGD("handler_thread finished");
}
clear_frames();
RETURN(0, int);
}
/*public*/
int AbstractBufferedPipeline::queueFrame(uvc_frame_t *frame) {
ENTER();
int ret = UVC_ERROR_OTHER;
if (LIKELY(frame)) {
// get empty frame from frame pool
uvc_frame_t *copy = get_frame(frame->data_bytes);
if (UNLIKELY(!copy)) {
LOGD("buffer pool is empty and exceeds the limit, drop frame");
RETURN(UVC_ERROR_NO_MEM, int);
}
// duplicate frame buffer and pass copy to publisher
ret = uvc_duplicate_frame(frame, copy);
if (LIKELY(!ret)) {
ret = add_frame(copy);
} else {
LOGW("uvc_duplicate_frame failed:%d", ret);
recycle_frame(copy);
}
}
RETURN(ret, int);
}
//********************************************************************************
//
//********************************************************************************
/**
* get uvc_frame_t from frame pool
* if pool is empty, create new frame
* this function does not confirm the frame size
* and you may need to confirm the size
*/
uvc_frame_t *AbstractBufferedPipeline::get_frame(const size_t &data_bytes) {
uvc_frame_t *frame = NULL;
Mutex::Autolock lock(pool_mutex);
if (UNLIKELY(frame_pool.empty() && (total_frame_num < max_buffer_num))) {
uint32_t n = total_frame_num * 2;
if (n > max_buffer_num) {
n = max_buffer_num;
}
n -= total_frame_num;
if (LIKELY(n > 0)) {
for (int i = 0; i < n; i++) {
frame = uvc_allocate_frame(data_bytes);
total_frame_num++;
}
LOGW("allocate new frame:%d", total_frame_num);
} else {
LOGW("number of allocated frame exceeds limit");
}
}
if (UNLIKELY(frame_pool.empty() && !drop_frames)) {
// if pool is empty and need to block(avoid dropping frames), wait frame recycling.
for (; mIsRunning && frame_pool.empty() ; ) {
pool_sync.wait(pool_mutex);
}
}
if (!frame_pool.empty()) {
frame = frame_pool.front();
frame_pool.pop_front();
}
return frame;
}
void AbstractBufferedPipeline::recycle_frame(uvc_frame_t *frame) {
ENTER();
if (LIKELY(frame)) {
Mutex::Autolock lock(pool_mutex);
if (LIKELY(frame_pool.size() < max_buffer_num)) {
frame_pool.push_back(frame);
frame = NULL;
}
if (UNLIKELY(frame)) {
// if pool overflowed
total_frame_num--;
uvc_free_frame(frame);
}
pool_sync.signal();
}
EXIT();
}
void AbstractBufferedPipeline::init_pool(const size_t &data_bytes) {
ENTER();
uvc_frame_t *frame = NULL;
clear_pool();
pool_mutex.lock();
{
size_t frame_sz = data_bytes / 4; // expects 25%, this will be able to much lower
if (!frame_sz) {
frame_sz = DEFAULT_FRAME_SZ;
}
for (uint32_t i = 0; i < init_pool_num; i++) {
frame = uvc_allocate_frame(frame_sz);
if (LIKELY(frame)) {
frame_pool.push_back(frame);
total_frame_num++;
} else {
LOGW("failed to allocate new frame:%d", total_frame_num);
break;
}
}
}
pool_mutex.unlock();
EXIT();
}
void AbstractBufferedPipeline::clear_pool() {
ENTER();
Mutex::Autolock lock(pool_mutex);
for (auto iter = frame_pool.begin(); iter != frame_pool.end(); iter++) {
total_frame_num--;
uvc_free_frame(*iter);
}
frame_pool.clear();
EXIT();
}
//********************************************************************************
//
//********************************************************************************
void AbstractBufferedPipeline::clear_frames() {
Mutex::Autolock lock(buffer_mutex);
for (auto iter = frame_buffers.begin(); iter != frame_buffers.end(); iter++) {
recycle_frame(*iter);
}
frame_buffers.clear();
}
int AbstractBufferedPipeline::add_frame(uvc_frame_t *frame) {
ENTER();
buffer_mutex.lock();
{
// FIXME as current implementation, transferring frame data on my device is slower than that coming from UVC camera... just drop them now
if (frame_buffers.size() > max_buffer_num) {
// erase old frames
int cnt = 0;
for (auto iter = frame_buffers.begin();
(iter != frame_buffers.end()) && (cnt < 5); iter++, cnt++) {
recycle_frame(*iter);
iter = frame_buffers.erase(iter);
}
LOGW("droped frame data");
}
if (isRunning() && (frame_buffers.size() < max_buffer_num)) {
frame_buffers.push_back(frame);
frame = NULL;
}
buffer_sync.signal();
}
buffer_mutex.unlock();
if (frame) {
recycle_frame(frame);
}
RETURN(0, int);
}
uvc_frame_t *AbstractBufferedPipeline::wait_frame() {
uvc_frame_t *frame = NULL;
Mutex::Autolock lock(buffer_mutex);
if (!frame_buffers.size()) {
buffer_sync.wait(buffer_mutex);
}
if (LIKELY(isRunning() && frame_buffers.size() > 0)) {
frame = frame_buffers.front();
frame_buffers.pop_front();
}
return frame;
}
uint32_t AbstractBufferedPipeline::get_frame_count() {
ENTER();
Mutex::Autolock lock(buffer_mutex);
uint32_t result = frame_buffers.size();
RETURN(result, uint32_t);
}
//********************************************************************************
//
//********************************************************************************
void *AbstractBufferedPipeline::handler_thread_func(void *vptr_args) {
ENTER();
AbstractBufferedPipeline *pipeline = reinterpret_cast(vptr_args);
if (LIKELY(pipeline)) {
pipeline->do_loop();
}
PRE_EXIT();
pthread_exit(NULL);
}
void AbstractBufferedPipeline::do_loop() {
ENTER();
clear_frames();
init_pool(default_frame_size);
on_start();
setState(PIPELINE_STATE_RUNNING);
for ( ; LIKELY(isRunning()) ; ) {
uvc_frame_t *frame = wait_frame();
if ((LIKELY(frame))) {
try {
if (!handle_frame(frame)) {
chain_frame(frame);
}
} catch (...) {
LOGE("exception");
}
recycle_frame(frame);
}
}
setState(PIPELINE_STATE_STOPPING);
mIsRunning = false;
on_stop();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/AbstractBufferedPipeline.h
================================================
//
// Created by saki on 15/11/05.
//
#ifndef PUPILMOBILE_ABSTRACTBUFFEREDPIPELINE_H
#define PUPILMOBILE_ABSTRACTBUFFEREDPIPELINE_H
#include
#include
#include
#include "Mutex.h"
#include "Condition.h"
#include "libUVCCamera.h"
#include "IPipeline.h"
#pragma interface
#define DEFAULT_INIT_FRAME_POOL_SZ 2
#define DEFAULT_MAX_FRAME_NUM 8
using namespace android;
class AbstractBufferedPipeline;
class AbstractBufferedPipeline : virtual public IPipeline {
private:
const uint32_t max_buffer_num;
const uint32_t init_pool_num;
const bool drop_frames;
volatile uint32_t total_frame_num;
// frame buffer pool to improve performance by reducing memory allocation
mutable Mutex pool_mutex;
Condition pool_sync;
std::list frame_pool;
// frame buffers
pthread_t handler_thread;
mutable Mutex buffer_mutex;
Condition buffer_sync;
std::list frame_buffers;
static void *handler_thread_func(void *vptr_args);
protected:
// frame buffer pool
uvc_frame_t *get_frame(const size_t &data_bytes);
void recycle_frame(uvc_frame_t *frame);
void init_pool(const size_t &data_bytes);
void clear_pool();
// frame buffers
void clear_frames();
int add_frame(uvc_frame_t *frame);
uvc_frame_t *wait_frame();
uint32_t get_frame_count();
virtual void do_loop();
virtual void on_start() = 0;
virtual void on_stop() = 0;
virtual int handle_frame(uvc_frame_t *frame) = 0;
public:
AbstractBufferedPipeline(const int &_max_buffer_num = DEFAULT_MAX_FRAME_NUM, const int &init_pool_num = DEFAULT_INIT_FRAME_POOL_SZ,
const size_t &default_frame_size = DEFAULT_FRAME_SZ, const bool &drop_frames_when_buffer_empty = true);
virtual ~AbstractBufferedPipeline();
virtual int release();
virtual int start();
virtual int stop();
virtual int queueFrame(uvc_frame_t *frame);
};
#endif //PUPILMOBILE_ABSTRACTBUFFEREDPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/CallbackPipeline.cpp
================================================
//
// Created by saki on 15/11/07.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
#include "CallbackPipeline.h"
#define INIT_FRAME_POOL_SZ 2
#define MAX_FRAME_NUM 8
CallbackPipeline::CallbackPipeline(const size_t &_data_bytes)
: CaptureBasePipeline(MAX_FRAME_NUM, INIT_FRAME_POOL_SZ, _data_bytes),
mFrameCallbackFunc(NULL),
callbackPixelBytes(0)
{
ENTER();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
CallbackPipeline::~CallbackPipeline() {
ENTER();
EXIT();
}
int CallbackPipeline::setFrameCallback(JNIEnv *env, jobject frame_callback_obj, int pixel_format) {
ENTER();
Mutex::Autolock lock(capture_mutex);
if (isRunning() && isCapturing()) {
mIsCapturing = false;
if (mFrameCallbackObj) {
capture_sync.signal();
capture_sync.wait(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;
}
RETURN(0, int);
}
void CallbackPipeline::callbackPixelFormatChanged(const uint32_t &width, const uint32_t &height) {
mFrameCallbackFunc = NULL;
const size_t sz = width * height;
switch (mPixelFormat) {
case PIXEL_FORMAT_RAW:
LOGI("PIXEL_FORMAT_RAW:");
callbackPixelBytes = sz * 2;
break;
case PIXEL_FORMAT_YUV:
LOGI("PIXEL_FORMAT_YUV:");
mFrameCallbackFunc = uvc_any2yuyv;
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_any2yuv420SP;
callbackPixelBytes = (sz * 3) / 2;
break;
case PIXEL_FORMAT_NV21:
LOGI("PIXEL_FORMAT_NV21:");
mFrameCallbackFunc = uvc_any2iyuv420SP;
callbackPixelBytes = (sz * 3) / 2;
break;
}
}
void CallbackPipeline::do_capture(JNIEnv *env) {
ENTER();
uvc_frame_t *frame;
uvc_frame_t *temp = get_frame(default_frame_size);
uvc_frame_t *callback_frame;
uint32_t width = 0, height = 0;
size_t sz = default_frame_size;
if (LIKELY(temp)) {
for (; isRunning() && isCapturing();) {
frame = waitCaptureFrame();
if ((LIKELY(frame))) {
if (UNLIKELY((width != frame->width) || (height != frame->height))) {
width = frame->width;
height = frame->height;
callbackPixelFormatChanged(width, height);
uvc_ensure_frame_size(temp, callbackPixelBytes);
sz = callbackPixelBytes;
}
if (mFrameCallbackObj) {
callback_frame = frame;
sz = frame->actual_bytes;
if (mFrameCallbackFunc) {
callback_frame = temp;
sz = callbackPixelBytes;
int b = mFrameCallbackFunc(frame, temp);
if (UNLIKELY(b)) {
LOGW("failed to convert to callback 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(frame);
}
}
recycle_frame(temp);
}
EXIT();
}
//**********************************************************************
//
//**********************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz) {
ENTER();
CallbackPipeline *pipeline = new CallbackPipeline();
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
CallbackPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
CallbackPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
CallbackPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
CallbackPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
jint result = JNI_ERR;
ENTER();
CallbackPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
static jint nativeSetFrameCallback(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject jIFrameCallback, jint pixel_format) {
jint result = JNI_ERR;
ENTER();
CallbackPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
jobject frame_callback_obj = env->NewGlobalRef(jIFrameCallback);
result = pipeline->setFrameCallback(env, frame_callback_obj, pixel_format);
}
RETURN(result, jint);
}
//**********************************************************************
//
//**********************************************************************
static JNINativeMethod methods[] = {
{ "nativeCreate", "()J", (void *) nativeCreate },
{ "nativeDestroy", "(J)V", (void *) nativeDestroy },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
{ "nativeSetFrameCallback", "(JLcom/serenegiant/usb/IFrameCallback;I)I", (void *) nativeSetFrameCallback },
};
int register_callback_pipeline(JNIEnv *env) {
LOGV("register_callback_pipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/FrameCallbackPipeline",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/CallbackPipeline.h
================================================
//
// Created by saki on 15/11/07.
//
#ifndef PUPILMOBILE_CALLBACKPIPELINE_H
#define PUPILMOBILE_CALLBACKPIPELINE_H
#include "libUVCCamera.h"
#include "CaptureBasePipeline.h"
class CallbackPipeline : virtual public CaptureBasePipeline {
private:
jobject mFrameCallbackObj;
convFunc_t mFrameCallbackFunc;
Fields_iframecallback iframecallback_fields;
int mPixelFormat;
size_t callbackPixelBytes;
void callbackPixelFormatChanged(const uint32_t &width, const uint32_t &height);
protected:
virtual void do_capture(JNIEnv *env);
public:
CallbackPipeline(const size_t &_data_bytes = DEFAULT_FRAME_SZ);
virtual ~CallbackPipeline();
int setFrameCallback(JNIEnv *env, jobject frame_callback_obj, int pixel_format);
};
#endif //PUPILMOBILE_CALLBACKPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/CaptureBasePipeline.cpp
================================================
//
// Created by saki on 15/11/07.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include "utilbase.h"
#include "common_utils.h"
#include "CaptureBasePipeline.h"
#define INIT_FRAME_POOL_SZ 2
#define MAX_FRAME_NUM 8
CaptureBasePipeline::CaptureBasePipeline(const size_t &_data_bytes)
: AbstractBufferedPipeline(MAX_FRAME_NUM, INIT_FRAME_POOL_SZ, _data_bytes),
mIsCapturing(false),
captureQueue(NULL),
frameWidth(0),
frameHeight(0)
{
ENTER();
EXIT();
}
CaptureBasePipeline::CaptureBasePipeline(const int &_max_buffer_num, const int &init_pool_num, const size_t &default_frame_size)
: AbstractBufferedPipeline(_max_buffer_num, init_pool_num, default_frame_size),
mIsCapturing(false),
captureQueue(NULL),
frameWidth(0),
frameHeight(0)
{
ENTER();
EXIT();
}
CaptureBasePipeline::~CaptureBasePipeline() {
ENTER();
clearCaptureFrame();
EXIT();
}
//********************************************************************************
//
//********************************************************************************
const bool CaptureBasePipeline::isCapturing() const { return mIsCapturing; }
/**
* clear frame data for capturing
*/
void CaptureBasePipeline::clearCaptureFrame() {
Mutex::Autolock lock(capture_mutex);
if (captureQueue)
recycle_frame(captureQueue);
captureQueue = NULL;
}
void CaptureBasePipeline::addCaptureFrame(uvc_frame_t *frame) {
// ENTER();
Mutex::Autolock lock(capture_mutex);
// keep only latest one
if (captureQueue) {
recycle_frame(captureQueue);
captureQueue = NULL;
}
if (LIKELY(isRunning())) {
captureQueue = frame;
capture_sync.signal();
} else {
recycle_frame(frame);
}
// EXIT();
}
/**
* get frame data for capturing, if not exist, block and wait
*/
uvc_frame_t *CaptureBasePipeline::waitCaptureFrame() {
uvc_frame_t *frame = NULL;
Mutex::Autolock lock(capture_mutex);
if (!captureQueue) {
capture_sync.wait(capture_mutex);
}
if (LIKELY(isRunning() && captureQueue)) {
frame = captureQueue;
captureQueue = NULL;
}
return frame;
}
/* override protected */
void CaptureBasePipeline::on_start() {
ENTER();
mIsCapturing = true;
pthread_create(&capture_thread, NULL, capture_thread_func, (void *)this);
EXIT();
}
/* override protected */
void CaptureBasePipeline::on_stop() {
ENTER();
mIsCapturing = false;
capture_sync.broadcast();
if (pthread_join(capture_thread, NULL) != EXIT_SUCCESS) {
LOGW("UVCCameraControl::terminate capture thread: pthread_join failed");
}
clearCaptureFrame();
EXIT();
}
/* override protected */
int CaptureBasePipeline::handle_frame(uvc_frame_t *frame) {
// ENTER();
if (LIKELY(frame)) {
// get empty frame from frame pool
uvc_frame_t *copy = get_frame(frame->data_bytes);
if (LIKELY(copy)) {
// duplicate frame buffer and pass copy
uvc_error_t ret = uvc_duplicate_frame(frame, copy);
if (LIKELY(!ret)) {
addCaptureFrame(copy);
} else {
LOGW("uvc_duplicate_frame failed:%d", ret);
recycle_frame(copy);
}
} else {
LOGW("buffer pool is empty and exceeds the limit, drop frame");
}
}
return 0; // RETURN(0, int);
}
/*
* thread function
* @param vptr_args pointer to UVCCameraControl instance
*/
// static
void *CaptureBasePipeline::capture_thread_func(void *vptr_args) {
ENTER();
CaptureBasePipeline *pipeline = reinterpret_cast(vptr_args);
if (LIKELY(pipeline)) {
JavaVM *vm = getVM();
JNIEnv *env;
// attach to JavaVM
vm->AttachCurrentThread(&env, NULL);
pipeline->internal_do_capture(env); // never return until finish streaming
// detach from JavaVM
vm->DetachCurrentThread();
MARK("DetachCurrentThread");
}
PRE_EXIT();
pthread_exit(NULL);
}
/**
* the actual function for capturing
*/
void CaptureBasePipeline::internal_do_capture(JNIEnv *env) {
ENTER();
clearCaptureFrame();
for (; isRunning() ;) {
mIsCapturing = true;
do_capture(env);
capture_sync.broadcast();
} // end of for (; isRunning() ;)
EXIT();
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/CaptureBasePipeline.h
================================================
//
// Created by saki on 15/11/07.
//
#ifndef PUPILMOBILE_CAPTUREBASEPIPELINE_H
#define PUPILMOBILE_CAPTUREBASEPIPELINE_H
#include "Mutex.h"
#include "Condition.h"
#include "libUVCCamera.h"
#include "AbstractBufferedPipeline.h"
using namespace android;
class CaptureBasePipeline : virtual public AbstractBufferedPipeline {
private:
static void *capture_thread_func(void *vptr_args);
void internal_do_capture(JNIEnv *env);
protected:
volatile bool mIsCapturing;
mutable Mutex capture_mutex;
Condition capture_sync;
pthread_t capture_thread;
uvc_frame_t *captureQueue; // keep latest one frame only
uint32_t frameWidth;
uint32_t frameHeight;
void clearCaptureFrame();
void addCaptureFrame(uvc_frame_t *frame);
uvc_frame_t *waitCaptureFrame();
virtual void on_start();
virtual void on_stop();
virtual int handle_frame(uvc_frame_t *frame);
virtual void do_capture(JNIEnv *env) = 0;
public:
CaptureBasePipeline(const size_t &_data_bytes = DEFAULT_FRAME_SZ);
CaptureBasePipeline(const int &_max_buffer_num = DEFAULT_MAX_FRAME_NUM, const int &init_pool_num = DEFAULT_INIT_FRAME_POOL_SZ, const size_t &default_frame_size = DEFAULT_FRAME_SZ);
virtual ~CaptureBasePipeline();
const bool isCapturing() const;
};
#endif //PUPILMOBILE_CAPTUREBASEPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/ConvertPipeline.cpp
================================================
//
// Created by saki on 15/11/05.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
#include "ConvertPipeline.h"
#define INIT_FRAME_POOL_SZ 2
#define MAX_FRAME_NUM 8
/* public */
ConvertPipeline::ConvertPipeline(const size_t &_data_bytes, const int &_target_pixel_format)
: AbstractBufferedPipeline(MAX_FRAME_NUM, INIT_FRAME_POOL_SZ, _data_bytes),
target_pixel_format(_target_pixel_format),
mFrameConvFunc(NULL)
{
ENTER();
updateConvFunc();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
/* public */
ConvertPipeline::~ConvertPipeline() {
ENTER();
EXIT();
}
void ConvertPipeline::updateConvFunc() {
ENTER();
Mutex::Autolock lock(pipeline_mutex);
mFrameConvFunc = NULL;
switch (target_pixel_format) {
case PIXEL_FORMAT_RAW:
LOGI("PIXEL_FORMAT_RAW:");
break;
case PIXEL_FORMAT_YUV:
LOGI("PIXEL_FORMAT_YUV:");
mFrameConvFunc = uvc_any2yuyv;
break;
case PIXEL_FORMAT_RGB565:
LOGI("PIXEL_FORMAT_RGB565:");
mFrameConvFunc = uvc_any2rgb565;
break;
case PIXEL_FORMAT_RGBX:
LOGI("PIXEL_FORMAT_RGBX:");
mFrameConvFunc = uvc_any2rgbx;
break;
case PIXEL_FORMAT_YUV20SP:
LOGI("PIXEL_FORMAT_YUV20SP:");
mFrameConvFunc = uvc_any2yuv420SP;
break;
case PIXEL_FORMAT_NV21:
LOGI("PIXEL_FORMAT_NV21:");
mFrameConvFunc = uvc_any2iyuv420SP;
break;
}
EXIT();
};
void ConvertPipeline::on_start() {
ENTER();
updateConvFunc();
EXIT();
}
void ConvertPipeline::on_stop() {
ENTER();
EXIT();
}
int ConvertPipeline::handle_frame(uvc_frame_t *frame) {
ENTER();
Mutex::Autolock lock(pipeline_mutex);
if (next_pipeline) {
uvc_frame_t *copy = frame;
if (mFrameConvFunc) {
copy = get_frame(frame->actual_bytes);
if (LIKELY(copy)) {
const uvc_error_t r = mFrameConvFunc(frame, copy);
if (UNLIKELY(r)) {
LOGW("failed to convert:%d", r);
recycle_frame(copy);
copy = frame;
}
}
}
next_pipeline->queueFrame(copy);
}
RETURN(1, int);
}
//**********************************************************************
//
//**********************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz, jint pixel_format) {
ENTER();
ConvertPipeline *pipeline = new ConvertPipeline(DEFAULT_FRAME_SZ, pixel_format);
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
ConvertPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
ConvertPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
ConvertPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
ConvertPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
jint result = JNI_ERR;
ENTER();
ConvertPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
//**********************************************************************
//
//**********************************************************************
static JNINativeMethod methods[] = {
{ "nativeCreate", "(I)J", (void *) nativeCreate },
{ "nativeDestroy", "(J)V", (void *) nativeDestroy },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
};
int register_convert_pipeline(JNIEnv *env) {
LOGV("register_convert_pipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/ConvertPipeline",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/ConvertPipeline.h
================================================
//
// Created by saki on 15/11/05.
//
#ifndef PUPILMOBILE_CONVERTPIPELINE_H
#define PUPILMOBILE_CONVERTPIPELINE_H
#include "libUVCCamera.h"
#include "AbstractBufferedPipeline.h"
class ConvertPipeline : virtual public AbstractBufferedPipeline {
private:
const int target_pixel_format;
convFunc_t mFrameConvFunc;
void updateConvFunc();
protected:
virtual void on_start();
virtual void on_stop();
virtual int handle_frame(uvc_frame_t *frame);
public:
ConvertPipeline(const size_t &_data_bytes, const int &target_pixel_format = PIXEL_FORMAT_RAW);
virtual ~ConvertPipeline();
};
#endif //PUPILMOBILE_CONVERTPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/DistributePipeline.cpp
================================================
//
// Created by saki on 15/11/25.
//
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
#include "DistributePipeline.h"
DistributePipeline::DistributePipeline(const int &_max_buffer_num, const int &init_pool_num,
const size_t &default_frame_size, const bool &drop_frames_when_buffer_empty)
: AbstractBufferedPipeline(_max_buffer_num, init_pool_num, default_frame_size, drop_frames_when_buffer_empty)
{
ENTER();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
DistributePipeline::~DistributePipeline() {
ENTER();
Mutex::Autolock lock(pipeline_mutex);
pipelines.clear();
EXIT();
}
void DistributePipeline::on_start() {
ENTER();
EXIT();
}
void DistributePipeline::on_stop() {
ENTER();
EXIT();
}
int DistributePipeline::handle_frame(uvc_frame_t *frame) {
ENTER();
Mutex::Autolock lock(pipeline_mutex);
for (auto iter = pipelines.begin(); iter != pipelines.end(); iter++) {
(*iter)->queueFrame(frame);
}
RETURN(0, int);
}
int DistributePipeline::addPipeline(IPipeline *pipeline) {
ENTER();
if (pipeline) {
Mutex::Autolock lock(pipeline_mutex);
pipelines.push_back(pipeline);
}
RETURN(0, int);
}
int DistributePipeline::removePipeline(IPipeline *pipeline) {
ENTER();
if (pipeline) {
Mutex::Autolock lock(pipeline_mutex);
for (auto iter = pipelines.begin(); iter != pipelines.end(); ) {
if (*iter == pipeline) {
iter = pipelines.erase(iter);
} else {
iter++;
}
}
}
RETURN(0, int);
}
//**********************************************************************
//
//**********************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz) {
ENTER();
DistributePipeline *pipeline = new DistributePipeline();
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeAddPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->addPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeRemovePipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->removePipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
jint result = JNI_ERR;
ENTER();
DistributePipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
//**********************************************************************
//
//**********************************************************************
static JNINativeMethod methods[] = {
{ "nativeCreate", "()J", (void *) nativeCreate },
{ "nativeDestroy", "(J)V", (void *) nativeDestroy },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeAddPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeAddPipeline },
{ "nativeRemovePipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeRemovePipeline },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
};
int register_distribute_pipeline(JNIEnv *env) {
LOGV("register_distribute_pipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/DistributePipeline",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/DistributePipeline.h
================================================
//
// Created by saki on 15/11/25.
//
#ifndef PUPILMOBILE_DISTRIBUTEPIPELINE_H
#define PUPILMOBILE_DISTRIBUTEPIPELINE_H
#include "AbstractBufferedPipeline.h"
#pragma interface
class DistributePipeline : virtual public AbstractBufferedPipeline {
private:
std::list pipelines;
protected:
virtual void on_start();
virtual void on_stop();
virtual int handle_frame(uvc_frame_t *frame);
public:
DistributePipeline(const int &_max_buffer_num = DEFAULT_MAX_FRAME_NUM, const int &init_pool_num = DEFAULT_INIT_FRAME_POOL_SZ,
const size_t &default_frame_size = DEFAULT_FRAME_SZ, const bool &drop_frames_when_buffer_empty = true);
virtual ~DistributePipeline();
virtual int addPipeline(IPipeline *pipeline);
virtual int removePipeline(IPipeline *pipeline);
};
#endif //PUPILMOBILE_DISTRIBUTEPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/IPipeline.cpp
================================================
//
// Created by saki on 15/11/05.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
/*public*/
IPipeline::IPipeline(const size_t &_default_frame_size)
: state(PIPELINE_STATE_UNINITIALIZED),
mIsRunning(false),
default_frame_size(_default_frame_size),
next_pipeline(NULL)
{
ENTER();
EXIT();
}
/*public*/
IPipeline::~IPipeline() {
ENTER();
EXIT();
}
/*public*/
const bool IPipeline::isRunning() const { return (mIsRunning); };
/*public*/
const pipeline_state_t IPipeline::getState() const { return (state); };
/*protected*/
void IPipeline::setState(const pipeline_state_t &new_state) { state = new_state; }
/*public*/
int IPipeline::setPipeline(IPipeline *pipeline) {
ENTER();
Mutex::Autolock lock(pipeline_mutex);
// XXX do I need to delete next_pipeline if it is not NULL?
next_pipeline = pipeline;
RETURN(0, int);
}
/**
* set frame to next_pipeline
* if you don't need this, override this function
*/
int IPipeline::chain_frame(uvc_frame_t *frame) {
ENTER();
int result = -1;
Mutex::Autolock lock(pipeline_mutex);
if (next_pipeline) {
next_pipeline->queueFrame(frame);
result = 0;
}
RETURN(result, int);
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/IPipeline.h
================================================
//
// Created by saki on 15/11/05.
//
#ifndef PUPILMOBILE_IPIPELINE_H
#define PUPILMOBILE_IPIPELINE_H
#include
#include
#include "Mutex.h"
#include "libUVCCamera.h"
#pragma interface
using namespace android;
#define DEFAULT_FRAME_SZ 1024
typedef enum pipeline_type {
PIPELINE_TYPE_SIMPLE_BUFFERED = 0,
PIPELINE_TYPE_SQLITE_BUFFERED = 10,
PIPELINE_TYPE_UVC_CONTROL = 100,
PIPELINE_TYPE_CALLBACK = 200,
PIPELINE_TYPE_CONVERT = 300,
PIPELINE_TYPE_PREVIEW = 400,
PIPELINE_TYPE_PUBLISHER = 500,
PIPELINE_TYPE_DISTRIBUTE = 600,
} pipeline_type_t;
typedef enum _pipeline_state {
PIPELINE_STATE_UNINITIALIZED = 0,
PIPELINE_STATE_RELEASING = 10,
PIPELINE_STATE_INITIALIZED = 20,
PIPELINE_STATE_STARTING = 30,
PIPELINE_STATE_RUNNING = 40,
PIPELINE_STATE_STOPPING = 50,
} pipeline_state_t;
class IPipeline;
class IPipeline {
private:
volatile pipeline_state_t state;
// force inhibiting copy/assignment
IPipeline(const IPipeline &src);
void operator =(const IPipeline &src);
protected:
volatile bool mIsRunning;
const size_t default_frame_size;
mutable Mutex pipeline_mutex;
IPipeline *next_pipeline;
void setState(const pipeline_state_t &new_state);
/**
* if handle_frame return 0, handler_thread call this function
* set frame to next pipeline
* this may block caller thread while the pipeline is full
* @return 0: success queueing, other: failed
*/
virtual int chain_frame(uvc_frame_t *frame);
public:
IPipeline(const size_t &default_frame_size = DEFAULT_FRAME_SZ);
virtual ~IPipeline();
const pipeline_state_t getState() const;
const bool isRunning() const;
virtual int setPipeline(IPipeline *pipeline);
virtual int release() { return 0; };
virtual int start() { return 0; };
virtual int stop() { return 0; };
virtual int queueFrame(uvc_frame_t *frame) = 0;
};
#endif //PUPILMOBILE_IPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/PreviewPipeline.cpp
================================================
//
// Created by saki on 15/11/06.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
#include "PreviewPipeline.h"
#define INIT_FRAME_POOL_SZ 2
#define MAX_FRAME_NUM 32 // max approx. 1sec
#define CAPTURE_PIXEL_BYTES 2 // RGB565
PreviewPipeline::PreviewPipeline(const size_t &_data_bytes)
: CaptureBasePipeline(MAX_FRAME_NUM, INIT_FRAME_POOL_SZ, _data_bytes),
mCaptureWindow(NULL)
{
ENTER();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
PreviewPipeline::~PreviewPipeline() {
ENTER();
if (mCaptureWindow) {
ANativeWindow_release(mCaptureWindow);
}
mCaptureWindow = NULL;
clearCaptureFrame();
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)
static 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 * CAPTURE_PIXEL_BYTES;
const int src_step = frame->width * CAPTURE_PIXEL_BYTES;
// destination = Surface(ANativeWindow)
uint8_t *dest = (uint8_t *)buffer.bits;
const int dest_w = buffer.width * CAPTURE_PIXEL_BYTES;
const int dest_step = buffer.stride * CAPTURE_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);
}
//********************************************************************************
//
//********************************************************************************
int PreviewPipeline::setCaptureDisplay(ANativeWindow *capture_window) {
ENTER();
LOGI("setCaptureDisplay:%p", capture_window);
Mutex::Autolock lock(capture_mutex);
if (isRunning() && isCapturing()) {
mIsCapturing = false;
if (mCaptureWindow) {
LOGD("wait for finishing capture loop");
capture_sync.broadcast();
capture_sync.wait(capture_mutex); // wait finishing capturing
}
}
if (mCaptureWindow != capture_window) {
// release current Surface if already assigned.
if (UNLIKELY(mCaptureWindow)) {
LOGD("ANativeWindow_release");
ANativeWindow_release(mCaptureWindow);
}
mCaptureWindow = capture_window;
}
RETURN(0, int);
}
/**
* the actual function for capturing
*/
void PreviewPipeline::do_capture(JNIEnv *env) {
// ENTER();
uvc_frame_t *frame = NULL;
uvc_frame_t *rgb565 = get_frame(default_frame_size);
if (LIKELY(rgb565)) {
for (; isRunning() && isCapturing() ;) {
frame = waitCaptureFrame();
if (LIKELY(frame)) {
if (LIKELY(isCapturing())) {
const bool need_update_geometry = (frame->width != frameWidth) || (frame->height != frameHeight);
capture_mutex.lock();
{
ANativeWindow *window = mCaptureWindow; // local cache
if (LIKELY(window)) {
if (UNLIKELY(need_update_geometry)) {
frameWidth = frame->width;
frameHeight = frame->height;
LOGD("ANativeWindow_setBuffersGeometry:(%dx%d)", frameWidth, frameHeight);
ANativeWindow_setBuffersGeometry(window,
frameWidth, frameHeight, WINDOW_FORMAT_RGB_565);
// 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...you should use RGBX8888 instead
// So we need check here.
int32_t window_format = ANativeWindow_getFormat(window);
if (window_format != WINDOW_FORMAT_RGB_565) {
LOGE("window format mismatch, cancelled movie capturing.");
ANativeWindow_release(window);
window = mCaptureWindow = NULL;
frameWidth = frameHeight = 0;
}
}
if (LIKELY(window)) {
int b = uvc_any2rgb565(frame, rgb565);
if (LIKELY(!b)) {
copyToSurface(rgb565, &window);
} else {
LOGE("failed to convert frame: err=%d", b);
}
}
}
}
capture_mutex.unlock();
}
recycle_frame(frame);
}
}
}
if (rgb565) {
recycle_frame(rgb565);
}
capture_mutex.lock();
{
if (mCaptureWindow) {
ANativeWindow_release(mCaptureWindow);
mCaptureWindow = NULL;
}
}
capture_mutex.unlock();
// EXIT();
}
//**********************************************************************
//
//**********************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz) {
ENTER();
PreviewPipeline *pipeline = new PreviewPipeline();
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
PreviewPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
PreviewPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
PreviewPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
PreviewPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
jint result = JNI_ERR;
ENTER();
PreviewPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
static jint nativeSetCaptureDisplay(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject jSurface) {
jint result = JNI_ERR;
ENTER();
PreviewPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
ANativeWindow *capture_window = jSurface ? ANativeWindow_fromSurface(env, jSurface) : NULL;
result = pipeline->setCaptureDisplay(capture_window);
}
RETURN(result, jint);
}
//**********************************************************************
//
//**********************************************************************
static JNINativeMethod methods[] = {
{ "nativeCreate", "()J", (void *) nativeCreate },
{ "nativeDestroy", "(J)V", (void *) nativeDestroy },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
{ "nativeSetCaptureDisplay", "(JLandroid/view/Surface;)I", (void *) nativeSetCaptureDisplay },
};
int register_preview_pipeline(JNIEnv *env) {
LOGV("register_preview_pipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/PreviewPipeline",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/PreviewPipeline.h
================================================
//
// Created by saki on 15/11/06.
//
#ifndef PUPILMOBILE_PREVIEWPIPELINE_H
#define PUPILMOBILE_PREVIEWPIPELINE_H
#include
#include "libUVCCamera.h"
#include "CaptureBasePipeline.h"
class PreviewPipeline : virtual public CaptureBasePipeline {
private:
ANativeWindow *mCaptureWindow;
protected:
virtual void do_capture(JNIEnv *env);
public:
PreviewPipeline(const size_t &_data_bytes = DEFAULT_FRAME_SZ);
virtual ~PreviewPipeline();
int setCaptureDisplay(ANativeWindow *capture_window);
};
#endif //PUPILMOBILE_PREVIEWPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/PublisherPipeline.cpp
================================================
//
// Created by saki on 15/10/06.
//
#define MEAS_TIME 0
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#if MEAS_TIME
#define MEAS_TIME_INIT nsecs_t _meas_time_ = 0; int _meas_count_ = 0;
#define MEAS_TIME_START const nsecs_t _meas_t_ = systemTime();
#define MEAS_TIME_STOP \
_meas_time_ += (systemTime() - _meas_t_); \
if UNLIKELY((++_meas_count_ % 100) == 0) { \
const float d = _meas_time_ / (1000000.f * _meas_count_); \
LOGI("meas time=%5.2f[msec]", d); \
}
#else
#define MEAS_TIME_INIT
#define MEAS_TIME_START
#define MEAS_TIME_STOP
#endif
#include
#include
#include
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "endian_unaligned.h"
#include "pipeline_helper.h"
#include "PublisherPipeline.h"
#include "pupilmobile_defs.h"
#define INIT_FRAME_POOL_SZ 2
#define MAX_FRAME_NUM 8
#define RETRY_INTERVALS_US 25000
/* public */
PublisherPipeline::PublisherPipeline(const size_t &_data_bytes, const char *addr, const char *_subscription_id)
: AbstractBufferedPipeline(MAX_FRAME_NUM, INIT_FRAME_POOL_SZ, _data_bytes),
host(addr),
subscription_id(_subscription_id),
data_bytes(_data_bytes),
context(NULL),
publisher(NULL)
{
ENTER();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
/* public */
PublisherPipeline::PublisherPipeline(const char *addr, const char *_subscription_id)
: PublisherPipeline(DEFAULT_FRAME_SZ, addr, _subscription_id)
{
}
/* public */
PublisherPipeline::~PublisherPipeline() {
ENTER();
LOGI("destructor finished");
EXIT();
}
/*public*/
int PublisherPipeline::queueFrame(uvc_frame_t *frame) {
// ENTER();
int result = AbstractBufferedPipeline::queueFrame(frame);
chain_frame(frame);
return result; // RETURN(result, int);
}
//********************************************************************************
//
//********************************************************************************
/**
* build transfer header.
* all multi bytes fields are little endian.
*/
static void build_header(publish_header_t &header, uvc_frame_t *frame) {
// build header
switch (frame->frame_format) {
case UVC_FRAME_FORMAT_YUYV:
header.format_le = htole32(VIDEO_FRAME_FORMAT_YUYV);
break;
case UVC_FRAME_FORMAT_MJPEG:
header.format_le = htole32(VIDEO_FRAME_FORMAT_MJPEG);
break;
// case UVC_FRAME_FORMAT_H264: // XXX this definition does not exist now
// header.format_le = htole32(VIDEO_FRAME_FORMAT_H264);
// break;
default:
header.format_le = htole32(VIDEO_FRAME_FORMAT_UNKNOWN);
}
header.width_le = htole32(frame->width);
header.height_le = htole32(frame->height);
header.sequence_le = htole32(frame->sequence);
// header.presentation_time_us_le = htole64(systemTime() / 1000);
header.presentation_time_us_le = htole64(nsecs_t(frame->capture_time.tv_sec)*1000000LL + nsecs_t(frame->capture_time.tv_usec));
header.data_bytes_le = htole32(frame->actual_bytes);
}
/* override protected */
void PublisherPipeline::on_start() {
ENTER();
Mutex::Autolock lock(publisher_mutex);
context = new zmq::context_t();
publisher = new zmq::socket_t(*context, ZMQ_PAIR/*ZMQ_PUB*/);
LOGV("set timeout value");
publisher->setsockopt(ZMQ_SNDTIMEO, 1000);
publisher->setsockopt(ZMQ_LINGER, 100);
LOGV("bind");
publisher->bind(host.c_str());
EXIT();
}
/* override protected */
void PublisherPipeline::on_stop() {
ENTER();
Mutex::Autolock lock(publisher_mutex);
LOGI("on_stop:finished");
LOGI("stop publisher zmq::socket");
if (publisher) {
publisher->close();
SAFE_DELETE(publisher);
}
LOGI("stop publisher zmq::context");
if (context) {
context->close();
SAFE_DELETE(context);
}
LOGI("on_stop:finished");
EXIT();
}
/* override protected */
int PublisherPipeline::handle_frame(uvc_frame_t *frame) {
// ENTER();
// local cache
const int sub_sz = subscription_id.size();
const char *sub_str = subscription_id.c_str();
// LOGD("sub_str=%s,sub_sz=%d", sub_str, sub_sz);
publish_header_t header;
// create payload
zmq::message_t payload(frame->actual_bytes + sizeof(publish_header_t));
// copy header to payload
build_header(header, frame);
memcpy(payload.data(), &header, sizeof(publish_header_t));
// copy frame data to payload
memcpy(((uint8_t *)payload.data()) + sizeof(publish_header_t), frame->data, frame->actual_bytes);
/*
* zmq::socket_t#send(backed by zmq_msg_send of libzmq) just add message to the internal queue.
* and we can't know how many entries we can send without exceeding queue
* and we also can't know when the queue exceed/overflow and message disappeared.
* As my current test result, if the subscribing speed is slower than publisher
* or bandwidth of network is not enough, zmq drops messages periodically without any error.
* Even worse, queueing to zmq socket always success and no error.
* As I can see the API and source code of zmq, there are no way to handle this now.
* Only one way is receive number of subscribed frames from subscriber via other connection
* and wait for publishing if the difference between number of publishing frames
* and number of subscribed frames become bigger than the limit.
* Unfortunately this way only works well if only one subscriber exist.
* If we actually need to handle this issue, I assume it will be better to use other protocol
* or make own protocol that supports handshake instead of using zmq.
*
* 1280x720p:
* Nexus7(2013, Android5.1.1) => 11n(2.4GHz) => router => 11n(5Ghz) => Nexus9(Android5.1.1) : OK
* Nexus7(2013, Android5.1.1) => 11n(2.4GHz) => router => 11n(2.4GHz) => GALAXY S5(Android5.0) : NG, slow, periodically drops frames.
* Nexus9(Android5.1.1) => 11n(5GHz) => router => 11n(2.4GHz) => GALAXY S5(Android5.0) : OK
* Nexus9(Android5.1.1) => 11n(5GHz) => router => 11n(2.4GHz) => MemoPad7(Android4.4.2) : NG, sometimes become slow, periodically drops frames.
* GALAXY S5(Android5.0) => 11n(2.4GHz) => router => 11n(5Ghz) => Nexus9(Android5.1.1) : OK
* GALAXY S5(Android5.0) => 11n(2.4GHz) => router => 11n(2.4Ghz) => GALAXY note2(Android4.4.2) : NG, slow, periodically drops frames.
* saki
*/
for ( ; LIKELY(isRunning()) ; ) {
try {
// set subscribe id
if ((LIKELY(publisher->send(sub_str, sub_sz, ZMQ_SNDMORE)))) {
// send payload
if (LIKELY(publisher->send(payload))) {
// success to send
break;
}
}
LOGD("failed to send");
usleep(RETRY_INTERVALS_US);
} catch (zmq::error_t e) {
// when error occur other than EAGAIN
LOGW("failed to send:%d", e.num());
break;
} catch (...) {
LOGW("publishing error");
break;
}
}
return 1; // RETURN(1, int);
}
//********************************************************************************
//
//********************************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz,
jstring publisher_addr_str, jstring subscription_id_str) {
ENTER();
const char *c_addr = env->GetStringUTFChars(publisher_addr_str, JNI_FALSE);
const char *c_sub_id = env->GetStringUTFChars(subscription_id_str, JNI_FALSE);
PublisherPipeline *pipeline = new PublisherPipeline(DEFAULT_FRAME_SZ, c_addr, c_sub_id);
env->ReleaseStringUTFChars(publisher_addr_str, c_addr);
env->ReleaseStringUTFChars(subscription_id_str, c_sub_id);
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
PublisherPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
PublisherPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
PublisherPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
PublisherPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = JNI_ERR;
PublisherPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
//================================================================================
static JNINativeMethod methods_publisher_pipeline[] = {
{ "nativeCreate", "(Ljava/lang/String;Ljava/lang/String;)J", (void *) nativeCreate},
{ "nativeDestroy", "(J)V", (void *) nativeDestroy},
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
};
int register_publisher_pipeline(JNIEnv *env) {
LOGV("register PublisherPipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/PublisherPipeline",
methods_publisher_pipeline, NUM_ARRAY_ELEMENTS(methods_publisher_pipeline)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/PublisherPipeline.h
================================================
//
// Created by saki on 15/10/06.
//
#ifndef PUPILMOBILE_PUBLISHER_PIPELINE_H
#define PUPILMOBILE_PUBLISHER_PIPELINE_H
#pragma interface
#include
#include "Mutex.h"
#include "Timers.h"
#include "zmq.hpp"
#include "pupilmobile_defs.h"
#include "AbstractBufferedPipeline.h"
using namespace android;
class PublisherPipeline : virtual public AbstractBufferedPipeline {
private:
protected:
const std::string host;
const std::string subscription_id;
size_t data_bytes;
zmq::context_t *context;
zmq::socket_t *publisher;
mutable Mutex publisher_mutex;
virtual void on_start();
virtual void on_stop();
virtual int handle_frame(uvc_frame_t *frame);
public:
PublisherPipeline(const size_t &_data_bytes = DEFAULT_FRAME_SZ, const char *addr = NULL, const char *subscription_id = NULL);
PublisherPipeline(const char *addr, const char *subscription_id);
virtual ~PublisherPipeline();
virtual int queueFrame(uvc_frame_t *frame);
};
#endif //PUPILMOBILE_PUBLISHER_PIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/SQLiteBufferedPipeline.cpp
================================================
//
// Created by saki on 15/11/09.
//
#if 1 // set 1 if you don't need debug message
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // ignore LOGV/LOGD/MARK
#endif
#undef USE_LOGALL
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG // depends on definition in Android.mk and Application.mk
#endif
#include
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
#include "Timers.h"
#include "SQLiteBufferedPipeline.h"
#define CHECK_INTERVAL_NSEC 5000000000LL // every 5sec
#define TABLE_NAME "backend"
#define INSERT_FIELDS "dtime, format, width, height, sequence, data_bytes, data"
#define ALL_FIELDS "id, dtime, format, width, height, sequence, data_bytes, data"
/*public*/
SQLiteBufferedPipeline::SQLiteBufferedPipeline(const char *database_name, const bool &clear_table)
: IPipeline(0),db(NULL),
sql_insert_one(NULL),
sql_query_oldest_10(NULL),
sql_delete_one(NULL),
sql_delete_older(NULL),
sql_count(NULL)
{
ENTER();
db = new sqlite3pp::database(database_name);
// 0:id, 1:dtime, 2:format, 3:width, 4:height, 5:sequence, 6:data_bytes, 7:data
sqlite3pp::command cmd(*db,
"CREATE TABLE IF NOT EXISTS " TABLE_NAME " ("
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
"dtime INTEGER NOT NULL UNIQUE, "
"format INTEGER NOT NULL, "
"width INTEGER NOT NULL, "
"height INTEGER NOT NULL, "
"sequence INTEGER NOT NULL, "
"data_bytes INTEGER NOT NULL, "
"data BLOB NOT NULL"
");"
);
cmd.execute();
if (clear_table) {
clear();
}
// sqlite3pp::statement and it's descendants that accessing table can only create when the specific table already exists.
sql_insert_one = new sqlite3pp::command(*db, "INSERT INTO " TABLE_NAME
" (" INSERT_FIELDS ") VALUES (?, ?, ?, ?, ?, ?, ?);");
sql_query_oldest_10 = new sqlite3pp::query(*db, "SELECT " ALL_FIELDS " FROM " TABLE_NAME " ORDER BY dtime LIMIT 10;");
sql_delete_one = new sqlite3pp::command(*db, "DELETE FROM " TABLE_NAME " WHERE (id=?);");
sql_delete_older = new sqlite3pp::command(*db, "DELETE FROM " TABLE_NAME " WHERE (dtime);");
sql_count = new sqlite3pp::query(*db, "SELECT count(id) FROM " TABLE_NAME ";");
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
/*public*/
SQLiteBufferedPipeline::~SQLiteBufferedPipeline() {
ENTER();
LOGD("deleting sql_count");
if (sql_count) {
sql_count->finish();
SAFE_DELETE(sql_count);
}
LOGD("deleting sql_delete_older");
if (sql_delete_older) {
sql_delete_older->finish();
SAFE_DELETE(sql_delete_older);
}
LOGD("deleting sql_delete_one");
if (sql_delete_one) {
sql_delete_one->finish();
SAFE_DELETE(sql_delete_one);
}
LOGD("deleting sql_query_oldest_10");
if (sql_query_oldest_10) {
sql_query_oldest_10->finish();
SAFE_DELETE(sql_query_oldest_10);
}
LOGD("deleting sql_insert_one");
if (sql_insert_one) {
sql_insert_one->finish();
SAFE_DELETE(sql_insert_one);
}
LOGD("deleting db");
if (db) {
db->disconnect();
SAFE_DELETE(db);
}
EXIT();
};
/*public*/
int SQLiteBufferedPipeline::release() {
ENTER();
setState(PIPELINE_STATE_RELEASING);
stop();
RETURN(0, int);
}
/*public*/
int SQLiteBufferedPipeline::start() {
ENTER();
int result = EXIT_FAILURE;
if (!isRunning()) {
LOGD("start handler thread");
setState(PIPELINE_STATE_STARTING);
mIsRunning = true;
result = pthread_create(&handler_thread, NULL, handler_thread_func, (void *) this);
if (UNLIKELY(result != EXIT_SUCCESS)) {
LOGW("PublisherPipeline::already running/could not create thread etc.");
setState(PIPELINE_STATE_INITIALIZED);
mIsRunning = false;
handler_sync.signal();
}
}
RETURN(result, int);
}
/*public*/
int SQLiteBufferedPipeline::stop() {
ENTER();
bool b = isRunning();
if (LIKELY(b)) {
LOGD("waiting SQLiteBufferedPipeline thread");
setState(PIPELINE_STATE_STOPPING);
mIsRunning = false;
handler_sync.broadcast();
if (pthread_join(handler_thread, NULL) != EXIT_SUCCESS) {
LOGW("SQLiteBufferedPipeline::terminate SQLiteBufferedPipeline thread: pthread_join failed");
}
LOGD("SQLiteBufferedPipeline thread finished");
}
RETURN(0, int);
}
/*public*/
int SQLiteBufferedPipeline::queueFrame(uvc_frame_t *frame) {
ENTER();
uvc_error_t ret = UVC_ERROR_OTHER;
Mutex::Autolock lock(handler_mutex);
if (LIKELY(frame && isRunning())) {
// FIXME if the number of record exceeds specific limit, need to delete old records or drop newer frames
// FIXME otherwise device storage will become empty at some point.
try {
sql_insert_one->reset();
sql_insert_one->bind(1, nsecs_t(frame->capture_time.tv_sec) * 1000000LL +
nsecs_t(frame->capture_time.tv_usec));
sql_insert_one->bind(2, (int) frame->frame_format);
sql_insert_one->bind(3, (int) frame->width);
sql_insert_one->bind(4, (int) frame->height);
sql_insert_one->bind(5, (int) frame->sequence);
sql_insert_one->bind(6, (int) frame->actual_bytes);
sql_insert_one->bind(7, (void *) frame->data, frame->actual_bytes, false);
sql_insert_one->execute();
ret = UVC_SUCCESS;
} catch (...) {
LOGW("failed insert frame");
}
handler_sync.broadcast();
}
RETURN(ret, int);
}
/*public*/
void SQLiteBufferedPipeline::clear() {
ENTER();
sqlite3pp::command sql_truncate(*db, "TRUNCATE TABLE " TABLE_NAME ";");
sql_truncate.execute();
EXIT();
}
/**
* delete record(s) older than specific dtime.
* if you want to delete all record(s), use clear instead
*/
/*protected*/
int SQLiteBufferedPipeline::delete_older(const nsecs_t &dtime) {
ENTER();
#ifndef NDEBUG
LOGI("before=%d", getCount());
#endif
int result = -1;
try {
sql_delete_older->reset();
sql_delete_older->bind(1, dtime);
sql_delete_older->execute();
result = 0;
} catch (...) {
LOGW("failed to delete older:%lld", dtime);
}
#ifndef NDEBUG
LOGI("after=%d", getCount());
#endif
RETURN(result, int);
}
/*protected*/
int SQLiteBufferedPipeline::purge_older(const nsecs_t &limit_rel_nsec) {
ENTER();
int result = -1;
if (LIKELY(limit_rel_nsec)) {
result = delete_older(systemTime() - limit_rel_nsec);
}
RETURN(result, int);
}
int SQLiteBufferedPipeline::getCount() {
ENTER();
int result = 0;
if (LIKELY(sql_count)) {
sql_count->reset();
for (auto iter = sql_count->begin(); iter != sql_count->end(); ++iter) {
result = (*iter).get(0);
break; // sql_count statement always return only one record and this will s redundant.
}
}
RETURN(result, int);
}
/*private*/
void *SQLiteBufferedPipeline::handler_thread_func(void *vptr_args) {
ENTER();
SQLiteBufferedPipeline *pipeline = reinterpret_cast(vptr_args);
if (LIKELY(pipeline)) {
pipeline->do_loop();
}
PRE_EXIT();
pthread_exit(NULL);
}
/*private*/
void SQLiteBufferedPipeline::do_loop() {
ENTER();
std::vector queued_ids;
struct timespec ts, ws;
ts.tv_sec = 5; ts.tv_nsec = 0; // wait maximum 5 sec
// ws.tv_sec = 0; ws.tv_nsec = 3000000; // 3msec
uvc_frame_t *frame = uvc_allocate_frame(DEFAULT_FRAME_SZ);
if (LIKELY(frame)) {
setState(PIPELINE_STATE_RUNNING);
nsecs_t prev_time = systemTime();
for (; LIKELY(isRunning());) {
handler_mutex.lock();
{
// wait for new arriving frame data
handler_sync.waitRelative(handler_mutex, 3000000);
}
handler_mutex.unlock();
if (LIKELY(isRunning())) {
if (next_pipeline) {
queued_ids.clear();
for (auto iter = sql_query_oldest_10->begin(); iter != sql_query_oldest_10->end(); ++iter) {
if (UNLIKELY(!isRunning())) {
break;
}
// 0:id, 1:dtime, 2:format, 3:width, 4:height, 5:sequence, 6:data_bytes, 7:data
const int64_t id = (*iter).get(0); // XXX int64_t(long long int) may be better
const nsecs_t dtime = (*iter).get (1);
const uvc_frame_format format = (uvc_frame_format)(*iter).get(2);
const uint32_t width = (uint32_t)(*iter).get(3);
const uint32_t height = (uint32_t)(*iter).get(4);
const uint32_t sequence = (uint32_t)((*iter).get (5));
const size_t actual_bytes = (size_t)(*iter).get(6);
const void *data = (*iter).get(7);
if (LIKELY(!uvc_ensure_frame_size(frame, actual_bytes))) {
frame->capture_time.tv_sec = dtime / 1000000LL;
frame->capture_time.tv_usec = dtime % 1000000LL;
frame->frame_format = format;
frame->width = width;
frame->height = height;
frame->sequence = sequence;
frame->actual_bytes = actual_bytes;
memcpy(frame->data, data, actual_bytes);
if (!chain_frame(frame)) {
// if queueing success, delete the record
queued_ids.push_back(id);
// LOGI("chain_frame:%lld,%lld,(%d,%d),actual_bytes=%d", id, dtime, width, height, actual_bytes);
if (iter != sql_query_oldest_10->end()) {
// wait several msecs here if the record is not a last one, otherwise after pipeline will exceed buffer and drop frame(s)
handler_mutex.lock();
{
handler_sync.waitRelative(handler_mutex, 5000000000L);
}
handler_mutex.unlock();
}
}
} else {
LOGW("uvc_ensure_frame_size failed:%lld,%lld,(%d,%d),actual_bytes=%d", id, dtime, width, height, actual_bytes);
}
} // end of for
// delete chained record(s) if exist
sqlite3pp::transaction xct(*db);
try {
for (auto iter = queued_ids.begin(); iter != queued_ids.end(); iter++) {
sql_delete_one->reset();
sql_delete_one->bind(1, *iter);
sql_delete_one->execute();
}
xct.commit();
} catch (std::exception &e) {
LOGI("exception: failed to delate");
xct.rollback(); // this may redundant
}
} // end of if (next_pipeline)
if (UNLIKELY(systemTime() > prev_time + CHECK_INTERVAL_NSEC)) {
prev_time = systemTime();
purge_older();
}
}
}
setState(PIPELINE_STATE_STOPPING);
uvc_free_frame(frame);
} else {
LOGW("uvc_allocate_frame failed");
}
setState(PIPELINE_STATE_INITIALIZED);
mIsRunning = false;
EXIT();
}
//********************************************************************************
//
//********************************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz,
jstring database_path_str, jboolean clear_table) {
ENTER();
const char *c_database_path = env->GetStringUTFChars(database_path_str, JNI_FALSE);
SQLiteBufferedPipeline *pipeline = NULL;
try {
pipeline = new SQLiteBufferedPipeline(c_database_path, clear_table);
} catch (...) {
LOGW("failed to create SQLiteBufferedPipeline");
}
env->ReleaseStringUTFChars(database_path_str, c_database_path);
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
SQLiteBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
SQLiteBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
SQLiteBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
SQLiteBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
jint result = JNI_ERR;
ENTER();
SQLiteBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
//**********************************************************************
//
//**********************************************************************
static JNINativeMethod methods[] = {
{"nativeCreate", "(Ljava/lang/String;Z)J", (void *) nativeCreate},
{ "nativeDestroy", "(J)V", (void *) nativeDestroy },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
};
int register_sqlite_buffered_pipeline(JNIEnv *env) {
LOGV("register PublisherPipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/SQLiteBufferedPipeline",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/SQLiteBufferedPipeline.h
================================================
//
// Created by saki on 15/11/09.
//
#ifndef PUPILMOBILE_SQLITEBUFFEREDPIPELINE_H
#define PUPILMOBILE_SQLITEBUFFEREDPIPELINE_H
#include
#include
#include
#include
#include "Mutex.h"
#include "Condition.h"
#include "libUVCCamera.h"
#include "IPipeline.h"
#include "sqlite3pp.h"
#pragma interface
using namespace android;
#define DTIME_LIMIT_NSEC 30000000000LL // 30sec
class SQLiteBufferedPipeline : virtual public IPipeline {
private:
sqlite3pp::database *db;
// precompile statements
sqlite3pp::command *sql_insert_one;
sqlite3pp::query *sql_query_oldest_10;
sqlite3pp::command *sql_delete_one;
sqlite3pp::command *sql_delete_older;
sqlite3pp::query *sql_count;
pthread_t handler_thread;
mutable Mutex handler_mutex;
Condition handler_sync;
static void *handler_thread_func(void *vptr_args);
void do_loop();
protected:
int getCount();
/**
* delete record(s) older than specific dtime.
* if you want to delete all record(s), use clear instead
*/
int delete_older(const nsecs_t &dtime);
/** helper of delete_older */
int purge_older(const nsecs_t &limit_rel_nsec = DTIME_LIMIT_NSEC);
public:
SQLiteBufferedPipeline(const char *database_name, const bool &clear = false);
virtual ~SQLiteBufferedPipeline();
virtual int release();
virtual int start();
virtual int stop();
virtual int queueFrame(uvc_frame_t *frame);
virtual void clear();
};
#endif //PUPILMOBILE_SQLITEBUFFEREDPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/SimpleBufferedPipeline.cpp
================================================
//
// Created by saki on 15/11/23.
//
#include "utilbase.h"
#include "common_utils.h"
#include "libUVCCamera.h"
#include "pipeline_helper.h"
#include "IPipeline.h"
#include "SimpleBufferedPipeline.h"
SimpleBufferedPipeline::SimpleBufferedPipeline(const int &_max_buffer_num, const int &init_pool_num,
const size_t &default_frame_size, const bool &drop_frames_when_buffer_empty)
: AbstractBufferedPipeline(_max_buffer_num, init_pool_num, default_frame_size, drop_frames_when_buffer_empty)
{
ENTER();
setState(PIPELINE_STATE_INITIALIZED);
EXIT();
}
SimpleBufferedPipeline::~SimpleBufferedPipeline() {
ENTER();
EXIT();
}
void SimpleBufferedPipeline::on_start() {
ENTER();
EXIT();
}
void SimpleBufferedPipeline::on_stop() {
ENTER();
EXIT();
}
int SimpleBufferedPipeline::handle_frame(uvc_frame_t *frame) {
ENTER();
RETURN(0, int);
}
//**********************************************************************
//
//**********************************************************************
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz) {
ENTER();
SimpleBufferedPipeline *pipeline = new SimpleBufferedPipeline();
setField_long(env, thiz, "mNativePtr", reinterpret_cast(pipeline));
RETURN(reinterpret_cast(pipeline), ID_TYPE);
}
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
SimpleBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
pipeline->release();
SAFE_DELETE(pipeline);
}
EXIT();
}
static jint nativeGetState(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
jint result = 0;
SimpleBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
result = pipeline->getState();
}
RETURN(result, jint);
}
static jint nativeSetPipeline(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline, jobject pipeline_obj) {
ENTER();
jint result = JNI_ERR;
SimpleBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (pipeline) {
IPipeline *target_pipeline = getPipeline(env, pipeline_obj);
result = pipeline->setPipeline(target_pipeline);
}
RETURN(result, jint);
}
static jint nativeStart(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
ENTER();
int result = JNI_ERR;
SimpleBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->start();
}
RETURN(result, jint);
}
static jint nativeStop(JNIEnv *env, jobject thiz,
ID_TYPE id_pipeline) {
jint result = JNI_ERR;
ENTER();
SimpleBufferedPipeline *pipeline = reinterpret_cast(id_pipeline);
if (LIKELY(pipeline)) {
result = pipeline->stop();
}
RETURN(result, jint);
}
//**********************************************************************
//
//**********************************************************************
static JNINativeMethod methods[] = {
{ "nativeCreate", "()J", (void *) nativeCreate },
{ "nativeDestroy", "(J)V", (void *) nativeDestroy },
{ "nativeGetState", "(J)I", (void *) nativeGetState },
{ "nativeSetPipeline", "(JLcom/serenegiant/usb/IPipeline;)I", (void *) nativeSetPipeline },
{ "nativeStart", "(J)I", (void *) nativeStart },
{ "nativeStop", "(J)I", (void *) nativeStop },
};
int register_simple_buffered_pipeline(JNIEnv *env) {
LOGV("register_simple_buffered_pipeline:");
if (registerNativeMethods(env,
"com/serenegiant/usb/SimpleBufferedPipeline",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/SimpleBufferedPipeline.h
================================================
//
// Created by saki on 15/11/23.
//
#ifndef PUPILMOBILE_SIMPLEBUFFEREDPIPELINE_H
#define PUPILMOBILE_SIMPLEBUFFEREDPIPELINE_H
#include "AbstractBufferedPipeline.h"
class SimpleBufferedPipeline : virtual public AbstractBufferedPipeline {
protected:
virtual void on_start();
virtual void on_stop();
virtual int handle_frame(uvc_frame_t *frame);
public:
SimpleBufferedPipeline(const int &_max_buffer_num = DEFAULT_MAX_FRAME_NUM, const int &init_pool_num = DEFAULT_INIT_FRAME_POOL_SZ,
const size_t &default_frame_size = DEFAULT_FRAME_SZ, const bool &drop_frames_when_buffer_empty = true);
virtual ~SimpleBufferedPipeline();
};
#endif //PUPILMOBILE_SIMPLEBUFFEREDPIPELINE_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/pipeline_helper.cpp
================================================
//
// Created by saki on 15/11/12.
//
#include "utilbase.h"
#include "Timers.h"
#include "SimpleBufferedPipeline.h"
#include "SQLiteBufferedPipeline.h"
#include "UVCCameraControl.h"
#include "CallbackPipeline.h"
#include "ConvertPipeline.h"
#include "PreviewPipeline.h"
#include "PublisherPipeline.h"
#include "DistributePipeline.h"
#include "pipeline_helper.h"
IPipeline *getPipeline(JNIEnv *env, jobject pipeline_obj) {
ENTER();
if (!pipeline_obj) return NULL;
ID_TYPE id_pipeline = getField_long(env, pipeline_obj, "mNativePtr");
jint type = getField_int(env, pipeline_obj, "mType");
env->ExceptionClear();
IPipeline *result = NULL;
switch (type) {
case PIPELINE_TYPE_SIMPLE_BUFFERED:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_SQLITE_BUFFERED:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_UVC_CONTROL:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_CALLBACK:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_CONVERT:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_PREVIEW:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_PUBLISHER:
result = reinterpret_cast(id_pipeline);
break;
case PIPELINE_TYPE_DISTRIBUTE:
result = reinterpret_cast(id_pipeline);
break;
default:
result = NULL;
break;
}
RETURN(result, IPipeline *);
}
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/pipeline/pipeline_helper.h
================================================
//
// Created by saki on 15/11/12.
//
#ifndef PUPILMOBILE_PIPELINE_HELPER_H_H
#define PUPILMOBILE_PIPELINE_HELPER_H_H
#include "common_utils.h"
#include "IPipeline.h"
IPipeline *getPipeline(JNIEnv *env, jobject pipeline_obj);
#endif //PUPILMOBILE_PIPELINE_HELPER_H_H
================================================
FILE: libuvccamera/src/main/jni/UVCCamera/serenegiant_usb_UVCCamera.cpp
================================================
/*
* 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: serenegiant_usb_UVCCamera.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.
*/
#if 1 // デバッグ情報を出さない時
#ifndef LOG_NDEBUG
#define LOG_NDEBUG // LOGV/LOGD/MARKを出力しない時
#endif
#undef USE_LOGALL // 指定したLOGxだけを出力
#else
#define USE_LOGALL
#undef LOG_NDEBUG
#undef NDEBUG
#endif
#include
#include
#include "libUVCCamera.h"
#include "UVCCamera.h"
/**
* set the value into the long field
* @param env: this param should not be null
* @param bullet_obj: this param should not be null
* @param field_name
* @params val
*/
static jlong setField_long(JNIEnv *env, jobject java_obj, const char *field_name, jlong val) {
#if LOCAL_DEBUG
LOGV("setField_long:");
#endif
jclass clazz = env->GetObjectClass(java_obj);
jfieldID field = env->GetFieldID(clazz, field_name, "J");
if (LIKELY(field))
env->SetLongField(java_obj, field, val);
else {
LOGE("__setField_long:field '%s' not found", field_name);
}
#ifdef ANDROID_NDK
env->DeleteLocalRef(clazz);
#endif
return val;
}
/**
* @param env: this param should not be null
* @param bullet_obj: this param should not be null
*/
static jlong __setField_long(JNIEnv *env, jobject java_obj, jclass clazz, const char *field_name, jlong val) {
#if LOCAL_DEBUG
LOGV("__setField_long:");
#endif
jfieldID field = env->GetFieldID(clazz, field_name, "J");
if (LIKELY(field))
env->SetLongField(java_obj, field, val);
else {
LOGE("__setField_long:field '%s' not found", field_name);
}
return val;
}
/**
* @param env: this param should not be null
* @param bullet_obj: this param should not be null
*/
jint __setField_int(JNIEnv *env, jobject java_obj, jclass clazz, const char *field_name, jint val) {
LOGV("__setField_int:");
jfieldID id = env->GetFieldID(clazz, field_name, "I");
if (LIKELY(id))
env->SetIntField(java_obj, id, val);
else {
LOGE("__setField_int:field '%s' not found", field_name);
env->ExceptionClear(); // clear java.lang.NoSuchFieldError exception
}
return val;
}
/**
* set the value into int field
* @param env: this param should not be null
* @param java_obj: this param should not be null
* @param field_name
* @params val
*/
jint setField_int(JNIEnv *env, jobject java_obj, const char *field_name, jint val) {
LOGV("setField_int:");
jclass clazz = env->GetObjectClass(java_obj);
__setField_int(env, java_obj, clazz, field_name, val);
#ifdef ANDROID_NDK
env->DeleteLocalRef(clazz);
#endif
return val;
}
static ID_TYPE nativeCreate(JNIEnv *env, jobject thiz) {
ENTER();
UVCCamera *camera = new UVCCamera();
setField_long(env, thiz, "mNativePtr", reinterpret_cast(camera));
RETURN(reinterpret_cast(camera), ID_TYPE);
}
// native側のカメラオブジェクトを破棄
static void nativeDestroy(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
ENTER();
setField_long(env, thiz, "mNativePtr", 0);
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
SAFE_DELETE(camera);
}
EXIT();
}
//======================================================================
// カメラへ接続
static jint nativeConnect(JNIEnv *env, jobject thiz,
ID_TYPE id_camera,
jint vid, jint pid, jint fd,
jint busNum, jint devAddr, jstring usbfs_str) {
ENTER();
int result = JNI_ERR;
UVCCamera *camera = reinterpret_cast(id_camera);
const char *c_usbfs = env->GetStringUTFChars(usbfs_str, JNI_FALSE);
if (LIKELY(camera && (fd > 0))) {
// libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_DEBUG);
result = camera->connect(vid, pid, fd, busNum, devAddr, c_usbfs);
}
env->ReleaseStringUTFChars(usbfs_str, c_usbfs);
RETURN(result, jint);
}
// カメラとの接続を解除
static jint nativeRelease(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
ENTER();
int result = JNI_ERR;
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->release();
}
RETURN(result, jint);
}
//======================================================================
static jint nativeSetStatusCallback(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jobject jIStatusCallback) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
jobject status_callback_obj = env->NewGlobalRef(jIStatusCallback);
result = camera->setStatusCallback(env, status_callback_obj);
}
RETURN(result, jint);
}
static jint nativeSetButtonCallback(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jobject jIButtonCallback) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
jobject button_callback_obj = env->NewGlobalRef(jIButtonCallback);
result = camera->setButtonCallback(env, button_callback_obj);
}
RETURN(result, jint);
}
static jobject nativeGetSupportedSize(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
ENTER();
jstring result = NULL;
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
char *c_str = camera->getSupportedSize();
if (LIKELY(c_str)) {
result = env->NewStringUTF(c_str);
free(c_str);
}
}
RETURN(result, jobject);
}
//======================================================================
// プレビュー画面の大きさをセット
static jint nativeSetPreviewSize(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint width, jint height, jint min_fps, jint max_fps, jint mode, jfloat bandwidth) {
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
return camera->setPreviewSize(width, height, min_fps, max_fps, mode, bandwidth);
}
RETURN(JNI_ERR, jint);
}
static jint nativeStartPreview(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
return camera->startPreview();
}
RETURN(JNI_ERR, jint);
}
// プレビューを停止
static jint nativeStopPreview(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->stopPreview();
}
RETURN(result, jint);
}
static jint nativeSetPreviewDisplay(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jobject jSurface) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
ANativeWindow *preview_window = jSurface ? ANativeWindow_fromSurface(env, jSurface) : NULL;
result = camera->setPreviewDisplay(preview_window);
}
RETURN(result, jint);
}
static jint nativeSetFrameCallback(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jobject jIFrameCallback, jint pixel_format) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
jobject frame_callback_obj = env->NewGlobalRef(jIFrameCallback);
result = camera->setFrameCallback(env, frame_callback_obj, pixel_format);
}
RETURN(result, jint);
}
static jint nativeSetCaptureDisplay(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jobject jSurface) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
ANativeWindow *capture_window = jSurface ? ANativeWindow_fromSurface(env, jSurface) : NULL;
result = camera->setCaptureDisplay(capture_window);
}
RETURN(result, jint);
}
//======================================================================
// カメラコントロールでサポートしている機能を取得する
static jlong nativeGetCtrlSupports(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jlong result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
uint64_t supports;
int r = camera->getCtrlSupports(&supports);
if (!r)
result = supports;
}
RETURN(result, jlong);
}
// プロセッシングユニットでサポートしている機能を取得する
static jlong nativeGetProcSupports(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jlong result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
uint64_t supports;
int r = camera->getProcSupports(&supports);
if (!r)
result = supports;
}
RETURN(result, jlong);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateScanningModeLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateScanningModeLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mScanningModeMin", min);
setField_int(env, thiz, "mScanningModeMax", max);
setField_int(env, thiz, "mScanningModeDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetScanningMode(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint scanningMode) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setScanningMode(scanningMode);
}
RETURN(result, jint);
}
static jint nativeGetScanningMode(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getScanningMode();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateExposureModeLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateExposureModeLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mExposureModeMin", min);
setField_int(env, thiz, "mExposureModeMax", max);
setField_int(env, thiz, "mExposureModeDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetExposureMode(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, int exposureMode) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setExposureMode(exposureMode);
}
RETURN(result, jint);
}
static jint nativeGetExposureMode(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getExposureMode();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateExposurePriorityLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateExposurePriorityLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mExposurePriorityMin", min);
setField_int(env, thiz, "mExposurePriorityMax", max);
setField_int(env, thiz, "mExposurePriorityDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetExposurePriority(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, int priority) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setExposurePriority(priority);
}
RETURN(result, jint);
}
static jint nativeGetExposurePriority(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getExposurePriority();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateExposureLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateExposureLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mExposureMin", min);
setField_int(env, thiz, "mExposureMax", max);
setField_int(env, thiz, "mExposureDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetExposure(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, int exposure) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setExposure(exposure);
}
RETURN(result, jint);
}
static jint nativeGetExposure(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getExposure();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateExposureRelLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateExposureRelLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mExposureRelMin", min);
setField_int(env, thiz, "mExposureRelMax", max);
setField_int(env, thiz, "mExposureRelDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetExposureRel(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint exposure_rel) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setExposureRel(exposure_rel);
}
RETURN(result, jint);
}
static jint nativeGetExposureRel(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getExposureRel();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateAutoFocusLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateAutoFocusLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mAutoFocusMin", min);
setField_int(env, thiz, "mAutoFocusMax", max);
setField_int(env, thiz, "mAutoFocusDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetAutoFocus(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jboolean autofocus) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setAutoFocus(autofocus);
}
RETURN(result, jint);
}
static jint nativeGetAutoFocus(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getAutoFocus();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateAutoWhiteBlanceLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateAutoWhiteBlanceLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mAutoWhiteBlanceMin", min);
setField_int(env, thiz, "mAutoWhiteBlanceMax", max);
setField_int(env, thiz, "mAutoWhiteBlanceDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetAutoWhiteBlance(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jboolean autofocus) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setAutoWhiteBlance(autofocus);
}
RETURN(result, jint);
}
static jint nativeGetAutoWhiteBlance(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getAutoWhiteBlance();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateAutoWhiteBlanceCompoLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateAutoWhiteBlanceCompoLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mAutoWhiteBlanceCompoMin", min);
setField_int(env, thiz, "mAutoWhiteBlanceCompoMax", max);
setField_int(env, thiz, "mAutoWhiteBlanceCompoDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetAutoWhiteBlanceCompo(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jboolean autofocus_compo) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setAutoWhiteBlanceCompo(autofocus_compo);
}
RETURN(result, jint);
}
static jint nativeGetAutoWhiteBlanceCompo(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getAutoWhiteBlanceCompo();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateBrightnessLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateBrightnessLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mBrightnessMin", min);
setField_int(env, thiz, "mBrightnessMax", max);
setField_int(env, thiz, "mBrightnessDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetBrightness(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint brightness) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setBrightness(brightness);
}
RETURN(result, jint);
}
static jint nativeGetBrightness(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getBrightness();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateFocusLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateFocusLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mFocusMin", min);
setField_int(env, thiz, "mFocusMax", max);
setField_int(env, thiz, "mFocusDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetFocus(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint focus) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setFocus(focus);
}
RETURN(result, jint);
}
static jint nativeGetFocus(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getFocus();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateFocusRelLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateFocusRelLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mFocusRelMin", min);
setField_int(env, thiz, "mFocusRelMax", max);
setField_int(env, thiz, "mFocusRelDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetFocusRel(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint focus_rel) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setFocusRel(focus_rel);
}
RETURN(result, jint);
}
static jint nativeGetFocusRel(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getFocusRel();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateIrisLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateIrisLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mIrisMin", min);
setField_int(env, thiz, "mIrisMax", max);
setField_int(env, thiz, "mIrisDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetIris(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint iris) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setIris(iris);
}
RETURN(result, jint);
}
static jint nativeGetIris(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->getIris();
}
RETURN(result, jint);
}
//======================================================================
// Java mnethod correspond to this function should not be a static mathod
static jint nativeUpdateIrisRelLimit(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
int min, max, def;
result = camera->updateIrisRelLimit(min, max, def);
if (!result) {
// Java側へ書き込む
setField_int(env, thiz, "mIrisRelMin", min);
setField_int(env, thiz, "mIrisRelMax", max);
setField_int(env, thiz, "mIrisRelDef", def);
}
}
RETURN(result, jint);
}
static jint nativeSetIrisRel(JNIEnv *env, jobject thiz,
ID_TYPE id_camera, jint iris_rel) {
jint result = JNI_ERR;
ENTER();
UVCCamera *camera = reinterpret_cast(id_camera);
if (LIKELY(camera)) {
result = camera->setIrisRel(iris_rel);
}
RETURN(result, jint);
}
static jint nativeGetIrisRel(JNIEnv *env, jobject thiz,
ID_TYPE id_camera) {
jint result = 0;
ENTER();
UVCCamera *camera = reinterpret_cast